/** * Compile and finish executing a function. * We don't actually replace the interpreter frame. Instead, this * routine JIT-compiles the current method and then calls the result * of that. The JIT-ted version returns to here and the interpreter * then immediately exits, returning the result of the JIT-ted version, * which is returned here. */ bool OSR::execute(MethodEnv *env, Atom* interp_frame, MethodSignaturep ms, const uint8_t* osr_pc, Atom* result) { BaseExecMgr* exec = BaseExecMgr::exec(env); OSR osr(osr_pc, interp_frame); #ifdef AVMPLUS_VERBOSE if (env->method->pool()->isVerbose(VB_execpolicy)) { env->core()->console << "execpolicy jit hot-loop " << env->method << " osr_pc=" << int(osr_pc - ms->abc_code_start()) << "\n"; } #endif // compile the method with an OSR entry point AvmAssert(!env->method->hasFailedJit()); exec->verifyJit(env->method, ms, env->toplevel(), env->abcEnv(), &osr); env->_implGPR = env->method->_implGPR; if (env->method->hasFailedJit()) { // Clean up OSR object explicitly, as there is no destructor. mmfx_delete(osr.jit_frame_state); return false; } // Save current_osr. It will be set to NULL in adjust_frame(), // once we have initialized the JIT frame from it. exec->current_osr = &osr; int fakeArgc = ms->requiredParamCount(); *result = exec->endCoerce(env, fakeArgc, (uint32_t*)interp_frame, ms); return true; }
DomainEnv::~DomainEnv() { mmfx_delete(m_globalMemoryScratch); }
/** * This function is called by JIT code if OSR has been requested * if (exec->current_osr != 0). This function fills the JIT frame locals * to match the interpreter frame. The JIT code looks like this: * * if (*(&exec->current_osr)) { * adjustFrame(...); * goto loop_entry * } */ void OSR::adjustFrame(MethodFrame* jitMethodFrame, CallStackNode *callStack, FramePtr jitFramePointer, uint8_t *jitFrameTags) { MethodEnv* env = jitMethodFrame->env(); BaseExecMgr* exec = BaseExecMgr::exec(env); OSR *osr = exec->current_osr; AvmAssert(osr && "should not have gotten here"); Atom* interpFramePointer = osr->interp_frame; MethodSignaturep ms = env->method->getMethodSignature(); int nLocals = ms->local_count(); int stackBase = nLocals + ms->max_scope(); FrameState* frameState = osr->jit_frame_state; int scopeTop = nLocals + frameState->scopeDepth; int stackTop = stackBase + frameState->stackDepth; // OSR has been requested. #ifdef AVMPLUS_VERBOSE if (env->method->pool()->isVerbose(VB_interp)) { env->core()->console << "osr-adjust_frame " << env->method->method_id() << " " << env->method << " scopeTop=" << scopeTop << " stackTop=" << stackTop << "\n"; } #endif // Patch the JIT frame local variable slots and the scope slots in use to match the interpreter state. for (int i = 0; i < scopeTop; i++) unboxSlot(frameState, env, interpFramePointer, jitFramePointer, jitFrameTags, i); // zero out stack area for unused scopes: if (scopeTop < stackBase) { void* p = ((char*) jitFramePointer + (scopeTop << VARSHIFT(env->method))); size_t nbytes = (stackBase - scopeTop) << VARSHIFT(env->method); VMPI_memset(p, 0, nbytes); } // Patch operand stack slots: for (int i = stackBase; i < stackTop; i++) unboxSlot(frameState, env, interpFramePointer, jitFramePointer, jitFrameTags, i); MethodFrame *interpreterMethodFrame = jitMethodFrame->next; jitMethodFrame->dxns = interpreterMethodFrame->dxns; jitMethodFrame->next = interpreterMethodFrame->next; // Clean up non-local OSR parameterization data: mmfx_delete(frameState); exec->current_osr = NULL; #ifdef DEBUGGER // Call debugEnter if necessary, since the jit code won't. // We can safely pass NULL for &eip here, because OSR is disabled // for methods with catch blocks. if (callStack) env->debugEnter(jitFrameTags, callStack, jitFramePointer, NULL); #else (void) callStack; #endif }
/** * This function detects if OSR has been requested or if this is a * subsequent normal call. In the latter case it has no side effect and * returns false and control flow is supposed to proceed normally. * If OSR is in the works, then it fills the JIT frame locals to match the * interpreter frame. Then it returns true, which indicates to the * generated code to jump to the OSR entry point. * * The JIT code looks like this: * * if (adjust_frame(...)) * goto loop_entry */ int32_t OSR::adjustFrame(MethodFrame* jitMethodFrame, CallStackNode *callStack, FramePtr jitFramePointer, uint8_t *jitFrameTags) { MethodEnv* env = jitMethodFrame->env(); BaseExecMgr* exec = BaseExecMgr::exec(env); OSR *osr = exec->current_osr; if (!osr) { // No OSR has been requested. // We are at the beginning of a normal AS method call. // Indicate proceeding with normal control flow. return 0; } Atom* interpFramePointer = osr->interp_frame; MethodSignaturep ms = env->method->getMethodSignature(); int nLocals = ms->local_count(); int stackBase = nLocals + ms->max_scope(); FrameState* frameState = osr->jit_frame_state; int scopeTop = nLocals + frameState->scopeDepth; int stackTop = stackBase + frameState->stackDepth; // OSR has been requested. #ifdef AVMPLUS_VERBOSE if (env->method->pool()->isVerbose(VB_interp)) { env->core()->console << "osr-adjust_frame " << env->method->method_id() << " " << env->method << " scopeTop=" << scopeTop << " stackTop=" << stackTop << "\n"; } #endif // Patch the JIT frame local variable slots and the scope slots in use to match the interpreter state. for (int i = 0; i < scopeTop; i++) unboxSlot(frameState, env, interpFramePointer, jitFramePointer, jitFrameTags, i); // zero out stack area for unused scopes: if (scopeTop < stackBase) { void* p = ((char*) jitFramePointer + scopeTop * VARSIZE); size_t nbytes = (stackBase - scopeTop) * VARSIZE; VMPI_memset(p, 0, nbytes); } // Patch operand stack slots: for (int i = stackBase; i < stackTop; i++) unboxSlot(frameState, env, interpFramePointer, jitFramePointer, jitFrameTags, i); MethodFrame *interpreterMethodFrame = jitMethodFrame->next; jitMethodFrame->dxns = interpreterMethodFrame->dxns; jitMethodFrame->next = interpreterMethodFrame->next; // Clean up non-local OSR parameterization data: mmfx_delete(frameState); exec->current_osr = NULL; #ifdef DEBUGGER // Call debugEnter if necessary, since the jit code won't. // We can safely pass NULL for &eip here, because OSR is disabled // for methods with catch blocks. if (callStack) env->debugEnter(jitFrameTags, callStack, jitFramePointer, NULL); #else (void) callStack; #endif // Indicate taking a shortcut from the call site // to the OSR entry point instead of normal control flow: return 1; }