summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecompiler
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-09-10 19:10:20 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-09-10 19:10:20 +0200
commit284837daa07b29d6a63a748544a90b1f5842ac5c (patch)
treeecd258180bde91fe741e0cfd2638beb3c6da7e8e /Source/JavaScriptCore/bytecompiler
parent2e2ba8ff45915f40ed3e014101269c175f2a89a0 (diff)
downloadqtwebkit-284837daa07b29d6a63a748544a90b1f5842ac5c.tar.gz
Imported WebKit commit 68645295d2e3e09af2c942f092556f06aa5f8b0d (http://svn.webkit.org/repository/webkit/trunk@128073)
New snapshot
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp261
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h69
-rw-r--r--Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp229
3 files changed, 368 insertions, 191 deletions
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index c8cfa74b6..52b576da2 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -33,13 +33,13 @@
#include "BatchedTransitionOptimizer.h"
#include "Comment.h"
+#include "Interpreter.h"
#include "JSActivation.h"
#include "JSFunction.h"
-#include "Interpreter.h"
+#include "JSNameScope.h"
#include "LowLevelInterpreter.h"
-#include "ScopeChain.h"
#include "StrongInlines.h"
-#include "UString.h"
+#include <wtf/text/WTFString.h>
using namespace std;
@@ -188,10 +188,28 @@ JSObject* BytecodeGenerator::generate()
m_scopeNode->emitBytecode(*this);
+ for (unsigned i = 0; i < m_tryRanges.size(); ++i) {
+ TryRange& range = m_tryRanges[i];
+ ASSERT(range.tryData->targetScopeDepth != UINT_MAX);
+ HandlerInfo info = {
+ range.start->bind(0, 0), range.end->bind(0, 0),
+ range.tryData->target->bind(0, 0), range.tryData->targetScopeDepth
+#if ENABLE(JIT)
+ ,
+#if ENABLE(LLINT)
+ CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(LLInt::getCodePtr(llint_op_catch)))
+#else
+ CodeLocationLabel()
+#endif
+#endif
+ };
+ m_codeBlock->addExceptionHandler(info);
+ }
+
m_codeBlock->instructions() = RefCountedArray<Instruction>(m_instructions);
if (s_dumpsGeneratedCode)
- m_codeBlock->dump(m_scopeChain->globalObject->globalExec());
+ m_codeBlock->dump(m_scope->globalObject()->globalExec());
#ifdef NDEBUG
if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode)
@@ -201,7 +219,7 @@ JSObject* BytecodeGenerator::generate()
m_codeBlock->shrinkToFit(CodeBlock::EarlyShrink);
if (m_expressionTooDeep)
- return createOutOfMemoryError(m_scopeChain->globalObject.get());
+ return createOutOfMemoryError(m_scope->globalObject());
return 0;
}
@@ -242,11 +260,11 @@ void BytecodeGenerator::preserveLastVar()
m_lastVar = &m_calleeRegisters.last();
}
-BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock, CompilationKind compilationKind)
- : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
- , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get()))
- , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get()))
- , m_scopeChain(*scopeChain->globalData, scopeChain)
+BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock, CompilationKind compilationKind)
+ : m_shouldEmitDebugHooks(scope->globalObject()->debugger())
+ , m_shouldEmitProfileHooks(scope->globalObject()->globalObjectMethodTable()->supportsProfiling(scope->globalObject()))
+ , m_shouldEmitRichSourceInfo(scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()))
+ , m_scope(*scope->globalData(), scope)
, m_symbolTable(symbolTable)
#if ENABLE(BYTECODE_COMMENTS)
, m_currentCommentString(0)
@@ -263,7 +281,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* s
, m_hasCreatedActivation(true)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
- , m_globalData(scopeChain->globalData)
+ , m_globalData(scope->globalData())
, m_lastOpcodeID(op_end)
#ifndef NDEBUG
, m_lastOpcodePosition(0)
@@ -288,7 +306,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* s
if (compilationKind == OptimizingCompilation)
return;
- JSGlobalObject* globalObject = scopeChain->globalObject.get();
+ JSGlobalObject* globalObject = scope->globalObject();
ExecState* exec = globalObject->globalExec();
BatchedTransitionOptimizer optimizer(*m_globalData, globalObject);
@@ -306,7 +324,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* s
bool propertyDidExist =
globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
- JSValue value = JSFunction::create(exec, makeFunction(exec, function), scopeChain);
+ JSValue value = JSFunction::create(exec, FunctionExecutable::create(*m_globalData, function), scope);
int index = addGlobalVar(
function->ident(), IsVariable,
!propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable);
@@ -323,11 +341,11 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* s
}
}
-BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainNode* scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, CompilationKind)
- : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
- , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get()))
- , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get()))
- , m_scopeChain(*scopeChain->globalData, scopeChain)
+BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* scope, SymbolTable* symbolTable, CodeBlock* codeBlock, CompilationKind)
+ : m_shouldEmitDebugHooks(scope->globalObject()->debugger())
+ , m_shouldEmitProfileHooks(scope->globalObject()->globalObjectMethodTable()->supportsProfiling(scope->globalObject()))
+ , m_shouldEmitRichSourceInfo(scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()))
+ , m_scope(*scope->globalData(), scope)
, m_symbolTable(symbolTable)
#if ENABLE(BYTECODE_COMMENTS)
, m_currentCommentString(0)
@@ -344,7 +362,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN
, m_hasCreatedActivation(false)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
- , m_globalData(scopeChain->globalData)
+ , m_globalData(scope->globalData())
, m_lastOpcodeID(op_end)
#ifndef NDEBUG
, m_lastOpcodePosition(0)
@@ -401,6 +419,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN
}
}
+ RegisterID* calleeRegister = resolveCallee(functionBody); // May push to the scope chain and/or add a captured var.
+
const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack();
const DeclarationStacks::VarStack& varStack = functionBody->varStack();
@@ -438,6 +458,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN
}
codeBlock->m_numCapturedVars = codeBlock->m_numVars;
+
m_firstLazyFunction = codeBlock->m_numVars;
for (size_t i = 0; i < functionStack.size(); ++i) {
FunctionBodyNode* function = functionStack[i];
@@ -479,6 +500,9 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN
preserveLastVar();
+ // We declare the callee's name last because it should lose to a var, function, and/or parameter declaration.
+ addCallee(functionBody, calleeRegister);
+
if (isConstructor()) {
prependComment("'this' because we are a Constructor function");
emitOpcode(op_create_this);
@@ -490,11 +514,11 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN
}
}
-BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock, CompilationKind)
- : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
- , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get()))
- , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get()))
- , m_scopeChain(*scopeChain->globalData, scopeChain)
+BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, JSScope* scope, SymbolTable* symbolTable, EvalCodeBlock* codeBlock, CompilationKind)
+ : m_shouldEmitDebugHooks(scope->globalObject()->debugger())
+ , m_shouldEmitProfileHooks(scope->globalObject()->globalObjectMethodTable()->supportsProfiling(scope->globalObject()))
+ , m_shouldEmitRichSourceInfo(scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()))
+ , m_scope(*scope->globalData(), scope)
, m_symbolTable(symbolTable)
#if ENABLE(BYTECODE_COMMENTS)
, m_currentCommentString(0)
@@ -511,7 +535,7 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeCh
, m_hasCreatedActivation(true)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
- , m_globalData(scopeChain->globalData)
+ , m_globalData(scope->globalData())
, m_lastOpcodeID(op_end)
#ifndef NDEBUG
, m_lastOpcodePosition(0)
@@ -531,7 +555,7 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeCh
const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack();
for (size_t i = 0; i < functionStack.size(); ++i)
- m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i]));
+ m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, functionStack[i]));
const DeclarationStacks::VarStack& varStack = evalNode->varStack();
unsigned numVariables = varStack.size();
@@ -556,6 +580,53 @@ RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg)
return reg;
}
+RegisterID* BytecodeGenerator::resolveCallee(FunctionBodyNode* functionBodyNode)
+{
+ if (functionBodyNode->ident().isNull() || !functionBodyNode->functionNameIsInScope())
+ return 0;
+
+ m_calleeRegister.setIndex(RegisterFile::Callee);
+
+ // If non-strict eval is in play, we use a separate object in the scope chain for the callee's name.
+ if ((m_codeBlock->usesEval() && !m_codeBlock->isStrictMode()) || m_shouldEmitDebugHooks) {
+ emitOpcode(op_push_name_scope);
+ instructions().append(addConstant(functionBodyNode->ident()));
+ instructions().append(m_calleeRegister.index());
+ instructions().append(ReadOnly | DontDelete);
+
+ // Put a mirror object in compilation scope, so compile-time variable resolution sees the property name we'll see at runtime.
+ m_scope.set(*globalData(),
+ JSNameScope::create(
+ m_scope->globalObject()->globalExec(),
+ functionBodyNode->ident(),
+ jsUndefined(),
+ ReadOnly | DontDelete,
+ m_scope.get()
+ )
+ );
+ return 0;
+ }
+
+ if (!functionBodyNode->captures(functionBodyNode->ident()))
+ return &m_calleeRegister;
+
+ // Move the callee into the captured section of the stack.
+ return emitMove(addVar(), &m_calleeRegister);
+}
+
+void BytecodeGenerator::addCallee(FunctionBodyNode* functionBodyNode, RegisterID* calleeRegister)
+{
+ if (functionBodyNode->ident().isNull() || !functionBodyNode->functionNameIsInScope())
+ return;
+
+ // If non-strict eval is in play, we use a separate object in the scope chain for the callee's name.
+ if ((m_codeBlock->usesEval() && !m_codeBlock->isStrictMode()) || m_shouldEmitDebugHooks)
+ return;
+
+ ASSERT(calleeRegister);
+ symbolTable().add(functionBodyNode->ident().impl(), SymbolTableEntry(calleeRegister->index(), ReadOnly));
+}
+
void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex)
{
// Parameters overwrite var declarations, but not function declarations.
@@ -624,14 +695,6 @@ RegisterID* BytecodeGenerator::newTemporary()
return result;
}
-RegisterID* BytecodeGenerator::highestUsedRegister()
-{
- size_t count = m_codeBlock->m_numCalleeRegisters;
- while (m_calleeRegisters.size() < count)
- newRegister();
- return &m_calleeRegisters.last();
-}
-
PassRefPtr<LabelScope> BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name)
{
// Reclaim free label scopes.
@@ -1022,7 +1085,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond,
emitOpcode(op_jneq_ptr);
instructions().append(cond->index());
- instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scopeChain->globalObject->callFunction()));
+ instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scope->globalObject()->callFunction()));
instructions().append(target->bind(begin, instructions().size()));
return target;
}
@@ -1033,7 +1096,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond
emitOpcode(op_jneq_ptr);
instructions().append(cond->index());
- instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scopeChain->globalObject->applyFunction()));
+ instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scope->globalObject()->applyFunction()));
instructions().append(target->bind(begin, instructions().size()));
return target;
}
@@ -1140,7 +1203,7 @@ RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst
&& src1->isTemporary()
&& m_codeBlock->isConstantRegisterIndex(src2->index())
&& m_codeBlock->constantRegister(src2->index()).get().isString()) {
- const UString& value = asString(m_codeBlock->constantRegister(src2->index()).get())->tryGetValue();
+ const String& value = asString(m_codeBlock->constantRegister(src2->index()).get())->tryGetValue();
if (value == "undefined") {
rewindUnaryOp();
emitOpcode(op_is_undefined);
@@ -1215,7 +1278,7 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& ident
{
JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).iterator->second;
if (!stringInMap)
- stringInMap = jsOwnedString(globalData(), identifier.ustring());
+ stringInMap = jsOwnedString(globalData(), identifier.string());
return emitLoad(dst, JSValue(stringInMap));
}
@@ -1248,19 +1311,19 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property)
if (property == propertyNames().arguments || !canOptimizeNonLocals())
return ResolveResult::dynamicResolve(0);
- ScopeChainIterator iter = m_scopeChain->begin();
- ScopeChainIterator end = m_scopeChain->end();
+ ScopeChainIterator iter = m_scope->begin();
+ ScopeChainIterator end = m_scope->end();
size_t depth = 0;
size_t depthOfFirstScopeWithDynamicChecks = 0;
unsigned flags = 0;
for (; iter != end; ++iter, ++depth) {
- JSObject* currentScope = iter->get();
+ JSObject* currentScope = iter.get();
if (!currentScope->isVariableObject()) {
flags |= ResolveResult::DynamicFlag;
break;
}
JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope);
- SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl());
+ SymbolTableEntry entry = currentVariableObject->symbolTable()->get(property.impl());
// Found the property
if (!entry.isNull()) {
@@ -1292,7 +1355,7 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property)
}
// Can't locate the property but we're able to avoid a few lookups.
- JSObject* scope = iter->get();
+ JSObject* scope = iter.get();
// Step over the function's activation, if it needs one. At this point we
// know there is no dynamic scope in the function itself, so this is safe to
// do.
@@ -1319,15 +1382,15 @@ ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property)
}
// Const declarations in eval code or global code.
- ScopeChainIterator iter = scopeChain()->begin();
- ScopeChainIterator end = scopeChain()->end();
+ ScopeChainIterator iter = scope()->begin();
+ ScopeChainIterator end = scope()->end();
size_t depth = 0;
for (; iter != end; ++iter, ++depth) {
- JSObject* currentScope = iter->get();
+ JSObject* currentScope = iter.get();
if (!currentScope->isVariableObject())
continue;
JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope);
- SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl());
+ SymbolTableEntry entry = currentVariableObject->symbolTable()->get(property.impl());
if (entry.isNull())
continue;
if (++iter == end)
@@ -1583,7 +1646,7 @@ RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResu
emitOpcode(op_put_global_var_check);
instructions().append(resolveResult.registerPointer());
instructions().append(value->index());
- instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable().get(identifier.impl()).addressOfIsWatched());
+ instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable()->get(identifier.impl()).addressOfIsWatched());
instructions().append(addConstant(identifier));
return value;
@@ -1757,7 +1820,7 @@ JSString* BytecodeGenerator::addStringConstant(const Identifier& identifier)
{
JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).iterator->second;
if (!stringInMap) {
- stringInMap = jsString(globalData(), identifier.ustring());
+ stringInMap = jsString(globalData(), identifier.string());
addConstantValue(stringInMap);
}
return stringInMap;
@@ -1820,14 +1883,14 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function)
{
- return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)), false);
+ return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, function)), false);
}
RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function)
{
FunctionOffsetMap::AddResult ptr = m_functionOffsets.add(function, 0);
if (ptr.isNewEntry)
- ptr.iterator->second = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function));
+ ptr.iterator->second = m_codeBlock->addFunctionDecl(FunctionExecutable::create(*m_globalData, function));
return emitNewFunctionInternal(dst, ptr.iterator->second, true);
}
@@ -1852,7 +1915,7 @@ RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
{
FunctionBodyNode* function = n->body();
- unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function));
+ unsigned index = m_codeBlock->addFunctionExpr(FunctionExecutable::create(*m_globalData, function));
createActivationIfNecessary();
emitOpcode(op_new_func_exp);
@@ -1925,6 +1988,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
emitExpressionInfo(divot, startOffset, endOffset);
// Emit call.
+ ArrayProfile* arrayProfile = newArrayProfile();
emitOpcode(opcodeID);
instructions().append(func->index()); // func
instructions().append(callArguments.argumentCountIncludingThis()); // argCount
@@ -1934,7 +1998,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
#else
instructions().append(0);
#endif
- instructions().append(0);
+ instructions().append(arrayProfile);
if (dst != ignoredResult()) {
ValueProfile* profile = emitProfiledOpcode(op_call_put_result);
instructions().append(dst->index()); // dst
@@ -2074,15 +2138,14 @@ void BytecodeGenerator::emitToPrimitive(RegisterID* dst, RegisterID* src)
instructions().append(src->index());
}
-RegisterID* BytecodeGenerator::emitPushScope(RegisterID* scope)
+RegisterID* BytecodeGenerator::emitPushWithScope(RegisterID* scope)
{
- ASSERT(scope->isTemporary());
ControlFlowContext context;
context.isFinallyBlock = false;
m_scopeContextStack.append(context);
m_dynamicScopeDepth++;
- return emitUnaryNoDstOp(op_push_scope, scope);
+ return emitUnaryNoDstOp(op_push_with_scope, scope);
}
void BytecodeGenerator::emitPopScope()
@@ -2121,6 +2184,7 @@ void BytecodeGenerator::pushFinallyContext(StatementNode* finallyBlock)
m_scopeContextStack.size(),
m_switchContextStack.size(),
m_forInContextStack.size(),
+ m_tryContextStack.size(),
m_labelScopes.size(),
m_finallyDepth,
m_dynamicScopeDepth
@@ -2254,14 +2318,18 @@ PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, Contro
Vector<ControlFlowContext> savedScopeContextStack;
Vector<SwitchInfo> savedSwitchContextStack;
Vector<ForInContext> savedForInContextStack;
+ Vector<TryContext> poppedTryContexts;
SegmentedVector<LabelScope, 8> savedLabelScopes;
while (topScope > bottomScope && topScope->isFinallyBlock) {
+ RefPtr<Label> beforeFinally = emitLabel(newLabel().get());
+
// Save the current state of the world while instating the state of the world
// for the finally block.
FinallyContext finallyContext = topScope->finallyContext;
bool flipScopes = finallyContext.scopeContextStackSize != m_scopeContextStack.size();
bool flipSwitches = finallyContext.switchContextStackSize != m_switchContextStack.size();
bool flipForIns = finallyContext.forInContextStackSize != m_forInContextStack.size();
+ bool flipTries = finallyContext.tryContextStackSize != m_tryContextStack.size();
bool flipLabelScopes = finallyContext.labelScopesSize != m_labelScopes.size();
int topScopeIndex = -1;
int bottomScopeIndex = -1;
@@ -2279,6 +2347,19 @@ PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, Contro
savedForInContextStack = m_forInContextStack;
m_forInContextStack.shrink(finallyContext.forInContextStackSize);
}
+ if (flipTries) {
+ while (m_tryContextStack.size() != finallyContext.tryContextStackSize) {
+ ASSERT(m_tryContextStack.size() > finallyContext.tryContextStackSize);
+ TryContext context = m_tryContextStack.last();
+ m_tryContextStack.removeLast();
+ TryRange range;
+ range.start = context.start;
+ range.end = beforeFinally;
+ range.tryData = context.tryData;
+ m_tryRanges.append(range);
+ poppedTryContexts.append(context);
+ }
+ }
if (flipLabelScopes) {
savedLabelScopes = m_labelScopes;
while (m_labelScopes.size() > finallyContext.labelScopesSize)
@@ -2292,6 +2373,8 @@ PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, Contro
// Emit the finally block.
emitNode(finallyContext.finallyBlock);
+ RefPtr<Label> afterFinally = emitLabel(newLabel().get());
+
// Restore the state of the world.
if (flipScopes) {
m_scopeContextStack = savedScopeContextStack;
@@ -2302,6 +2385,14 @@ PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, Contro
m_switchContextStack = savedSwitchContextStack;
if (flipForIns)
m_forInContextStack = savedForInContextStack;
+ if (flipTries) {
+ ASSERT(m_tryContextStack.size() == finallyContext.tryContextStackSize);
+ for (unsigned i = poppedTryContexts.size(); i--;) {
+ TryContext context = poppedTryContexts[i];
+ context.start = afterFinally;
+ m_tryContextStack.append(context);
+ }
+ }
if (flipLabelScopes)
m_labelScopes = savedLabelScopes;
m_finallyDepth = savedFinallyDepth;
@@ -2361,42 +2452,61 @@ RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID*
return dst;
}
-RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end)
+TryData* BytecodeGenerator::pushTry(Label* start)
+{
+ TryData tryData;
+ tryData.target = newLabel();
+ tryData.targetScopeDepth = UINT_MAX;
+ m_tryData.append(tryData);
+ TryData* result = &m_tryData.last();
+
+ TryContext tryContext;
+ tryContext.start = start;
+ tryContext.tryData = result;
+
+ m_tryContextStack.append(tryContext);
+
+ return result;
+}
+
+RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* targetRegister, Label* end)
{
m_usesExceptions = true;
-#if ENABLE(JIT)
-#if ENABLE(LLINT)
- HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(bitwise_cast<void*>(&llint_op_catch))) };
-#else
- HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() };
-#endif
-#else
- HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth };
-#endif
+
+ ASSERT_UNUSED(tryData, m_tryContextStack.last().tryData == tryData);
+
+ TryRange tryRange;
+ tryRange.start = m_tryContextStack.last().start;
+ tryRange.end = end;
+ tryRange.tryData = m_tryContextStack.last().tryData;
+ m_tryRanges.append(tryRange);
+ m_tryContextStack.removeLast();
+
+ emitLabel(tryRange.tryData->target.get());
+ tryRange.tryData->targetScopeDepth = m_dynamicScopeDepth + m_baseScopeDepth;
- m_codeBlock->addExceptionHandler(info);
emitOpcode(op_catch);
instructions().append(targetRegister->index());
return targetRegister;
}
-void BytecodeGenerator::emitThrowReferenceError(const UString& message)
+void BytecodeGenerator::emitThrowReferenceError(const String& message)
{
emitOpcode(op_throw_reference_error);
instructions().append(addConstantValue(jsString(globalData(), message))->index());
}
-void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value)
+void BytecodeGenerator::emitPushNameScope(const Identifier& property, RegisterID* value, unsigned attributes)
{
ControlFlowContext context;
context.isFinallyBlock = false;
m_scopeContextStack.append(context);
m_dynamicScopeDepth++;
- emitOpcode(op_push_new_scope);
- instructions().append(dst->index());
+ emitOpcode(op_push_name_scope);
instructions().append(addConstant(property));
instructions().append(value->index());
+ instructions().append(attributes);
}
void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
@@ -2537,4 +2647,13 @@ bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNu
return registerID->index() == CallFrame::argumentOffset(argumentNumber);
}
+void BytecodeGenerator::emitReadOnlyExceptionIfNeeded()
+{
+ if (!isStrictMode())
+ return;
+
+ RefPtr<RegisterID> error = emitLoad(newTemporary(), JSValue(createTypeError(scope()->globalObject()->globalExec(), StrictModeReadonlyPropertyWriteError)));
+ emitThrow(error.get());
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 9c094414d..037a2ce25 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -49,7 +49,7 @@ namespace JSC {
class Identifier;
class Label;
- class ScopeChainNode;
+ class JSScope;
class CallArguments {
public:
@@ -75,6 +75,7 @@ namespace JSC {
unsigned scopeContextStackSize;
unsigned switchContextStackSize;
unsigned forInContextStackSize;
+ unsigned tryContextStackSize;
unsigned labelScopesSize;
int finallyDepth;
int dynamicScopeDepth;
@@ -92,6 +93,22 @@ namespace JSC {
RefPtr<RegisterID> propertyRegister;
};
+ struct TryData {
+ RefPtr<Label> target;
+ unsigned targetScopeDepth;
+ };
+
+ struct TryContext {
+ RefPtr<Label> start;
+ TryData* tryData;
+ };
+
+ struct TryRange {
+ RefPtr<Label> start;
+ RefPtr<Label> end;
+ TryData* tryData;
+ };
+
class ResolveResult {
public:
enum Flags {
@@ -244,9 +261,9 @@ namespace JSC {
JS_EXPORT_PRIVATE static void setDumpsGeneratedCode(bool dumpsGeneratedCode);
static bool dumpsGeneratedCode();
- BytecodeGenerator(ProgramNode*, ScopeChainNode*, SymbolTable*, ProgramCodeBlock*, CompilationKind);
- BytecodeGenerator(FunctionBodyNode*, ScopeChainNode*, SymbolTable*, CodeBlock*, CompilationKind);
- BytecodeGenerator(EvalNode*, ScopeChainNode*, SymbolTable*, EvalCodeBlock*, CompilationKind);
+ BytecodeGenerator(ProgramNode*, JSScope*, SymbolTable*, ProgramCodeBlock*, CompilationKind);
+ BytecodeGenerator(FunctionBodyNode*, JSScope*, SymbolTable*, CodeBlock*, CompilationKind);
+ BytecodeGenerator(EvalNode*, JSScope*, SymbolTable*, EvalCodeBlock*, CompilationKind);
~BytecodeGenerator();
@@ -279,8 +296,6 @@ namespace JSC {
// the next instruction may overwrite it.
RegisterID* newTemporary();
- RegisterID* highestUsedRegister();
-
// The same as newTemporary(), but this function returns "suggestion" if
// "suggestion" is a temporary. This function is helpful in situations
// where you've put "suggestion" in a RefPtr, but you'd like to allow
@@ -492,18 +507,24 @@ namespace JSC {
RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget);
RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target);
- RegisterID* emitCatch(RegisterID*, Label* start, Label* end);
+ void emitReadOnlyExceptionIfNeeded();
+
+ // Start a try block. 'start' must have been emitted.
+ TryData* pushTry(Label* start);
+ // End a try block. 'end' must have been emitted.
+ RegisterID* popTryAndEmitCatch(TryData*, RegisterID* targetRegister, Label* end);
+
void emitThrow(RegisterID* exc)
{
m_usesExceptions = true;
emitUnaryNoDstOp(op_throw, exc);
}
- void emitThrowReferenceError(const UString& message);
+ void emitThrowReferenceError(const String& message);
- void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value);
+ void emitPushNameScope(const Identifier& property, RegisterID* value, unsigned attributes);
- RegisterID* emitPushScope(RegisterID* scope);
+ RegisterID* emitPushWithScope(RegisterID* scope);
void emitPopScope();
void emitDebugHook(DebugHookID, int firstLine, int lastLine, int column);
@@ -537,7 +558,7 @@ namespace JSC {
bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
- ScopeChainNode* scopeChain() const { return m_scopeChain.get(); }
+ JSScope* scope() const { return m_scope.get(); }
private:
friend class Label;
@@ -596,7 +617,9 @@ namespace JSC {
int addGlobalVar(const Identifier&, ConstantMode, FunctionMode);
void addParameter(const Identifier&, int parameterIndex);
-
+ RegisterID* resolveCallee(FunctionBodyNode*);
+ void addCallee(FunctionBodyNode*, RegisterID*);
+
void preserveLastVar();
bool shouldAvoidResolveGlobal();
@@ -605,6 +628,9 @@ namespace JSC {
if (index >= 0)
return m_calleeRegisters[index];
+ if (index == RegisterFile::Callee)
+ return m_calleeRegister;
+
ASSERT(m_parameters.size());
return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize];
}
@@ -615,16 +641,6 @@ namespace JSC {
unsigned addConstantBuffer(unsigned length);
- FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body)
- {
- return FunctionExecutable::create(exec, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
- }
-
- FunctionExecutable* makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
- {
- return FunctionExecutable::create(*globalData, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
- }
-
JSString* addStringConstant(const Identifier&);
void addLineInfo(unsigned lineNo)
@@ -634,7 +650,9 @@ namespace JSC {
RegisterID* emitInitLazyRegister(RegisterID*);
+ public:
Vector<Instruction>& instructions() { return m_instructions; }
+
SymbolTable& symbolTable() { return *m_symbolTable; }
#if ENABLE(BYTECODE_COMMENTS)
Vector<Comment>& comments() { return m_comments; }
@@ -677,7 +695,7 @@ namespace JSC {
bool m_shouldEmitProfileHooks;
bool m_shouldEmitRichSourceInfo;
- Strong<ScopeChainNode> m_scopeChain;
+ Strong<JSScope> m_scope;
SymbolTable* m_symbolTable;
#if ENABLE(BYTECODE_COMMENTS)
@@ -693,6 +711,7 @@ namespace JSC {
HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions;
RegisterID m_ignoredResultRegister;
RegisterID m_thisRegister;
+ RegisterID m_calleeRegister;
RegisterID* m_activationRegister;
SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
SegmentedVector<RegisterID, 32> m_calleeRegisters;
@@ -708,6 +727,10 @@ namespace JSC {
Vector<ControlFlowContext> m_scopeContextStack;
Vector<SwitchInfo> m_switchContextStack;
Vector<ForInContext> m_forInContextStack;
+ Vector<TryContext> m_tryContextStack;
+
+ Vector<TryRange> m_tryRanges;
+ SegmentedVector<TryData, 8> m_tryData;
int m_firstConstantIndex;
int m_nextConstantOffset;
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 249f822e2..63f4657c9 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -34,7 +34,7 @@
#include "JIT.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
-#include "JSStaticScopeObject.h"
+#include "JSNameScope.h"
#include "LabelScope.h"
#include "Lexer.h"
#include "Operations.h"
@@ -43,7 +43,6 @@
#include "RegExpCache.h"
#include "RegExpObject.h"
#include "SamplingTool.h"
-#include "UStringConcatenate.h"
#include <wtf/Assertions.h>
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/Threading.h>
@@ -77,7 +76,7 @@ namespace JSC {
// ------------------------------ ThrowableExpressionData --------------------------------
-RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const UString& message)
+RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const String& message)
{
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
generator.emitThrowReferenceError(message);
@@ -126,7 +125,7 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
{
if (dst == generator.ignoredResult())
return 0;
- return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.globalData(), m_pattern.ustring(), regExpFlags(m_flags.ustring())));
+ return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.globalData(), m_pattern.string(), regExpFlags(m_flags.string())));
}
// ------------------------------ ThisNode -------------------------------------
@@ -591,7 +590,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
return finalDestinationOrIgnored.get();
}
-// ------------------------------ PostfixResolveNode ----------------------------------
+// ------------------------------ PostfixNode ----------------------------------
static RegisterID* emitPreIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper)
{
@@ -605,14 +604,17 @@ static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* ds
return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst);
}
-RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst)
{
- ResolveResult resolveResult = generator.resolve(m_ident);
+ ASSERT(m_expr->isResolveNode());
+ ResolveNode* resolve = static_cast<ResolveNode*>(m_expr);
+ const Identifier& ident = resolve->identifier();
+
+ ResolveResult resolveResult = generator.resolve(ident);
if (RegisterID* local = resolveResult.local()) {
if (resolveResult.isReadOnly()) {
- if (dst == generator.ignoredResult())
- return 0;
+ generator.emitReadOnlyExceptionIfNeeded();
return generator.emitToJSNumber(generator.finalDestination(dst), local);
}
if (dst == generator.ignoredResult())
@@ -621,83 +623,88 @@ RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, Regis
}
if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
- RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, m_ident);
+ RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, ident);
RegisterID* oldValue;
if (dst == generator.ignoredResult()) {
oldValue = 0;
emitPreIncOrDec(generator, value.get(), m_operator);
- } else {
+ } else
oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
- }
- generator.emitPutStaticVar(resolveResult, m_ident, value.get());
+ generator.emitPutStaticVar(resolveResult, ident, value.get());
return oldValue;
}
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RefPtr<RegisterID> value = generator.newTemporary();
- RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, ident);
RegisterID* oldValue;
if (dst == generator.ignoredResult()) {
oldValue = 0;
emitPreIncOrDec(generator, value.get(), m_operator);
- } else {
+ } else
oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
- }
- generator.emitPutById(base.get(), m_ident, value.get());
+ generator.emitPutById(base.get(), ident, value.get());
return oldValue;
}
-// ------------------------------ PostfixBracketNode ----------------------------------
-
-RegisterID* PostfixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst)
{
- RefPtr<RegisterID> base = generator.emitNode(m_base);
- RefPtr<RegisterID> property = generator.emitNode(m_subscript);
+ ASSERT(m_expr->isBracketAccessorNode());
+ BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr);
+ ExpressionNode* baseNode = bracketAccessor->base();
+ ExpressionNode* subscript = bracketAccessor->subscript();
- generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(baseNode, bracketAccessor->subscriptHasAssignments(), subscript->isPure(generator));
+ RefPtr<RegisterID> property = generator.emitNode(subscript);
+
+ generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->startOffset(), bracketAccessor->endOffset());
RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
- RegisterID* oldValue;
if (dst == generator.ignoredResult()) {
- oldValue = 0;
- if (m_operator == OpPlusPlus)
- generator.emitPreInc(value.get());
- else
- generator.emitPreDec(value.get());
- } else {
- oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get());
+ emitPreIncOrDec(generator, value.get(), m_operator);
+ generator.emitExpressionInfo(divot(), startOffset(), endOffset());
+ generator.emitPutByVal(base.get(), property.get(), value.get());
+ return 0;
}
+ RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
generator.emitPutByVal(base.get(), property.get(), value.get());
- return oldValue;
+ return generator.moveToDestinationIfNeeded(dst, oldValue);
}
-// ------------------------------ PostfixDotNode ----------------------------------
-
-RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst)
{
- RefPtr<RegisterID> base = generator.emitNode(m_base);
+ ASSERT(m_expr->isDotAccessorNode());
+ DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr);
+ ExpressionNode* baseNode = dotAccessor->base();
+ const Identifier& ident = dotAccessor->identifier();
- generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
- RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
- RegisterID* oldValue;
+ RefPtr<RegisterID> base = generator.emitNode(baseNode);
+
+ generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->startOffset(), dotAccessor->endOffset());
+ RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), ident);
if (dst == generator.ignoredResult()) {
- oldValue = 0;
- if (m_operator == OpPlusPlus)
- generator.emitPreInc(value.get());
- else
- generator.emitPreDec(value.get());
- } else {
- oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get());
+ emitPreIncOrDec(generator, value.get(), m_operator);
+ generator.emitExpressionInfo(divot(), startOffset(), endOffset());
+ generator.emitPutById(base.get(), ident, value.get());
+ return 0;
}
+ RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
- generator.emitPutById(base.get(), m_ident, value.get());
- return oldValue;
+ generator.emitPutById(base.get(), ident, value.get());
+ return generator.moveToDestinationIfNeeded(dst, oldValue);
}
-// ------------------------------ PostfixErrorNode -----------------------------------
-
-RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
+RegisterID* PostfixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
+ if (m_expr->isResolveNode())
+ return emitResolve(generator, dst);
+
+ if (m_expr->isBracketAccessorNode())
+ return emitBracket(generator, dst);
+
+ if (m_expr->isDotAccessorNode())
+ return emitDot(generator, dst);
+
return emitThrowReferenceError(generator, m_operator == OpPlusPlus
? "Postfix ++ operator applied to value that is not a reference."
: "Postfix -- operator applied to value that is not a reference.");
@@ -789,78 +796,91 @@ RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, Register
return generator.emitTypeOf(generator.finalDestination(dst), src.get());
}
-// ------------------------------ PrefixResolveNode ----------------------------------
+// ------------------------------ PrefixNode ----------------------------------
-RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst)
{
- ResolveResult resolveResult = generator.resolve(m_ident);
+ ASSERT(m_expr->isResolveNode());
+ ResolveNode* resolve = static_cast<ResolveNode*>(m_expr);
+ const Identifier& ident = resolve->identifier();
+
+ ResolveResult resolveResult = generator.resolve(ident);
if (RegisterID* local = resolveResult.local()) {
if (resolveResult.isReadOnly()) {
+ generator.emitReadOnlyExceptionIfNeeded();
if (dst == generator.ignoredResult())
- return 0;
- RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0);
- return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes());
+ return generator.emitToJSNumber(generator.newTemporary(), local);
+ RefPtr<RegisterID> r0 = generator.emitLoad(generator.tempDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0);
+ generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes());
+ return generator.moveToDestinationIfNeeded(dst, r0.get());
}
emitPreIncOrDec(generator, local, m_operator);
return generator.moveToDestinationIfNeeded(dst, local);
}
if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
- RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
+ RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, ident);
emitPreIncOrDec(generator, propDst.get(), m_operator);
- generator.emitPutStaticVar(resolveResult, m_ident, propDst.get());
+ generator.emitPutStaticVar(resolveResult, ident, propDst.get());
return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RefPtr<RegisterID> propDst = generator.tempDestination(dst);
- RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, ident);
emitPreIncOrDec(generator, propDst.get(), m_operator);
- generator.emitPutById(base.get(), m_ident, propDst.get());
+ generator.emitPutById(base.get(), ident, propDst.get());
return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
-// ------------------------------ PrefixBracketNode ----------------------------------
-
-RegisterID* PrefixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+RegisterID* PrefixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst)
{
- RefPtr<RegisterID> base = generator.emitNode(m_base);
- RefPtr<RegisterID> property = generator.emitNode(m_subscript);
+ ASSERT(m_expr->isBracketAccessorNode());
+ BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr);
+ ExpressionNode* baseNode = bracketAccessor->base();
+ ExpressionNode* subscript = bracketAccessor->subscript();
+
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(baseNode, bracketAccessor->subscriptHasAssignments(), subscript->isPure(generator));
+ RefPtr<RegisterID> property = generator.emitNode(subscript);
RefPtr<RegisterID> propDst = generator.tempDestination(dst);
- generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset);
+ generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->startOffset(), bracketAccessor->endOffset());
RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
- if (m_operator == OpPlusPlus)
- generator.emitPreInc(value);
- else
- generator.emitPreDec(value);
+ emitPreIncOrDec(generator, value, m_operator);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
generator.emitPutByVal(base.get(), property.get(), value);
return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
-// ------------------------------ PrefixDotNode ----------------------------------
-
-RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst)
{
- RefPtr<RegisterID> base = generator.emitNode(m_base);
+ ASSERT(m_expr->isDotAccessorNode());
+ DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr);
+ ExpressionNode* baseNode = dotAccessor->base();
+ const Identifier& ident = dotAccessor->identifier();
+
+ RefPtr<RegisterID> base = generator.emitNode(baseNode);
RefPtr<RegisterID> propDst = generator.tempDestination(dst);
- generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset);
- RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident);
- if (m_operator == OpPlusPlus)
- generator.emitPreInc(value);
- else
- generator.emitPreDec(value);
+ generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->startOffset(), dotAccessor->endOffset());
+ RegisterID* value = generator.emitGetById(propDst.get(), base.get(), ident);
+ emitPreIncOrDec(generator, value, m_operator);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
- generator.emitPutById(base.get(), m_ident, value);
+ generator.emitPutById(base.get(), ident, value);
return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
-// ------------------------------ PrefixErrorNode -----------------------------------
-
-RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
+RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
+ if (m_expr->isResolveNode())
+ return emitResolve(generator, dst);
+
+ if (m_expr->isBracketAccessorNode())
+ return emitBracket(generator, dst);
+
+ if (m_expr->isDotAccessorNode())
+ return emitDot(generator, dst);
+
return emitThrowReferenceError(generator, m_operator == OpPlusPlus
? "Prefix ++ operator applied to value that is not a reference."
: "Prefix -- operator applied to value that is not a reference.");
@@ -1213,8 +1233,10 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
ResolveResult resolveResult = generator.resolve(m_ident);
if (RegisterID *local = resolveResult.local()) {
- if (resolveResult.isReadOnly())
+ if (resolveResult.isReadOnly()) {
+ generator.emitReadOnlyExceptionIfNeeded();
return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
+ }
if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
RefPtr<RegisterID> result = generator.newTemporary();
@@ -1249,8 +1271,10 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
ResolveResult resolveResult = generator.resolve(m_ident);
if (RegisterID *local = resolveResult.local()) {
- if (resolveResult.isReadOnly())
+ if (resolveResult.isReadOnly()) {
+ generator.emitReadOnlyExceptionIfNeeded();
return generator.emitNode(dst, m_right);
+ }
RegisterID* result = generator.emitNode(local, m_right);
return generator.moveToDestinationIfNeeded(dst, result);
}
@@ -1757,11 +1781,10 @@ RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
RegisterID* WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column());
-
- RefPtr<RegisterID> scope = generator.newTemporary();
- generator.emitNode(scope.get(), m_expr); // scope must be protected until popped
+
+ RefPtr<RegisterID> scope = generator.emitNode(m_expr);
generator.emitExpressionInfo(m_divot, m_expressionLength, 0);
- generator.emitPushScope(scope.get());
+ generator.emitPushWithScope(scope.get());
RegisterID* result = generator.emitNode(dst, m_statement);
generator.emitPopScope();
return result;
@@ -1808,7 +1831,7 @@ static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>&
typeForTable = SwitchNeither;
break;
}
- const UString& value = static_cast<StringNode*>(clauseExpression)->value().ustring();
+ const String& value = static_cast<StringNode*>(clauseExpression)->value().string();
if (singleCharacterSwitch &= value.length() == 1) {
int32_t intVal = value[0];
if (intVal < min_num)
@@ -1970,11 +1993,15 @@ RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column());
+ ASSERT(m_catchBlock || m_finallyBlock);
+
RefPtr<Label> tryStartLabel = generator.newLabel();
+ generator.emitLabel(tryStartLabel.get());
+
if (m_finallyBlock)
generator.pushFinallyContext(m_finallyBlock);
+ TryData* tryData = generator.pushTry(tryStartLabel.get());
- generator.emitLabel(tryStartLabel.get());
generator.emitNode(dst, m_tryBlock);
if (m_catchBlock) {
@@ -1985,14 +2012,23 @@ RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
// Uncaught exception path: the catch block.
RefPtr<Label> here = generator.emitLabel(generator.newLabel().get());
- RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get());
- generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get());
+ RefPtr<RegisterID> exceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), here.get());
+
+ if (m_finallyBlock) {
+ // If the catch block throws an exception and we have a finally block, then the finally
+ // block should "catch" that exception.
+ tryData = generator.pushTry(here.get());
+ }
+
+ generator.emitPushNameScope(m_exceptionIdent, exceptionRegister.get(), DontDelete);
generator.emitNode(dst, m_catchBlock);
generator.emitPopScope();
generator.emitLabel(catchEndLabel.get());
}
if (m_finallyBlock) {
+ RefPtr<Label> preFinallyLabel = generator.emitLabel(generator.newLabel().get());
+
generator.popFinallyContext();
RefPtr<Label> finallyEndLabel = generator.newLabel();
@@ -2002,8 +2038,7 @@ RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
generator.emitJump(finallyEndLabel.get());
// Uncaught exception path: invoke the finally block, then re-throw the exception.
- RefPtr<Label> here = generator.emitLabel(generator.newLabel().get());
- RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get());
+ RefPtr<RegisterID> tempExceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), preFinallyLabel.get());
generator.emitNode(dst, m_finallyBlock);
generator.emitThrow(tempExceptionRegister.get());