diff options
| author | Ben Murdoch <benm@google.com> | 2010-10-22 13:02:20 +0100 |
|---|---|---|
| committer | Ben Murdoch <benm@google.com> | 2010-10-26 15:21:41 +0100 |
| commit | a94275402997c11dd2e778633dacf4b7e630a35d (patch) | |
| tree | e66f56c67e3b01f22c9c23cd932271ee9ac558ed /JavaScriptCore/interpreter | |
| parent | 09e26c78506587b3f5d930d7bc72a23287ffbec0 (diff) | |
| download | external_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.zip external_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.tar.gz external_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.tar.bz2 | |
Merge WebKit at r70209: Initial merge by Git
Change-Id: Id23a68efa36e9d1126bcce0b137872db00892c8e
Diffstat (limited to 'JavaScriptCore/interpreter')
| -rw-r--r-- | JavaScriptCore/interpreter/Interpreter.cpp | 229 |
1 files changed, 175 insertions, 54 deletions
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp index 5943ece..632571d 100644 --- a/JavaScriptCore/interpreter/Interpreter.cpp +++ b/JavaScriptCore/interpreter/Interpreter.cpp @@ -59,6 +59,7 @@ #include "RegExpPrototype.h" #include "Register.h" #include "SamplingTool.h" +#include "StrictEvalActivation.h" #include <limits.h> #include <stdio.h> #include <wtf/Threading.h> @@ -127,6 +128,12 @@ NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vP 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->r(codeBlock->activationRegister()).jsValue()) + ++iter; + } while (skip--) { ++iter; ASSERT(iter != end); @@ -140,6 +147,7 @@ NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vP exceptionValue = callFrame->globalData().exception; if (exceptionValue) return false; + ASSERT(result); callFrame->r(dst) = JSValue(result); return true; } @@ -203,6 +211,12 @@ NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instru 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->r(codeBlock->activationRegister()).jsValue()) + ++iter; + } while (skip--) { JSObject* o = *iter; if (o->hasCustomProperties()) { @@ -214,6 +228,7 @@ NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instru exceptionValue = callFrame->globalData().exception; if (exceptionValue) return false; + ASSERT(result); callFrame->r(dst) = JSValue(result); return true; } @@ -230,6 +245,7 @@ NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instru if (structure == globalObject->structure()) { callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset)); + ASSERT(callFrame->r(dst).jsValue()); return true; } @@ -243,6 +259,7 @@ NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instru globalObject->structure()->ref(); vPC[3] = globalObject->structure(); vPC[4] = slot.cachedOffset(); + ASSERT(result); callFrame->r(dst) = JSValue(result); return true; } @@ -250,6 +267,7 @@ NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instru exceptionValue = callFrame->globalData().exception; if (exceptionValue) return false; + ASSERT(result); callFrame->r(dst) = JSValue(result); return true; } @@ -262,7 +280,14 @@ NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vP { int dst = vPC[1].u.operand; int property = vPC[2].u.operand; - callFrame->r(dst) = JSValue(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain())); + bool isStrictPut = vPC[3].u.operand; + Identifier ident = callFrame->codeBlock()->identifier(property); + JSValue result = JSC::resolveBase(callFrame, ident, callFrame->scopeChain(), isStrictPut); + if (!result) { + callFrame->r(dst) = result; + ASSERT(callFrame->r(dst).jsValue()); + } else + callFrame->globalData().exception = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring()); } NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) @@ -371,14 +396,18 @@ NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* r UString programSource = asString(program)->value(callFrame); if (callFrame->hadException()) return JSValue(); - - LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON); - if (JSValue parsedObject = preparser.tryLiteralParse()) - return parsedObject; + + CodeBlock* codeBlock = callFrame->codeBlock(); + if (!codeBlock->isStrictMode()) { + // FIXME: We can use the preparser in strict mode, we just need additional logic + // to prevent duplicates. + LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON); + if (JSValue parsedObject = preparser.tryLiteralParse()) + return parsedObject; + } ScopeChainNode* scopeChain = callFrame->scopeChain(); - CodeBlock* codeBlock = callFrame->codeBlock(); - RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue); + RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue); JSValue result = jsUndefined(); if (eval) @@ -535,13 +564,19 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex // If this call frame created an activation or an 'arguments' object, tear it off. if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) { + if (!callFrame->r(oldCodeBlock->activationRegister()).jsValue()) { + oldCodeBlock->createActivation(callFrame); + scopeChain = callFrame->scopeChain(); + } while (!scopeChain->object->inherits(&JSActivation::info)) scopeChain = scopeChain->pop(); JSActivation* activation = asActivation(scopeChain->object); activation->copyRegisters(); - if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) - asArguments(arguments)->setActivation(activation); - } else if (oldCodeBlock->usesArguments()) { + if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) { + if (!oldCodeBlock->isStrictMode()) + asArguments(arguments)->setActivation(activation); + } + } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) { if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) asArguments(arguments)->copyRegisters(); } @@ -641,12 +676,23 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV } // Shrink the JS stack, in case stack overflow made it huge. - m_registerFile.shrink(callFrame->registers() + callFrame->codeBlock()->m_numCalleeRegisters); + Register* highWaterMark = callFrame->registers() + callFrame->codeBlock()->m_numCalleeRegisters; + for (CallFrame* callerFrame = callFrame->callerFrame()->removeHostCallFrameFlag(); callerFrame; callerFrame = callerFrame->callerFrame()->removeHostCallFrameFlag()) { + CodeBlock* codeBlock = callerFrame->codeBlock(); + if (!codeBlock) + continue; + Register* callerHighWaterMark = callerFrame->registers() + codeBlock->m_numCalleeRegisters; + highWaterMark = max(highWaterMark, callerHighWaterMark); + } + m_registerFile.shrink(highWaterMark); // 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; + int scopeDelta = 0; + if (!codeBlock->needsFullScopeChain() || codeBlock->codeType() != FunctionCode + || callFrame->r(codeBlock->activationRegister()).jsValue()) + scopeDelta = depth(codeBlock, sc) - handler->scopeDepth; ASSERT(scopeDelta >= 0); while (scopeDelta--) scopeChain = scopeChain->pop(); @@ -1036,7 +1082,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec } EvalCodeBlock* codeBlock = &eval->generatedBytecode(); - JSVariableObject* variableObject; + JSObject* variableObject; for (ScopeChainNode* node = scopeChain; ; node = node->next) { ASSERT(node); if (node->object->isVariableObject()) { @@ -1047,7 +1093,13 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec unsigned numVariables = codeBlock->numVariables(); int numFunctions = codeBlock->numberOfFunctionDecls(); + bool pushedScope = false; if (numVariables || numFunctions) { + if (codeBlock->isStrictMode()) { + variableObject = new (callFrame) StrictEvalActivation(callFrame); + scopeChain = scopeChain->push(variableObject); + pushedScope = true; + } // Scope for BatchedTransitionOptimizer BatchedTransitionOptimizer optimizer(variableObject); @@ -1070,6 +1122,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters; if (!m_registerFile.grow(newEnd)) { *exception = createStackOverflowError(callFrame); + if (pushedScope) + scopeChain->pop(); return jsNull(); } @@ -1112,6 +1166,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); m_registerFile.shrink(oldEnd); + if (pushedScope) + scopeChain->pop(); return result; } @@ -1518,6 +1574,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi */ int dst = vPC[1].u.operand; int src = vPC[2].u.operand; + callFrame->r(dst) = callFrame->r(src); vPC += OPCODE_LENGTH(op_mov); @@ -2327,6 +2384,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); ASSERT(iter != end); + ASSERT(codeBlock == callFrame->codeBlock()); + bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); + ASSERT(skip || !checkTopLevel); + if (checkTopLevel && skip--) { + if (callFrame->r(codeBlock->activationRegister()).jsValue()) + ++iter; + } while (skip--) { ++iter; ASSERT(iter != end); @@ -2334,6 +2398,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT((*iter)->isVariableObject()); JSVariableObject* scope = static_cast<JSVariableObject*>(*iter); callFrame->r(dst) = scope->registerAt(index); + ASSERT(callFrame->r(dst).jsValue()); vPC += OPCODE_LENGTH(op_get_scoped_var); NEXT_INSTRUCTION(); } @@ -2348,7 +2413,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); + ASSERT(codeBlock == callFrame->codeBlock()); ASSERT(iter != end); + bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); + ASSERT(skip || !checkTopLevel); + if (checkTopLevel && skip--) { + if (callFrame->r(codeBlock->activationRegister()).jsValue()) + ++iter; + } while (skip--) { ++iter; ASSERT(iter != end); @@ -2356,6 +2428,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT((*iter)->isVariableObject()); JSVariableObject* scope = static_cast<JSVariableObject*>(*iter); + ASSERT(callFrame->r(value).jsValue()); scope->registerAt(index) = JSValue(callFrame->r(value).jsValue()); vPC += OPCODE_LENGTH(op_put_scoped_var); NEXT_INSTRUCTION(); @@ -2373,6 +2446,24 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi vPC += OPCODE_LENGTH(op_resolve_base); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_ensure_property_exists) { + /* ensure_property_exists base(r) property(id) + + Throws an exception if property does not exist on base + */ + int base = vPC[1].u.operand; + int property = vPC[2].u.operand; + Identifier& ident = codeBlock->identifier(property); + + JSValue baseVal = callFrame->r(base).jsValue(); + JSObject* baseObject = asObject(baseVal); + PropertySlot slot(baseVal); + if (!baseObject->getPropertySlot(callFrame, ident, slot)) { + exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring()); + goto vm_throw; + } + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_resolve_with_base) { /* resolve_with_base baseDst(r) propDst(r) property(id) @@ -2922,7 +3013,7 @@ skip_id_custom_self: JSValue baseValue = callFrame->r(base).jsValue(); Identifier& ident = codeBlock->identifier(property); - PutPropertySlot slot; + PutPropertySlot slot(codeBlock->isStrictMode()); if (direct) { baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot); ASSERT(slot.base() == baseValue); @@ -3038,7 +3129,7 @@ skip_id_custom_self: JSValue baseValue = callFrame->r(base).jsValue(); Identifier& ident = codeBlock->identifier(property); - PutPropertySlot slot; + PutPropertySlot slot(codeBlock->isStrictMode()); if (direct) { baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot); ASSERT(slot.base() == baseValue); @@ -3063,9 +3154,13 @@ skip_id_custom_self: JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); Identifier& ident = codeBlock->identifier(property); - JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident)); + bool result = baseObj->deleteProperty(callFrame, ident); + if (!result && codeBlock->isStrictMode()) { + exceptionValue = createTypeError(callFrame, "Unable to delete property."); + goto vm_throw; + } CHECK_FOR_EXCEPTION(); - callFrame->r(dst) = result; + callFrame->r(dst) = jsBoolean(result); vPC += OPCODE_LENGTH(op_del_by_id); NEXT_INSTRUCTION(); } @@ -3131,8 +3226,8 @@ skip_id_custom_self: } if (!arguments) { Arguments* arguments = new (globalData) Arguments(callFrame); - callFrame->r(dst) = JSValue(arguments); - callFrame->r(unmodifiedArgumentsRegister(dst)) = JSValue(arguments); + callFrame->r(argumentsRegister) = JSValue(arguments); + callFrame->r(unmodifiedArgumentsRegister(argumentsRegister)) = JSValue(arguments); } // fallthrough } @@ -3218,7 +3313,7 @@ skip_id_custom_self: } else { Identifier property(callFrame, subscript.toString(callFrame)); if (!globalData->exception) { // Don't put to an object if toString threw an exception. - PutPropertySlot slot; + PutPropertySlot slot(codeBlock->isStrictMode()); baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot); } } @@ -3242,19 +3337,22 @@ skip_id_custom_self: JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw JSValue subscript = callFrame->r(property).jsValue(); - JSValue result; + bool result; uint32_t i; if (subscript.getUInt32(i)) - result = jsBoolean(baseObj->deleteProperty(callFrame, i)); + result = baseObj->deleteProperty(callFrame, i); else { CHECK_FOR_EXCEPTION(); Identifier property(callFrame, subscript.toString(callFrame)); CHECK_FOR_EXCEPTION(); - result = jsBoolean(baseObj->deleteProperty(callFrame, property)); + result = baseObj->deleteProperty(callFrame, property); + } + if (!result && codeBlock->isStrictMode()) { + exceptionValue = createTypeError(callFrame, "Unable to delete property."); + goto vm_throw; } - CHECK_FOR_EXCEPTION(); - callFrame->r(dst) = result; + callFrame->r(dst) = jsBoolean(result); vPC += OPCODE_LENGTH(op_del_by_val); NEXT_INSTRUCTION(); } @@ -3658,7 +3756,7 @@ skip_id_custom_self: int dst = vPC[1].u.operand; int func = vPC[2].u.operand; int shouldCheck = vPC[3].u.operand; - + ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue()); if (!shouldCheck || !callFrame->r(dst).jsValue()) callFrame->r(dst) = JSValue(codeBlock->functionDecl(func)->make(callFrame, callFrame->scopeChain())); @@ -3675,7 +3773,8 @@ skip_id_custom_self: */ int dst = vPC[1].u.operand; int funcIndex = vPC[2].u.operand; - + + ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue()); FunctionExecutable* function = codeBlock->functionExpr(funcIndex); JSFunction* func = function->make(callFrame, callFrame->scopeChain()); @@ -3711,7 +3810,8 @@ skip_id_custom_self: int func = vPC[1].u.operand; int argCount = vPC[2].u.operand; int registerOffset = vPC[3].u.operand; - + + ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue()); JSValue funcVal = callFrame->r(func).jsValue(); Register* newCallFrame = callFrame->registers() + registerOffset; @@ -3980,15 +4080,22 @@ skip_id_custom_self: This opcode appears before op_ret in functions that require full scope chains. */ - int src1 = vPC[1].u.operand; - int src2 = vPC[2].u.operand; + int activation = vPC[1].u.operand; + int arguments = vPC[2].u.operand; ASSERT(codeBlock->needsFullScopeChain()); - - JSActivation* activation = asActivation(callFrame->r(src1).jsValue()); - activation->copyRegisters(); - - if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(src2)).jsValue()) - asArguments(arguments)->setActivation(activation); + JSValue activationValue = callFrame->r(activation).jsValue(); + if (activationValue) { + asActivation(activationValue)->copyRegisters(); + + if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) + asArguments(argumentsValue)->setActivation(asActivation(activationValue)); + } else if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) + asArguments(argumentsValue)->copyRegisters(); + + if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) { + if (!codeBlock->isStrictMode()) + asArguments(argumentsValue)->setActivation(asActivation(activationValue)); + } vPC += OPCODE_LENGTH(op_tear_off_activation); NEXT_INSTRUCTION(); @@ -4026,7 +4133,7 @@ skip_id_custom_self: int result = vPC[1].u.operand; - if (callFrame->codeBlock()->needsFullScopeChain()) + if (callFrame->codeBlock()->needsFullScopeChain() && callFrame->r(codeBlock->activationRegister()).jsValue()) callFrame->scopeChain()->deref(); JSValue returnValue = callFrame->r(result).jsValue(); @@ -4067,7 +4174,7 @@ skip_id_custom_self: int result = vPC[1].u.operand; - if (codeBlock->needsFullScopeChain()) + if (codeBlock->needsFullScopeChain() && callFrame->r(codeBlock->activationRegister()).jsValue()) callFrame->scopeChain()->deref(); JSValue returnValue = callFrame->r(result).jsValue(); @@ -4103,25 +4210,20 @@ skip_id_custom_self: vPC += OPCODE_LENGTH(op_enter); NEXT_INSTRUCTION(); } - DEFINE_OPCODE(op_enter_with_activation) { - /* enter_with_activation dst(r) - - Initializes local variables to undefined, creates an activation object, - places it in dst, and pushes it onto the scope chain. + DEFINE_OPCODE(op_create_activation) { + /* create_activation dst(r) - This opcode appears only at the beginning of a code block. + If the activation object for this callframe has not yet been created, + this creates it and writes it back to dst. */ - size_t i = 0; - for (size_t count = codeBlock->m_numVars; i < count; ++i) - callFrame->r(i) = jsUndefined(); - - int dst = vPC[1].u.operand; - JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable())); - callFrame->r(dst) = JSValue(activation); - callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation)); - - vPC += OPCODE_LENGTH(op_enter_with_activation); + int activationReg = vPC[1].u.operand; + if (!callFrame->r(activationReg).jsValue()) { + JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable())); + callFrame->r(activationReg) = JSValue(activation); + callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation)); + } + vPC += OPCODE_LENGTH(op_create_activation); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_callee) { @@ -4184,6 +4286,25 @@ skip_id_custom_self: vPC += OPCODE_LENGTH(op_convert_this); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_convert_this_strict) { + /* convert_this_strict this(r) + + Takes the value in the 'this' register, and converts it to + its "this" form if (and only if) "this" is an object with a + custom this conversion + + This opcode should only be used at the beginning of a code + block. + */ + + int thisRegister = vPC[1].u.operand; + JSValue thisVal = callFrame->r(thisRegister).jsValue(); + if (thisVal.isObject() && thisVal.needsThisConversion()) + callFrame->r(thisRegister) = JSValue(thisVal.toStrictThisObject(callFrame)); + + vPC += OPCODE_LENGTH(op_convert_this_strict); + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_init_lazy_reg) { /* init_lazy_reg dst(r) |
