Exemplo n.º 1
0
AsmJSActivation::~AsmJSActivation()
{
    if (profiler_)
        profiler_->exitNative();

    JSContext *cx = cx_->asJSContext();
    JS_ASSERT(cx->mainThread().asmJSActivationStack_ == this);

    JSRuntime::AutoLockForInterrupt lock(cx->runtime());
    cx->mainThread().asmJSActivationStack_ = prevAsmJS_;
}
Exemplo n.º 2
0
void
ion::HandleException(ResumeFromException *rfe)
{
    AssertCanGC();
    JSContext *cx = GetIonContext()->cx;

    IonSpew(IonSpew_Invalidate, "handling exception");

    // Immediately remove any bailout frame guard that might be left over from
    // an error in between ConvertFrames and ThunkToInterpreter.
    js_delete(cx->mainThread().ionActivation->maybeTakeBailout());

    IonFrameIterator iter(cx->mainThread().ionTop);
    while (!iter.isEntry()) {
        if (iter.isScripted()) {
            // Search each inlined frame for live iterator objects, and close
            // them.
            InlineFrameIterator frames(cx, &iter);
            for (;;) {
                CloseLiveIterators(cx, frames);

                // When profiling, each frame popped needs a notification that
                // the function has exited, so invoke the probe that a function
                // is exiting.
                AutoAssertNoGC nogc;
                RawScript script = frames.script();
                Probes::exitScript(cx, script, script->function(), NULL);
                if (!frames.more())
                    break;
                ++frames;
            }

            IonScript *ionScript = NULL;
            if (iter.checkInvalidation(&ionScript))
                ionScript->decref(cx->runtime->defaultFreeOp());
        }

        ++iter;
    }

    // Clear any Ion return override that's been set.
    // This may happen if a callVM function causes an invalidation (setting the
    // override), and then fails, bypassing the bailout handlers that would
    // otherwise clear the return override.
    if (cx->runtime->hasIonReturnOverride())
        cx->runtime->takeIonReturnOverride();

    rfe->stackPointer = iter.fp();
}
Exemplo n.º 3
0
uint32_t
ion::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
{
    JS_ASSERT(bailoutInfo);
    JSContext *cx = GetIonContext()->cx;
    // We don't have an exit frame.
    cx->mainThread().ionTop = NULL;
    JitActivationIterator jitActivations(cx->runtime());
    IonBailoutIterator iter(jitActivations, sp);
    JitActivation *activation = jitActivations.activation()->asJit();

    IonSpew(IonSpew_Bailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());

    JS_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = NULL;
    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
    JS_ASSERT(retval == BAILOUT_RETURN_OK ||
              retval == BAILOUT_RETURN_FATAL_ERROR ||
              retval == BAILOUT_RETURN_OVERRECURSED);
    JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != NULL);

    if (retval != BAILOUT_RETURN_OK)
        EnsureExitFrame(iter.jsFrame());

    return retval;
}
Exemplo n.º 4
0
uint32_t
ion::ReflowTypeInfo(uint32_t bailoutResult)
{
    JSContext *cx = GetIonContext()->cx;
    IonActivation *activation = cx->mainThread().ionActivation;

    IonSpew(IonSpew_Bailouts, "reflowing type info");

    if (bailoutResult == BAILOUT_RETURN_ARGUMENT_CHECK) {
        IonSpew(IonSpew_Bailouts, "reflowing type info at argument-checked entry");
        ReflowArgTypes(cx);
        return true;
    }

    RootedScript script(cx, cx->fp()->script());
    jsbytecode *pc = activation->bailout()->bailoutPc();

    JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);

    IonSpew(IonSpew_Bailouts, "reflowing type info at %s:%d pcoff %d", script->filename(),
            script->lineno, pc - script->code);

    types::AutoEnterAnalysis enter(cx);
    if (bailoutResult == BAILOUT_RETURN_TYPE_BARRIER)
        script->analysis()->breakTypeBarriers(cx, pc - script->code, false);
    else
        JS_ASSERT(bailoutResult == BAILOUT_RETURN_MONITOR);

    // When a type barrier fails, the bad value is at the top of the stack.
    Value &result = cx->regs().sp[-1];
    types::TypeScript::Monitor(cx, script, pc, result);

    return true;
}
Exemplo n.º 5
0
uint32_t
ion::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
{
    JS_ASSERT(bailoutInfo);
    JSContext *cx = GetIonContext()->cx;
    // We don't have an exit frame.
    cx->mainThread().ionTop = NULL;
    IonActivationIterator ionActivations(cx);
    IonBailoutIterator iter(ionActivations, sp);
    IonActivation *activation = ionActivations.activation();

    // IonCompartment *ioncompartment = cx->compartment->ionCompartment();
    // IonActivation *activation = cx->runtime->ionActivation;
    // FrameRecovery in = FrameRecoveryFromBailout(ioncompartment, sp);

    IonSpew(IonSpew_Bailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());

    uint32_t retval;
    if (IsBaselineEnabled(cx)) {
        *bailoutInfo = NULL;
        retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
        JS_ASSERT(retval == BAILOUT_RETURN_BASELINE ||
                  retval == BAILOUT_RETURN_FATAL_ERROR ||
                  retval == BAILOUT_RETURN_OVERRECURSED);
        JS_ASSERT_IF(retval == BAILOUT_RETURN_BASELINE, *bailoutInfo != NULL);
    } else {
        retval = ConvertFrames(cx, activation, iter);
    }

    if (retval != BAILOUT_RETURN_BASELINE)
        EnsureExitFrame(iter.jsFrame());

    return retval;
}
Exemplo n.º 6
0
AsmJSActivation::~AsmJSActivation()
{
    if (profiler_)
        profiler_->exitAsmJS();

    JS_ASSERT(fp_ == nullptr);

    JS_ASSERT(module_.activation() == this);
    module_.activation() = prevAsmJSForModule_;

    JSContext *cx = cx_->asJSContext();
    JS_ASSERT(cx->mainThread().asmJSActivationStack_ == this);

    JSRuntime::AutoLockForInterrupt lock(cx->runtime());
    cx->mainThread().asmJSActivationStack_ = prevAsmJS_;
}
Exemplo n.º 7
0
static void
DisableActivationFromAsmJS(AsmJSActivation *activation)
{
    JSContext *cx = activation->cx();
    Activation *act = cx->mainThread().activation();
    JS_ASSERT(act->isJit());
    act->asJit()->setActive(cx, false);
}
Exemplo n.º 8
0
AsmJSActivation::~AsmJSActivation()
{
    // Hide this activation from the profiler before is is destroyed.
    unregisterProfiling();

    if (profiler_)
        profiler_->exitAsmJS();

    MOZ_ASSERT(fp_ == nullptr);

    MOZ_ASSERT(module_.activation() == this);
    module_.activation() = prevAsmJSForModule_;

    JSContext *cx = cx_->asJSContext();
    MOZ_ASSERT(cx->mainThread().asmJSActivationStack_ == this);

    cx->mainThread().asmJSActivationStack_ = prevAsmJS_;
}
Exemplo n.º 9
0
uint32_t
jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
{
    JSContext *cx = GetJSContextFromJitCode();
    JS_ASSERT(bailoutInfo);

    // We don't have an exit frame.
    MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
               IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
               "Fake jitTop pointer should be within the first page.");
    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
    gc::AutoSuppressGC suppress(cx);

    JitActivationIterator jitActivations(cx->runtime());
    IonBailoutIterator iter(jitActivations, sp);
    JitActivation *activation = jitActivations->asJit();

    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    TraceLogTimestamp(logger, TraceLogger::Bailout);

    JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());

    JS_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = nullptr;
    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
    JS_ASSERT(retval == BAILOUT_RETURN_OK ||
              retval == BAILOUT_RETURN_FATAL_ERROR ||
              retval == BAILOUT_RETURN_OVERRECURSED);
    JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);

    if (retval != BAILOUT_RETURN_OK) {
        // If the bailout failed, then bailout trampoline will pop the
        // current frame and jump straight to exception handling code when
        // this function returns.  Any SPS entry pushed for this frame will
        // be silently forgotten.
        //
        // We call ExitScript here to ensure that if the ionScript had SPS
        // instrumentation, then the SPS entry for it is popped.
        //
        // However, if the bailout was during argument check, then a
        // pseudostack frame would not have been pushed in the first
        // place, so don't pop anything in that case.
        bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
                           (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck);
        JSScript *script = iter.script();
        probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);

        EnsureExitFrame(iter.jsFrame());
    }

    return retval;
}
Exemplo n.º 10
0
uint32_t
jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
                         BaselineBailoutInfo **bailoutInfo)
{
    sp->checkInvariants();

    JSContext *cx = GetJSContextFromJitCode();

    // We don't have an exit frame.
    cx->mainThread().ionTop = nullptr;
    JitActivationIterator jitActivations(cx->runtime());
    IonBailoutIterator iter(jitActivations, sp);
    JitActivation *activation = jitActivations.activation()->asJit();

    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    TraceLogTimestamp(logger, TraceLogger::Invalidation);

    IonSpew(IonSpew_Bailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());

    // Note: the frame size must be computed before we return from this function.
    *frameSizeOut = iter.topFrameSize();

    JS_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = nullptr;
    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo);
    JS_ASSERT(retval == BAILOUT_RETURN_OK ||
              retval == BAILOUT_RETURN_FATAL_ERROR ||
              retval == BAILOUT_RETURN_OVERRECURSED);
    JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);

    if (retval != BAILOUT_RETURN_OK) {
        IonJSFrameLayout *frame = iter.jsFrame();
        IonSpew(IonSpew_Invalidate, "converting to exit frame");
        IonSpew(IonSpew_Invalidate, "   orig calleeToken %p", (void *) frame->calleeToken());
        IonSpew(IonSpew_Invalidate, "   orig frameSize %u", unsigned(frame->prevFrameLocalSize()));
        IonSpew(IonSpew_Invalidate, "   orig ra %p", (void *) frame->returnAddress());

        frame->replaceCalleeToken(nullptr);
        EnsureExitFrame(frame);

        IonSpew(IonSpew_Invalidate, "   new  calleeToken %p", (void *) frame->calleeToken());
        IonSpew(IonSpew_Invalidate, "   new  frameSize %u", unsigned(frame->prevFrameLocalSize()));
        IonSpew(IonSpew_Invalidate, "   new  ra %p", (void *) frame->returnAddress());
    }

    iter.ionScript()->decref(cx->runtime()->defaultFreeOp());

    return retval;
}
Exemplo n.º 11
0
 ~AutoEnterParallelSection() {
     cx_->mainThread().ionTop = prevIonTop_;
 }
