diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/JavaScriptCore/bytecompiler | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp | 534 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h | 234 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/Label.h | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/LabelScope.h | 67 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp | 835 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/StaticPropertyAnalysis.h | 67 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/StaticPropertyAnalyzer.h | 170 |
7 files changed, 1154 insertions, 755 deletions
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 507241696..b4e3d3de8 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * Copyright (C) 2012 Igalia, S.L. * @@ -32,95 +32,21 @@ #include "BytecodeGenerator.h" #include "BatchedTransitionOptimizer.h" -#include "Comment.h" #include "Interpreter.h" #include "JSActivation.h" #include "JSFunction.h" #include "JSNameScope.h" #include "LowLevelInterpreter.h" +#include "Operations.h" #include "Options.h" #include "StrongInlines.h" +#include "UnlinkedCodeBlock.h" #include <wtf/text/WTFString.h> using namespace std; namespace JSC { -/* - The layout of a register frame looks like this: - - For - - function f(x, y) { - var v1; - function g() { } - var v2; - return (x) * (y); - } - - assuming (x) and (y) generated temporaries t1 and t2, you would have - - ------------------------------------ - | x | y | g | v2 | v1 | t1 | t2 | <-- value held - ------------------------------------ - | -5 | -4 | -3 | -2 | -1 | +0 | +1 | <-- register index - ------------------------------------ - | params->|<-locals | temps-> - - Because temporary registers are allocated in a stack-like fashion, we - can reclaim them with a simple popping algorithm. The same goes for labels. - (We never reclaim parameter or local registers, because parameters and - locals are DontDelete.) - - The register layout before a function call looks like this: - - For - - function f(x, y) - { - } - - f(1); - - > <------------------------------ - < > reserved: call frame | 1 | <-- value held - > >snip< <------------------------------ - < > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index - > <------------------------------ - | params->|<-locals | temps-> - - The call instruction fills in the "call frame" registers. It also pads - missing arguments at the end of the call: - - > <----------------------------------- - < > reserved: call frame | 1 | ? | <-- value held ("?" stands for "undefined") - > >snip< <----------------------------------- - < > +0 | +1 | +2 | +3 | +4 | +5 | +6 | <-- register index - > <----------------------------------- - | params->|<-locals | temps-> - - After filling in missing arguments, the call instruction sets up the new - stack frame to overlap the end of the old stack frame: - - |----------------------------------> < - | reserved: call frame | 1 | ? < > <-- value held ("?" stands for "undefined") - |----------------------------------> >snip< < - | -7 | -6 | -5 | -4 | -3 | -2 | -1 < > <-- register index - |----------------------------------> < - | | params->|<-locals | temps-> - - That way, arguments are "copied" into the callee's stack frame for free. - - If the caller supplies too many arguments, this trick doesn't work. The - extra arguments protrude into space reserved for locals and temporaries. - In that case, the call instruction makes a real copy of the call frame header, - along with just the arguments expected by the callee, leaving the original - call frame header and arguments behind. (The call instruction can't just discard - extra arguments, because the "arguments" object may access them later.) - This copying strategy ensures that all named values will be at the indices - expected by the callee. -*/ - void Label::setLocation(unsigned location) { m_location = location; @@ -141,8 +67,12 @@ void ResolveResult::checkValidity() case Dynamic: ASSERT(!m_local); return; + case Lexical: + case ReadOnlyLexical: + ASSERT(!m_local); + return; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } #endif @@ -154,7 +84,9 @@ ParserError BytecodeGenerator::generate() m_codeBlock->setThisRegister(m_thisRegister.index()); m_scopeNode->emitBytecode(*this); - + + m_staticPropertyAnalyzer.kill(); + for (unsigned i = 0; i < m_tryRanges.size(); ++i) { TryRange& range = m_tryRanges[i]; int start = range.start->bind(); @@ -199,8 +131,8 @@ ParserError BytecodeGenerator::generate() m_codeBlock->shrinkToFit(); if (m_expressionTooDeep) - return ParserError::OutOfMemory; - return ParserError::ErrorNone; + return ParserError(ParserError::OutOfMemory); + return ParserError(ParserError::ErrorNone); } bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0) @@ -224,17 +156,15 @@ void BytecodeGenerator::preserveLastVar() m_lastVar = &m_calleeRegisters.last(); } -BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) +BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope*, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn) , m_shouldEmitProfileHooks(profilerMode == ProfilerOn) -#if ENABLE(BYTECODE_COMMENTS) - , m_currentCommentString(0) -#endif , m_symbolTable(0) , m_scopeNode(programNode) - , m_codeBlock(globalData, codeBlock) + , m_codeBlock(vm, codeBlock) , m_thisRegister(CallFrame::thisArgumentOffset()) , m_emptyValueRegister(0) + , m_globalObjectRegister(0) , m_finallyDepth(0) , m_dynamicScopeDepth(0) , m_codeType(GlobalCode) @@ -243,12 +173,13 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog , m_hasCreatedActivation(true) , m_firstLazyFunction(0) , m_lastLazyFunction(0) - , m_globalData(&globalData) + , m_staticPropertyAnalyzer(&m_instructions) + , m_vm(&vm) , m_lastOpcodeID(op_end) #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(wtfThreadData().stack()) + , m_stack(vm, wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -257,7 +188,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog m_codeBlock->setNumParameters(1); // Allocate space for "this" - prependComment("entering Program block"); emitOpcode(op_enter); const VarStack& varStack = programNode->varStack(); @@ -266,7 +196,7 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog for (size_t i = 0; i < functionStack.size(); ++i) { FunctionBodyNode* function = functionStack[i]; UnlinkedFunctionExecutable* unlinkedFunction = makeFunction(function); - codeBlock->addFunctionDeclaration(*m_globalData, function->ident(), unlinkedFunction); + codeBlock->addFunctionDeclaration(*m_vm, function->ident(), unlinkedFunction); } for (size_t i = 0; i < varStack.size(); ++i) @@ -274,17 +204,16 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog } -BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) +BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope* scope, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn) , m_shouldEmitProfileHooks(profilerMode == ProfilerOn) , m_symbolTable(codeBlock->symbolTable()) -#if ENABLE(BYTECODE_COMMENTS) - , m_currentCommentString(0) -#endif , m_scopeNode(functionBody) - , m_codeBlock(globalData, codeBlock) + , m_scope(vm, scope) + , m_codeBlock(vm, codeBlock) , m_activationRegister(0) , m_emptyValueRegister(0) + , m_globalObjectRegister(0) , m_finallyDepth(0) , m_dynamicScopeDepth(0) , m_codeType(FunctionCode) @@ -293,12 +222,13 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* , m_hasCreatedActivation(false) , m_firstLazyFunction(0) , m_lastLazyFunction(0) - , m_globalData(&globalData) + , m_staticPropertyAnalyzer(&m_instructions) + , m_vm(&vm) , m_lastOpcodeID(op_end) #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(wtfThreadData().stack()) + , m_stack(vm, wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -308,11 +238,9 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()); m_symbolTable->setParameterCountIncludingThis(functionBody->parameters()->size() + 1); - prependComment("entering Function block"); emitOpcode(op_enter); if (m_codeBlock->needsFullScopeChain()) { m_activationRegister = addVar(); - prependComment("activation for Full Scope Chain"); emitInitLazyRegister(m_activationRegister); m_codeBlock->setActivationRegister(m_activationRegister->index()); } @@ -329,13 +257,10 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* codeBlock->setArgumentsRegister(argumentsRegister->index()); ASSERT_UNUSED(unmodifiedArgumentsRegister, unmodifiedArgumentsRegister->index() == JSC::unmodifiedArgumentsRegister(codeBlock->argumentsRegister())); - prependComment("arguments for Full Scope Chain"); emitInitLazyRegister(argumentsRegister); - prependComment("unmodified arguments for Full Scope Chain"); emitInitLazyRegister(unmodifiedArgumentsRegister); if (m_codeBlock->isStrictMode()) { - prependComment("create arguments for strict mode"); emitOpcode(op_create_arguments); instructions().append(argumentsRegister->index()); } @@ -344,7 +269,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* // it from a call frame. In the long-term it should stop doing that (<rdar://problem/6911886>), // but for now we force eager creation of the arguments object when debugging. if (m_shouldEmitDebugHooks) { - prependComment("create arguments for debug hooks"); emitOpcode(op_create_arguments); instructions().append(argumentsRegister->index()); } @@ -353,13 +277,13 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* bool shouldCaptureAllTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval(); bool capturesAnyArgumentByName = false; - Vector<RegisterID*> capturedArguments; + Vector<RegisterID*, 0, UnsafeVectorOverflow> capturedArguments; if (functionBody->hasCapturedVariables() || shouldCaptureAllTheThings) { FunctionParameters& parameters = *functionBody->parameters(); capturedArguments.resize(parameters.size()); for (size_t i = 0; i < parameters.size(); ++i) { capturedArguments[i] = 0; - if (!functionBody->captures(parameters[i]) && !shouldCaptureAllTheThings) + if (!functionBody->captures(parameters.at(i)) && !shouldCaptureAllTheThings) continue; capturesAnyArgumentByName = true; capturedArguments[i] = addVar(); @@ -396,12 +320,10 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* if (functionBody->captures(ident)) { if (!m_hasCreatedActivation) { m_hasCreatedActivation = true; - prependComment("activation for captured vars"); emitOpcode(op_create_activation); instructions().append(m_activationRegister->index()); } m_functions.add(ident.impl()); - prependComment("captured function var"); emitNewFunction(addVar(ident, false), function); } } @@ -414,7 +336,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks; if (!canLazilyCreateFunctions && !m_hasCreatedActivation) { m_hasCreatedActivation = true; - prependComment("cannot lazily create functions"); emitOpcode(op_create_activation); instructions().append(m_activationRegister->index()); } @@ -430,7 +351,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* RefPtr<RegisterID> reg = addVar(ident, false); // Don't lazily create functions that override the name 'arguments' // as this would complicate lazy instantiation of actual arguments. - prependComment("a function that override 'arguments'"); if (!canLazilyCreateFunctions || ident == propertyNames().arguments) emitNewFunction(reg.get(), function); else { @@ -460,12 +380,12 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* for (size_t i = 0; i < parameters.size(); ++i, --nextParameterIndex) { int index = nextParameterIndex; if (capturedArguments.size() && capturedArguments[i]) { - ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters[i])) || shouldCaptureAllTheThings); + ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters.at(i))) || shouldCaptureAllTheThings); index = capturedArguments[i]->index(); RegisterID original(nextParameterIndex); emitMove(capturedArguments[i], &original); } - addParameter(parameters[i], index); + addParameter(parameters.at(i), index); } preserveLastVar(); @@ -473,35 +393,24 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* addCallee(functionBody, calleeRegister); if (isConstructor()) { - prependComment("'this' because we are a Constructor function"); - - RefPtr<RegisterID> func = newTemporary(); - - UnlinkedValueProfile profile = emitProfiledOpcode(op_get_callee); - instructions().append(func->index()); - instructions().append(profile); - - emitOpcode(op_create_this); - instructions().append(m_thisRegister.index()); - instructions().append(func->index()); + emitCreateThis(&m_thisRegister); } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) { UnlinkedValueProfile profile = emitProfiledOpcode(op_convert_this); - instructions().append(m_thisRegister.index()); + instructions().append(kill(&m_thisRegister)); instructions().append(profile); } } -BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) +BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope* scope, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn) , m_shouldEmitProfileHooks(profilerMode == ProfilerOn) , m_symbolTable(codeBlock->symbolTable()) -#if ENABLE(BYTECODE_COMMENTS) - , m_currentCommentString(0) -#endif , m_scopeNode(evalNode) - , m_codeBlock(globalData, codeBlock) + , m_scope(vm, scope) + , m_codeBlock(vm, codeBlock) , m_thisRegister(CallFrame::thisArgumentOffset()) , m_emptyValueRegister(0) + , m_globalObjectRegister(0) , m_finallyDepth(0) , m_dynamicScopeDepth(0) , m_codeType(EvalCode) @@ -510,12 +419,13 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNod , m_hasCreatedActivation(true) , m_firstLazyFunction(0) , m_lastLazyFunction(0) - , m_globalData(&globalData) + , m_staticPropertyAnalyzer(&m_instructions) + , m_vm(&vm) , m_lastOpcodeID(op_end) #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(wtfThreadData().stack()) + , m_stack(vm, wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -524,7 +434,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNod m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()); m_codeBlock->setNumParameters(1); - prependComment("entering Eval block"); emitOpcode(op_enter); const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack(); @@ -533,7 +442,7 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNod const DeclarationStacks::VarStack& varStack = evalNode->varStack(); unsigned numVariables = varStack.size(); - Vector<Identifier> variables; + Vector<Identifier, 0, UnsafeVectorOverflow> variables; variables.reserveCapacity(numVariables); for (size_t i = 0; i < numVariables; ++i) variables.append(*varStack[i].first); @@ -656,7 +565,7 @@ RegisterID* BytecodeGenerator::newTemporary() return result; } -PassRefPtr<LabelScope> BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name) +LabelScopePtr BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name) { // Reclaim free label scopes. while (m_labelScopes.size() && !m_labelScopes.last().refCount()) @@ -665,7 +574,7 @@ PassRefPtr<LabelScope> BytecodeGenerator::newLabelScope(LabelScope::Type type, c // Allocate new label scope. LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : PassRefPtr<Label>()); // Only loops have continue targets. m_labelScopes.append(scope); - return &m_labelScopes.last(); + return LabelScopePtr(&m_labelScopes, m_labelScopes.size() - 1); } PassRefPtr<Label> BytecodeGenerator::newLabel() @@ -707,31 +616,10 @@ void BytecodeGenerator::emitOpcode(OpcodeID opcodeID) ASSERT(opcodePosition - m_lastOpcodePosition == opcodeLength(m_lastOpcodeID) || m_lastOpcodeID == op_end); m_lastOpcodePosition = opcodePosition; #endif - emitComment(); instructions().append(opcodeID); m_lastOpcodeID = opcodeID; } -#if ENABLE(BYTECODE_COMMENTS) -// Record a comment in the CodeBlock's comments list for the current opcode -// that is about to be emitted. -void BytecodeGenerator::emitComment() -{ - if (m_currentCommentString) { - size_t opcodePosition = instructions().size(); - Comment comment = { opcodePosition, m_currentCommentString }; - m_codeBlock->bytecodeComments().append(comment); - m_currentCommentString = 0; - } -} - -// Register a comment to be associated with the next opcode that will be emitted. -void BytecodeGenerator::prependComment(const char* string) -{ - m_currentCommentString = string; -} -#endif - UnlinkedArrayProfile BytecodeGenerator::newArrayProfile() { #if ENABLE(VALUE_PROFILER) @@ -750,6 +638,11 @@ UnlinkedArrayAllocationProfile BytecodeGenerator::newArrayAllocationProfile() #endif } +UnlinkedObjectAllocationProfile BytecodeGenerator::newObjectAllocationProfile() +{ + return m_codeBlock->addObjectAllocationProfile(); +} + UnlinkedValueProfile BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID) { #if ENABLE(VALUE_PROFILER) @@ -763,9 +656,7 @@ UnlinkedValueProfile BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID) void BytecodeGenerator::emitLoopHint() { -#if ENABLE(DFG_JIT) emitOpcode(op_loop_hint); -#endif } void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index) @@ -802,7 +693,7 @@ void ALWAYS_INLINE BytecodeGenerator::rewindUnaryOp() PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target) { size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jmp : op_loop); + emitOpcode(op_jmp); instructions().append(target->bind(begin, instructions().size())); return target; } @@ -820,7 +711,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar rewindBinaryOp(); size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jless : op_loop_if_less); + emitOpcode(op_jless); instructions().append(src1Index); instructions().append(src2Index); instructions().append(target->bind(begin, instructions().size())); @@ -837,7 +728,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar rewindBinaryOp(); size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jlesseq : op_loop_if_lesseq); + emitOpcode(op_jlesseq); instructions().append(src1Index); instructions().append(src2Index); instructions().append(target->bind(begin, instructions().size())); @@ -854,7 +745,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar rewindBinaryOp(); size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jgreater : op_loop_if_greater); + emitOpcode(op_jgreater); instructions().append(src1Index); instructions().append(src2Index); instructions().append(target->bind(begin, instructions().size())); @@ -871,7 +762,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar rewindBinaryOp(); size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jgreatereq : op_loop_if_greatereq); + emitOpcode(op_jgreatereq); instructions().append(src1Index); instructions().append(src2Index); instructions().append(target->bind(begin, instructions().size())); @@ -911,7 +802,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true); + emitOpcode(op_jtrue); instructions().append(cond->index()); instructions().append(target->bind(begin, instructions().size())); return target; @@ -997,7 +888,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* ta rewindUnaryOp(); size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true); + emitOpcode(op_jtrue); instructions().append(srcIndex); instructions().append(target->bind(begin, instructions().size())); return target; @@ -1035,7 +926,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* ta } size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jfalse : op_loop_if_false); + emitOpcode(op_jfalse); instructions().append(cond->index()); instructions().append(target->bind(begin, instructions().size())); return target; @@ -1068,7 +959,7 @@ unsigned BytecodeGenerator::addConstant(const Identifier& ident) StringImpl* rep = ident.impl(); IdentifierMap::AddResult result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers()); if (result.isNewEntry) - m_codeBlock->addIdentifier(Identifier(m_globalData, rep)); + m_codeBlock->addIdentifier(Identifier(m_vm, rep)); return result.iterator->value; } @@ -1110,6 +1001,8 @@ unsigned BytecodeGenerator::addRegExp(RegExp* r) RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src) { + m_staticPropertyAnalyzer.mov(dst->index(), src->index()); + emitOpcode(op_mov); instructions().append(dst->index()); instructions().append(src->index()); @@ -1124,36 +1017,20 @@ RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, R return dst; } -RegisterID* BytecodeGenerator::emitPreInc(RegisterID* srcDst) +RegisterID* BytecodeGenerator::emitInc(RegisterID* srcDst) { - emitOpcode(op_pre_inc); + emitOpcode(op_inc); instructions().append(srcDst->index()); return srcDst; } -RegisterID* BytecodeGenerator::emitPreDec(RegisterID* srcDst) +RegisterID* BytecodeGenerator::emitDec(RegisterID* srcDst) { - emitOpcode(op_pre_dec); + emitOpcode(op_dec); instructions().append(srcDst->index()); return srcDst; } -RegisterID* BytecodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst) -{ - emitOpcode(op_post_inc); - instructions().append(dst->index()); - instructions().append(srcDst->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst) -{ - emitOpcode(op_post_dec); - instructions().append(dst->index()); - instructions().append(srcDst->index()); - return dst; -} - RegisterID* BytecodeGenerator::emitBinaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types) { emitOpcode(opcodeID); @@ -1243,7 +1120,7 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, double number) // FIXME: Our hash tables won't hold infinity, so we make a new JSValue each time. // Later we can do the extra work to handle that like the other cases. They also don't // work correctly with NaN as a key. - if (isnan(number) || number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number)) + if (std::isnan(number) || number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number)) return emitLoad(dst, jsNumber(number)); JSValue& valueInMap = m_numberMap.add(number, JSValue()).iterator->value; if (!valueInMap) @@ -1255,7 +1132,7 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& ident { JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).iterator->value; if (!stringInMap) - stringInMap = jsOwnedString(globalData(), identifier.string()); + stringInMap = jsOwnedString(vm(), identifier.string()); return emitLoad(dst, JSValue(stringInMap)); } @@ -1267,6 +1144,21 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v) return constantID; } +RegisterID* BytecodeGenerator::emitLoadGlobalObject(RegisterID* dst) +{ + if (!m_globalObjectRegister) { + int index = m_nextConstantOffset; + m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); + ++m_nextConstantOffset; + m_codeBlock->addConstant(JSValue()); + m_globalObjectRegister = &m_constantPoolRegisters[index]; + m_codeBlock->setGlobalObjectRegister(index); + } + if (dst) + emitMove(dst, m_globalObjectRegister); + return m_globalObjectRegister; +} + ResolveResult BytecodeGenerator::resolve(const Identifier& property) { if (property == propertyNames().thisIdentifier) @@ -1283,13 +1175,51 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) return ResolveResult::registerResolve(local, flags); } } + // Cases where we cannot statically optimize the lookup. + if (property == propertyNames().arguments || !canOptimizeNonLocals()) + return ResolveResult::dynamicResolve(); + + if (!m_scope || m_codeType != FunctionCode || m_shouldEmitDebugHooks) + return ResolveResult::dynamicResolve(); + + ScopeChainIterator iter = m_scope->begin(); + ScopeChainIterator end = m_scope->end(); + size_t depth = m_codeBlock->needsFullScopeChain(); + unsigned flags = 0; + for (; iter != end; ++iter, ++depth) { + JSObject* currentScope = iter.get(); + if (!currentScope->isStaticScopeObject()) + return ResolveResult::dynamicResolve(); + + JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope); + SymbolTableEntry entry = currentVariableObject->symbolTable()->get(property.impl()); + + // Found the property + if (!entry.isNull()) { + if (entry.isReadOnly()) + flags |= ResolveResult::ReadOnlyFlag; + if (++iter == end) + return ResolveResult::dynamicResolve(); +#if !ASSERT_DISABLED + if (JSActivation* activation = jsDynamicCast<JSActivation*>(currentVariableObject)) + ASSERT(activation->isValid(entry)); +#endif + return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags); + } + bool scopeRequiresDynamicChecks = false; + if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks)) + break; + if (scopeRequiresDynamicChecks) + flags |= ResolveResult::DynamicFlag; + } + return ResolveResult::dynamicResolve(); } ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property) { // Register-allocated const declarations. - if (m_codeType != EvalCode && m_codeType != GlobalCode && m_symbolTable) { + if (m_codeType == FunctionCode && m_symbolTable) { SymbolTableEntry entry = symbolTable().get(property.impl()); if (!entry.isNull()) { unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0; @@ -1328,11 +1258,11 @@ bool BytecodeGenerator::shouldAvoidResolveGlobal() RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) { - if (resolveResult.isRegister()) - return emitGetLocalVar(dst, resolveResult, property); + if (resolveResult.isStatic()) + return emitGetStaticVar(dst, resolveResult, property); UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve); - instructions().append(dst->index()); + instructions().append(kill(dst)); instructions().append(addConstant(property)); instructions().append(getResolveOperations(property)); instructions().append(profile); @@ -1341,10 +1271,14 @@ RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) { - ASSERT_UNUSED(resolveResult, !resolveResult.isRegister()); + if (!resolveResult.isDynamic()) { + // Global object is the base + return emitLoadGlobalObject(dst); + } + // We can't optimise at all :-( UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_base); - instructions().append(dst->index()); + instructions().append(kill(dst)); instructions().append(addConstant(property)); instructions().append(false); instructions().append(getResolveBaseOperations(property)); @@ -1353,12 +1287,11 @@ RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveRes return dst; } -RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier) +RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo& verifier) { - ASSERT_UNUSED(resolveResult, !resolveResult.isRegister()); // We can't optimise at all :-( UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_base); - instructions().append(dst->index()); + instructions().append(kill(dst)); instructions().append(addConstant(property)); instructions().append(m_codeBlock->isStrictMode()); uint32_t putToBaseIndex = 0; @@ -1371,9 +1304,9 @@ RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Reso RegisterID* BytecodeGenerator::emitResolveWithBaseForPut(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier) { - ASSERT_UNUSED(resolveResult, !resolveResult.isRegister()); + ASSERT_UNUSED(resolveResult, !resolveResult.isStatic()); UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_with_base); - instructions().append(baseDst->index()); + instructions().append(kill(baseDst)); instructions().append(propDst->index()); instructions().append(addConstant(property)); uint32_t putToBaseIndex = 0; @@ -1386,14 +1319,14 @@ RegisterID* BytecodeGenerator::emitResolveWithBaseForPut(RegisterID* baseDst, Re RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property) { - if (resolveResult.isRegister()) { + if (resolveResult.isStatic()) { emitLoad(baseDst, jsUndefined()); - emitGetLocalVar(propDst, resolveResult, property); + emitGetStaticVar(propDst, resolveResult, property); return baseDst; } UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_with_this); - instructions().append(baseDst->index()); + instructions().append(kill(baseDst)); instructions().append(propDst->index()); instructions().append(addConstant(property)); instructions().append(getResolveWithThisOperations(property)); @@ -1401,8 +1334,9 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register return baseDst; } -RegisterID* BytecodeGenerator::emitGetLocalVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier&) +RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier&) { + ASSERT(m_codeType == FunctionCode); switch (resolveResult.type()) { case ResolveResult::Register: case ResolveResult::ReadOnlyRegister: @@ -1410,8 +1344,18 @@ RegisterID* BytecodeGenerator::emitGetLocalVar(RegisterID* dst, const ResolveRes return 0; return moveToDestinationIfNeeded(dst, resolveResult.local()); + case ResolveResult::Lexical: + case ResolveResult::ReadOnlyLexical: { + UnlinkedValueProfile profile = emitProfiledOpcode(op_get_scoped_var); + instructions().append(dst->index()); + instructions().append(resolveResult.index()); + instructions().append(resolveResult.depth()); + instructions().append(profile); + return dst; + } + default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return 0; } } @@ -1427,12 +1371,34 @@ RegisterID* BytecodeGenerator::emitInitGlobalConst(const Identifier& identifier, return value; } +RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, const Identifier&, RegisterID* value) +{ + ASSERT(m_codeType == FunctionCode); + switch (resolveResult.type()) { + case ResolveResult::Register: + case ResolveResult::ReadOnlyRegister: + return moveToDestinationIfNeeded(resolveResult.local(), value); + + case ResolveResult::Lexical: + case ResolveResult::ReadOnlyLexical: + emitOpcode(op_put_scoped_var); + instructions().append(resolveResult.index()); + instructions().append(resolveResult.depth()); + instructions().append(value->index()); + return value; + + default: + RELEASE_ASSERT_NOT_REACHED(); + return 0; + } +} + RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property) { m_codeBlock->addPropertyAccessInstruction(instructions().size()); UnlinkedValueProfile profile = emitProfiledOpcode(op_get_by_id); - instructions().append(dst->index()); + instructions().append(kill(dst)); instructions().append(base->index()); instructions().append(addConstant(property)); instructions().append(0); @@ -1455,11 +1421,15 @@ RegisterID* BytecodeGenerator::emitGetArgumentsLength(RegisterID* dst, RegisterI RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value) { + unsigned propertyIndex = addConstant(property); + + m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); + m_codeBlock->addPropertyAccessInstruction(instructions().size()); emitOpcode(op_put_by_id); instructions().append(base->index()); - instructions().append(addConstant(property)); + instructions().append(propertyIndex); instructions().append(value->index()); instructions().append(0); instructions().append(0); @@ -1481,27 +1451,35 @@ RegisterID* BytecodeGenerator::emitPutToBase(RegisterID* base, const Identifier& RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value) { + unsigned propertyIndex = addConstant(property); + + m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); + m_codeBlock->addPropertyAccessInstruction(instructions().size()); emitOpcode(op_put_by_id); instructions().append(base->index()); - instructions().append(addConstant(property)); + instructions().append(propertyIndex); instructions().append(value->index()); instructions().append(0); instructions().append(0); instructions().append(0); instructions().append(0); instructions().append( - property != m_globalData->propertyNames->underscoreProto + property != m_vm->propertyNames->underscoreProto && PropertyName(property).asIndex() == PropertyName::NotAnIndex); return value; } void BytecodeGenerator::emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter) { + unsigned propertyIndex = addConstant(property); + + m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); + emitOpcode(op_put_getter_setter); instructions().append(base->index()); - instructions().append(addConstant(property)); + instructions().append(propertyIndex); instructions().append(getter->index()); instructions().append(setter->index()); } @@ -1519,7 +1497,7 @@ RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* { UnlinkedArrayProfile arrayProfile = newArrayProfile(); UnlinkedValueProfile profile = emitProfiledOpcode(op_get_argument_by_val); - instructions().append(dst->index()); + instructions().append(kill(dst)); ASSERT(base->index() == m_codeBlock->argumentsRegister()); instructions().append(base->index()); instructions().append(property->index()); @@ -1545,7 +1523,7 @@ RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, R } UnlinkedArrayProfile arrayProfile = newArrayProfile(); UnlinkedValueProfile profile = emitProfiledOpcode(op_get_by_val); - instructions().append(dst->index()); + instructions().append(kill(dst)); instructions().append(base->index()); instructions().append(property->index()); instructions().append(arrayProfile); @@ -1582,10 +1560,33 @@ RegisterID* BytecodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, return value; } +RegisterID* BytecodeGenerator::emitCreateThis(RegisterID* dst) +{ + RefPtr<RegisterID> func = newTemporary(); + + UnlinkedValueProfile profile = emitProfiledOpcode(op_get_callee); + instructions().append(func->index()); + instructions().append(profile); + + size_t begin = instructions().size(); + m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3); + + emitOpcode(op_create_this); + instructions().append(m_thisRegister.index()); + instructions().append(func->index()); + instructions().append(0); + return dst; +} + RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst) { + size_t begin = instructions().size(); + m_staticPropertyAnalyzer.newObject(dst->index(), begin + 2); + emitOpcode(op_new_object); instructions().append(dst->index()); + instructions().append(0); + instructions().append(newObjectAllocationProfile()); return dst; } @@ -1598,7 +1599,7 @@ JSString* BytecodeGenerator::addStringConstant(const Identifier& identifier) { JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).iterator->value; if (!stringInMap) { - stringInMap = jsString(globalData(), identifier.string()); + stringInMap = jsString(vm(), identifier.string()); addConstantValue(stringInMap); } return stringInMap; @@ -1612,7 +1613,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen bool hadVariableExpression = false; if (length) { for (ElementNode* n = elements; n; n = n->next()) { - if (!n->value()->isNumber() && !n->value()->isString()) { + if (!n->value()->isConstant()) { hadVariableExpression = true; break; } @@ -1628,12 +1629,8 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen JSValue* constantBuffer = m_codeBlock->constantBuffer(constantBufferIndex).data(); unsigned index = 0; for (ElementNode* n = elements; index < length; n = n->next()) { - if (n->value()->isNumber()) - constantBuffer[index++] = jsNumber(static_cast<NumberNode*>(n->value())->value()); - else { - ASSERT(n->value()->isString()); - constantBuffer[index++] = addStringConstant(static_cast<StringNode*>(n->value())->value()); - } + ASSERT(n->value()->isConstant()); + constantBuffer[index++] = static_cast<ConstantNode*>(n->value())->jsValue(*this); } emitOpcode(op_new_array_buffer); instructions().append(dst->index()); @@ -1644,7 +1641,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen } } - Vector<RefPtr<RegisterID>, 16> argv; + Vector<RefPtr<RegisterID>, 16, UnsafeVectorOverflow> argv; for (ElementNode* n = elements; n; n = n->next()) { if (n->elision()) break; @@ -1704,9 +1701,9 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExp return r0; } -RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) +RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart) { - return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, startOffset, endOffset); + return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, startOffset, endOffset, line, lineStart); } void BytecodeGenerator::createArgumentsIfNecessary() @@ -1737,16 +1734,16 @@ void BytecodeGenerator::createActivationIfNecessary() instructions().append(m_activationRegister->index()); } -RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) +RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart) { - return emitCall(op_call_eval, dst, func, NoExpectedFunction, callArguments, divot, startOffset, endOffset); + return emitCall(op_call_eval, dst, func, NoExpectedFunction, callArguments, divot, startOffset, endOffset, line, lineStart); } ExpectedFunction BytecodeGenerator::expectedFunctionForIdentifier(const Identifier& identifier) { - if (identifier == m_globalData->propertyNames->Object) + if (identifier == m_vm->propertyNames->Object) return ExpectObjectConstructor; - if (identifier == m_globalData->propertyNames->Array) + if (identifier == m_vm->propertyNames->Array) return ExpectArrayConstructor; return NoExpectedFunction; } @@ -1766,10 +1763,8 @@ ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst, instructions().append(Special::ObjectConstructor); instructions().append(realCall->bind(begin, instructions().size())); - if (dst != ignoredResult()) { - emitOpcode(op_new_object); - instructions().append(dst->index()); - } + if (dst != ignoredResult()) + emitNewObject(dst); break; } @@ -1819,7 +1814,7 @@ ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst, return expectedFunction; } -RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) +RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart) { ASSERT(opcodeID == op_call || opcodeID == op_call_eval); ASSERT(func->refCount()); @@ -1833,7 +1828,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi emitNode(callArguments.argumentRegister(argument++), n); // Reserve space for call frame. - Vector<RefPtr<RegisterID>, JSStack::CallFrameHeaderSize> callFrame; + Vector<RefPtr<RegisterID>, JSStack::CallFrameHeaderSize, UnsafeVectorOverflow> callFrame; for (int i = 0; i < JSStack::CallFrameHeaderSize; ++i) callFrame.append(newTemporary()); @@ -1842,7 +1837,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi instructions().append(callArguments.profileHookRegister()->index()); } - emitExpressionInfo(divot, startOffset, endOffset); + emitExpressionInfo(divot, startOffset, endOffset, line, lineStart); RefPtr<Label> done = newLabel(); expectedFunction = emitExpectedFunctionSnippet(dst, func, expectedFunction, callArguments, done.get()); @@ -1861,7 +1856,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi instructions().append(arrayProfile); if (dst != ignoredResult()) { UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result); - instructions().append(dst->index()); // dst + instructions().append(kill(dst)); instructions().append(profile); } @@ -1876,7 +1871,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi return dst; } -RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, RegisterID* profileHookRegister, unsigned divot, unsigned startOffset, unsigned endOffset) +RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, RegisterID* profileHookRegister, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart) { if (m_shouldEmitProfileHooks) { emitMove(profileHookRegister, func); @@ -1884,7 +1879,7 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func instructions().append(profileHookRegister->index()); } - emitExpressionInfo(divot, startOffset, endOffset); + emitExpressionInfo(divot, startOffset, endOffset, line, lineStart); // Emit call. emitOpcode(op_call_varargs); @@ -1894,7 +1889,7 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func instructions().append(firstFreeRegister->index()); if (dst != ignoredResult()) { UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result); - instructions().append(dst->index()); + instructions().append(kill(dst)); instructions().append(profile); } if (m_shouldEmitProfileHooks) { @@ -1936,7 +1931,7 @@ RegisterID* BytecodeGenerator::emitUnaryNoDstOp(OpcodeID opcodeID, RegisterID* s return src; } -RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) +RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart) { ASSERT(func->refCount()); @@ -1956,11 +1951,11 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, } // Reserve space for call frame. - Vector<RefPtr<RegisterID>, JSStack::CallFrameHeaderSize> callFrame; + Vector<RefPtr<RegisterID>, JSStack::CallFrameHeaderSize, UnsafeVectorOverflow> callFrame; for (int i = 0; i < JSStack::CallFrameHeaderSize; ++i) callFrame.append(newTemporary()); - emitExpressionInfo(divot, startOffset, endOffset); + emitExpressionInfo(divot, startOffset, endOffset, line, lineStart); RefPtr<Label> done = newLabel(); expectedFunction = emitExpectedFunctionSnippet(dst, func, expectedFunction, callArguments, done.get()); @@ -1977,7 +1972,7 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, instructions().append(0); if (dst != ignoredResult()) { UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result); - instructions().append(dst->index()); // dst + instructions().append(kill(dst)); instructions().append(profile); } @@ -2030,7 +2025,7 @@ void BytecodeGenerator::emitPopScope() m_dynamicScopeDepth--; } -void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine, int column) +void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, unsigned firstLine, unsigned lastLine, unsigned charOffset, unsigned lineStart) { #if ENABLE(DEBUG_WITH_BREAKPOINT) if (debugHookID != DidReachBreakpoint) @@ -2039,11 +2034,13 @@ void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, in if (!m_shouldEmitDebugHooks) return; #endif + emitExpressionInfo(charOffset, 0, 0, firstLine, lineStart); + unsigned charPosition = charOffset - m_scopeNode->source().startOffset(); emitOpcode(op_debug); instructions().append(debugHookID); instructions().append(firstLine); instructions().append(lastLine); - instructions().append(column); + instructions().append(charPosition); } void BytecodeGenerator::pushFinallyContext(StatementNode* finallyBlock) @@ -2151,7 +2148,7 @@ LabelScope* BytecodeGenerator::continueTarget(const Identifier& name) return 0; } -PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope) +void BytecodeGenerator::emitComplexPopScopes(ControlFlowContext* topScope, ControlFlowContext* bottomScope) { while (topScope > bottomScope) { // First we count the number of dynamic scopes we need to remove to get @@ -2165,32 +2162,21 @@ PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, Contro } if (nNormalScopes) { - size_t begin = instructions().size(); - // We need to remove a number of dynamic scopes to get to the next // finally block - emitOpcode(op_jmp_scopes); - instructions().append(nNormalScopes); - - // If topScope == bottomScope then there isn't actually a finally block - // left to emit, so make the jmp_scopes jump directly to the target label - if (topScope == bottomScope) { - instructions().append(target->bind(begin, instructions().size())); - return target; - } + while (nNormalScopes--) + emitOpcode(op_pop_scope); - // Otherwise we just use jmp_scopes to pop a group of scopes and go - // to the next instruction - RefPtr<Label> nextInsn = newLabel(); - instructions().append(nextInsn->bind(begin, instructions().size())); - emitLabel(nextInsn.get()); + // If topScope == bottomScope then there isn't a finally block left to emit. + if (topScope == bottomScope) + return; } Vector<ControlFlowContext> savedScopeContextStack; Vector<SwitchInfo> savedSwitchContextStack; Vector<ForInContext> savedForInContextStack; Vector<TryContext> poppedTryContexts; - SegmentedVector<LabelScope, 8> savedLabelScopes; + LabelScopeStore savedLabelScopes; while (topScope > bottomScope && topScope->isFinallyBlock) { RefPtr<Label> beforeFinally = emitLabel(newLabel().get()); @@ -2273,28 +2259,24 @@ PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, Contro --topScope; } } - return emitJump(target); } -PassRefPtr<Label> BytecodeGenerator::emitJumpScopes(Label* target, int targetScopeDepth) +void BytecodeGenerator::emitPopScopes(int targetScopeDepth) { ASSERT(scopeDepth() - targetScopeDepth >= 0); - ASSERT(target->isForward()); size_t scopeDelta = scopeDepth() - targetScopeDepth; ASSERT(scopeDelta <= m_scopeContextStack.size()); if (!scopeDelta) - return emitJump(target); - - if (m_finallyDepth) - return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta); + return; - size_t begin = instructions().size(); + if (!m_finallyDepth) { + while (scopeDelta--) + emitOpcode(op_pop_scope); + return; + } - emitOpcode(op_jmp_scopes); - instructions().append(scopeDelta); - instructions().append(target->bind(begin, instructions().size())); - return target; + emitComplexPopScopes(&m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta); } RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget) @@ -2365,7 +2347,7 @@ RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* void BytecodeGenerator::emitThrowReferenceError(const String& message) { emitOpcode(op_throw_static_error); - instructions().append(addConstantValue(jsString(globalData(), message))->index()); + instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, message)))->index()); instructions().append(true); } @@ -2396,7 +2378,7 @@ void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::S emitOpcode(op_switch_string); break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } instructions().append(0); // place holder for table index @@ -2523,7 +2505,7 @@ void BytecodeGenerator::emitReadOnlyExceptionIfNeeded() if (!isStrictMode()) return; emitOpcode(op_throw_static_error); - instructions().append(addConstantValue(jsString(globalData(), StrictModeReadonlyPropertyWriteError))->index()); + instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, StrictModeReadonlyPropertyWriteError)))->index()); instructions().append(false); } diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index a5bb95b6c..c268b9165 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * Copyright (C) 2012 Igalia, S.L. * @@ -37,11 +37,14 @@ #include "Label.h" #include "LabelScope.h" #include "Interpreter.h" +#include "ParserError.h" #include "RegisterID.h" #include "SymbolTable.h" #include "Debugger.h" #include "Nodes.h" +#include "StaticPropertyAnalyzer.h" #include "UnlinkedCodeBlock.h" +#include "VMStackBounds.h" #include <wtf/PassRefPtr.h> #include <wtf/SegmentedVector.h> #include <wtf/Vector.h> @@ -74,7 +77,7 @@ namespace JSC { RefPtr<RegisterID> m_profileHookRegister; ArgumentsNode* m_argumentsNode; - Vector<RefPtr<RegisterID>, 8> m_argv; + Vector<RefPtr<RegisterID>, 8, UnsafeVectorOverflow> m_argv; }; struct FinallyContext { @@ -126,14 +129,22 @@ namespace JSC { DynamicFlag = 0x2, // The resolved binding is immutable. ReadOnlyFlag = 0x4, + // The property has a static location + StaticFlag = 0x8, + // Entry at scope distance "m_depth" and located at "m_index" + ScopedFlag = 0x10 }; enum Type { // The property is local, and stored in a register. - Register = RegisterFlag, + Register = RegisterFlag | StaticFlag, // A read-only local, created by "const". - ReadOnlyRegister = RegisterFlag | ReadOnlyFlag, - // Any form of non-local lookup + ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag, + // Lexically fixed location in the scope chain + Lexical = ScopedFlag | StaticFlag, + // A read-only Lexical, created by "const". + ReadOnlyLexical = ScopedFlag | ReadOnlyFlag | StaticFlag, + // Any other form of lookup Dynamic = DynamicFlag, }; @@ -145,6 +156,12 @@ namespace JSC { { return ResolveResult(Dynamic, 0); } + static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags) + { + if (flags & DynamicFlag) + return dynamicResolve(); + return ResolveResult(Lexical | flags, index, depth); + } unsigned type() const { return m_type; } // Returns the register corresponding to a local variable, or 0 if no @@ -153,13 +170,30 @@ namespace JSC { RegisterID* local() const { return m_local; } bool isRegister() const { return m_type & RegisterFlag; } + bool isStatic() const { return (m_type & StaticFlag) && !isDynamic(); } bool isDynamic() const { return m_type & DynamicFlag; } bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); } + unsigned depth() const { ASSERT(isStatic()); return m_depth; } + int32_t index() const { ASSERT(isStatic()); return m_index; } + private: ResolveResult(unsigned type, RegisterID* local) : m_type(type) , m_local(local) + , m_index(0) + , m_depth(0) + { +#ifndef NDEBUG + checkValidity(); +#endif + } + + ResolveResult(unsigned type, int index, unsigned depth) + : m_type(type) + , m_local(0) + , m_index(index) + , m_depth(depth) { #ifndef NDEBUG checkValidity(); @@ -172,6 +206,8 @@ namespace JSC { unsigned m_type; RegisterID* m_local; // Local register, if RegisterFlag is set + int m_index; + unsigned m_depth; }; struct NonlocalResolveInfo { @@ -209,14 +245,14 @@ namespace JSC { typedef DeclarationStacks::VarStack VarStack; typedef DeclarationStacks::FunctionStack FunctionStack; - BytecodeGenerator(JSGlobalData&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode); - BytecodeGenerator(JSGlobalData&, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode); - BytecodeGenerator(JSGlobalData&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode); + BytecodeGenerator(VM&, JSScope*, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode); + BytecodeGenerator(VM&, JSScope*, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode); + BytecodeGenerator(VM&, JSScope*, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode); ~BytecodeGenerator(); - JSGlobalData* globalData() const { return m_globalData; } - const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; } + VM* vm() const { return m_vm; } + const CommonIdentifiers& propertyNames() const { return *m_vm->propertyNames; } bool isConstructor() { return m_codeBlock->isConstructor(); } @@ -296,65 +332,70 @@ namespace JSC { return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; } - PassRefPtr<LabelScope> newLabelScope(LabelScope::Type, const Identifier* = 0); + LabelScopePtr newLabelScope(LabelScope::Type, const Identifier* = 0); PassRefPtr<Label> newLabel(); - // The emitNode functions are just syntactic sugar for calling - // Node::emitCode. These functions accept a 0 for the register, - // meaning that the node should allocate a register, or ignoredResult(), - // meaning that the node need not put the result in a register. - // Other emit functions do not accept 0 or ignoredResult(). - RegisterID* emitNode(RegisterID* dst, Node* n) + void emitNode(RegisterID* dst, StatementNode* n) { // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); - addLineInfo(n->lineNo()); - return m_stack.isSafeToRecurse() - ? n->emitBytecode(*this, dst) - : emitThrowExpressionTooDeepException(); + if (!m_stack.isSafeToRecurse()) { + emitThrowExpressionTooDeepException(); + return; + } + n->emitBytecode(*this, dst); } - RegisterID* emitNode(Node* n) + void emitNode(StatementNode* n) + { + emitNode(0, n); + } + + RegisterID* emitNode(RegisterID* dst, ExpressionNode* n) + { + // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. + ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); + if (!m_stack.isSafeToRecurse()) + return emitThrowExpressionTooDeepException(); + return n->emitBytecode(*this, dst); + } + + RegisterID* emitNode(ExpressionNode* n) { return emitNode(0, n); } - void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) + void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { - addLineInfo(n->lineNo()); - if (m_stack.isSafeToRecurse()) - n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue); - else + if (!m_stack.isSafeToRecurse()) { emitThrowExpressionTooDeepException(); + return; + } + + n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMode); } - void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset) - { - divot -= m_scopeNode->source().startOffset(); - if (divot > ExpressionRangeInfo::MaxDivot) { - // Overflow has occurred, we can only give line number info for errors for this region - divot = 0; - startOffset = 0; - endOffset = 0; - } else if (startOffset > ExpressionRangeInfo::MaxOffset) { - // If the start offset is out of bounds we clear both offsets - // so we only get the divot marker. Error message will have to be reduced - // to line and column number. - startOffset = 0; - endOffset = 0; - } else if (endOffset > ExpressionRangeInfo::MaxOffset) { - // The end offset is only used for additional context, and is much more likely - // to overflow (eg. function call arguments) so we are willing to drop it without - // dropping the rest of the range. - endOffset = 0; - } - - ExpressionRangeInfo info; - info.instructionOffset = instructions().size(); - info.divotPoint = divot; - info.startOffset = startOffset; - info.endOffset = endOffset; - m_codeBlock->addExpressionInfo(info); + void emitExpressionInfo(int divot, int startOffset, int endOffset, unsigned line, int lineStart) + { + int sourceOffset = m_scopeNode->source().startOffset(); + unsigned firstLine = m_scopeNode->source().firstLine(); + + ASSERT(divot >= lineStart); + ASSERT(divot >= sourceOffset); + divot -= sourceOffset; + + if (lineStart > sourceOffset) + lineStart -= sourceOffset; + else + lineStart = 0; + + ASSERT(line >= firstLine); + line -= firstLine; + + unsigned instructionOffset = instructions().size(); + ASSERT(divot >= lineStart); + unsigned column = divot - lineStart; + m_codeBlock->addExpressionInfo(instructionOffset, divot, startOffset, endOffset, line, column); } ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) @@ -377,12 +418,14 @@ namespace JSC { RegisterID* emitLoad(RegisterID* dst, double); RegisterID* emitLoad(RegisterID* dst, const Identifier&); RegisterID* emitLoad(RegisterID* dst, JSValue); + RegisterID* emitLoadGlobalObject(RegisterID* dst); RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src); RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes); RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2); RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src); + RegisterID* emitCreateThis(RegisterID* dst); RegisterID* emitNewObject(RegisterID* dst); RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision @@ -394,18 +437,17 @@ namespace JSC { RegisterID* emitMove(RegisterID* dst, RegisterID* src); - RegisterID* emitToJSNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_jsnumber, dst, src); } - RegisterID* emitPreInc(RegisterID* srcDst); - RegisterID* emitPreDec(RegisterID* srcDst); - RegisterID* emitPostInc(RegisterID* dst, RegisterID* srcDst); - RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst); + RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); } + RegisterID* emitInc(RegisterID* srcDst); + RegisterID* emitDec(RegisterID* srcDst); void emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target); RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype); RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } - RegisterID* emitGetLocalVar(RegisterID* dst, const ResolveResult&, const Identifier&); + RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&, const Identifier&); + RegisterID* emitPutStaticVar(const ResolveResult&, const Identifier&, RegisterID* value); RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value); RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property); @@ -429,15 +471,15 @@ namespace JSC { void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter); ExpectedFunction expectedFunctionForIdentifier(const Identifier&); - RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); - RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); - RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, RegisterID* profileHookRegister, unsigned divot, unsigned startOffset, unsigned endOffset); + RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart); + RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart); + RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, RegisterID* profileHookRegister, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart); RegisterID* emitLoadVarargs(RegisterID* argCountDst, RegisterID* thisRegister, RegisterID* args); RegisterID* emitReturn(RegisterID* src); RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); } - RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); + RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart); RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count); void emitToPrimitive(RegisterID* dst, RegisterID* src); @@ -448,7 +490,7 @@ namespace JSC { PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target); PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target); PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target); - PassRefPtr<Label> emitJumpScopes(Label* target, int targetScopeDepth); + void emitPopScopes(int targetScopeDepth); 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); @@ -473,7 +515,7 @@ namespace JSC { RegisterID* emitPushWithScope(RegisterID* scope); void emitPopScope(); - void emitDebugHook(DebugHookID, int firstLine, int lastLine, int column); + void emitDebugHook(DebugHookID, unsigned firstLine, unsigned lastLine, unsigned charOffset, unsigned lineStart); int scopeDepth() { return m_dynamicScopeDepth + m_finallyDepth; } bool hasFinaliser() { return m_finallyDepth != 0; } @@ -501,34 +543,31 @@ namespace JSC { CodeType codeType() const { return m_codeType; } bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; } + bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; } bool isStrictMode() const { return m_codeBlock->isStrictMode(); } private: friend class Label; -#if ENABLE(BYTECODE_COMMENTS) - // Record a comment in the CodeBlock's comments list for the current - // opcode that is about to be emitted. - void emitComment(); - // Register a comment to be associated with the next opcode that will - // be emitted. - void prependComment(const char* string); -#else - ALWAYS_INLINE void emitComment() { } - ALWAYS_INLINE void prependComment(const char*) { } -#endif - void emitOpcode(OpcodeID); UnlinkedArrayAllocationProfile newArrayAllocationProfile(); + UnlinkedObjectAllocationProfile newObjectAllocationProfile(); UnlinkedArrayProfile newArrayProfile(); UnlinkedValueProfile emitProfiledOpcode(OpcodeID); + int kill(RegisterID* dst) + { + int index = dst->index(); + m_staticPropertyAnalyzer.kill(index); + return index; + } + void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); ALWAYS_INLINE void rewindBinaryOp(); ALWAYS_INLINE void rewindUnaryOp(); - PassRefPtr<Label> emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope); + void emitComplexPopScopes(ControlFlowContext* topScope, ControlFlowContext* bottomScope); typedef HashMap<double, JSValue> NumberMap; typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; @@ -544,7 +583,7 @@ namespace JSC { // (i.e. "Object()" is identical to "new Object()"). ExpectedFunction emitExpectedFunctionSnippet(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, Label* done); - RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); + RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset, unsigned line, unsigned lineStart); RegisterID* newRegister(); @@ -595,25 +634,17 @@ namespace JSC { UnlinkedFunctionExecutable* makeFunction(FunctionBodyNode* body) { - return UnlinkedFunctionExecutable::create(m_globalData, m_scopeNode->source(), body); - } - - JSString* addStringConstant(const Identifier&); - - void addLineInfo(unsigned lineNo) - { - m_codeBlock->addLineInfo(instructions().size(), lineNo - m_scopeNode->firstLine()); + return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body); } RegisterID* emitInitLazyRegister(RegisterID*); public: - Vector<UnlinkedInstruction>& instructions() { return m_instructions; } + JSString* addStringConstant(const Identifier&); + + Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; } SharedSymbolTable& symbolTable() { return *m_symbolTable; } -#if ENABLE(BYTECODE_COMMENTS) - Vector<Comment>& comments() { return m_comments; } -#endif bool shouldOptimizeLocals() { @@ -646,19 +677,15 @@ namespace JSC { void createActivationIfNecessary(); RegisterID* createLazyRegisterIfNecessary(RegisterID*); - Vector<UnlinkedInstruction> m_instructions; + Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow> m_instructions; bool m_shouldEmitDebugHooks; bool m_shouldEmitProfileHooks; SharedSymbolTable* m_symbolTable; -#if ENABLE(BYTECODE_COMMENTS) - Vector<Comment> m_comments; - const char *m_currentCommentString; -#endif - ScopeNode* m_scopeNode; + Strong<JSScope> m_scope; Strong<UnlinkedCodeBlock> m_codeBlock; // Some of these objects keep pointers to one another. They are arranged @@ -669,17 +696,18 @@ namespace JSC { RegisterID m_calleeRegister; RegisterID* m_activationRegister; RegisterID* m_emptyValueRegister; + RegisterID* m_globalObjectRegister; SegmentedVector<RegisterID, 32> m_constantPoolRegisters; SegmentedVector<RegisterID, 32> m_calleeRegisters; SegmentedVector<RegisterID, 32> m_parameters; SegmentedVector<Label, 32> m_labels; - SegmentedVector<LabelScope, 8> m_labelScopes; + LabelScopeStore m_labelScopes; RefPtr<RegisterID> m_lastVar; int m_finallyDepth; int m_dynamicScopeDepth; CodeType m_codeType; - Vector<ControlFlowContext> m_scopeContextStack; + Vector<ControlFlowContext, 0, UnsafeVectorOverflow> m_scopeContextStack; Vector<SwitchInfo> m_switchContextStack; Vector<ForInContext> m_forInContextStack; Vector<TryContext> m_tryContextStack; @@ -775,14 +803,16 @@ namespace JSC { IdentifierResolvePutMap m_resolveBaseForPutMap; IdentifierResolvePutMap m_resolveWithBaseForPutMap; - JSGlobalData* m_globalData; + StaticPropertyAnalyzer m_staticPropertyAnalyzer; + + VM* m_vm; OpcodeID m_lastOpcodeID; #ifndef NDEBUG size_t m_lastOpcodePosition; #endif - StackBounds m_stack; + VMStackBounds m_stack; bool m_usesExceptions; bool m_expressionTooDeep; diff --git a/Source/JavaScriptCore/bytecompiler/Label.h b/Source/JavaScriptCore/bytecompiler/Label.h index 8b444de91..d29ab8ff3 100644 --- a/Source/JavaScriptCore/bytecompiler/Label.h +++ b/Source/JavaScriptCore/bytecompiler/Label.h @@ -37,6 +37,8 @@ namespace JSC { + class BytecodeGenerator; + class Label { public: explicit Label(BytecodeGenerator* generator) diff --git a/Source/JavaScriptCore/bytecompiler/LabelScope.h b/Source/JavaScriptCore/bytecompiler/LabelScope.h index cc21fffd1..2df6f1b9b 100644 --- a/Source/JavaScriptCore/bytecompiler/LabelScope.h +++ b/Source/JavaScriptCore/bytecompiler/LabelScope.h @@ -49,13 +49,6 @@ namespace JSC { , m_continueTarget(continueTarget) { } - - void ref() { ++m_refCount; } - void deref() - { - --m_refCount; - ASSERT(m_refCount >= 0); - } int refCount() const { return m_refCount; } Label* breakTarget() const { return m_breakTarget.get(); } @@ -66,6 +59,15 @@ namespace JSC { int scopeDepth() const { return m_scopeDepth; } private: + friend class LabelScopePtr; + + void ref() { ++m_refCount; } + void deref() + { + --m_refCount; + ASSERT(m_refCount >= 0); + } + int m_refCount; Type m_type; const Identifier* m_name; @@ -74,6 +76,57 @@ namespace JSC { RefPtr<Label> m_continueTarget; }; + typedef Vector<LabelScope, 8> LabelScopeStore; + + class LabelScopePtr { + public: + LabelScopePtr() + : m_owner(0) + , m_index(0) + { + } + LabelScopePtr(LabelScopeStore* owner, size_t index) + : m_owner(owner) + , m_index(index) + { + m_owner->at(index).ref(); + } + + LabelScopePtr(const LabelScopePtr& other) + : m_owner(other.m_owner) + , m_index(other.m_index) + { + if (m_owner) + m_owner->at(m_index).ref(); + } + + const LabelScopePtr& operator=(const LabelScopePtr& other) + { + if (other.m_owner) + other.m_owner->at(other.m_index).ref(); + if (m_owner) + m_owner->at(m_index).deref(); + m_owner = other.m_owner; + m_index = other.m_index; + return *this; + } + + ~LabelScopePtr() + { + if (m_owner) + m_owner->at(m_index).deref(); + } + + LabelScope& operator*() { ASSERT(m_owner); return m_owner->at(m_index); } + LabelScope* operator->() { ASSERT(m_owner); return &m_owner->at(m_index); } + const LabelScope& operator*() const { ASSERT(m_owner); return m_owner->at(m_index); } + const LabelScope* operator->() const { ASSERT(m_owner); return &m_owner->at(m_index); } + + private: + LabelScopeStore* m_owner; + size_t m_index; + }; + } // namespace JSC #endif // LabelScope_h diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp index 71b6c7cac..40f703c08 100644 --- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) -* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved. +* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel <eric@webkit.org> @@ -74,49 +74,49 @@ namespace JSC { because the assignment node, "x =", passes r[x] as dst to the number node, "1". */ +void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) +{ + RegisterID* result = generator.emitNode(this); + if (fallThroughMode == FallThroughMeansTrue) + generator.emitJumpIfFalse(result, falseTarget); + else + generator.emitJumpIfTrue(result, trueTarget); +} + // ------------------------------ ThrowableExpressionData -------------------------------- RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const String& message) { - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitThrowReferenceError(message); return generator.newTemporary(); } -// ------------------------------ NullNode ------------------------------------- +// ------------------------------ ConstantNode ---------------------------------- -RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, jsNull()); -} - -// ------------------------------ BooleanNode ---------------------------------- + TriState value = jsValue(generator).pureToBoolean(); + if (value == MixedTriState) + ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); + else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse) + generator.emitJump(trueTarget); + else if (value == FalseTriState && fallThroughMode == FallThroughMeansTrue) + generator.emitJump(falseTarget); -RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); + // All other cases are unconditional fall-throughs, like "if (true)". } -// ------------------------------ NumberNode ----------------------------------- - -RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (dst == generator.ignoredResult()) return 0; - return generator.emitLoad(dst, m_value); + return generator.emitLoad(dst, jsValue(generator)); } -// ------------------------------ StringNode ----------------------------------- - -RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +JSValue StringNode::jsValue(BytecodeGenerator& generator) const { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); + return generator.addStringConstant(m_value); } // ------------------------------ RegExpNode ----------------------------------- @@ -125,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.string(), regExpFlags(m_flags.string()))); + return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.vm(), m_pattern.string(), regExpFlags(m_flags.string()))); } // ------------------------------ ThisNode ------------------------------------- @@ -141,7 +141,7 @@ RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst bool ResolveNode::isPure(BytecodeGenerator& generator) const { - return generator.resolve(m_ident).isRegister(); + return generator.resolve(m_ident).isStatic(); } RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -153,7 +153,8 @@ RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* return generator.moveToDestinationIfNeeded(dst, local); } - generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0); + unsigned divot = m_startOffset + m_ident.length(); + generator.emitExpressionInfo(divot, m_ident.length(), 0, m_divotLine, m_divotLineStart); return generator.emitResolve(generator.finalDestination(dst), resolveResult, m_ident); } @@ -201,7 +202,7 @@ bool ArrayNode::isSimpleArray() const return true; } -ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData, int lineNumber, int columnNumber) const +ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPosition) const { ASSERT(!m_elision && !m_optional); ElementNode* ptr = m_element; @@ -209,13 +210,13 @@ ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData, int lineNu return 0; JSTokenLocation location; location.line = lineNumber; - location.column = columnNumber; - ArgumentListNode* head = new (globalData) ArgumentListNode(location, ptr->value()); + location.startOffset = startPosition; + ArgumentListNode* head = new (vm) ArgumentListNode(location, ptr->value()); ArgumentListNode* tail = head; ptr = ptr->next(); for (; ptr; ptr = ptr->next()) { ASSERT(!ptr->elision()); - tail = new (globalData) ArgumentListNode(location, tail, ptr->value()); + tail = new (vm) ArgumentListNode(location, tail, ptr->value()); } return head; } @@ -324,13 +325,13 @@ RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, Regi && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier()) && !generator.symbolTable().slowArguments()) { RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property); } RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); } @@ -344,13 +345,13 @@ RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, Register ResolveNode* resolveNode = static_cast<ResolveNode*>(m_base); if (!generator.willResolveToArguments(resolveNode->identifier())) goto nonArgumentsPath; - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments()); } nonArgumentsPath: RegisterID* base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitGetById(generator.finalDestination(dst), base, m_ident); } @@ -373,7 +374,7 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* expectedFunction = NoExpectedFunction; RefPtr<RegisterID> func = generator.emitNode(m_expr); CallArguments callArguments(generator, m_args); - return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset()); + return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), expectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } inline CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode) @@ -408,9 +409,9 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg { RefPtr<RegisterID> func = generator.tempDestination(dst); CallArguments callArguments(generator, m_args); - generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); + generator.emitExpressionInfo(divot() - divotStartOffset() + 4, 4, 0, divotLine(), divotLineStart()); generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.resolve(generator.propertyNames().eval), generator.propertyNames().eval); - return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } // ------------------------------ FunctionCallValueNode ---------------------------------- @@ -420,7 +421,7 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re RefPtr<RegisterID> func = generator.emitNode(m_expr); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } // ------------------------------ FunctionCallResolveNode ---------------------------------- @@ -436,16 +437,24 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, generator.emitLoad(callArguments.thisRegister(), jsUndefined()); // This passes NoExpectedFunction because we expect that if the function is in a // local variable, then it's not one of our built-in constructors. - return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); + } + + if (resolveResult.isStatic()) { + RefPtr<RegisterID> func = generator.newTemporary(); + CallArguments callArguments(generator, m_args); + generator.emitGetStaticVar(func.get(), resolveResult, m_ident); + generator.emitLoad(callArguments.thisRegister(), jsUndefined()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } RefPtr<RegisterID> func = generator.newTemporary(); CallArguments callArguments(generator, m_args); - int identifierStart = divot() - startOffset(); + int identifierStart = divot() - divotStartOffset(); - generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0); + generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0, divotLine(), divotLineStart()); generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), resolveResult, m_ident); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } // ------------------------------ FunctionCallBracketNode ---------------------------------- @@ -454,11 +463,11 @@ RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, { RefPtr<RegisterID> base = generator.emitNode(m_base); RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStartOffset(), subexpressionEndOffset(), subexpressionLine(), subexpressionLineStart()); RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property); CallArguments callArguments(generator, m_args); generator.emitMove(callArguments.thisRegister(), base.get()); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } // ------------------------------ FunctionCallDotNode ---------------------------------- @@ -468,9 +477,9 @@ RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, Regi RefPtr<RegisterID> function = generator.tempDestination(dst); CallArguments callArguments(generator, m_args); generator.emitNode(callArguments.thisRegister(), m_base); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStartOffset(), subexpressionEndOffset(), subexpressionLine(), subexpressionLineStart()); generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -478,7 +487,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr<Label> realCall = generator.newLabel(); RefPtr<Label> end = generator.newLabel(); RefPtr<RegisterID> base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStartOffset(), subexpressionEndOffset(), subexpressionLine(), subexpressionLineStart()); RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); RefPtr<RegisterID> finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get()); generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); @@ -490,7 +499,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); CallArguments callArguments(generator, m_args); generator.emitNode(callArguments.thisRegister(), oldList->m_expr); - generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitJump(end.get()); m_args->m_listNode = oldList; @@ -498,7 +507,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitJump(end.get()); } } @@ -506,7 +515,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, { CallArguments callArguments(generator, m_args); generator.emitMove(callArguments.thisRegister(), base.get()); - generator.emitCall(finalDestinationOrIgnored.get(), function.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + generator.emitCall(finalDestinationOrIgnored.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } generator.emitLabel(end.get()); return finalDestinationOrIgnored.get(); @@ -528,7 +537,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr<Label> realCall = generator.newLabel(); RefPtr<Label> end = generator.newLabel(); RefPtr<RegisterID> base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStartOffset(), subexpressionEndOffset(), subexpressionLine(), subexpressionLineStart()); RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); RefPtr<RegisterID> finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get()); generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); @@ -539,24 +548,24 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, if (m_args->m_listNode->m_next) { ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray()); ASSERT(!m_args->m_listNode->m_next->m_next); - m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.globalData(), 0, 0); + m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.vm(), 0, 0); RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); CallArguments callArguments(generator, m_args); generator.emitNode(callArguments.thisRegister(), oldList->m_expr); - generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } else { m_args->m_listNode = m_args->m_listNode->m_next; RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); CallArguments callArguments(generator, m_args); generator.emitNode(callArguments.thisRegister(), oldList->m_expr); - generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } m_args->m_listNode = oldList; } else { RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } } else { ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); @@ -577,7 +586,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, while ((args = args->m_next)) generator.emitNode(args->m_expr); - generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), startOffset(), endOffset()); + generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } generator.emitJump(end.get()); } @@ -585,7 +594,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, { CallArguments callArguments(generator, m_args); generator.emitMove(callArguments.thisRegister(), base.get()); - generator.emitCall(finalDestinationOrIgnored.get(), function.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset()); + generator.emitCall(finalDestinationOrIgnored.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } generator.emitLabel(end.get()); return finalDestinationOrIgnored.get(); @@ -593,52 +602,60 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, // ------------------------------ PostfixNode ---------------------------------- -static RegisterID* emitPreIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) +static RegisterID* emitIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) { - return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(srcDst); + return (oper == OpPlusPlus) ? generator.emitInc(srcDst) : generator.emitDec(srcDst); } static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) { - if (srcDst == dst) - return generator.emitToJSNumber(dst, srcDst); - return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst); + if (dst == srcDst) + return generator.emitToNumber(generator.finalDestination(dst), srcDst); + RefPtr<RegisterID> tmp = generator.emitToNumber(generator.tempDestination(dst), srcDst); + emitIncOrDec(generator, srcDst, oper); + return generator.moveToDestinationIfNeeded(dst, tmp.get()); } RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst) { + if (dst == generator.ignoredResult()) + return PrefixNode::emitResolve(generator, dst); + 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 (RefPtr<RegisterID> local = resolveResult.local()) { if (resolveResult.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); - return generator.emitToJSNumber(generator.finalDestination(dst), local); + local = generator.emitMove(generator.tempDestination(dst), local.get()); } - if (dst == generator.ignoredResult()) - return emitPreIncOrDec(generator, local, m_operator); - return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); + return emitPostIncOrDec(generator, generator.finalDestination(dst), local.get(), m_operator); } - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + + if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { + RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, ident); + RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); + generator.emitPutStaticVar(resolveResult, ident, value.get()); + return oldValue.get(); + } + + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); RefPtr<RegisterID> value = generator.newTemporary(); NonlocalResolveInfo resolveInfo; RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), value.get(), resolveResult, ident, resolveInfo); - RegisterID* oldValue; - if (dst == generator.ignoredResult()) { - oldValue = 0; - emitPreIncOrDec(generator, value.get(), m_operator); - } else - oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); + RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); generator.emitPutToBase(base.get(), ident, value.get(), resolveInfo); - return oldValue; + return oldValue.get(); } RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst) { + if (dst == generator.ignoredResult()) + return PrefixNode::emitBracket(generator, dst); + ASSERT(m_expr->isBracketAccessorNode()); BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr); ExpressionNode* baseNode = bracketAccessor->base(); @@ -647,22 +664,19 @@ RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* d 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()); + generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStartOffset(), bracketAccessor->divotEndOffset(), bracketAccessor->divotLine(), bracketAccessor->divotLineStart()); RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); - if (dst == generator.ignoredResult()) { - 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.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitPutByVal(base.get(), property.get(), value.get()); return generator.moveToDestinationIfNeeded(dst, oldValue); } RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) { + if (dst == generator.ignoredResult()) + return PrefixNode::emitDot(generator, dst); + ASSERT(m_expr->isDotAccessorNode()); DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr); ExpressionNode* baseNode = dotAccessor->base(); @@ -670,16 +684,10 @@ RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) RefPtr<RegisterID> base = generator.emitNode(baseNode); - generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->startOffset(), dotAccessor->endOffset()); + generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStartOffset(), dotAccessor->divotEndOffset(), dotAccessor->divotLine(), dotAccessor->divotLineStart()); RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), ident); - if (dst == generator.ignoredResult()) { - 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.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitPutById(base.get(), ident, value.get()); return generator.moveToDestinationIfNeeded(dst, oldValue); } @@ -708,7 +716,7 @@ RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, Regist if (resolveResult.isRegister()) return generator.emitLoad(generator.finalDestination(dst), false); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident); return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); } @@ -720,7 +728,7 @@ RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, Regist RefPtr<RegisterID> r0 = generator.emitNode(m_base); RegisterID* r1 = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); } @@ -730,7 +738,7 @@ RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID { RegisterID* r0 = generator.emitNode(m_base); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); } @@ -767,6 +775,11 @@ RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, Regist return generator.emitTypeOf(generator.finalDestination(dst), local); } + if (resolveResult.isStatic()) { + RefPtr<RegisterID> scratch = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident); + return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); + } + RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident); generator.emitGetById(scratch.get(), scratch.get(), m_ident); if (dst == generator.ignoredResult()) @@ -795,24 +808,27 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds const Identifier& ident = resolve->identifier(); ResolveResult resolveResult = generator.resolve(ident); - if (RegisterID* local = resolveResult.local()) { + if (RefPtr<RegisterID> local = resolveResult.local()) { if (resolveResult.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); - if (dst == generator.ignoredResult()) - 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()); + local = generator.emitMove(generator.tempDestination(dst), local.get()); } - emitPreIncOrDec(generator, local, m_operator); - return generator.moveToDestinationIfNeeded(dst, local); + emitIncOrDec(generator, local.get(), m_operator); + return generator.moveToDestinationIfNeeded(dst, local.get()); + } + + if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { + RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, ident); + emitIncOrDec(generator, propDst.get(), m_operator); + generator.emitPutStaticVar(resolveResult, ident, propDst.get()); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); } - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); RefPtr<RegisterID> propDst = generator.tempDestination(dst); NonlocalResolveInfo resolveVerifier; RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), propDst.get(), resolveResult, ident, resolveVerifier); - emitPreIncOrDec(generator, propDst.get(), m_operator); + emitIncOrDec(generator, propDst.get(), m_operator); generator.emitPutToBase(base.get(), ident, propDst.get(), resolveVerifier); return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -828,10 +844,10 @@ RegisterID* PrefixNode::emitBracket(BytecodeGenerator& generator, RegisterID* ds RefPtr<RegisterID> property = generator.emitNode(subscript); RefPtr<RegisterID> propDst = generator.tempDestination(dst); - generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->startOffset(), bracketAccessor->endOffset()); + generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStartOffset(), bracketAccessor->divotEndOffset(), bracketAccessor->divotLine(), bracketAccessor->divotLineStart()); RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); - emitPreIncOrDec(generator, value, m_operator); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + emitIncOrDec(generator, value, m_operator); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitPutByVal(base.get(), property.get(), value); return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -846,10 +862,10 @@ RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) RefPtr<RegisterID> base = generator.emitNode(baseNode); RefPtr<RegisterID> propDst = generator.tempDestination(dst); - generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->startOffset(), dotAccessor->endOffset()); + generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStartOffset(), dotAccessor->divotEndOffset(), dotAccessor->divotLine(), dotAccessor->divotLineStart()); RegisterID* value = generator.emitGetById(propDst.get(), base.get(), ident); - emitPreIncOrDec(generator, value, m_operator); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + emitIncOrDec(generator, value, m_operator); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitPutById(base.get(), ident, value); return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -875,6 +891,7 @@ RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RegisterID* src = generator.emitNode(m_expr); + generator.emitExpressionInfo(startOffset(), 0, 0, lineNo(), lineStartOffset()); return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); } @@ -889,12 +906,10 @@ RegisterID* BitwiseNotNode::emitBytecode(BytecodeGenerator& generator, RegisterI // ------------------------------ LogicalNotNode ----------------------------------- -void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) +void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { - ASSERT(expr()->hasConditionContextCodegen()); - // reverse the true and false targets - generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, !fallThroughMeansTrue); + generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, invert(fallThroughMode)); } @@ -1008,7 +1023,7 @@ RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* d // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. if (emitExpressionInfoForMe) - generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); + generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->divotStartOffset(), emitExpressionInfoForMe->divotEndOffset(), emitExpressionInfoForMe->divotLine(), emitExpressionInfoForMe->divotLineStart()); // If there is an assignment convert the lhs now. This will also copy lhs to // the temporary register we allocated for it. @@ -1018,12 +1033,72 @@ RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* d return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); } +void BinaryOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) +{ + TriState branchCondition; + ExpressionNode* branchExpression; + tryFoldToBranch(generator, branchCondition, branchExpression); + + if (branchCondition == MixedTriState) + ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); + else if (branchCondition == TrueTriState) + generator.emitNodeInConditionContext(branchExpression, trueTarget, falseTarget, fallThroughMode); + else + generator.emitNodeInConditionContext(branchExpression, falseTarget, trueTarget, invert(fallThroughMode)); +} + +static inline bool canFoldToBranch(OpcodeID opcodeID, ExpressionNode* branchExpression, JSValue constant) +{ + ResultType expressionType = branchExpression->resultDescriptor(); + + if (expressionType.definitelyIsBoolean() && constant.isBoolean()) + return true; + else if (expressionType.definitelyIsBoolean() && constant.isInt32() && (constant.asInt32() == 0 || constant.asInt32() == 1)) + return opcodeID == op_eq || opcodeID == op_neq; // Strict equality is false in the case of type mismatch. + else if (expressionType.isInt32() && constant.isInt32() && constant.asInt32() == 0) + return true; + + return false; +} + +void BinaryOpNode::tryFoldToBranch(BytecodeGenerator& generator, TriState& branchCondition, ExpressionNode*& branchExpression) +{ + branchCondition = MixedTriState; + branchExpression = 0; + + ConstantNode* constant = 0; + if (m_expr1->isConstant()) { + constant = static_cast<ConstantNode*>(m_expr1); + branchExpression = m_expr2; + } else if (m_expr2->isConstant()) { + constant = static_cast<ConstantNode*>(m_expr2); + branchExpression = m_expr1; + } + + if (!constant) + return; + ASSERT(branchExpression); + + OpcodeID opcodeID = this->opcodeID(); + JSValue value = constant->jsValue(generator); + bool canFoldToBranch = JSC::canFoldToBranch(opcodeID, branchExpression, value); + if (!canFoldToBranch) + return; + + if (opcodeID == op_eq || opcodeID == op_stricteq) + branchCondition = triState(value.pureToBoolean()); + else if (opcodeID == op_neq || opcodeID == op_nstricteq) + branchCondition = triState(!value.pureToBoolean()); +} + RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { OpcodeID opcodeID = this->opcodeID(); - if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) + if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) { + generator.emitExpressionInfo(startOffset(), 0, 0, lineNo(), lineStartOffset()); return emitStrcat(generator, dst); + } if (opcodeID == op_neq) { if (m_expr1->isNull() || m_expr2->isNull()) { @@ -1033,19 +1108,28 @@ RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* } } - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - if (generator.m_lastOpcodeID == op_typeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) { + ExpressionNode* left = m_expr1; + ExpressionNode* right = m_expr2; + if (opcodeID == op_neq || opcodeID == op_nstricteq) { + if (left->isString()) + std::swap(left, right); + } + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); + bool wasTypeof = generator.m_lastOpcodeID == op_typeof; + RegisterID* src2 = generator.emitNode(right); + generator.emitExpressionInfo(startOffset(), 0, 0, lineNo(), lineStartOffset()); + if (wasTypeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) { RefPtr<RegisterID> tmp = generator.tempDestination(dst); if (opcodeID == op_neq) generator.emitEqualityOp(op_eq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2); else if (opcodeID == op_nstricteq) generator.emitEqualityOp(op_stricteq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2); else - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return generator.emitUnaryOp(op_not, generator.finalDestination(dst, tmp.get()), tmp.get()); } - return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); + return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(left->resultDescriptor(), right->resultDescriptor())); } RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -1056,15 +1140,25 @@ RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); } - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); + ExpressionNode* left = m_expr1; + ExpressionNode* right = m_expr2; + if (left->isString()) + std::swap(left, right); + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(right); return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2); } RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); + ExpressionNode* left = m_expr1; + ExpressionNode* right = m_expr2; + if (left->isString()) + std::swap(left, right); + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(right); return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2); } @@ -1072,7 +1166,7 @@ RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, Re { RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); RegisterID* src2 = generator.emitNode(m_expr2); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); } @@ -1084,13 +1178,13 @@ RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterI RefPtr<RegisterID> dstReg = generator.finalDestination(dst, src1.get()); RefPtr<Label> target = generator.newLabel(); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitCheckHasInstance(dstReg.get(), src1.get(), src2.get(), target.get()); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitGetById(prototype.get(), src2.get(), generator.globalData()->propertyNames->prototype); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); + generator.emitGetById(prototype.get(), src2.get(), generator.vm()->propertyNames->prototype); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); RegisterID* result = generator.emitInstanceOf(dstReg.get(), src1.get(), prototype.get()); generator.emitLabel(target.get()); return result; @@ -1114,32 +1208,16 @@ RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID return generator.moveToDestinationIfNeeded(dst, temp.get()); } -void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) +void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { - if (m_expr1->hasConditionContextCodegen()) { - RefPtr<Label> afterExpr1 = generator.newLabel(); - if (m_operator == OpLogicalAnd) - generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, true); - else - generator.emitNodeInConditionContext(m_expr1, trueTarget, afterExpr1.get(), false); - generator.emitLabel(afterExpr1.get()); - } else { - RegisterID* temp = generator.emitNode(m_expr1); - if (m_operator == OpLogicalAnd) - generator.emitJumpIfFalse(temp, falseTarget); - else - generator.emitJumpIfTrue(temp, trueTarget); - } + RefPtr<Label> afterExpr1 = generator.newLabel(); + if (m_operator == OpLogicalAnd) + generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, FallThroughMeansTrue); + else + generator.emitNodeInConditionContext(m_expr1, trueTarget, afterExpr1.get(), FallThroughMeansFalse); + generator.emitLabel(afterExpr1.get()); - if (m_expr2->hasConditionContextCodegen()) - generator.emitNodeInConditionContext(m_expr2, trueTarget, falseTarget, fallThroughMeansTrue); - else { - RegisterID* temp = generator.emitNode(m_expr2); - if (fallThroughMeansTrue) - generator.emitJumpIfFalse(temp, falseTarget); - else - generator.emitJumpIfTrue(temp, trueTarget); - } + generator.emitNodeInConditionContext(m_expr2, trueTarget, falseTarget, fallThroughMode); } // ------------------------------ ConditionalNode ------------------------------ @@ -1150,14 +1228,9 @@ RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, Register RefPtr<Label> beforeElse = generator.newLabel(); RefPtr<Label> afterElse = generator.newLabel(); - if (m_logical->hasConditionContextCodegen()) { - RefPtr<Label> beforeThen = generator.newLabel(); - generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), true); - generator.emitLabel(beforeThen.get()); - } else { - RegisterID* cond = generator.emitNode(m_logical); - generator.emitJumpIfFalse(cond, beforeElse.get()); - } + RefPtr<Label> beforeThen = generator.newLabel(); + generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue); + generator.emitLabel(beforeThen.get()); generator.emitNode(newDst.get(), m_expr1); generator.emitJump(afterElse.get()); @@ -1213,7 +1286,7 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& gen opcodeID = op_mod; break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return dst; } @@ -1222,7 +1295,7 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& gen // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. if (emitExpressionInfoForMe) - generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); + generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->divotStartOffset(), emitExpressionInfoForMe->divotEndOffset(), emitExpressionInfoForMe->divotLine(), emitExpressionInfoForMe->divotLineStart()); return generator.emitBinaryOp(opcodeID, dst, src1, src2, types); } @@ -1249,8 +1322,15 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re return generator.moveToDestinationIfNeeded(dst, result); } + if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { + RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident); + RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + generator.emitPutStaticVar(resolveResult, m_ident, result); + return result; + } + RefPtr<RegisterID> src1 = generator.tempDestination(dst); - generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0); + generator.emitExpressionInfo(divot() - divotStartOffset() + m_ident.length(), m_ident.length(), 0, divotLine(), divotLineStart()); NonlocalResolveInfo resolveVerifier; RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), src1.get(), resolveResult, m_ident, resolveVerifier); RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); @@ -1272,12 +1352,22 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist return generator.moveToDestinationIfNeeded(dst, result); } + if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { + if (dst == generator.ignoredResult()) + dst = 0; + RegisterID* value = generator.emitNode(dst, m_right); + generator.emitPutStaticVar(resolveResult, m_ident, value); + return value; + } + NonlocalResolveInfo resolveVerifier; + if (generator.isStrictMode()) + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident, resolveVerifier); if (dst == generator.ignoredResult()) dst = 0; RegisterID* value = generator.emitNode(dst, m_right); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitPutToBase(base.get(), m_ident, value, resolveVerifier); } @@ -1288,7 +1378,7 @@ RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); RegisterID* result = generator.emitNode(value.get(), m_right); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result : generator.moveToDestinationIfNeeded(generator.tempDestination(result), result); generator.emitPutById(base.get(), m_ident, forwardResult); return generator.moveToDestinationIfNeeded(dst, forwardResult); @@ -1300,11 +1390,11 @@ RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, Regist { RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStartOffset(), subexpressionEndOffset(), subexpressionLine(), subexpressionLineStart()); RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitPutById(base.get(), m_ident, updatedValue); } @@ -1324,7 +1414,7 @@ RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, Regist RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); RegisterID* result = generator.emitNode(value.get(), m_right); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result : generator.moveToDestinationIfNeeded(generator.tempDestination(result), result); generator.emitPutByVal(base.get(), property.get(), forwardResult); return generator.moveToDestinationIfNeeded(dst, forwardResult); @@ -1337,11 +1427,11 @@ RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, Re RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStartOffset(), subexpressionEndOffset(), subexpressionLine(), subexpressionLineStart()); RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitPutByVal(base.get(), property.get(), updatedValue); return updatedValue; @@ -1373,10 +1463,9 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); - if (generator.codeType() == GlobalCode) { - if (RegisterID* result = generator.emitInitGlobalConst(m_ident, value.get())) - return result; - } + if (generator.codeType() == GlobalCode) + return generator.emitInitGlobalConst(m_ident, value.get()); + if (generator.codeType() != EvalCode) return value.get(); @@ -1396,10 +1485,10 @@ RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID // ------------------------------ ConstStatementNode ----------------------------- -RegisterID* ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +void ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); - return generator.emitNode(m_next); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); + generator.emitNode(m_next); } // ------------------------------ SourceElements ------------------------------- @@ -1430,142 +1519,143 @@ inline StatementNode* BlockNode::singleStatement() const return m_statements ? m_statements->singleStatement() : 0; } -RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (m_statements) - m_statements->emitBytecode(generator, dst); - return 0; + if (!m_statements) + return; + m_statements->emitBytecode(generator, dst); } // ------------------------------ EmptyStatementNode --------------------------- -RegisterID* EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); - return dst; + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); } // ------------------------------ DebuggerStatementNode --------------------------- -RegisterID* DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine(), column()); - return dst; + generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine(), startOffset(), lineStartOffset()); } // ------------------------------ ExprStatementNode ---------------------------- -RegisterID* ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { ASSERT(m_expr); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); - return generator.emitNode(dst, m_expr); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); + generator.emitNode(dst, m_expr); } // ------------------------------ VarStatementNode ---------------------------- -RegisterID* VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +void VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { ASSERT(m_expr); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); - return generator.emitNode(m_expr); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); + generator.emitNode(m_expr); } -// ------------------------------ IfNode --------------------------------------- +// ------------------------------ IfElseNode --------------------------------------- -RegisterID* IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +static inline StatementNode* singleStatement(StatementNode* statementNode) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); - - RefPtr<Label> afterThen = generator.newLabel(); + if (statementNode->isBlock()) + return static_cast<BlockNode*>(statementNode)->singleStatement(); + return statementNode; +} - if (m_condition->hasConditionContextCodegen()) { - RefPtr<Label> beforeThen = generator.newLabel(); - generator.emitNodeInConditionContext(m_condition, beforeThen.get(), afterThen.get(), true); - generator.emitLabel(beforeThen.get()); - } else { - RegisterID* cond = generator.emitNode(m_condition); - generator.emitJumpIfFalse(cond, afterThen.get()); +bool IfElseNode::tryFoldBreakAndContinue(BytecodeGenerator& generator, StatementNode* ifBlock, + Label*& trueTarget, FallThroughMode& fallThroughMode) +{ + StatementNode* singleStatement = JSC::singleStatement(ifBlock); + if (!singleStatement) + return false; + + if (singleStatement->isBreak()) { + BreakNode* breakNode = static_cast<BreakNode*>(singleStatement); + Label* target = breakNode->trivialTarget(generator); + if (!target) + return false; + trueTarget = target; + fallThroughMode = FallThroughMeansFalse; + return true; } - generator.emitNode(dst, m_ifBlock); - generator.emitLabel(afterThen.get()); + if (singleStatement->isContinue()) { + ContinueNode* continueNode = static_cast<ContinueNode*>(singleStatement); + Label* target = continueNode->trivialTarget(generator); + if (!target) + return false; + trueTarget = target; + fallThroughMode = FallThroughMeansFalse; + return true; + } - // FIXME: This should return the last statement executed so that it can be returned as a Completion. - return 0; + return false; } -// ------------------------------ IfElseNode --------------------------------------- - -RegisterID* IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); + RefPtr<Label> beforeThen = generator.newLabel(); RefPtr<Label> beforeElse = generator.newLabel(); RefPtr<Label> afterElse = generator.newLabel(); - if (m_condition->hasConditionContextCodegen()) { - RefPtr<Label> beforeThen = generator.newLabel(); - generator.emitNodeInConditionContext(m_condition, beforeThen.get(), beforeElse.get(), true); - generator.emitLabel(beforeThen.get()); - } else { - RegisterID* cond = generator.emitNode(m_condition); - generator.emitJumpIfFalse(cond, beforeElse.get()); - } + Label* trueTarget = beforeThen.get(); + Label* falseTarget = beforeElse.get(); + FallThroughMode fallThroughMode = FallThroughMeansTrue; + bool didFoldIfBlock = tryFoldBreakAndContinue(generator, m_ifBlock, trueTarget, fallThroughMode); - generator.emitNode(dst, m_ifBlock); - generator.emitJump(afterElse.get()); + generator.emitNodeInConditionContext(m_condition, trueTarget, falseTarget, fallThroughMode); + generator.emitLabel(beforeThen.get()); + + if (!didFoldIfBlock) { + generator.emitNode(dst, m_ifBlock); + if (m_elseBlock) + generator.emitJump(afterElse.get()); + } generator.emitLabel(beforeElse.get()); - generator.emitNode(dst, m_elseBlock); + if (m_elseBlock) + generator.emitNode(dst, m_elseBlock); generator.emitLabel(afterElse.get()); - - // FIXME: This should return the last statement executed so that it can be returned as a Completion. - return 0; } // ------------------------------ DoWhileNode ---------------------------------- -RegisterID* DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); RefPtr<Label> topOfLoop = generator.newLabel(); generator.emitLabel(topOfLoop.get()); generator.emitLoopHint(); - generator.emitDebugHook(WillExecuteStatement, lastLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, lastLine(), lastLine(), startOffset(), lineStartOffset()); - RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); + generator.emitNode(dst, m_statement); generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, lastLine(), lastLine(), column()); - if (m_expr->hasConditionContextCodegen()) - generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), false); - else { - RegisterID* cond = generator.emitNode(m_expr); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - } + generator.emitDebugHook(WillExecuteStatement, lastLine(), lastLine(), startOffset(), lineStartOffset()); + generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); generator.emitLabel(scope->breakTarget()); - return result.get(); } // ------------------------------ WhileNode ------------------------------------ -RegisterID* WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); RefPtr<Label> topOfLoop = generator.newLabel(); - generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo(), m_expr->columnNo()); - if (m_expr->hasConditionContextCodegen()) - generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), true); - else { - RegisterID* cond = generator.emitNode(m_expr); - generator.emitJumpIfFalse(cond, scope->breakTarget()); - } + generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo(), m_expr->startOffset(), m_expr->lineStartOffset()); + generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); generator.emitLabel(topOfLoop.get()); generator.emitLoopHint(); @@ -1573,76 +1663,58 @@ RegisterID* WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds generator.emitNode(dst, m_statement); generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); - if (m_expr->hasConditionContextCodegen()) - generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), false); - else { - RegisterID* cond = generator.emitNode(m_expr); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - } + generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); generator.emitLabel(scope->breakTarget()); - - // FIXME: This should return the last statement executed so that it can be returned as a Completion - return 0; } // ------------------------------ ForNode -------------------------------------- -RegisterID* ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); if (m_expr1) generator.emitNode(generator.ignoredResult(), m_expr1); RefPtr<Label> topOfLoop = generator.newLabel(); - if (m_expr2) { - if (m_expr2->hasConditionContextCodegen()) - generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), true); - else { - RegisterID* cond = generator.emitNode(m_expr2); - generator.emitJumpIfFalse(cond, scope->breakTarget()); - } - } + if (m_expr2) + generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); generator.emitLabel(topOfLoop.get()); generator.emitLoopHint(); - RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); + generator.emitNode(dst, m_statement); generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); if (m_expr3) generator.emitNode(generator.ignoredResult(), m_expr3); - if (m_expr2) { - if (m_expr2->hasConditionContextCodegen()) - generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), false); - else { - RegisterID* cond = generator.emitNode(m_expr2); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - } - } else + if (m_expr2) + generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); + else generator.emitJump(topOfLoop.get()); generator.emitLabel(scope->breakTarget()); - return result.get(); } // ------------------------------ ForInNode ------------------------------------ -RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); - if (!m_lexpr->isLocation()) - return emitThrowReferenceError(generator, "Left side of for-in statement is not a reference."); + if (!m_lexpr->isLocation()) { + emitThrowReferenceError(generator, "Left side of for-in statement is not a reference."); + return; + } - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); if (m_init) generator.emitNode(generator.ignoredResult(), m_init); @@ -1669,9 +1741,11 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds propertyName = generator.newTemporary(); RefPtr<RegisterID> protect = propertyName; NonlocalResolveInfo resolveVerifier; + if (generator.isStrictMode()) + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident, resolveVerifier); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitPutToBase(base, ident, propertyName, resolveVerifier); } else { expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName); @@ -1685,7 +1759,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds RefPtr<RegisterID> protect = propertyName; RegisterID* base = generator.emitNode(assignNode->base()); - generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); + generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStartOffset(), assignNode->divotEndOffset(), assignNode->divotLine(), assignNode->divotLineStart()); generator.emitPutById(base, ident, propertyName); } else { ASSERT(m_lexpr->isBracketAccessorNode()); @@ -1695,7 +1769,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); RegisterID* subscript = generator.emitNode(assignNode->subscript()); - generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); + generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStartOffset(), assignNode->divotEndOffset(), assignNode->divotLine(), assignNode->divotLineStart()); generator.emitPutByVal(base.get(), subscript, propertyName); } @@ -1706,83 +1780,104 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds generator.emitLabel(scope->continueTarget()); generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get()); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); generator.emitLabel(scope->breakTarget()); - return dst; } // ------------------------------ ContinueNode --------------------------------- -// ECMA 12.7 -RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +Label* ContinueNode::trivialTarget(BytecodeGenerator& generator) +{ + if (generator.shouldEmitDebugHooks()) + return 0; + + LabelScope* scope = generator.continueTarget(m_ident); + ASSERT(scope); + + if (generator.scopeDepth() != scope->scopeDepth()) + return 0; + + return scope->continueTarget(); +} + +void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); LabelScope* scope = generator.continueTarget(m_ident); ASSERT(scope); - generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth()); - return dst; + generator.emitPopScopes(scope->scopeDepth()); + generator.emitJump(scope->continueTarget()); } // ------------------------------ BreakNode ------------------------------------ -// ECMA 12.8 -RegisterID* BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +Label* BreakNode::trivialTarget(BytecodeGenerator& generator) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + if (generator.shouldEmitDebugHooks()) + return 0; + + LabelScope* scope = generator.breakTarget(m_ident); + ASSERT(scope); + + if (generator.scopeDepth() != scope->scopeDepth()) + return 0; + + return scope->breakTarget(); +} + +void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); LabelScope* scope = generator.breakTarget(m_ident); ASSERT(scope); - generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth()); - return dst; + generator.emitPopScopes(scope->scopeDepth()); + generator.emitJump(scope->breakTarget()); } // ------------------------------ ReturnNode ----------------------------------- -RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); ASSERT(generator.codeType() == FunctionCode); if (dst == generator.ignoredResult()) dst = 0; - RegisterID* r0 = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); - RefPtr<RegisterID> returnRegister; + + RefPtr<RegisterID> returnRegister = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); if (generator.scopeDepth()) { - RefPtr<Label> l0 = generator.newLabel(); - if (generator.hasFinaliser()) { - returnRegister = generator.emitMove(generator.newTemporary(), r0); - r0 = returnRegister.get(); - } - generator.emitJumpScopes(l0.get(), 0); - generator.emitLabel(l0.get()); + returnRegister = generator.emitMove(generator.newTemporary(), returnRegister.get()); + generator.emitPopScopes(0); } - generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine(), column()); - return generator.emitReturn(r0); + + generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine(), startOffset(), lineStartOffset()); + generator.emitReturn(returnRegister.get()); } // ------------------------------ WithNode ------------------------------------- -RegisterID* WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); RefPtr<RegisterID> scope = generator.emitNode(m_expr); - generator.emitExpressionInfo(m_divot, m_expressionLength, 0); + generator.emitExpressionInfo(m_divot, m_expressionLength, 0, m_divotLine, m_divotLineStart); generator.emitPushWithScope(scope.get()); - RegisterID* result = generator.emitNode(dst, m_statement); + generator.emitNode(dst, m_statement); generator.emitPopScope(); - return result; } // ------------------------------ CaseClauseNode -------------------------------- inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (m_statements) - m_statements->emitBytecode(generator, dst); + if (!m_statements) + return; + m_statements->emitBytecode(generator, dst); } // ------------------------------ CaseBlockNode -------------------------------- @@ -1833,9 +1928,22 @@ static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& break; } } - -SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) + +static inline size_t length(ClauseListNode* list1, ClauseListNode* list2) +{ + size_t length = 0; + for (ClauseListNode* node = list1; node; node = node->getNext()) + ++length; + for (ClauseListNode* node = list2; node; node = node->getNext()) + ++length; + return length; +} + +SwitchInfo::SwitchType CaseBlockNode::tryTableSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) { + if (length(m_list1, m_list2) < s_tableSwitchMinimum) + return SwitchInfo::SwitchNone; + SwitchKind typeForTable = SwitchUnset; bool singleCharacterSwitch = true; @@ -1863,14 +1971,14 @@ SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, return SwitchInfo::SwitchString; } -RegisterID* CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) +void CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) { RefPtr<Label> defaultLabel; Vector<RefPtr<Label>, 8> labelVector; Vector<ExpressionNode*, 8> literalVector; int32_t min_num = std::numeric_limits<int32_t>::max(); int32_t max_num = std::numeric_limits<int32_t>::min(); - SwitchInfo::SwitchType switchType = tryOptimizedSwitch(literalVector, min_num, max_num); + SwitchInfo::SwitchType switchType = tryTableSwitch(literalVector, min_num, max_num); if (switchType != SwitchInfo::SwitchNone) { // Prepare the various labels @@ -1899,8 +2007,6 @@ RegisterID* CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, Re generator.emitJump(defaultLabel.get()); } - RegisterID* result = 0; - size_t i = 0; for (ClauseListNode* list = m_list1; list; list = list->getNext()) { generator.emitLabel(labelVector[i++].get()); @@ -1924,61 +2030,57 @@ RegisterID* CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, Re ASSERT(labelVector.size() == literalVector.size()); generator.endSwitch(labelVector.size(), labelVector.data(), literalVector.data(), defaultLabel.get(), min_num, max_num); } - return result; } // ------------------------------ SwitchNode ----------------------------------- -RegisterID* SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); + LabelScopePtr scope = generator.newLabelScope(LabelScope::Switch); RefPtr<RegisterID> r0 = generator.emitNode(m_expr); - RegisterID* r1 = m_block->emitBytecodeForBlock(generator, r0.get(), dst); + m_block->emitBytecodeForBlock(generator, r0.get(), dst); generator.emitLabel(scope->breakTarget()); - return r1; } // ------------------------------ LabelNode ------------------------------------ -RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); ASSERT(!generator.breakTarget(m_name)); - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); - RegisterID* r0 = generator.emitNode(dst, m_statement); + LabelScopePtr scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); + generator.emitNode(dst, m_statement); generator.emitLabel(scope->breakTarget()); - return r0; } // ------------------------------ ThrowNode ------------------------------------ -RegisterID* ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); if (dst == generator.ignoredResult()) dst = 0; RefPtr<RegisterID> expr = generator.emitNode(m_expr); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitThrow(expr.get()); - return 0; } // ------------------------------ TryNode -------------------------------------- -RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { // NOTE: The catch and finally blocks must be labeled explicitly, so the // optimizer knows they may be jumped to from anywhere. - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), startOffset(), lineStartOffset()); ASSERT(m_catchBlock || m_finallyBlock); @@ -2031,53 +2133,50 @@ RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitLabel(finallyEndLabel.get()); } - - return dst; } // ------------------------------ ScopeNode ----------------------------- inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (m_statements) - m_statements->emitBytecode(generator, dst); + if (!m_statements) + return; + m_statements->emitBytecode(generator, dst); } // ------------------------------ ProgramNode ----------------------------- -RegisterID* ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +void ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteProgram, startLine(), startLine(), startStartOffset(), startLineStartOffset()); RefPtr<RegisterID> dstRegister = generator.newTemporary(); generator.emitLoad(dstRegister.get(), jsUndefined()); emitStatementsBytecode(generator, dstRegister.get()); - generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine(), column()); + generator.emitDebugHook(DidExecuteProgram, lastLine(), lastLine(), startOffset(), lineStartOffset()); generator.emitEnd(dstRegister.get()); - return 0; } // ------------------------------ EvalNode ----------------------------- -RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +void EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine(), column()); + generator.emitDebugHook(WillExecuteProgram, startLine(), startLine(), startStartOffset(), startLineStartOffset()); RefPtr<RegisterID> dstRegister = generator.newTemporary(); generator.emitLoad(dstRegister.get(), jsUndefined()); emitStatementsBytecode(generator, dstRegister.get()); - generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine(), column()); + generator.emitDebugHook(DidExecuteProgram, lastLine(), lastLine(), startOffset(), lineStartOffset()); generator.emitEnd(dstRegister.get()); - return 0; } // ------------------------------ FunctionBodyNode ----------------------------- -RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +void FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine(), column()); + generator.emitDebugHook(DidEnterCallFrame, startLine(), startLine(), startStartOffset(), startLineStartOffset()); emitStatementsBytecode(generator, generator.ignoredResult()); StatementNode* singleStatement = this->singleStatement(); @@ -2093,9 +2192,10 @@ RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, Registe // If there is no return we must automatically insert one. if (!returnNode) { RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined()); - generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine(), column()); + ASSERT((startOffset() - 1) >= lineStartOffset()); + generator.emitDebugHook(WillLeaveCallFrame, lastLine(), lastLine(), startOffset() - 1, lineStartOffset()); generator.emitReturn(r0); - return 0; + return; } // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare. @@ -2113,17 +2213,12 @@ RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, Registe } } } - - return 0; } // ------------------------------ FuncDeclNode --------------------------------- -RegisterID* FuncDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void FuncDeclNode::emitBytecode(BytecodeGenerator&, RegisterID*) { - if (dst == generator.ignoredResult()) - dst = 0; - return dst; } // ------------------------------ FuncExprNode --------------------------------- diff --git a/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalysis.h b/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalysis.h new file mode 100644 index 000000000..78ee17adf --- /dev/null +++ b/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalysis.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef StaticPropertyAnalysis_h +#define StaticPropertyAnalysis_h + +#include "Executable.h" +#include "JSGlobalObject.h" +#include <wtf/HashSet.h> + +namespace JSC { + +// Reference count indicates number of live registers that alias this object. +class StaticPropertyAnalysis : public RefCounted<StaticPropertyAnalysis> { +public: + static PassRefPtr<StaticPropertyAnalysis> create(Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* instructions, unsigned target) + { + return adoptRef(new StaticPropertyAnalysis(instructions, target)); + } + + void addPropertyIndex(unsigned propertyIndex) { m_propertyIndexes.add(propertyIndex); } + + void record() + { + (*m_instructions)[m_target] = m_propertyIndexes.size(); + } + + int propertyIndexCount() { return m_propertyIndexes.size(); } + +private: + StaticPropertyAnalysis(Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* instructions, unsigned target) + : m_instructions(instructions) + , m_target(target) + { + } + + Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* m_instructions; + unsigned m_target; + typedef HashSet<unsigned, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > PropertyIndexSet; + PropertyIndexSet m_propertyIndexes; +}; + +} // namespace JSC + +#endif // StaticPropertyAnalysis_h diff --git a/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalyzer.h b/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalyzer.h new file mode 100644 index 000000000..dd7f0ab38 --- /dev/null +++ b/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalyzer.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef StaticPropertyAnalyzer_h +#define StaticPropertyAnalyzer_h + +#include "StaticPropertyAnalysis.h" +#include <wtf/HashMap.h> + +namespace JSC { + +// Used for flow-insensitive static analysis of the number of properties assigned to an object. +// We use this analysis with other runtime data to produce an optimization guess. This analysis +// is understood to be lossy, and it's OK if it turns out to be wrong sometimes. +class StaticPropertyAnalyzer { +public: + StaticPropertyAnalyzer(Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>*); + + void createThis(int dst, unsigned offsetOfInlineCapacityOperand); + void newObject(int dst, unsigned offsetOfInlineCapacityOperand); + void putById(int dst, unsigned propertyIndex); // propertyIndex is an index into a uniqued set of strings. + void mov(int dst, int src); + + void kill(); + void kill(int dst); + +private: + void kill(StaticPropertyAnalysis*); + + Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* m_instructions; + typedef HashMap<int, RefPtr<StaticPropertyAnalysis>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int> > AnalysisMap; + AnalysisMap m_analyses; +}; + +inline StaticPropertyAnalyzer::StaticPropertyAnalyzer(Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* instructions) + : m_instructions(instructions) +{ +} + +inline void StaticPropertyAnalyzer::createThis(int dst, unsigned offsetOfInlineCapacityOperand) +{ + AnalysisMap::AddResult addResult = m_analyses.add( + dst, StaticPropertyAnalysis::create(m_instructions, offsetOfInlineCapacityOperand)); + ASSERT_UNUSED(addResult, addResult.isNewEntry); // Can't have two 'this' in the same constructor. +} + +inline void StaticPropertyAnalyzer::newObject(int dst, unsigned offsetOfInlineCapacityOperand) +{ + RefPtr<StaticPropertyAnalysis> analysis = StaticPropertyAnalysis::create(m_instructions, offsetOfInlineCapacityOperand); + AnalysisMap::AddResult addResult = m_analyses.add(dst, analysis); + if (!addResult.isNewEntry) { + kill(addResult.iterator->value.get()); + addResult.iterator->value = analysis.release(); + } +} + +inline void StaticPropertyAnalyzer::putById(int dst, unsigned propertyIndex) +{ + StaticPropertyAnalysis* analysis = m_analyses.get(dst); + if (!analysis) + return; + analysis->addPropertyIndex(propertyIndex); +} + +inline void StaticPropertyAnalyzer::mov(int dst, int src) +{ + RefPtr<StaticPropertyAnalysis> analysis = m_analyses.get(src); + if (!analysis) { + kill(dst); + return; + } + + AnalysisMap::AddResult addResult = m_analyses.add(dst, analysis); + if (!addResult.isNewEntry) { + kill(addResult.iterator->value.get()); + addResult.iterator->value = analysis.release(); + } +} + +inline void StaticPropertyAnalyzer::kill(StaticPropertyAnalysis* analysis) +{ + if (!analysis) + return; + if (!analysis->hasOneRef()) // Aliases for this object still exist, so it might acquire more properties. + return; + analysis->record(); +} + +inline void StaticPropertyAnalyzer::kill(int dst) +{ + // We observe kills in order to avoid piling on properties to an object after + // its bytecode register has been recycled. + + // Consider these cases: + + // (1) Aliased temporary + // var o1 = { name: name }; + // var o2 = { name: name }; + + // (2) Aliased local -- no control flow + // var local; + // local = new Object; + // local.name = name; + // ... + + // local = lookup(); + // local.didLookup = true; + // ... + + // (3) Aliased local -- control flow + // var local; + // if (condition) + // local = { }; + // else { + // local = new Object; + // } + // local.name = name; + + // (Note: our default codegen for "new Object" looks like case (3).) + + // Case (1) is easy because temporaries almost never survive across control flow. + + // Cases (2) and (3) are hard. Case (2) should kill "local", while case (3) should + // not. There is no great way to solve these cases with simple static analysis. + + // Since this is a simple static analysis, we just try to catch the simplest cases, + // so we accept kills to any registers except for registers that have no inferred + // properties yet. + + AnalysisMap::iterator it = m_analyses.find(dst); + if (it == m_analyses.end()) + return; + if (!it->value->propertyIndexCount()) + return; + + kill(it->value.get()); + m_analyses.remove(it); +} + +inline void StaticPropertyAnalyzer::kill() +{ + while (m_analyses.size()) + kill(m_analyses.take(m_analyses.begin()->key).get()); +} + +} // namespace JSC + +#endif // StaticPropertyAnalyzer_h |