/* * Clean up a frame and return. */ static void InlineReturn(VMFrame &f) { JSContext *cx = f.cx; JSStackFrame *fp = f.regs.fp; JS_ASSERT(f.fp() != f.entryfp); JS_ASSERT(!js_IsActiveWithOrBlock(cx, &fp->scopeChain(), 0)); Value *newsp = fp->actualArgs() - 1; newsp[-1] = fp->returnValue(); cx->stack().popInlineFrame(cx, fp->prev(), newsp); }
void * RunTracer(VMFrame &f) #endif { JSContext *cx = f.cx; JSStackFrame *entryFrame = f.fp(); TracePointAction tpa; /* :TODO: nuke PIC? */ if (!cx->traceJitEnabled) return NULL; /* * Force initialization of the entry frame's scope chain and return value, * if necessary. The tracer can query the scope chain without needing to * check the HAS_SCOPECHAIN flag, and the frame is guaranteed to have the * correct return value stored if we trace/interpret through to the end * of the frame. */ entryFrame->scopeChain(); entryFrame->returnValue(); bool blacklist; uintN inlineCallCount = 0; void **traceData; uintN *traceEpoch; uint32 *loopCounter; uint32 hits; #if JS_MONOIC traceData = &ic.traceData; traceEpoch = &ic.traceEpoch; loopCounter = &ic.loopCounter; *loopCounter = 1; hits = ic.loopCounterStart; #else traceData = NULL; traceEpoch = NULL; loopCounter = NULL; hits = 1; #endif tpa = MonitorTracePoint(f.cx, inlineCallCount, &blacklist, traceData, traceEpoch, loopCounter, hits); JS_ASSERT(!TRACE_RECORDER(cx)); #if JS_MONOIC ic.loopCounterStart = *loopCounter; if (blacklist) DisableTraceHint(entryFrame->jit(), ic); #endif // Even though ExecuteTree() bypasses the interpreter, it should propagate // error failures correctly. JS_ASSERT_IF(cx->isExceptionPending(), tpa == TPA_Error); f.fp() = cx->fp(); JS_ASSERT(f.fp() == cx->fp()); switch (tpa) { case TPA_Nothing: return NULL; case TPA_Error: if (!HandleErrorInExcessFrame(f, entryFrame, f.fp()->finishedInInterpreter())) THROWV(NULL); JS_ASSERT(!cx->fp()->hasImacropc()); break; case TPA_RanStuff: case TPA_Recorded: break; } /* * The tracer could have dropped us off on any frame at any position. * Well, it could not have removed frames (recursion is disabled). * * Frames after the entryFrame cannot be entered via JaegerShotAtSafePoint() * unless each is at a safe point. We can JaegerShotAtSafePoint these * frames individually, but we must unwind to the entryFrame. * * Note carefully that JaegerShotAtSafePoint can resume methods at * arbitrary safe points whereas JaegerShot cannot. * * If we land on entryFrame without a safe point in sight, we'll end up * at the RETURN op. This is an edge case with two paths: * * 1) The entryFrame is the last inline frame. If it fell on a RETURN, * move the return value down. * 2) The entryFrame is NOT the last inline frame. Pop the frame. * * In both cases, we hijack the stub to return to the force-return * trampoline. This trampoline simulates the frame-popping portion of * emitReturn (except without the benefit of the FrameState) and will * produce the necessary register state to return to the caller. */ restart: /* Step 1. Finish frames created after the entry frame. */ if (!FinishExcessFrames(f, entryFrame)) THROWV(NULL); /* IMacros are guaranteed to have been removed by now. */ JS_ASSERT(f.fp() == entryFrame); JS_ASSERT(!entryFrame->hasImacropc()); /* Step 2. If entryFrame is done, use a special path to return to EnterMethodJIT(). */ if (FrameIsFinished(cx)) { if (!HandleFinishedFrame(f, entryFrame)) THROWV(NULL); void *retPtr = JS_FUNC_TO_DATA_PTR(void *, cx->jaegerCompartment()->forceReturnTrampoline()); *f.returnAddressLocation() = retPtr; return NULL; } /* Step 3. If entryFrame is at a safe point, just leave. */ if (void *ncode = AtSafePoint(cx)) return ncode; /* Step 4. Do a partial interp, then restart the whole process. */ if (!PartialInterpret(f)) { if (!HandleErrorInExcessFrame(f, entryFrame)) THROWV(NULL); } goto restart; }