js/src/jit/IonFrames.cpp

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.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jit/IonFrames-inl.h"
     9 #include "jsfun.h"
    10 #include "jsobj.h"
    11 #include "jsscript.h"
    13 #include "gc/Marking.h"
    14 #include "jit/BaselineDebugModeOSR.h"
    15 #include "jit/BaselineFrame.h"
    16 #include "jit/BaselineIC.h"
    17 #include "jit/BaselineJIT.h"
    18 #include "jit/Ion.h"
    19 #include "jit/IonMacroAssembler.h"
    20 #include "jit/IonSpewer.h"
    21 #include "jit/JitCompartment.h"
    22 #include "jit/ParallelFunctions.h"
    23 #include "jit/PcScriptCache.h"
    24 #include "jit/Recover.h"
    25 #include "jit/Safepoints.h"
    26 #include "jit/Snapshots.h"
    27 #include "jit/VMFunctions.h"
    28 #include "vm/ArgumentsObject.h"
    29 #include "vm/ForkJoin.h"
    30 #include "vm/Interpreter.h"
    32 #include "jsscriptinlines.h"
    33 #include "jit/JitFrameIterator-inl.h"
    34 #include "vm/Probes-inl.h"
    36 namespace js {
    37 namespace jit {
    39 // Given a slot index, returns the offset, in bytes, of that slot from an
    40 // IonJSFrameLayout. Slot distances are uniform across architectures, however,
    41 // the distance does depend on the size of the frame header.
    42 static inline int32_t
    43 OffsetOfFrameSlot(int32_t slot)
    44 {
    45     return -slot;
    46 }
    48 static inline uintptr_t
    49 ReadFrameSlot(IonJSFrameLayout *fp, int32_t slot)
    50 {
    51     return *(uintptr_t *)((char *)fp + OffsetOfFrameSlot(slot));
    52 }
    54 static inline double
    55 ReadFrameDoubleSlot(IonJSFrameLayout *fp, int32_t slot)
    56 {
    57     return *(double *)((char *)fp + OffsetOfFrameSlot(slot));
    58 }
    60 static inline float
    61 ReadFrameFloat32Slot(IonJSFrameLayout *fp, int32_t slot)
    62 {
    63     return *(float *)((char *)fp + OffsetOfFrameSlot(slot));
    64 }
    66 static inline int32_t
    67 ReadFrameInt32Slot(IonJSFrameLayout *fp, int32_t slot)
    68 {
    69     return *(int32_t *)((char *)fp + OffsetOfFrameSlot(slot));
    70 }
    72 static inline bool
    73 ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot)
    74 {
    75     return *(bool *)((char *)fp + OffsetOfFrameSlot(slot));
    76 }
    78 JitFrameIterator::JitFrameIterator(JSContext *cx)
    79   : current_(cx->mainThread().ionTop),
    80     type_(JitFrame_Exit),
    81     returnAddressToFp_(nullptr),
    82     frameSize_(0),
    83     cachedSafepointIndex_(nullptr),
    84     activation_(nullptr),
    85     mode_(SequentialExecution)
    86 {
    87 }
    89 JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
    90     : current_(activations.jitTop()),
    91       type_(JitFrame_Exit),
    92       returnAddressToFp_(nullptr),
    93       frameSize_(0),
    94       cachedSafepointIndex_(nullptr),
    95       activation_(activations->asJit()),
    96       mode_(SequentialExecution)
    97 {
    98 }
   100 JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
   101   : current_((uint8_t *)fp),
   102     type_(JitFrame_IonJS),
   103     returnAddressToFp_(fp->returnAddress()),
   104     frameSize_(fp->prevFrameLocalSize()),
   105     mode_(mode)
   106 {
   107 }
   109 bool
   110 JitFrameIterator::checkInvalidation() const
   111 {
   112     IonScript *dummy;
   113     return checkInvalidation(&dummy);
   114 }
   116 bool
   117 JitFrameIterator::checkInvalidation(IonScript **ionScriptOut) const
   118 {
   119     uint8_t *returnAddr = returnAddressToFp();
   120     JSScript *script = this->script();
   121     // N.B. the current IonScript is not the same as the frame's
   122     // IonScript if the frame has since been invalidated.
   123     bool invalidated;
   124     if (mode_ == ParallelExecution) {
   125         // Parallel execution does not have invalidating bailouts.
   126         invalidated = false;
   127     } else {
   128         invalidated = !script->hasIonScript() ||
   129             !script->ionScript()->containsReturnAddress(returnAddr);
   130     }
   131     if (!invalidated)
   132         return false;
   134     int32_t invalidationDataOffset = ((int32_t *) returnAddr)[-1];
   135     uint8_t *ionScriptDataOffset = returnAddr + invalidationDataOffset;
   136     IonScript *ionScript = (IonScript *) Assembler::getPointer(ionScriptDataOffset);
   137     JS_ASSERT(ionScript->containsReturnAddress(returnAddr));
   138     *ionScriptOut = ionScript;
   139     return true;
   140 }
   142 CalleeToken
   143 JitFrameIterator::calleeToken() const
   144 {
   145     return ((IonJSFrameLayout *) current_)->calleeToken();
   146 }
   148 JSFunction *
   149 JitFrameIterator::callee() const
   150 {
   151     JS_ASSERT(isScripted());
   152     JS_ASSERT(isFunctionFrame());
   153     return CalleeTokenToFunction(calleeToken());
   154 }
   156 JSFunction *
   157 JitFrameIterator::maybeCallee() const
   158 {
   159     if (isScripted() && (isFunctionFrame()))
   160         return callee();
   161     return nullptr;
   162 }
   164 bool
   165 JitFrameIterator::isNative() const
   166 {
   167     if (type_ != JitFrame_Exit || isFakeExitFrame())
   168         return false;
   169     return exitFrame()->footer()->jitCode() == nullptr;
   170 }
   172 bool
   173 JitFrameIterator::isOOLNative() const
   174 {
   175     if (type_ != JitFrame_Exit)
   176         return false;
   177     return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_NATIVE;
   178 }
   180 bool
   181 JitFrameIterator::isOOLPropertyOp() const
   182 {
   183     if (type_ != JitFrame_Exit)
   184         return false;
   185     return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_PROPERTY_OP;
   186 }
   188 bool
   189 JitFrameIterator::isOOLProxy() const
   190 {
   191     if (type_ != JitFrame_Exit)
   192         return false;
   193     return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_PROXY;
   194 }
   196 bool
   197 JitFrameIterator::isDOMExit() const
   198 {
   199     if (type_ != JitFrame_Exit)
   200         return false;
   201     return exitFrame()->isDomExit();
   202 }
   204 bool
   205 JitFrameIterator::isFunctionFrame() const
   206 {
   207     return CalleeTokenIsFunction(calleeToken());
   208 }
   210 JSScript *
   211 JitFrameIterator::script() const
   212 {
   213     JS_ASSERT(isScripted());
   214     if (isBaselineJS())
   215         return baselineFrame()->script();
   216     JSScript *script = ScriptFromCalleeToken(calleeToken());
   217     JS_ASSERT(script);
   218     return script;
   219 }
   221 void
   222 JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const
   223 {
   224     JS_ASSERT(isBaselineJS());
   225     JSScript *script = this->script();
   226     if (scriptRes)
   227         *scriptRes = script;
   228     uint8_t *retAddr = returnAddressToFp();
   230     // If we are in the middle of a recompile handler, get the real return
   231     // address as stashed in the RecompileInfo.
   232     if (BaselineDebugModeOSRInfo *info = baselineFrame()->getDebugModeOSRInfo())
   233         retAddr = info->resumeAddr;
   235     if (pcRes) {
   236         // If the return address is into the prologue entry address or just
   237         // after the debug prologue, then assume start of script.
   238         if (retAddr == script->baselineScript()->prologueEntryAddr() ||
   239             retAddr == script->baselineScript()->postDebugPrologueAddr())
   240         {
   241             *pcRes = script->code();
   242             return;
   243         }
   245         // The return address _may_ be a return from a callVM or IC chain call done for
   246         // some op.
   247         ICEntry *icEntry = script->baselineScript()->maybeICEntryFromReturnAddress(retAddr);
   248         if (icEntry) {
   249             *pcRes = icEntry->pc(script);
   250             return;
   251         }
   253         // If not, the return address _must_ be the start address of an op, which can
   254         // be computed from the pc mapping table.
   255         *pcRes = script->baselineScript()->pcForReturnAddress(script, retAddr);
   256     }
   257 }
   259 Value *
   260 JitFrameIterator::actualArgs() const
   261 {
   262     return jsFrame()->argv() + 1;
   263 }
   265 static inline size_t
   266 SizeOfFramePrefix(FrameType type)
   267 {
   268     switch (type) {
   269       case JitFrame_Entry:
   270         return IonEntryFrameLayout::Size();
   271       case JitFrame_BaselineJS:
   272       case JitFrame_IonJS:
   273       case JitFrame_Unwound_IonJS:
   274         return IonJSFrameLayout::Size();
   275       case JitFrame_BaselineStub:
   276         return IonBaselineStubFrameLayout::Size();
   277       case JitFrame_Rectifier:
   278         return IonRectifierFrameLayout::Size();
   279       case JitFrame_Unwound_Rectifier:
   280         return IonUnwoundRectifierFrameLayout::Size();
   281       case JitFrame_Exit:
   282         return IonExitFrameLayout::Size();
   283       default:
   284         MOZ_ASSUME_UNREACHABLE("unknown frame type");
   285     }
   286 }
   288 uint8_t *
   289 JitFrameIterator::prevFp() const
   290 {
   291     size_t currentSize = SizeOfFramePrefix(type_);
   292     // This quick fix must be removed as soon as bug 717297 land.  This is
   293     // needed because the descriptor size of JS-to-JS frame which is just after
   294     // a Rectifier frame should not change. (cf EnsureExitFrame function)
   295     if (isFakeExitFrame()) {
   296         JS_ASSERT(SizeOfFramePrefix(JitFrame_BaselineJS) ==
   297                   SizeOfFramePrefix(JitFrame_IonJS));
   298         currentSize = SizeOfFramePrefix(JitFrame_IonJS);
   299     }
   300     currentSize += current()->prevFrameLocalSize();
   301     return current_ + currentSize;
   302 }
   304 JitFrameIterator &
   305 JitFrameIterator::operator++()
   306 {
   307     JS_ASSERT(type_ != JitFrame_Entry);
   309     frameSize_ = prevFrameLocalSize();
   310     cachedSafepointIndex_ = nullptr;
   312     // If the next frame is the entry frame, just exit. Don't update current_,
   313     // since the entry and first frames overlap.
   314     if (current()->prevType() == JitFrame_Entry) {
   315         type_ = JitFrame_Entry;
   316         return *this;
   317     }
   319     // Note: prevFp() needs the current type, so set it after computing the
   320     // next frame.
   321     uint8_t *prev = prevFp();
   322     type_ = current()->prevType();
   323     if (type_ == JitFrame_Unwound_IonJS)
   324         type_ = JitFrame_IonJS;
   325     else if (type_ == JitFrame_Unwound_BaselineStub)
   326         type_ = JitFrame_BaselineStub;
   327     returnAddressToFp_ = current()->returnAddress();
   328     current_ = prev;
   329     return *this;
   330 }
   332 uintptr_t *
   333 JitFrameIterator::spillBase() const
   334 {
   335     // Get the base address to where safepoint registers are spilled.
   336     // Out-of-line calls do not unwind the extra padding space used to
   337     // aggregate bailout tables, so we use frameSize instead of frameLocals,
   338     // which would only account for local stack slots.
   339     return reinterpret_cast<uintptr_t *>(fp() - ionScript()->frameSize());
   340 }
   342 MachineState
   343 JitFrameIterator::machineState() const
   344 {
   345     SafepointReader reader(ionScript(), safepoint());
   346     uintptr_t *spill = spillBase();
   348     MachineState machine;
   349     for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++)
   350         machine.setRegisterLocation(*iter, --spill);
   352     double *floatSpill = reinterpret_cast<double *>(spill);
   353     for (FloatRegisterBackwardIterator iter(reader.allFloatSpills()); iter.more(); iter++)
   354         machine.setRegisterLocation(*iter, --floatSpill);
   356     return machine;
   357 }
   359 static void
   360 CloseLiveIterator(JSContext *cx, const InlineFrameIterator &frame, uint32_t localSlot)
   361 {
   362     SnapshotIterator si = frame.snapshotIterator();
   364     // Skip stack slots until we reach the iterator object.
   365     uint32_t base = CountArgSlots(frame.script(), frame.maybeCallee()) + frame.script()->nfixed();
   366     uint32_t skipSlots = base + localSlot - 1;
   368     for (unsigned i = 0; i < skipSlots; i++)
   369         si.skip();
   371     Value v = si.read();
   372     RootedObject obj(cx, &v.toObject());
   374     if (cx->isExceptionPending())
   375         UnwindIteratorForException(cx, obj);
   376     else
   377         UnwindIteratorForUncatchableException(cx, obj);
   378 }
   380 static void
   381 HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe,
   382                    bool *overrecursed)
   383 {
   384     RootedScript script(cx, frame.script());
   385     jsbytecode *pc = frame.pc();
   387     bool bailedOutForDebugMode = false;
   388     if (cx->compartment()->debugMode()) {
   389         // If we have an exception from within Ion and the debugger is active,
   390         // we do the following:
   391         //
   392         //   1. Bailout to baseline to reconstruct a baseline frame.
   393         //   2. Resume immediately into the exception tail afterwards, and
   394         //   handle the exception again with the top frame now a baseline
   395         //   frame.
   396         //
   397         // An empty exception info denotes that we're propagating an Ion
   398         // exception due to debug mode, which BailoutIonToBaseline needs to
   399         // know. This is because we might not be able to fully reconstruct up
   400         // to the stack depth at the snapshot, as we could've thrown in the
   401         // middle of a call.
   402         ExceptionBailoutInfo propagateInfo;
   403         uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed);
   404         bailedOutForDebugMode = retval == BAILOUT_RETURN_OK;
   405     }
   407     if (!script->hasTrynotes())
   408         return;
   410     JSTryNote *tn = script->trynotes()->vector;
   411     JSTryNote *tnEnd = tn + script->trynotes()->length;
   413     uint32_t pcOffset = uint32_t(pc - script->main());
   414     for (; tn != tnEnd; ++tn) {
   415         if (pcOffset < tn->start)
   416             continue;
   417         if (pcOffset >= tn->start + tn->length)
   418             continue;
   420         switch (tn->kind) {
   421           case JSTRY_ITER: {
   422             JS_ASSERT(JSOp(*(script->main() + tn->start + tn->length)) == JSOP_ENDITER);
   423             JS_ASSERT(tn->stackDepth > 0);
   425             uint32_t localSlot = tn->stackDepth;
   426             CloseLiveIterator(cx, frame, localSlot);
   427             break;
   428           }
   430           case JSTRY_LOOP:
   431             break;
   433           case JSTRY_CATCH:
   434             if (cx->isExceptionPending() && !bailedOutForDebugMode) {
   435                 // Ion can compile try-catch, but bailing out to catch
   436                 // exceptions is slow. Reset the use count so that if we
   437                 // catch many exceptions we won't Ion-compile the script.
   438                 script->resetUseCount();
   440                 // Bailout at the start of the catch block.
   441                 jsbytecode *catchPC = script->main() + tn->start + tn->length;
   442                 ExceptionBailoutInfo excInfo(frame.frameNo(), catchPC, tn->stackDepth);
   443                 uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed);
   444                 if (retval == BAILOUT_RETURN_OK)
   445                     return;
   447                 // Error on bailout clears pending exception.
   448                 MOZ_ASSERT(!cx->isExceptionPending());
   449             }
   450             break;
   452           default:
   453             MOZ_ASSUME_UNREACHABLE("Unexpected try note");
   454         }
   455     }
   456 }
   458 static void
   459 HandleExceptionBaseline(JSContext *cx, const JitFrameIterator &frame, ResumeFromException *rfe,
   460                         bool *calledDebugEpilogue)
   461 {
   462     JS_ASSERT(frame.isBaselineJS());
   463     JS_ASSERT(!*calledDebugEpilogue);
   465     RootedScript script(cx);
   466     jsbytecode *pc;
   467     frame.baselineScriptAndPc(script.address(), &pc);
   469     if (cx->isExceptionPending() && cx->compartment()->debugMode()) {
   470         BaselineFrame *baselineFrame = frame.baselineFrame();
   471         JSTrapStatus status = DebugExceptionUnwind(cx, baselineFrame, pc);
   472         switch (status) {
   473           case JSTRAP_ERROR:
   474             // Uncatchable exception.
   475             JS_ASSERT(!cx->isExceptionPending());
   476             break;
   478           case JSTRAP_CONTINUE:
   479           case JSTRAP_THROW:
   480             JS_ASSERT(cx->isExceptionPending());
   481             break;
   483           case JSTRAP_RETURN:
   484             JS_ASSERT(baselineFrame->hasReturnValue());
   485             if (jit::DebugEpilogue(cx, baselineFrame, pc, true)) {
   486                 rfe->kind = ResumeFromException::RESUME_FORCED_RETURN;
   487                 rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
   488                 rfe->stackPointer = reinterpret_cast<uint8_t *>(baselineFrame);
   489                 return;
   490             }
   492             // DebugEpilogue threw an exception. Propagate to the caller frame.
   493             *calledDebugEpilogue = true;
   494             return;
   496           default:
   497             MOZ_ASSUME_UNREACHABLE("Invalid trap status");
   498         }
   499     }
   501     if (!script->hasTrynotes())
   502         return;
   504     JSTryNote *tn = script->trynotes()->vector;
   505     JSTryNote *tnEnd = tn + script->trynotes()->length;
   507     uint32_t pcOffset = uint32_t(pc - script->main());
   508     ScopeIter si(frame.baselineFrame(), pc, cx);
   509     for (; tn != tnEnd; ++tn) {
   510         if (pcOffset < tn->start)
   511             continue;
   512         if (pcOffset >= tn->start + tn->length)
   513             continue;
   515         // Skip if the try note's stack depth exceeds the frame's stack depth.
   516         // See the big comment in TryNoteIter::settle for more info.
   517         JS_ASSERT(frame.baselineFrame()->numValueSlots() >= script->nfixed());
   518         size_t stackDepth = frame.baselineFrame()->numValueSlots() - script->nfixed();
   519         if (tn->stackDepth > stackDepth)
   520             continue;
   522         // Unwind scope chain (pop block objects).
   523         if (cx->isExceptionPending())
   524             UnwindScope(cx, si, script->main() + tn->start);
   526         // Compute base pointer and stack pointer.
   527         rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
   528         rfe->stackPointer = rfe->framePointer - BaselineFrame::Size() -
   529             (script->nfixed() + tn->stackDepth) * sizeof(Value);
   531         switch (tn->kind) {
   532           case JSTRY_CATCH:
   533             if (cx->isExceptionPending()) {
   534                 // Ion can compile try-catch, but bailing out to catch
   535                 // exceptions is slow. Reset the use count so that if we
   536                 // catch many exceptions we won't Ion-compile the script.
   537                 script->resetUseCount();
   539                 // Resume at the start of the catch block.
   540                 rfe->kind = ResumeFromException::RESUME_CATCH;
   541                 jsbytecode *catchPC = script->main() + tn->start + tn->length;
   542                 rfe->target = script->baselineScript()->nativeCodeForPC(script, catchPC);
   543                 return;
   544             }
   545             break;
   547           case JSTRY_FINALLY:
   548             if (cx->isExceptionPending()) {
   549                 rfe->kind = ResumeFromException::RESUME_FINALLY;
   550                 jsbytecode *finallyPC = script->main() + tn->start + tn->length;
   551                 rfe->target = script->baselineScript()->nativeCodeForPC(script, finallyPC);
   552                 // Drop the exception instead of leaking cross compartment data.
   553                 if (!cx->getPendingException(MutableHandleValue::fromMarkedLocation(&rfe->exception)))
   554                     rfe->exception = UndefinedValue();
   555                 cx->clearPendingException();
   556                 return;
   557             }
   558             break;
   560           case JSTRY_ITER: {
   561             Value iterValue(* (Value *) rfe->stackPointer);
   562             RootedObject iterObject(cx, &iterValue.toObject());
   563             if (cx->isExceptionPending())
   564                 UnwindIteratorForException(cx, iterObject);
   565             else
   566                 UnwindIteratorForUncatchableException(cx, iterObject);
   567             break;
   568           }
   570           case JSTRY_LOOP:
   571             break;
   573           default:
   574             MOZ_ASSUME_UNREACHABLE("Invalid try note");
   575         }
   576     }
   578 }
   580 struct AutoDeleteDebugModeOSRInfo
   581 {
   582     BaselineFrame *frame;
   583     AutoDeleteDebugModeOSRInfo(BaselineFrame *frame) : frame(frame) { MOZ_ASSERT(frame); }
   584     ~AutoDeleteDebugModeOSRInfo() { frame->deleteDebugModeOSRInfo(); }
   585 };
   587 void
   588 HandleException(ResumeFromException *rfe)
   589 {
   590     JSContext *cx = GetJSContextFromJitCode();
   592     rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
   594     IonSpew(IonSpew_Invalidate, "handling exception");
   596     // Clear any Ion return override that's been set.
   597     // This may happen if a callVM function causes an invalidation (setting the
   598     // override), and then fails, bypassing the bailout handlers that would
   599     // otherwise clear the return override.
   600     if (cx->runtime()->hasIonReturnOverride())
   601         cx->runtime()->takeIonReturnOverride();
   603     JitFrameIterator iter(cx);
   604     while (!iter.isEntry()) {
   605         bool overrecursed = false;
   606         if (iter.isIonJS()) {
   607             // Search each inlined frame for live iterator objects, and close
   608             // them.
   609             InlineFrameIterator frames(cx, &iter);
   611             // Invalidation state will be the same for all inlined scripts in the frame.
   612             IonScript *ionScript = nullptr;
   613             bool invalidated = iter.checkInvalidation(&ionScript);
   615             for (;;) {
   616                 HandleExceptionIon(cx, frames, rfe, &overrecursed);
   618                 if (rfe->kind == ResumeFromException::RESUME_BAILOUT) {
   619                     if (invalidated)
   620                         ionScript->decref(cx->runtime()->defaultFreeOp());
   621                     return;
   622                 }
   624                 JS_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME);
   626                 // Figure out whether SPS frame was pushed for this frame or not.
   627                 // Even if profiler is enabled, the frame being popped might have
   628                 // been entered prior to SPS being enabled, and thus not have
   629                 // a pushed SPS frame.
   630                 bool popSPSFrame = cx->runtime()->spsProfiler.enabled();
   631                 if (invalidated)
   632                     popSPSFrame = ionScript->hasSPSInstrumentation();
   634                 // If inline-frames are not profiled, then don't pop an SPS frame
   635                 // for them.
   636                 if (frames.more() && !js_JitOptions.profileInlineFrames)
   637                     popSPSFrame = false;
   639                 // When profiling, each frame popped needs a notification that
   640                 // the function has exited, so invoke the probe that a function
   641                 // is exiting.
   642                 JSScript *script = frames.script();
   643                 probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
   644                 if (!frames.more())
   645                     break;
   646                 ++frames;
   647             }
   649             if (invalidated)
   650                 ionScript->decref(cx->runtime()->defaultFreeOp());
   652         } else if (iter.isBaselineJS()) {
   653             // It's invalid to call DebugEpilogue twice for the same frame.
   654             bool calledDebugEpilogue = false;
   656             HandleExceptionBaseline(cx, iter, rfe, &calledDebugEpilogue);
   658             // If we are propagating an exception through a frame with
   659             // on-stack recompile info, we should free the allocated
   660             // RecompileInfo struct before we leave this block, as we will not
   661             // be returning to the recompile handler.
   662             //
   663             // We cannot delete it immediately because of the call to
   664             // iter.baselineScriptAndPc below.
   665             AutoDeleteDebugModeOSRInfo deleteDebugModeOSRInfo(iter.baselineFrame());
   667             if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
   668                 return;
   670             // Unwind profiler pseudo-stack
   671             JSScript *script = iter.script();
   672             probes::ExitScript(cx, script, script->functionNonDelazifying(),
   673                                iter.baselineFrame()->hasPushedSPSFrame());
   674             // After this point, any pushed SPS frame would have been popped if it needed
   675             // to be.  Unset the flag here so that if we call DebugEpilogue below,
   676             // it doesn't try to pop the SPS frame again.
   677             iter.baselineFrame()->unsetPushedSPSFrame();
   679             if (cx->compartment()->debugMode() && !calledDebugEpilogue) {
   680                 // If DebugEpilogue returns |true|, we have to perform a forced
   681                 // return, e.g. return frame->returnValue() to the caller.
   682                 BaselineFrame *frame = iter.baselineFrame();
   683                 RootedScript script(cx);
   684                 jsbytecode *pc;
   685                 iter.baselineScriptAndPc(script.address(), &pc);
   686                 if (jit::DebugEpilogue(cx, frame, pc, false)) {
   687                     JS_ASSERT(frame->hasReturnValue());
   688                     rfe->kind = ResumeFromException::RESUME_FORCED_RETURN;
   689                     rfe->framePointer = iter.fp() - BaselineFrame::FramePointerOffset;
   690                     rfe->stackPointer = reinterpret_cast<uint8_t *>(frame);
   691                     return;
   692                 }
   693             }
   694         }
   696         IonJSFrameLayout *current = iter.isScripted() ? iter.jsFrame() : nullptr;
   698         ++iter;
   700         if (current) {
   701             // Unwind the frame by updating ionTop. This is necessary so that
   702             // (1) debugger exception unwind and leave frame hooks don't see this
   703             // frame when they use ScriptFrameIter, and (2) ScriptFrameIter does
   704             // not crash when accessing an IonScript that's destroyed by the
   705             // ionScript->decref call.
   706             EnsureExitFrame(current);
   707             cx->mainThread().ionTop = (uint8_t *)current;
   708         }
   710         if (overrecursed) {
   711             // We hit an overrecursion error during bailout. Report it now.
   712             js_ReportOverRecursed(cx);
   713         }
   714     }
   716     rfe->stackPointer = iter.fp();
   717 }
   719 void
   720 HandleParallelFailure(ResumeFromException *rfe)
   721 {
   722     ForkJoinContext *cx = ForkJoinContext::current();
   723     JitFrameIterator iter(cx->perThreadData->ionTop, ParallelExecution);
   725     parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry");
   727     while (!iter.isEntry()) {
   728         if (iter.isScripted()) {
   729             cx->bailoutRecord->updateCause(ParallelBailoutUnsupportedVM,
   730                                            iter.script(), iter.script(), nullptr);
   731             break;
   732         }
   733         ++iter;
   734     }
   736     while (!iter.isEntry()) {
   737         if (iter.isScripted())
   738             PropagateAbortPar(iter.script(), iter.script());
   739         ++iter;
   740     }
   742     rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
   743     rfe->stackPointer = iter.fp();
   744 }
   746 void
   747 EnsureExitFrame(IonCommonFrameLayout *frame)
   748 {
   749     if (frame->prevType() == JitFrame_Unwound_IonJS ||
   750         frame->prevType() == JitFrame_Unwound_BaselineStub ||
   751         frame->prevType() == JitFrame_Unwound_Rectifier)
   752     {
   753         // Already an exit frame, nothing to do.
   754         return;
   755     }
   757     if (frame->prevType() == JitFrame_Entry) {
   758         // The previous frame type is the entry frame, so there's no actual
   759         // need for an exit frame.
   760         return;
   761     }
   763     if (frame->prevType() == JitFrame_Rectifier) {
   764         // The rectifier code uses the frame descriptor to discard its stack,
   765         // so modifying its descriptor size here would be dangerous. Instead,
   766         // we change the frame type, and teach the stack walking code how to
   767         // deal with this edge case. bug 717297 would obviate the need
   768         frame->changePrevType(JitFrame_Unwound_Rectifier);
   769         return;
   770     }
   772     if (frame->prevType() == JitFrame_BaselineStub) {
   773         frame->changePrevType(JitFrame_Unwound_BaselineStub);
   774         return;
   775     }
   777     JS_ASSERT(frame->prevType() == JitFrame_IonJS);
   778     frame->changePrevType(JitFrame_Unwound_IonJS);
   779 }
   781 CalleeToken
   782 MarkCalleeToken(JSTracer *trc, CalleeToken token)
   783 {
   784     switch (GetCalleeTokenTag(token)) {
   785       case CalleeToken_Function:
   786       {
   787         JSFunction *fun = CalleeTokenToFunction(token);
   788         MarkObjectRoot(trc, &fun, "ion-callee");
   789         return CalleeToToken(fun);
   790       }
   791       case CalleeToken_Script:
   792       {
   793         JSScript *script = CalleeTokenToScript(token);
   794         MarkScriptRoot(trc, &script, "ion-entry");
   795         return CalleeToToken(script);
   796       }
   797       default:
   798         MOZ_ASSUME_UNREACHABLE("unknown callee token type");
   799     }
   800 }
   802 #ifdef JS_NUNBOX32
   803 static inline uintptr_t
   804 ReadAllocation(const JitFrameIterator &frame, const LAllocation *a)
   805 {
   806     if (a->isGeneralReg()) {
   807         Register reg = a->toGeneralReg()->reg();
   808         return frame.machineState().read(reg);
   809     }
   810     if (a->isStackSlot()) {
   811         uint32_t slot = a->toStackSlot()->slot();
   812         return *frame.jsFrame()->slotRef(slot);
   813     }
   814     uint32_t index = a->toArgument()->index();
   815     uint8_t *argv = reinterpret_cast<uint8_t *>(frame.jsFrame()->argv());
   816     return *reinterpret_cast<uintptr_t *>(argv + index);
   817 }
   818 #endif
   820 static void
   821 MarkActualArguments(JSTracer *trc, const JitFrameIterator &frame)
   822 {
   823     IonJSFrameLayout *layout = frame.jsFrame();
   824     JS_ASSERT(CalleeTokenIsFunction(layout->calleeToken()));
   826     size_t nargs = frame.numActualArgs();
   828     // Trace function arguments. Note + 1 for thisv.
   829     Value *argv = layout->argv();
   830     for (size_t i = 0; i < nargs + 1; i++)
   831         gc::MarkValueRoot(trc, &argv[i], "ion-argv");
   832 }
   834 #ifdef JS_NUNBOX32
   835 static inline void
   836 WriteAllocation(const JitFrameIterator &frame, const LAllocation *a, uintptr_t value)
   837 {
   838     if (a->isGeneralReg()) {
   839         Register reg = a->toGeneralReg()->reg();
   840         frame.machineState().write(reg, value);
   841         return;
   842     }
   843     if (a->isStackSlot()) {
   844         uint32_t slot = a->toStackSlot()->slot();
   845         *frame.jsFrame()->slotRef(slot) = value;
   846         return;
   847     }
   848     uint32_t index = a->toArgument()->index();
   849     uint8_t *argv = reinterpret_cast<uint8_t *>(frame.jsFrame()->argv());
   850     *reinterpret_cast<uintptr_t *>(argv + index) = value;
   851 }
   852 #endif
   854 static void
   855 MarkIonJSFrame(JSTracer *trc, const JitFrameIterator &frame)
   856 {
   857     IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp();
   859     layout->replaceCalleeToken(MarkCalleeToken(trc, layout->calleeToken()));
   861     IonScript *ionScript = nullptr;
   862     if (frame.checkInvalidation(&ionScript)) {
   863         // This frame has been invalidated, meaning that its IonScript is no
   864         // longer reachable through the callee token (JSFunction/JSScript->ion
   865         // is now nullptr or recompiled). Manually trace it here.
   866         IonScript::Trace(trc, ionScript);
   867     } else if (CalleeTokenIsFunction(layout->calleeToken())) {
   868         ionScript = CalleeTokenToFunction(layout->calleeToken())->nonLazyScript()->ionScript();
   869     } else {
   870         ionScript = CalleeTokenToScript(layout->calleeToken())->ionScript();
   871     }
   873     if (CalleeTokenIsFunction(layout->calleeToken()))
   874         MarkActualArguments(trc, frame);
   876     const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp());
   878     SafepointReader safepoint(ionScript, si);
   880     // Scan through slots which contain pointers (or on punboxing systems,
   881     // actual values).
   882     uint32_t slot;
   883     while (safepoint.getGcSlot(&slot)) {
   884         uintptr_t *ref = layout->slotRef(slot);
   885         gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(ref), "ion-gc-slot");
   886     }
   888     while (safepoint.getValueSlot(&slot)) {
   889         Value *v = (Value *)layout->slotRef(slot);
   890         gc::MarkValueRoot(trc, v, "ion-gc-slot");
   891     }
   893     uintptr_t *spill = frame.spillBase();
   894     GeneralRegisterSet gcRegs = safepoint.gcSpills();
   895     GeneralRegisterSet valueRegs = safepoint.valueSpills();
   896     for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
   897         --spill;
   898         if (gcRegs.has(*iter))
   899             gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(spill), "ion-gc-spill");
   900         else if (valueRegs.has(*iter))
   901             gc::MarkValueRoot(trc, reinterpret_cast<Value *>(spill), "ion-value-spill");
   902     }
   904 #ifdef JS_NUNBOX32
   905     LAllocation type, payload;
   906     while (safepoint.getNunboxSlot(&type, &payload)) {
   907         jsval_layout layout;
   908         layout.s.tag = (JSValueTag)ReadAllocation(frame, &type);
   909         layout.s.payload.uintptr = ReadAllocation(frame, &payload);
   911         Value v = IMPL_TO_JSVAL(layout);
   912         gc::MarkValueRoot(trc, &v, "ion-torn-value");
   914         if (v != IMPL_TO_JSVAL(layout)) {
   915             // GC moved the value, replace the stored payload.
   916             layout = JSVAL_TO_IMPL(v);
   917             WriteAllocation(frame, &payload, layout.s.payload.uintptr);
   918         }
   919     }
   920 #endif
   921 }
   923 #ifdef JSGC_GENERATIONAL
   924 static void
   925 UpdateIonJSFrameForMinorGC(JSTracer *trc, const JitFrameIterator &frame)
   926 {
   927     // Minor GCs may move slots/elements allocated in the nursery. Update
   928     // any slots/elements pointers stored in this frame.
   930     IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp();
   932     IonScript *ionScript = nullptr;
   933     if (frame.checkInvalidation(&ionScript)) {
   934         // This frame has been invalidated, meaning that its IonScript is no
   935         // longer reachable through the callee token (JSFunction/JSScript->ion
   936         // is now nullptr or recompiled).
   937     } else if (CalleeTokenIsFunction(layout->calleeToken())) {
   938         ionScript = CalleeTokenToFunction(layout->calleeToken())->nonLazyScript()->ionScript();
   939     } else {
   940         ionScript = CalleeTokenToScript(layout->calleeToken())->ionScript();
   941     }
   943     const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp());
   944     SafepointReader safepoint(ionScript, si);
   946     GeneralRegisterSet slotsRegs = safepoint.slotsOrElementsSpills();
   947     uintptr_t *spill = frame.spillBase();
   948     for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
   949         --spill;
   950         if (slotsRegs.has(*iter))
   951             trc->runtime()->gcNursery.forwardBufferPointer(reinterpret_cast<HeapSlot **>(spill));
   952     }
   954     // Skip to the right place in the safepoint
   955     uint32_t slot;
   956     while (safepoint.getGcSlot(&slot));
   957     while (safepoint.getValueSlot(&slot));
   958 #ifdef JS_NUNBOX32
   959     LAllocation type, payload;
   960     while (safepoint.getNunboxSlot(&type, &payload));
   961 #endif
   963     while (safepoint.getSlotsOrElementsSlot(&slot)) {
   964         HeapSlot **slots = reinterpret_cast<HeapSlot **>(layout->slotRef(slot));
   965         trc->runtime()->gcNursery.forwardBufferPointer(slots);
   966     }
   967 }
   968 #endif
   970 static void
   971 MarkBaselineStubFrame(JSTracer *trc, const JitFrameIterator &frame)
   972 {
   973     // Mark the ICStub pointer stored in the stub frame. This is necessary
   974     // so that we don't destroy the stub code after unlinking the stub.
   976     JS_ASSERT(frame.type() == JitFrame_BaselineStub);
   977     IonBaselineStubFrameLayout *layout = (IonBaselineStubFrameLayout *)frame.fp();
   979     if (ICStub *stub = layout->maybeStubPtr()) {
   980         JS_ASSERT(ICStub::CanMakeCalls(stub->kind()));
   981         stub->trace(trc);
   982     }
   983 }
   985 void
   986 JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
   987 {
   988     JitFrameIterator frames(jitTop(), SequentialExecution);
   990     if (frames.isFakeExitFrame()) {
   991         min = reinterpret_cast<uintptr_t *>(frames.fp());
   992     } else {
   993         IonExitFrameLayout *exitFrame = frames.exitFrame();
   994         IonExitFooterFrame *footer = exitFrame->footer();
   995         const VMFunction *f = footer->function();
   996         if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) {
   997             switch (f->outParamRootType) {
   998               case VMFunction::RootNone:
   999                 MOZ_ASSUME_UNREACHABLE("Handle outparam must have root type");
  1000               case VMFunction::RootObject:
  1001               case VMFunction::RootString:
  1002               case VMFunction::RootPropertyName:
  1003               case VMFunction::RootFunction:
  1004               case VMFunction::RootCell:
  1005                 // These are all handles to GCThing pointers.
  1006                 min = reinterpret_cast<uintptr_t *>(footer->outParam<void *>());
  1007                 break;
  1008               case VMFunction::RootValue:
  1009                 min = reinterpret_cast<uintptr_t *>(footer->outParam<Value>());
  1010                 break;
  1012         } else {
  1013             min = reinterpret_cast<uintptr_t *>(footer);
  1017     while (!frames.done())
  1018         ++frames;
  1020     end = reinterpret_cast<uintptr_t *>(frames.prevFp());
  1023 static void
  1024 MarkJitExitFrame(JSTracer *trc, const JitFrameIterator &frame)
  1026     // Ignore fake exit frames created by EnsureExitFrame.
  1027     if (frame.isFakeExitFrame())
  1028         return;
  1030     IonExitFooterFrame *footer = frame.exitFrame()->footer();
  1032     // Mark the code of the code handling the exit path.  This is needed because
  1033     // invalidated script are no longer marked because data are erased by the
  1034     // invalidation and relocation data are no longer reliable.  So the VM
  1035     // wrapper or the invalidation code may be GC if no JitCode keep reference
  1036     // on them.
  1037     JS_ASSERT(uintptr_t(footer->jitCode()) != uintptr_t(-1));
  1039     // This correspond to the case where we have build a fake exit frame in
  1040     // CodeGenerator.cpp which handle the case of a native function call. We
  1041     // need to mark the argument vector of the function call.
  1042     if (frame.isNative()) {
  1043         IonNativeExitFrameLayout *native = frame.exitFrame()->nativeExit();
  1044         size_t len = native->argc() + 2;
  1045         Value *vp = native->vp();
  1046         gc::MarkValueRootRange(trc, len, vp, "ion-native-args");
  1047         return;
  1050     if (frame.isOOLNative()) {
  1051         IonOOLNativeExitFrameLayout *oolnative = frame.exitFrame()->oolNativeExit();
  1052         gc::MarkJitCodeRoot(trc, oolnative->stubCode(), "ion-ool-native-code");
  1053         gc::MarkValueRoot(trc, oolnative->vp(), "iol-ool-native-vp");
  1054         size_t len = oolnative->argc() + 1;
  1055         gc::MarkValueRootRange(trc, len, oolnative->thisp(), "ion-ool-native-thisargs");
  1056         return;
  1059     if (frame.isOOLPropertyOp()) {
  1060         IonOOLPropertyOpExitFrameLayout *oolgetter = frame.exitFrame()->oolPropertyOpExit();
  1061         gc::MarkJitCodeRoot(trc, oolgetter->stubCode(), "ion-ool-property-op-code");
  1062         gc::MarkValueRoot(trc, oolgetter->vp(), "ion-ool-property-op-vp");
  1063         gc::MarkIdRoot(trc, oolgetter->id(), "ion-ool-property-op-id");
  1064         gc::MarkObjectRoot(trc, oolgetter->obj(), "ion-ool-property-op-obj");
  1065         return;
  1068     if (frame.isOOLProxy()) {
  1069         IonOOLProxyExitFrameLayout *oolproxy = frame.exitFrame()->oolProxyExit();
  1070         gc::MarkJitCodeRoot(trc, oolproxy->stubCode(), "ion-ool-proxy-code");
  1071         gc::MarkValueRoot(trc, oolproxy->vp(), "ion-ool-proxy-vp");
  1072         gc::MarkIdRoot(trc, oolproxy->id(), "ion-ool-proxy-id");
  1073         gc::MarkObjectRoot(trc, oolproxy->proxy(), "ion-ool-proxy-proxy");
  1074         gc::MarkObjectRoot(trc, oolproxy->receiver(), "ion-ool-proxy-receiver");
  1075         return;
  1078     if (frame.isDOMExit()) {
  1079         IonDOMExitFrameLayout *dom = frame.exitFrame()->DOMExit();
  1080         gc::MarkObjectRoot(trc, dom->thisObjAddress(), "ion-dom-args");
  1081         if (dom->isMethodFrame()) {
  1082             IonDOMMethodExitFrameLayout *method =
  1083                 reinterpret_cast<IonDOMMethodExitFrameLayout *>(dom);
  1084             size_t len = method->argc() + 2;
  1085             Value *vp = method->vp();
  1086             gc::MarkValueRootRange(trc, len, vp, "ion-dom-args");
  1087         } else {
  1088             gc::MarkValueRoot(trc, dom->vp(), "ion-dom-args");
  1090         return;
  1093     MarkJitCodeRoot(trc, footer->addressOfJitCode(), "ion-exit-code");
  1095     const VMFunction *f = footer->function();
  1096     if (f == nullptr)
  1097         return;
  1099     // Mark arguments of the VM wrapper.
  1100     uint8_t *argBase = frame.exitFrame()->argBase();
  1101     for (uint32_t explicitArg = 0; explicitArg < f->explicitArgs; explicitArg++) {
  1102         switch (f->argRootType(explicitArg)) {
  1103           case VMFunction::RootNone:
  1104             break;
  1105           case VMFunction::RootObject: {
  1106             // Sometimes we can bake in HandleObjects to nullptr.
  1107             JSObject **pobj = reinterpret_cast<JSObject **>(argBase);
  1108             if (*pobj)
  1109                 gc::MarkObjectRoot(trc, pobj, "ion-vm-args");
  1110             break;
  1112           case VMFunction::RootString:
  1113           case VMFunction::RootPropertyName:
  1114             gc::MarkStringRoot(trc, reinterpret_cast<JSString**>(argBase), "ion-vm-args");
  1115             break;
  1116           case VMFunction::RootFunction:
  1117             gc::MarkObjectRoot(trc, reinterpret_cast<JSFunction**>(argBase), "ion-vm-args");
  1118             break;
  1119           case VMFunction::RootValue:
  1120             gc::MarkValueRoot(trc, reinterpret_cast<Value*>(argBase), "ion-vm-args");
  1121             break;
  1122           case VMFunction::RootCell:
  1123             gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(argBase), "ion-vm-args");
  1124             break;
  1127         switch (f->argProperties(explicitArg)) {
  1128           case VMFunction::WordByValue:
  1129           case VMFunction::WordByRef:
  1130             argBase += sizeof(void *);
  1131             break;
  1132           case VMFunction::DoubleByValue:
  1133           case VMFunction::DoubleByRef:
  1134             argBase += 2 * sizeof(void *);
  1135             break;
  1139     if (f->outParam == Type_Handle) {
  1140         switch (f->outParamRootType) {
  1141           case VMFunction::RootNone:
  1142             MOZ_ASSUME_UNREACHABLE("Handle outparam must have root type");
  1143           case VMFunction::RootObject:
  1144             gc::MarkObjectRoot(trc, footer->outParam<JSObject *>(), "ion-vm-out");
  1145             break;
  1146           case VMFunction::RootString:
  1147           case VMFunction::RootPropertyName:
  1148             gc::MarkStringRoot(trc, footer->outParam<JSString *>(), "ion-vm-out");
  1149             break;
  1150           case VMFunction::RootFunction:
  1151             gc::MarkObjectRoot(trc, footer->outParam<JSFunction *>(), "ion-vm-out");
  1152             break;
  1153           case VMFunction::RootValue:
  1154             gc::MarkValueRoot(trc, footer->outParam<Value>(), "ion-vm-outvp");
  1155             break;
  1156           case VMFunction::RootCell:
  1157             gc::MarkGCThingRoot(trc, footer->outParam<void *>(), "ion-vm-out");
  1158             break;
  1163 static void
  1164 MarkRectifierFrame(JSTracer *trc, const JitFrameIterator &frame)
  1166     // Mark thisv.
  1167     //
  1168     // Baseline JIT code generated as part of the ICCall_Fallback stub may use
  1169     // it if we're calling a constructor that returns a primitive value.
  1170     IonRectifierFrameLayout *layout = (IonRectifierFrameLayout *)frame.fp();
  1171     gc::MarkValueRoot(trc, &layout->argv()[0], "ion-thisv");
  1174 static void
  1175 MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
  1177     JitActivation *activation = activations->asJit();
  1179 #ifdef CHECK_OSIPOINT_REGISTERS
  1180     if (js_JitOptions.checkOsiPointRegisters) {
  1181         // GC can modify spilled registers, breaking our register checks.
  1182         // To handle this, we disable these checks for the current VM call
  1183         // when a GC happens.
  1184         activation->setCheckRegs(false);
  1186 #endif
  1188     activation->markRematerializedFrames(trc);
  1190     for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
  1191         switch (frames.type()) {
  1192           case JitFrame_Exit:
  1193             MarkJitExitFrame(trc, frames);
  1194             break;
  1195           case JitFrame_BaselineJS:
  1196             frames.baselineFrame()->trace(trc, frames);
  1197             break;
  1198           case JitFrame_BaselineStub:
  1199             MarkBaselineStubFrame(trc, frames);
  1200             break;
  1201           case JitFrame_IonJS:
  1202             MarkIonJSFrame(trc, frames);
  1203             break;
  1204           case JitFrame_Unwound_IonJS:
  1205             MOZ_ASSUME_UNREACHABLE("invalid");
  1206           case JitFrame_Rectifier:
  1207             MarkRectifierFrame(trc, frames);
  1208             break;
  1209           case JitFrame_Unwound_Rectifier:
  1210             break;
  1211           default:
  1212             MOZ_ASSUME_UNREACHABLE("unexpected frame type");
  1217 void
  1218 MarkJitActivations(JSRuntime *rt, JSTracer *trc)
  1220     for (JitActivationIterator activations(rt); !activations.done(); ++activations)
  1221         MarkJitActivation(trc, activations);
  1224 #ifdef JSGC_GENERATIONAL
  1225 void
  1226 UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc)
  1228     JS_ASSERT(trc->runtime()->isHeapMinorCollecting());
  1229     for (JitActivationIterator activations(rt); !activations.done(); ++activations) {
  1230         for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
  1231             if (frames.type() == JitFrame_IonJS)
  1232                 UpdateIonJSFrameForMinorGC(trc, frames);
  1236 #endif
  1238 void
  1239 AutoTempAllocatorRooter::trace(JSTracer *trc)
  1241     for (CompilerRootNode *root = temp->rootList(); root != nullptr; root = root->next)
  1242         gc::MarkGCThingRoot(trc, root->address(), "ion-compiler-root");
  1245 void
  1246 GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
  1248     IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
  1250     JSRuntime *rt = cx->runtime();
  1252     // Recover the return address.
  1253     JitFrameIterator it(rt->mainThread.ionTop, SequentialExecution);
  1255     // If the previous frame is a rectifier frame (maybe unwound),
  1256     // skip past it.
  1257     if (it.prevType() == JitFrame_Rectifier || it.prevType() == JitFrame_Unwound_Rectifier) {
  1258         ++it;
  1259         JS_ASSERT(it.prevType() == JitFrame_BaselineStub ||
  1260                   it.prevType() == JitFrame_BaselineJS ||
  1261                   it.prevType() == JitFrame_IonJS);
  1264     // If the previous frame is a stub frame, skip the exit frame so that
  1265     // returnAddress below gets the return address into the BaselineJS
  1266     // frame.
  1267     if (it.prevType() == JitFrame_BaselineStub || it.prevType() == JitFrame_Unwound_BaselineStub) {
  1268         ++it;
  1269         JS_ASSERT(it.prevType() == JitFrame_BaselineJS);
  1272     uint8_t *retAddr = it.returnAddress();
  1273     uint32_t hash = PcScriptCache::Hash(retAddr);
  1274     JS_ASSERT(retAddr != nullptr);
  1276     // Lazily initialize the cache. The allocation may safely fail and will not GC.
  1277     if (MOZ_UNLIKELY(rt->ionPcScriptCache == nullptr)) {
  1278         rt->ionPcScriptCache = (PcScriptCache *)js_malloc(sizeof(struct PcScriptCache));
  1279         if (rt->ionPcScriptCache)
  1280             rt->ionPcScriptCache->clear(rt->gcNumber);
  1283     // Attempt to lookup address in cache.
  1284     if (rt->ionPcScriptCache && rt->ionPcScriptCache->get(rt, hash, retAddr, scriptRes, pcRes))
  1285         return;
  1287     // Lookup failed: undertake expensive process to recover the innermost inlined frame.
  1288     ++it; // Skip exit frame.
  1289     jsbytecode *pc = nullptr;
  1291     if (it.isIonJS()) {
  1292         InlineFrameIterator ifi(cx, &it);
  1293         *scriptRes = ifi.script();
  1294         pc = ifi.pc();
  1295     } else {
  1296         JS_ASSERT(it.isBaselineJS());
  1297         it.baselineScriptAndPc(scriptRes, &pc);
  1300     if (pcRes)
  1301         *pcRes = pc;
  1303     // Add entry to cache.
  1304     if (rt->ionPcScriptCache)
  1305         rt->ionPcScriptCache->add(hash, retAddr, pc, *scriptRes);
  1308 void
  1309 OsiIndex::fixUpOffset(MacroAssembler &masm)
  1311     callPointDisplacement_ = masm.actualOffset(callPointDisplacement_);
  1314 uint32_t
  1315 OsiIndex::returnPointDisplacement() const
  1317     // In general, pointer arithmetic on code is bad, but in this case,
  1318     // getting the return address from a call instruction, stepping over pools
  1319     // would be wrong.
  1320     return callPointDisplacement_ + Assembler::patchWrite_NearCallSize();
  1323 SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
  1324                                    IonJSFrameLayout *fp, const MachineState &machine)
  1325   : snapshot_(ionScript->snapshots(),
  1326               snapshotOffset,
  1327               ionScript->snapshotsRVATableSize(),
  1328               ionScript->snapshotsListSize()),
  1329     recover_(snapshot_,
  1330              ionScript->recovers(),
  1331              ionScript->recoversSize()),
  1332     fp_(fp),
  1333     machine_(machine),
  1334     ionScript_(ionScript)
  1336     JS_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
  1339 SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
  1340   : snapshot_(iter.ionScript()->snapshots(),
  1341               iter.osiIndex()->snapshotOffset(),
  1342               iter.ionScript()->snapshotsRVATableSize(),
  1343               iter.ionScript()->snapshotsListSize()),
  1344     recover_(snapshot_,
  1345              iter.ionScript()->recovers(),
  1346              iter.ionScript()->recoversSize()),
  1347     fp_(iter.jsFrame()),
  1348     machine_(iter.machineState()),
  1349     ionScript_(iter.ionScript())
  1353 SnapshotIterator::SnapshotIterator()
  1354   : snapshot_(nullptr, 0, 0, 0),
  1355     recover_(snapshot_, nullptr, 0),
  1356     fp_(nullptr),
  1357     ionScript_(nullptr)
  1361 uintptr_t
  1362 SnapshotIterator::fromStack(int32_t offset) const
  1364     return ReadFrameSlot(fp_, offset);
  1367 static Value
  1368 FromObjectPayload(uintptr_t payload)
  1370     return ObjectValue(*reinterpret_cast<JSObject *>(payload));
  1373 static Value
  1374 FromStringPayload(uintptr_t payload)
  1376     return StringValue(reinterpret_cast<JSString *>(payload));
  1379 static Value
  1380 FromTypedPayload(JSValueType type, uintptr_t payload)
  1382     switch (type) {
  1383       case JSVAL_TYPE_INT32:
  1384         return Int32Value(payload);
  1385       case JSVAL_TYPE_BOOLEAN:
  1386         return BooleanValue(!!payload);
  1387       case JSVAL_TYPE_STRING:
  1388         return FromStringPayload(payload);
  1389       case JSVAL_TYPE_OBJECT:
  1390         return FromObjectPayload(payload);
  1391       default:
  1392         MOZ_ASSUME_UNREACHABLE("unexpected type - needs payload");
  1396 bool
  1397 SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
  1399     switch (alloc.mode()) {
  1400       case RValueAllocation::DOUBLE_REG:
  1401         return hasRegister(alloc.fpuReg());
  1403       case RValueAllocation::TYPED_REG:
  1404         return hasRegister(alloc.reg2());
  1406 #if defined(JS_NUNBOX32)
  1407       case RValueAllocation::UNTYPED_REG_REG:
  1408         return hasRegister(alloc.reg()) && hasRegister(alloc.reg2());
  1409       case RValueAllocation::UNTYPED_REG_STACK:
  1410         return hasRegister(alloc.reg()) && hasStack(alloc.stackOffset2());
  1411       case RValueAllocation::UNTYPED_STACK_REG:
  1412         return hasStack(alloc.stackOffset()) && hasRegister(alloc.reg2());
  1413       case RValueAllocation::UNTYPED_STACK_STACK:
  1414         return hasStack(alloc.stackOffset()) && hasStack(alloc.stackOffset2());
  1415 #elif defined(JS_PUNBOX64)
  1416       case RValueAllocation::UNTYPED_REG:
  1417         return hasRegister(alloc.reg());
  1418       case RValueAllocation::UNTYPED_STACK:
  1419         return hasStack(alloc.stackOffset());
  1420 #endif
  1422       default:
  1423         return true;
  1427 Value
  1428 SnapshotIterator::allocationValue(const RValueAllocation &alloc)
  1430     switch (alloc.mode()) {
  1431       case RValueAllocation::CONSTANT:
  1432         return ionScript_->getConstant(alloc.index());
  1434       case RValueAllocation::CST_UNDEFINED:
  1435         return UndefinedValue();
  1437       case RValueAllocation::CST_NULL:
  1438         return NullValue();
  1440       case RValueAllocation::DOUBLE_REG:
  1441         return DoubleValue(fromRegister(alloc.fpuReg()));
  1443       case RValueAllocation::FLOAT32_REG:
  1445         union {
  1446             double d;
  1447             float f;
  1448         } pun;
  1449         pun.d = fromRegister(alloc.fpuReg());
  1450         // The register contains the encoding of a float32. We just read
  1451         // the bits without making any conversion.
  1452         return Float32Value(pun.f);
  1455       case RValueAllocation::FLOAT32_STACK:
  1456         return Float32Value(ReadFrameFloat32Slot(fp_, alloc.stackOffset()));
  1458       case RValueAllocation::TYPED_REG:
  1459         return FromTypedPayload(alloc.knownType(), fromRegister(alloc.reg2()));
  1461       case RValueAllocation::TYPED_STACK:
  1463         switch (alloc.knownType()) {
  1464           case JSVAL_TYPE_DOUBLE:
  1465             return DoubleValue(ReadFrameDoubleSlot(fp_, alloc.stackOffset2()));
  1466           case JSVAL_TYPE_INT32:
  1467             return Int32Value(ReadFrameInt32Slot(fp_, alloc.stackOffset2()));
  1468           case JSVAL_TYPE_BOOLEAN:
  1469             return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset2()));
  1470           case JSVAL_TYPE_STRING:
  1471             return FromStringPayload(fromStack(alloc.stackOffset2()));
  1472           case JSVAL_TYPE_OBJECT:
  1473             return FromObjectPayload(fromStack(alloc.stackOffset2()));
  1474           default:
  1475             MOZ_ASSUME_UNREACHABLE("Unexpected type");
  1479 #if defined(JS_NUNBOX32)
  1480       case RValueAllocation::UNTYPED_REG_REG:
  1482         jsval_layout layout;
  1483         layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
  1484         layout.s.payload.word = fromRegister(alloc.reg2());
  1485         return IMPL_TO_JSVAL(layout);
  1488       case RValueAllocation::UNTYPED_REG_STACK:
  1490         jsval_layout layout;
  1491         layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
  1492         layout.s.payload.word = fromStack(alloc.stackOffset2());
  1493         return IMPL_TO_JSVAL(layout);
  1496       case RValueAllocation::UNTYPED_STACK_REG:
  1498         jsval_layout layout;
  1499         layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
  1500         layout.s.payload.word = fromRegister(alloc.reg2());
  1501         return IMPL_TO_JSVAL(layout);
  1504       case RValueAllocation::UNTYPED_STACK_STACK:
  1506         jsval_layout layout;
  1507         layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
  1508         layout.s.payload.word = fromStack(alloc.stackOffset2());
  1509         return IMPL_TO_JSVAL(layout);
  1511 #elif defined(JS_PUNBOX64)
  1512       case RValueAllocation::UNTYPED_REG:
  1514         jsval_layout layout;
  1515         layout.asBits = fromRegister(alloc.reg());
  1516         return IMPL_TO_JSVAL(layout);
  1519       case RValueAllocation::UNTYPED_STACK:
  1521         jsval_layout layout;
  1522         layout.asBits = fromStack(alloc.stackOffset());
  1523         return IMPL_TO_JSVAL(layout);
  1525 #endif
  1527       default:
  1528         MOZ_ASSUME_UNREACHABLE("huh?");
  1532 const RResumePoint *
  1533 SnapshotIterator::resumePoint() const
  1535     return instruction()->toResumePoint();
  1538 uint32_t
  1539 SnapshotIterator::numAllocations() const
  1541     return resumePoint()->numOperands();
  1544 uint32_t
  1545 SnapshotIterator::pcOffset() const
  1547     return resumePoint()->pcOffset();
  1550 void
  1551 SnapshotIterator::skipInstruction()
  1553     MOZ_ASSERT(snapshot_.numAllocationsRead() == 0);
  1554     size_t numOperands = instruction()->numOperands();
  1555     for (size_t i = 0; i < numOperands; i++)
  1556         skip();
  1557     nextInstruction();
  1560 void
  1561 SnapshotIterator::nextFrame()
  1563     nextInstruction();
  1564     while (!instruction()->isResumePoint())
  1565         skipInstruction();
  1568 IonScript *
  1569 JitFrameIterator::ionScript() const
  1571     JS_ASSERT(type() == JitFrame_IonJS);
  1573     IonScript *ionScript = nullptr;
  1574     if (checkInvalidation(&ionScript))
  1575         return ionScript;
  1576     switch (GetCalleeTokenTag(calleeToken())) {
  1577       case CalleeToken_Function:
  1578       case CalleeToken_Script:
  1579         return mode_ == ParallelExecution ? script()->parallelIonScript() : script()->ionScript();
  1580       default:
  1581         MOZ_ASSUME_UNREACHABLE("unknown callee token type");
  1585 const SafepointIndex *
  1586 JitFrameIterator::safepoint() const
  1588     if (!cachedSafepointIndex_)
  1589         cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp());
  1590     return cachedSafepointIndex_;
  1593 const OsiIndex *
  1594 JitFrameIterator::osiIndex() const
  1596     SafepointReader reader(ionScript(), safepoint());
  1597     return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
  1600 template <AllowGC allowGC>
  1601 void
  1602 InlineFrameIteratorMaybeGC<allowGC>::resetOn(const JitFrameIterator *iter)
  1604     frame_ = iter;
  1605     framesRead_ = 0;
  1606     frameCount_ = UINT32_MAX;
  1608     if (iter) {
  1609         start_ = SnapshotIterator(*iter);
  1610         findNextFrame();
  1613 template void InlineFrameIteratorMaybeGC<NoGC>::resetOn(const JitFrameIterator *iter);
  1614 template void InlineFrameIteratorMaybeGC<CanGC>::resetOn(const JitFrameIterator *iter);
  1616 template <AllowGC allowGC>
  1617 void
  1618 InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
  1620     JS_ASSERT(more());
  1622     si_ = start_;
  1624     // Read the initial frame out of the C stack.
  1625     callee_ = frame_->maybeCallee();
  1626     script_ = frame_->script();
  1627     MOZ_ASSERT(script_->hasBaselineScript());
  1629     // Settle on the outermost frame without evaluating any instructions before
  1630     // looking for a pc.
  1631     if (!si_.instruction()->isResumePoint())
  1632         si_.nextFrame();
  1634     pc_ = script_->offsetToPC(si_.pcOffset());
  1635 #ifdef DEBUG
  1636     numActualArgs_ = 0xbadbad;
  1637 #endif
  1639     // This unfortunately is O(n*m), because we must skip over outer frames
  1640     // before reading inner ones.
  1642     // The first time (frameCount_ == UINT32_MAX) we do not know the number of
  1643     // frames that we are going to inspect.  So we are iterating until there is
  1644     // no more frames, to settle on the inner most frame and to count the number
  1645     // of frames.
  1646     size_t remaining = (frameCount_ != UINT32_MAX) ? frameNo() - 1 : SIZE_MAX;
  1648     size_t i = 1;
  1649     for (; i <= remaining && si_.moreFrames(); i++) {
  1650         JS_ASSERT(IsIonInlinablePC(pc_));
  1652         // Recover the number of actual arguments from the script.
  1653         if (JSOp(*pc_) != JSOP_FUNAPPLY)
  1654             numActualArgs_ = GET_ARGC(pc_);
  1655         if (JSOp(*pc_) == JSOP_FUNCALL) {
  1656             JS_ASSERT(GET_ARGC(pc_) > 0);
  1657             numActualArgs_ = GET_ARGC(pc_) - 1;
  1658         } else if (IsGetPropPC(pc_)) {
  1659             numActualArgs_ = 0;
  1660         } else if (IsSetPropPC(pc_)) {
  1661             numActualArgs_ = 1;
  1664         JS_ASSERT(numActualArgs_ != 0xbadbad);
  1666         // Skip over non-argument slots, as well as |this|.
  1667         unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1;
  1668         for (unsigned j = 0; j < skipCount; j++)
  1669             si_.skip();
  1671         // The JSFunction is a constant, otherwise we would not have inlined it.
  1672         Value funval = si_.read();
  1674         // Skip extra value allocations.
  1675         while (si_.moreAllocations())
  1676             si_.skip();
  1678         si_.nextFrame();
  1680         callee_ = &funval.toObject().as<JSFunction>();
  1682         // Inlined functions may be clones that still point to the lazy script
  1683         // for the executed script, if they are clones. The actual script
  1684         // exists though, just make sure the function points to it.
  1685         script_ = callee_->existingScriptForInlinedFunction();
  1686         MOZ_ASSERT(script_->hasBaselineScript());
  1688         pc_ = script_->offsetToPC(si_.pcOffset());
  1691     // The first time we do not know the number of frames, we only settle on the
  1692     // last frame, and update the number of frames based on the number of
  1693     // iteration that we have done.
  1694     if (frameCount_ == UINT32_MAX) {
  1695         MOZ_ASSERT(!si_.moreFrames());
  1696         frameCount_ = i;
  1699     framesRead_++;
  1701 template void InlineFrameIteratorMaybeGC<NoGC>::findNextFrame();
  1702 template void InlineFrameIteratorMaybeGC<CanGC>::findNextFrame();
  1704 template <AllowGC allowGC>
  1705 bool
  1706 InlineFrameIteratorMaybeGC<allowGC>::isFunctionFrame() const
  1708     return !!callee_;
  1710 template bool InlineFrameIteratorMaybeGC<NoGC>::isFunctionFrame() const;
  1711 template bool InlineFrameIteratorMaybeGC<CanGC>::isFunctionFrame() const;
  1713 MachineState
  1714 MachineState::FromBailout(mozilla::Array<uintptr_t, Registers::Total> &regs,
  1715                           mozilla::Array<double, FloatRegisters::Total> &fpregs)
  1717     MachineState machine;
  1719     for (unsigned i = 0; i < Registers::Total; i++)
  1720         machine.setRegisterLocation(Register::FromCode(i), &regs[i]);
  1721     for (unsigned i = 0; i < FloatRegisters::Total; i++)
  1722         machine.setRegisterLocation(FloatRegister::FromCode(i), &fpregs[i]);
  1724     return machine;
  1727 template <AllowGC allowGC>
  1728 bool
  1729 InlineFrameIteratorMaybeGC<allowGC>::isConstructing() const
  1731     // Skip the current frame and look at the caller's.
  1732     if (more()) {
  1733         InlineFrameIteratorMaybeGC<allowGC> parent(GetJSContextFromJitCode(), this);
  1734         ++parent;
  1736         // Inlined Getters and Setters are never constructing.
  1737         if (IsGetPropPC(parent.pc()) || IsSetPropPC(parent.pc()))
  1738             return false;
  1740         // In the case of a JS frame, look up the pc from the snapshot.
  1741         JS_ASSERT(IsCallPC(parent.pc()));
  1743         return (JSOp)*parent.pc() == JSOP_NEW;
  1746     return frame_->isConstructing();
  1748 template bool InlineFrameIteratorMaybeGC<NoGC>::isConstructing() const;
  1749 template bool InlineFrameIteratorMaybeGC<CanGC>::isConstructing() const;
  1751 bool
  1752 JitFrameIterator::isConstructing() const
  1754     JitFrameIterator parent(*this);
  1756     // Skip the current frame and look at the caller's.
  1757     do {
  1758         ++parent;
  1759     } while (!parent.done() && !parent.isScripted());
  1761     if (parent.isIonJS()) {
  1762         // In the case of a JS frame, look up the pc from the snapshot.
  1763         InlineFrameIterator inlinedParent(GetJSContextFromJitCode(), &parent);
  1765         //Inlined Getters and Setters are never constructing.
  1766         if (IsGetPropPC(inlinedParent.pc()) || IsSetPropPC(inlinedParent.pc()))
  1767             return false;
  1769         JS_ASSERT(IsCallPC(inlinedParent.pc()));
  1771         return (JSOp)*inlinedParent.pc() == JSOP_NEW;
  1774     if (parent.isBaselineJS()) {
  1775         jsbytecode *pc;
  1776         parent.baselineScriptAndPc(nullptr, &pc);
  1778         // Inlined Getters and Setters are never constructing.
  1779         // Baseline may call getters from [GET|SET]PROP or [GET|SET]ELEM ops.
  1780         if (IsGetPropPC(pc) || IsSetPropPC(pc) || IsGetElemPC(pc) || IsSetElemPC(pc))
  1781             return false;
  1783         JS_ASSERT(IsCallPC(pc));
  1785         return JSOp(*pc) == JSOP_NEW;
  1788     JS_ASSERT(parent.done());
  1789     return activation_->firstFrameIsConstructing();
  1792 unsigned
  1793 JitFrameIterator::numActualArgs() const
  1795     if (isScripted())
  1796         return jsFrame()->numActualArgs();
  1798     JS_ASSERT(isNative());
  1799     return exitFrame()->nativeExit()->argc();
  1802 void
  1803 SnapshotIterator::warnUnreadableAllocation()
  1805     fprintf(stderr, "Warning! Tried to access unreadable value allocation (possible f.arguments).\n");
  1808 struct DumpOp {
  1809     DumpOp(unsigned int i) : i_(i) {}
  1811     unsigned int i_;
  1812     void operator()(const Value& v) {
  1813         fprintf(stderr, "  actual (arg %d): ", i_);
  1814 #ifdef DEBUG
  1815         js_DumpValue(v);
  1816 #else
  1817         fprintf(stderr, "?\n");
  1818 #endif
  1819         i_++;
  1821 };
  1823 void
  1824 JitFrameIterator::dumpBaseline() const
  1826     JS_ASSERT(isBaselineJS());
  1828     fprintf(stderr, " JS Baseline frame\n");
  1829     if (isFunctionFrame()) {
  1830         fprintf(stderr, "  callee fun: ");
  1831 #ifdef DEBUG
  1832         js_DumpObject(callee());
  1833 #else
  1834         fprintf(stderr, "?\n");
  1835 #endif
  1836     } else {
  1837         fprintf(stderr, "  global frame, no callee\n");
  1840     fprintf(stderr, "  file %s line %u\n",
  1841             script()->filename(), (unsigned) script()->lineno());
  1843     JSContext *cx = GetJSContextFromJitCode();
  1844     RootedScript script(cx);
  1845     jsbytecode *pc;
  1846     baselineScriptAndPc(script.address(), &pc);
  1848     fprintf(stderr, "  script = %p, pc = %p (offset %u)\n", (void *)script, pc, uint32_t(script->pcToOffset(pc)));
  1849     fprintf(stderr, "  current op: %s\n", js_CodeName[*pc]);
  1851     fprintf(stderr, "  actual args: %d\n", numActualArgs());
  1853     BaselineFrame *frame = baselineFrame();
  1855     for (unsigned i = 0; i < frame->numValueSlots(); i++) {
  1856         fprintf(stderr, "  slot %u: ", i);
  1857 #ifdef DEBUG
  1858         Value *v = frame->valueSlot(i);
  1859         js_DumpValue(*v);
  1860 #else
  1861         fprintf(stderr, "?\n");
  1862 #endif
  1866 template <AllowGC allowGC>
  1867 void
  1868 InlineFrameIteratorMaybeGC<allowGC>::dump() const
  1870     if (more())
  1871         fprintf(stderr, " JS frame (inlined)\n");
  1872     else
  1873         fprintf(stderr, " JS frame\n");
  1875     bool isFunction = false;
  1876     if (isFunctionFrame()) {
  1877         isFunction = true;
  1878         fprintf(stderr, "  callee fun: ");
  1879 #ifdef DEBUG
  1880         js_DumpObject(callee());
  1881 #else
  1882         fprintf(stderr, "?\n");
  1883 #endif
  1884     } else {
  1885         fprintf(stderr, "  global frame, no callee\n");
  1888     fprintf(stderr, "  file %s line %u\n",
  1889             script()->filename(), (unsigned) script()->lineno());
  1891     fprintf(stderr, "  script = %p, pc = %p\n", (void*) script(), pc());
  1892     fprintf(stderr, "  current op: %s\n", js_CodeName[*pc()]);
  1894     if (!more()) {
  1895         numActualArgs();
  1898     SnapshotIterator si = snapshotIterator();
  1899     fprintf(stderr, "  slots: %u\n", si.numAllocations() - 1);
  1900     for (unsigned i = 0; i < si.numAllocations() - 1; i++) {
  1901         if (isFunction) {
  1902             if (i == 0)
  1903                 fprintf(stderr, "  scope chain: ");
  1904             else if (i == 1)
  1905                 fprintf(stderr, "  this: ");
  1906             else if (i - 2 < callee()->nargs())
  1907                 fprintf(stderr, "  formal (arg %d): ", i - 2);
  1908             else {
  1909                 if (i - 2 == callee()->nargs() && numActualArgs() > callee()->nargs()) {
  1910                     DumpOp d(callee()->nargs());
  1911                     unaliasedForEachActual(GetJSContextFromJitCode(), d, ReadFrame_Overflown);
  1914                 fprintf(stderr, "  slot %d: ", int(i - 2 - callee()->nargs()));
  1916         } else
  1917             fprintf(stderr, "  slot %u: ", i);
  1918 #ifdef DEBUG
  1919         js_DumpValue(si.maybeRead());
  1920 #else
  1921         fprintf(stderr, "?\n");
  1922 #endif
  1925     fputc('\n', stderr);
  1927 template void InlineFrameIteratorMaybeGC<NoGC>::dump() const;
  1928 template void InlineFrameIteratorMaybeGC<CanGC>::dump() const;
  1930 void
  1931 JitFrameIterator::dump() const
  1933     switch (type_) {
  1934       case JitFrame_Entry:
  1935         fprintf(stderr, " Entry frame\n");
  1936         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
  1937         break;
  1938       case JitFrame_BaselineJS:
  1939         dumpBaseline();
  1940         break;
  1941       case JitFrame_BaselineStub:
  1942       case JitFrame_Unwound_BaselineStub:
  1943         fprintf(stderr, " Baseline stub frame\n");
  1944         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
  1945         break;
  1946       case JitFrame_IonJS:
  1948         InlineFrameIterator frames(GetJSContextFromJitCode(), this);
  1949         for (;;) {
  1950             frames.dump();
  1951             if (!frames.more())
  1952                 break;
  1953             ++frames;
  1955         break;
  1957       case JitFrame_Rectifier:
  1958       case JitFrame_Unwound_Rectifier:
  1959         fprintf(stderr, " Rectifier frame\n");
  1960         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
  1961         break;
  1962       case JitFrame_Unwound_IonJS:
  1963         fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
  1964         break;
  1965       case JitFrame_Exit:
  1966         break;
  1967     };
  1968     fputc('\n', stderr);
  1971 IonJSFrameLayout *
  1972 InvalidationBailoutStack::fp() const
  1974     return (IonJSFrameLayout *) (sp() + ionScript_->frameSize());
  1977 void
  1978 InvalidationBailoutStack::checkInvariants() const
  1980 #ifdef DEBUG
  1981     IonJSFrameLayout *frame = fp();
  1982     CalleeToken token = frame->calleeToken();
  1983     JS_ASSERT(token);
  1985     uint8_t *rawBase = ionScript()->method()->raw();
  1986     uint8_t *rawLimit = rawBase + ionScript()->method()->instructionsSize();
  1987     uint8_t *osiPoint = osiPointReturnAddress();
  1988     JS_ASSERT(rawBase <= osiPoint && osiPoint <= rawLimit);
  1989 #endif
  1992 } // namespace jit
  1993 } // namespace js

mercurial