📄 interpreter.cpp
字号:
Profiler** profiler = Profiler::enabledProfilerReference(); if (*profiler) (*profiler)->willExecute(callFrame, function); 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, function); m_registerFile.shrink(oldEnd); return result;}JSValuePtr Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValuePtr* exception){ return execute(evalNode, callFrame, thisObj, m_registerFile.size() + evalNode->bytecode(scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);}JSValuePtr Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValuePtr* exception){ ASSERT(!scopeChain->globalData->exception); if (m_reentryDepth >= MaxReentryDepth) { *exception = createStackOverflowError(callFrame); return jsNull(); } DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject()); EvalCodeBlock* codeBlock = &evalNode->bytecode(scopeChain); JSVariableObject* variableObject; for (ScopeChainNode* node = scopeChain; ; node = node->next) { ASSERT(node); if (node->object->isVariableObject()) { variableObject = static_cast<JSVariableObject*>(node->object); break; } } { // Scope for BatchedTransitionOptimizer BatchedTransitionOptimizer optimizer(variableObject); const DeclarationStacks::VarStack& varStack = codeBlock->ownerNode()->varStack(); DeclarationStacks::VarStack::const_iterator varStackEnd = varStack.end(); for (DeclarationStacks::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) { const Identifier& ident = (*it).first; if (!variableObject->hasProperty(callFrame, ident)) { PutPropertySlot slot; variableObject->put(callFrame, ident, jsUndefined(), slot); } } const DeclarationStacks::FunctionStack& functionStack = codeBlock->ownerNode()->functionStack(); DeclarationStacks::FunctionStack::const_iterator functionStackEnd = functionStack.end(); for (DeclarationStacks::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) { PutPropertySlot slot; variableObject->put(callFrame, (*it)->m_ident, (*it)->makeFunction(callFrame, scopeChain), slot); } } Register* oldEnd = m_registerFile.end(); Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters; if (!m_registerFile.grow(newEnd)) { *exception = createStackOverflowError(callFrame); return jsNull(); } CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset); // a 0 codeBlock indicates a built-in caller newCallFrame[codeBlock->thisRegister()] = JSValuePtr(thisObj); newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0); if (codeBlock->needsFullScopeChain()) scopeChain->ref(); Profiler** profiler = Profiler::enabledProfilerReference(); if (*profiler) (*profiler)->willExecute(newCallFrame, evalNode->sourceURL(), evalNode->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, evalNode->sourceURL(), evalNode->lineNo()); m_registerFile.shrink(oldEnd); return result;}NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine){ Debugger* debugger = callFrame->dynamicGlobalObject()->debugger(); if (!debugger) return; switch (debugHookID) { case DidEnterCallFrame: debugger->callEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); return; case WillLeaveCallFrame: debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); return; case WillExecuteStatement: debugger->atStatement(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); return; case WillExecuteProgram: debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); return; case DidExecuteProgram: debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); return; case DidReachBreakpoint: debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); return; }}NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC){ int dst = (++vPC)->u.operand; CodeBlock* codeBlock = callFrame->codeBlock(); Identifier& property = codeBlock->identifier((++vPC)->u.operand); JSValuePtr value = callFrame[(++vPC)->u.operand].jsValue(callFrame); JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete); callFrame[dst] = JSValuePtr(scope); return callFrame->scopeChain()->push(scope);}NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValuePtr baseValue, const PutPropertySlot& slot){ // Recursive invocation may already have specialized this instruction. if (vPC[0].u.opcode != getOpcode(op_put_by_id)) return; if (!baseValue.isCell()) return; // Uncacheable: give up. if (!slot.isCacheable()) { vPC[0] = getOpcode(op_put_by_id_generic); return; } JSCell* baseCell = asCell(baseValue); Structure* structure = baseCell->structure(); if (structure->isDictionary()) { vPC[0] = getOpcode(op_put_by_id_generic); return; } // Cache miss: record Structure to compare against next time. Structure* lastStructure = vPC[4].u.structure; if (structure != lastStructure) { // First miss: record Structure to compare against next time. if (!lastStructure) { vPC[4] = structure; return; } // Second miss: give up. vPC[0] = getOpcode(op_put_by_id_generic); return; } // Cache hit: Specialize instruction and ref Structures. // If baseCell != slot.base(), then baseCell must be a proxy for another object. if (baseCell != slot.base()) { vPC[0] = getOpcode(op_put_by_id_generic); return; } // Structure transition, cache transition info if (slot.type() == PutPropertySlot::NewProperty) { vPC[0] = getOpcode(op_put_by_id_transition); vPC[4] = structure->previousID(); vPC[5] = structure; vPC[6] = structure->prototypeChain(callFrame); vPC[7] = slot.cachedOffset(); codeBlock->refStructures(vPC); return; } vPC[0] = getOpcode(op_put_by_id_replace); vPC[5] = slot.cachedOffset(); codeBlock->refStructures(vPC);}NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC){ codeBlock->derefStructures(vPC); vPC[0] = getOpcode(op_put_by_id); vPC[4] = 0;}NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValuePtr baseValue, const Identifier& propertyName, const PropertySlot& slot){ // Recursive invocation may already have specialized this instruction. if (vPC[0].u.opcode != getOpcode(op_get_by_id)) return; // FIXME: Cache property access for immediates. if (!baseValue.isCell()) { vPC[0] = getOpcode(op_get_by_id_generic); return; } JSGlobalData* globalData = &callFrame->globalData(); if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { vPC[0] = getOpcode(op_get_array_length); return; } if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { vPC[0] = getOpcode(op_get_string_length); return; } // Uncacheable: give up. if (!slot.isCacheable()) { vPC[0] = getOpcode(op_get_by_id_generic); return; } Structure* structure = asCell(baseValue)->structure(); if (structure->isDictionary()) { vPC[0] = getOpcode(op_get_by_id_generic); return; } // Cache miss Structure* lastStructure = vPC[4].u.structure; if (structure != lastStructure) { // First miss: record Structure to compare against next time. if (!lastStructure) { vPC[4] = structure; return; } // Second miss: give up. vPC[0] = getOpcode(op_get_by_id_generic); return; } // Cache hit: Specialize instruction and ref Structures. if (slot.slotBase() == baseValue) { vPC[0] = getOpcode(op_get_by_id_self); vPC[5] = slot.cachedOffset(); codeBlock->refStructures(vPC); return; } if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { ASSERT(slot.slotBase().isObject()); JSObject* baseObject = asObject(slot.slotBase()); // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (baseObject->structure()->isDictionary()) baseObject->setStructure(Structure::fromDictionaryTransition(baseObject->structure())); vPC[0] = getOpcode(op_get_by_id_proto); vPC[5] = baseObject->structure(); vPC[6] = slot.cachedOffset(); codeBlock->refStructures(vPC); return; } size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot); if (!count) { vPC[0] = getOpcode(op_get_by_id_generic); return; } vPC[0] = getOpcode(op_get_by_id_chain); vPC[4] = structure; vPC[5] = structure->prototypeChain(callFrame); vPC[6] = count; vPC[7] = slot.cachedOffset(); codeBlock->refStructures(vPC);}NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC){ codeBlock->derefStructures(vPC); vPC[0] = getOpcode(op_get_by_id); vPC[4] = 0;}JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValuePtr* exception){ // One-time initialization of our address tables. We have to put this code // here because our labels are only in scope inside this function. if (flag == InitializeAndReturn) { #if HAVE(COMPUTED_GOTO) #define ADD_BYTECODE(id, length) m_opcodeTable[id] = &&id; FOR_EACH_OPCODE_ID(ADD_BYTECODE); #undef ADD_BYTECODE #define ADD_OPCODE_ID(id, length) m_opcodeIDTable.add(&&id, id); FOR_EACH_OPCODE_ID(ADD_OPCODE_ID); #undef ADD_OPCODE_ID
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -