📄 interpreter.cpp
字号:
RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue); JSValuePtr result = jsUndefined(); if (evalNode) result = callFrame->globalData().interpreter->execute(evalNode.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue); return result;}Interpreter::Interpreter() : m_sampler(0) , m_reentryDepth(0){ privateExecute(InitializeAndReturn, 0, 0, 0);}#ifndef NDEBUGvoid Interpreter::dumpCallFrame(CallFrame* callFrame){ callFrame->codeBlock()->dump(callFrame); dumpRegisters(callFrame);}void Interpreter::dumpRegisters(CallFrame* callFrame){ printf("Register frame: \n\n"); printf("----------------------------------------------------\n"); printf(" use | address | value \n"); printf("----------------------------------------------------\n"); CodeBlock* codeBlock = callFrame->codeBlock(); RegisterFile* registerFile = &callFrame->scopeChain()->globalObject()->globalData()->interpreter->registerFile(); const Register* it; const Register* end; if (codeBlock->codeType() == GlobalCode) { it = registerFile->lastGlobal(); end = it + registerFile->numGlobals(); while (it != end) { printf("[global var] | %10p | %10p \n", it, (*it).v()); ++it; } printf("----------------------------------------------------\n"); } it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters; printf("[this] | %10p | %10p \n", it, (*it).v()); ++it; end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this" if (it != end) { do { printf("[param] | %10p | %10p \n", it, (*it).v()); ++it; } while (it != end); } printf("----------------------------------------------------\n"); printf("[CodeBlock] | %10p | %10p \n", it, (*it).v()); ++it; printf("[ScopeChain] | %10p | %10p \n", it, (*it).v()); ++it; printf("[CallerRegisters] | %10p | %10p \n", it, (*it).v()); ++it; printf("[ReturnPC] | %10p | %10p \n", it, (*it).v()); ++it; printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it; printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it; printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it; printf("[OptionalCalleeArguments] | %10p | %10p \n", it, (*it).v()); ++it; printf("----------------------------------------------------\n"); int registerCount = 0; end = it + codeBlock->m_numVars; if (it != end) { do { printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v()); ++it; ++registerCount; } while (it != end); } printf("----------------------------------------------------\n"); end = it + codeBlock->m_numConstants; if (it != end) { do { printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v()); ++it; ++registerCount; } while (it != end); } printf("----------------------------------------------------\n"); end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numConstants - codeBlock->m_numVars; if (it != end) { do { printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v()); ++it; ++registerCount; } while (it != end); } printf("----------------------------------------------------\n");}#endifbool Interpreter::isOpcode(Opcode opcode){#if HAVE(COMPUTED_GOTO) return opcode != HashTraits<Opcode>::emptyValue() && !HashTraits<Opcode>::isDeletedValue(opcode) && m_opcodeIDTable.contains(opcode);#else return opcode >= 0 && opcode <= op_end;#endif}NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValuePtr exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock){ CodeBlock* oldCodeBlock = codeBlock; ScopeChainNode* scopeChain = callFrame->scopeChain(); if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); if (callFrame->callee()) debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine()); else debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine()); } if (Profiler* profiler = *Profiler::enabledProfilerReference()) { if (callFrame->callee()) profiler->didExecute(callFrame, callFrame->callee()); else profiler->didExecute(callFrame, codeBlock->ownerNode()->sourceURL(), codeBlock->ownerNode()->lineNo()); } // If this call frame created an activation or an 'arguments' object, tear it off. if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) { while (!scopeChain->object->isObject(&JSActivation::info)) scopeChain = scopeChain->pop(); static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments()); } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) { if (!arguments->isTornOff()) arguments->copyRegisters(); } if (oldCodeBlock->needsFullScopeChain()) scopeChain->deref(); void* returnPC = callFrame->returnPC(); callFrame = callFrame->callerFrame(); if (callFrame->hasHostCallFrameFlag()) return false; codeBlock = callFrame->codeBlock(); bytecodeOffset = bytecodeOffsetForPC(callFrame, codeBlock, returnPC); return true;}NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValuePtr& exceptionValue, unsigned bytecodeOffset, bool explicitThrow){ // Set up the exception object CodeBlock* codeBlock = callFrame->codeBlock(); if (exceptionValue.isObject()) { JSObject* exception = asObject(exceptionValue); if (exception->isNotAnObjectErrorStub()) { exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock); exceptionValue = exception; } else { if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) && !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) && !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) && !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) && !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) && !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) { if (explicitThrow) { int startOffset = 0; int endOffset = 0; int divotPoint = 0; int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset); exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete); // We only hit this path for error messages and throw statements, which don't have a specific failure position // So we just give the full range of the error/throw statement. exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete); exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete); } else exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete); exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerNode()->sourceID()), ReadOnly | DontDelete); exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerNode()->sourceURL()), ReadOnly | DontDelete); } if (exception->isWatchdogException()) { while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) { // Don't need handler checks or anything, we just want to unroll all the JS callframes possible. } return 0; } } } if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); debugger->exception(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)); } // If we throw in the middle of a call instruction, we need to notify // the profiler manually that the call instruction has returned, since // we'll never reach the relevant op_profile_did_call. if (Profiler* profiler = *Profiler::enabledProfilerReference()) {#if !ENABLE(JIT) if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode)) profiler->didExecute(callFrame, callFrame[codeBlock->instructions()[bytecodeOffset + 2].u.operand].jsValue(callFrame)); else if (codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct)) profiler->didExecute(callFrame, callFrame[codeBlock->instructions()[bytecodeOffset + 10].u.operand].jsValue(callFrame));#else int functionRegisterIndex; if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex)) profiler->didExecute(callFrame, callFrame[functionRegisterIndex].jsValue(callFrame));#endif } // Calculate an exception handler vPC, unwinding call frames as necessary. HandlerInfo* handler = 0; while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) return 0; } // Now unwind the scope chain within the exception handler's call frame. ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChain sc(scopeChain); int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth; ASSERT(scopeDelta >= 0); while (scopeDelta--) scopeChain = scopeChain->pop(); callFrame->setScopeChain(scopeChain); return handler;}JSValuePtr Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValuePtr* exception){ ASSERT(!scopeChain->globalData->exception); if (m_reentryDepth >= MaxReentryDepth) { *exception = createStackOverflowError(callFrame); return jsNull(); } CodeBlock* codeBlock = &programNode->bytecode(scopeChain); Register* oldEnd = m_registerFile.end(); Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters; if (!m_registerFile.grow(newEnd)) { *exception = createStackOverflowError(callFrame); return jsNull(); } DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject()); JSGlobalObject* lastGlobalObject = m_registerFile.globalObject(); JSGlobalObject* globalObject = callFrame->dynamicGlobalObject(); globalObject->copyGlobalsTo(m_registerFile); CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize); newCallFrame[codeBlock->thisRegister()] = JSValuePtr(thisObj); newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0); if (codeBlock->needsFullScopeChain()) scopeChain->ref(); Profiler** profiler = Profiler::enabledProfilerReference(); if (*profiler) (*profiler)->willExecute(newCallFrame, programNode->sourceURL(), programNode->lineNo()); JSValuePtr result; { SamplingTool::CallRecord callRecord(m_sampler); m_reentryDepth++;#if ENABLE(JIT) if (!codeBlock->jitCode()) JIT::compile(scopeChain->globalData, codeBlock); result = codeBlock->jitCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);#else result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);#endif m_reentryDepth--; } if (*profiler) (*profiler)->didExecute(callFrame, programNode->sourceURL(), programNode->lineNo()); if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject) lastGlobalObject->copyGlobalsTo(m_registerFile); m_registerFile.shrink(oldEnd); return result;}JSValuePtr Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValuePtr* exception){ ASSERT(!scopeChain->globalData->exception); if (m_reentryDepth >= MaxReentryDepth) { *exception = createStackOverflowError(callFrame); return jsNull(); } Register* oldEnd = m_registerFile.end(); int argc = 1 + args.size(); // implicit "this" parameter if (!m_registerFile.grow(oldEnd + argc)) { *exception = createStackOverflowError(callFrame); return jsNull(); } DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject()); CallFrame* newCallFrame = CallFrame::create(oldEnd); size_t dst = 0; newCallFrame[0] = JSValuePtr(thisObj); ArgList::const_iterator end = args.end(); for (ArgList::const_iterator it = args.begin(); it != end; ++it) newCallFrame[++dst] = *it; CodeBlock* codeBlock = &functionBodyNode->bytecode(scopeChain); newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc); if (UNLIKELY(!newCallFrame)) { *exception = createStackOverflowError(callFrame); m_registerFile.shrink(oldEnd); return jsNull(); } // a 0 codeBlock indicates a built-in caller newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -