diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-09-10 19:10:20 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-09-10 19:10:20 +0200 |
commit | 284837daa07b29d6a63a748544a90b1f5842ac5c (patch) | |
tree | ecd258180bde91fe741e0cfd2638beb3c6da7e8e /Source/JavaScriptCore/interpreter/Interpreter.cpp | |
parent | 2e2ba8ff45915f40ed3e014101269c175f2a89a0 (diff) | |
download | qtwebkit-284837daa07b29d6a63a748544a90b1f5842ac5c.tar.gz |
Imported WebKit commit 68645295d2e3e09af2c942f092556f06aa5f8b0d (http://svn.webkit.org/repository/webkit/trunk@128073)
New snapshot
Diffstat (limited to 'Source/JavaScriptCore/interpreter/Interpreter.cpp')
-rw-r--r-- | Source/JavaScriptCore/interpreter/Interpreter.cpp | 727 |
1 files changed, 257 insertions, 470 deletions
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index f6a197ef0..87b77d639 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -45,11 +45,13 @@ #include "JSActivation.h" #include "JSArray.h" #include "JSBoundFunction.h" +#include "JSNameScope.h" #include "JSNotAnObject.h" #include "JSPropertyNameIterator.h" -#include "LiteralParser.h" -#include "JSStaticScopeObject.h" #include "JSString.h" +#include "JSWithScope.h" +#include "LLIntCLoop.h" +#include "LiteralParser.h" #include "NameInstance.h" #include "ObjectPrototype.h" #include "Operations.h" @@ -61,7 +63,6 @@ #include "SamplingTool.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" -#include "UStringConcatenate.h" #include <limits.h> #include <stdio.h> #include <wtf/Threading.h> @@ -80,7 +81,7 @@ namespace JSC { static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset); // Returns the depth of the scope chain within a given call frame. -static int depth(CodeBlock* codeBlock, ScopeChainNode* sc) +static int depth(CodeBlock* codeBlock, JSScope* sc) { if (!codeBlock->needsFullScopeChain()) return 0; @@ -93,282 +94,6 @@ static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* string return jsString(exec, strings, count); } -NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& 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->get(); - PropertySlot slot(o); - if (o->getPropertySlot(callFrame, ident, slot)) { - JSValue result = slot.getValue(callFrame, ident); - exceptionValue = callFrame->globalData().exception; - if (exceptionValue) - return false; - callFrame->uncheckedR(dst) = JSValue(result); - return true; - } - } while (++iter != end); - exceptionValue = createUndefinedVariableError(callFrame, ident); - return false; -} - -NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) -{ - CodeBlock* codeBlock = callFrame->codeBlock(); - - int dst = vPC[1].u.operand; - int property = vPC[2].u.operand; - int skip = vPC[3].u.operand; - - ScopeChainNode* scopeChain = callFrame->scopeChain(); - ScopeChainIterator iter = scopeChain->begin(); - ScopeChainIterator end = scopeChain->end(); - ASSERT(iter != end); - bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); - ASSERT(skip || !checkTopLevel); - if (checkTopLevel && skip--) { - if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) - ++iter; - } - while (skip--) { - ++iter; - ASSERT(iter != end); - } - Identifier& ident = codeBlock->identifier(property); - do { - JSObject* o = iter->get(); - PropertySlot slot(o); - if (o->getPropertySlot(callFrame, ident, slot)) { - JSValue result = slot.getValue(callFrame, ident); - exceptionValue = callFrame->globalData().exception; - if (exceptionValue) - return false; - ASSERT(result); - callFrame->uncheckedR(dst) = JSValue(result); - return true; - } - } while (++iter != end); - exceptionValue = createUndefinedVariableError(callFrame, ident); - return false; -} - -NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) -{ - int dst = vPC[1].u.operand; - CodeBlock* codeBlock = callFrame->codeBlock(); - JSGlobalObject* globalObject = codeBlock->globalObject(); - ASSERT(globalObject->isGlobalObject()); - int property = vPC[2].u.operand; - Structure* structure = vPC[3].u.structure.get(); - int offset = vPC[4].u.operand; - - if (structure == globalObject->structure()) { - callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset)); - return true; - } - - Identifier& ident = codeBlock->identifier(property); - PropertySlot slot(globalObject); - if (globalObject->getPropertySlot(callFrame, ident, slot)) { - JSValue result = slot.getValue(callFrame, ident); - if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { - vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure()); - vPC[4] = slot.cachedOffset(); - callFrame->uncheckedR(dst) = JSValue(result); - return true; - } - - exceptionValue = callFrame->globalData().exception; - if (exceptionValue) - return false; - callFrame->uncheckedR(dst) = JSValue(result); - return true; - } - - exceptionValue = createUndefinedVariableError(callFrame, ident); - return false; -} - -NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) -{ - int dst = vPC[1].u.operand; - CodeBlock* codeBlock = callFrame->codeBlock(); - JSGlobalObject* globalObject = codeBlock->globalObject(); - ASSERT(globalObject->isGlobalObject()); - int property = vPC[2].u.operand; - Structure* structure = vPC[3].u.structure.get(); - int offset = vPC[4].u.operand; - int skip = vPC[5].u.operand; - - ScopeChainNode* scopeChain = callFrame->scopeChain(); - ScopeChainIterator iter = scopeChain->begin(); - ScopeChainIterator end = scopeChain->end(); - ASSERT(iter != end); - bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); - ASSERT(skip || !checkTopLevel); - if (checkTopLevel && skip--) { - if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) - ++iter; - } - while (skip--) { - JSObject* o = iter->get(); - if (o->hasCustomProperties()) { - Identifier& ident = codeBlock->identifier(property); - do { - PropertySlot slot(o); - if (o->getPropertySlot(callFrame, ident, slot)) { - JSValue result = slot.getValue(callFrame, ident); - exceptionValue = callFrame->globalData().exception; - if (exceptionValue) - return false; - ASSERT(result); - callFrame->uncheckedR(dst) = JSValue(result); - return true; - } - if (iter == end) - break; - o = iter->get(); - ++iter; - } while (true); - exceptionValue = createUndefinedVariableError(callFrame, ident); - return false; - } - ++iter; - } - - if (structure == globalObject->structure()) { - callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset)); - ASSERT(callFrame->uncheckedR(dst).jsValue()); - return true; - } - - Identifier& ident = codeBlock->identifier(property); - PropertySlot slot(globalObject); - if (globalObject->getPropertySlot(callFrame, ident, slot)) { - JSValue result = slot.getValue(callFrame, ident); - if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { - vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure()); - vPC[4] = slot.cachedOffset(); - ASSERT(result); - callFrame->uncheckedR(dst) = JSValue(result); - return true; - } - - exceptionValue = callFrame->globalData().exception; - if (exceptionValue) - return false; - ASSERT(result); - callFrame->uncheckedR(dst) = JSValue(result); - return true; - } - - exceptionValue = createUndefinedVariableError(callFrame, ident); - return false; -} - -NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC) -{ - int dst = vPC[1].u.operand; - int property = vPC[2].u.operand; - bool isStrictPut = vPC[3].u.operand; - Identifier ident = callFrame->codeBlock()->identifier(property); - JSValue result = JSC::resolveBase(callFrame, ident, callFrame->scopeChain(), isStrictPut); - if (result) { - callFrame->uncheckedR(dst) = result; - ASSERT(callFrame->uncheckedR(dst).jsValue()); - } else - callFrame->globalData().exception = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring()); -} - -NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& 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->get(); - PropertySlot slot(base); - if (base->getPropertySlot(callFrame, ident, slot)) { - JSValue result = slot.getValue(callFrame, ident); - exceptionValue = callFrame->globalData().exception; - if (exceptionValue) - return false; - callFrame->uncheckedR(propDst) = JSValue(result); - callFrame->uncheckedR(baseDst) = JSValue(base); - return true; - } - ++iter; - } while (iter != end); - - exceptionValue = createUndefinedVariableError(callFrame, ident); - return false; -} - -NEVER_INLINE bool Interpreter::resolveThisAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) -{ - int thisDst = 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->get(); - ++iter; - PropertySlot slot(base); - if (base->getPropertySlot(callFrame, ident, slot)) { - JSValue result = slot.getValue(callFrame, ident); - exceptionValue = callFrame->globalData().exception; - if (exceptionValue) - return false; - callFrame->uncheckedR(propDst) = JSValue(result); - // All entries on the scope chain should be EnvironmentRecords (activations etc), - // other then 'with' object, which are directly referenced from the scope chain, - // and the global object. If we hit either an EnvironmentRecord or a global - // object at the end of the scope chain, this is undefined. If we hit a non- - // EnvironmentRecord within the scope chain, pass the base as the this value. - if (iter == end || base->structure()->typeInfo().isEnvironmentRecord()) - callFrame->uncheckedR(thisDst) = jsUndefined(); - else - callFrame->uncheckedR(thisDst) = JSValue(base); - return true; - } - } while (iter != end); - - exceptionValue = createUndefinedVariableError(callFrame, ident); - return false; -} - #endif // ENABLE(CLASSIC_INTERPRETER) ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argumentCountIncludingThis) @@ -426,13 +151,13 @@ JSValue eval(CallFrame* callFrame) return program; TopCallFrameSetter topCallFrame(callFrame->globalData(), callFrame); - UString programSource = asString(program)->value(callFrame); + String programSource = asString(program)->value(callFrame); if (callFrame->hadException()) return JSValue(); CallFrame* callerFrame = callFrame->callerFrame(); CodeBlock* callerCodeBlock = callerFrame->codeBlock(); - ScopeChainNode* callerScopeChain = callerFrame->scopeChain(); + JSScope* callerScopeChain = callerFrame->scope(); EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, callerScopeChain); if (!eval) { @@ -554,15 +279,14 @@ Interpreter::Interpreter() Interpreter::~Interpreter() { -#if ENABLE(LLINT) +#if ENABLE(LLINT) && ENABLE(COMPUTED_GOTO_OPCODES) if (m_classicEnabled) delete[] m_opcodeTable; #endif } -void Interpreter::initialize(LLInt::Data* llintData, bool canUseJIT) +void Interpreter::initialize(bool canUseJIT) { - UNUSED_PARAM(llintData); UNUSED_PARAM(canUseJIT); // If we have LLInt, then we shouldn't be building any kind of classic interpreter. @@ -570,15 +294,16 @@ void Interpreter::initialize(LLInt::Data* llintData, bool canUseJIT) #error "Building both LLInt and the Classic Interpreter is not supported because it doesn't make sense." #endif +#if ENABLE(COMPUTED_GOTO_OPCODES) #if ENABLE(LLINT) - m_opcodeTable = llintData->opcodeMap(); + m_opcodeTable = LLInt::opcodeMap(); for (int i = 0; i < numOpcodeIDs; ++i) m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); m_classicEnabled = false; + #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) if (canUseJIT) { // If the JIT is present, don't use jump destinations for opcodes. - for (int i = 0; i < numOpcodeIDs; ++i) { Opcode opcode = bitwise_cast<void*>(static_cast<uintptr_t>(i)); m_opcodeTable[i] = opcode; @@ -592,13 +317,16 @@ void Interpreter::initialize(LLInt::Data* llintData, bool canUseJIT) m_classicEnabled = true; } -#else +#endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) + +#else // !ENABLE(COMPUTED_GOTO_OPCODES) #if ENABLE(CLASSIC_INTERPRETER) m_classicEnabled = true; #else m_classicEnabled = false; #endif -#endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) +#endif // !ENABLE(COMPUTED_GOTO_OPCODES) + #if !ASSERT_DISABLED m_initialized = true; #endif @@ -638,7 +366,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) while (it < end) { JSValue v = it->jsValue(); int registerNumber = it - callFrame->registers(); - UString name = codeBlock->nameForRegister(registerNumber); + String name = codeBlock->nameForRegister(registerNumber); #if USE(JSVALUE32_64) dataLog("[r% 3d %14s] | %10p | %-16s 0x%llx \n", registerNumber, name.ascii().data(), it, v.description(), JSValue::encode(v)); #else @@ -654,7 +382,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) ++it; dataLog("[Callee] | %10p | %p \n", it, callFrame->callee()); ++it; - dataLog("[ScopeChain] | %10p | %p \n", it, callFrame->scopeChain()); + dataLog("[ScopeChain] | %10p | %p \n", it, callFrame->scope()); ++it; #if ENABLE(JIT) AbstractPC pc = callFrame->abstractReturnPC(callFrame->globalData()); @@ -677,7 +405,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) do { JSValue v = it->jsValue(); int registerNumber = it - callFrame->registers(); - UString name = codeBlock->nameForRegister(registerNumber); + String name = codeBlock->nameForRegister(registerNumber); #if USE(JSVALUE32_64) dataLog("[r% 3d %14s] | %10p | %-16s 0x%llx \n", registerNumber, name.ascii().data(), it, v.description(), JSValue::encode(v)); #else @@ -709,7 +437,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) bool Interpreter::isOpcode(Opcode opcode) { -#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT) +#if ENABLE(COMPUTED_GOTO_OPCODES) #if !ENABLE(LLINT) if (!m_classicEnabled) return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)) <= op_end; @@ -725,7 +453,7 @@ bool Interpreter::isOpcode(Opcode opcode) NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock) { CodeBlock* oldCodeBlock = codeBlock; - ScopeChainNode* scopeChain = callFrame->scopeChain(); + JSScope* scope = callFrame->scope(); if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); @@ -739,14 +467,14 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) { if (!callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue()) { oldCodeBlock->createActivation(callFrame); - scopeChain = callFrame->scopeChain(); + scope = callFrame->scope(); } - while (!scopeChain->object->inherits(&JSActivation::s_info)) - scopeChain = scopeChain->pop(); + while (!scope->inherits(&JSActivation::s_info)) + scope = scope->next(); - callFrame->setScopeChain(scopeChain); - JSActivation* activation = asActivation(scopeChain->object.get()); - activation->tearOff(*scopeChain->globalData); + callFrame->setScope(scope); + JSActivation* activation = asActivation(scope); + activation->tearOff(*scope->globalData()); if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) asArguments(arguments)->didTearOffActivation(callFrame->globalData(), activation); } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) { @@ -773,7 +501,7 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); else bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1; -#elif ENABLE(JIT) +#elif ENABLE(JIT) || ENABLE(LLINT) bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); #else bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1; @@ -808,10 +536,10 @@ static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, if (!jsMessage || !jsMessage.isString()) return; - UString message = asString(jsMessage)->value(callFrame); + String message = asString(jsMessage)->value(callFrame); if (expressionStart < expressionStop) - message = makeUString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')"); + message = makeString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')"); else { // No range information, so give a few characters of context const StringImpl* data = codeBlock->source()->data(); @@ -828,7 +556,7 @@ static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, stop++; while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1])) stop--; - message = makeUString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')"); + message = makeString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')"); } exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message)); @@ -845,7 +573,7 @@ static int getLineNumberForCallFrame(JSGlobalData* globalData, CallFrame* callFr if (!globalData->canUseJIT()) return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode() - 1); #endif -#if ENABLE(JIT) +#if ENABLE(JIT) || ENABLE(LLINT) #if ENABLE(DFG_JIT) if (codeBlock->getJITType() == JITCode::DFGJIT) return codeBlock->lineNumberForBytecodeOffset(codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex); @@ -871,7 +599,7 @@ static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* callerCodeBlock = callerFrame->codeBlock(); -#if ENABLE(JIT) +#if ENABLE(JIT) || ENABLE(LLINT) if (!callFrame->hasReturnPC()) callframeIsHost = true; #endif @@ -890,7 +618,7 @@ static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, return callerFrame; } #endif -#if ENABLE(JIT) +#if ENABLE(JIT) || ENABLE(LLINT) #if ENABLE(DFG_JIT) if (callerCodeBlock && callerCodeBlock->getJITType() == JITCode::DFGJIT) { unsigned codeOriginIndex = callerFrame->codeOriginIndexForDFG(); @@ -907,7 +635,7 @@ static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, return callerFrame; } #endif -#if ENABLE(JIT) +#if ENABLE(JIT) || ENABLE(LLINT) #if ENABLE(DFG_JIT) if (callFrame->isInlineCallFrame()) { InlineCallFrame* icf = callFrame->inlineCallFrame(); @@ -941,7 +669,7 @@ static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, return callerFrame; } -static ALWAYS_INLINE const UString getSourceURLFromCallFrame(CallFrame* callFrame) +static ALWAYS_INLINE const String getSourceURLFromCallFrame(CallFrame* callFrame) { ASSERT(!callFrame->hasHostCallFrameFlag()); #if ENABLE(CLASSIC_INTERPRETER) @@ -982,13 +710,13 @@ void Interpreter::getStackTrace(JSGlobalData* globalData, Vector<StackFrame>& re callFrame = callFrame->trueCallFrameFromVMCode(); while (callFrame && callFrame != CallFrame::noCaller()) { - UString sourceURL; + String sourceURL; if (callFrame->codeBlock()) { sourceURL = getSourceURLFromCallFrame(callFrame); StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), getStackFrameCodeType(callFrame), Strong<ExecutableBase>(*globalData, callFrame->codeBlock()->ownerExecutable()), line, sourceURL}; results.append(s); } else { - StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), -1, UString()}; + StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), -1, String()}; results.append(s); } unsigned unusedBytecodeOffset = 0; @@ -1014,6 +742,8 @@ void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSObject* error globalObject = globalData->dynamicGlobalObject; else globalObject = error->globalObject(); + + // FIXME: JSStringJoiner could be more efficient than StringBuilder here. StringBuilder builder; for (unsigned i = 0; i < stackTrace.size(); i++) { builder.append(String(stackTrace[i].toString(globalObject->globalExec()).impl())); @@ -1021,7 +751,7 @@ void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSObject* error builder.append('\n'); } - error->putDirect(*globalData, globalData->propertyNames->stack, jsString(globalData, UString(builder.toString().impl())), ReadOnly | DontDelete); + error->putDirect(*globalData, globalData->propertyNames->stack, jsString(globalData, builder.toString()), ReadOnly | DontDelete); } NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset) @@ -1085,15 +815,15 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV m_registerFile.shrink(highWaterMark); // Unwind the scope chain within the exception handler's call frame. - ScopeChainNode* scopeChain = callFrame->scopeChain(); + JSScope* scope = callFrame->scope(); int scopeDelta = 0; if (!codeBlock->needsFullScopeChain() || codeBlock->codeType() != FunctionCode || callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) - scopeDelta = depth(codeBlock, scopeChain) - handler->scopeDepth; + scopeDelta = depth(codeBlock, scope) - handler->scopeDepth; ASSERT(scopeDelta >= 0); while (scopeDelta--) - scopeChain = scopeChain->pop(); - callFrame->setScopeChain(scopeChain); + scope = scope->next(); + callFrame->setScope(scope); return handler; } @@ -1110,10 +840,11 @@ static inline JSObject* checkedReturn(JSObject* returnValue) return returnValue; } -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj) +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, JSObject* thisObj) { + JSScope* scope = callFrame->scope(); ASSERT(isValidThisObject(thisObj, callFrame)); - ASSERT(!scopeChain->globalData->exception); + ASSERT(!scope->globalData()->exception); ASSERT(!callFrame->globalData().isCollectorBusy()); if (callFrame->globalData().isCollectorBusy()) CRASH(); @@ -1121,22 +852,25 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, S if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth) return checkedReturn(throwStackOverflowError(callFrame)); - DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get()); + // First check if the "program" is actually just a JSON object. If so, + // we'll handle the JSON object here. Else, we'll handle real JS code + // below at failedJSONP. + DynamicGlobalObjectScope globalObjectScope(*scope->globalData(), scope->globalObject()); Vector<JSONPData> JSONPData; bool parseResult; - const UString programSource = program->source().toString(); + const String programSource = program->source().toString(); if (programSource.isNull()) return jsUndefined(); if (programSource.is8Bit()) { LiteralParser<LChar> literalParser(callFrame, programSource.characters8(), programSource.length(), JSONP); - parseResult = literalParser.tryJSONPParse(JSONPData, scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get())); + parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject())); } else { LiteralParser<UChar> literalParser(callFrame, programSource.characters16(), programSource.length(), JSONP); - parseResult = literalParser.tryJSONPParse(JSONPData, scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get())); + parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject())); } if (parseResult) { - JSGlobalObject* globalObject = scopeChain->globalObject.get(); + JSGlobalObject* globalObject = scope->globalObject(); JSValue result; for (unsigned entry = 0; entry < JSONPData.size(); entry++) { Vector<JSONPPathEntry> JSONPPath; @@ -1221,36 +955,47 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, S return result; } failedJSONP: - JSObject* error = program->compile(callFrame, scopeChain); + // If we get here, then we have already proven that the script is not a JSON + // object. + + // Compile source to bytecode if necessary: + JSObject* error = program->compile(callFrame, scope); if (error) return checkedReturn(throwError(callFrame, error)); CodeBlock* codeBlock = &program->generatedBytecode(); + // Reserve stack space for this invocation: Register* oldEnd = m_registerFile.end(); Register* newEnd = oldEnd + codeBlock->numParameters() + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters; if (!m_registerFile.grow(newEnd)) return checkedReturn(throwStackOverflowError(callFrame)); + // Push the call frame for this invocation: CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->numParameters() + RegisterFile::CallFrameHeaderSize); ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. - newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), codeBlock->numParameters(), 0); + newCallFrame->init(codeBlock, 0, scope, CallFrame::noCaller(), codeBlock->numParameters(), 0); newCallFrame->setThisValue(thisObj); TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); if (Profiler* profiler = callFrame->globalData().enabledProfiler()) profiler->willExecute(callFrame, program->sourceURL(), program->lineNo()); + // Execute the code: JSValue result; { SamplingTool::CallRecord callRecord(m_sampler.get()); m_reentryDepth++; +#if ENABLE(LLINT_C_LOOP) + result = LLInt::CLoop::execute(newCallFrame, llint_program_prologue); +#else // !ENABLE(LLINT_C_LOOP) #if ENABLE(JIT) if (!classicEnabled()) - result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData); + result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scope->globalData()); else -#endif +#endif // ENABLE(JIT) result = privateExecute(Normal, &m_registerFile, newCallFrame); +#endif // !ENABLE(LLINT_C_LOOP) m_reentryDepth--; } @@ -1275,7 +1020,7 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT return checkedReturn(throwStackOverflowError(callFrame)); Register* oldEnd = m_registerFile.end(); - ASSERT(callFrame->frameExtent() <= oldEnd || callFrame == callFrame->scopeChain()->globalObject->globalExec()); + ASSERT(callFrame->frameExtent() <= oldEnd || callFrame == callFrame->scope()->globalObject()->globalExec()); int argCount = 1 + args.size(); // implicit "this" parameter size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize; @@ -1288,11 +1033,11 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT newCallFrame->setArgument(i, args.at(i)); if (callType == CallTypeJS) { - ScopeChainNode* callDataScopeChain = callData.js.scopeChain; + JSScope* callDataScope = callData.js.scope; - DynamicGlobalObjectScope globalObjectScope(*callDataScopeChain->globalData, callDataScopeChain->globalObject.get()); + DynamicGlobalObjectScope globalObjectScope(*callDataScope->globalData(), callDataScope->globalObject()); - JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain); + JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScope); if (UNLIKELY(!!compileError)) { m_registerFile.shrink(oldEnd); return checkedReturn(throwError(callFrame, compileError)); @@ -1305,7 +1050,7 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT return checkedReturn(throwStackOverflowError(callFrame)); } - newCallFrame->init(newCodeBlock, 0, callDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, function); + newCallFrame->init(newCodeBlock, 0, callDataScope, callFrame->addHostCallFrameFlag(), argCount, function); TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); @@ -1317,12 +1062,17 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT SamplingTool::CallRecord callRecord(m_sampler.get()); m_reentryDepth++; +#if ENABLE(LLINT_C_LOOP) + result = LLInt::CLoop::execute(newCallFrame, llint_function_for_call_prologue); +#else // ENABLE(LLINT_C_LOOP) #if ENABLE(JIT) if (!classicEnabled()) - result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScopeChain->globalData); + result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScope->globalData()); else -#endif +#endif // ENABLE(JIT) result = privateExecute(Normal, &m_registerFile, newCallFrame); +#endif // !ENABLE(LLINT_C_LOOP) + m_reentryDepth--; } @@ -1334,12 +1084,12 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT } ASSERT(callType == CallTypeHost); - ScopeChainNode* scopeChain = callFrame->scopeChain(); - newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, function); + JSScope* scope = callFrame->scope(); + newCallFrame->init(0, 0, scope, callFrame->addHostCallFrameFlag(), argCount, function); TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); - DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get()); + DynamicGlobalObjectScope globalObjectScope(*scope->globalData(), scope->globalObject()); if (Profiler* profiler = callFrame->globalData().enabledProfiler()) profiler->willExecute(callFrame, function); @@ -1382,11 +1132,11 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc newCallFrame->setArgument(i, args.at(i)); if (constructType == ConstructTypeJS) { - ScopeChainNode* constructDataScopeChain = constructData.js.scopeChain; + JSScope* constructDataScope = constructData.js.scope; - DynamicGlobalObjectScope globalObjectScope(*constructDataScopeChain->globalData, constructDataScopeChain->globalObject.get()); + DynamicGlobalObjectScope globalObjectScope(*constructDataScope->globalData(), constructDataScope->globalObject()); - JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScopeChain); + JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScope); if (UNLIKELY(!!compileError)) { m_registerFile.shrink(oldEnd); return checkedReturn(throwError(callFrame, compileError)); @@ -1399,7 +1149,7 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc return checkedReturn(throwStackOverflowError(callFrame)); } - newCallFrame->init(newCodeBlock, 0, constructDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor); + newCallFrame->init(newCodeBlock, 0, constructDataScope, callFrame->addHostCallFrameFlag(), argCount, constructor); TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); @@ -1411,12 +1161,16 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc SamplingTool::CallRecord callRecord(m_sampler.get()); m_reentryDepth++; +#if ENABLE(LLINT_C_LOOP) + result = LLInt::CLoop::execute(newCallFrame, llint_function_for_construct_prologue); +#else // !ENABLE(LLINT_C_LOOP) #if ENABLE(JIT) if (!classicEnabled()) - result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScopeChain->globalData); + result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScope->globalData()); else -#endif +#endif // ENABLE(JIT) result = privateExecute(Normal, &m_registerFile, newCallFrame); +#endif // !ENABLE(LLINT_C_LOOP) m_reentryDepth--; } @@ -1431,12 +1185,12 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc } ASSERT(constructType == ConstructTypeHost); - ScopeChainNode* scopeChain = callFrame->scopeChain(); - newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor); + JSScope* scope = callFrame->scope(); + newCallFrame->init(0, 0, scope, callFrame->addHostCallFrameFlag(), argCount, constructor); TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); - DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get()); + DynamicGlobalObjectScope globalObjectScope(*scope->globalData(), scope->globalObject()); if (Profiler* profiler = callFrame->globalData().enabledProfiler()) profiler->willExecute(callFrame, constructor); @@ -1457,9 +1211,9 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc return checkedReturn(asObject(result)); } -CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, int argumentCountIncludingThis, ScopeChainNode* scopeChain) +CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope) { - ASSERT(!scopeChain->globalData->exception); + ASSERT(!scope->globalData()->exception); if (callFrame->globalData().isCollectorBusy()) return CallFrameClosure(); @@ -1478,7 +1232,7 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE return CallFrameClosure(); } - JSObject* error = functionExecutable->compileForCall(callFrame, scopeChain); + JSObject* error = functionExecutable->compileForCall(callFrame, scope); if (error) { throwError(callFrame, error); m_registerFile.shrink(oldEnd); @@ -1492,9 +1246,9 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE m_registerFile.shrink(oldEnd); return CallFrameClosure(); } - newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), argumentCountIncludingThis, function); - scopeChain->globalData->topCallFrame = newCallFrame; - CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->numParameters(), argumentCountIncludingThis }; + newCallFrame->init(codeBlock, 0, scope, callFrame->addHostCallFrameFlag(), argumentCountIncludingThis, function); + scope->globalData()->topCallFrame = newCallFrame; + CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, scope->globalData(), oldEnd, scope, codeBlock->numParameters(), argumentCountIncludingThis }; return result; } @@ -1514,6 +1268,9 @@ JSValue Interpreter::execute(CallFrameClosure& closure) SamplingTool::CallRecord callRecord(m_sampler.get()); m_reentryDepth++; +#if ENABLE(LLINT_C_LOOP) + result = LLInt::CLoop::execute(closure.newCallFrame, llint_function_for_call_prologue); +#else // !ENABLE(LLINT_C_LOOP) #if ENABLE(JIT) #if ENABLE(CLASSIC_INTERPRETER) if (closure.newCallFrame->globalData().canUseJIT()) @@ -1522,10 +1279,12 @@ JSValue Interpreter::execute(CallFrameClosure& closure) #if ENABLE(CLASSIC_INTERPRETER) else #endif -#endif +#endif // ENABLE(JIT) #if ENABLE(CLASSIC_INTERPRETER) result = privateExecute(Normal, &m_registerFile, closure.newCallFrame); #endif +#endif // !ENABLE(LLINT_C_LOOP) + m_reentryDepth--; } @@ -1540,41 +1299,39 @@ void Interpreter::endRepeatCall(CallFrameClosure& closure) m_registerFile.shrink(closure.oldEnd); } -JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, ScopeChainNode* scopeChain, int globalRegisterOffset) +JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope, int globalRegisterOffset) { ASSERT(isValidThisObject(thisValue, callFrame)); - ASSERT(!scopeChain->globalData->exception); + ASSERT(!scope->globalData()->exception); ASSERT(!callFrame->globalData().isCollectorBusy()); if (callFrame->globalData().isCollectorBusy()) return jsNull(); - DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get()); + DynamicGlobalObjectScope globalObjectScope(*scope->globalData(), scope->globalObject()); if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth) return checkedReturn(throwStackOverflowError(callFrame)); - JSObject* compileError = eval->compile(callFrame, scopeChain); + JSObject* compileError = eval->compile(callFrame, scope); if (UNLIKELY(!!compileError)) return checkedReturn(throwError(callFrame, compileError)); EvalCodeBlock* codeBlock = &eval->generatedBytecode(); JSObject* variableObject; - for (ScopeChainNode* node = scopeChain; ; node = node->next.get()) { + for (JSScope* node = scope; ; node = node->next()) { ASSERT(node); - if (node->object->isVariableObject() && !node->object->isStaticScopeObject()) { - variableObject = jsCast<JSSymbolTableObject*>(node->object.get()); + if (node->isVariableObject() && !node->isNameScopeObject()) { + variableObject = node; break; } } unsigned numVariables = codeBlock->numVariables(); int numFunctions = codeBlock->numberOfFunctionDecls(); - bool pushedScope = false; if (numVariables || numFunctions) { if (codeBlock->isStrictMode()) { - variableObject = StrictEvalActivation::create(callFrame); - scopeChain = scopeChain->push(variableObject); - pushedScope = true; + scope = StrictEvalActivation::create(callFrame); + variableObject = scope; } // Scope for BatchedTransitionOptimizer BatchedTransitionOptimizer optimizer(callFrame->globalData(), variableObject); @@ -1590,22 +1347,19 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue for (int i = 0; i < numFunctions; ++i) { FunctionExecutable* function = codeBlock->functionDecl(i); PutPropertySlot slot; - variableObject->methodTable()->put(variableObject, callFrame, function->name(), function->make(callFrame, scopeChain), slot); + variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(callFrame, function, scope), slot); } } Register* oldEnd = m_registerFile.end(); Register* newEnd = m_registerFile.begin() + globalRegisterOffset + codeBlock->m_numCalleeRegisters; - if (!m_registerFile.grow(newEnd)) { - if (pushedScope) - scopeChain->pop(); + if (!m_registerFile.grow(newEnd)) return checkedReturn(throwStackOverflowError(callFrame)); - } CallFrame* newCallFrame = CallFrame::create(m_registerFile.begin() + globalRegisterOffset); ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. - newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->numParameters(), 0); + newCallFrame->init(codeBlock, 0, scope, callFrame->addHostCallFrameFlag(), codeBlock->numParameters(), 0); newCallFrame->setThisValue(thisValue); TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); @@ -1619,18 +1373,22 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue m_reentryDepth++; +#if ENABLE(LLINT_C_LOOP) + result = LLInt::CLoop::execute(newCallFrame, llint_eval_prologue); +#else // !ENABLE(LLINT_C_LOOP) #if ENABLE(JIT) #if ENABLE(CLASSIC_INTERPRETER) if (callFrame->globalData().canUseJIT()) #endif - result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData); + result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scope->globalData()); #if ENABLE(CLASSIC_INTERPRETER) else #endif -#endif +#endif // ENABLE(JIT) #if ENABLE(CLASSIC_INTERPRETER) result = privateExecute(Normal, &m_registerFile, newCallFrame); #endif +#endif // !ENABLE(LLINT_C_LOOP) m_reentryDepth--; } @@ -1638,8 +1396,6 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); m_registerFile.shrink(oldEnd); - if (pushedScope) - scopeChain->pop(); return checkedReturn(result); } @@ -1672,16 +1428,14 @@ NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHook } #if ENABLE(CLASSIC_INTERPRETER) -NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC) +NEVER_INLINE JSScope* Interpreter::createNameScope(CallFrame* callFrame, const Instruction* vPC) { - int dst = vPC[1].u.operand; CodeBlock* codeBlock = callFrame->codeBlock(); - Identifier& property = codeBlock->identifier(vPC[2].u.operand); - JSValue value = callFrame->r(vPC[3].u.operand).jsValue(); - JSObject* scope = JSStaticScopeObject::create(callFrame, property, value, DontDelete); - callFrame->uncheckedR(dst) = JSValue(scope); - - return callFrame->scopeChain()->push(scope); + Identifier& property = codeBlock->identifier(vPC[1].u.operand); + JSValue value = callFrame->r(vPC[2].u.operand).jsValue(); + unsigned attributes = vPC[3].u.operand; + JSNameScope* scope = JSNameScope::create(callFrame, property, value, attributes); + return scope; } NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot) @@ -1906,6 +1660,8 @@ NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock*, Instruction* vPC) #endif // ENABLE(CLASSIC_INTERPRETER) +#if !ENABLE(LLINT_C_LOOP) + JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame) { // One-time initialization of our address tables. We have to put this code @@ -1991,9 +1747,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi UPDATE_BYTECODE_OFFSET(); #else #define DEFINE_OPCODE(opcode) opcode: UPDATE_BYTECODE_OFFSET(); -#endif +#endif // !ENABLE(OPCODE_STATS) NEXT_INSTRUCTION(); -#else +#else // !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart #if ENABLE(OPCODE_STATS) #define DEFINE_OPCODE(opcode) \ @@ -2006,7 +1762,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi while (1) { // iterator loop begins interpreterLoopStart:; switch (vPC->u.opcode) -#endif +#endif // !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) { DEFINE_OPCODE(op_new_object) { /* new_object dst(r) @@ -2064,7 +1820,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi exceptionValue = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor."); goto vm_throw; } - callFrame->uncheckedR(dst) = JSValue(RegExpObject::create(*globalData, callFrame->lexicalGlobalObject(), callFrame->scopeChain()->globalObject->regExpStructure(), regExp)); + callFrame->uncheckedR(dst) = JSValue(RegExpObject::create(*globalData, callFrame->lexicalGlobalObject(), callFrame->scope()->globalObject()->regExpStructure(), regExp)); vPC += OPCODE_LENGTH(op_new_regexp); NEXT_INSTRUCTION(); @@ -2825,8 +2581,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi scope chain, and writes the resulting value to register dst. If the property is not found, raises an exception. */ - if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue))) - goto vm_throw; + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; + Identifier& ident = callFrame->codeBlock()->identifier(property); + + JSValue result = JSScope::resolve(callFrame, ident); + CHECK_FOR_EXCEPTION(); + callFrame->uncheckedR(dst) = result; vPC += OPCODE_LENGTH(op_resolve); NEXT_INSTRUCTION(); @@ -2838,11 +2599,16 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi scope chain skipping the top 'skip' levels, and writes the resulting value to register dst. If the property is not found, raises an exception. */ - if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue))) - goto vm_throw; + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; + int skip = vPC[3].u.operand; + Identifier& ident = callFrame->codeBlock()->identifier(property); - vPC += OPCODE_LENGTH(op_resolve_skip); + JSValue result = JSScope::resolveSkip(callFrame, ident, skip); + CHECK_FOR_EXCEPTION(); + callFrame->uncheckedR(dst) = result; + vPC += OPCODE_LENGTH(op_resolve_skip); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_resolve_global) { @@ -2853,11 +2619,21 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi a fast lookup using the case offset, otherwise fall back to a full resolve and cache the new structure and offset */ - if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue))) - goto vm_throw; - + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; + Identifier& ident = callFrame->codeBlock()->identifier(property); + + JSValue result = JSScope::resolveGlobal( + callFrame, + ident, + callFrame->lexicalGlobalObject(), + &vPC[3].u.structure, + &vPC[4].u.operand + ); + CHECK_FOR_EXCEPTION(); + callFrame->uncheckedR(dst) = result; + vPC += OPCODE_LENGTH(op_resolve_global); - NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_resolve_global_dynamic) { @@ -2871,11 +2647,16 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi This walks through n levels of the scope chain to verify that none of those levels in the scope chain include dynamically added properties. */ - if (UNLIKELY(!resolveGlobalDynamic(callFrame, vPC, exceptionValue))) - goto vm_throw; - + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; + int skip = vPC[5].u.operand; + Identifier& ident = callFrame->codeBlock()->identifier(property); + + JSValue result = JSScope::resolveGlobalDynamic(callFrame, ident, skip, &vPC[3].u.structure, &vPC[4].u.operand); + CHECK_FOR_EXCEPTION(); + callFrame->uncheckedR(dst) = result; + vPC += OPCODE_LENGTH(op_resolve_global_dynamic); - NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_global_var) { @@ -2942,9 +2723,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int index = vPC[2].u.operand; int skip = vPC[3].u.operand; - ScopeChainNode* scopeChain = callFrame->scopeChain(); - ScopeChainIterator iter = scopeChain->begin(); - ScopeChainIterator end = scopeChain->end(); + JSScope* scope = callFrame->scope(); + ScopeChainIterator iter = scope->begin(); + ScopeChainIterator end = scope->end(); ASSERT_UNUSED(end, iter != end); ASSERT(codeBlock == callFrame->codeBlock()); bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); @@ -2957,9 +2738,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ++iter; ASSERT_UNUSED(end, iter != end); } - ASSERT((*iter)->isVariableObject()); - JSVariableObject* scope = jsCast<JSVariableObject*>(iter->get()); - callFrame->uncheckedR(dst) = scope->registerAt(index).get(); + ASSERT(iter->isVariableObject()); + JSVariableObject* variableObject = jsCast<JSVariableObject*>(iter.get()); + callFrame->uncheckedR(dst) = variableObject->registerAt(index).get(); ASSERT(callFrame->r(dst).jsValue()); vPC += OPCODE_LENGTH(op_get_scoped_var); NEXT_INSTRUCTION(); @@ -2972,9 +2753,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int skip = vPC[2].u.operand; int value = vPC[3].u.operand; - ScopeChainNode* scopeChain = callFrame->scopeChain(); - ScopeChainIterator iter = scopeChain->begin(); - ScopeChainIterator end = scopeChain->end(); + JSScope* scope = callFrame->scope(); + ScopeChainIterator iter = scope->begin(); + ScopeChainIterator end = scope->end(); ASSERT(codeBlock == callFrame->codeBlock()); ASSERT_UNUSED(end, iter != end); bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); @@ -2988,10 +2769,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT_UNUSED(end, iter != end); } - ASSERT((*iter)->isVariableObject()); - JSVariableObject* scope = jsCast<JSVariableObject*>(iter->get()); + ASSERT(iter->isVariableObject()); + JSVariableObject* variableObject = jsCast<JSVariableObject*>(iter.get()); ASSERT(callFrame->r(value).jsValue()); - scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue()); + variableObject->registerAt(index).set(*globalData, variableObject, callFrame->r(value).jsValue()); vPC += OPCODE_LENGTH(op_put_scoped_var); NEXT_INSTRUCTION(); } @@ -3004,8 +2785,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi outermost scope (which will be the global object) is stored in register dst. */ - resolveBase(callFrame, vPC); + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; + bool isStrict = vPC[3].u.operand; + Identifier& ident = callFrame->codeBlock()->identifier(property); + + JSValue result = JSScope::resolveBase(callFrame, ident, isStrict); CHECK_FOR_EXCEPTION(); + callFrame->uncheckedR(dst) = result; vPC += OPCODE_LENGTH(op_resolve_base); NEXT_INSTRUCTION(); @@ -3023,7 +2810,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSObject* baseObject = asObject(baseVal); PropertySlot slot(baseVal); if (!baseObject->getPropertySlot(callFrame, ident, slot)) { - exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring()); + exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.string()); goto vm_throw; } @@ -3042,8 +2829,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi resolve, or resolve_base followed by get_by_id, as it avoids duplicate hash lookups. */ - if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue))) - goto vm_throw; + int baseDst = vPC[1].u.operand; + int propDst = vPC[2].u.operand; + int property = vPC[3].u.operand; + Identifier& ident = codeBlock->identifier(property); + + JSValue prop = JSScope::resolveWithBase(callFrame, ident, &callFrame->uncheckedR(baseDst)); + CHECK_FOR_EXCEPTION(); + callFrame->uncheckedR(propDst) = prop; vPC += OPCODE_LENGTH(op_resolve_with_base); NEXT_INSTRUCTION(); @@ -3058,8 +2851,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi If the property is not found, raises an exception. */ - if (UNLIKELY(!resolveThisAndProperty(callFrame, vPC, exceptionValue))) - goto vm_throw; + int thisDst = vPC[1].u.operand; + int propDst = vPC[2].u.operand; + int property = vPC[3].u.operand; + Identifier& ident = codeBlock->identifier(property); + + JSValue prop = JSScope::resolveWithThis(callFrame, ident, &callFrame->uncheckedR(thisDst)); + CHECK_FOR_EXCEPTION(); + callFrame->uncheckedR(propDst) = prop; vPC += OPCODE_LENGTH(op_resolve_with_this); NEXT_INSTRUCTION(); @@ -3928,7 +3727,7 @@ skip_id_custom_self: JSValue arrayValue = callFrame->r(base).jsValue(); ASSERT(isJSArray(arrayValue)); - asArray(arrayValue)->putDirectIndex(callFrame, property, callFrame->r(value).jsValue(), false); + asArray(arrayValue)->putDirectIndex(callFrame, property, callFrame->r(value).jsValue()); vPC += OPCODE_LENGTH(op_put_by_index); NEXT_INSTRUCTION(); @@ -4460,7 +4259,7 @@ skip_id_custom_self: int shouldCheck = vPC[3].u.operand; ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue()); if (!shouldCheck || !callFrame->r(dst).jsValue()) - callFrame->uncheckedR(dst) = JSValue(codeBlock->functionDecl(func)->make(callFrame, callFrame->scopeChain())); + callFrame->uncheckedR(dst) = JSValue(JSFunction::create(callFrame, codeBlock->functionDecl(func), callFrame->scope())); vPC += OPCODE_LENGTH(op_new_func); NEXT_INSTRUCTION(); @@ -4478,19 +4277,7 @@ skip_id_custom_self: ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue()); FunctionExecutable* function = codeBlock->functionExpr(funcIndex); - JSFunction* func = function->make(callFrame, callFrame->scopeChain()); - - /* - The Identifier in a FunctionExpression can be referenced from inside - the FunctionExpression's FunctionBody to allow the function to call - itself recursively. However, unlike in a FunctionDeclaration, the - Identifier in a FunctionExpression cannot be referenced from and - does not affect the scope enclosing the FunctionExpression. - */ - if (!function->name().isNull()) { - JSStaticScopeObject* functionScopeObject = JSStaticScopeObject::create(callFrame, function->name(), func, ReadOnly | DontDelete); - func->setScope(*globalData, func->scope()->push(functionScopeObject)); - } + JSFunction* func = JSFunction::create(callFrame, function, callFrame->scope()); callFrame->uncheckedR(dst) = JSValue(func); @@ -4518,7 +4305,7 @@ skip_id_custom_self: if (isHostFunction(funcVal, globalFuncEval)) { CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); - newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_eval), callFrame->scopeChain(), callFrame, argCount, jsCast<JSFunction*>(funcVal)); + newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_eval), callFrame->scope(), callFrame, argCount, jsCast<JSFunction*>(funcVal)); JSValue result = eval(newCallFrame); if ((exceptionValue = globalData->exception)) @@ -4554,9 +4341,9 @@ skip_id_custom_self: CallType callType = getCallData(v, callData); if (callType == CallTypeJS) { - ScopeChainNode* callDataScopeChain = callData.js.scopeChain; + JSScope* callDataScope = callData.js.scope; - JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain); + JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScope); if (UNLIKELY(!!error)) { exceptionValue = error; goto vm_throw; @@ -4571,7 +4358,7 @@ skip_id_custom_self: goto vm_throw; } - callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call), callDataScopeChain, previousCallFrame, argCount, jsCast<JSFunction*>(v)); + callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call), callDataScope, previousCallFrame, argCount, jsCast<JSFunction*>(v)); codeBlock = newCodeBlock; ASSERT(codeBlock == callFrame->codeBlock()); *topCallFrameSlot = callFrame; @@ -4585,9 +4372,9 @@ skip_id_custom_self: } if (callType == CallTypeHost) { - ScopeChainNode* scopeChain = callFrame->scopeChain(); + JSScope* scope = callFrame->scope(); CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); - newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scopeChain, callFrame, argCount, asObject(v)); + newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scope, callFrame, argCount, asObject(v)); JSValue returnValue; { *topCallFrameSlot = newCallFrame; @@ -4634,9 +4421,9 @@ skip_id_custom_self: CallType callType = getCallData(v, callData); if (callType == CallTypeJS) { - ScopeChainNode* callDataScopeChain = callData.js.scopeChain; + JSScope* callDataScope = callData.js.scope; - JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain); + JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScope); if (UNLIKELY(!!error)) { exceptionValue = error; goto vm_throw; @@ -4649,7 +4436,7 @@ skip_id_custom_self: goto vm_throw; } - newCallFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call_varargs), callDataScopeChain, callFrame, argCount, jsCast<JSFunction*>(v)); + newCallFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call_varargs), callDataScope, callFrame, argCount, jsCast<JSFunction*>(v)); codeBlock = newCodeBlock; callFrame = newCallFrame; ASSERT(codeBlock == callFrame->codeBlock()); @@ -4664,8 +4451,8 @@ skip_id_custom_self: } if (callType == CallTypeHost) { - ScopeChainNode* scopeChain = callFrame->scopeChain(); - newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scopeChain, callFrame, argCount, asObject(v)); + JSScope* scope = callFrame->scope(); + newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scope, callFrame, argCount, asObject(v)); JSValue returnValue; { @@ -4832,7 +4619,7 @@ skip_id_custom_self: if (!callFrame->r(activationReg).jsValue()) { JSActivation* activation = JSActivation::create(*globalData, callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable())); callFrame->r(activationReg) = JSValue(activation); - callFrame->setScopeChain(callFrame->scopeChain()->push(activation)); + callFrame->setScope(activation); } vPC += OPCODE_LENGTH(op_create_activation); NEXT_INSTRUCTION(); @@ -4936,9 +4723,9 @@ skip_id_custom_self: ConstructType constructType = getConstructData(v, constructData); if (constructType == ConstructTypeJS) { - ScopeChainNode* callDataScopeChain = constructData.js.scopeChain; + JSScope* callDataScope = constructData.js.scope; - JSObject* error = constructData.js.functionExecutable->compileForConstruct(callFrame, callDataScopeChain); + JSObject* error = constructData.js.functionExecutable->compileForConstruct(callFrame, callDataScope); if (UNLIKELY(!!error)) { exceptionValue = error; goto vm_throw; @@ -4953,7 +4740,7 @@ skip_id_custom_self: goto vm_throw; } - callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_construct), callDataScopeChain, previousCallFrame, argCount, jsCast<JSFunction*>(v)); + callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_construct), callDataScope, previousCallFrame, argCount, jsCast<JSFunction*>(v)); codeBlock = newCodeBlock; *topCallFrameSlot = callFrame; vPC = newCodeBlock->instructions().begin(); @@ -4965,9 +4752,9 @@ skip_id_custom_self: } if (constructType == ConstructTypeHost) { - ScopeChainNode* scopeChain = callFrame->scopeChain(); + JSScope* scope = callFrame->scope(); CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); - newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scopeChain, callFrame, argCount, asObject(v)); + newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scope, callFrame, argCount, asObject(v)); JSValue returnValue; { @@ -5016,22 +4803,20 @@ skip_id_custom_self: NEXT_INSTRUCTION(); } - DEFINE_OPCODE(op_push_scope) { - /* push_scope scope(r) + DEFINE_OPCODE(op_push_with_scope) { + /* push_with_scope scope(r) Converts register scope to object, and pushes it onto the top - of the current scope chain. The contents of the register scope - are replaced by the result of toObject conversion of the scope. + of the scope chain. */ int scope = vPC[1].u.operand; JSValue v = callFrame->r(scope).jsValue(); JSObject* o = v.toObject(callFrame); CHECK_FOR_EXCEPTION(); - callFrame->uncheckedR(scope) = JSValue(o); - callFrame->setScopeChain(callFrame->scopeChain()->push(o)); + callFrame->setScope(JSWithScope::create(callFrame, o)); - vPC += OPCODE_LENGTH(op_push_scope); + vPC += OPCODE_LENGTH(op_push_with_scope); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_pop_scope) { @@ -5039,7 +4824,7 @@ skip_id_custom_self: Removes the top item from the current scope chain. */ - callFrame->setScopeChain(callFrame->scopeChain()->pop()); + callFrame->setScope(callFrame->scope()->next()); vPC += OPCODE_LENGTH(op_pop_scope); NEXT_INSTRUCTION(); @@ -5117,10 +4902,10 @@ skip_id_custom_self: int count = vPC[1].u.operand; int target = vPC[2].u.operand; - ScopeChainNode* tmp = callFrame->scopeChain(); + JSScope* tmp = callFrame->scope(); while (count--) - tmp = tmp->pop(); - callFrame->setScopeChain(tmp); + tmp = tmp->next(); + callFrame->setScope(tmp); vPC += target; NEXT_INSTRUCTION(); @@ -5129,16 +4914,15 @@ skip_id_custom_self: // Appease GCC goto *(&&skip_new_scope); #endif - DEFINE_OPCODE(op_push_new_scope) { - /* new_scope dst(r) property(id) value(r) + DEFINE_OPCODE(op_push_name_scope) { + /* new_scope property(id) value(r) attributes(unsigned) - Constructs a new StaticScopeObject with property set to value. That scope - object is then pushed onto the ScopeChain. The scope object is then stored - in dst for GC. + Constructs a name scope of the form { property<attributes>: value }, + and pushes it onto the scope chain. */ - callFrame->setScopeChain(createExceptionScope(callFrame, vPC)); + callFrame->setScope(createNameScope(callFrame, vPC)); - vPC += OPCODE_LENGTH(op_push_new_scope); + vPC += OPCODE_LENGTH(op_push_name_scope); NEXT_INSTRUCTION(); } #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) @@ -5189,7 +4973,7 @@ skip_id_custom_self: original constructor, using constant message as the message string. The result is thrown. */ - UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame)->value(callFrame); + String message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame)->value(callFrame); exceptionValue = JSValue(createReferenceError(callFrame, message)); goto vm_throw; } @@ -5319,6 +5103,9 @@ skip_id_custom_self: #endif // ENABLE(CLASSIC_INTERPRETER) } +#endif // !ENABLE(LLINT_C_LOOP) + + JSValue Interpreter::retrieveArgumentsFromVMCode(CallFrame* callFrame, JSFunction* function) const { CallFrame* functionCallFrame = findFunctionCallFrameFromVMCode(callFrame, function); @@ -5373,11 +5160,11 @@ JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction* return caller; } -void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const +void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, String& sourceURL, JSValue& function) const { function = JSValue(); lineNumber = -1; - sourceURL = UString(); + sourceURL = String(); CallFrame* callerFrame = callFrame->callerFrame(); if (callerFrame->hasHostCallFrameFlag()) |