summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/interpreter/Interpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/interpreter/Interpreter.cpp')
-rw-r--r--JavaScriptCore/interpreter/Interpreter.cpp2238
1 files changed, 1572 insertions, 666 deletions
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index 2498d69..febdb71 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
*
* Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,10 @@
#include "Collector.h"
#include "Debugger.h"
#include "DebuggerCallFrame.h"
+#include "ErrorInstance.h"
#include "EvalCodeCache.h"
#include "ExceptionHelpers.h"
+#include "GetterSetter.h"
#include "GlobalEvalFunction.h"
#include "JSActivation.h"
#include "JSArray.h"
@@ -58,6 +60,8 @@
#include "RegExpPrototype.h"
#include "Register.h"
#include "SamplingTool.h"
+#include "StrictEvalActivation.h"
+#include "UStringConcatenate.h"
#include <limits.h>
#include <stdio.h>
#include <wtf/Threading.h>
@@ -66,20 +70,12 @@
#include "JIT.h"
#endif
+#define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(COMPUTED_GOTO_INTERPRETER) && !defined(__llvm__))
+
using namespace std;
namespace JSC {
-static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc)
-{
-#if ENABLE(JIT)
- return codeBlock->getBytecodeIndex(callFrame, ReturnAddressPtr(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)
{
@@ -88,7 +84,12 @@ static int depth(CodeBlock* codeBlock, ScopeChain& sc)
return sc.localDepth();
}
-#if USE(INTERPRETER)
+#if ENABLE(INTERPRETER)
+static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* strings, unsigned count)
+{
+ return jsString(exec, strings, count);
+}
+
NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
{
int dst = vPC[1].u.operand;
@@ -109,11 +110,11 @@ NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, J
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(dst) = JSValue(result);
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
} while (++iter != end);
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
@@ -123,12 +124,18 @@ NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vP
int dst = vPC[1].u.operand;
int property = vPC[2].u.operand;
- int skip = vPC[3].u.operand + codeBlock->needsFullScopeChain();
+ 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);
@@ -142,51 +149,132 @@ NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vP
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(dst) = JSValue(result);
+ ASSERT(result);
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
} while (++iter != end);
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
{
int dst = vPC[1].u.operand;
- JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ JSGlobalObject* globalObject = codeBlock->globalObject();
ASSERT(globalObject->isGlobalObject());
- int property = vPC[3].u.operand;
- Structure* structure = vPC[4].u.structure;
- int offset = vPC[5].u.operand;
+ int property = vPC[2].u.operand;
+ Structure* structure = vPC[3].u.structure;
+ int offset = vPC[4].u.operand;
if (structure == globalObject->structure()) {
- callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
return true;
}
- CodeBlock* codeBlock = callFrame->codeBlock();
Identifier& ident = codeBlock->identifier(property);
PropertySlot slot(globalObject);
if (globalObject->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
- if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
- if (vPC[4].u.structure)
- vPC[4].u.structure->deref();
+ if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
+ if (vPC[3].u.structure)
+ vPC[3].u.structure->deref();
globalObject->structure()->ref();
- vPC[4] = globalObject->structure();
- vPC[5] = slot.cachedOffset();
- callFrame->r(dst) = JSValue(result);
+ vPC[3] = globalObject->structure();
+ vPC[4] = slot.cachedOffset();
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(dst) = JSValue(result);
+ 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;
+ 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;
+ 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;
+ ++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;
}
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ 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) {
+ if (vPC[3].u.structure)
+ vPC[3].u.structure->deref();
+ globalObject->structure()->ref();
+ vPC[3] = 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;
}
@@ -194,7 +282,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->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)
@@ -222,18 +317,18 @@ NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Inst
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(propDst) = JSValue(result);
- callFrame->r(baseDst) = JSValue(base);
+ callFrame->uncheckedR(propDst) = JSValue(result);
+ callFrame->uncheckedR(baseDst) = JSValue(base);
return true;
}
++iter;
} while (iter != end);
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
-#endif // USE(INTERPRETER)
+#endif // ENABLE(INTERPRETER)
ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
{
@@ -272,25 +367,25 @@ ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newC
return CallFrame::create(r);
}
-#if USE(INTERPRETER)
-static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
+#if ENABLE(INTERPRETER)
+static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
{
if (value.isObject())
return false;
- exceptionData = createInvalidParamError(callFrame, "in" , value, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionData = createInvalidParamError(callFrame, "in" , value);
return true;
}
-static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
+static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
{
if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
return false;
- exceptionData = createInvalidParamError(callFrame, "instanceof" , value, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionData = createInvalidParamError(callFrame, "instanceof" , value);
return true;
}
#endif
-NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue& exceptionValue)
+NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset)
{
if (argc < 2)
return jsUndefined();
@@ -301,32 +396,39 @@ NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* r
return program;
UString programSource = asString(program)->value(callFrame);
-
- LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
- if (JSValue parsedObject = preparser.tryLiteralParse())
- return parsedObject;
+ if (callFrame->hadException())
+ return JSValue();
+
+ 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);
+ JSValue exceptionValue;
+ RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue);
- JSValue result = jsUndefined();
- if (eval)
- result = callFrame->globalData().interpreter->execute(eval.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue);
+ ASSERT(!eval == exceptionValue);
+ if (UNLIKELY(!eval))
+ return throwError(callFrame, exceptionValue);
- return result;
+ return callFrame->globalData().interpreter->execute(eval.get(), callFrame, callFrame->uncheckedR(codeBlock->thisRegister()).jsValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain);
}
Interpreter::Interpreter()
: m_sampleEntryDepth(0)
, m_reentryDepth(0)
{
-#if HAVE(COMPUTED_GOTO)
- privateExecute(InitializeAndReturn, 0, 0, 0);
+#if ENABLE(COMPUTED_GOTO_INTERPRETER)
+ privateExecute(InitializeAndReturn, 0, 0);
for (int i = 0; i < numOpcodeIDs; ++i)
m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
-#endif // HAVE(COMPUTED_GOTO)
+#endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
#if ENABLE(OPCODE_SAMPLING)
enableSampler();
@@ -349,7 +451,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
printf("-----------------------------------------------------------------------------\n");
CodeBlock* codeBlock = callFrame->codeBlock();
- RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData()->interpreter->registerFile();
+ RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData().interpreter->registerFile();
const Register* it;
const Register* end;
JSValue v;
@@ -393,10 +495,8 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
- printf("[ReturnValueRegister] | %10p | %d \n", it, (*it).i()); ++it;
printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it;
- printf("[OptionalCalleeArguments] | %10p | %p \n", it, (*it).arguments()); ++it;
printf("-----------------------------------------------------------------------------\n");
int registerCount = 0;
@@ -436,7 +536,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
bool Interpreter::isOpcode(Opcode opcode)
{
-#if HAVE(COMPUTED_GOTO)
+#if ENABLE(COMPUTED_GOTO_INTERPRETER)
return opcode != HashTraits<Opcode>::emptyValue()
&& !HashTraits<Opcode>::isDeletedValue(opcode)
&& m_opcodeIDTable.contains(opcode);
@@ -458,114 +558,161 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex
debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
}
- if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
- if (callFrame->callee())
- profiler->didExecute(callFrame, callFrame->callee());
- else
- profiler->didExecute(callFrame, codeBlock->ownerExecutable()->sourceURL(), codeBlock->ownerExecutable()->lineNo());
- }
-
// If this call frame created an activation or an 'arguments' object, tear it off.
if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
+ if (!callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue()) {
+ oldCodeBlock->createActivation(callFrame);
+ scopeChain = callFrame->scopeChain();
+ }
while (!scopeChain->object->inherits(&JSActivation::info))
scopeChain = scopeChain->pop();
- static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments());
- } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
- if (!arguments->isTornOff())
- arguments->copyRegisters();
+ JSActivation* activation = asActivation(scopeChain->object);
+ activation->copyRegisters();
+ if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) {
+ if (!oldCodeBlock->isStrictMode())
+ asArguments(arguments)->setActivation(activation);
+ }
+ } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) {
+ if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
+ asArguments(arguments)->copyRegisters();
}
if (oldCodeBlock->needsFullScopeChain())
scopeChain->deref();
- void* returnPC = callFrame->returnPC();
- callFrame = callFrame->callerFrame();
- if (callFrame->hasHostCallFrameFlag())
+ CallFrame* callerFrame = callFrame->callerFrame();
+ if (callerFrame->hasHostCallFrameFlag())
return false;
- codeBlock = callFrame->codeBlock();
- bytecodeOffset = bytecodeOffsetForPC(callFrame, codeBlock, returnPC);
+ codeBlock = callerFrame->codeBlock();
+#if ENABLE(JIT) && ENABLE(INTERPRETER)
+ if (callerFrame->globalData().canUseJIT())
+ bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
+ else
+ bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC());
+#elif ENABLE(JIT)
+ bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
+#else
+ bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC());
+#endif
+
+ callFrame = callerFrame;
return true;
}
-NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow)
+static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
{
- // Set up the exception object
+ exception->clearAppendSourceToMessage();
+
+ if (!callFrame->codeBlock()->hasExpressionInfo())
+ return;
+
+ int startOffset = 0;
+ int endOffset = 0;
+ int divotPoint = 0;
CodeBlock* codeBlock = callFrame->codeBlock();
+ codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset);
+
+ int expressionStart = divotPoint - startOffset;
+ int expressionStop = divotPoint + endOffset;
+
+ if (!expressionStop || expressionStart > codeBlock->source()->length())
+ return;
+
+ JSGlobalData* globalData = &callFrame->globalData();
+ JSValue jsMessage = exception->getDirect(globalData->propertyNames->message);
+ if (!jsMessage || !jsMessage.isString())
+ return;
+
+ UString message = asString(jsMessage)->value(callFrame);
+
+ if (expressionStart < expressionStop)
+ message = makeUString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')");
+ else {
+ // No range information, so give a few characters of context
+ const UChar* data = codeBlock->source()->data();
+ int dataLength = codeBlock->source()->length();
+ int start = expressionStart;
+ int stop = expressionStart;
+ // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
+ // then strip whitespace.
+ while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
+ start--;
+ while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
+ start++;
+ while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
+ stop++;
+ while (stop > expressionStart && isStrWhiteSpace(data[stop]))
+ stop--;
+ message = makeUString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')");
+ }
+
+ exception->putDirect(globalData->propertyNames->message, jsString(globalData, message));
+}
+
+NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
+{
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ bool isInterrupt = false;
+
+ // Set up the exception object
if (exceptionValue.isObject()) {
JSObject* exception = asObject(exceptionValue);
- if (exception->isNotAnObjectErrorStub()) {
- exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock);
- exceptionValue = exception;
- } else {
- if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) {
- if (explicitThrow) {
- int startOffset = 0;
- int endOffset = 0;
- int divotPoint = 0;
- int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset);
- exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete);
-
- // We only hit this path for error messages and throw statements, which don't have a specific failure position
- // So we just give the full range of the error/throw statement.
- exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete);
- exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete);
- } else
- exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete);
- exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerExecutable()->sourceID()), ReadOnly | DontDelete);
- exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerExecutable()->sourceURL()), ReadOnly | DontDelete);
- }
-
- if (exception->isWatchdogException()) {
- while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
- // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
- }
- return 0;
- }
+
+ if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage())
+ appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset);
+
+ // Using hasExpressionInfo to imply we are interested in rich exception info.
+ if (codeBlock->hasExpressionInfo() && !hasErrorInfo(callFrame, exception)) {
+ ASSERT(codeBlock->hasLineInfo());
+
+ // FIXME: should only really be adding these properties to VM generated exceptions,
+ // but the inspector currently requires these for all thrown objects.
+ addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
}
+
+ ComplType exceptionType = exception->exceptionType();
+ isInterrupt = exceptionType == Interrupted || exceptionType == Terminated;
}
if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
- debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset), hasHandler);
- }
-
- // If we throw in the middle of a call instruction, we need to notify
- // the profiler manually that the call instruction has returned, since
- // we'll never reach the relevant op_profile_did_call.
- if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
-#if !ENABLE(JIT)
- if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode))
- profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 2].u.operand).jsValue());
- else if (codeBlock->instructions().size() > (bytecodeOffset + 8) && codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct))
- profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 10].u.operand).jsValue());
-#else
- int functionRegisterIndex;
- if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex))
- profiler->didExecute(callFrame, callFrame->r(functionRegisterIndex).jsValue());
-#endif
+ debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), hasHandler);
}
// Calculate an exception handler vPC, unwinding call frames as necessary.
-
HandlerInfo* handler = 0;
- while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
- if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock))
+ while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
+ if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
+ if (Profiler* profiler = *Profiler::enabledProfilerReference())
+ profiler->exceptionUnwind(callFrame);
return 0;
+ }
}
- // Now unwind the scope chain within the exception handler's call frame.
+ if (Profiler* profiler = *Profiler::enabledProfilerReference())
+ profiler->exceptionUnwind(callFrame);
+
+ // Shrink the JS stack, in case stack overflow made it huge.
+ Register* highWaterMark = 0;
+ for (CallFrame* callerFrame = callFrame; 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->uncheckedR(codeBlock->activationRegister()).jsValue())
+ scopeDelta = depth(codeBlock, sc) - handler->scopeDepth;
ASSERT(scopeDelta >= 0);
while (scopeDelta--)
scopeChain = scopeChain->pop();
@@ -574,53 +721,65 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV
return handler;
}
-JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception)
+static inline JSValue checkedReturn(JSValue returnValue)
+{
+ ASSERT(returnValue);
+ return returnValue;
+}
+
+static inline JSObject* checkedReturn(JSObject* returnValue)
+{
+ ASSERT(returnValue);
+ return returnValue;
+}
+
+JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
{
ASSERT(!scopeChain->globalData->exception);
- if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
- if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
- }
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ return checkedReturn(throwStackOverflowError(callFrame));
- CodeBlock* codeBlock = &program->bytecode(callFrame, scopeChain);
+ JSObject* error = program->compile(callFrame, scopeChain);
+ if (error)
+ return checkedReturn(throwError(callFrame, error));
+ CodeBlock* codeBlock = &program->generatedBytecode();
Register* oldEnd = m_registerFile.end();
Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
- if (!m_registerFile.grow(newEnd)) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
-
- DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
+ if (!m_registerFile.grow(newEnd))
+ return checkedReturn(throwStackOverflowError(callFrame));
JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
globalObject->copyGlobalsTo(m_registerFile);
CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
- newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
- newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0);
+ ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
+ newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), codeBlock->m_numParameters, 0);
+ newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
if (codeBlock->needsFullScopeChain())
scopeChain->ref();
+ DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
+
Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
- (*profiler)->willExecute(newCallFrame, program->sourceURL(), program->lineNo());
+ (*profiler)->willExecute(callFrame, program->sourceURL(), program->lineNo());
JSValue result;
{
SamplingTool::CallRecord callRecord(m_sampler.get());
- m_reentryDepth++;
+ m_reentryDepth++;
#if ENABLE(JIT)
- result = program->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
-#else
- result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
+ if (callFrame->globalData().canUseJIT())
+ result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
+ else
#endif
+ result = privateExecute(Normal, &m_registerFile, newCallFrame);
+
m_reentryDepth--;
}
@@ -632,46 +791,81 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, S
m_registerFile.shrink(oldEnd);
- return result;
+ return checkedReturn(result);
}
-JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception)
+JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
{
- ASSERT(!scopeChain->globalData->exception);
+ ASSERT(!callFrame->hadException());
- if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
- if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
- }
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ return checkedReturn(throwStackOverflowError(callFrame));
Register* oldEnd = m_registerFile.end();
- int argc = 1 + args.size(); // implicit "this" parameter
+ int argCount = 1 + args.size(); // implicit "this" parameter
+ size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
- if (!m_registerFile.grow(oldEnd + argc)) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
-
- DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
+ if (!m_registerFile.grow(oldEnd + registerOffset))
+ return checkedReturn(throwStackOverflowError(callFrame));
CallFrame* newCallFrame = CallFrame::create(oldEnd);
size_t dst = 0;
- newCallFrame->r(0) = JSValue(thisObj);
+ newCallFrame->uncheckedR(0) = thisValue;
ArgList::const_iterator end = args.end();
for (ArgList::const_iterator it = args.begin(); it != end; ++it)
- newCallFrame->r(++dst) = *it;
+ newCallFrame->uncheckedR(++dst) = *it;
+
+ if (callType == CallTypeJS) {
+ ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
+
+ JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
+ if (UNLIKELY(!!compileError)) {
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(throwError(callFrame, compileError));
+ }
+
+ CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
+ newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
+ if (UNLIKELY(!newCallFrame)) {
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(throwStackOverflowError(callFrame));
+ }
+
+ newCallFrame->init(newCodeBlock, 0, callDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
+
+ DynamicGlobalObjectScope globalObjectScope(newCallFrame, callDataScopeChain->globalObject);
+
+ Profiler** profiler = Profiler::enabledProfilerReference();
+ if (*profiler)
+ (*profiler)->willExecute(callFrame, function);
+
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get());
+
+ m_reentryDepth++;
+#if ENABLE(JIT)
+ if (callFrame->globalData().canUseJIT())
+ result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScopeChain->globalData);
+ else
+#endif
+ result = privateExecute(Normal, &m_registerFile, newCallFrame);
+ m_reentryDepth--;
+ }
+
+ if (*profiler)
+ (*profiler)->didExecute(callFrame, function);
- CodeBlock* codeBlock = &functionExecutable->bytecode(callFrame, scopeChain);
- newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
- if (UNLIKELY(!newCallFrame)) {
- *exception = createStackOverflowError(callFrame);
m_registerFile.shrink(oldEnd);
- return jsNull();
+ return checkedReturn(result);
}
- // a 0 codeBlock indicates a built-in caller
- newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
+
+ ASSERT(callType == CallTypeHost);
+ ScopeChainNode* scopeChain = callFrame->scopeChain();
+ newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
+ newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
+
+ DynamicGlobalObjectScope globalObjectScope(newCallFrame, scopeChain->globalObject);
Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
@@ -679,31 +873,119 @@ JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame*
JSValue result;
{
- SamplingTool::CallRecord callRecord(m_sampler.get());
+ SamplingTool::HostCallRecord callRecord(m_sampler.get());
+ result = JSValue::decode(callData.native.function(newCallFrame));
+ }
- m_reentryDepth++;
+ if (*profiler)
+ (*profiler)->didExecute(callFrame, function);
+
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(result);
+}
+
+JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+{
+ ASSERT(!callFrame->hadException());
+
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ Register* oldEnd = m_registerFile.end();
+ int argCount = 1 + args.size(); // implicit "this" parameter
+ size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
+
+ if (!m_registerFile.grow(oldEnd + registerOffset))
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ CallFrame* newCallFrame = CallFrame::create(oldEnd);
+ size_t dst = 0;
+ ArgList::const_iterator end = args.end();
+ for (ArgList::const_iterator it = args.begin(); it != end; ++it)
+ newCallFrame->uncheckedR(++dst) = *it;
+
+ if (constructType == ConstructTypeJS) {
+ ScopeChainNode* constructDataScopeChain = constructData.js.scopeChain;
+
+ JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScopeChain);
+ if (UNLIKELY(!!compileError)) {
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(throwError(callFrame, compileError));
+ }
+
+ CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
+ newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
+ if (UNLIKELY(!newCallFrame)) {
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(throwStackOverflowError(callFrame));
+ }
+
+ newCallFrame->init(newCodeBlock, 0, constructDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
+
+ DynamicGlobalObjectScope globalObjectScope(newCallFrame, constructDataScopeChain->globalObject);
+
+ Profiler** profiler = Profiler::enabledProfilerReference();
+ if (*profiler)
+ (*profiler)->willExecute(callFrame, constructor);
+
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get());
+
+ m_reentryDepth++;
#if ENABLE(JIT)
- result = functionExecutable->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
-#else
- result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
+ if (callFrame->globalData().canUseJIT())
+ result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScopeChain->globalData);
+ else
#endif
- m_reentryDepth--;
+ result = privateExecute(Normal, &m_registerFile, newCallFrame);
+ m_reentryDepth--;
+ }
+
+ if (*profiler)
+ (*profiler)->didExecute(callFrame, constructor);
+
+ m_registerFile.shrink(oldEnd);
+ if (callFrame->hadException())
+ return 0;
+ ASSERT(result.isObject());
+ return checkedReturn(asObject(result));
}
+ ASSERT(constructType == ConstructTypeHost);
+ ScopeChainNode* scopeChain = callFrame->scopeChain();
+ newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
+ newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
+
+ DynamicGlobalObjectScope globalObjectScope(newCallFrame, scopeChain->globalObject);
+
+ Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
- (*profiler)->didExecute(callFrame, function);
+ (*profiler)->willExecute(callFrame, constructor);
+
+ JSValue result;
+ {
+ SamplingTool::HostCallRecord callRecord(m_sampler.get());
+ result = JSValue::decode(constructData.native.function(newCallFrame));
+ }
+
+ if (*profiler)
+ (*profiler)->didExecute(callFrame, constructor);
m_registerFile.shrink(oldEnd);
- return result;
+ if (callFrame->hadException())
+ return 0;
+ ASSERT(result.isObject());
+ return checkedReturn(asObject(result));
}
-CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception)
+CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain)
{
ASSERT(!scopeChain->globalData->exception);
- if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
- if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
- *exception = createStackOverflowError(callFrame);
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth) {
+ if (m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
+ throwStackOverflowError(callFrame);
return CallFrameClosure();
}
}
@@ -712,33 +994,35 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionE
int argc = 1 + argCount; // implicit "this" parameter
if (!m_registerFile.grow(oldEnd + argc)) {
- *exception = createStackOverflowError(callFrame);
+ throwStackOverflowError(callFrame);
return CallFrameClosure();
}
CallFrame* newCallFrame = CallFrame::create(oldEnd);
size_t dst = 0;
for (int i = 0; i < argc; ++i)
- newCallFrame->r(++dst) = jsUndefined();
+ newCallFrame->uncheckedR(++dst) = jsUndefined();
- CodeBlock* codeBlock = &FunctionExecutable->bytecode(callFrame, scopeChain);
+ JSObject* error = FunctionExecutable->compileForCall(callFrame, scopeChain);
+ if (error) {
+ throwError(callFrame, error);
+ m_registerFile.shrink(oldEnd);
+ return CallFrameClosure();
+ }
+ CodeBlock* codeBlock = &FunctionExecutable->generatedBytecodeForCall();
+
newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
if (UNLIKELY(!newCallFrame)) {
- *exception = createStackOverflowError(callFrame);
+ throwStackOverflowError(callFrame);
m_registerFile.shrink(oldEnd);
return CallFrameClosure();
}
- // a 0 codeBlock indicates a built-in caller
- newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
-#if ENABLE(JIT)
- FunctionExecutable->jitCode(newCallFrame, scopeChain);
-#endif
-
+ newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), argc, function);
CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
return result;
}
-JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception)
+JSValue Interpreter::execute(CallFrameClosure& closure)
{
closure.resetCallFrame();
Profiler** profiler = Profiler::enabledProfilerReference();
@@ -749,18 +1033,25 @@ JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception)
{
SamplingTool::CallRecord callRecord(m_sampler.get());
- m_reentryDepth++;
+ m_reentryDepth++;
#if ENABLE(JIT)
- result = closure.functionExecutable->generatedJITCode().execute(&m_registerFile, closure.newCallFrame, closure.globalData, exception);
-#else
- result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception);
+#if ENABLE(INTERPRETER)
+ if (closure.newCallFrame->globalData().canUseJIT())
+#endif
+ result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData);
+#if ENABLE(INTERPRETER)
+ else
+#endif
+#endif
+#if ENABLE(INTERPRETER)
+ result = privateExecute(Normal, &m_registerFile, closure.newCallFrame);
#endif
m_reentryDepth--;
}
if (*profiler)
(*profiler)->didExecute(closure.oldCallFrame, closure.function);
- return result;
+ return checkedReturn(result);
}
void Interpreter::endRepeatCall(CallFrameClosure& closure)
@@ -768,27 +1059,29 @@ void Interpreter::endRepeatCall(CallFrameClosure& closure)
m_registerFile.shrink(closure.oldEnd);
}
-JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception)
+JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain)
{
- return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->bytecode(callFrame, scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
+ JSObject* compileError = eval->compile(callFrame, scopeChain);
+ if (UNLIKELY(!!compileError))
+ return checkedReturn(throwError(callFrame, compileError));
+ return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->generatedBytecode().m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain);
}
-JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception)
+JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain)
{
ASSERT(!scopeChain->globalData->exception);
- if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
- if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
- }
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ return checkedReturn(throwStackOverflowError(callFrame));
DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
- EvalCodeBlock* codeBlock = &eval->bytecode(callFrame, scopeChain);
+ JSObject* compileError = eval->compile(callFrame, scopeChain);
+ if (UNLIKELY(!!compileError))
+ return checkedReturn(throwError(callFrame, compileError));
+ EvalCodeBlock* codeBlock = &eval->generatedBytecode();
- JSVariableObject* variableObject;
+ JSObject* variableObject;
for (ScopeChainNode* node = scopeChain; ; node = node->next) {
ASSERT(node);
if (node->object->isVariableObject()) {
@@ -797,11 +1090,18 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec
}
}
- { // Scope for BatchedTransitionOptimizer
-
+ 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);
- unsigned numVariables = codeBlock->numVariables();
for (unsigned i = 0; i < numVariables; ++i) {
const Identifier& ident = codeBlock->variable(i);
if (!variableObject->hasProperty(callFrame, ident)) {
@@ -810,44 +1110,51 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec
}
}
- int numFunctions = codeBlock->numberOfFunctionDecls();
for (int i = 0; i < numFunctions; ++i) {
FunctionExecutable* function = codeBlock->functionDecl(i);
PutPropertySlot slot;
variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot);
}
-
}
Register* oldEnd = m_registerFile.end();
Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
if (!m_registerFile.grow(newEnd)) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
+ if (pushedScope)
+ scopeChain->pop();
+ return checkedReturn(throwStackOverflowError(callFrame));
}
CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
- // a 0 codeBlock indicates a built-in caller
- newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
- newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0);
+ ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
+ newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->m_numParameters, 0);
+ newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
if (codeBlock->needsFullScopeChain())
scopeChain->ref();
Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
- (*profiler)->willExecute(newCallFrame, eval->sourceURL(), eval->lineNo());
+ (*profiler)->willExecute(callFrame, eval->sourceURL(), eval->lineNo());
JSValue result;
{
SamplingTool::CallRecord callRecord(m_sampler.get());
m_reentryDepth++;
+
#if ENABLE(JIT)
- result = eval->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
-#else
- result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
+#if ENABLE(INTERPRETER)
+ if (callFrame->globalData().canUseJIT())
+#endif
+ result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
+#if ENABLE(INTERPRETER)
+ else
+#endif
+#endif
+#if ENABLE(INTERPRETER)
+ result = privateExecute(Normal, &m_registerFile, newCallFrame);
#endif
m_reentryDepth--;
}
@@ -856,7 +1163,9 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec
(*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
m_registerFile.shrink(oldEnd);
- return result;
+ if (pushedScope)
+ scopeChain->pop();
+ return checkedReturn(result);
}
NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
@@ -887,7 +1196,7 @@ NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHook
}
}
-#if USE(INTERPRETER)
+#if ENABLE(INTERPRETER)
NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
{
int dst = vPC[1].u.operand;
@@ -895,7 +1204,7 @@ NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFr
Identifier& property = codeBlock->identifier(vPC[2].u.operand);
JSValue value = callFrame->r(vPC[3].u.operand).jsValue();
JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
- callFrame->r(dst) = JSValue(scope);
+ callFrame->uncheckedR(dst) = JSValue(scope);
return callFrame->scopeChain()->push(scope);
}
@@ -915,7 +1224,7 @@ NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock*
return;
}
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* structure = baseCell->structure();
if (structure->isUncacheableDictionary()) {
@@ -1005,7 +1314,7 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
return;
}
- Structure* structure = asCell(baseValue)->structure();
+ Structure* structure = baseValue.asCell()->structure();
if (structure->isUncacheableDictionary()) {
vPC[0] = getOpcode(op_get_by_id_generic);
@@ -1029,8 +1338,20 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
// Cache hit: Specialize instruction and ref Structures.
if (slot.slotBase() == baseValue) {
- vPC[0] = getOpcode(op_get_by_id_self);
- vPC[5] = slot.cachedOffset();
+ switch (slot.cachedPropertyType()) {
+ case PropertySlot::Getter:
+ vPC[0] = getOpcode(op_get_by_id_getter_self);
+ vPC[5] = slot.cachedOffset();
+ break;
+ case PropertySlot::Custom:
+ vPC[0] = getOpcode(op_get_by_id_custom_self);
+ vPC[5] = slot.customGetter();
+ break;
+ default:
+ vPC[0] = getOpcode(op_get_by_id_self);
+ vPC[5] = slot.cachedOffset();
+ break;
+ }
codeBlock->refStructures(vPC);
return;
@@ -1055,10 +1376,22 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
}
ASSERT(!baseObject->structure()->isUncacheableDictionary());
-
- vPC[0] = getOpcode(op_get_by_id_proto);
+
+ switch (slot.cachedPropertyType()) {
+ case PropertySlot::Getter:
+ vPC[0] = getOpcode(op_get_by_id_getter_proto);
+ vPC[6] = offset;
+ break;
+ case PropertySlot::Custom:
+ vPC[0] = getOpcode(op_get_by_id_custom_proto);
+ vPC[6] = slot.customGetter();
+ break;
+ default:
+ vPC[0] = getOpcode(op_get_by_id_proto);
+ vPC[6] = offset;
+ break;
+ }
vPC[5] = baseObject->structure();
- vPC[6] = offset;
codeBlock->refStructures(vPC);
return;
@@ -1071,11 +1404,24 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
return;
}
- vPC[0] = getOpcode(op_get_by_id_chain);
+
+ switch (slot.cachedPropertyType()) {
+ case PropertySlot::Getter:
+ vPC[0] = getOpcode(op_get_by_id_getter_chain);
+ vPC[7] = offset;
+ break;
+ case PropertySlot::Custom:
+ vPC[0] = getOpcode(op_get_by_id_custom_chain);
+ vPC[7] = slot.customGetter();
+ break;
+ default:
+ vPC[0] = getOpcode(op_get_by_id_chain);
+ vPC[7] = offset;
+ break;
+ }
vPC[4] = structure;
vPC[5] = structure->prototypeChain(callFrame);
vPC[6] = count;
- vPC[7] = offset;
codeBlock->refStructures(vPC);
}
@@ -1086,31 +1432,34 @@ NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction*
vPC[4] = 0;
}
-#endif // USE(INTERPRETER)
+#endif // ENABLE(INTERPRETER)
-JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValue* exception)
+JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame)
{
// One-time initialization of our address tables. We have to put this code
// here because our labels are only in scope inside this function.
if (UNLIKELY(flag == InitializeAndReturn)) {
- #if HAVE(COMPUTED_GOTO)
+ #if ENABLE(COMPUTED_GOTO_INTERPRETER)
#define LIST_OPCODE_LABEL(id, length) &&id,
static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) };
- for (size_t i = 0; i < sizeof(labels) / sizeof(Opcode); ++i)
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(labels); ++i)
m_opcodeTable[i] = labels[i];
#undef LIST_OPCODE_LABEL
- #endif // HAVE(COMPUTED_GOTO)
+ #endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
return JSValue();
}
-
+
#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
// Mixing Interpreter + JIT is not supported.
- ASSERT_NOT_REACHED();
+ if (callFrame->globalData().canUseJIT())
+#endif
+ ASSERT_NOT_REACHED();
#endif
-#if !USE(INTERPRETER)
+
+#if !ENABLE(INTERPRETER)
UNUSED_PARAM(registerFile);
UNUSED_PARAM(callFrame);
- UNUSED_PARAM(exception);
return JSValue();
#else
@@ -1118,9 +1467,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue exceptionValue;
HandlerInfo* handler = 0;
- Instruction* vPC = callFrame->codeBlock()->instructions().begin();
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ Instruction* vPC = codeBlock->instructions().begin();
Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
+ JSValue functionReturnValue;
#define CHECK_FOR_EXCEPTION() \
do { \
@@ -1136,7 +1487,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
#define CHECK_FOR_TIMEOUT() \
if (!--tickCount) { \
- if (globalData->timeoutChecker.didTimeOut(callFrame)) { \
+ if (globalData->terminator.shouldTerminate() || globalData->timeoutChecker.didTimeOut(callFrame)) { \
exceptionValue = jsNull(); \
goto vm_throw; \
} \
@@ -1149,8 +1500,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
#define SAMPLE(codeBlock, vPC)
#endif
-#if HAVE(COMPUTED_GOTO)
- #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
+#if ENABLE(COMPUTED_GOTO_INTERPRETER)
+ #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode
#if ENABLE(OPCODE_STATS)
#define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
#else
@@ -1158,7 +1509,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
#endif
NEXT_INSTRUCTION();
#else
- #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
+ #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart
#if ENABLE(OPCODE_STATS)
#define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
#else
@@ -1176,7 +1527,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
constructor, and puts the result in register dst.
*/
int dst = vPC[1].u.operand;
- callFrame->r(dst) = JSValue(constructEmptyObject(callFrame));
+ callFrame->uncheckedR(dst) = JSValue(constructEmptyObject(callFrame));
vPC += OPCODE_LENGTH(op_new_object);
NEXT_INSTRUCTION();
@@ -1193,7 +1544,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int firstArg = vPC[2].u.operand;
int argCount = vPC[3].u.operand;
ArgList args(callFrame->registers() + firstArg, argCount);
- callFrame->r(dst) = JSValue(constructArray(callFrame, args));
+ callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
vPC += OPCODE_LENGTH(op_new_array);
NEXT_INSTRUCTION();
@@ -1207,7 +1558,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int regExp = vPC[2].u.operand;
- callFrame->r(dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject->regExpStructure(), callFrame->codeBlock()->regexp(regExp)));
+ callFrame->uncheckedR(dst) = JSValue(new (globalData) RegExpObject(callFrame->lexicalGlobalObject(), callFrame->scopeChain()->globalObject->regExpStructure(), codeBlock->regexp(regExp)));
vPC += OPCODE_LENGTH(op_new_regexp);
NEXT_INSTRUCTION();
@@ -1219,7 +1570,8 @@ 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);
+
+ callFrame->uncheckedR(dst) = callFrame->r(src);
vPC += OPCODE_LENGTH(op_mov);
NEXT_INSTRUCTION();
@@ -1235,11 +1587,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
+ callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
else {
JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_eq);
@@ -1255,12 +1607,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
if (src.isUndefinedOrNull()) {
- callFrame->r(dst) = jsBoolean(true);
+ callFrame->uncheckedR(dst) = jsBoolean(true);
vPC += OPCODE_LENGTH(op_eq_null);
NEXT_INSTRUCTION();
}
- callFrame->r(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
+ callFrame->uncheckedR(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
vPC += OPCODE_LENGTH(op_eq_null);
NEXT_INSTRUCTION();
}
@@ -1275,11 +1627,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
+ callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
else {
JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_neq);
@@ -1295,12 +1647,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
if (src.isUndefinedOrNull()) {
- callFrame->r(dst) = jsBoolean(false);
+ callFrame->uncheckedR(dst) = jsBoolean(false);
vPC += OPCODE_LENGTH(op_neq_null);
NEXT_INSTRUCTION();
}
- callFrame->r(dst) = jsBoolean(!src.isCell() || !asCell(src)->structure()->typeInfo().masqueradesAsUndefined());
+ callFrame->uncheckedR(dst) = jsBoolean(!src.isCell() || !src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
vPC += OPCODE_LENGTH(op_neq_null);
NEXT_INSTRUCTION();
}
@@ -1314,7 +1666,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int dst = vPC[1].u.operand;
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
- callFrame->r(dst) = jsBoolean(JSValue::strictEqual(callFrame, src1, src2));
+ bool result = JSValue::strictEqual(callFrame, src1, src2);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_stricteq);
NEXT_INSTRUCTION();
@@ -1329,7 +1683,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int dst = vPC[1].u.operand;
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
- callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(callFrame, src1, src2));
+ bool result = !JSValue::strictEqual(callFrame, src1, src2);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_nstricteq);
NEXT_INSTRUCTION();
@@ -1346,7 +1702,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
JSValue result = jsBoolean(jsLess(callFrame, src1, src2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_less);
NEXT_INSTRUCTION();
@@ -1363,7 +1719,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_lesseq);
NEXT_INSTRUCTION();
@@ -1377,11 +1733,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int srcDst = vPC[1].u.operand;
JSValue v = callFrame->r(srcDst).jsValue();
if (v.isInt32() && v.asInt32() < INT_MAX)
- callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
+ callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
else {
- JSValue result = jsNumber(callFrame, v.toNumber(callFrame) + 1);
+ JSValue result = jsNumber(v.toNumber(callFrame) + 1);
CHECK_FOR_EXCEPTION();
- callFrame->r(srcDst) = result;
+ callFrame->uncheckedR(srcDst) = result;
}
vPC += OPCODE_LENGTH(op_pre_inc);
@@ -1396,11 +1752,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int srcDst = vPC[1].u.operand;
JSValue v = callFrame->r(srcDst).jsValue();
if (v.isInt32() && v.asInt32() > INT_MIN)
- callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
+ callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
else {
- JSValue result = jsNumber(callFrame, v.toNumber(callFrame) - 1);
+ JSValue result = jsNumber(v.toNumber(callFrame) - 1);
CHECK_FOR_EXCEPTION();
- callFrame->r(srcDst) = result;
+ callFrame->uncheckedR(srcDst) = result;
}
vPC += OPCODE_LENGTH(op_pre_dec);
@@ -1417,13 +1773,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int srcDst = vPC[2].u.operand;
JSValue v = callFrame->r(srcDst).jsValue();
if (v.isInt32() && v.asInt32() < INT_MAX) {
- callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
- callFrame->r(dst) = v;
+ callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
+ callFrame->uncheckedR(dst) = v;
} else {
JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
CHECK_FOR_EXCEPTION();
- callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() + 1);
- callFrame->r(dst) = number;
+ callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() + 1);
+ callFrame->uncheckedR(dst) = number;
}
vPC += OPCODE_LENGTH(op_post_inc);
@@ -1440,13 +1796,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int srcDst = vPC[2].u.operand;
JSValue v = callFrame->r(srcDst).jsValue();
if (v.isInt32() && v.asInt32() > INT_MIN) {
- callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
- callFrame->r(dst) = v;
+ callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
+ callFrame->uncheckedR(dst) = v;
} else {
JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
CHECK_FOR_EXCEPTION();
- callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() - 1);
- callFrame->r(dst) = number;
+ callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() - 1);
+ callFrame->uncheckedR(dst) = number;
}
vPC += OPCODE_LENGTH(op_post_dec);
@@ -1464,11 +1820,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue srcVal = callFrame->r(src).jsValue();
if (LIKELY(srcVal.isNumber()))
- callFrame->r(dst) = callFrame->r(src);
+ callFrame->uncheckedR(dst) = callFrame->r(src);
else {
JSValue result = srcVal.toJSNumber(callFrame);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_to_jsnumber);
@@ -1482,12 +1838,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
- if (src.isInt32() && src.asInt32())
- callFrame->r(dst) = jsNumber(callFrame, -src.asInt32());
+ if (src.isInt32() && (src.asInt32() & 0x7fffffff)) // non-zero and no overflow
+ callFrame->uncheckedR(dst) = jsNumber(-src.asInt32());
else {
- JSValue result = jsNumber(callFrame, -src.toNumber(callFrame));
+ JSValue result = jsNumber(-src.toNumber(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_negate);
@@ -1504,11 +1860,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() + src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() + src2.asInt32());
else {
JSValue result = jsAdd(callFrame, src1, src2);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_add);
NEXT_INSTRUCTION();
@@ -1523,11 +1879,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() * src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() * src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) * src2.toNumber(callFrame));
+ JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_mul);
@@ -1544,9 +1900,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
- JSValue result = jsNumber(callFrame, dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
+ JSValue result = jsNumber(dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_div);
NEXT_INSTRUCTION();
@@ -1563,9 +1919,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
- JSValue result = jsNumber(callFrame, dividend.asInt32() % divisor.asInt32());
+ JSValue result = jsNumber(dividend.asInt32() % divisor.asInt32());
ASSERT(result);
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_mod);
NEXT_INSTRUCTION();
}
@@ -1574,9 +1930,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
// order of argument evaluation is not guaranteed.
double d1 = dividend.toNumber(callFrame);
double d2 = divisor.toNumber(callFrame);
- JSValue result = jsNumber(callFrame, fmod(d1, d2));
+ JSValue result = jsNumber(fmod(d1, d2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_mod);
NEXT_INSTRUCTION();
}
@@ -1591,11 +1947,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() - src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() - src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame));
+ JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_sub);
NEXT_INSTRUCTION();
@@ -1612,11 +1968,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
if (val.isInt32() && shift.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, val.asInt32() << (shift.asInt32() & 0x1f));
+ callFrame->uncheckedR(dst) = jsNumber(val.asInt32() << (shift.asInt32() & 0x1f));
else {
- JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_lshift);
@@ -1634,11 +1990,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
if (val.isInt32() && shift.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
+ callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
else {
- JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_rshift);
@@ -1655,11 +2011,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
if (val.isUInt32() && shift.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
+ callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
else {
- JSValue result = jsNumber(callFrame, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_urshift);
@@ -1676,11 +2032,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() & src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() & src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) & src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_bitand);
@@ -1697,11 +2053,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() ^ src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() ^ src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_bitxor);
@@ -1718,11 +2074,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() | src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() | src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) | src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_bitor);
@@ -1737,11 +2093,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int dst = vPC[1].u.operand;
JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
if (src.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, ~src.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(~src.asInt32());
else {
- JSValue result = jsNumber(callFrame, ~src.toInt32(callFrame));
+ JSValue result = jsNumber(~src.toInt32(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_bitnot);
NEXT_INSTRUCTION();
@@ -1756,11 +2112,28 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int src = vPC[2].u.operand;
JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_not);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_check_has_instance) {
+ /* check_has_instance constructor(r)
+
+ Check 'constructor' is an object with the internal property
+ [HasInstance] (i.e. is a function ... *shakes head sadly at
+ JSC API*). Raises an exception if register constructor is not
+ an valid parameter for instanceof.
+ */
+ int base = vPC[1].u.operand;
+ JSValue baseVal = callFrame->r(base).jsValue();
+
+ if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue))
+ goto vm_throw;
+
+ vPC += OPCODE_LENGTH(op_check_has_instance);
+ NEXT_INSTRUCTION();
+ }
DEFINE_OPCODE(op_instanceof) {
/* instanceof dst(r) value(r) constructor(r) constructorProto(r)
@@ -1781,12 +2154,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue baseVal = callFrame->r(base).jsValue();
- if (isInvalidParamForInstanceOf(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
- goto vm_throw;
+ ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue));
bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = jsBoolean(result);
+ callFrame->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_instanceof);
NEXT_INSTRUCTION();
@@ -1799,7 +2171,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
+ callFrame->uncheckedR(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
vPC += OPCODE_LENGTH(op_typeof);
NEXT_INSTRUCTION();
@@ -1814,7 +2186,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
JSValue v = callFrame->r(src).jsValue();
- callFrame->r(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
+ callFrame->uncheckedR(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
vPC += OPCODE_LENGTH(op_is_undefined);
NEXT_INSTRUCTION();
@@ -1828,7 +2200,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
+ callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
vPC += OPCODE_LENGTH(op_is_boolean);
NEXT_INSTRUCTION();
@@ -1842,7 +2214,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
+ callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
vPC += OPCODE_LENGTH(op_is_number);
NEXT_INSTRUCTION();
@@ -1856,7 +2228,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
+ callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
vPC += OPCODE_LENGTH(op_is_string);
NEXT_INSTRUCTION();
@@ -1870,7 +2242,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
+ callFrame->uncheckedR(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
vPC += OPCODE_LENGTH(op_is_object);
NEXT_INSTRUCTION();
@@ -1884,7 +2256,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
+ callFrame->uncheckedR(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
vPC += OPCODE_LENGTH(op_is_function);
NEXT_INSTRUCTION();
@@ -1903,7 +2275,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int base = vPC[3].u.operand;
JSValue baseVal = callFrame->r(base).jsValue();
- if (isInvalidParamForIn(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
+ if (isInvalidParamForIn(callFrame, baseVal, exceptionValue))
goto vm_throw;
JSObject* baseObj = asObject(baseVal);
@@ -1912,11 +2284,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
uint32_t i;
if (propName.getUInt32(i))
- callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
+ callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
else {
Identifier property(callFrame, propName.toString(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
+ callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
}
vPC += OPCODE_LENGTH(op_in);
@@ -1964,17 +2336,35 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_resolve_global_dynamic) {
+ /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)
+
+ Performs a dynamic property lookup for the given property, on the provided
+ global object. If structure matches the Structure of the global then perform
+ a fast lookup using the case offset, otherwise fall back to a full resolve and
+ cache the new structure and offset.
+
+ 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;
+
+ vPC += OPCODE_LENGTH(op_resolve_global_dynamic);
+
+ NEXT_INSTRUCTION();
+ }
DEFINE_OPCODE(op_get_global_var) {
/* get_global_var dst(r) globalObject(c) index(n)
Gets the global var at global slot index and places it in register dst.
*/
int dst = vPC[1].u.operand;
- JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
+ JSGlobalObject* scope = codeBlock->globalObject();
ASSERT(scope->isGlobalObject());
- int index = vPC[3].u.operand;
+ int index = vPC[2].u.operand;
- callFrame->r(dst) = scope->registerAt(index);
+ callFrame->uncheckedR(dst) = scope->registerAt(index);
vPC += OPCODE_LENGTH(op_get_global_var);
NEXT_INSTRUCTION();
}
@@ -1983,37 +2373,44 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
Puts value into global slot index.
*/
- JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[1].u.jsCell);
+ JSGlobalObject* scope = codeBlock->globalObject();
ASSERT(scope->isGlobalObject());
- int index = vPC[2].u.operand;
- int value = vPC[3].u.operand;
+ int index = vPC[1].u.operand;
+ int value = vPC[2].u.operand;
scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
vPC += OPCODE_LENGTH(op_put_global_var);
NEXT_INSTRUCTION();
- }
+ }
DEFINE_OPCODE(op_get_scoped_var) {
/* get_scoped_var dst(r) index(n) skip(n)
Loads the contents of the index-th local from the scope skip nodes from
- the top of the scope chain, and places it in register dst
+ the top of the scope chain, and places it in register dst.
*/
int dst = vPC[1].u.operand;
int index = vPC[2].u.operand;
- int skip = vPC[3].u.operand + callFrame->codeBlock()->needsFullScopeChain();
+ int skip = vPC[3].u.operand;
ScopeChainNode* scopeChain = callFrame->scopeChain();
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);
}
-
ASSERT((*iter)->isVariableObject());
JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
- callFrame->r(dst) = scope->registerAt(index);
+ callFrame->uncheckedR(dst) = scope->registerAt(index);
+ ASSERT(callFrame->r(dst).jsValue());
vPC += OPCODE_LENGTH(op_get_scoped_var);
NEXT_INSTRUCTION();
}
@@ -2022,13 +2419,20 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int index = vPC[1].u.operand;
- int skip = vPC[2].u.operand + callFrame->codeBlock()->needsFullScopeChain();
+ int skip = vPC[2].u.operand;
int value = vPC[3].u.operand;
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);
@@ -2036,6 +2440,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();
@@ -2053,6 +2458,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)
@@ -2081,7 +2504,6 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int base = vPC[2].u.operand;
int property = vPC[3].u.operand;
- CodeBlock* codeBlock = callFrame->codeBlock();
Identifier& ident = codeBlock->identifier(property);
JSValue baseValue = callFrame->r(base).jsValue();
PropertySlot slot(baseValue);
@@ -2090,7 +2512,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_id);
NEXT_INSTRUCTION();
}
@@ -2105,7 +2527,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* structure = vPC[4].u.structure;
if (LIKELY(baseCell->structure() == structure)) {
@@ -2114,15 +2536,15 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int dst = vPC[1].u.operand;
int offset = vPC[5].u.operand;
- ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
- callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
+ ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_id_self);
NEXT_INSTRUCTION();
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_get_by_id_proto) {
@@ -2136,7 +2558,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* structure = vPC[4].u.structure;
if (LIKELY(baseCell->structure() == structure)) {
@@ -2148,9 +2570,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int dst = vPC[1].u.operand;
int offset = vPC[6].u.operand;
- ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
- ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
- callFrame->r(dst) = JSValue(protoObject->getDirectOffset(offset));
+ ASSERT(protoObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
+ ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(protoObject->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_id_proto);
NEXT_INSTRUCTION();
@@ -2158,9 +2580,96 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
+ NEXT_INSTRUCTION();
+ }
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ goto *(&&skip_id_getter_proto);
+#endif
+ DEFINE_OPCODE(op_get_by_id_getter_proto) {
+ /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
+
+ Cached property access: Attempts to get a cached getter property from the
+ value base's prototype. If the cache misses, op_get_by_id_getter_proto
+ reverts to op_get_by_id.
+ */
+ int base = vPC[2].u.operand;
+ JSValue baseValue = callFrame->r(base).jsValue();
+
+ if (LIKELY(baseValue.isCell())) {
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure;
+
+ if (LIKELY(baseCell->structure() == structure)) {
+ ASSERT(structure->prototypeForLookup(callFrame).isObject());
+ JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
+ Structure* prototypeStructure = vPC[5].u.structure;
+
+ if (LIKELY(protoObject->structure() == prototypeStructure)) {
+ int dst = vPC[1].u.operand;
+ int offset = vPC[6].u.operand;
+ if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) {
+ JSObject* getter = getterSetter->getter();
+ CallData callData;
+ CallType callType = getter->getCallData(callData);
+ JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = result;
+ } else
+ callFrame->uncheckedR(dst) = jsUndefined();
+ vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);
+ NEXT_INSTRUCTION();
+ }
+ }
+ }
+ uncacheGetByID(codeBlock, vPC);
+ NEXT_INSTRUCTION();
+ }
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_id_getter_proto:
+#endif
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ goto *(&&skip_id_custom_proto);
+#endif
+ DEFINE_OPCODE(op_get_by_id_custom_proto) {
+ /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
+
+ Cached property access: Attempts to use a cached named property getter
+ from the value base's prototype. If the cache misses, op_get_by_id_custom_proto
+ reverts to op_get_by_id.
+ */
+ int base = vPC[2].u.operand;
+ JSValue baseValue = callFrame->r(base).jsValue();
+
+ if (LIKELY(baseValue.isCell())) {
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure;
+
+ if (LIKELY(baseCell->structure() == structure)) {
+ ASSERT(structure->prototypeForLookup(callFrame).isObject());
+ JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
+ Structure* prototypeStructure = vPC[5].u.structure;
+
+ if (LIKELY(protoObject->structure() == prototypeStructure)) {
+ int dst = vPC[1].u.operand;
+ int property = vPC[3].u.operand;
+ Identifier& ident = codeBlock->identifier(property);
+
+ PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc;
+ JSValue result = getter(callFrame, protoObject, ident);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = result;
+ vPC += OPCODE_LENGTH(op_get_by_id_custom_proto);
+ NEXT_INSTRUCTION();
+ }
+ }
+ }
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_id_custom_proto:
+#endif
DEFINE_OPCODE(op_get_by_id_self_list) {
// Polymorphic self access caching currently only supported when JITting.
ASSERT_NOT_REACHED();
@@ -2175,6 +2684,34 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_get_by_id_getter_self_list) {
+ // Polymorphic self access caching currently only supported when JITting.
+ ASSERT_NOT_REACHED();
+ // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
+ vPC += OPCODE_LENGTH(op_get_by_id_self_list);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_get_by_id_getter_proto_list) {
+ // Polymorphic prototype access caching currently only supported when JITting.
+ ASSERT_NOT_REACHED();
+ // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
+ vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_get_by_id_custom_self_list) {
+ // Polymorphic self access caching currently only supported when JITting.
+ ASSERT_NOT_REACHED();
+ // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
+ vPC += OPCODE_LENGTH(op_get_by_id_custom_self_list);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_get_by_id_custom_proto_list) {
+ // Polymorphic prototype access caching currently only supported when JITting.
+ ASSERT_NOT_REACHED();
+ // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
+ vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
+ NEXT_INSTRUCTION();
+ }
DEFINE_OPCODE(op_get_by_id_chain) {
/* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
@@ -2186,7 +2723,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* structure = vPC[4].u.structure;
if (LIKELY(baseCell->structure() == structure)) {
@@ -2204,9 +2741,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int dst = vPC[1].u.operand;
int offset = vPC[7].u.operand;
- ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
- ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
- callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
+ ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
+ ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_id_chain);
NEXT_INSTRUCTION();
@@ -2218,9 +2755,89 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
+ NEXT_INSTRUCTION();
+ }
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ goto *(&&skip_id_getter_self);
+#endif
+ DEFINE_OPCODE(op_get_by_id_getter_self) {
+ /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
+
+ Cached property access: Attempts to get a cached property from the
+ value base. If the cache misses, op_get_by_id_getter_self reverts to
+ op_get_by_id.
+ */
+ int base = vPC[2].u.operand;
+ JSValue baseValue = callFrame->r(base).jsValue();
+
+ if (LIKELY(baseValue.isCell())) {
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure;
+
+ if (LIKELY(baseCell->structure() == structure)) {
+ ASSERT(baseCell->isObject());
+ JSObject* baseObject = asObject(baseCell);
+ int dst = vPC[1].u.operand;
+ int offset = vPC[5].u.operand;
+
+ if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
+ JSObject* getter = getterSetter->getter();
+ CallData callData;
+ CallType callType = getter->getCallData(callData);
+ JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList());
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = result;
+ } else
+ callFrame->uncheckedR(dst) = jsUndefined();
+
+ vPC += OPCODE_LENGTH(op_get_by_id_getter_self);
+ NEXT_INSTRUCTION();
+ }
+ }
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_id_getter_self:
+#endif
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ goto *(&&skip_id_custom_self);
+#endif
+ DEFINE_OPCODE(op_get_by_id_custom_self) {
+ /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
+
+ Cached property access: Attempts to use a cached named property getter
+ from the value base. If the cache misses, op_get_by_id_custom_self reverts to
+ op_get_by_id.
+ */
+ int base = vPC[2].u.operand;
+ JSValue baseValue = callFrame->r(base).jsValue();
+
+ if (LIKELY(baseValue.isCell())) {
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure;
+
+ if (LIKELY(baseCell->structure() == structure)) {
+ ASSERT(baseCell->isObject());
+ int dst = vPC[1].u.operand;
+ int property = vPC[3].u.operand;
+ Identifier& ident = codeBlock->identifier(property);
+
+ PropertySlot::GetValueFunc getter = vPC[5].u.getterFunc;
+ JSValue result = getter(callFrame, baseValue, ident);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = result;
+ vPC += OPCODE_LENGTH(op_get_by_id_custom_self);
+ NEXT_INSTRUCTION();
+ }
+ }
+ uncacheGetByID(codeBlock, vPC);
+ NEXT_INSTRUCTION();
+ }
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+skip_id_custom_self:
+#endif
DEFINE_OPCODE(op_get_by_id_generic) {
/* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
@@ -2231,16 +2848,123 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int base = vPC[2].u.operand;
int property = vPC[3].u.operand;
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
JSValue baseValue = callFrame->r(base).jsValue();
PropertySlot slot(baseValue);
JSValue result = baseValue.get(callFrame, ident, slot);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_id_generic);
NEXT_INSTRUCTION();
}
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ goto *(&&skip_id_getter_chain);
+#endif
+ DEFINE_OPCODE(op_get_by_id_getter_chain) {
+ /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
+
+ Cached property access: Attempts to get a cached property from the
+ value base's prototype chain. If the cache misses, op_get_by_id_getter_chain
+ reverts to op_get_by_id.
+ */
+ int base = vPC[2].u.operand;
+ JSValue baseValue = callFrame->r(base).jsValue();
+
+ if (LIKELY(baseValue.isCell())) {
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure;
+
+ if (LIKELY(baseCell->structure() == structure)) {
+ RefPtr<Structure>* it = vPC[5].u.structureChain->head();
+ size_t count = vPC[6].u.operand;
+ RefPtr<Structure>* end = it + count;
+
+ while (true) {
+ JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
+
+ if (UNLIKELY(baseObject->structure() != (*it).get()))
+ break;
+
+ if (++it == end) {
+ int dst = vPC[1].u.operand;
+ int offset = vPC[7].u.operand;
+ if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
+ JSObject* getter = getterSetter->getter();
+ CallData callData;
+ CallType callType = getter->getCallData(callData);
+ JSValue result = call(callFrame, getter, callType, callData, baseValue, ArgList());
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = result;
+ } else
+ callFrame->uncheckedR(dst) = jsUndefined();
+ vPC += OPCODE_LENGTH(op_get_by_id_getter_chain);
+ NEXT_INSTRUCTION();
+ }
+
+ // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
+ baseCell = baseObject;
+ }
+ }
+ }
+ uncacheGetByID(codeBlock, vPC);
+ NEXT_INSTRUCTION();
+ }
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_id_getter_chain:
+#endif
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ goto *(&&skip_id_custom_chain);
+#endif
+ DEFINE_OPCODE(op_get_by_id_custom_chain) {
+ /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
+
+ Cached property access: Attempts to use a cached named property getter on the
+ value base's prototype chain. If the cache misses, op_get_by_id_custom_chain
+ reverts to op_get_by_id.
+ */
+ int base = vPC[2].u.operand;
+ JSValue baseValue = callFrame->r(base).jsValue();
+
+ if (LIKELY(baseValue.isCell())) {
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure;
+
+ if (LIKELY(baseCell->structure() == structure)) {
+ RefPtr<Structure>* it = vPC[5].u.structureChain->head();
+ size_t count = vPC[6].u.operand;
+ RefPtr<Structure>* end = it + count;
+
+ while (true) {
+ JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
+
+ if (UNLIKELY(baseObject->structure() != (*it).get()))
+ break;
+
+ if (++it == end) {
+ int dst = vPC[1].u.operand;
+ int property = vPC[3].u.operand;
+ Identifier& ident = codeBlock->identifier(property);
+
+ PropertySlot::GetValueFunc getter = vPC[7].u.getterFunc;
+ JSValue result = getter(callFrame, baseObject, ident);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = result;
+ vPC += OPCODE_LENGTH(op_get_by_id_custom_chain);
+ NEXT_INSTRUCTION();
+ }
+
+ // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
+ baseCell = baseObject;
+ }
+ }
+ }
+ uncacheGetByID(codeBlock, vPC);
+ NEXT_INSTRUCTION();
+ }
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_id_custom_chain:
+#endif
DEFINE_OPCODE(op_get_array_length) {
/* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
@@ -2253,12 +2977,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(isJSArray(globalData, baseValue))) {
int dst = vPC[1].u.operand;
- callFrame->r(dst) = jsNumber(callFrame, asArray(baseValue)->length());
+ callFrame->uncheckedR(dst) = jsNumber(asArray(baseValue)->length());
vPC += OPCODE_LENGTH(op_get_array_length);
NEXT_INSTRUCTION();
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_get_string_length) {
@@ -2273,33 +2997,40 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(isJSString(globalData, baseValue))) {
int dst = vPC[1].u.operand;
- callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->length());
+ callFrame->uncheckedR(dst) = jsNumber(asString(baseValue)->length());
vPC += OPCODE_LENGTH(op_get_string_length);
NEXT_INSTRUCTION();
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_put_by_id) {
- /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
+ /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
Generic property access: Sets the property named by identifier
property, belonging to register base, to register value.
Unlike many opcodes, this one does not write any output to
the register file.
+
+ The "direct" flag should only be set this put_by_id is to initialize
+ an object literal.
*/
int base = vPC[1].u.operand;
int property = vPC[2].u.operand;
int value = vPC[3].u.operand;
+ int direct = vPC[8].u.operand;
- CodeBlock* codeBlock = callFrame->codeBlock();
JSValue baseValue = callFrame->r(base).jsValue();
Identifier& ident = codeBlock->identifier(property);
- PutPropertySlot slot;
- baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
+ PutPropertySlot slot(codeBlock->isStrictMode());
+ if (direct) {
+ baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
+ ASSERT(slot.base() == baseValue);
+ } else
+ baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
CHECK_FOR_EXCEPTION();
tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
@@ -2308,7 +3039,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_put_by_id_transition) {
- /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
+ /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)
Cached property access: Attempts to set a new property with a cached transition
property named by identifier property, belonging to register base,
@@ -2322,31 +3053,33 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* oldStructure = vPC[4].u.structure;
Structure* newStructure = vPC[5].u.structure;
if (LIKELY(baseCell->structure() == oldStructure)) {
ASSERT(baseCell->isObject());
JSObject* baseObject = asObject(baseCell);
-
- RefPtr<Structure>* it = vPC[6].u.structureChain->head();
-
- JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
- while (!proto.isNull()) {
- if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
- uncachePutByID(callFrame->codeBlock(), vPC);
- NEXT_INSTRUCTION();
+ int direct = vPC[8].u.operand;
+
+ if (!direct) {
+ RefPtr<Structure>* it = vPC[6].u.structureChain->head();
+
+ JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
+ while (!proto.isNull()) {
+ if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
+ uncachePutByID(codeBlock, vPC);
+ NEXT_INSTRUCTION();
+ }
+ ++it;
+ proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
}
- ++it;
- proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
}
-
baseObject->transitionTo(newStructure);
int value = vPC[3].u.operand;
unsigned offset = vPC[7].u.operand;
- ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
+ ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifier(vPC[2].u.operand))) == offset);
baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
vPC += OPCODE_LENGTH(op_put_by_id_transition);
@@ -2354,11 +3087,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
}
}
- uncachePutByID(callFrame->codeBlock(), vPC);
+ uncachePutByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_put_by_id_replace) {
- /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
+ /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n) direct(b)
Cached property access: Attempts to set a pre-existing, cached
property named by identifier property, belonging to register base,
@@ -2372,7 +3105,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* structure = vPC[4].u.structure;
if (LIKELY(baseCell->structure() == structure)) {
@@ -2381,7 +3114,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int value = vPC[3].u.operand;
unsigned offset = vPC[5].u.operand;
- ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
+ ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifier(vPC[2].u.operand))) == offset);
baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
vPC += OPCODE_LENGTH(op_put_by_id_replace);
@@ -2389,11 +3122,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
}
}
- uncachePutByID(callFrame->codeBlock(), vPC);
+ uncachePutByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_put_by_id_generic) {
- /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
+ /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
Generic property access: Sets the property named by identifier
property, belonging to register base, to register value.
@@ -2404,11 +3137,16 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int base = vPC[1].u.operand;
int property = vPC[2].u.operand;
int value = vPC[3].u.operand;
+ int direct = vPC[8].u.operand;
JSValue baseValue = callFrame->r(base).jsValue();
- Identifier& ident = callFrame->codeBlock()->identifier(property);
- PutPropertySlot slot;
- baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
+ Identifier& ident = codeBlock->identifier(property);
+ PutPropertySlot slot(codeBlock->isStrictMode());
+ if (direct) {
+ baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
+ ASSERT(slot.base() == baseValue);
+ } else
+ baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
CHECK_FOR_EXCEPTION();
vPC += OPCODE_LENGTH(op_put_by_id_generic);
@@ -2427,10 +3165,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int property = vPC[3].u.operand;
JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
- Identifier& ident = callFrame->codeBlock()->identifier(property);
- JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
+ Identifier& ident = codeBlock->identifier(property);
+ 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->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_del_by_id);
NEXT_INSTRUCTION();
}
@@ -2450,17 +3192,57 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSValue result;
int offset = 0;
if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
- callFrame->r(dst) = asObject(baseValue)->getDirectOffset(offset);
+ callFrame->uncheckedR(dst) = JSValue(asObject(baseValue)->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_pname);
NEXT_INSTRUCTION();
}
Identifier propertyName(callFrame, subscript.toString(callFrame));
result = baseValue.get(callFrame, propertyName);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_pname);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_get_arguments_length) {
+ int dst = vPC[1].u.operand;
+ int argumentsRegister = vPC[2].u.operand;
+ int property = vPC[3].u.operand;
+ JSValue arguments = callFrame->r(argumentsRegister).jsValue();
+ if (arguments) {
+ Identifier& ident = codeBlock->identifier(property);
+ PropertySlot slot(arguments);
+ JSValue result = arguments.get(callFrame, ident, slot);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = result;
+ } else
+ callFrame->uncheckedR(dst) = jsNumber(callFrame->argumentCount());
+
+ vPC += OPCODE_LENGTH(op_get_arguments_length);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_get_argument_by_val) {
+ int dst = vPC[1].u.operand;
+ int argumentsRegister = vPC[2].u.operand;
+ int property = vPC[3].u.operand;
+ JSValue arguments = callFrame->r(argumentsRegister).jsValue();
+ JSValue subscript = callFrame->r(property).jsValue();
+ if (!arguments && subscript.isUInt32() && subscript.asUInt32() < callFrame->argumentCount()) {
+ unsigned arg = subscript.asUInt32() + 1;
+ unsigned numParameters = callFrame->codeBlock()->m_numParameters;
+ if (arg < numParameters)
+ callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters);
+ else
+ callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters - callFrame->argumentCount() - 1);
+ vPC += OPCODE_LENGTH(op_get_argument_by_val);
+ NEXT_INSTRUCTION();
+ }
+ if (!arguments) {
+ Arguments* arguments = new (globalData) Arguments(callFrame);
+ callFrame->uncheckedR(argumentsRegister) = JSValue(arguments);
+ callFrame->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister)) = JSValue(arguments);
+ }
+ // fallthrough
+ }
DEFINE_OPCODE(op_get_by_val) {
/* get_by_val dst(r) base(r) property(r)
@@ -2498,7 +3280,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
}
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_val);
NEXT_INSTRUCTION();
}
@@ -2543,7 +3325,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
} 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);
}
}
@@ -2567,19 +3349,22 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
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->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_del_by_val);
NEXT_INSTRUCTION();
}
@@ -2884,6 +3669,29 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
vPC += OPCODE_LENGTH(op_jnlesseq);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_jlesseq) {
+ /* jlesseq src1(r) src2(r) target(offset)
+
+ Checks whether register src1 is less than or equal to
+ register src2, as with the ECMAScript '<=' operator,
+ and then jumps to offset target from the current instruction,
+ if and only if the result of the comparison is true.
+ */
+ JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
+ JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
+ int target = vPC[3].u.operand;
+
+ bool result = jsLessEq(callFrame, src1, src2);
+ CHECK_FOR_EXCEPTION();
+
+ if (result) {
+ vPC += target;
+ NEXT_INSTRUCTION();
+ }
+
+ vPC += OPCODE_LENGTH(op_jlesseq);
+ NEXT_INSTRUCTION();
+ }
DEFINE_OPCODE(op_switch_imm) {
/* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
@@ -2897,12 +3705,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int defaultOffset = vPC[2].u.operand;
JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
if (scrutinee.isInt32())
- vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
+ vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
else {
double value;
int32_t intValue;
if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
- vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
+ vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
else
vPC += defaultOffset;
}
@@ -2923,11 +3731,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
if (!scrutinee.isString())
vPC += defaultOffset;
else {
- UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
- if (value->size() != 1)
+ StringImpl* value = asString(scrutinee)->value(callFrame).impl();
+ if (value->length() != 1)
vPC += defaultOffset;
else
- vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->data()[0], defaultOffset);
+ vPC += codeBlock->characterSwitchJumpTable(tableIndex).offsetForValue(value->characters()[0], defaultOffset);
}
NEXT_INSTRUCTION();
}
@@ -2946,7 +3754,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
if (!scrutinee.isString())
vPC += defaultOffset;
else
- vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).rep(), defaultOffset);
+ vPC += codeBlock->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).impl(), defaultOffset);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_new_func) {
@@ -2959,8 +3767,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int func = vPC[2].u.operand;
-
- callFrame->r(dst) = JSValue(callFrame->codeBlock()->functionDecl(func)->make(callFrame, callFrame->scopeChain()));
+ 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()));
vPC += OPCODE_LENGTH(op_new_func);
NEXT_INSTRUCTION();
@@ -2975,8 +3785,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
*/
int dst = vPC[1].u.operand;
int funcIndex = vPC[2].u.operand;
-
- FunctionExecutable* function = callFrame->codeBlock()->functionExpr(funcIndex);
+
+ ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
+ FunctionExecutable* function = codeBlock->functionExpr(funcIndex);
JSFunction* func = function->make(callFrame, callFrame->scopeChain());
/*
@@ -2991,13 +3802,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
func->scope().push(functionScopeObject);
}
- callFrame->r(dst) = JSValue(func);
+ callFrame->uncheckedR(dst) = JSValue(func);
vPC += OPCODE_LENGTH(op_new_func_exp);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_call_eval) {
- /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
+ /* call_eval func(r) argCount(n) registerOffset(n)
Call a function named "eval" with no explicit "this" value
(which may therefore be the eval operator). If register
@@ -3008,11 +3819,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
opcode). Otherwise, act exactly as the "call" opcode would.
*/
- int dst = vPC[1].u.operand;
- int func = vPC[2].u.operand;
- int argCount = vPC[3].u.operand;
- int registerOffset = vPC[4].u.operand;
-
+ 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;
@@ -3021,10 +3832,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject;
if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
- JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
- if (exceptionValue)
+ JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset);
+ if ((exceptionValue = globalData->exception))
goto vm_throw;
- callFrame->r(dst) = result;
+ functionReturnValue = result;
vPC += OPCODE_LENGTH(op_call_eval);
NEXT_INSTRUCTION();
@@ -3035,7 +3846,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
// fall through to op_call
}
DEFINE_OPCODE(op_call) {
- /* call dst(r) func(r) argCount(n) registerOffset(n)
+ /* call func(r) argCount(n) registerOffset(n)
Perform a function call.
@@ -3045,22 +3856,26 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
dst is where op_ret should store its result.
*/
- int dst = vPC[1].u.operand;
- int func = vPC[2].u.operand;
- int argCount = vPC[3].u.operand;
- int registerOffset = vPC[4].u.operand;
+ int func = vPC[1].u.operand;
+ int argCount = vPC[2].u.operand;
+ int registerOffset = vPC[3].u.operand;
JSValue v = callFrame->r(func).jsValue();
CallData callData;
- CallType callType = v.getCallData(callData);
+ CallType callType = getCallData(v, callData);
if (callType == CallTypeJS) {
ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
- CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
- CallFrame* previousCallFrame = callFrame;
+ JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
+ if (UNLIKELY(!!error)) {
+ exceptionValue = error;
+ goto vm_throw;
+ }
+ CallFrame* previousCallFrame = callFrame;
+ CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
if (UNLIKELY(!callFrame)) {
callFrame = previousCallFrame;
@@ -3068,7 +3883,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
goto vm_throw;
}
- callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
+ callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
+ codeBlock = newCodeBlock;
+ ASSERT(codeBlock == callFrame->codeBlock());
vPC = newCodeBlock->instructions().begin();
#if ENABLE(OPCODE_STATS)
@@ -3081,24 +3898,21 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
if (callType == CallTypeHost) {
ScopeChainNode* scopeChain = callFrame->scopeChain();
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
- newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
-
- Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
- ArgList args(thisRegister + 1, argCount - 1);
+ if (!registerFile->grow(newCallFrame->registers())) {
+ exceptionValue = createStackOverflowError(callFrame);
+ goto vm_throw;
+ }
- // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
- JSValue thisValue = thisRegister->jsValue();
- if (thisValue == jsNull())
- thisValue = callFrame->globalThisValue();
+ newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scopeChain, callFrame, argCount, asObject(v));
JSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(m_sampler.get());
- returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
+ returnValue = JSValue::decode(callData.native.function(newCallFrame));
}
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = returnValue;
+ functionReturnValue = returnValue;
vPC += OPCODE_LENGTH(op_call);
NEXT_INSTRUCTION();
@@ -3106,7 +3920,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
ASSERT(callType == CallTypeNone);
- exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createNotAFunctionError(callFrame, v);
goto vm_throw;
}
DEFINE_OPCODE(op_load_varargs) {
@@ -3114,18 +3928,19 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int argsOffset = vPC[2].u.operand;
JSValue arguments = callFrame->r(argsOffset).jsValue();
- int32_t argCount = 0;
+ uint32_t argCount = 0;
if (!arguments) {
- argCount = (uint32_t)(callFrame->argumentCount()) - 1;
+ argCount = (uint32_t)(callFrame->argumentCount());
+ argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
exceptionValue = createStackOverflowError(callFrame);
goto vm_throw;
}
- ASSERT(!callFrame->callee()->isHostFunction());
- int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount();
- int32_t inplaceArgs = min(argCount, expectedParams);
+ ASSERT(!asFunction(callFrame->callee())->isHostFunction());
+ int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount();
+ int32_t inplaceArgs = min(static_cast<int32_t>(argCount), expectedParams);
int32_t i = 0;
Register* argStore = callFrame->registers() + argsOffset;
@@ -3133,16 +3948,17 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
for (; i < inplaceArgs; i++)
argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
// Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
- for (; i < argCount; i++)
- argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - argCount - 1];
+ for (; i < static_cast<int32_t>(argCount); i++)
+ argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - static_cast<int32_t>(argCount) - 1];
} else if (!arguments.isUndefinedOrNull()) {
if (!arguments.isObject()) {
- exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
goto vm_throw;
}
if (asObject(arguments)->classInfo() == &Arguments::info) {
Arguments* args = asArguments(arguments);
argCount = args->numProvidedArguments(callFrame);
+ argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -3153,6 +3969,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
} else if (isJSArray(&callFrame->globalData(), arguments)) {
JSArray* array = asArray(arguments);
argCount = array->length();
+ argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -3163,6 +3980,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
} else if (asObject(arguments)->inherits(&JSArray::info)) {
JSObject* argObject = asObject(arguments);
argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
+ argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -3170,24 +3988,22 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
goto vm_throw;
}
Register* argsBuffer = callFrame->registers() + argsOffset;
- for (int32_t i = 0; i < argCount; ++i) {
+ for (uint32_t i = 0; i < argCount; ++i) {
argsBuffer[i] = asObject(arguments)->get(callFrame, i);
CHECK_FOR_EXCEPTION();
}
} else {
- if (!arguments.isObject()) {
- exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
- goto vm_throw;
- }
+ exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
+ goto vm_throw;
}
}
CHECK_FOR_EXCEPTION();
- callFrame->r(argCountDst) = Register::withInt(argCount + 1);
+ callFrame->uncheckedR(argCountDst) = Register::withInt(argCount + 1);
vPC += OPCODE_LENGTH(op_load_varargs);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_call_varargs) {
- /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
+ /* call_varargs func(r) argCountReg(r) baseRegisterOffset(n)
Perform a function call with a dynamic set of arguments.
@@ -3198,31 +4014,37 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
dst is where op_ret should store its result.
*/
- int dst = vPC[1].u.operand;
- int func = vPC[2].u.operand;
- int argCountReg = vPC[3].u.operand;
- int registerOffset = vPC[4].u.operand;
+ int func = vPC[1].u.operand;
+ int argCountReg = vPC[2].u.operand;
+ int registerOffset = vPC[3].u.operand;
JSValue v = callFrame->r(func).jsValue();
int argCount = callFrame->r(argCountReg).i();
registerOffset += argCount;
CallData callData;
- CallType callType = v.getCallData(callData);
+ CallType callType = getCallData(v, callData);
if (callType == CallTypeJS) {
ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
- CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
-
+
+ JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
+ if (UNLIKELY(!!error)) {
+ exceptionValue = error;
+ goto vm_throw;
+ }
+
CallFrame* previousCallFrame = callFrame;
-
+ CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
if (UNLIKELY(!callFrame)) {
callFrame = previousCallFrame;
exceptionValue = createStackOverflowError(callFrame);
goto vm_throw;
}
-
- callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
+
+ callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call_varargs), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
+ codeBlock = newCodeBlock;
+ ASSERT(codeBlock == callFrame->codeBlock());
vPC = newCodeBlock->instructions().begin();
#if ENABLE(OPCODE_STATS)
@@ -3235,24 +4057,20 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
if (callType == CallTypeHost) {
ScopeChainNode* scopeChain = callFrame->scopeChain();
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
- newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
-
- Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
- ArgList args(thisRegister + 1, argCount - 1);
-
- // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
- JSValue thisValue = thisRegister->jsValue();
- if (thisValue == jsNull())
- thisValue = callFrame->globalThisValue();
+ if (!registerFile->grow(newCallFrame->registers())) {
+ exceptionValue = createStackOverflowError(callFrame);
+ goto vm_throw;
+ }
+ newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scopeChain, callFrame, argCount, asObject(v));
JSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(m_sampler.get());
- returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
+ returnValue = JSValue::decode(callData.native.function(newCallFrame));
}
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = returnValue;
+ functionReturnValue = returnValue;
vPC += OPCODE_LENGTH(op_call_varargs);
NEXT_INSTRUCTION();
@@ -3260,47 +4078,56 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
ASSERT(callType == CallTypeNone);
- exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createNotAFunctionError(callFrame, v);
goto vm_throw;
}
DEFINE_OPCODE(op_tear_off_activation) {
- /* tear_off_activation activation(r)
+ /* tear_off_activation activation(r) arguments(r)
- Copy all locals and parameters to new memory allocated on
- the heap, and make the passed activation use this memory
- in the future when looking up entries in the symbol table.
- If there is an 'arguments' object, then it will also use
- this memory for storing the named parameters, but not any
- extra arguments.
+ Copy locals and named parameters from the register file to the heap.
+ Point the bindings in 'activation' and 'arguments' to this new backing
+ store. (Note that 'arguments' may not have been created. If created,
+ 'arguments' already holds a copy of any extra / unnamed parameters.)
- This opcode should only be used immediately before op_ret.
+ This opcode appears before op_ret in functions that require full scope chains.
*/
- int src = vPC[1].u.operand;
- ASSERT(callFrame->codeBlock()->needsFullScopeChain());
+ int activation = vPC[1].u.operand;
+ int arguments = vPC[2].u.operand;
+ ASSERT(codeBlock->needsFullScopeChain());
+ JSValue activationValue = callFrame->r(activation).jsValue();
+ if (activationValue) {
+ asActivation(activationValue)->copyRegisters();
- asActivation(callFrame->r(src).jsValue())->copyRegisters(callFrame->optionalCalleeArguments());
+ if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
+ if (!codeBlock->isStrictMode())
+ asArguments(argumentsValue)->setActivation(asActivation(activationValue));
+ }
+ } else if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
+ if (!codeBlock->isStrictMode())
+ asArguments(argumentsValue)->copyRegisters();
+ }
vPC += OPCODE_LENGTH(op_tear_off_activation);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_tear_off_arguments) {
- /* tear_off_arguments
+ /* tear_off_arguments arguments(r)
- Copy all arguments to new memory allocated on the heap,
- and make the 'arguments' object use this memory in the
- future when looking up named parameters, but not any
- extra arguments. If an activation object exists for the
- current function context, then the tear_off_activation
- opcode should be used instead.
+ Copy named parameters from the register file to the heap. Point the
+ bindings in 'arguments' to this new backing store. (Note that
+ 'arguments' may not have been created. If created, 'arguments' already
+ holds a copy of any extra / unnamed parameters.)
- This opcode should only be used immediately before op_ret.
+ This opcode appears before op_ret in functions that don't require full
+ scope chains, but do use 'arguments'.
*/
- ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
+ int src1 = vPC[1].u.operand;
+ ASSERT(!codeBlock->needsFullScopeChain() && codeBlock->ownerExecutable()->usesArguments());
- if (callFrame->optionalCalleeArguments())
- callFrame->optionalCalleeArguments()->copyRegisters();
+ if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(src1)).jsValue())
+ asArguments(arguments)->copyRegisters();
vPC += OPCODE_LENGTH(op_tear_off_arguments);
NEXT_INSTRUCTION();
@@ -3309,6 +4136,47 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
/* ret result(r)
Return register result as the return value of the current
+ function call, writing it into functionReturnValue.
+ In addition, unwind one call frame and restore the scope
+ chain, code block instruction pointer and register base
+ to those of the calling function.
+ */
+
+ int result = vPC[1].u.operand;
+
+ if (callFrame->codeBlock()->needsFullScopeChain() && callFrame->r(codeBlock->activationRegister()).jsValue())
+ callFrame->scopeChain()->deref();
+
+ JSValue returnValue = callFrame->r(result).jsValue();
+
+ vPC = callFrame->returnVPC();
+ callFrame = callFrame->callerFrame();
+
+ if (callFrame->hasHostCallFrameFlag())
+ return returnValue;
+
+ functionReturnValue = returnValue;
+ codeBlock = callFrame->codeBlock();
+ ASSERT(codeBlock == callFrame->codeBlock());
+
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_call_put_result) {
+ /* op_call_put_result result(r)
+
+ Move call result from functionReturnValue to caller's
+ expected return value register.
+ */
+
+ callFrame->uncheckedR(vPC[1].u.operand) = functionReturnValue;
+
+ vPC += OPCODE_LENGTH(op_call_put_result);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_ret_object_or_this) {
+ /* ret result(r)
+
+ Return register result as the return value of the current
function call, writing it into the caller's expected return
value register. In addition, unwind one call frame and
restore the scope chain, code block instruction pointer and
@@ -3317,67 +4185,96 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int result = vPC[1].u.operand;
- if (callFrame->codeBlock()->needsFullScopeChain())
+ if (codeBlock->needsFullScopeChain() && callFrame->r(codeBlock->activationRegister()).jsValue())
callFrame->scopeChain()->deref();
JSValue returnValue = callFrame->r(result).jsValue();
- vPC = callFrame->returnPC();
- int dst = callFrame->returnValueRegister();
+ if (UNLIKELY(!returnValue.isObject()))
+ returnValue = callFrame->r(vPC[2].u.operand).jsValue();
+
+ vPC = callFrame->returnVPC();
callFrame = callFrame->callerFrame();
-
+
if (callFrame->hasHostCallFrameFlag())
return returnValue;
- callFrame->r(dst) = returnValue;
+ functionReturnValue = returnValue;
+ codeBlock = callFrame->codeBlock();
+ ASSERT(codeBlock == callFrame->codeBlock());
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_enter) {
/* enter
- Initializes local variables to undefined and fills constant
- registers with their values. If the code block requires an
- activation, enter_with_activation should be used instead.
+ Initializes local variables to undefined. If the code block requires
+ an activation, enter_with_activation is used instead.
- This opcode should only be used at the beginning of a code
- block.
+ This opcode appears only at the beginning of a code block.
*/
size_t i = 0;
- CodeBlock* codeBlock = callFrame->codeBlock();
-
for (size_t count = codeBlock->m_numVars; i < count; ++i)
- callFrame->r(i) = jsUndefined();
+ callFrame->uncheckedR(i) = jsUndefined();
vPC += OPCODE_LENGTH(op_enter);
NEXT_INSTRUCTION();
}
- DEFINE_OPCODE(op_enter_with_activation) {
- /* enter_with_activation dst(r)
+ DEFINE_OPCODE(op_create_activation) {
+ /* create_activation dst(r)
+
+ If the activation object for this callframe has not yet been created,
+ this creates it and writes it back to dst.
+ */
+
+ 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) {
+ /* op_get_callee callee(r)
+
+ Move callee into a register.
+ */
- Initializes local variables to undefined, fills constant
- registers with their values, creates an activation object,
- and places the new activation both in dst and at the top
- of the scope chain. If the code block does not require an
- activation, enter should be used instead.
+ callFrame->uncheckedR(vPC[1].u.operand) = JSValue(callFrame->callee());
+
+ vPC += OPCODE_LENGTH(op_get_callee);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_create_this) {
+ /* op_create_this this(r) proto(r)
+
+ Allocate an object as 'this', fr use in construction.
This opcode should only be used at the beginning of a code
block.
*/
- size_t i = 0;
- CodeBlock* codeBlock = callFrame->codeBlock();
+ int thisRegister = vPC[1].u.operand;
+ int protoRegister = vPC[2].u.operand;
- for (size_t count = codeBlock->m_numVars; i < count; ++i)
- callFrame->r(i) = jsUndefined();
+ JSFunction* constructor = asFunction(callFrame->callee());
+#if !ASSERT_DISABLED
+ ConstructData constructData;
+ ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
+#endif
- 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));
+ Structure* structure;
+ JSValue proto = callFrame->r(protoRegister).jsValue();
+ if (proto.isObject())
+ structure = asObject(proto)->inheritorID();
+ else
+ structure = constructor->scope().node()->globalObject->emptyObjectStructure();
+ callFrame->uncheckedR(thisRegister) = JSValue(new (&callFrame->globalData()) JSObject(structure));
- vPC += OPCODE_LENGTH(op_enter_with_activation);
+ vPC += OPCODE_LENGTH(op_create_this);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_convert_this) {
@@ -3395,43 +4292,63 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int thisRegister = vPC[1].u.operand;
JSValue thisVal = callFrame->r(thisRegister).jsValue();
if (thisVal.needsThisConversion())
- callFrame->r(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
+ callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
vPC += OPCODE_LENGTH(op_convert_this);
NEXT_INSTRUCTION();
}
- DEFINE_OPCODE(op_init_arguments) {
- /* create_arguments
+ 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->uncheckedR(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)
- Initialises the arguments object reference to null to ensure
- we can correctly detect that we need to create it later (or
- avoid creating it altogether).
+ Initialises dst(r) to JSValue().
- This opcode should only be used at the beginning of a code
- block.
+ This opcode appears only at the beginning of a code block.
*/
- callFrame->r(RegisterFile::ArgumentsRegister) = JSValue();
- vPC += OPCODE_LENGTH(op_init_arguments);
+ int dst = vPC[1].u.operand;
+
+ callFrame->uncheckedR(dst) = JSValue();
+ vPC += OPCODE_LENGTH(op_init_lazy_reg);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_create_arguments) {
- /* create_arguments
+ /* create_arguments dst(r)
Creates the 'arguments' object and places it in both the
'arguments' call frame slot and the local 'arguments'
register, if it has not already been initialised.
*/
- if (!callFrame->r(RegisterFile::ArgumentsRegister).jsValue()) {
- Arguments* arguments = new (globalData) Arguments(callFrame);
- callFrame->setCalleeArguments(arguments);
- callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
- }
+ int dst = vPC[1].u.operand;
+
+ if (!callFrame->r(dst).jsValue()) {
+ Arguments* arguments = new (globalData) Arguments(callFrame);
+ callFrame->uncheckedR(dst) = JSValue(arguments);
+ callFrame->uncheckedR(unmodifiedArgumentsRegister(dst)) = JSValue(arguments);
+ }
vPC += OPCODE_LENGTH(op_create_arguments);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_construct) {
- /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
+ /* construct func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
Invoke register "func" as a constructor. For JS
functions, the calling convention is exactly as for the
@@ -3445,34 +4362,26 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
caching of this lookup.
*/
- int dst = vPC[1].u.operand;
- int func = vPC[2].u.operand;
- int argCount = vPC[3].u.operand;
- int registerOffset = vPC[4].u.operand;
- int proto = vPC[5].u.operand;
- int thisRegister = vPC[6].u.operand;
+ int func = vPC[1].u.operand;
+ int argCount = vPC[2].u.operand;
+ int registerOffset = vPC[3].u.operand;
JSValue v = callFrame->r(func).jsValue();
ConstructData constructData;
- ConstructType constructType = v.getConstructData(constructData);
+ ConstructType constructType = getConstructData(v, constructData);
if (constructType == ConstructTypeJS) {
ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
- CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
-
- Structure* structure;
- JSValue prototype = callFrame->r(proto).jsValue();
- if (prototype.isObject())
- structure = asObject(prototype)->inheritorID();
- else
- structure = callDataScopeChain->globalObject->emptyObjectStructure();
- JSObject* newObject = new (globalData) JSObject(structure);
- callFrame->r(thisRegister) = JSValue(newObject); // "this" value
+ JSObject* error = constructData.js.functionExecutable->compileForConstruct(callFrame, callDataScopeChain);
+ if (UNLIKELY(!!error)) {
+ exceptionValue = error;
+ goto vm_throw;
+ }
CallFrame* previousCallFrame = callFrame;
-
+ CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
if (UNLIKELY(!callFrame)) {
callFrame = previousCallFrame;
@@ -3480,9 +4389,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
goto vm_throw;
}
- callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
+ callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_construct), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
+ codeBlock = newCodeBlock;
vPC = newCodeBlock->instructions().begin();
-
#if ENABLE(OPCODE_STATS)
OpcodeStats::resetLastInstruction();
#endif
@@ -3491,19 +4400,21 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
}
if (constructType == ConstructTypeHost) {
- ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);
-
ScopeChainNode* scopeChain = callFrame->scopeChain();
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
- newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
+ if (!registerFile->grow(newCallFrame->registers())) {
+ exceptionValue = createStackOverflowError(callFrame);
+ goto vm_throw;
+ }
+ newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scopeChain, callFrame, argCount, asObject(v));
JSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(m_sampler.get());
- returnValue = constructData.native.function(newCallFrame, asObject(v), args);
+ returnValue = JSValue::decode(constructData.native.function(newCallFrame));
}
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = JSValue(returnValue);
+ functionReturnValue = returnValue;
vPC += OPCODE_LENGTH(op_construct);
NEXT_INSTRUCTION();
@@ -3511,34 +4422,23 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
ASSERT(constructType == ConstructTypeNone);
- exceptionValue = createNotAConstructorError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createNotAConstructorError(callFrame, v);
goto vm_throw;
}
- DEFINE_OPCODE(op_construct_verify) {
- /* construct_verify dst(r) override(r)
+ DEFINE_OPCODE(op_strcat) {
+ /* strcat dst(r) src(r) count(n)
- Verifies that register dst holds an object. If not, moves
- the object in register override to register dst.
+ Construct a new String instance using the original
+ constructor, and puts the result in register dst.
+ The string will be the result of concatenating count
+ strings with values taken from registers starting at
+ register src.
*/
-
- int dst = vPC[1].u.operand;
- if (LIKELY(callFrame->r(dst).jsValue().isObject())) {
- vPC += OPCODE_LENGTH(op_construct_verify);
- NEXT_INSTRUCTION();
- }
-
- int override = vPC[2].u.operand;
- callFrame->r(dst) = callFrame->r(override);
-
- vPC += OPCODE_LENGTH(op_construct_verify);
- NEXT_INSTRUCTION();
- }
- DEFINE_OPCODE(op_strcat) {
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
int count = vPC[3].u.operand;
- callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count);
+ callFrame->uncheckedR(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
CHECK_FOR_EXCEPTION();
vPC += OPCODE_LENGTH(op_strcat);
@@ -3548,7 +4448,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).jsValue().toPrimitive(callFrame);
+ callFrame->uncheckedR(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
vPC += OPCODE_LENGTH(op_to_primitive);
NEXT_INSTRUCTION();
@@ -3565,7 +4465,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSObject* o = v.toObject(callFrame);
CHECK_FOR_EXCEPTION();
- callFrame->r(scope) = JSValue(o);
+ callFrame->uncheckedR(scope) = JSValue(o);
callFrame->setScopeChain(callFrame->scopeChain()->push(o));
vPC += OPCODE_LENGTH(op_push_scope);
@@ -3606,10 +4506,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
- callFrame->r(dst) = jsPropertyNameIterator;
- callFrame->r(base) = JSValue(o);
- callFrame->r(i) = Register::withInt(0);
- callFrame->r(size) = Register::withInt(jsPropertyNameIterator->size());
+ callFrame->uncheckedR(dst) = jsPropertyNameIterator;
+ callFrame->uncheckedR(base) = JSValue(o);
+ callFrame->uncheckedR(i) = Register::withInt(0);
+ callFrame->uncheckedR(size) = Register::withInt(jsPropertyNameIterator->size());
vPC += OPCODE_LENGTH(op_get_pnames);
NEXT_INSTRUCTION();
}
@@ -3631,10 +4531,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
while (callFrame->r(i).i() != callFrame->r(size).i()) {
JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
- callFrame->r(i) = Register::withInt(callFrame->r(i).i() + 1);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(i) = Register::withInt(callFrame->r(i).i() + 1);
if (key) {
CHECK_FOR_TIMEOUT();
- callFrame->r(dst) = key;
+ callFrame->uncheckedR(dst) = key;
vPC += target;
NEXT_INSTRUCTION();
}
@@ -3661,7 +4562,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
vPC += target;
NEXT_INSTRUCTION();
}
-#if HAVE(COMPUTED_GOTO)
+#if ENABLE(COMPUTED_GOTO_INTERPRETER)
// Appease GCC
goto *(&&skip_new_scope);
#endif
@@ -3677,7 +4578,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
vPC += OPCODE_LENGTH(op_push_new_scope);
NEXT_INSTRUCTION();
}
-#if HAVE(COMPUTED_GOTO)
+#if ENABLE(COMPUTED_GOTO_INTERPRETER)
skip_new_scope:
#endif
DEFINE_OPCODE(op_catch) {
@@ -3690,7 +4591,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
ASSERT(exceptionValue);
ASSERT(!globalData->exception);
int ex = vPC[1].u.operand;
- callFrame->r(ex) = exceptionValue;
+ callFrame->uncheckedR(ex) = exceptionValue;
exceptionValue = JSValue();
vPC += OPCODE_LENGTH(op_catch);
@@ -3710,32 +4611,35 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
int ex = vPC[1].u.operand;
exceptionValue = callFrame->r(ex).jsValue();
- handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), true);
- if (!handler) {
- *exception = exceptionValue;
- return jsNull();
- }
+ handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
+ if (!handler)
+ return throwError(callFrame, exceptionValue);
- vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
+ codeBlock = callFrame->codeBlock();
+ vPC = codeBlock->instructions().begin() + handler->target;
NEXT_INSTRUCTION();
}
- DEFINE_OPCODE(op_new_error) {
- /* new_error dst(r) type(n) message(k)
+ DEFINE_OPCODE(op_throw_reference_error) {
+ /* op_throw_reference_error message(k)
- Constructs a new Error instance using the original
- constructor, using immediate number n as the type and
- constant message as the message string. The result is
- written to register dst.
+ Constructs a new reference Error instance using the
+ original constructor, using constant message as the
+ message string. The result is thrown.
*/
- int dst = vPC[1].u.operand;
- int type = vPC[2].u.operand;
- int message = vPC[3].u.operand;
-
- CodeBlock* codeBlock = callFrame->codeBlock();
- callFrame->r(dst) = JSValue(Error::create(callFrame, (ErrorType)type, callFrame->r(message).jsValue().toString(callFrame), codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()));
+ UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame);
+ exceptionValue = JSValue(createReferenceError(callFrame, message));
+ goto vm_throw;
+ }
+ DEFINE_OPCODE(op_throw_syntax_error) {
+ /* op_throw_syntax_error message(k)
- vPC += OPCODE_LENGTH(op_new_error);
- NEXT_INSTRUCTION();
+ Constructs a new syntax Error instance using the
+ original constructor, using constant message as the
+ message string. The result is thrown.
+ */
+ UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame);
+ exceptionValue = JSValue(createSyntaxError(callFrame, message));
+ goto vm_throw;
}
DEFINE_OPCODE(op_end) {
/* end result(r)
@@ -3744,7 +4648,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
program. Return control to the calling native code.
*/
- if (callFrame->codeBlock()->needsFullScopeChain()) {
+ if (codeBlock->needsFullScopeChain()) {
ScopeChainNode* scopeChain = callFrame->scopeChain();
ASSERT(scopeChain->refCount > 1);
scopeChain->deref();
@@ -3769,7 +4673,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
ASSERT(callFrame->r(base).jsValue().isObject());
JSObject* baseObj = asObject(callFrame->r(base).jsValue());
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
ASSERT(callFrame->r(function).jsValue().isObject());
baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
@@ -3793,7 +4697,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
ASSERT(callFrame->r(base).jsValue().isObject());
JSObject* baseObj = asObject(callFrame->r(base).jsValue());
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
ASSERT(callFrame->r(function).jsValue().isObject());
baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
@@ -3878,24 +4782,23 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
// cannot fathom if we don't assign to the exceptionValue before branching)
exceptionValue = createInterruptedExecutionException(globalData);
}
- handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), false);
- if (!handler) {
- *exception = exceptionValue;
- return jsNull();
- }
+ handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
+ if (!handler)
+ return throwError(callFrame, exceptionValue);
- vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
+ codeBlock = callFrame->codeBlock();
+ vPC = codeBlock->instructions().begin() + handler->target;
NEXT_INSTRUCTION();
}
}
-#if !HAVE(COMPUTED_GOTO)
+#if !ENABLE(COMPUTED_GOTO_INTERPRETER)
} // iterator loop ends
#endif
-#endif // USE(INTERPRETER)
#undef NEXT_INSTRUCTION
#undef DEFINE_OPCODE
#undef CHECK_FOR_EXCEPTION
#undef CHECK_FOR_TIMEOUT
+#endif // ENABLE(INTERPRETER)
}
JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
@@ -3907,27 +4810,21 @@ JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* functio
CodeBlock* codeBlock = functionCallFrame->codeBlock();
if (codeBlock->usesArguments()) {
ASSERT(codeBlock->codeType() == FunctionCode);
- SymbolTable& symbolTable = *codeBlock->symbolTable();
- int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
- if (!functionCallFrame->r(argumentsIndex).jsValue()) {
- Arguments* arguments = new (callFrame) Arguments(functionCallFrame);
- functionCallFrame->setCalleeArguments(arguments);
- functionCallFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
+ int argumentsRegister = codeBlock->argumentsRegister();
+ if (!functionCallFrame->r(argumentsRegister).jsValue()) {
+ JSValue arguments = JSValue(new (callFrame) Arguments(functionCallFrame));
+ functionCallFrame->r(argumentsRegister) = arguments;
+ functionCallFrame->r(unmodifiedArgumentsRegister(argumentsRegister)) = arguments;
}
- return functionCallFrame->r(argumentsIndex).jsValue();
- }
-
- Arguments* arguments = functionCallFrame->optionalCalleeArguments();
- if (!arguments) {
- arguments = new (functionCallFrame) Arguments(functionCallFrame);
- arguments->copyRegisters();
- callFrame->setCalleeArguments(arguments);
+ return functionCallFrame->r(argumentsRegister).jsValue();
}
+ Arguments* arguments = new (functionCallFrame) Arguments(functionCallFrame);
+ arguments->copyRegisters();
return arguments;
}
-JSValue Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const
+JSValue Interpreter::retrieveCaller(CallFrame* callFrame, JSFunction* function) const
{
CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
if (!functionCallFrame)
@@ -3957,15 +4854,24 @@ void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intp
CodeBlock* callerCodeBlock = callerFrame->codeBlock();
if (!callerCodeBlock)
return;
-
- unsigned bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnPC());
- lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset - 1);
+ unsigned bytecodeOffset = 0;
+#if ENABLE(INTERPRETER)
+ if (!callerFrame->globalData().canUseJIT())
+ bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());
+#if ENABLE(JIT)
+ else
+ bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
+#endif
+#else
+ bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
+#endif
+ lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
sourceID = callerCodeBlock->ownerExecutable()->sourceID();
sourceURL = callerCodeBlock->ownerExecutable()->sourceURL();
function = callerFrame->callee();
}
-CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function)
+CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, JSFunction* function)
{
for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
if (candidate->callee() == function)