js/src/vm/SPSProfiler.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef vm_SPSProfiler_h
michael@0 8 #define vm_SPSProfiler_h
michael@0 9
michael@0 10 #include "mozilla/DebugOnly.h"
michael@0 11 #include "mozilla/GuardObjects.h"
michael@0 12
michael@0 13 #include <stddef.h>
michael@0 14
michael@0 15 #include "jslock.h"
michael@0 16 #include "jsscript.h"
michael@0 17
michael@0 18 #include "js/ProfilingStack.h"
michael@0 19
michael@0 20 /*
michael@0 21 * SPS Profiler integration with the JS Engine
michael@0 22 * https://developer.mozilla.org/en/Performance/Profiling_with_the_Built-in_Profiler
michael@0 23 *
michael@0 24 * The SPS profiler (found in tools/profiler) is an implementation of a profiler
michael@0 25 * which has the ability to walk the C++ stack as well as use instrumentation to
michael@0 26 * gather information. When dealing with JS, however, SPS needs integration
michael@0 27 * with the engine because otherwise it is very difficult to figure out what
michael@0 28 * javascript is executing.
michael@0 29 *
michael@0 30 * The current method of integration with SPS is a form of instrumentation:
michael@0 31 * every time a JS function is entered, a bit of information is pushed onto a
michael@0 32 * stack that SPS owns and maintains. This information is then popped at the end
michael@0 33 * of the JS function. SPS informs the JS engine of this stack at runtime, and
michael@0 34 * it can by turned on/off dynamically.
michael@0 35 *
michael@0 36 * The SPS stack has three parameters: a base pointer, a size, and a maximum
michael@0 37 * size. The stack is the ProfileEntry stack which will have information written
michael@0 38 * to it. The size location is a pointer to an integer which represents the
michael@0 39 * current size of the stack (number of valid frames). This size will be
michael@0 40 * modified when JS functions are called. The maximum specified is the maximum
michael@0 41 * capacity of the ProfileEntry stack.
michael@0 42 *
michael@0 43 * Throughout execution, the size of the stack recorded in memory may exceed the
michael@0 44 * maximum. The JS engine will not write any information past the maximum limit,
michael@0 45 * but it will still maintain the size of the stack. SPS code is aware of this
michael@0 46 * and iterates the stack accordingly.
michael@0 47 *
michael@0 48 * There is some information pushed on the SPS stack for every JS function that
michael@0 49 * is entered. First is a char* pointer of a description of what function was
michael@0 50 * entered. Currently this string is of the form "function (file:line)" if
michael@0 51 * there's a function name, or just "file:line" if there's no function name
michael@0 52 * available. The other bit of information is the relevant C++ (native) stack
michael@0 53 * pointer. This stack pointer is what enables the interleaving of the C++ and
michael@0 54 * the JS stack. Finally, throughout execution of the function, some extra
michael@0 55 * information may be updated on the ProfileEntry structure.
michael@0 56 *
michael@0 57 * = Profile Strings
michael@0 58 *
michael@0 59 * The profile strings' allocations and deallocation must be carefully
michael@0 60 * maintained, and ideally at a very low overhead cost. For this reason, the JS
michael@0 61 * engine maintains a mapping of all known profile strings. These strings are
michael@0 62 * keyed in lookup by a JSScript*, but are serialized with a JSFunction*,
michael@0 63 * JSScript* pair. A JSScript will destroy its corresponding profile string when
michael@0 64 * the script is finalized.
michael@0 65 *
michael@0 66 * For this reason, a char* pointer pushed on the SPS stack is valid only while
michael@0 67 * it is on the SPS stack. SPS uses sampling to read off information from this
michael@0 68 * instrumented stack, and it therefore copies the string byte for byte when a
michael@0 69 * JS function is encountered during sampling.
michael@0 70 *
michael@0 71 * = Native Stack Pointer
michael@0 72 *
michael@0 73 * The actual value pushed as the native pointer is nullptr for most JS
michael@0 74 * functions. The reason for this is that there's actually very little
michael@0 75 * correlation between the JS stack and the C++ stack because many JS functions
michael@0 76 * all run in the same C++ frame, or can even go backwards in C++ when going
michael@0 77 * from the JIT back to the interpreter.
michael@0 78 *
michael@0 79 * To alleviate this problem, all JS functions push nullptr as their "native
michael@0 80 * stack pointer" to indicate that it's a JS function call. The function
michael@0 81 * RunScript(), however, pushes an actual C++ stack pointer onto the SPS stack.
michael@0 82 * This way when interleaving C++ and JS, if SPS sees a nullptr native stack
michael@0 83 * pointer on the SPS stack, it looks backwards for the first non-nullptr
michael@0 84 * pointer and uses that for all subsequent nullptr native stack pointers.
michael@0 85 *
michael@0 86 * = Line Numbers
michael@0 87 *
michael@0 88 * One goal of sampling is to get both a backtrace of the JS stack, but also
michael@0 89 * know where within each function on the stack execution currently is. For
michael@0 90 * this, each ProfileEntry has a 'pc' field to tell where its execution
michael@0 91 * currently is. This field is updated whenever a call is made to another JS
michael@0 92 * function, and for the JIT it is also updated whenever the JIT is left.
michael@0 93 *
michael@0 94 * This field is in a union with a uint32_t 'line' so that C++ can make use of
michael@0 95 * the field as well. It was observed that tracking 'line' via PCToLineNumber in
michael@0 96 * JS was far too expensive, so that is why the pc instead of the translated
michael@0 97 * line number is stored.
michael@0 98 *
michael@0 99 * As an invariant, if the pc is nullptr, then the JIT is currently executing
michael@0 100 * generated code. Otherwise execution is in another JS function or in C++. With
michael@0 101 * this in place, only the top entry of the stack can ever have nullptr as its
michael@0 102 * pc. Additionally with this invariant, it is possible to maintain mappings of
michael@0 103 * JIT code to pc which can be accessed safely because they will only be
michael@0 104 * accessed from a signal handler when the JIT code is executing.
michael@0 105 */
michael@0 106
michael@0 107 namespace js {
michael@0 108
michael@0 109 class ProfileEntry;
michael@0 110
michael@0 111 typedef HashMap<JSScript*, const char*, DefaultHasher<JSScript*>, SystemAllocPolicy>
michael@0 112 ProfileStringMap;
michael@0 113
michael@0 114 class SPSEntryMarker;
michael@0 115
michael@0 116 class SPSProfiler
michael@0 117 {
michael@0 118 friend class SPSEntryMarker;
michael@0 119
michael@0 120 JSRuntime *rt;
michael@0 121 ProfileStringMap strings;
michael@0 122 ProfileEntry *stack_;
michael@0 123 uint32_t *size_;
michael@0 124 uint32_t max_;
michael@0 125 bool slowAssertions;
michael@0 126 uint32_t enabled_;
michael@0 127 PRLock *lock_;
michael@0 128 void (*eventMarker_)(const char *);
michael@0 129
michael@0 130 const char *allocProfileString(JSScript *script, JSFunction *function);
michael@0 131 void push(const char *string, void *sp, JSScript *script, jsbytecode *pc);
michael@0 132 void pushNoCopy(const char *string, void *sp,
michael@0 133 JSScript *script, jsbytecode *pc) {
michael@0 134 push(string, reinterpret_cast<void*>(
michael@0 135 reinterpret_cast<uintptr_t>(sp) | ProfileEntry::NoCopyBit),
michael@0 136 script, pc);
michael@0 137 }
michael@0 138 void pop();
michael@0 139
michael@0 140 public:
michael@0 141 SPSProfiler(JSRuntime *rt);
michael@0 142 ~SPSProfiler();
michael@0 143
michael@0 144 bool init();
michael@0 145
michael@0 146 uint32_t **addressOfSizePointer() {
michael@0 147 return &size_;
michael@0 148 }
michael@0 149
michael@0 150 uint32_t *addressOfMaxSize() {
michael@0 151 return &max_;
michael@0 152 }
michael@0 153
michael@0 154 ProfileEntry **addressOfStack() {
michael@0 155 return &stack_;
michael@0 156 }
michael@0 157
michael@0 158 uint32_t *sizePointer() { return size_; }
michael@0 159 uint32_t maxSize() { return max_; }
michael@0 160 ProfileEntry *stack() { return stack_; }
michael@0 161
michael@0 162 /* management of whether instrumentation is on or off */
michael@0 163 bool enabled() { JS_ASSERT_IF(enabled_, installed()); return enabled_; }
michael@0 164 bool installed() { return stack_ != nullptr && size_ != nullptr; }
michael@0 165 void enable(bool enabled);
michael@0 166 void enableSlowAssertions(bool enabled) { slowAssertions = enabled; }
michael@0 167 bool slowAssertionsEnabled() { return slowAssertions; }
michael@0 168
michael@0 169 /*
michael@0 170 * Functions which are the actual instrumentation to track run information
michael@0 171 *
michael@0 172 * - enter: a function has started to execute
michael@0 173 * - updatePC: updates the pc information about where a function
michael@0 174 * is currently executing
michael@0 175 * - exit: this function has ceased execution, and no further
michael@0 176 * entries/exits will be made
michael@0 177 */
michael@0 178 bool enter(JSScript *script, JSFunction *maybeFun);
michael@0 179 void exit(JSScript *script, JSFunction *maybeFun);
michael@0 180 void updatePC(JSScript *script, jsbytecode *pc) {
michael@0 181 if (enabled() && *size_ - 1 < max_) {
michael@0 182 JS_ASSERT(*size_ > 0);
michael@0 183 JS_ASSERT(stack_[*size_ - 1].script() == script);
michael@0 184 stack_[*size_ - 1].setPC(pc);
michael@0 185 }
michael@0 186 }
michael@0 187
michael@0 188 /* Enter a C++ function. */
michael@0 189 void enterNative(const char *string, void *sp);
michael@0 190 void exitNative() { pop(); }
michael@0 191
michael@0 192 jsbytecode *ipToPC(JSScript *script, size_t ip) { return nullptr; }
michael@0 193
michael@0 194 void setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max);
michael@0 195 void setEventMarker(void (*fn)(const char *));
michael@0 196 const char *profileString(JSScript *script, JSFunction *maybeFun);
michael@0 197 void onScriptFinalized(JSScript *script);
michael@0 198
michael@0 199 void markEvent(const char *event);
michael@0 200
michael@0 201 /* meant to be used for testing, not recommended to call in normal code */
michael@0 202 size_t stringsCount();
michael@0 203 void stringsReset();
michael@0 204
michael@0 205 uint32_t *addressOfEnabled() {
michael@0 206 return &enabled_;
michael@0 207 }
michael@0 208 };
michael@0 209
michael@0 210 /*
michael@0 211 * This class is used to make sure the strings table
michael@0 212 * is only accessed on one thread at a time.
michael@0 213 */
michael@0 214 class AutoSPSLock
michael@0 215 {
michael@0 216 public:
michael@0 217 #ifdef JS_THREADSAFE
michael@0 218 AutoSPSLock(PRLock *lock)
michael@0 219 {
michael@0 220 MOZ_ASSERT(lock, "Parameter should not be null!");
michael@0 221 lock_ = lock;
michael@0 222 PR_Lock(lock);
michael@0 223 }
michael@0 224 ~AutoSPSLock() { PR_Unlock(lock_); }
michael@0 225 #else
michael@0 226 AutoSPSLock(PRLock *) {}
michael@0 227 #endif
michael@0 228
michael@0 229 private:
michael@0 230 PRLock *lock_;
michael@0 231 };
michael@0 232
michael@0 233 inline size_t
michael@0 234 SPSProfiler::stringsCount()
michael@0 235 {
michael@0 236 AutoSPSLock lock(lock_);
michael@0 237 return strings.count();
michael@0 238 }
michael@0 239
michael@0 240 inline void
michael@0 241 SPSProfiler::stringsReset()
michael@0 242 {
michael@0 243 AutoSPSLock lock(lock_);
michael@0 244 strings.clear();
michael@0 245 }
michael@0 246
michael@0 247 /*
michael@0 248 * This class is used in RunScript() to push the marker onto the sampling stack
michael@0 249 * that we're about to enter JS function calls. This is the only time in which a
michael@0 250 * valid stack pointer is pushed to the sampling stack.
michael@0 251 */
michael@0 252 class SPSEntryMarker
michael@0 253 {
michael@0 254 public:
michael@0 255 SPSEntryMarker(JSRuntime *rt
michael@0 256 MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
michael@0 257 ~SPSEntryMarker();
michael@0 258
michael@0 259 private:
michael@0 260 SPSProfiler *profiler;
michael@0 261 mozilla::DebugOnly<uint32_t> size_before;
michael@0 262 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
michael@0 263 };
michael@0 264
michael@0 265 /*
michael@0 266 * SPS is the profiling backend used by the JS engine to enable time profiling.
michael@0 267 * More information can be found in vm/SPSProfiler.{h,cpp}. This class manages
michael@0 268 * the instrumentation portion of the profiling for JIT code.
michael@0 269 *
michael@0 270 * The instrumentation tracks entry into functions, leaving those functions via
michael@0 271 * a function call, reentering the functions from a function call, and exiting
michael@0 272 * the functions from returning. This class also handles inline frames and
michael@0 273 * manages the instrumentation which needs to be attached to them as well.
michael@0 274 *
michael@0 275 * The basic methods which emit instrumentation are at the end of this class,
michael@0 276 * and the management functions are all described in the middle.
michael@0 277 */
michael@0 278 template<class Assembler, class Register>
michael@0 279 class SPSInstrumentation
michael@0 280 {
michael@0 281 /* Because of inline frames, this is a nested structure in a vector */
michael@0 282 struct FrameState {
michael@0 283 JSScript *script; // script for this frame, nullptr if not pushed yet
michael@0 284 jsbytecode *pc; // pc at which this frame was left for entry into a callee
michael@0 285 bool skipNext; // should the next call to reenter be skipped?
michael@0 286 int left; // number of leave() calls made without a matching reenter()
michael@0 287 };
michael@0 288
michael@0 289 SPSProfiler *profiler_; // Instrumentation location management
michael@0 290
michael@0 291 Vector<FrameState, 1, SystemAllocPolicy> frames;
michael@0 292 FrameState *frame;
michael@0 293
michael@0 294 static void clearFrame(FrameState *frame) {
michael@0 295 frame->script = nullptr;
michael@0 296 frame->pc = nullptr;
michael@0 297 frame->skipNext = false;
michael@0 298 frame->left = 0;
michael@0 299 }
michael@0 300
michael@0 301 public:
michael@0 302 /*
michael@0 303 * Creates instrumentation which writes information out the the specified
michael@0 304 * profiler's stack and constituent fields.
michael@0 305 */
michael@0 306 SPSInstrumentation(SPSProfiler *profiler)
michael@0 307 : profiler_(profiler), frame(nullptr)
michael@0 308 {
michael@0 309 enterInlineFrame(nullptr);
michael@0 310 }
michael@0 311
michael@0 312 /* Small proxies around SPSProfiler */
michael@0 313 bool enabled() { return profiler_ && profiler_->enabled(); }
michael@0 314 SPSProfiler *profiler() { JS_ASSERT(enabled()); return profiler_; }
michael@0 315 void disable() { profiler_ = nullptr; }
michael@0 316
michael@0 317 /* Signals an inline function returned, reverting to the previous state */
michael@0 318 void leaveInlineFrame() {
michael@0 319 if (!enabled())
michael@0 320 return;
michael@0 321 JS_ASSERT(frame->left == 0);
michael@0 322 JS_ASSERT(frame->script != nullptr);
michael@0 323 frames.shrinkBy(1);
michael@0 324 JS_ASSERT(frames.length() > 0);
michael@0 325 frame = &frames[frames.length() - 1];
michael@0 326 }
michael@0 327
michael@0 328 /* Saves the current state and assumes a fresh one for the inline function */
michael@0 329 bool enterInlineFrame(jsbytecode *callerPC) {
michael@0 330 if (!enabled())
michael@0 331 return true;
michael@0 332 JS_ASSERT_IF(frames.empty(), callerPC == nullptr);
michael@0 333
michael@0 334 JS_ASSERT_IF(frame != nullptr, frame->script != nullptr);
michael@0 335 JS_ASSERT_IF(frame != nullptr, frame->left == 1);
michael@0 336 if (!frames.empty()) {
michael@0 337 JS_ASSERT(frame == &frames[frames.length() - 1]);
michael@0 338 frame->pc = callerPC;
michael@0 339 }
michael@0 340 if (!frames.growBy(1))
michael@0 341 return false;
michael@0 342 frame = &frames[frames.length() - 1];
michael@0 343 clearFrame(frame);
michael@0 344 return true;
michael@0 345 }
michael@0 346
michael@0 347 /* Prepares the instrumenter state for generating OOL code, by
michael@0 348 * setting up the frame state to seem as if there are exactly
michael@0 349 * two pushed frames: a frame for the top-level script, and
michael@0 350 * a frame for the OOL code being generated. Any
michael@0 351 * vm-calls from the OOL code will "leave" the OOL frame and
michael@0 352 * return back to it.
michael@0 353 */
michael@0 354 bool prepareForOOL() {
michael@0 355 if (!enabled())
michael@0 356 return true;
michael@0 357 JS_ASSERT(!frames.empty());
michael@0 358 if (frames.length() >= 2) {
michael@0 359 frames.shrinkBy(frames.length() - 2);
michael@0 360
michael@0 361 } else { // frames.length() == 1
michael@0 362 if (!frames.growBy(1))
michael@0 363 return false;
michael@0 364 }
michael@0 365 frames[0].pc = frames[0].script->code();
michael@0 366 frame = &frames[1];
michael@0 367 clearFrame(frame);
michael@0 368 return true;
michael@0 369 }
michael@0 370 void finishOOL() {
michael@0 371 if (!enabled())
michael@0 372 return;
michael@0 373 JS_ASSERT(!frames.empty());
michael@0 374 frames.shrinkBy(frames.length() - 1);
michael@0 375 }
michael@0 376
michael@0 377 /* Number of inline frames currently active (doesn't include original one) */
michael@0 378 unsigned inliningDepth() {
michael@0 379 return frames.length() - 1;
michael@0 380 }
michael@0 381
michael@0 382 /*
michael@0 383 * When debugging or with slow assertions, sometimes a C++ method will be
michael@0 384 * invoked to perform the pop operation from the SPS stack. When we leave
michael@0 385 * JIT code, we need to record the current PC, but upon reentering JIT
michael@0 386 * code, no update back to nullptr should happen. This method exists to
michael@0 387 * flag this behavior. The next leave() will emit instrumentation, but the
michael@0 388 * following reenter() will be a no-op.
michael@0 389 */
michael@0 390 void skipNextReenter() {
michael@0 391 /* If we've left the frame, the reenter will be skipped anyway */
michael@0 392 if (!enabled() || frame->left != 0)
michael@0 393 return;
michael@0 394 JS_ASSERT(frame->script);
michael@0 395 JS_ASSERT(!frame->skipNext);
michael@0 396 frame->skipNext = true;
michael@0 397 }
michael@0 398
michael@0 399 /*
michael@0 400 * In some cases, a frame needs to be flagged as having been pushed, but no
michael@0 401 * instrumentation should be emitted. This updates internal state to flag
michael@0 402 * that further instrumentation should actually be emitted.
michael@0 403 */
michael@0 404 void setPushed(JSScript *script) {
michael@0 405 if (!enabled())
michael@0 406 return;
michael@0 407 JS_ASSERT(frame->left == 0);
michael@0 408 frame->script = script;
michael@0 409 }
michael@0 410
michael@0 411 /*
michael@0 412 * Flags entry into a JS function for the first time. Before this is called,
michael@0 413 * no instrumentation is emitted, but after this instrumentation is emitted.
michael@0 414 */
michael@0 415 bool push(JSScript *script, Assembler &masm, Register scratch, bool inlinedFunction = false) {
michael@0 416 if (!enabled())
michael@0 417 return true;
michael@0 418 #ifdef JS_ION
michael@0 419 if (!inlinedFunction || jit::js_JitOptions.profileInlineFrames) {
michael@0 420 #endif
michael@0 421 const char *string = profiler_->profileString(script, script->functionNonDelazifying());
michael@0 422 if (string == nullptr)
michael@0 423 return false;
michael@0 424 masm.spsPushFrame(profiler_, string, script, scratch);
michael@0 425 #ifdef JS_ION
michael@0 426 }
michael@0 427 #endif
michael@0 428 setPushed(script);
michael@0 429 return true;
michael@0 430 }
michael@0 431
michael@0 432 /*
michael@0 433 * Signifies that C++ performed the push() for this function. C++ always
michael@0 434 * sets the current PC to something non-null, however, so as soon as JIT
michael@0 435 * code is reentered this updates the current pc to nullptr.
michael@0 436 */
michael@0 437 void pushManual(JSScript *script, Assembler &masm, Register scratch,
michael@0 438 bool inlinedFunction = false)
michael@0 439 {
michael@0 440 if (!enabled())
michael@0 441 return;
michael@0 442
michael@0 443 #ifdef JS_ION
michael@0 444 if (!inlinedFunction || jit::js_JitOptions.profileInlineFrames)
michael@0 445 #endif
michael@0 446 masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCIndex, scratch);
michael@0 447
michael@0 448 setPushed(script);
michael@0 449 }
michael@0 450
michael@0 451 /*
michael@0 452 * Signals that the current function is leaving for a function call. This
michael@0 453 * can happen both on JS function calls and also calls to C++. This
michael@0 454 * internally manages how many leave() calls have been seen, and only the
michael@0 455 * first leave() emits instrumentation. Similarly, only the last
michael@0 456 * corresponding reenter() actually emits instrumentation.
michael@0 457 */
michael@0 458 void leave(jsbytecode *pc, Assembler &masm, Register scratch, bool inlinedFunction = false) {
michael@0 459 if (enabled() && frame->script && frame->left++ == 0) {
michael@0 460 jsbytecode *updatePC = pc;
michael@0 461 JSScript *script = frame->script;
michael@0 462 #ifdef JS_ION
michael@0 463 if (!inlinedFunction) {
michael@0 464 // We may be leaving an inlined frame for entry into a C++
michael@0 465 // frame. If profileInlineFrames is turned off, use the top
michael@0 466 // script's pc offset instead of the innermost script's.
michael@0 467 if (!jit::js_JitOptions.profileInlineFrames && inliningDepth() > 0) {
michael@0 468 JS_ASSERT(frames[0].pc);
michael@0 469 updatePC = frames[0].pc;
michael@0 470 script = frames[0].script;
michael@0 471 }
michael@0 472 }
michael@0 473 #endif
michael@0 474
michael@0 475 #ifdef JS_ION
michael@0 476 if (!inlinedFunction || jit::js_JitOptions.profileInlineFrames)
michael@0 477 #endif
michael@0 478 masm.spsUpdatePCIdx(profiler_, script->pcToOffset(updatePC), scratch);
michael@0 479 }
michael@0 480 }
michael@0 481
michael@0 482 /*
michael@0 483 * Flags that the leaving of the current function has returned. This tracks
michael@0 484 * state with leave() to only emit instrumentation at proper times.
michael@0 485 */
michael@0 486 void reenter(Assembler &masm, Register scratch, bool inlinedFunction = false) {
michael@0 487 if (!enabled() || !frame->script || frame->left-- != 1)
michael@0 488 return;
michael@0 489 if (frame->skipNext) {
michael@0 490 frame->skipNext = false;
michael@0 491 } else {
michael@0 492 #ifdef JS_ION
michael@0 493 if (!inlinedFunction || jit::js_JitOptions.profileInlineFrames)
michael@0 494 #endif
michael@0 495 masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCIndex, scratch);
michael@0 496 }
michael@0 497 }
michael@0 498
michael@0 499 /*
michael@0 500 * Signifies exiting a JS frame, popping the SPS entry. Because there can be
michael@0 501 * multiple return sites of a function, this does not cease instrumentation
michael@0 502 * emission.
michael@0 503 */
michael@0 504 void pop(Assembler &masm, Register scratch, bool inlinedFunction = false) {
michael@0 505 if (enabled()) {
michael@0 506 JS_ASSERT(frame->left == 0);
michael@0 507 JS_ASSERT(frame->script);
michael@0 508 #ifdef JS_ION
michael@0 509 if (!inlinedFunction || jit::js_JitOptions.profileInlineFrames)
michael@0 510 #endif
michael@0 511 masm.spsPopFrame(profiler_, scratch);
michael@0 512 }
michael@0 513 }
michael@0 514 };
michael@0 515
michael@0 516 } /* namespace js */
michael@0 517
michael@0 518 #endif /* vm_SPSProfiler_h */

mercurial