js/src/jit/IonFrames.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/IonFrames.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1993 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jit/IonFrames-inl.h"
    1.11 +
    1.12 +#include "jsfun.h"
    1.13 +#include "jsobj.h"
    1.14 +#include "jsscript.h"
    1.15 +
    1.16 +#include "gc/Marking.h"
    1.17 +#include "jit/BaselineDebugModeOSR.h"
    1.18 +#include "jit/BaselineFrame.h"
    1.19 +#include "jit/BaselineIC.h"
    1.20 +#include "jit/BaselineJIT.h"
    1.21 +#include "jit/Ion.h"
    1.22 +#include "jit/IonMacroAssembler.h"
    1.23 +#include "jit/IonSpewer.h"
    1.24 +#include "jit/JitCompartment.h"
    1.25 +#include "jit/ParallelFunctions.h"
    1.26 +#include "jit/PcScriptCache.h"
    1.27 +#include "jit/Recover.h"
    1.28 +#include "jit/Safepoints.h"
    1.29 +#include "jit/Snapshots.h"
    1.30 +#include "jit/VMFunctions.h"
    1.31 +#include "vm/ArgumentsObject.h"
    1.32 +#include "vm/ForkJoin.h"
    1.33 +#include "vm/Interpreter.h"
    1.34 +
    1.35 +#include "jsscriptinlines.h"
    1.36 +#include "jit/JitFrameIterator-inl.h"
    1.37 +#include "vm/Probes-inl.h"
    1.38 +
    1.39 +namespace js {
    1.40 +namespace jit {
    1.41 +
    1.42 +// Given a slot index, returns the offset, in bytes, of that slot from an
    1.43 +// IonJSFrameLayout. Slot distances are uniform across architectures, however,
    1.44 +// the distance does depend on the size of the frame header.
    1.45 +static inline int32_t
    1.46 +OffsetOfFrameSlot(int32_t slot)
    1.47 +{
    1.48 +    return -slot;
    1.49 +}
    1.50 +
    1.51 +static inline uintptr_t
    1.52 +ReadFrameSlot(IonJSFrameLayout *fp, int32_t slot)
    1.53 +{
    1.54 +    return *(uintptr_t *)((char *)fp + OffsetOfFrameSlot(slot));
    1.55 +}
    1.56 +
    1.57 +static inline double
    1.58 +ReadFrameDoubleSlot(IonJSFrameLayout *fp, int32_t slot)
    1.59 +{
    1.60 +    return *(double *)((char *)fp + OffsetOfFrameSlot(slot));
    1.61 +}
    1.62 +
    1.63 +static inline float
    1.64 +ReadFrameFloat32Slot(IonJSFrameLayout *fp, int32_t slot)
    1.65 +{
    1.66 +    return *(float *)((char *)fp + OffsetOfFrameSlot(slot));
    1.67 +}
    1.68 +
    1.69 +static inline int32_t
    1.70 +ReadFrameInt32Slot(IonJSFrameLayout *fp, int32_t slot)
    1.71 +{
    1.72 +    return *(int32_t *)((char *)fp + OffsetOfFrameSlot(slot));
    1.73 +}
    1.74 +
    1.75 +static inline bool
    1.76 +ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot)
    1.77 +{
    1.78 +    return *(bool *)((char *)fp + OffsetOfFrameSlot(slot));
    1.79 +}
    1.80 +
    1.81 +JitFrameIterator::JitFrameIterator(JSContext *cx)
    1.82 +  : current_(cx->mainThread().ionTop),
    1.83 +    type_(JitFrame_Exit),
    1.84 +    returnAddressToFp_(nullptr),
    1.85 +    frameSize_(0),
    1.86 +    cachedSafepointIndex_(nullptr),
    1.87 +    activation_(nullptr),
    1.88 +    mode_(SequentialExecution)
    1.89 +{
    1.90 +}
    1.91 +
    1.92 +JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
    1.93 +    : current_(activations.jitTop()),
    1.94 +      type_(JitFrame_Exit),
    1.95 +      returnAddressToFp_(nullptr),
    1.96 +      frameSize_(0),
    1.97 +      cachedSafepointIndex_(nullptr),
    1.98 +      activation_(activations->asJit()),
    1.99 +      mode_(SequentialExecution)
   1.100 +{
   1.101 +}
   1.102 +
   1.103 +JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
   1.104 +  : current_((uint8_t *)fp),
   1.105 +    type_(JitFrame_IonJS),
   1.106 +    returnAddressToFp_(fp->returnAddress()),
   1.107 +    frameSize_(fp->prevFrameLocalSize()),
   1.108 +    mode_(mode)
   1.109 +{
   1.110 +}
   1.111 +
   1.112 +bool
   1.113 +JitFrameIterator::checkInvalidation() const
   1.114 +{
   1.115 +    IonScript *dummy;
   1.116 +    return checkInvalidation(&dummy);
   1.117 +}
   1.118 +
   1.119 +bool
   1.120 +JitFrameIterator::checkInvalidation(IonScript **ionScriptOut) const
   1.121 +{
   1.122 +    uint8_t *returnAddr = returnAddressToFp();
   1.123 +    JSScript *script = this->script();
   1.124 +    // N.B. the current IonScript is not the same as the frame's
   1.125 +    // IonScript if the frame has since been invalidated.
   1.126 +    bool invalidated;
   1.127 +    if (mode_ == ParallelExecution) {
   1.128 +        // Parallel execution does not have invalidating bailouts.
   1.129 +        invalidated = false;
   1.130 +    } else {
   1.131 +        invalidated = !script->hasIonScript() ||
   1.132 +            !script->ionScript()->containsReturnAddress(returnAddr);
   1.133 +    }
   1.134 +    if (!invalidated)
   1.135 +        return false;
   1.136 +
   1.137 +    int32_t invalidationDataOffset = ((int32_t *) returnAddr)[-1];
   1.138 +    uint8_t *ionScriptDataOffset = returnAddr + invalidationDataOffset;
   1.139 +    IonScript *ionScript = (IonScript *) Assembler::getPointer(ionScriptDataOffset);
   1.140 +    JS_ASSERT(ionScript->containsReturnAddress(returnAddr));
   1.141 +    *ionScriptOut = ionScript;
   1.142 +    return true;
   1.143 +}
   1.144 +
   1.145 +CalleeToken
   1.146 +JitFrameIterator::calleeToken() const
   1.147 +{
   1.148 +    return ((IonJSFrameLayout *) current_)->calleeToken();
   1.149 +}
   1.150 +
   1.151 +JSFunction *
   1.152 +JitFrameIterator::callee() const
   1.153 +{
   1.154 +    JS_ASSERT(isScripted());
   1.155 +    JS_ASSERT(isFunctionFrame());
   1.156 +    return CalleeTokenToFunction(calleeToken());
   1.157 +}
   1.158 +
   1.159 +JSFunction *
   1.160 +JitFrameIterator::maybeCallee() const
   1.161 +{
   1.162 +    if (isScripted() && (isFunctionFrame()))
   1.163 +        return callee();
   1.164 +    return nullptr;
   1.165 +}
   1.166 +
   1.167 +bool
   1.168 +JitFrameIterator::isNative() const
   1.169 +{
   1.170 +    if (type_ != JitFrame_Exit || isFakeExitFrame())
   1.171 +        return false;
   1.172 +    return exitFrame()->footer()->jitCode() == nullptr;
   1.173 +}
   1.174 +
   1.175 +bool
   1.176 +JitFrameIterator::isOOLNative() const
   1.177 +{
   1.178 +    if (type_ != JitFrame_Exit)
   1.179 +        return false;
   1.180 +    return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_NATIVE;
   1.181 +}
   1.182 +
   1.183 +bool
   1.184 +JitFrameIterator::isOOLPropertyOp() const
   1.185 +{
   1.186 +    if (type_ != JitFrame_Exit)
   1.187 +        return false;
   1.188 +    return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_PROPERTY_OP;
   1.189 +}
   1.190 +
   1.191 +bool
   1.192 +JitFrameIterator::isOOLProxy() const
   1.193 +{
   1.194 +    if (type_ != JitFrame_Exit)
   1.195 +        return false;
   1.196 +    return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_PROXY;
   1.197 +}
   1.198 +
   1.199 +bool
   1.200 +JitFrameIterator::isDOMExit() const
   1.201 +{
   1.202 +    if (type_ != JitFrame_Exit)
   1.203 +        return false;
   1.204 +    return exitFrame()->isDomExit();
   1.205 +}
   1.206 +
   1.207 +bool
   1.208 +JitFrameIterator::isFunctionFrame() const
   1.209 +{
   1.210 +    return CalleeTokenIsFunction(calleeToken());
   1.211 +}
   1.212 +
   1.213 +JSScript *
   1.214 +JitFrameIterator::script() const
   1.215 +{
   1.216 +    JS_ASSERT(isScripted());
   1.217 +    if (isBaselineJS())
   1.218 +        return baselineFrame()->script();
   1.219 +    JSScript *script = ScriptFromCalleeToken(calleeToken());
   1.220 +    JS_ASSERT(script);
   1.221 +    return script;
   1.222 +}
   1.223 +
   1.224 +void
   1.225 +JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const
   1.226 +{
   1.227 +    JS_ASSERT(isBaselineJS());
   1.228 +    JSScript *script = this->script();
   1.229 +    if (scriptRes)
   1.230 +        *scriptRes = script;
   1.231 +    uint8_t *retAddr = returnAddressToFp();
   1.232 +
   1.233 +    // If we are in the middle of a recompile handler, get the real return
   1.234 +    // address as stashed in the RecompileInfo.
   1.235 +    if (BaselineDebugModeOSRInfo *info = baselineFrame()->getDebugModeOSRInfo())
   1.236 +        retAddr = info->resumeAddr;
   1.237 +
   1.238 +    if (pcRes) {
   1.239 +        // If the return address is into the prologue entry address or just
   1.240 +        // after the debug prologue, then assume start of script.
   1.241 +        if (retAddr == script->baselineScript()->prologueEntryAddr() ||
   1.242 +            retAddr == script->baselineScript()->postDebugPrologueAddr())
   1.243 +        {
   1.244 +            *pcRes = script->code();
   1.245 +            return;
   1.246 +        }
   1.247 +
   1.248 +        // The return address _may_ be a return from a callVM or IC chain call done for
   1.249 +        // some op.
   1.250 +        ICEntry *icEntry = script->baselineScript()->maybeICEntryFromReturnAddress(retAddr);
   1.251 +        if (icEntry) {
   1.252 +            *pcRes = icEntry->pc(script);
   1.253 +            return;
   1.254 +        }
   1.255 +
   1.256 +        // If not, the return address _must_ be the start address of an op, which can
   1.257 +        // be computed from the pc mapping table.
   1.258 +        *pcRes = script->baselineScript()->pcForReturnAddress(script, retAddr);
   1.259 +    }
   1.260 +}
   1.261 +
   1.262 +Value *
   1.263 +JitFrameIterator::actualArgs() const
   1.264 +{
   1.265 +    return jsFrame()->argv() + 1;
   1.266 +}
   1.267 +
   1.268 +static inline size_t
   1.269 +SizeOfFramePrefix(FrameType type)
   1.270 +{
   1.271 +    switch (type) {
   1.272 +      case JitFrame_Entry:
   1.273 +        return IonEntryFrameLayout::Size();
   1.274 +      case JitFrame_BaselineJS:
   1.275 +      case JitFrame_IonJS:
   1.276 +      case JitFrame_Unwound_IonJS:
   1.277 +        return IonJSFrameLayout::Size();
   1.278 +      case JitFrame_BaselineStub:
   1.279 +        return IonBaselineStubFrameLayout::Size();
   1.280 +      case JitFrame_Rectifier:
   1.281 +        return IonRectifierFrameLayout::Size();
   1.282 +      case JitFrame_Unwound_Rectifier:
   1.283 +        return IonUnwoundRectifierFrameLayout::Size();
   1.284 +      case JitFrame_Exit:
   1.285 +        return IonExitFrameLayout::Size();
   1.286 +      default:
   1.287 +        MOZ_ASSUME_UNREACHABLE("unknown frame type");
   1.288 +    }
   1.289 +}
   1.290 +
   1.291 +uint8_t *
   1.292 +JitFrameIterator::prevFp() const
   1.293 +{
   1.294 +    size_t currentSize = SizeOfFramePrefix(type_);
   1.295 +    // This quick fix must be removed as soon as bug 717297 land.  This is
   1.296 +    // needed because the descriptor size of JS-to-JS frame which is just after
   1.297 +    // a Rectifier frame should not change. (cf EnsureExitFrame function)
   1.298 +    if (isFakeExitFrame()) {
   1.299 +        JS_ASSERT(SizeOfFramePrefix(JitFrame_BaselineJS) ==
   1.300 +                  SizeOfFramePrefix(JitFrame_IonJS));
   1.301 +        currentSize = SizeOfFramePrefix(JitFrame_IonJS);
   1.302 +    }
   1.303 +    currentSize += current()->prevFrameLocalSize();
   1.304 +    return current_ + currentSize;
   1.305 +}
   1.306 +
   1.307 +JitFrameIterator &
   1.308 +JitFrameIterator::operator++()
   1.309 +{
   1.310 +    JS_ASSERT(type_ != JitFrame_Entry);
   1.311 +
   1.312 +    frameSize_ = prevFrameLocalSize();
   1.313 +    cachedSafepointIndex_ = nullptr;
   1.314 +
   1.315 +    // If the next frame is the entry frame, just exit. Don't update current_,
   1.316 +    // since the entry and first frames overlap.
   1.317 +    if (current()->prevType() == JitFrame_Entry) {
   1.318 +        type_ = JitFrame_Entry;
   1.319 +        return *this;
   1.320 +    }
   1.321 +
   1.322 +    // Note: prevFp() needs the current type, so set it after computing the
   1.323 +    // next frame.
   1.324 +    uint8_t *prev = prevFp();
   1.325 +    type_ = current()->prevType();
   1.326 +    if (type_ == JitFrame_Unwound_IonJS)
   1.327 +        type_ = JitFrame_IonJS;
   1.328 +    else if (type_ == JitFrame_Unwound_BaselineStub)
   1.329 +        type_ = JitFrame_BaselineStub;
   1.330 +    returnAddressToFp_ = current()->returnAddress();
   1.331 +    current_ = prev;
   1.332 +    return *this;
   1.333 +}
   1.334 +
   1.335 +uintptr_t *
   1.336 +JitFrameIterator::spillBase() const
   1.337 +{
   1.338 +    // Get the base address to where safepoint registers are spilled.
   1.339 +    // Out-of-line calls do not unwind the extra padding space used to
   1.340 +    // aggregate bailout tables, so we use frameSize instead of frameLocals,
   1.341 +    // which would only account for local stack slots.
   1.342 +    return reinterpret_cast<uintptr_t *>(fp() - ionScript()->frameSize());
   1.343 +}
   1.344 +
   1.345 +MachineState
   1.346 +JitFrameIterator::machineState() const
   1.347 +{
   1.348 +    SafepointReader reader(ionScript(), safepoint());
   1.349 +    uintptr_t *spill = spillBase();
   1.350 +
   1.351 +    MachineState machine;
   1.352 +    for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++)
   1.353 +        machine.setRegisterLocation(*iter, --spill);
   1.354 +
   1.355 +    double *floatSpill = reinterpret_cast<double *>(spill);
   1.356 +    for (FloatRegisterBackwardIterator iter(reader.allFloatSpills()); iter.more(); iter++)
   1.357 +        machine.setRegisterLocation(*iter, --floatSpill);
   1.358 +
   1.359 +    return machine;
   1.360 +}
   1.361 +
   1.362 +static void
   1.363 +CloseLiveIterator(JSContext *cx, const InlineFrameIterator &frame, uint32_t localSlot)
   1.364 +{
   1.365 +    SnapshotIterator si = frame.snapshotIterator();
   1.366 +
   1.367 +    // Skip stack slots until we reach the iterator object.
   1.368 +    uint32_t base = CountArgSlots(frame.script(), frame.maybeCallee()) + frame.script()->nfixed();
   1.369 +    uint32_t skipSlots = base + localSlot - 1;
   1.370 +
   1.371 +    for (unsigned i = 0; i < skipSlots; i++)
   1.372 +        si.skip();
   1.373 +
   1.374 +    Value v = si.read();
   1.375 +    RootedObject obj(cx, &v.toObject());
   1.376 +
   1.377 +    if (cx->isExceptionPending())
   1.378 +        UnwindIteratorForException(cx, obj);
   1.379 +    else
   1.380 +        UnwindIteratorForUncatchableException(cx, obj);
   1.381 +}
   1.382 +
   1.383 +static void
   1.384 +HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe,
   1.385 +                   bool *overrecursed)
   1.386 +{
   1.387 +    RootedScript script(cx, frame.script());
   1.388 +    jsbytecode *pc = frame.pc();
   1.389 +
   1.390 +    bool bailedOutForDebugMode = false;
   1.391 +    if (cx->compartment()->debugMode()) {
   1.392 +        // If we have an exception from within Ion and the debugger is active,
   1.393 +        // we do the following:
   1.394 +        //
   1.395 +        //   1. Bailout to baseline to reconstruct a baseline frame.
   1.396 +        //   2. Resume immediately into the exception tail afterwards, and
   1.397 +        //   handle the exception again with the top frame now a baseline
   1.398 +        //   frame.
   1.399 +        //
   1.400 +        // An empty exception info denotes that we're propagating an Ion
   1.401 +        // exception due to debug mode, which BailoutIonToBaseline needs to
   1.402 +        // know. This is because we might not be able to fully reconstruct up
   1.403 +        // to the stack depth at the snapshot, as we could've thrown in the
   1.404 +        // middle of a call.
   1.405 +        ExceptionBailoutInfo propagateInfo;
   1.406 +        uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed);
   1.407 +        bailedOutForDebugMode = retval == BAILOUT_RETURN_OK;
   1.408 +    }
   1.409 +
   1.410 +    if (!script->hasTrynotes())
   1.411 +        return;
   1.412 +
   1.413 +    JSTryNote *tn = script->trynotes()->vector;
   1.414 +    JSTryNote *tnEnd = tn + script->trynotes()->length;
   1.415 +
   1.416 +    uint32_t pcOffset = uint32_t(pc - script->main());
   1.417 +    for (; tn != tnEnd; ++tn) {
   1.418 +        if (pcOffset < tn->start)
   1.419 +            continue;
   1.420 +        if (pcOffset >= tn->start + tn->length)
   1.421 +            continue;
   1.422 +
   1.423 +        switch (tn->kind) {
   1.424 +          case JSTRY_ITER: {
   1.425 +            JS_ASSERT(JSOp(*(script->main() + tn->start + tn->length)) == JSOP_ENDITER);
   1.426 +            JS_ASSERT(tn->stackDepth > 0);
   1.427 +
   1.428 +            uint32_t localSlot = tn->stackDepth;
   1.429 +            CloseLiveIterator(cx, frame, localSlot);
   1.430 +            break;
   1.431 +          }
   1.432 +
   1.433 +          case JSTRY_LOOP:
   1.434 +            break;
   1.435 +
   1.436 +          case JSTRY_CATCH:
   1.437 +            if (cx->isExceptionPending() && !bailedOutForDebugMode) {
   1.438 +                // Ion can compile try-catch, but bailing out to catch
   1.439 +                // exceptions is slow. Reset the use count so that if we
   1.440 +                // catch many exceptions we won't Ion-compile the script.
   1.441 +                script->resetUseCount();
   1.442 +
   1.443 +                // Bailout at the start of the catch block.
   1.444 +                jsbytecode *catchPC = script->main() + tn->start + tn->length;
   1.445 +                ExceptionBailoutInfo excInfo(frame.frameNo(), catchPC, tn->stackDepth);
   1.446 +                uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed);
   1.447 +                if (retval == BAILOUT_RETURN_OK)
   1.448 +                    return;
   1.449 +
   1.450 +                // Error on bailout clears pending exception.
   1.451 +                MOZ_ASSERT(!cx->isExceptionPending());
   1.452 +            }
   1.453 +            break;
   1.454 +
   1.455 +          default:
   1.456 +            MOZ_ASSUME_UNREACHABLE("Unexpected try note");
   1.457 +        }
   1.458 +    }
   1.459 +}
   1.460 +
   1.461 +static void
   1.462 +HandleExceptionBaseline(JSContext *cx, const JitFrameIterator &frame, ResumeFromException *rfe,
   1.463 +                        bool *calledDebugEpilogue)
   1.464 +{
   1.465 +    JS_ASSERT(frame.isBaselineJS());
   1.466 +    JS_ASSERT(!*calledDebugEpilogue);
   1.467 +
   1.468 +    RootedScript script(cx);
   1.469 +    jsbytecode *pc;
   1.470 +    frame.baselineScriptAndPc(script.address(), &pc);
   1.471 +
   1.472 +    if (cx->isExceptionPending() && cx->compartment()->debugMode()) {
   1.473 +        BaselineFrame *baselineFrame = frame.baselineFrame();
   1.474 +        JSTrapStatus status = DebugExceptionUnwind(cx, baselineFrame, pc);
   1.475 +        switch (status) {
   1.476 +          case JSTRAP_ERROR:
   1.477 +            // Uncatchable exception.
   1.478 +            JS_ASSERT(!cx->isExceptionPending());
   1.479 +            break;
   1.480 +
   1.481 +          case JSTRAP_CONTINUE:
   1.482 +          case JSTRAP_THROW:
   1.483 +            JS_ASSERT(cx->isExceptionPending());
   1.484 +            break;
   1.485 +
   1.486 +          case JSTRAP_RETURN:
   1.487 +            JS_ASSERT(baselineFrame->hasReturnValue());
   1.488 +            if (jit::DebugEpilogue(cx, baselineFrame, pc, true)) {
   1.489 +                rfe->kind = ResumeFromException::RESUME_FORCED_RETURN;
   1.490 +                rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
   1.491 +                rfe->stackPointer = reinterpret_cast<uint8_t *>(baselineFrame);
   1.492 +                return;
   1.493 +            }
   1.494 +
   1.495 +            // DebugEpilogue threw an exception. Propagate to the caller frame.
   1.496 +            *calledDebugEpilogue = true;
   1.497 +            return;
   1.498 +
   1.499 +          default:
   1.500 +            MOZ_ASSUME_UNREACHABLE("Invalid trap status");
   1.501 +        }
   1.502 +    }
   1.503 +
   1.504 +    if (!script->hasTrynotes())
   1.505 +        return;
   1.506 +
   1.507 +    JSTryNote *tn = script->trynotes()->vector;
   1.508 +    JSTryNote *tnEnd = tn + script->trynotes()->length;
   1.509 +
   1.510 +    uint32_t pcOffset = uint32_t(pc - script->main());
   1.511 +    ScopeIter si(frame.baselineFrame(), pc, cx);
   1.512 +    for (; tn != tnEnd; ++tn) {
   1.513 +        if (pcOffset < tn->start)
   1.514 +            continue;
   1.515 +        if (pcOffset >= tn->start + tn->length)
   1.516 +            continue;
   1.517 +
   1.518 +        // Skip if the try note's stack depth exceeds the frame's stack depth.
   1.519 +        // See the big comment in TryNoteIter::settle for more info.
   1.520 +        JS_ASSERT(frame.baselineFrame()->numValueSlots() >= script->nfixed());
   1.521 +        size_t stackDepth = frame.baselineFrame()->numValueSlots() - script->nfixed();
   1.522 +        if (tn->stackDepth > stackDepth)
   1.523 +            continue;
   1.524 +
   1.525 +        // Unwind scope chain (pop block objects).
   1.526 +        if (cx->isExceptionPending())
   1.527 +            UnwindScope(cx, si, script->main() + tn->start);
   1.528 +
   1.529 +        // Compute base pointer and stack pointer.
   1.530 +        rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
   1.531 +        rfe->stackPointer = rfe->framePointer - BaselineFrame::Size() -
   1.532 +            (script->nfixed() + tn->stackDepth) * sizeof(Value);
   1.533 +
   1.534 +        switch (tn->kind) {
   1.535 +          case JSTRY_CATCH:
   1.536 +            if (cx->isExceptionPending()) {
   1.537 +                // Ion can compile try-catch, but bailing out to catch
   1.538 +                // exceptions is slow. Reset the use count so that if we
   1.539 +                // catch many exceptions we won't Ion-compile the script.
   1.540 +                script->resetUseCount();
   1.541 +
   1.542 +                // Resume at the start of the catch block.
   1.543 +                rfe->kind = ResumeFromException::RESUME_CATCH;
   1.544 +                jsbytecode *catchPC = script->main() + tn->start + tn->length;
   1.545 +                rfe->target = script->baselineScript()->nativeCodeForPC(script, catchPC);
   1.546 +                return;
   1.547 +            }
   1.548 +            break;
   1.549 +
   1.550 +          case JSTRY_FINALLY:
   1.551 +            if (cx->isExceptionPending()) {
   1.552 +                rfe->kind = ResumeFromException::RESUME_FINALLY;
   1.553 +                jsbytecode *finallyPC = script->main() + tn->start + tn->length;
   1.554 +                rfe->target = script->baselineScript()->nativeCodeForPC(script, finallyPC);
   1.555 +                // Drop the exception instead of leaking cross compartment data.
   1.556 +                if (!cx->getPendingException(MutableHandleValue::fromMarkedLocation(&rfe->exception)))
   1.557 +                    rfe->exception = UndefinedValue();
   1.558 +                cx->clearPendingException();
   1.559 +                return;
   1.560 +            }
   1.561 +            break;
   1.562 +
   1.563 +          case JSTRY_ITER: {
   1.564 +            Value iterValue(* (Value *) rfe->stackPointer);
   1.565 +            RootedObject iterObject(cx, &iterValue.toObject());
   1.566 +            if (cx->isExceptionPending())
   1.567 +                UnwindIteratorForException(cx, iterObject);
   1.568 +            else
   1.569 +                UnwindIteratorForUncatchableException(cx, iterObject);
   1.570 +            break;
   1.571 +          }
   1.572 +
   1.573 +          case JSTRY_LOOP:
   1.574 +            break;
   1.575 +
   1.576 +          default:
   1.577 +            MOZ_ASSUME_UNREACHABLE("Invalid try note");
   1.578 +        }
   1.579 +    }
   1.580 +
   1.581 +}
   1.582 +
   1.583 +struct AutoDeleteDebugModeOSRInfo
   1.584 +{
   1.585 +    BaselineFrame *frame;
   1.586 +    AutoDeleteDebugModeOSRInfo(BaselineFrame *frame) : frame(frame) { MOZ_ASSERT(frame); }
   1.587 +    ~AutoDeleteDebugModeOSRInfo() { frame->deleteDebugModeOSRInfo(); }
   1.588 +};
   1.589 +
   1.590 +void
   1.591 +HandleException(ResumeFromException *rfe)
   1.592 +{
   1.593 +    JSContext *cx = GetJSContextFromJitCode();
   1.594 +
   1.595 +    rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
   1.596 +
   1.597 +    IonSpew(IonSpew_Invalidate, "handling exception");
   1.598 +
   1.599 +    // Clear any Ion return override that's been set.
   1.600 +    // This may happen if a callVM function causes an invalidation (setting the
   1.601 +    // override), and then fails, bypassing the bailout handlers that would
   1.602 +    // otherwise clear the return override.
   1.603 +    if (cx->runtime()->hasIonReturnOverride())
   1.604 +        cx->runtime()->takeIonReturnOverride();
   1.605 +
   1.606 +    JitFrameIterator iter(cx);
   1.607 +    while (!iter.isEntry()) {
   1.608 +        bool overrecursed = false;
   1.609 +        if (iter.isIonJS()) {
   1.610 +            // Search each inlined frame for live iterator objects, and close
   1.611 +            // them.
   1.612 +            InlineFrameIterator frames(cx, &iter);
   1.613 +
   1.614 +            // Invalidation state will be the same for all inlined scripts in the frame.
   1.615 +            IonScript *ionScript = nullptr;
   1.616 +            bool invalidated = iter.checkInvalidation(&ionScript);
   1.617 +
   1.618 +            for (;;) {
   1.619 +                HandleExceptionIon(cx, frames, rfe, &overrecursed);
   1.620 +
   1.621 +                if (rfe->kind == ResumeFromException::RESUME_BAILOUT) {
   1.622 +                    if (invalidated)
   1.623 +                        ionScript->decref(cx->runtime()->defaultFreeOp());
   1.624 +                    return;
   1.625 +                }
   1.626 +
   1.627 +                JS_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME);
   1.628 +
   1.629 +                // Figure out whether SPS frame was pushed for this frame or not.
   1.630 +                // Even if profiler is enabled, the frame being popped might have
   1.631 +                // been entered prior to SPS being enabled, and thus not have
   1.632 +                // a pushed SPS frame.
   1.633 +                bool popSPSFrame = cx->runtime()->spsProfiler.enabled();
   1.634 +                if (invalidated)
   1.635 +                    popSPSFrame = ionScript->hasSPSInstrumentation();
   1.636 +
   1.637 +                // If inline-frames are not profiled, then don't pop an SPS frame
   1.638 +                // for them.
   1.639 +                if (frames.more() && !js_JitOptions.profileInlineFrames)
   1.640 +                    popSPSFrame = false;
   1.641 +
   1.642 +                // When profiling, each frame popped needs a notification that
   1.643 +                // the function has exited, so invoke the probe that a function
   1.644 +                // is exiting.
   1.645 +                JSScript *script = frames.script();
   1.646 +                probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
   1.647 +                if (!frames.more())
   1.648 +                    break;
   1.649 +                ++frames;
   1.650 +            }
   1.651 +
   1.652 +            if (invalidated)
   1.653 +                ionScript->decref(cx->runtime()->defaultFreeOp());
   1.654 +
   1.655 +        } else if (iter.isBaselineJS()) {
   1.656 +            // It's invalid to call DebugEpilogue twice for the same frame.
   1.657 +            bool calledDebugEpilogue = false;
   1.658 +
   1.659 +            HandleExceptionBaseline(cx, iter, rfe, &calledDebugEpilogue);
   1.660 +
   1.661 +            // If we are propagating an exception through a frame with
   1.662 +            // on-stack recompile info, we should free the allocated
   1.663 +            // RecompileInfo struct before we leave this block, as we will not
   1.664 +            // be returning to the recompile handler.
   1.665 +            //
   1.666 +            // We cannot delete it immediately because of the call to
   1.667 +            // iter.baselineScriptAndPc below.
   1.668 +            AutoDeleteDebugModeOSRInfo deleteDebugModeOSRInfo(iter.baselineFrame());
   1.669 +
   1.670 +            if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
   1.671 +                return;
   1.672 +
   1.673 +            // Unwind profiler pseudo-stack
   1.674 +            JSScript *script = iter.script();
   1.675 +            probes::ExitScript(cx, script, script->functionNonDelazifying(),
   1.676 +                               iter.baselineFrame()->hasPushedSPSFrame());
   1.677 +            // After this point, any pushed SPS frame would have been popped if it needed
   1.678 +            // to be.  Unset the flag here so that if we call DebugEpilogue below,
   1.679 +            // it doesn't try to pop the SPS frame again.
   1.680 +            iter.baselineFrame()->unsetPushedSPSFrame();
   1.681 +
   1.682 +            if (cx->compartment()->debugMode() && !calledDebugEpilogue) {
   1.683 +                // If DebugEpilogue returns |true|, we have to perform a forced
   1.684 +                // return, e.g. return frame->returnValue() to the caller.
   1.685 +                BaselineFrame *frame = iter.baselineFrame();
   1.686 +                RootedScript script(cx);
   1.687 +                jsbytecode *pc;
   1.688 +                iter.baselineScriptAndPc(script.address(), &pc);
   1.689 +                if (jit::DebugEpilogue(cx, frame, pc, false)) {
   1.690 +                    JS_ASSERT(frame->hasReturnValue());
   1.691 +                    rfe->kind = ResumeFromException::RESUME_FORCED_RETURN;
   1.692 +                    rfe->framePointer = iter.fp() - BaselineFrame::FramePointerOffset;
   1.693 +                    rfe->stackPointer = reinterpret_cast<uint8_t *>(frame);
   1.694 +                    return;
   1.695 +                }
   1.696 +            }
   1.697 +        }
   1.698 +
   1.699 +        IonJSFrameLayout *current = iter.isScripted() ? iter.jsFrame() : nullptr;
   1.700 +
   1.701 +        ++iter;
   1.702 +
   1.703 +        if (current) {
   1.704 +            // Unwind the frame by updating ionTop. This is necessary so that
   1.705 +            // (1) debugger exception unwind and leave frame hooks don't see this
   1.706 +            // frame when they use ScriptFrameIter, and (2) ScriptFrameIter does
   1.707 +            // not crash when accessing an IonScript that's destroyed by the
   1.708 +            // ionScript->decref call.
   1.709 +            EnsureExitFrame(current);
   1.710 +            cx->mainThread().ionTop = (uint8_t *)current;
   1.711 +        }
   1.712 +
   1.713 +        if (overrecursed) {
   1.714 +            // We hit an overrecursion error during bailout. Report it now.
   1.715 +            js_ReportOverRecursed(cx);
   1.716 +        }
   1.717 +    }
   1.718 +
   1.719 +    rfe->stackPointer = iter.fp();
   1.720 +}
   1.721 +
   1.722 +void
   1.723 +HandleParallelFailure(ResumeFromException *rfe)
   1.724 +{
   1.725 +    ForkJoinContext *cx = ForkJoinContext::current();
   1.726 +    JitFrameIterator iter(cx->perThreadData->ionTop, ParallelExecution);
   1.727 +
   1.728 +    parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry");
   1.729 +
   1.730 +    while (!iter.isEntry()) {
   1.731 +        if (iter.isScripted()) {
   1.732 +            cx->bailoutRecord->updateCause(ParallelBailoutUnsupportedVM,
   1.733 +                                           iter.script(), iter.script(), nullptr);
   1.734 +            break;
   1.735 +        }
   1.736 +        ++iter;
   1.737 +    }
   1.738 +
   1.739 +    while (!iter.isEntry()) {
   1.740 +        if (iter.isScripted())
   1.741 +            PropagateAbortPar(iter.script(), iter.script());
   1.742 +        ++iter;
   1.743 +    }
   1.744 +
   1.745 +    rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
   1.746 +    rfe->stackPointer = iter.fp();
   1.747 +}
   1.748 +
   1.749 +void
   1.750 +EnsureExitFrame(IonCommonFrameLayout *frame)
   1.751 +{
   1.752 +    if (frame->prevType() == JitFrame_Unwound_IonJS ||
   1.753 +        frame->prevType() == JitFrame_Unwound_BaselineStub ||
   1.754 +        frame->prevType() == JitFrame_Unwound_Rectifier)
   1.755 +    {
   1.756 +        // Already an exit frame, nothing to do.
   1.757 +        return;
   1.758 +    }
   1.759 +
   1.760 +    if (frame->prevType() == JitFrame_Entry) {
   1.761 +        // The previous frame type is the entry frame, so there's no actual
   1.762 +        // need for an exit frame.
   1.763 +        return;
   1.764 +    }
   1.765 +
   1.766 +    if (frame->prevType() == JitFrame_Rectifier) {
   1.767 +        // The rectifier code uses the frame descriptor to discard its stack,
   1.768 +        // so modifying its descriptor size here would be dangerous. Instead,
   1.769 +        // we change the frame type, and teach the stack walking code how to
   1.770 +        // deal with this edge case. bug 717297 would obviate the need
   1.771 +        frame->changePrevType(JitFrame_Unwound_Rectifier);
   1.772 +        return;
   1.773 +    }
   1.774 +
   1.775 +    if (frame->prevType() == JitFrame_BaselineStub) {
   1.776 +        frame->changePrevType(JitFrame_Unwound_BaselineStub);
   1.777 +        return;
   1.778 +    }
   1.779 +
   1.780 +    JS_ASSERT(frame->prevType() == JitFrame_IonJS);
   1.781 +    frame->changePrevType(JitFrame_Unwound_IonJS);
   1.782 +}
   1.783 +
   1.784 +CalleeToken
   1.785 +MarkCalleeToken(JSTracer *trc, CalleeToken token)
   1.786 +{
   1.787 +    switch (GetCalleeTokenTag(token)) {
   1.788 +      case CalleeToken_Function:
   1.789 +      {
   1.790 +        JSFunction *fun = CalleeTokenToFunction(token);
   1.791 +        MarkObjectRoot(trc, &fun, "ion-callee");
   1.792 +        return CalleeToToken(fun);
   1.793 +      }
   1.794 +      case CalleeToken_Script:
   1.795 +      {
   1.796 +        JSScript *script = CalleeTokenToScript(token);
   1.797 +        MarkScriptRoot(trc, &script, "ion-entry");
   1.798 +        return CalleeToToken(script);
   1.799 +      }
   1.800 +      default:
   1.801 +        MOZ_ASSUME_UNREACHABLE("unknown callee token type");
   1.802 +    }
   1.803 +}
   1.804 +
   1.805 +#ifdef JS_NUNBOX32
   1.806 +static inline uintptr_t
   1.807 +ReadAllocation(const JitFrameIterator &frame, const LAllocation *a)
   1.808 +{
   1.809 +    if (a->isGeneralReg()) {
   1.810 +        Register reg = a->toGeneralReg()->reg();
   1.811 +        return frame.machineState().read(reg);
   1.812 +    }
   1.813 +    if (a->isStackSlot()) {
   1.814 +        uint32_t slot = a->toStackSlot()->slot();
   1.815 +        return *frame.jsFrame()->slotRef(slot);
   1.816 +    }
   1.817 +    uint32_t index = a->toArgument()->index();
   1.818 +    uint8_t *argv = reinterpret_cast<uint8_t *>(frame.jsFrame()->argv());
   1.819 +    return *reinterpret_cast<uintptr_t *>(argv + index);
   1.820 +}
   1.821 +#endif
   1.822 +
   1.823 +static void
   1.824 +MarkActualArguments(JSTracer *trc, const JitFrameIterator &frame)
   1.825 +{
   1.826 +    IonJSFrameLayout *layout = frame.jsFrame();
   1.827 +    JS_ASSERT(CalleeTokenIsFunction(layout->calleeToken()));
   1.828 +
   1.829 +    size_t nargs = frame.numActualArgs();
   1.830 +
   1.831 +    // Trace function arguments. Note + 1 for thisv.
   1.832 +    Value *argv = layout->argv();
   1.833 +    for (size_t i = 0; i < nargs + 1; i++)
   1.834 +        gc::MarkValueRoot(trc, &argv[i], "ion-argv");
   1.835 +}
   1.836 +
   1.837 +#ifdef JS_NUNBOX32
   1.838 +static inline void
   1.839 +WriteAllocation(const JitFrameIterator &frame, const LAllocation *a, uintptr_t value)
   1.840 +{
   1.841 +    if (a->isGeneralReg()) {
   1.842 +        Register reg = a->toGeneralReg()->reg();
   1.843 +        frame.machineState().write(reg, value);
   1.844 +        return;
   1.845 +    }
   1.846 +    if (a->isStackSlot()) {
   1.847 +        uint32_t slot = a->toStackSlot()->slot();
   1.848 +        *frame.jsFrame()->slotRef(slot) = value;
   1.849 +        return;
   1.850 +    }
   1.851 +    uint32_t index = a->toArgument()->index();
   1.852 +    uint8_t *argv = reinterpret_cast<uint8_t *>(frame.jsFrame()->argv());
   1.853 +    *reinterpret_cast<uintptr_t *>(argv + index) = value;
   1.854 +}
   1.855 +#endif
   1.856 +
   1.857 +static void
   1.858 +MarkIonJSFrame(JSTracer *trc, const JitFrameIterator &frame)
   1.859 +{
   1.860 +    IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp();
   1.861 +
   1.862 +    layout->replaceCalleeToken(MarkCalleeToken(trc, layout->calleeToken()));
   1.863 +
   1.864 +    IonScript *ionScript = nullptr;
   1.865 +    if (frame.checkInvalidation(&ionScript)) {
   1.866 +        // This frame has been invalidated, meaning that its IonScript is no
   1.867 +        // longer reachable through the callee token (JSFunction/JSScript->ion
   1.868 +        // is now nullptr or recompiled). Manually trace it here.
   1.869 +        IonScript::Trace(trc, ionScript);
   1.870 +    } else if (CalleeTokenIsFunction(layout->calleeToken())) {
   1.871 +        ionScript = CalleeTokenToFunction(layout->calleeToken())->nonLazyScript()->ionScript();
   1.872 +    } else {
   1.873 +        ionScript = CalleeTokenToScript(layout->calleeToken())->ionScript();
   1.874 +    }
   1.875 +
   1.876 +    if (CalleeTokenIsFunction(layout->calleeToken()))
   1.877 +        MarkActualArguments(trc, frame);
   1.878 +
   1.879 +    const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp());
   1.880 +
   1.881 +    SafepointReader safepoint(ionScript, si);
   1.882 +
   1.883 +    // Scan through slots which contain pointers (or on punboxing systems,
   1.884 +    // actual values).
   1.885 +    uint32_t slot;
   1.886 +    while (safepoint.getGcSlot(&slot)) {
   1.887 +        uintptr_t *ref = layout->slotRef(slot);
   1.888 +        gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(ref), "ion-gc-slot");
   1.889 +    }
   1.890 +
   1.891 +    while (safepoint.getValueSlot(&slot)) {
   1.892 +        Value *v = (Value *)layout->slotRef(slot);
   1.893 +        gc::MarkValueRoot(trc, v, "ion-gc-slot");
   1.894 +    }
   1.895 +
   1.896 +    uintptr_t *spill = frame.spillBase();
   1.897 +    GeneralRegisterSet gcRegs = safepoint.gcSpills();
   1.898 +    GeneralRegisterSet valueRegs = safepoint.valueSpills();
   1.899 +    for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
   1.900 +        --spill;
   1.901 +        if (gcRegs.has(*iter))
   1.902 +            gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(spill), "ion-gc-spill");
   1.903 +        else if (valueRegs.has(*iter))
   1.904 +            gc::MarkValueRoot(trc, reinterpret_cast<Value *>(spill), "ion-value-spill");
   1.905 +    }
   1.906 +
   1.907 +#ifdef JS_NUNBOX32
   1.908 +    LAllocation type, payload;
   1.909 +    while (safepoint.getNunboxSlot(&type, &payload)) {
   1.910 +        jsval_layout layout;
   1.911 +        layout.s.tag = (JSValueTag)ReadAllocation(frame, &type);
   1.912 +        layout.s.payload.uintptr = ReadAllocation(frame, &payload);
   1.913 +
   1.914 +        Value v = IMPL_TO_JSVAL(layout);
   1.915 +        gc::MarkValueRoot(trc, &v, "ion-torn-value");
   1.916 +
   1.917 +        if (v != IMPL_TO_JSVAL(layout)) {
   1.918 +            // GC moved the value, replace the stored payload.
   1.919 +            layout = JSVAL_TO_IMPL(v);
   1.920 +            WriteAllocation(frame, &payload, layout.s.payload.uintptr);
   1.921 +        }
   1.922 +    }
   1.923 +#endif
   1.924 +}
   1.925 +
   1.926 +#ifdef JSGC_GENERATIONAL
   1.927 +static void
   1.928 +UpdateIonJSFrameForMinorGC(JSTracer *trc, const JitFrameIterator &frame)
   1.929 +{
   1.930 +    // Minor GCs may move slots/elements allocated in the nursery. Update
   1.931 +    // any slots/elements pointers stored in this frame.
   1.932 +
   1.933 +    IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp();
   1.934 +
   1.935 +    IonScript *ionScript = nullptr;
   1.936 +    if (frame.checkInvalidation(&ionScript)) {
   1.937 +        // This frame has been invalidated, meaning that its IonScript is no
   1.938 +        // longer reachable through the callee token (JSFunction/JSScript->ion
   1.939 +        // is now nullptr or recompiled).
   1.940 +    } else if (CalleeTokenIsFunction(layout->calleeToken())) {
   1.941 +        ionScript = CalleeTokenToFunction(layout->calleeToken())->nonLazyScript()->ionScript();
   1.942 +    } else {
   1.943 +        ionScript = CalleeTokenToScript(layout->calleeToken())->ionScript();
   1.944 +    }
   1.945 +
   1.946 +    const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp());
   1.947 +    SafepointReader safepoint(ionScript, si);
   1.948 +
   1.949 +    GeneralRegisterSet slotsRegs = safepoint.slotsOrElementsSpills();
   1.950 +    uintptr_t *spill = frame.spillBase();
   1.951 +    for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
   1.952 +        --spill;
   1.953 +        if (slotsRegs.has(*iter))
   1.954 +            trc->runtime()->gcNursery.forwardBufferPointer(reinterpret_cast<HeapSlot **>(spill));
   1.955 +    }
   1.956 +
   1.957 +    // Skip to the right place in the safepoint
   1.958 +    uint32_t slot;
   1.959 +    while (safepoint.getGcSlot(&slot));
   1.960 +    while (safepoint.getValueSlot(&slot));
   1.961 +#ifdef JS_NUNBOX32
   1.962 +    LAllocation type, payload;
   1.963 +    while (safepoint.getNunboxSlot(&type, &payload));
   1.964 +#endif
   1.965 +
   1.966 +    while (safepoint.getSlotsOrElementsSlot(&slot)) {
   1.967 +        HeapSlot **slots = reinterpret_cast<HeapSlot **>(layout->slotRef(slot));
   1.968 +        trc->runtime()->gcNursery.forwardBufferPointer(slots);
   1.969 +    }
   1.970 +}
   1.971 +#endif
   1.972 +
   1.973 +static void
   1.974 +MarkBaselineStubFrame(JSTracer *trc, const JitFrameIterator &frame)
   1.975 +{
   1.976 +    // Mark the ICStub pointer stored in the stub frame. This is necessary
   1.977 +    // so that we don't destroy the stub code after unlinking the stub.
   1.978 +
   1.979 +    JS_ASSERT(frame.type() == JitFrame_BaselineStub);
   1.980 +    IonBaselineStubFrameLayout *layout = (IonBaselineStubFrameLayout *)frame.fp();
   1.981 +
   1.982 +    if (ICStub *stub = layout->maybeStubPtr()) {
   1.983 +        JS_ASSERT(ICStub::CanMakeCalls(stub->kind()));
   1.984 +        stub->trace(trc);
   1.985 +    }
   1.986 +}
   1.987 +
   1.988 +void
   1.989 +JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
   1.990 +{
   1.991 +    JitFrameIterator frames(jitTop(), SequentialExecution);
   1.992 +
   1.993 +    if (frames.isFakeExitFrame()) {
   1.994 +        min = reinterpret_cast<uintptr_t *>(frames.fp());
   1.995 +    } else {
   1.996 +        IonExitFrameLayout *exitFrame = frames.exitFrame();
   1.997 +        IonExitFooterFrame *footer = exitFrame->footer();
   1.998 +        const VMFunction *f = footer->function();
   1.999 +        if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) {
  1.1000 +            switch (f->outParamRootType) {
  1.1001 +              case VMFunction::RootNone:
  1.1002 +                MOZ_ASSUME_UNREACHABLE("Handle outparam must have root type");
  1.1003 +              case VMFunction::RootObject:
  1.1004 +              case VMFunction::RootString:
  1.1005 +              case VMFunction::RootPropertyName:
  1.1006 +              case VMFunction::RootFunction:
  1.1007 +              case VMFunction::RootCell:
  1.1008 +                // These are all handles to GCThing pointers.
  1.1009 +                min = reinterpret_cast<uintptr_t *>(footer->outParam<void *>());
  1.1010 +                break;
  1.1011 +              case VMFunction::RootValue:
  1.1012 +                min = reinterpret_cast<uintptr_t *>(footer->outParam<Value>());
  1.1013 +                break;
  1.1014 +            }
  1.1015 +        } else {
  1.1016 +            min = reinterpret_cast<uintptr_t *>(footer);
  1.1017 +        }
  1.1018 +    }
  1.1019 +
  1.1020 +    while (!frames.done())
  1.1021 +        ++frames;
  1.1022 +
  1.1023 +    end = reinterpret_cast<uintptr_t *>(frames.prevFp());
  1.1024 +}
  1.1025 +
  1.1026 +static void
  1.1027 +MarkJitExitFrame(JSTracer *trc, const JitFrameIterator &frame)
  1.1028 +{
  1.1029 +    // Ignore fake exit frames created by EnsureExitFrame.
  1.1030 +    if (frame.isFakeExitFrame())
  1.1031 +        return;
  1.1032 +
  1.1033 +    IonExitFooterFrame *footer = frame.exitFrame()->footer();
  1.1034 +
  1.1035 +    // Mark the code of the code handling the exit path.  This is needed because
  1.1036 +    // invalidated script are no longer marked because data are erased by the
  1.1037 +    // invalidation and relocation data are no longer reliable.  So the VM
  1.1038 +    // wrapper or the invalidation code may be GC if no JitCode keep reference
  1.1039 +    // on them.
  1.1040 +    JS_ASSERT(uintptr_t(footer->jitCode()) != uintptr_t(-1));
  1.1041 +
  1.1042 +    // This correspond to the case where we have build a fake exit frame in
  1.1043 +    // CodeGenerator.cpp which handle the case of a native function call. We
  1.1044 +    // need to mark the argument vector of the function call.
  1.1045 +    if (frame.isNative()) {
  1.1046 +        IonNativeExitFrameLayout *native = frame.exitFrame()->nativeExit();
  1.1047 +        size_t len = native->argc() + 2;
  1.1048 +        Value *vp = native->vp();
  1.1049 +        gc::MarkValueRootRange(trc, len, vp, "ion-native-args");
  1.1050 +        return;
  1.1051 +    }
  1.1052 +
  1.1053 +    if (frame.isOOLNative()) {
  1.1054 +        IonOOLNativeExitFrameLayout *oolnative = frame.exitFrame()->oolNativeExit();
  1.1055 +        gc::MarkJitCodeRoot(trc, oolnative->stubCode(), "ion-ool-native-code");
  1.1056 +        gc::MarkValueRoot(trc, oolnative->vp(), "iol-ool-native-vp");
  1.1057 +        size_t len = oolnative->argc() + 1;
  1.1058 +        gc::MarkValueRootRange(trc, len, oolnative->thisp(), "ion-ool-native-thisargs");
  1.1059 +        return;
  1.1060 +    }
  1.1061 +
  1.1062 +    if (frame.isOOLPropertyOp()) {
  1.1063 +        IonOOLPropertyOpExitFrameLayout *oolgetter = frame.exitFrame()->oolPropertyOpExit();
  1.1064 +        gc::MarkJitCodeRoot(trc, oolgetter->stubCode(), "ion-ool-property-op-code");
  1.1065 +        gc::MarkValueRoot(trc, oolgetter->vp(), "ion-ool-property-op-vp");
  1.1066 +        gc::MarkIdRoot(trc, oolgetter->id(), "ion-ool-property-op-id");
  1.1067 +        gc::MarkObjectRoot(trc, oolgetter->obj(), "ion-ool-property-op-obj");
  1.1068 +        return;
  1.1069 +    }
  1.1070 +
  1.1071 +    if (frame.isOOLProxy()) {
  1.1072 +        IonOOLProxyExitFrameLayout *oolproxy = frame.exitFrame()->oolProxyExit();
  1.1073 +        gc::MarkJitCodeRoot(trc, oolproxy->stubCode(), "ion-ool-proxy-code");
  1.1074 +        gc::MarkValueRoot(trc, oolproxy->vp(), "ion-ool-proxy-vp");
  1.1075 +        gc::MarkIdRoot(trc, oolproxy->id(), "ion-ool-proxy-id");
  1.1076 +        gc::MarkObjectRoot(trc, oolproxy->proxy(), "ion-ool-proxy-proxy");
  1.1077 +        gc::MarkObjectRoot(trc, oolproxy->receiver(), "ion-ool-proxy-receiver");
  1.1078 +        return;
  1.1079 +    }
  1.1080 +
  1.1081 +    if (frame.isDOMExit()) {
  1.1082 +        IonDOMExitFrameLayout *dom = frame.exitFrame()->DOMExit();
  1.1083 +        gc::MarkObjectRoot(trc, dom->thisObjAddress(), "ion-dom-args");
  1.1084 +        if (dom->isMethodFrame()) {
  1.1085 +            IonDOMMethodExitFrameLayout *method =
  1.1086 +                reinterpret_cast<IonDOMMethodExitFrameLayout *>(dom);
  1.1087 +            size_t len = method->argc() + 2;
  1.1088 +            Value *vp = method->vp();
  1.1089 +            gc::MarkValueRootRange(trc, len, vp, "ion-dom-args");
  1.1090 +        } else {
  1.1091 +            gc::MarkValueRoot(trc, dom->vp(), "ion-dom-args");
  1.1092 +        }
  1.1093 +        return;
  1.1094 +    }
  1.1095 +
  1.1096 +    MarkJitCodeRoot(trc, footer->addressOfJitCode(), "ion-exit-code");
  1.1097 +
  1.1098 +    const VMFunction *f = footer->function();
  1.1099 +    if (f == nullptr)
  1.1100 +        return;
  1.1101 +
  1.1102 +    // Mark arguments of the VM wrapper.
  1.1103 +    uint8_t *argBase = frame.exitFrame()->argBase();
  1.1104 +    for (uint32_t explicitArg = 0; explicitArg < f->explicitArgs; explicitArg++) {
  1.1105 +        switch (f->argRootType(explicitArg)) {
  1.1106 +          case VMFunction::RootNone:
  1.1107 +            break;
  1.1108 +          case VMFunction::RootObject: {
  1.1109 +            // Sometimes we can bake in HandleObjects to nullptr.
  1.1110 +            JSObject **pobj = reinterpret_cast<JSObject **>(argBase);
  1.1111 +            if (*pobj)
  1.1112 +                gc::MarkObjectRoot(trc, pobj, "ion-vm-args");
  1.1113 +            break;
  1.1114 +          }
  1.1115 +          case VMFunction::RootString:
  1.1116 +          case VMFunction::RootPropertyName:
  1.1117 +            gc::MarkStringRoot(trc, reinterpret_cast<JSString**>(argBase), "ion-vm-args");
  1.1118 +            break;
  1.1119 +          case VMFunction::RootFunction:
  1.1120 +            gc::MarkObjectRoot(trc, reinterpret_cast<JSFunction**>(argBase), "ion-vm-args");
  1.1121 +            break;
  1.1122 +          case VMFunction::RootValue:
  1.1123 +            gc::MarkValueRoot(trc, reinterpret_cast<Value*>(argBase), "ion-vm-args");
  1.1124 +            break;
  1.1125 +          case VMFunction::RootCell:
  1.1126 +            gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(argBase), "ion-vm-args");
  1.1127 +            break;
  1.1128 +        }
  1.1129 +
  1.1130 +        switch (f->argProperties(explicitArg)) {
  1.1131 +          case VMFunction::WordByValue:
  1.1132 +          case VMFunction::WordByRef:
  1.1133 +            argBase += sizeof(void *);
  1.1134 +            break;
  1.1135 +          case VMFunction::DoubleByValue:
  1.1136 +          case VMFunction::DoubleByRef:
  1.1137 +            argBase += 2 * sizeof(void *);
  1.1138 +            break;
  1.1139 +        }
  1.1140 +    }
  1.1141 +
  1.1142 +    if (f->outParam == Type_Handle) {
  1.1143 +        switch (f->outParamRootType) {
  1.1144 +          case VMFunction::RootNone:
  1.1145 +            MOZ_ASSUME_UNREACHABLE("Handle outparam must have root type");
  1.1146 +          case VMFunction::RootObject:
  1.1147 +            gc::MarkObjectRoot(trc, footer->outParam<JSObject *>(), "ion-vm-out");
  1.1148 +            break;
  1.1149 +          case VMFunction::RootString:
  1.1150 +          case VMFunction::RootPropertyName:
  1.1151 +            gc::MarkStringRoot(trc, footer->outParam<JSString *>(), "ion-vm-out");
  1.1152 +            break;
  1.1153 +          case VMFunction::RootFunction:
  1.1154 +            gc::MarkObjectRoot(trc, footer->outParam<JSFunction *>(), "ion-vm-out");
  1.1155 +            break;
  1.1156 +          case VMFunction::RootValue:
  1.1157 +            gc::MarkValueRoot(trc, footer->outParam<Value>(), "ion-vm-outvp");
  1.1158 +            break;
  1.1159 +          case VMFunction::RootCell:
  1.1160 +            gc::MarkGCThingRoot(trc, footer->outParam<void *>(), "ion-vm-out");
  1.1161 +            break;
  1.1162 +        }
  1.1163 +    }
  1.1164 +}
  1.1165 +
  1.1166 +static void
  1.1167 +MarkRectifierFrame(JSTracer *trc, const JitFrameIterator &frame)
  1.1168 +{
  1.1169 +    // Mark thisv.
  1.1170 +    //
  1.1171 +    // Baseline JIT code generated as part of the ICCall_Fallback stub may use
  1.1172 +    // it if we're calling a constructor that returns a primitive value.
  1.1173 +    IonRectifierFrameLayout *layout = (IonRectifierFrameLayout *)frame.fp();
  1.1174 +    gc::MarkValueRoot(trc, &layout->argv()[0], "ion-thisv");
  1.1175 +}
  1.1176 +
  1.1177 +static void
  1.1178 +MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
  1.1179 +{
  1.1180 +    JitActivation *activation = activations->asJit();
  1.1181 +
  1.1182 +#ifdef CHECK_OSIPOINT_REGISTERS
  1.1183 +    if (js_JitOptions.checkOsiPointRegisters) {
  1.1184 +        // GC can modify spilled registers, breaking our register checks.
  1.1185 +        // To handle this, we disable these checks for the current VM call
  1.1186 +        // when a GC happens.
  1.1187 +        activation->setCheckRegs(false);
  1.1188 +    }
  1.1189 +#endif
  1.1190 +
  1.1191 +    activation->markRematerializedFrames(trc);
  1.1192 +
  1.1193 +    for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
  1.1194 +        switch (frames.type()) {
  1.1195 +          case JitFrame_Exit:
  1.1196 +            MarkJitExitFrame(trc, frames);
  1.1197 +            break;
  1.1198 +          case JitFrame_BaselineJS:
  1.1199 +            frames.baselineFrame()->trace(trc, frames);
  1.1200 +            break;
  1.1201 +          case JitFrame_BaselineStub:
  1.1202 +            MarkBaselineStubFrame(trc, frames);
  1.1203 +            break;
  1.1204 +          case JitFrame_IonJS:
  1.1205 +            MarkIonJSFrame(trc, frames);
  1.1206 +            break;
  1.1207 +          case JitFrame_Unwound_IonJS:
  1.1208 +            MOZ_ASSUME_UNREACHABLE("invalid");
  1.1209 +          case JitFrame_Rectifier:
  1.1210 +            MarkRectifierFrame(trc, frames);
  1.1211 +            break;
  1.1212 +          case JitFrame_Unwound_Rectifier:
  1.1213 +            break;
  1.1214 +          default:
  1.1215 +            MOZ_ASSUME_UNREACHABLE("unexpected frame type");
  1.1216 +        }
  1.1217 +    }
  1.1218 +}
  1.1219 +
  1.1220 +void
  1.1221 +MarkJitActivations(JSRuntime *rt, JSTracer *trc)
  1.1222 +{
  1.1223 +    for (JitActivationIterator activations(rt); !activations.done(); ++activations)
  1.1224 +        MarkJitActivation(trc, activations);
  1.1225 +}
  1.1226 +
  1.1227 +#ifdef JSGC_GENERATIONAL
  1.1228 +void
  1.1229 +UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc)
  1.1230 +{
  1.1231 +    JS_ASSERT(trc->runtime()->isHeapMinorCollecting());
  1.1232 +    for (JitActivationIterator activations(rt); !activations.done(); ++activations) {
  1.1233 +        for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
  1.1234 +            if (frames.type() == JitFrame_IonJS)
  1.1235 +                UpdateIonJSFrameForMinorGC(trc, frames);
  1.1236 +        }
  1.1237 +    }
  1.1238 +}
  1.1239 +#endif
  1.1240 +
  1.1241 +void
  1.1242 +AutoTempAllocatorRooter::trace(JSTracer *trc)
  1.1243 +{
  1.1244 +    for (CompilerRootNode *root = temp->rootList(); root != nullptr; root = root->next)
  1.1245 +        gc::MarkGCThingRoot(trc, root->address(), "ion-compiler-root");
  1.1246 +}
  1.1247 +
  1.1248 +void
  1.1249 +GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
  1.1250 +{
  1.1251 +    IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
  1.1252 +
  1.1253 +    JSRuntime *rt = cx->runtime();
  1.1254 +
  1.1255 +    // Recover the return address.
  1.1256 +    JitFrameIterator it(rt->mainThread.ionTop, SequentialExecution);
  1.1257 +
  1.1258 +    // If the previous frame is a rectifier frame (maybe unwound),
  1.1259 +    // skip past it.
  1.1260 +    if (it.prevType() == JitFrame_Rectifier || it.prevType() == JitFrame_Unwound_Rectifier) {
  1.1261 +        ++it;
  1.1262 +        JS_ASSERT(it.prevType() == JitFrame_BaselineStub ||
  1.1263 +                  it.prevType() == JitFrame_BaselineJS ||
  1.1264 +                  it.prevType() == JitFrame_IonJS);
  1.1265 +    }
  1.1266 +
  1.1267 +    // If the previous frame is a stub frame, skip the exit frame so that
  1.1268 +    // returnAddress below gets the return address into the BaselineJS
  1.1269 +    // frame.
  1.1270 +    if (it.prevType() == JitFrame_BaselineStub || it.prevType() == JitFrame_Unwound_BaselineStub) {
  1.1271 +        ++it;
  1.1272 +        JS_ASSERT(it.prevType() == JitFrame_BaselineJS);
  1.1273 +    }
  1.1274 +
  1.1275 +    uint8_t *retAddr = it.returnAddress();
  1.1276 +    uint32_t hash = PcScriptCache::Hash(retAddr);
  1.1277 +    JS_ASSERT(retAddr != nullptr);
  1.1278 +
  1.1279 +    // Lazily initialize the cache. The allocation may safely fail and will not GC.
  1.1280 +    if (MOZ_UNLIKELY(rt->ionPcScriptCache == nullptr)) {
  1.1281 +        rt->ionPcScriptCache = (PcScriptCache *)js_malloc(sizeof(struct PcScriptCache));
  1.1282 +        if (rt->ionPcScriptCache)
  1.1283 +            rt->ionPcScriptCache->clear(rt->gcNumber);
  1.1284 +    }
  1.1285 +
  1.1286 +    // Attempt to lookup address in cache.
  1.1287 +    if (rt->ionPcScriptCache && rt->ionPcScriptCache->get(rt, hash, retAddr, scriptRes, pcRes))
  1.1288 +        return;
  1.1289 +
  1.1290 +    // Lookup failed: undertake expensive process to recover the innermost inlined frame.
  1.1291 +    ++it; // Skip exit frame.
  1.1292 +    jsbytecode *pc = nullptr;
  1.1293 +
  1.1294 +    if (it.isIonJS()) {
  1.1295 +        InlineFrameIterator ifi(cx, &it);
  1.1296 +        *scriptRes = ifi.script();
  1.1297 +        pc = ifi.pc();
  1.1298 +    } else {
  1.1299 +        JS_ASSERT(it.isBaselineJS());
  1.1300 +        it.baselineScriptAndPc(scriptRes, &pc);
  1.1301 +    }
  1.1302 +
  1.1303 +    if (pcRes)
  1.1304 +        *pcRes = pc;
  1.1305 +
  1.1306 +    // Add entry to cache.
  1.1307 +    if (rt->ionPcScriptCache)
  1.1308 +        rt->ionPcScriptCache->add(hash, retAddr, pc, *scriptRes);
  1.1309 +}
  1.1310 +
  1.1311 +void
  1.1312 +OsiIndex::fixUpOffset(MacroAssembler &masm)
  1.1313 +{
  1.1314 +    callPointDisplacement_ = masm.actualOffset(callPointDisplacement_);
  1.1315 +}
  1.1316 +
  1.1317 +uint32_t
  1.1318 +OsiIndex::returnPointDisplacement() const
  1.1319 +{
  1.1320 +    // In general, pointer arithmetic on code is bad, but in this case,
  1.1321 +    // getting the return address from a call instruction, stepping over pools
  1.1322 +    // would be wrong.
  1.1323 +    return callPointDisplacement_ + Assembler::patchWrite_NearCallSize();
  1.1324 +}
  1.1325 +
  1.1326 +SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
  1.1327 +                                   IonJSFrameLayout *fp, const MachineState &machine)
  1.1328 +  : snapshot_(ionScript->snapshots(),
  1.1329 +              snapshotOffset,
  1.1330 +              ionScript->snapshotsRVATableSize(),
  1.1331 +              ionScript->snapshotsListSize()),
  1.1332 +    recover_(snapshot_,
  1.1333 +             ionScript->recovers(),
  1.1334 +             ionScript->recoversSize()),
  1.1335 +    fp_(fp),
  1.1336 +    machine_(machine),
  1.1337 +    ionScript_(ionScript)
  1.1338 +{
  1.1339 +    JS_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
  1.1340 +}
  1.1341 +
  1.1342 +SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
  1.1343 +  : snapshot_(iter.ionScript()->snapshots(),
  1.1344 +              iter.osiIndex()->snapshotOffset(),
  1.1345 +              iter.ionScript()->snapshotsRVATableSize(),
  1.1346 +              iter.ionScript()->snapshotsListSize()),
  1.1347 +    recover_(snapshot_,
  1.1348 +             iter.ionScript()->recovers(),
  1.1349 +             iter.ionScript()->recoversSize()),
  1.1350 +    fp_(iter.jsFrame()),
  1.1351 +    machine_(iter.machineState()),
  1.1352 +    ionScript_(iter.ionScript())
  1.1353 +{
  1.1354 +}
  1.1355 +
  1.1356 +SnapshotIterator::SnapshotIterator()
  1.1357 +  : snapshot_(nullptr, 0, 0, 0),
  1.1358 +    recover_(snapshot_, nullptr, 0),
  1.1359 +    fp_(nullptr),
  1.1360 +    ionScript_(nullptr)
  1.1361 +{
  1.1362 +}
  1.1363 +
  1.1364 +uintptr_t
  1.1365 +SnapshotIterator::fromStack(int32_t offset) const
  1.1366 +{
  1.1367 +    return ReadFrameSlot(fp_, offset);
  1.1368 +}
  1.1369 +
  1.1370 +static Value
  1.1371 +FromObjectPayload(uintptr_t payload)
  1.1372 +{
  1.1373 +    return ObjectValue(*reinterpret_cast<JSObject *>(payload));
  1.1374 +}
  1.1375 +
  1.1376 +static Value
  1.1377 +FromStringPayload(uintptr_t payload)
  1.1378 +{
  1.1379 +    return StringValue(reinterpret_cast<JSString *>(payload));
  1.1380 +}
  1.1381 +
  1.1382 +static Value
  1.1383 +FromTypedPayload(JSValueType type, uintptr_t payload)
  1.1384 +{
  1.1385 +    switch (type) {
  1.1386 +      case JSVAL_TYPE_INT32:
  1.1387 +        return Int32Value(payload);
  1.1388 +      case JSVAL_TYPE_BOOLEAN:
  1.1389 +        return BooleanValue(!!payload);
  1.1390 +      case JSVAL_TYPE_STRING:
  1.1391 +        return FromStringPayload(payload);
  1.1392 +      case JSVAL_TYPE_OBJECT:
  1.1393 +        return FromObjectPayload(payload);
  1.1394 +      default:
  1.1395 +        MOZ_ASSUME_UNREACHABLE("unexpected type - needs payload");
  1.1396 +    }
  1.1397 +}
  1.1398 +
  1.1399 +bool
  1.1400 +SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
  1.1401 +{
  1.1402 +    switch (alloc.mode()) {
  1.1403 +      case RValueAllocation::DOUBLE_REG:
  1.1404 +        return hasRegister(alloc.fpuReg());
  1.1405 +
  1.1406 +      case RValueAllocation::TYPED_REG:
  1.1407 +        return hasRegister(alloc.reg2());
  1.1408 +
  1.1409 +#if defined(JS_NUNBOX32)
  1.1410 +      case RValueAllocation::UNTYPED_REG_REG:
  1.1411 +        return hasRegister(alloc.reg()) && hasRegister(alloc.reg2());
  1.1412 +      case RValueAllocation::UNTYPED_REG_STACK:
  1.1413 +        return hasRegister(alloc.reg()) && hasStack(alloc.stackOffset2());
  1.1414 +      case RValueAllocation::UNTYPED_STACK_REG:
  1.1415 +        return hasStack(alloc.stackOffset()) && hasRegister(alloc.reg2());
  1.1416 +      case RValueAllocation::UNTYPED_STACK_STACK:
  1.1417 +        return hasStack(alloc.stackOffset()) && hasStack(alloc.stackOffset2());
  1.1418 +#elif defined(JS_PUNBOX64)
  1.1419 +      case RValueAllocation::UNTYPED_REG:
  1.1420 +        return hasRegister(alloc.reg());
  1.1421 +      case RValueAllocation::UNTYPED_STACK:
  1.1422 +        return hasStack(alloc.stackOffset());
  1.1423 +#endif
  1.1424 +
  1.1425 +      default:
  1.1426 +        return true;
  1.1427 +    }
  1.1428 +}
  1.1429 +
  1.1430 +Value
  1.1431 +SnapshotIterator::allocationValue(const RValueAllocation &alloc)
  1.1432 +{
  1.1433 +    switch (alloc.mode()) {
  1.1434 +      case RValueAllocation::CONSTANT:
  1.1435 +        return ionScript_->getConstant(alloc.index());
  1.1436 +
  1.1437 +      case RValueAllocation::CST_UNDEFINED:
  1.1438 +        return UndefinedValue();
  1.1439 +
  1.1440 +      case RValueAllocation::CST_NULL:
  1.1441 +        return NullValue();
  1.1442 +
  1.1443 +      case RValueAllocation::DOUBLE_REG:
  1.1444 +        return DoubleValue(fromRegister(alloc.fpuReg()));
  1.1445 +
  1.1446 +      case RValueAllocation::FLOAT32_REG:
  1.1447 +      {
  1.1448 +        union {
  1.1449 +            double d;
  1.1450 +            float f;
  1.1451 +        } pun;
  1.1452 +        pun.d = fromRegister(alloc.fpuReg());
  1.1453 +        // The register contains the encoding of a float32. We just read
  1.1454 +        // the bits without making any conversion.
  1.1455 +        return Float32Value(pun.f);
  1.1456 +      }
  1.1457 +
  1.1458 +      case RValueAllocation::FLOAT32_STACK:
  1.1459 +        return Float32Value(ReadFrameFloat32Slot(fp_, alloc.stackOffset()));
  1.1460 +
  1.1461 +      case RValueAllocation::TYPED_REG:
  1.1462 +        return FromTypedPayload(alloc.knownType(), fromRegister(alloc.reg2()));
  1.1463 +
  1.1464 +      case RValueAllocation::TYPED_STACK:
  1.1465 +      {
  1.1466 +        switch (alloc.knownType()) {
  1.1467 +          case JSVAL_TYPE_DOUBLE:
  1.1468 +            return DoubleValue(ReadFrameDoubleSlot(fp_, alloc.stackOffset2()));
  1.1469 +          case JSVAL_TYPE_INT32:
  1.1470 +            return Int32Value(ReadFrameInt32Slot(fp_, alloc.stackOffset2()));
  1.1471 +          case JSVAL_TYPE_BOOLEAN:
  1.1472 +            return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset2()));
  1.1473 +          case JSVAL_TYPE_STRING:
  1.1474 +            return FromStringPayload(fromStack(alloc.stackOffset2()));
  1.1475 +          case JSVAL_TYPE_OBJECT:
  1.1476 +            return FromObjectPayload(fromStack(alloc.stackOffset2()));
  1.1477 +          default:
  1.1478 +            MOZ_ASSUME_UNREACHABLE("Unexpected type");
  1.1479 +        }
  1.1480 +      }
  1.1481 +
  1.1482 +#if defined(JS_NUNBOX32)
  1.1483 +      case RValueAllocation::UNTYPED_REG_REG:
  1.1484 +      {
  1.1485 +        jsval_layout layout;
  1.1486 +        layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
  1.1487 +        layout.s.payload.word = fromRegister(alloc.reg2());
  1.1488 +        return IMPL_TO_JSVAL(layout);
  1.1489 +      }
  1.1490 +
  1.1491 +      case RValueAllocation::UNTYPED_REG_STACK:
  1.1492 +      {
  1.1493 +        jsval_layout layout;
  1.1494 +        layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
  1.1495 +        layout.s.payload.word = fromStack(alloc.stackOffset2());
  1.1496 +        return IMPL_TO_JSVAL(layout);
  1.1497 +      }
  1.1498 +
  1.1499 +      case RValueAllocation::UNTYPED_STACK_REG:
  1.1500 +      {
  1.1501 +        jsval_layout layout;
  1.1502 +        layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
  1.1503 +        layout.s.payload.word = fromRegister(alloc.reg2());
  1.1504 +        return IMPL_TO_JSVAL(layout);
  1.1505 +      }
  1.1506 +
  1.1507 +      case RValueAllocation::UNTYPED_STACK_STACK:
  1.1508 +      {
  1.1509 +        jsval_layout layout;
  1.1510 +        layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
  1.1511 +        layout.s.payload.word = fromStack(alloc.stackOffset2());
  1.1512 +        return IMPL_TO_JSVAL(layout);
  1.1513 +      }
  1.1514 +#elif defined(JS_PUNBOX64)
  1.1515 +      case RValueAllocation::UNTYPED_REG:
  1.1516 +      {
  1.1517 +        jsval_layout layout;
  1.1518 +        layout.asBits = fromRegister(alloc.reg());
  1.1519 +        return IMPL_TO_JSVAL(layout);
  1.1520 +      }
  1.1521 +
  1.1522 +      case RValueAllocation::UNTYPED_STACK:
  1.1523 +      {
  1.1524 +        jsval_layout layout;
  1.1525 +        layout.asBits = fromStack(alloc.stackOffset());
  1.1526 +        return IMPL_TO_JSVAL(layout);
  1.1527 +      }
  1.1528 +#endif
  1.1529 +
  1.1530 +      default:
  1.1531 +        MOZ_ASSUME_UNREACHABLE("huh?");
  1.1532 +    }
  1.1533 +}
  1.1534 +
  1.1535 +const RResumePoint *
  1.1536 +SnapshotIterator::resumePoint() const
  1.1537 +{
  1.1538 +    return instruction()->toResumePoint();
  1.1539 +}
  1.1540 +
  1.1541 +uint32_t
  1.1542 +SnapshotIterator::numAllocations() const
  1.1543 +{
  1.1544 +    return resumePoint()->numOperands();
  1.1545 +}
  1.1546 +
  1.1547 +uint32_t
  1.1548 +SnapshotIterator::pcOffset() const
  1.1549 +{
  1.1550 +    return resumePoint()->pcOffset();
  1.1551 +}
  1.1552 +
  1.1553 +void
  1.1554 +SnapshotIterator::skipInstruction()
  1.1555 +{
  1.1556 +    MOZ_ASSERT(snapshot_.numAllocationsRead() == 0);
  1.1557 +    size_t numOperands = instruction()->numOperands();
  1.1558 +    for (size_t i = 0; i < numOperands; i++)
  1.1559 +        skip();
  1.1560 +    nextInstruction();
  1.1561 +}
  1.1562 +
  1.1563 +void
  1.1564 +SnapshotIterator::nextFrame()
  1.1565 +{
  1.1566 +    nextInstruction();
  1.1567 +    while (!instruction()->isResumePoint())
  1.1568 +        skipInstruction();
  1.1569 +}
  1.1570 +
  1.1571 +IonScript *
  1.1572 +JitFrameIterator::ionScript() const
  1.1573 +{
  1.1574 +    JS_ASSERT(type() == JitFrame_IonJS);
  1.1575 +
  1.1576 +    IonScript *ionScript = nullptr;
  1.1577 +    if (checkInvalidation(&ionScript))
  1.1578 +        return ionScript;
  1.1579 +    switch (GetCalleeTokenTag(calleeToken())) {
  1.1580 +      case CalleeToken_Function:
  1.1581 +      case CalleeToken_Script:
  1.1582 +        return mode_ == ParallelExecution ? script()->parallelIonScript() : script()->ionScript();
  1.1583 +      default:
  1.1584 +        MOZ_ASSUME_UNREACHABLE("unknown callee token type");
  1.1585 +    }
  1.1586 +}
  1.1587 +
  1.1588 +const SafepointIndex *
  1.1589 +JitFrameIterator::safepoint() const
  1.1590 +{
  1.1591 +    if (!cachedSafepointIndex_)
  1.1592 +        cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp());
  1.1593 +    return cachedSafepointIndex_;
  1.1594 +}
  1.1595 +
  1.1596 +const OsiIndex *
  1.1597 +JitFrameIterator::osiIndex() const
  1.1598 +{
  1.1599 +    SafepointReader reader(ionScript(), safepoint());
  1.1600 +    return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
  1.1601 +}
  1.1602 +
  1.1603 +template <AllowGC allowGC>
  1.1604 +void
  1.1605 +InlineFrameIteratorMaybeGC<allowGC>::resetOn(const JitFrameIterator *iter)
  1.1606 +{
  1.1607 +    frame_ = iter;
  1.1608 +    framesRead_ = 0;
  1.1609 +    frameCount_ = UINT32_MAX;
  1.1610 +
  1.1611 +    if (iter) {
  1.1612 +        start_ = SnapshotIterator(*iter);
  1.1613 +        findNextFrame();
  1.1614 +    }
  1.1615 +}
  1.1616 +template void InlineFrameIteratorMaybeGC<NoGC>::resetOn(const JitFrameIterator *iter);
  1.1617 +template void InlineFrameIteratorMaybeGC<CanGC>::resetOn(const JitFrameIterator *iter);
  1.1618 +
  1.1619 +template <AllowGC allowGC>
  1.1620 +void
  1.1621 +InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
  1.1622 +{
  1.1623 +    JS_ASSERT(more());
  1.1624 +
  1.1625 +    si_ = start_;
  1.1626 +
  1.1627 +    // Read the initial frame out of the C stack.
  1.1628 +    callee_ = frame_->maybeCallee();
  1.1629 +    script_ = frame_->script();
  1.1630 +    MOZ_ASSERT(script_->hasBaselineScript());
  1.1631 +
  1.1632 +    // Settle on the outermost frame without evaluating any instructions before
  1.1633 +    // looking for a pc.
  1.1634 +    if (!si_.instruction()->isResumePoint())
  1.1635 +        si_.nextFrame();
  1.1636 +
  1.1637 +    pc_ = script_->offsetToPC(si_.pcOffset());
  1.1638 +#ifdef DEBUG
  1.1639 +    numActualArgs_ = 0xbadbad;
  1.1640 +#endif
  1.1641 +
  1.1642 +    // This unfortunately is O(n*m), because we must skip over outer frames
  1.1643 +    // before reading inner ones.
  1.1644 +
  1.1645 +    // The first time (frameCount_ == UINT32_MAX) we do not know the number of
  1.1646 +    // frames that we are going to inspect.  So we are iterating until there is
  1.1647 +    // no more frames, to settle on the inner most frame and to count the number
  1.1648 +    // of frames.
  1.1649 +    size_t remaining = (frameCount_ != UINT32_MAX) ? frameNo() - 1 : SIZE_MAX;
  1.1650 +
  1.1651 +    size_t i = 1;
  1.1652 +    for (; i <= remaining && si_.moreFrames(); i++) {
  1.1653 +        JS_ASSERT(IsIonInlinablePC(pc_));
  1.1654 +
  1.1655 +        // Recover the number of actual arguments from the script.
  1.1656 +        if (JSOp(*pc_) != JSOP_FUNAPPLY)
  1.1657 +            numActualArgs_ = GET_ARGC(pc_);
  1.1658 +        if (JSOp(*pc_) == JSOP_FUNCALL) {
  1.1659 +            JS_ASSERT(GET_ARGC(pc_) > 0);
  1.1660 +            numActualArgs_ = GET_ARGC(pc_) - 1;
  1.1661 +        } else if (IsGetPropPC(pc_)) {
  1.1662 +            numActualArgs_ = 0;
  1.1663 +        } else if (IsSetPropPC(pc_)) {
  1.1664 +            numActualArgs_ = 1;
  1.1665 +        }
  1.1666 +
  1.1667 +        JS_ASSERT(numActualArgs_ != 0xbadbad);
  1.1668 +
  1.1669 +        // Skip over non-argument slots, as well as |this|.
  1.1670 +        unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1;
  1.1671 +        for (unsigned j = 0; j < skipCount; j++)
  1.1672 +            si_.skip();
  1.1673 +
  1.1674 +        // The JSFunction is a constant, otherwise we would not have inlined it.
  1.1675 +        Value funval = si_.read();
  1.1676 +
  1.1677 +        // Skip extra value allocations.
  1.1678 +        while (si_.moreAllocations())
  1.1679 +            si_.skip();
  1.1680 +
  1.1681 +        si_.nextFrame();
  1.1682 +
  1.1683 +        callee_ = &funval.toObject().as<JSFunction>();
  1.1684 +
  1.1685 +        // Inlined functions may be clones that still point to the lazy script
  1.1686 +        // for the executed script, if they are clones. The actual script
  1.1687 +        // exists though, just make sure the function points to it.
  1.1688 +        script_ = callee_->existingScriptForInlinedFunction();
  1.1689 +        MOZ_ASSERT(script_->hasBaselineScript());
  1.1690 +
  1.1691 +        pc_ = script_->offsetToPC(si_.pcOffset());
  1.1692 +    }
  1.1693 +
  1.1694 +    // The first time we do not know the number of frames, we only settle on the
  1.1695 +    // last frame, and update the number of frames based on the number of
  1.1696 +    // iteration that we have done.
  1.1697 +    if (frameCount_ == UINT32_MAX) {
  1.1698 +        MOZ_ASSERT(!si_.moreFrames());
  1.1699 +        frameCount_ = i;
  1.1700 +    }
  1.1701 +
  1.1702 +    framesRead_++;
  1.1703 +}
  1.1704 +template void InlineFrameIteratorMaybeGC<NoGC>::findNextFrame();
  1.1705 +template void InlineFrameIteratorMaybeGC<CanGC>::findNextFrame();
  1.1706 +
  1.1707 +template <AllowGC allowGC>
  1.1708 +bool
  1.1709 +InlineFrameIteratorMaybeGC<allowGC>::isFunctionFrame() const
  1.1710 +{
  1.1711 +    return !!callee_;
  1.1712 +}
  1.1713 +template bool InlineFrameIteratorMaybeGC<NoGC>::isFunctionFrame() const;
  1.1714 +template bool InlineFrameIteratorMaybeGC<CanGC>::isFunctionFrame() const;
  1.1715 +
  1.1716 +MachineState
  1.1717 +MachineState::FromBailout(mozilla::Array<uintptr_t, Registers::Total> &regs,
  1.1718 +                          mozilla::Array<double, FloatRegisters::Total> &fpregs)
  1.1719 +{
  1.1720 +    MachineState machine;
  1.1721 +
  1.1722 +    for (unsigned i = 0; i < Registers::Total; i++)
  1.1723 +        machine.setRegisterLocation(Register::FromCode(i), &regs[i]);
  1.1724 +    for (unsigned i = 0; i < FloatRegisters::Total; i++)
  1.1725 +        machine.setRegisterLocation(FloatRegister::FromCode(i), &fpregs[i]);
  1.1726 +
  1.1727 +    return machine;
  1.1728 +}
  1.1729 +
  1.1730 +template <AllowGC allowGC>
  1.1731 +bool
  1.1732 +InlineFrameIteratorMaybeGC<allowGC>::isConstructing() const
  1.1733 +{
  1.1734 +    // Skip the current frame and look at the caller's.
  1.1735 +    if (more()) {
  1.1736 +        InlineFrameIteratorMaybeGC<allowGC> parent(GetJSContextFromJitCode(), this);
  1.1737 +        ++parent;
  1.1738 +
  1.1739 +        // Inlined Getters and Setters are never constructing.
  1.1740 +        if (IsGetPropPC(parent.pc()) || IsSetPropPC(parent.pc()))
  1.1741 +            return false;
  1.1742 +
  1.1743 +        // In the case of a JS frame, look up the pc from the snapshot.
  1.1744 +        JS_ASSERT(IsCallPC(parent.pc()));
  1.1745 +
  1.1746 +        return (JSOp)*parent.pc() == JSOP_NEW;
  1.1747 +    }
  1.1748 +
  1.1749 +    return frame_->isConstructing();
  1.1750 +}
  1.1751 +template bool InlineFrameIteratorMaybeGC<NoGC>::isConstructing() const;
  1.1752 +template bool InlineFrameIteratorMaybeGC<CanGC>::isConstructing() const;
  1.1753 +
  1.1754 +bool
  1.1755 +JitFrameIterator::isConstructing() const
  1.1756 +{
  1.1757 +    JitFrameIterator parent(*this);
  1.1758 +
  1.1759 +    // Skip the current frame and look at the caller's.
  1.1760 +    do {
  1.1761 +        ++parent;
  1.1762 +    } while (!parent.done() && !parent.isScripted());
  1.1763 +
  1.1764 +    if (parent.isIonJS()) {
  1.1765 +        // In the case of a JS frame, look up the pc from the snapshot.
  1.1766 +        InlineFrameIterator inlinedParent(GetJSContextFromJitCode(), &parent);
  1.1767 +
  1.1768 +        //Inlined Getters and Setters are never constructing.
  1.1769 +        if (IsGetPropPC(inlinedParent.pc()) || IsSetPropPC(inlinedParent.pc()))
  1.1770 +            return false;
  1.1771 +
  1.1772 +        JS_ASSERT(IsCallPC(inlinedParent.pc()));
  1.1773 +
  1.1774 +        return (JSOp)*inlinedParent.pc() == JSOP_NEW;
  1.1775 +    }
  1.1776 +
  1.1777 +    if (parent.isBaselineJS()) {
  1.1778 +        jsbytecode *pc;
  1.1779 +        parent.baselineScriptAndPc(nullptr, &pc);
  1.1780 +
  1.1781 +        // Inlined Getters and Setters are never constructing.
  1.1782 +        // Baseline may call getters from [GET|SET]PROP or [GET|SET]ELEM ops.
  1.1783 +        if (IsGetPropPC(pc) || IsSetPropPC(pc) || IsGetElemPC(pc) || IsSetElemPC(pc))
  1.1784 +            return false;
  1.1785 +
  1.1786 +        JS_ASSERT(IsCallPC(pc));
  1.1787 +
  1.1788 +        return JSOp(*pc) == JSOP_NEW;
  1.1789 +    }
  1.1790 +
  1.1791 +    JS_ASSERT(parent.done());
  1.1792 +    return activation_->firstFrameIsConstructing();
  1.1793 +}
  1.1794 +
  1.1795 +unsigned
  1.1796 +JitFrameIterator::numActualArgs() const
  1.1797 +{
  1.1798 +    if (isScripted())
  1.1799 +        return jsFrame()->numActualArgs();
  1.1800 +
  1.1801 +    JS_ASSERT(isNative());
  1.1802 +    return exitFrame()->nativeExit()->argc();
  1.1803 +}
  1.1804 +
  1.1805 +void
  1.1806 +SnapshotIterator::warnUnreadableAllocation()
  1.1807 +{
  1.1808 +    fprintf(stderr, "Warning! Tried to access unreadable value allocation (possible f.arguments).\n");
  1.1809 +}
  1.1810 +
  1.1811 +struct DumpOp {
  1.1812 +    DumpOp(unsigned int i) : i_(i) {}
  1.1813 +
  1.1814 +    unsigned int i_;
  1.1815 +    void operator()(const Value& v) {
  1.1816 +        fprintf(stderr, "  actual (arg %d): ", i_);
  1.1817 +#ifdef DEBUG
  1.1818 +        js_DumpValue(v);
  1.1819 +#else
  1.1820 +        fprintf(stderr, "?\n");
  1.1821 +#endif
  1.1822 +        i_++;
  1.1823 +    }
  1.1824 +};
  1.1825 +
  1.1826 +void
  1.1827 +JitFrameIterator::dumpBaseline() const
  1.1828 +{
  1.1829 +    JS_ASSERT(isBaselineJS());
  1.1830 +
  1.1831 +    fprintf(stderr, " JS Baseline frame\n");
  1.1832 +    if (isFunctionFrame()) {
  1.1833 +        fprintf(stderr, "  callee fun: ");
  1.1834 +#ifdef DEBUG
  1.1835 +        js_DumpObject(callee());
  1.1836 +#else
  1.1837 +        fprintf(stderr, "?\n");
  1.1838 +#endif
  1.1839 +    } else {
  1.1840 +        fprintf(stderr, "  global frame, no callee\n");
  1.1841 +    }
  1.1842 +
  1.1843 +    fprintf(stderr, "  file %s line %u\n",
  1.1844 +            script()->filename(), (unsigned) script()->lineno());
  1.1845 +
  1.1846 +    JSContext *cx = GetJSContextFromJitCode();
  1.1847 +    RootedScript script(cx);
  1.1848 +    jsbytecode *pc;
  1.1849 +    baselineScriptAndPc(script.address(), &pc);
  1.1850 +
  1.1851 +    fprintf(stderr, "  script = %p, pc = %p (offset %u)\n", (void *)script, pc, uint32_t(script->pcToOffset(pc)));
  1.1852 +    fprintf(stderr, "  current op: %s\n", js_CodeName[*pc]);
  1.1853 +
  1.1854 +    fprintf(stderr, "  actual args: %d\n", numActualArgs());
  1.1855 +
  1.1856 +    BaselineFrame *frame = baselineFrame();
  1.1857 +
  1.1858 +    for (unsigned i = 0; i < frame->numValueSlots(); i++) {
  1.1859 +        fprintf(stderr, "  slot %u: ", i);
  1.1860 +#ifdef DEBUG
  1.1861 +        Value *v = frame->valueSlot(i);
  1.1862 +        js_DumpValue(*v);
  1.1863 +#else
  1.1864 +        fprintf(stderr, "?\n");
  1.1865 +#endif
  1.1866 +    }
  1.1867 +}
  1.1868 +
  1.1869 +template <AllowGC allowGC>
  1.1870 +void
  1.1871 +InlineFrameIteratorMaybeGC<allowGC>::dump() const
  1.1872 +{
  1.1873 +    if (more())
  1.1874 +        fprintf(stderr, " JS frame (inlined)\n");
  1.1875 +    else
  1.1876 +        fprintf(stderr, " JS frame\n");
  1.1877 +
  1.1878 +    bool isFunction = false;
  1.1879 +    if (isFunctionFrame()) {
  1.1880 +        isFunction = true;
  1.1881 +        fprintf(stderr, "  callee fun: ");
  1.1882 +#ifdef DEBUG
  1.1883 +        js_DumpObject(callee());
  1.1884 +#else
  1.1885 +        fprintf(stderr, "?\n");
  1.1886 +#endif
  1.1887 +    } else {
  1.1888 +        fprintf(stderr, "  global frame, no callee\n");
  1.1889 +    }
  1.1890 +
  1.1891 +    fprintf(stderr, "  file %s line %u\n",
  1.1892 +            script()->filename(), (unsigned) script()->lineno());
  1.1893 +
  1.1894 +    fprintf(stderr, "  script = %p, pc = %p\n", (void*) script(), pc());
  1.1895 +    fprintf(stderr, "  current op: %s\n", js_CodeName[*pc()]);
  1.1896 +
  1.1897 +    if (!more()) {
  1.1898 +        numActualArgs();
  1.1899 +    }
  1.1900 +
  1.1901 +    SnapshotIterator si = snapshotIterator();
  1.1902 +    fprintf(stderr, "  slots: %u\n", si.numAllocations() - 1);
  1.1903 +    for (unsigned i = 0; i < si.numAllocations() - 1; i++) {
  1.1904 +        if (isFunction) {
  1.1905 +            if (i == 0)
  1.1906 +                fprintf(stderr, "  scope chain: ");
  1.1907 +            else if (i == 1)
  1.1908 +                fprintf(stderr, "  this: ");
  1.1909 +            else if (i - 2 < callee()->nargs())
  1.1910 +                fprintf(stderr, "  formal (arg %d): ", i - 2);
  1.1911 +            else {
  1.1912 +                if (i - 2 == callee()->nargs() && numActualArgs() > callee()->nargs()) {
  1.1913 +                    DumpOp d(callee()->nargs());
  1.1914 +                    unaliasedForEachActual(GetJSContextFromJitCode(), d, ReadFrame_Overflown);
  1.1915 +                }
  1.1916 +
  1.1917 +                fprintf(stderr, "  slot %d: ", int(i - 2 - callee()->nargs()));
  1.1918 +            }
  1.1919 +        } else
  1.1920 +            fprintf(stderr, "  slot %u: ", i);
  1.1921 +#ifdef DEBUG
  1.1922 +        js_DumpValue(si.maybeRead());
  1.1923 +#else
  1.1924 +        fprintf(stderr, "?\n");
  1.1925 +#endif
  1.1926 +    }
  1.1927 +
  1.1928 +    fputc('\n', stderr);
  1.1929 +}
  1.1930 +template void InlineFrameIteratorMaybeGC<NoGC>::dump() const;
  1.1931 +template void InlineFrameIteratorMaybeGC<CanGC>::dump() const;
  1.1932 +
  1.1933 +void
  1.1934 +JitFrameIterator::dump() const
  1.1935 +{
  1.1936 +    switch (type_) {
  1.1937 +      case JitFrame_Entry:
  1.1938 +        fprintf(stderr, " Entry frame\n");
  1.1939 +        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
  1.1940 +        break;
  1.1941 +      case JitFrame_BaselineJS:
  1.1942 +        dumpBaseline();
  1.1943 +        break;
  1.1944 +      case JitFrame_BaselineStub:
  1.1945 +      case JitFrame_Unwound_BaselineStub:
  1.1946 +        fprintf(stderr, " Baseline stub frame\n");
  1.1947 +        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
  1.1948 +        break;
  1.1949 +      case JitFrame_IonJS:
  1.1950 +      {
  1.1951 +        InlineFrameIterator frames(GetJSContextFromJitCode(), this);
  1.1952 +        for (;;) {
  1.1953 +            frames.dump();
  1.1954 +            if (!frames.more())
  1.1955 +                break;
  1.1956 +            ++frames;
  1.1957 +        }
  1.1958 +        break;
  1.1959 +      }
  1.1960 +      case JitFrame_Rectifier:
  1.1961 +      case JitFrame_Unwound_Rectifier:
  1.1962 +        fprintf(stderr, " Rectifier frame\n");
  1.1963 +        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
  1.1964 +        break;
  1.1965 +      case JitFrame_Unwound_IonJS:
  1.1966 +        fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
  1.1967 +        break;
  1.1968 +      case JitFrame_Exit:
  1.1969 +        break;
  1.1970 +    };
  1.1971 +    fputc('\n', stderr);
  1.1972 +}
  1.1973 +
  1.1974 +IonJSFrameLayout *
  1.1975 +InvalidationBailoutStack::fp() const
  1.1976 +{
  1.1977 +    return (IonJSFrameLayout *) (sp() + ionScript_->frameSize());
  1.1978 +}
  1.1979 +
  1.1980 +void
  1.1981 +InvalidationBailoutStack::checkInvariants() const
  1.1982 +{
  1.1983 +#ifdef DEBUG
  1.1984 +    IonJSFrameLayout *frame = fp();
  1.1985 +    CalleeToken token = frame->calleeToken();
  1.1986 +    JS_ASSERT(token);
  1.1987 +
  1.1988 +    uint8_t *rawBase = ionScript()->method()->raw();
  1.1989 +    uint8_t *rawLimit = rawBase + ionScript()->method()->instructionsSize();
  1.1990 +    uint8_t *osiPoint = osiPointReturnAddress();
  1.1991 +    JS_ASSERT(rawBase <= osiPoint && osiPoint <= rawLimit);
  1.1992 +#endif
  1.1993 +}
  1.1994 +
  1.1995 +} // namespace jit
  1.1996 +} // namespace js

mercurial