void CallStackNode::enumerateScopeChainAtoms(IScopeChainEnumerator& scb) { // First, get the "dynamic" portion of the scope chain, that is, the // part that is modified on-the-fly within the function. This includes // activation objects for try/catch blocks and "with" clauses. if (m_info) { MethodSignaturep const ms = m_info->getMethodSignature(); for (int i = (ms->max_scope() + ms->local_count() - 1), n = ms->local_count(); i >= n; --i) { Atom const scope = m_info->boxOneLocal(m_framep, i, m_traits); AvmAssert(atomKind(scope) != kUnusedAtomTag); // go ahead and call addScope, even if null or undefined. scb.addScope(scope); } } // Next, get the "static" portion of the scope chain, that is, the // part that is defined as part of the definition of the function. This // includes the locals of any functions that enclose this one, and the "this" // object, if any. ScopeChain* scopeChain = m_env ? m_env->scope() : NULL; if (scopeChain) { int scopeChainLength = scopeChain->getSize(); for (int i = scopeChainLength - 1; i >= 0; --i) { Atom scope = scopeChain->getScope(i); if (AvmCore::isObject(scope)) { scb.addScope(scope); } } } }
/** * 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; }