📄 interpreter.cpp
字号:
/* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "Interpreter.h"#include "Arguments.h"#include "BatchedTransitionOptimizer.h"#include "CodeBlock.h"#include "DebuggerCallFrame.h"#include "EvalCodeCache.h"#include "ExceptionHelpers.h"#include "CallFrame.h"#include "GlobalEvalFunction.h"#include "JSActivation.h"#include "JSArray.h"#include "JSByteArray.h"#include "JSFunction.h"#include "JSNotAnObject.h"#include "JSPropertyNameIterator.h"#include "JSStaticScopeObject.h"#include "JSString.h"#include "ObjectPrototype.h"#include "Parser.h"#include "Profiler.h"#include "RegExpObject.h"#include "RegExpPrototype.h"#include "Register.h"#include "Collector.h"#include "Debugger.h"#include "Operations.h"#include "SamplingTool.h"#include <stdio.h>#if ENABLE(JIT)#include "JIT.h"#endif#if ENABLE(ASSEMBLER)#include "AssemblerBuffer.h"#endifusing namespace std;namespace JSC {static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc){#if ENABLE(JIT) return codeBlock->getBytecodeIndex(callFrame, pc);#else UNUSED_PARAM(callFrame); return static_cast<Instruction*>(pc) - codeBlock->instructions().begin();#endif}// Returns the depth of the scope chain within a given call frame.static int depth(CodeBlock* codeBlock, ScopeChain& sc){ if (!codeBlock->needsFullScopeChain()) return 0; return sc.localDepth();}NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue){ int dst = (vPC + 1)->u.operand; int property = (vPC + 2)->u.operand; ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); ASSERT(iter != end); CodeBlock* codeBlock = callFrame->codeBlock(); Identifier& ident = codeBlock->identifier(property); do { JSObject* o = *iter; PropertySlot slot(o); if (o->getPropertySlot(callFrame, ident, slot)) { JSValuePtr result = slot.getValue(callFrame, ident); exceptionValue = callFrame->globalData().exception; if (exceptionValue) return false; callFrame[dst] = JSValuePtr(result); return true; } } while (++iter != end); exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); return false;}NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue){ CodeBlock* codeBlock = callFrame->codeBlock(); int dst = (vPC + 1)->u.operand; int property = (vPC + 2)->u.operand; int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain(); ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); ASSERT(iter != end); while (skip--) { ++iter; ASSERT(iter != end); } Identifier& ident = codeBlock->identifier(property); do { JSObject* o = *iter; PropertySlot slot(o); if (o->getPropertySlot(callFrame, ident, slot)) { JSValuePtr result = slot.getValue(callFrame, ident); exceptionValue = callFrame->globalData().exception; if (exceptionValue) return false; callFrame[dst] = JSValuePtr(result); return true; } } while (++iter != end); exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); return false;}NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue){ int dst = (vPC + 1)->u.operand; JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell); ASSERT(globalObject->isGlobalObject()); int property = (vPC + 3)->u.operand; Structure* structure = (vPC + 4)->u.structure; int offset = (vPC + 5)->u.operand; if (structure == globalObject->structure()) { callFrame[dst] = JSValuePtr(globalObject->getDirectOffset(offset)); return true; } CodeBlock* codeBlock = callFrame->codeBlock(); Identifier& ident = codeBlock->identifier(property); PropertySlot slot(globalObject); if (globalObject->getPropertySlot(callFrame, ident, slot)) { JSValuePtr result = slot.getValue(callFrame, ident); if (slot.isCacheable() && !globalObject->structure()->isDictionary()) { if (vPC[4].u.structure) vPC[4].u.structure->deref(); globalObject->structure()->ref(); vPC[4] = globalObject->structure(); vPC[5] = slot.cachedOffset(); callFrame[dst] = JSValuePtr(result); return true; } exceptionValue = callFrame->globalData().exception; if (exceptionValue) return false; callFrame[dst] = JSValuePtr(result); return true; } exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); return false;}NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC){ int dst = (vPC + 1)->u.operand; int property = (vPC + 2)->u.operand; callFrame[dst] = JSValuePtr(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain()));}NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue){ int baseDst = (vPC + 1)->u.operand; int propDst = (vPC + 2)->u.operand; int property = (vPC + 3)->u.operand; ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); // FIXME: add scopeDepthIsZero optimization ASSERT(iter != end); CodeBlock* codeBlock = callFrame->codeBlock(); Identifier& ident = codeBlock->identifier(property); JSObject* base; do { base = *iter; PropertySlot slot(base); if (base->getPropertySlot(callFrame, ident, slot)) { JSValuePtr result = slot.getValue(callFrame, ident); exceptionValue = callFrame->globalData().exception; if (exceptionValue) return false; callFrame[propDst] = JSValuePtr(result); callFrame[baseDst] = JSValuePtr(base); return true; } ++iter; } while (iter != end); exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); return false;}NEVER_INLINE bool Interpreter::resolveBaseAndFunc(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue){ int baseDst = (vPC + 1)->u.operand; int funcDst = (vPC + 2)->u.operand; int property = (vPC + 3)->u.operand; ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); // FIXME: add scopeDepthIsZero optimization ASSERT(iter != end); CodeBlock* codeBlock = callFrame->codeBlock(); Identifier& ident = codeBlock->identifier(property); JSObject* base; do { base = *iter; PropertySlot slot(base); if (base->getPropertySlot(callFrame, ident, slot)) { // ECMA 11.2.3 says that if we hit an activation the this value should be null. // However, section 10.2.3 says that in the case where the value provided // by the caller is null, the global object should be used. It also says // that the section does not apply to internal functions, but for simplicity // of implementation we use the global object anyway here. This guarantees // that in host objects you always get a valid object for this. // We also handle wrapper substitution for the global object at the same time. JSObject* thisObj = base->toThisObject(callFrame); JSValuePtr result = slot.getValue(callFrame, ident); exceptionValue = callFrame->globalData().exception; if (exceptionValue) return false; callFrame[baseDst] = JSValuePtr(thisObj); callFrame[funcDst] = JSValuePtr(result); return true; } ++iter; } while (iter != end); exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); return false;}ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc){ Register* r = callFrame->registers(); Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters; if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments if (UNLIKELY(!registerFile->grow(newEnd))) return 0; r += registerOffset; } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks size_t omittedArgCount = newCodeBlock->m_numParameters - argc; registerOffset += omittedArgCount; newEnd += omittedArgCount; if (!registerFile->grow(newEnd)) return 0; r += registerOffset; Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; for (size_t i = 0; i < omittedArgCount; ++i) argv[i] = jsUndefined(); } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind size_t numParameters = newCodeBlock->m_numParameters; registerOffset += numParameters; newEnd += numParameters; if (!registerFile->grow(newEnd)) return 0; r += registerOffset; Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc; for (size_t i = 0; i < numParameters; ++i) argv[i + argc] = argv[i]; } return CallFrame::create(r);}static NEVER_INLINE bool isNotObject(CallFrame* callFrame, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValuePtr value, JSValuePtr& exceptionData){ if (value.isObject()) return false; exceptionData = createInvalidParamError(callFrame, forInstanceOf ? "instanceof" : "in" , value, vPC - codeBlock->instructions().begin(), codeBlock); return true;}NEVER_INLINE JSValuePtr Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValuePtr& exceptionValue){ if (argc < 2) return jsUndefined(); JSValuePtr program = argv[1].jsValue(callFrame); if (!program.isString()) return program; UString programSource = asString(program)->value(); ScopeChainNode* scopeChain = callFrame->scopeChain(); CodeBlock* codeBlock = callFrame->codeBlock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -