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()) { ArgumentsObject *argsObj; if (fp->hasArgsObj()) { argsObj = &fp->argsObj(); } else { 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; }