Exemplo n.º 12
0
uint32_t
jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
                         BaselineBailoutInfo **bailoutInfo)
{
    sp->checkInvariants();

    JSContext *cx = GetJSContextFromJitCode();

    // We don't have an exit frame.
    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
    gc::AutoSuppressGC suppress(cx);

    JitActivationIterator jitActivations(cx->runtime());
    IonBailoutIterator iter(jitActivations, sp);
    JitActivation *activation = jitActivations->asJit();

    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    TraceLogTimestamp(logger, TraceLogger::Invalidation);

    JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());

    // Note: the frame size must be computed before we return from this function.
    *frameSizeOut = iter.topFrameSize();

    JS_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = nullptr;
    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo);
    JS_ASSERT(retval == BAILOUT_RETURN_OK ||
              retval == BAILOUT_RETURN_FATAL_ERROR ||
              retval == BAILOUT_RETURN_OVERRECURSED);
    JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);

    if (retval != BAILOUT_RETURN_OK) {
        // If the bailout failed, then bailout trampoline will pop the
        // current frame and jump straight to exception handling code when
        // this function returns.  Any SPS entry pushed for this frame will
        // be silently forgotten.
        //
        // We call ExitScript here to ensure that if the ionScript had SPS
        // instrumentation, then the SPS entry for it is popped.
        //
        // However, if the bailout was during argument check, then a
        // pseudostack frame would not have been pushed in the first
        // place, so don't pop anything in that case.
        bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
                           (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck);
        JSScript *script = iter.script();
        probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);

        IonJSFrameLayout *frame = iter.jsFrame();
        JitSpew(JitSpew_IonInvalidate, "Bailout failed (%s): converting to exit frame",
                (retval == BAILOUT_RETURN_FATAL_ERROR) ? "Fatal Error" : "Over Recursion");
        JitSpew(JitSpew_IonInvalidate, "   orig calleeToken %p", (void *) frame->calleeToken());
        JitSpew(JitSpew_IonInvalidate, "   orig frameSize %u", unsigned(frame->prevFrameLocalSize()));
        JitSpew(JitSpew_IonInvalidate, "   orig ra %p", (void *) frame->returnAddress());

        frame->replaceCalleeToken(nullptr);
        EnsureExitFrame(frame);

        JitSpew(JitSpew_IonInvalidate, "   new  calleeToken %p", (void *) frame->calleeToken());
        JitSpew(JitSpew_IonInvalidate, "   new  frameSize %u", unsigned(frame->prevFrameLocalSize()));
        JitSpew(JitSpew_IonInvalidate, "   new  ra %p", (void *) frame->returnAddress());
    }

    iter.ionScript()->decref(cx->runtime()->defaultFreeOp());

    return retval;
}
Exemplo n.º 13
0
bool
BaselineFrame::initForOsr(StackFrame *fp, uint32_t numStackValues)
{
    mozilla::PodZero(this);

    scopeChain_ = fp->scopeChain();

    if (fp->hasCallObjUnchecked())
        flags_ |= BaselineFrame::HAS_CALL_OBJ;

    if (fp->hasBlockChain()) {
        flags_ |= BaselineFrame::HAS_BLOCKCHAIN;
        blockChain_ = &fp->blockChain();
    }

    if (fp->isEvalFrame()) {
        flags_ |= BaselineFrame::EVAL;
        evalScript_ = fp->script();
    }

    if (fp->script()->needsArgsObj() && fp->hasArgsObj()) {
        flags_ |= BaselineFrame::HAS_ARGS_OBJ;
        argsObj_ = &fp->argsObj();
    }

    if (fp->hasHookData()) {
        flags_ |= BaselineFrame::HAS_HOOK_DATA;
        hookData_ = fp->hookData();
    }

    if (fp->hasPushedSPSFrame())
        flags_ |= BaselineFrame::HAS_PUSHED_SPS_FRAME;

    frameSize_ = BaselineFrame::FramePointerOffset +
        BaselineFrame::Size() +
        numStackValues * sizeof(Value);

    JS_ASSERT(numValueSlots() == numStackValues);

    for (uint32_t i = 0; i < numStackValues; i++)
        *valueSlot(i) = fp->slots()[i];

    JSContext *cx = GetIonContext()->cx;
    if (cx->compartment()->debugMode()) {
        // In debug mode, update any Debugger.Frame objects for the StackFrame to
        // point to the BaselineFrame.

        // The caller pushed a fake return address. ScriptFrameIter, used by the
        // debugger, wants a valid return address, but it's okay to just pick one.
        // In debug mode there's always at least 1 ICEntry (since there are always
        // debug prologue/epilogue calls).
        IonFrameIterator iter(cx->mainThread().ionTop);
        JS_ASSERT(iter.returnAddress() == NULL);
        BaselineScript *baseline = fp->script()->baselineScript();
        iter.current()->setReturnAddress(baseline->returnAddressForIC(baseline->icEntry(0)));

        if (!Debugger::handleBaselineOsr(cx, fp, this))
            return false;
    }

    return true;
}
Exemplo n.º 14
0
uint32_t
ion::ThunkToInterpreter(Value *vp)
{
    JSContext *cx = GetIonContext()->cx;
    IonActivation *activation = cx->mainThread().ionActivation;
    BailoutClosure *br = activation->takeBailout();
    InterpMode resumeMode = JSINTERP_BAILOUT;

    if (!EnsureHasScopeObjects(cx, cx->fp()))
        resumeMode = JSINTERP_RETHROW;

    // By default we set the forbidOsr flag on the ion script, but if a GC
    // happens just after we re-enter the interpreter, the ion script get
    // invalidated and we do not see the forbidOsr flag.  This may cause a loop
    // which apear with eager compilation and gc zeal enabled.  This code is a
    // workaround to avoid recompiling with OSR just after a bailout followed by
    // a GC. (see Bug 746691 & Bug 751383)
    jsbytecode *pc = cx->regs().pc;
    while (JSOp(*pc) == JSOP_GOTO)
        pc += GET_JUMP_OFFSET(pc);
    if (JSOp(*pc) == JSOP_LOOPENTRY)
        cx->regs().pc = GetNextPc(pc);

    // When JSScript::argumentsOptimizationFailed, we cannot access Ion frames
    // in order to create an arguments object for them.  However, there is an
    // invariant that script->needsArgsObj() implies fp->hasArgsObj() (after the
    // prologue), so we must create one now for each inlined frame which needs
    // one.
    {
        ScriptFrameIter iter(cx);
        StackFrame *fp = NULL;
        Rooted<JSScript*> script(cx);
        do {
            fp = iter.interpFrame();
            script = iter.script();
            if (script->needsArgsObj()) {
                // Currently IonMonkey does not compile if the script needs an
                // arguments object, so the frame should not have any argument
                // object yet.
                JS_ASSERT(!fp->hasArgsObj());
                ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, fp);
                if (!argsobj) {
                    resumeMode = JSINTERP_RETHROW;
                    break;
                }
                // The arguments is a local binding and needsArgsObj does not
                // check if it is clobbered. Ensure that the local binding
                // restored during bailout before storing the arguments object
                // to the slot.
                SetFrameArgumentsObject(cx, fp, script, argsobj);
            }
            ++iter;
        } while (fp != br->entryfp());
    }

    if (activation->entryfp() == br->entryfp()) {
        // If the bailout entry fp is the same as the activation entryfp, then
        // there are no scripted frames below us. In this case, just shortcut
        // out with a special return code, and resume interpreting in the
        // original Interpret activation.
        vp->setMagic(JS_ION_BAILOUT);
        js_delete(br);
        return resumeMode == JSINTERP_RETHROW ? Interpret_Error : Interpret_Ok;
    }

    InterpretStatus status = Interpret(cx, br->entryfp(), resumeMode);
    JS_ASSERT_IF(resumeMode == JSINTERP_RETHROW, status == Interpret_Error);

    if (status == Interpret_OSR) {
        // The interpreter currently does not ask to perform inline OSR, so
        // this path is unreachable.
        JS_NOT_REACHED("invalid");

        IonSpew(IonSpew_Bailouts, "Performing inline OSR %s:%d",
                cx->fp()->script()->filename(),
                PCToLineNumber(cx->fp()->script(), cx->regs().pc));

        // We want to OSR again. We need to avoid the problem where frequent
        // bailouts cause recursive nestings of Interpret and EnterIon. The
        // interpreter therefore shortcuts out, and now we're responsible for
        // completing the OSR inline.
        //
        // Note that we set runningInIon so that if we re-enter C++ from within
        // the inlined OSR, StackIter will know to traverse these frames.
        StackFrame *fp = cx->fp();

        fp->setRunningInIon();
        vp->setPrivate(fp);
        js_delete(br);
        return Interpret_OSR;
    }

    if (status == Interpret_Ok)
        *vp = br->entryfp()->returnValue();

    // The BailoutFrameGuard's destructor will ensure that the frame is
    // removed.
    js_delete(br);

    return status;
}
Exemplo n.º 15
0
uint32_t
ion::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
                         BaselineBailoutInfo **bailoutInfo)
{
    sp->checkInvariants();

    JSContext *cx = GetIonContext()->cx;

    // We don't have an exit frame.
    cx->mainThread().ionTop = NULL;
    IonActivationIterator ionActivations(cx);
    IonBailoutIterator iter(ionActivations, sp);
    IonActivation *activation = ionActivations.activation();

    IonSpew(IonSpew_Bailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());

    // Note: the frame size must be computed before we return from this function.
    *frameSizeOut = iter.topFrameSize();

    uint32_t retval;
    if (IsBaselineEnabled(cx)) {
        *bailoutInfo = NULL;
        retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo);
        JS_ASSERT(retval == BAILOUT_RETURN_BASELINE ||
                  retval == BAILOUT_RETURN_FATAL_ERROR ||
                  retval == BAILOUT_RETURN_OVERRECURSED);
        JS_ASSERT_IF(retval == BAILOUT_RETURN_BASELINE, *bailoutInfo != NULL);

        if (retval != BAILOUT_RETURN_BASELINE) {
            IonJSFrameLayout *frame = iter.jsFrame();
            IonSpew(IonSpew_Invalidate, "converting to exit frame");
            IonSpew(IonSpew_Invalidate, "   orig calleeToken %p", (void *) frame->calleeToken());
            IonSpew(IonSpew_Invalidate, "   orig frameSize %u", unsigned(frame->prevFrameLocalSize()));
            IonSpew(IonSpew_Invalidate, "   orig ra %p", (void *) frame->returnAddress());

            frame->replaceCalleeToken(NULL);
            EnsureExitFrame(frame);

            IonSpew(IonSpew_Invalidate, "   new  calleeToken %p", (void *) frame->calleeToken());
            IonSpew(IonSpew_Invalidate, "   new  frameSize %u", unsigned(frame->prevFrameLocalSize()));
            IonSpew(IonSpew_Invalidate, "   new  ra %p", (void *) frame->returnAddress());
        }

        iter.ionScript()->decref(cx->runtime->defaultFreeOp());

        return retval;
    } else {
        retval = ConvertFrames(cx, activation, iter);

        IonJSFrameLayout *frame = iter.jsFrame();
        IonSpew(IonSpew_Invalidate, "converting to exit frame");
        IonSpew(IonSpew_Invalidate, "   orig calleeToken %p", (void *) frame->calleeToken());
        IonSpew(IonSpew_Invalidate, "   orig frameSize %u", unsigned(frame->prevFrameLocalSize()));
        IonSpew(IonSpew_Invalidate, "   orig ra %p", (void *) frame->returnAddress());

        frame->replaceCalleeToken(NULL);
        EnsureExitFrame(frame);

        IonSpew(IonSpew_Invalidate, "   new  calleeToken %p", (void *) frame->calleeToken());
        IonSpew(IonSpew_Invalidate, "   new  frameSize %u", unsigned(frame->prevFrameLocalSize()));
        IonSpew(IonSpew_Invalidate, "   new  ra %p", (void *) frame->returnAddress());

        iter.ionScript()->decref(cx->runtime->defaultFreeOp());

        // Only need to take ion return override if resuming to interpreter.
        if (cx->runtime->hasIonReturnOverride())
            cx->regs().sp[-1] = cx->runtime->takeIonReturnOverride();

        if (retval != BAILOUT_RETURN_FATAL_ERROR) {
            // If invalidation was triggered inside a stub call, we may still have to
            // monitor the result, since the bailout happens before the MMonitorTypes
            // instruction is executed.
            jsbytecode *pc = activation->bailout()->bailoutPc();

            // If this is not a ResumeAfter bailout, there's nothing to monitor,
            // we will redo the op in the interpreter.
            bool isResumeAfter = GetNextPc(pc) == cx->regs().pc;

            if ((js_CodeSpec[*pc].format & JOF_TYPESET) && isResumeAfter) {
                JS_ASSERT(retval == BAILOUT_RETURN_OK);
                return BAILOUT_RETURN_MONITOR;
            }

            return retval;
        }

        return BAILOUT_RETURN_FATAL_ERROR;
    }
}
Exemplo n.º 16
0
uint32_t
jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
{
    JSContext *cx = GetJSContextFromJitCode();
    MOZ_ASSERT(bailoutInfo);

    // We don't have an exit frame.
    MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
               IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
               "Fake jitTop pointer should be within the first page.");
    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;

    JitActivationIterator jitActivations(cx->runtime());
    BailoutFrameInfo bailoutData(jitActivations, sp);
    JitFrameIterator iter(jitActivations);
    MOZ_ASSERT(!iter.ionScript()->invalidated());

    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    TraceLogTimestamp(logger, TraceLogger::Bailout);

    JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());

    MOZ_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = nullptr;
    bool poppedLastSPSFrame = false;
    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo,
                                           /* excInfo = */ nullptr, &poppedLastSPSFrame);
    MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
               retval == BAILOUT_RETURN_FATAL_ERROR ||
               retval == BAILOUT_RETURN_OVERRECURSED);
    MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);

    if (retval != BAILOUT_RETURN_OK) {
        // If the bailout failed, then bailout trampoline will pop the
        // current frame and jump straight to exception handling code when
        // this function returns.  Any SPS entry pushed for this frame will
        // be silently forgotten.
        //
        // We call ExitScript here to ensure that if the ionScript had SPS
        // instrumentation, then the SPS entry for it is popped.
        //
        // However, if the bailout was during argument check, then a
        // pseudostack frame would not have been pushed in the first
        // place, so don't pop anything in that case.
        bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
                           (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck) &&
                           !poppedLastSPSFrame;
        JSScript *script = iter.script();
        probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);

        EnsureExitFrame(iter.jsFrame());
    }

    // This condition was wrong when we entered this bailout function, but it
    // might be true now. A GC might have reclaimed all the Jit code and
    // invalidated all frames which are currently on the stack. As we are
    // already in a bailout, we could not switch to an invalidation
    // bailout. When the code of an IonScript which is on the stack is
    // invalidated (see InvalidateActivation), we remove references to it and
    // increment the reference counter for each activation that appear on the
    // stack. As the bailed frame is one of them, we have to decrement it now.
    if (iter.ionScript()->invalidated())
        iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());

    return retval;
}