uint32 ion::ReflowTypeInfo(uint32 bailoutResult) { JSContext *cx = GetIonContext()->cx; IonActivation *activation = cx->runtime->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::AutoEnterTypeInference 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; }
uint32 ion::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut) { AssertCanGC(); sp->checkInvariants(); JSContext *cx = GetIonContext()->cx; // We don't have an exit frame. cx->runtime->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 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()); if (cx->runtime->hasIonReturnOverride()) cx->regs().sp[-1] = cx->runtime->takeIonReturnOverride(); if (retval != BAILOUT_RETURN_FATAL_ERROR) { if (activation->entryfp()) { if (void *annotation = activation->entryfp()->annotation()) { // If the entry frame has an annotation, then we invalidated and have // immediately returned into this bailout. Transfer the annotation to // the new topmost frame. activation->entryfp()->setAnnotation(NULL); cx->fp()->setAnnotation(annotation); } } // 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; }
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; } }