diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-09-10 19:10:20 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-09-10 19:10:20 +0200 |
commit | 284837daa07b29d6a63a748544a90b1f5842ac5c (patch) | |
tree | ecd258180bde91fe741e0cfd2638beb3c6da7e8e /Source/JavaScriptCore/bytecompiler | |
parent | 2e2ba8ff45915f40ed3e014101269c175f2a89a0 (diff) | |
download | qtwebkit-284837daa07b29d6a63a748544a90b1f5842ac5c.tar.gz |
Imported WebKit commit 68645295d2e3e09af2c942f092556f06aa5f8b0d (http://svn.webkit.org/repository/webkit/trunk@128073)
New snapshot
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
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()); |