diff options
| author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
|---|---|---|
| committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
| commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
| tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /JavaScriptCore/bytecompiler | |
| parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
| download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 | |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'JavaScriptCore/bytecompiler')
| -rw-r--r-- | JavaScriptCore/bytecompiler/BytecodeGenerator.cpp | 2233 | ||||
| -rw-r--r-- | JavaScriptCore/bytecompiler/BytecodeGenerator.h | 588 | ||||
| -rw-r--r-- | JavaScriptCore/bytecompiler/Label.h | 90 | ||||
| -rw-r--r-- | JavaScriptCore/bytecompiler/LabelScope.h | 79 | ||||
| -rw-r--r-- | JavaScriptCore/bytecompiler/NodesCodegen.cpp | 2076 | ||||
| -rw-r--r-- | JavaScriptCore/bytecompiler/RegisterID.h | 121 |
6 files changed, 0 insertions, 5187 deletions
diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp deleted file mode 100644 index 3a99957..0000000 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ /dev/null @@ -1,2233 +0,0 @@ -/* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> - * - * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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. - */ - -#include "config.h" -#include "BytecodeGenerator.h" - -#include "BatchedTransitionOptimizer.h" -#include "PrototypeFunction.h" -#include "JSFunction.h" -#include "Interpreter.h" -#include "UString.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. -*/ - -#ifndef NDEBUG -static bool s_dumpsGeneratedCode = false; -#endif - -void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode) -{ -#ifndef NDEBUG - s_dumpsGeneratedCode = dumpsGeneratedCode; -#else - UNUSED_PARAM(dumpsGeneratedCode); -#endif -} - -bool BytecodeGenerator::dumpsGeneratedCode() -{ -#ifndef NDEBUG - return s_dumpsGeneratedCode; -#else - return false; -#endif -} - -void BytecodeGenerator::generate() -{ - m_codeBlock->setThisRegister(m_thisRegister.index()); - - m_scopeNode->emitBytecode(*this); - -#ifndef NDEBUG - m_codeBlock->setInstructionCount(m_codeBlock->instructions().size()); - - if (s_dumpsGeneratedCode) - m_codeBlock->dump(m_scopeChain->globalObject()->globalExec()); -#endif - - if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode) - symbolTable().clear(); - - m_codeBlock->shrinkToFit(); -} - -bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0) -{ - int index = m_calleeRegisters.size(); - SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); - pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry); - - if (!result.second) { - r0 = ®isterFor(result.first->second.getIndex()); - return false; - } - - r0 = addVar(); - return true; -} - -bool BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0) -{ - int index = m_nextGlobalIndex; - SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); - pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry); - - if (!result.second) - index = result.first->second.getIndex(); - else { - --m_nextGlobalIndex; - m_globals.append(index + m_globalVarStorageOffset); - } - - r0 = ®isterFor(index); - return result.second; -} - -void BytecodeGenerator::preserveLastVar() -{ - if ((m_firstConstantIndex = m_calleeRegisters.size()) != 0) - m_lastVar = &m_calleeRegisters.last(); -} - -BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const ScopeChain& scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock) - : m_shouldEmitDebugHooks(scopeChain.globalObject()->debugger()) - , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) - , m_shouldEmitRichSourceInfo(scopeChain.globalObject()->supportsRichSourceInfo()) - , m_scopeChain(&scopeChain) - , m_symbolTable(symbolTable) - , m_scopeNode(programNode) - , m_codeBlock(codeBlock) - , m_thisRegister(RegisterFile::ProgramCodeThisRegister) - , m_finallyDepth(0) - , m_dynamicScopeDepth(0) - , m_baseScopeDepth(0) - , m_codeType(GlobalCode) - , m_nextGlobalIndex(-1) - , m_nextConstantOffset(0) - , m_globalConstantIndex(0) - , m_hasCreatedActivation(true) - , m_firstLazyFunction(0) - , m_lastLazyFunction(0) - , m_globalData(&scopeChain.globalObject()->globalData()) - , m_lastOpcodeID(op_end) -#ifndef NDEBUG - , m_lastOpcodePosition(0) -#endif - , m_stack(m_globalData->stack()) - , m_usesExceptions(false) - , m_regeneratingForExceptionInfo(false) - , m_codeBlockBeingRegeneratedFrom(0) -{ - if (m_shouldEmitDebugHooks) - m_codeBlock->setNeedsFullScopeChain(true); - - emitOpcode(op_enter); - codeBlock->setGlobalData(m_globalData); - - // FIXME: Move code that modifies the global object to Interpreter::execute. - - m_codeBlock->m_numParameters = 1; // Allocate space for "this" - - JSGlobalObject* globalObject = scopeChain.globalObject(); - ExecState* exec = globalObject->globalExec(); - RegisterFile* registerFile = &exec->globalData().interpreter->registerFile(); - - // Shift register indexes in generated code to elide registers allocated by intermediate stack frames. - m_globalVarStorageOffset = -RegisterFile::CallFrameHeaderSize - m_codeBlock->m_numParameters - registerFile->size(); - - // Add previously defined symbols to bookkeeping. - m_globals.grow(symbolTable->size()); - SymbolTable::iterator end = symbolTable->end(); - for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it) - registerFor(it->second.getIndex()).setIndex(it->second.getIndex() + m_globalVarStorageOffset); - - BatchedTransitionOptimizer optimizer(globalObject); - - const VarStack& varStack = programNode->varStack(); - const FunctionStack& functionStack = programNode->functionStack(); - bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals(); - if (canOptimizeNewGlobals) { - // Shift new symbols so they get stored prior to existing symbols. - m_nextGlobalIndex -= symbolTable->size(); - - for (size_t i = 0; i < functionStack.size(); ++i) { - FunctionBodyNode* function = functionStack[i]; - globalObject->removeDirect(function->ident()); // Make sure our new function is not shadowed by an old property. - emitNewFunction(addGlobalVar(function->ident(), false), function); - } - - Vector<RegisterID*, 32> newVars; - for (size_t i = 0; i < varStack.size(); ++i) - if (!globalObject->hasProperty(exec, *varStack[i].first)) - newVars.append(addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant)); - - preserveLastVar(); - - for (size_t i = 0; i < newVars.size(); ++i) - emitLoad(newVars[i], jsUndefined()); - } else { - for (size_t i = 0; i < functionStack.size(); ++i) { - FunctionBodyNode* function = functionStack[i]; - globalObject->putWithAttributes(exec, function->ident(), new (exec) JSFunction(exec, makeFunction(exec, function), scopeChain.node()), DontDelete); - } - for (size_t i = 0; i < varStack.size(); ++i) { - if (globalObject->hasProperty(exec, *varStack[i].first)) - continue; - int attributes = DontDelete; - if (varStack[i].second & DeclarationStacks::IsConstant) - attributes |= ReadOnly; - globalObject->putWithAttributes(exec, *varStack[i].first, jsUndefined(), attributes); - } - - preserveLastVar(); - } - codeBlock->m_numCapturedVars = codeBlock->m_numVars; -} - -BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock) - : m_shouldEmitDebugHooks(scopeChain.globalObject()->debugger()) - , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) - , m_shouldEmitRichSourceInfo(scopeChain.globalObject()->supportsRichSourceInfo()) - , m_scopeChain(&scopeChain) - , m_symbolTable(symbolTable) - , m_scopeNode(functionBody) - , m_codeBlock(codeBlock) - , m_activationRegister(0) - , m_finallyDepth(0) - , m_dynamicScopeDepth(0) - , m_baseScopeDepth(0) - , m_codeType(FunctionCode) - , m_nextConstantOffset(0) - , m_globalConstantIndex(0) - , m_hasCreatedActivation(false) - , m_firstLazyFunction(0) - , m_lastLazyFunction(0) - , m_globalData(&scopeChain.globalObject()->globalData()) - , m_lastOpcodeID(op_end) -#ifndef NDEBUG - , m_lastOpcodePosition(0) -#endif - , m_stack(m_globalData->stack()) - , m_usesExceptions(false) - , m_regeneratingForExceptionInfo(false) - , m_codeBlockBeingRegeneratedFrom(0) -{ - if (m_shouldEmitDebugHooks) - m_codeBlock->setNeedsFullScopeChain(true); - - codeBlock->setGlobalData(m_globalData); - - emitOpcode(op_enter); - if (m_codeBlock->needsFullScopeChain()) { - m_activationRegister = addVar(); - emitInitLazyRegister(m_activationRegister); - m_codeBlock->setActivationRegister(m_activationRegister->index()); - } - - // Both op_tear_off_activation and op_tear_off_arguments tear off the 'arguments' - // object, if created. - if (m_codeBlock->needsFullScopeChain() || functionBody->usesArguments()) { - RegisterID* unmodifiedArgumentsRegister = addVar(); // Anonymous, so it can't be modified by user code. - RegisterID* argumentsRegister = addVar(propertyNames().arguments, false); // Can be changed by assigning to 'arguments'. - - // We can save a little space by hard-coding the knowledge that the two - // 'arguments' values are stored in consecutive registers, and storing - // only the index of the assignable one. - codeBlock->setArgumentsRegister(argumentsRegister->index()); - ASSERT_UNUSED(unmodifiedArgumentsRegister, unmodifiedArgumentsRegister->index() == JSC::unmodifiedArgumentsRegister(codeBlock->argumentsRegister())); - - emitInitLazyRegister(argumentsRegister); - emitInitLazyRegister(unmodifiedArgumentsRegister); - - if (m_codeBlock->isStrictMode()) { - emitOpcode(op_create_arguments); - instructions().append(argumentsRegister->index()); - } - - // The debugger currently retrieves the arguments object from an activation rather than pulling - // 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) { - emitOpcode(op_create_arguments); - instructions().append(argumentsRegister->index()); - } - } - - const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack(); - const DeclarationStacks::VarStack& varStack = functionBody->varStack(); - - // Captured variables and functions go first so that activations don't have - // to step over the non-captured locals to mark them. - m_hasCreatedActivation = false; - if (functionBody->hasCapturedVariables()) { - for (size_t i = 0; i < functionStack.size(); ++i) { - FunctionBodyNode* function = functionStack[i]; - const Identifier& ident = function->ident(); - if (functionBody->captures(ident)) { - if (!m_hasCreatedActivation) { - m_hasCreatedActivation = true; - emitOpcode(op_create_activation); - instructions().append(m_activationRegister->index()); - } - m_functions.add(ident.impl()); - emitNewFunction(addVar(ident, false), function); - } - } - for (size_t i = 0; i < varStack.size(); ++i) { - const Identifier& ident = *varStack[i].first; - if (functionBody->captures(ident)) - addVar(ident, varStack[i].second & DeclarationStacks::IsConstant); - } - } - bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks; - if (!canLazilyCreateFunctions && !m_hasCreatedActivation) { - m_hasCreatedActivation = true; - emitOpcode(op_create_activation); - instructions().append(m_activationRegister->index()); - } - - codeBlock->m_numCapturedVars = codeBlock->m_numVars; - m_firstLazyFunction = codeBlock->m_numVars; - for (size_t i = 0; i < functionStack.size(); ++i) { - FunctionBodyNode* function = functionStack[i]; - const Identifier& ident = function->ident(); - if (!functionBody->captures(ident)) { - m_functions.add(ident.impl()); - 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. - if (!canLazilyCreateFunctions || ident == propertyNames().arguments) - emitNewFunction(reg.get(), function); - else { - emitInitLazyRegister(reg.get()); - m_lazyFunctions.set(reg->index(), function); - } - } - } - m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction; - for (size_t i = 0; i < varStack.size(); ++i) { - const Identifier& ident = *varStack[i].first; - if (!functionBody->captures(ident)) - addVar(ident, varStack[i].second & DeclarationStacks::IsConstant); - } - - if (m_shouldEmitDebugHooks) - codeBlock->m_numCapturedVars = codeBlock->m_numVars; - - FunctionParameters& parameters = *functionBody->parameters(); - size_t parameterCount = parameters.size(); - int nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1; - m_parameters.grow(1 + parameterCount); // reserve space for "this" - - // Add "this" as a parameter - m_thisRegister.setIndex(nextParameterIndex); - ++m_codeBlock->m_numParameters; - - for (size_t i = 0; i < parameterCount; ++i) - addParameter(parameters[i], ++nextParameterIndex); - - preserveLastVar(); - - if (isConstructor()) { - RefPtr<RegisterID> func = newTemporary(); - RefPtr<RegisterID> funcProto = newTemporary(); - - emitOpcode(op_get_callee); - instructions().append(func->index()); - // Load prototype. - emitGetById(funcProto.get(), func.get(), globalData()->propertyNames->prototype); - - emitOpcode(op_create_this); - instructions().append(m_thisRegister.index()); - instructions().append(funcProto->index()); - } else if (functionBody->usesThis() || m_shouldEmitDebugHooks) { - if (codeBlock->isStrictMode()) - emitOpcode(op_convert_this_strict); - else - emitOpcode(op_convert_this); - instructions().append(m_thisRegister.index()); - } -} - -BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock) - : m_shouldEmitDebugHooks(scopeChain.globalObject()->debugger()) - , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) - , m_shouldEmitRichSourceInfo(scopeChain.globalObject()->supportsRichSourceInfo()) - , m_scopeChain(&scopeChain) - , m_symbolTable(symbolTable) - , m_scopeNode(evalNode) - , m_codeBlock(codeBlock) - , m_thisRegister(RegisterFile::ProgramCodeThisRegister) - , m_finallyDepth(0) - , m_dynamicScopeDepth(0) - , m_baseScopeDepth(codeBlock->baseScopeDepth()) - , m_codeType(EvalCode) - , m_nextConstantOffset(0) - , m_globalConstantIndex(0) - , m_hasCreatedActivation(true) - , m_firstLazyFunction(0) - , m_lastLazyFunction(0) - , m_globalData(&scopeChain.globalObject()->globalData()) - , m_lastOpcodeID(op_end) -#ifndef NDEBUG - , m_lastOpcodePosition(0) -#endif - , m_stack(m_globalData->stack()) - , m_usesExceptions(false) - , m_regeneratingForExceptionInfo(false) - , m_codeBlockBeingRegeneratedFrom(0) -{ - if (m_shouldEmitDebugHooks || m_baseScopeDepth) - m_codeBlock->setNeedsFullScopeChain(true); - - emitOpcode(op_enter); - codeBlock->setGlobalData(m_globalData); - m_codeBlock->m_numParameters = 1; // Allocate space for "this" - - const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack(); - for (size_t i = 0; i < functionStack.size(); ++i) - m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i])); - - const DeclarationStacks::VarStack& varStack = evalNode->varStack(); - unsigned numVariables = varStack.size(); - Vector<Identifier> variables; - variables.reserveCapacity(numVariables); - for (size_t i = 0; i < numVariables; ++i) - variables.append(*varStack[i].first); - codeBlock->adoptVariables(variables); - codeBlock->m_numCapturedVars = codeBlock->m_numVars; - preserveLastVar(); -} - -RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg) -{ - emitOpcode(op_init_lazy_reg); - instructions().append(reg->index()); - return reg; -} - -void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex) -{ - // Parameters overwrite var declarations, but not function declarations. - StringImpl* rep = ident.impl(); - if (!m_functions.contains(rep)) { - symbolTable().set(rep, parameterIndex); - RegisterID& parameter = registerFor(parameterIndex); - parameter.setIndex(parameterIndex); - } - - // To maintain the calling convention, we have to allocate unique space for - // each parameter, even if the parameter doesn't make it into the symbol table. - ++m_codeBlock->m_numParameters; -} - -RegisterID* BytecodeGenerator::registerFor(const Identifier& ident) -{ - if (ident == propertyNames().thisIdentifier) - return &m_thisRegister; - - if (!shouldOptimizeLocals()) - return 0; - - SymbolTableEntry entry = symbolTable().get(ident.impl()); - if (entry.isNull()) - return 0; - - if (ident == propertyNames().arguments) - createArgumentsIfNecessary(); - - return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); -} - -bool BytecodeGenerator::willResolveToArguments(const Identifier& ident) -{ - if (ident != propertyNames().arguments) - return false; - - if (!shouldOptimizeLocals()) - return false; - - SymbolTableEntry entry = symbolTable().get(ident.impl()); - if (entry.isNull()) - return false; - - if (m_codeBlock->usesArguments() && m_codeType == FunctionCode) - return true; - - return false; -} - -RegisterID* BytecodeGenerator::uncheckedRegisterForArguments() -{ - ASSERT(willResolveToArguments(propertyNames().arguments)); - - SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.impl()); - ASSERT(!entry.isNull()); - return ®isterFor(entry.getIndex()); -} - -RegisterID* BytecodeGenerator::createLazyRegisterIfNecessary(RegisterID* reg) -{ - if (m_lastLazyFunction <= reg->index() || reg->index() < m_firstLazyFunction) - return reg; - emitLazyNewFunction(reg, m_lazyFunctions.get(reg->index())); - return reg; -} - -RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident) -{ - if (m_codeType == EvalCode) - return 0; - - SymbolTableEntry entry = symbolTable().get(ident.impl()); - if (entry.isNull()) - return 0; - - return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); -} - -bool BytecodeGenerator::isLocal(const Identifier& ident) -{ - if (ident == propertyNames().thisIdentifier) - return true; - - return shouldOptimizeLocals() && symbolTable().contains(ident.impl()); -} - -bool BytecodeGenerator::isLocalConstant(const Identifier& ident) -{ - return symbolTable().get(ident.impl()).isReadOnly(); -} - -RegisterID* BytecodeGenerator::newRegister() -{ - m_calleeRegisters.append(m_calleeRegisters.size()); - m_codeBlock->m_numCalleeRegisters = max<int>(m_codeBlock->m_numCalleeRegisters, m_calleeRegisters.size()); - return &m_calleeRegisters.last(); -} - -RegisterID* BytecodeGenerator::newTemporary() -{ - // Reclaim free register IDs. - while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount()) - m_calleeRegisters.removeLast(); - - RegisterID* result = newRegister(); - result->setTemporary(); - return result; -} - -RegisterID* BytecodeGenerator::highestUsedRegister() -{ - size_t count = m_codeBlock->m_numCalleeRegisters; - while (m_calleeRegisters.size() < count) - newRegister(); - return &m_calleeRegisters.last(); -} - -PassRefPtr<LabelScope> BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name) -{ - // Reclaim free label scopes. - while (m_labelScopes.size() && !m_labelScopes.last().refCount()) - m_labelScopes.removeLast(); - - // 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(); -} - -PassRefPtr<Label> BytecodeGenerator::newLabel() -{ - // Reclaim free label IDs. - while (m_labels.size() && !m_labels.last().refCount()) - m_labels.removeLast(); - - // Allocate new label ID. - m_labels.append(m_codeBlock); - return &m_labels.last(); -} - -PassRefPtr<Label> BytecodeGenerator::emitLabel(Label* l0) -{ - unsigned newLabelIndex = instructions().size(); - l0->setLocation(newLabelIndex); - - if (m_codeBlock->numberOfJumpTargets()) { - unsigned lastLabelIndex = m_codeBlock->lastJumpTarget(); - ASSERT(lastLabelIndex <= newLabelIndex); - if (newLabelIndex == lastLabelIndex) { - // Peephole optimizations have already been disabled by emitting the last label - return l0; - } - } - - m_codeBlock->addJumpTarget(newLabelIndex); - - // This disables peephole optimizations when an instruction is a jump target - m_lastOpcodeID = op_end; - return l0; -} - -void BytecodeGenerator::emitOpcode(OpcodeID opcodeID) -{ -#ifndef NDEBUG - size_t opcodePosition = instructions().size(); - ASSERT(opcodePosition - m_lastOpcodePosition == opcodeLength(m_lastOpcodeID) || m_lastOpcodeID == op_end); - m_lastOpcodePosition = opcodePosition; -#endif - instructions().append(globalData()->interpreter->getOpcode(opcodeID)); - m_lastOpcodeID = opcodeID; -} - -void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index) -{ - ASSERT(instructions().size() >= 4); - size_t size = instructions().size(); - dstIndex = instructions().at(size - 3).u.operand; - src1Index = instructions().at(size - 2).u.operand; - src2Index = instructions().at(size - 1).u.operand; -} - -void BytecodeGenerator::retrieveLastUnaryOp(int& dstIndex, int& srcIndex) -{ - ASSERT(instructions().size() >= 3); - size_t size = instructions().size(); - dstIndex = instructions().at(size - 2).u.operand; - srcIndex = instructions().at(size - 1).u.operand; -} - -void ALWAYS_INLINE BytecodeGenerator::rewindBinaryOp() -{ - ASSERT(instructions().size() >= 4); - instructions().shrink(instructions().size() - 4); - m_lastOpcodeID = op_end; -} - -void ALWAYS_INLINE BytecodeGenerator::rewindUnaryOp() -{ - ASSERT(instructions().size() >= 3); - instructions().shrink(instructions().size() - 3); - m_lastOpcodeID = op_end; -} - -PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target) -{ - size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jmp : op_loop); - instructions().append(target->bind(begin, instructions().size())); - return target; -} - -PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* target) -{ - if (m_lastOpcodeID == op_less) { - int dstIndex; - int src1Index; - int src2Index; - - retrieveLastBinaryOp(dstIndex, src1Index, src2Index); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindBinaryOp(); - - size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jless : op_loop_if_less); - instructions().append(src1Index); - instructions().append(src2Index); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } else if (m_lastOpcodeID == op_lesseq) { - int dstIndex; - int src1Index; - int src2Index; - - retrieveLastBinaryOp(dstIndex, src1Index, src2Index); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindBinaryOp(); - - size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jlesseq : op_loop_if_lesseq); - instructions().append(src1Index); - instructions().append(src2Index); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } else if (m_lastOpcodeID == op_eq_null && target->isForward()) { - int dstIndex; - int srcIndex; - - retrieveLastUnaryOp(dstIndex, srcIndex); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindUnaryOp(); - - size_t begin = instructions().size(); - emitOpcode(op_jeq_null); - instructions().append(srcIndex); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } else if (m_lastOpcodeID == op_neq_null && target->isForward()) { - int dstIndex; - int srcIndex; - - retrieveLastUnaryOp(dstIndex, srcIndex); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindUnaryOp(); - - size_t begin = instructions().size(); - emitOpcode(op_jneq_null); - instructions().append(srcIndex); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } - - size_t begin = instructions().size(); - - emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true); - instructions().append(cond->index()); - instructions().append(target->bind(begin, instructions().size())); - return target; -} - -PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* target) -{ - if (m_lastOpcodeID == op_less && target->isForward()) { - int dstIndex; - int src1Index; - int src2Index; - - retrieveLastBinaryOp(dstIndex, src1Index, src2Index); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindBinaryOp(); - - size_t begin = instructions().size(); - emitOpcode(op_jnless); - instructions().append(src1Index); - instructions().append(src2Index); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } else if (m_lastOpcodeID == op_lesseq && target->isForward()) { - int dstIndex; - int src1Index; - int src2Index; - - retrieveLastBinaryOp(dstIndex, src1Index, src2Index); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindBinaryOp(); - - size_t begin = instructions().size(); - emitOpcode(op_jnlesseq); - instructions().append(src1Index); - instructions().append(src2Index); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } else if (m_lastOpcodeID == op_not) { - int dstIndex; - int srcIndex; - - retrieveLastUnaryOp(dstIndex, srcIndex); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindUnaryOp(); - - size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true); - instructions().append(srcIndex); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } else if (m_lastOpcodeID == op_eq_null && target->isForward()) { - int dstIndex; - int srcIndex; - - retrieveLastUnaryOp(dstIndex, srcIndex); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindUnaryOp(); - - size_t begin = instructions().size(); - emitOpcode(op_jneq_null); - instructions().append(srcIndex); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } else if (m_lastOpcodeID == op_neq_null && target->isForward()) { - int dstIndex; - int srcIndex; - - retrieveLastUnaryOp(dstIndex, srcIndex); - - if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { - rewindUnaryOp(); - - size_t begin = instructions().size(); - emitOpcode(op_jeq_null); - instructions().append(srcIndex); - instructions().append(target->bind(begin, instructions().size())); - return target; - } - } - - size_t begin = instructions().size(); - emitOpcode(target->isForward() ? op_jfalse : op_loop_if_false); - instructions().append(cond->index()); - instructions().append(target->bind(begin, instructions().size())); - return target; -} - -PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond, Label* target) -{ - size_t begin = instructions().size(); - - emitOpcode(op_jneq_ptr); - instructions().append(cond->index()); - instructions().append(m_scopeChain->globalObject()->d()->callFunction); - instructions().append(target->bind(begin, instructions().size())); - return target; -} - -PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond, Label* target) -{ - size_t begin = instructions().size(); - - emitOpcode(op_jneq_ptr); - instructions().append(cond->index()); - instructions().append(m_scopeChain->globalObject()->d()->applyFunction); - instructions().append(target->bind(begin, instructions().size())); - return target; -} - -unsigned BytecodeGenerator::addConstant(const Identifier& ident) -{ - StringImpl* rep = ident.impl(); - pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers()); - if (result.second) // new entry - m_codeBlock->addIdentifier(Identifier(m_globalData, rep)); - - return result.first->second; -} - -RegisterID* BytecodeGenerator::addConstantValue(JSValue v) -{ - int index = m_nextConstantOffset; - - pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(JSValue::encode(v), m_nextConstantOffset); - if (result.second) { - m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); - ++m_nextConstantOffset; - m_codeBlock->addConstantRegister(JSValue(v)); - } else - index = result.first->second; - - return &m_constantPoolRegisters[index]; -} - -unsigned BytecodeGenerator::addRegExp(RegExp* r) -{ - return m_codeBlock->addRegExp(r); -} - -RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src) -{ - emitOpcode(op_mov); - instructions().append(dst->index()); - instructions().append(src->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src) -{ - emitOpcode(opcodeID); - instructions().append(dst->index()); - instructions().append(src->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitPreInc(RegisterID* srcDst) -{ - emitOpcode(op_pre_inc); - instructions().append(srcDst->index()); - return srcDst; -} - -RegisterID* BytecodeGenerator::emitPreDec(RegisterID* srcDst) -{ - emitOpcode(op_pre_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); - instructions().append(dst->index()); - instructions().append(src1->index()); - instructions().append(src2->index()); - - if (opcodeID == op_bitor || opcodeID == op_bitand || opcodeID == op_bitxor || - opcodeID == op_add || opcodeID == op_mul || opcodeID == op_sub || opcodeID == op_div) - instructions().append(types.toInt()); - - return dst; -} - -RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2) -{ - if (m_lastOpcodeID == op_typeof) { - int dstIndex; - int srcIndex; - - retrieveLastUnaryOp(dstIndex, srcIndex); - - if (src1->index() == dstIndex - && src1->isTemporary() - && m_codeBlock->isConstantRegisterIndex(src2->index()) - && m_codeBlock->constantRegister(src2->index()).jsValue().isString()) { - const UString& value = asString(m_codeBlock->constantRegister(src2->index()).jsValue())->tryGetValue(); - if (value == "undefined") { - rewindUnaryOp(); - emitOpcode(op_is_undefined); - instructions().append(dst->index()); - instructions().append(srcIndex); - return dst; - } - if (value == "boolean") { - rewindUnaryOp(); - emitOpcode(op_is_boolean); - instructions().append(dst->index()); - instructions().append(srcIndex); - return dst; - } - if (value == "number") { - rewindUnaryOp(); - emitOpcode(op_is_number); - instructions().append(dst->index()); - instructions().append(srcIndex); - return dst; - } - if (value == "string") { - rewindUnaryOp(); - emitOpcode(op_is_string); - instructions().append(dst->index()); - instructions().append(srcIndex); - return dst; - } - if (value == "object") { - rewindUnaryOp(); - emitOpcode(op_is_object); - instructions().append(dst->index()); - instructions().append(srcIndex); - return dst; - } - if (value == "function") { - rewindUnaryOp(); - emitOpcode(op_is_function); - instructions().append(dst->index()); - instructions().append(srcIndex); - return dst; - } - } - } - - emitOpcode(opcodeID); - instructions().append(dst->index()); - instructions().append(src1->index()); - instructions().append(src2->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, bool b) -{ - return emitLoad(dst, jsBoolean(b)); -} - -RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, double number) -{ - // FIXME: Our hash tables won't hold infinity, so we make a new JSNumberCell each time. - // Later we can do the extra work to handle that like the other cases. - if (number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number)) - return emitLoad(dst, jsNumber(number)); - JSValue& valueInMap = m_numberMap.add(number, JSValue()).first->second; - if (!valueInMap) - valueInMap = jsNumber(number); - return emitLoad(dst, valueInMap); -} - -RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier) -{ - JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).first->second; - if (!stringInMap) - stringInMap = jsOwnedString(globalData(), identifier.ustring()); - return emitLoad(dst, JSValue(stringInMap)); -} - -RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v) -{ - RegisterID* constantID = addConstantValue(v); - if (dst) - return emitMove(dst, constantID); - return constantID; -} - -bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, bool& requiresDynamicChecks, JSObject*& globalObject) -{ - // Cases where we cannot statically optimize the lookup. - if (property == propertyNames().arguments || !canOptimizeNonLocals()) { - stackDepth = 0; - index = missingSymbolMarker(); - - if (shouldOptimizeLocals() && m_codeType == GlobalCode) { - ScopeChainIterator iter = m_scopeChain->begin(); - globalObject = *iter; - ASSERT((++iter) == m_scopeChain->end()); - } - return false; - } - - size_t depth = 0; - requiresDynamicChecks = false; - ScopeChainIterator iter = m_scopeChain->begin(); - ScopeChainIterator end = m_scopeChain->end(); - for (; iter != end; ++iter, ++depth) { - JSObject* currentScope = *iter; - if (!currentScope->isVariableObject()) - break; - JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); - SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); - - // Found the property - if (!entry.isNull()) { - if (entry.isReadOnly() && forWriting) { - stackDepth = 0; - index = missingSymbolMarker(); - if (++iter == end) - globalObject = currentVariableObject; - return false; - } - stackDepth = depth + m_codeBlock->needsFullScopeChain(); - index = entry.getIndex(); - if (++iter == end) - globalObject = currentVariableObject; - return true; - } - bool scopeRequiresDynamicChecks = false; - if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks)) - break; - requiresDynamicChecks |= scopeRequiresDynamicChecks; - } - // Can't locate the property but we're able to avoid a few lookups. - stackDepth = depth + m_codeBlock->needsFullScopeChain(); - index = missingSymbolMarker(); - JSObject* scope = *iter; - if (++iter == end) - globalObject = scope; - return true; -} - -void BytecodeGenerator::emitCheckHasInstance(RegisterID* base) -{ - emitOpcode(op_check_has_instance); - instructions().append(base->index()); -} - -RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype) -{ - emitOpcode(op_instanceof); - instructions().append(dst->index()); - instructions().append(value->index()); - instructions().append(base->index()); - instructions().append(basePrototype->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& property) -{ - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) && !globalObject) { - // We can't optimise at all :-( - emitOpcode(op_resolve); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - return dst; - } - - if (globalObject) { - bool forceGlobalResolve = false; - if (m_regeneratingForExceptionInfo) { -#if ENABLE(JIT) - forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInfoAtBytecodeOffset(instructions().size()); -#else - forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInstructionAtBytecodeOffset(instructions().size()); -#endif - } - - if (index != missingSymbolMarker() && !forceGlobalResolve && !requiresDynamicChecks) { - // Directly index the property lookup across multiple scopes. - return emitGetScopedVar(dst, depth, index, globalObject); - } - -#if ENABLE(JIT) - m_codeBlock->addGlobalResolveInfo(instructions().size()); -#else - m_codeBlock->addGlobalResolveInstruction(instructions().size()); -#endif - emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - instructions().append(0); - instructions().append(0); - if (requiresDynamicChecks) - instructions().append(depth); - return dst; - } - - if (requiresDynamicChecks) { - // If we get here we have eval nested inside a |with| just give up - emitOpcode(op_resolve); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - return dst; - } - - if (index != missingSymbolMarker()) { - // Directly index the property lookup across multiple scopes. - return emitGetScopedVar(dst, depth, index, globalObject); - } - - // In this case we are at least able to drop a few scope chains from the - // lookup chain, although we still need to hash from then on. - emitOpcode(op_resolve_skip); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - instructions().append(depth); - return dst; -} - -RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue globalObject) -{ - if (globalObject) { - emitOpcode(op_get_global_var); - instructions().append(dst->index()); - instructions().append(index); - return dst; - } - - emitOpcode(op_get_scoped_var); - instructions().append(dst->index()); - instructions().append(index); - instructions().append(depth); - return dst; -} - -RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue globalObject) -{ - if (globalObject) { - emitOpcode(op_put_global_var); - instructions().append(index); - instructions().append(value->index()); - return value; - } - emitOpcode(op_put_scoped_var); - instructions().append(index); - instructions().append(depth); - instructions().append(value->index()); - return value; -} - -RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property) -{ - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); - if (!globalObject || requiresDynamicChecks) { - // We can't optimise at all :-( - emitOpcode(op_resolve_base); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - instructions().append(false); - return dst; - } - - // Global object is the base - return emitLoad(dst, JSValue(globalObject)); -} - -RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property) -{ - if (!m_codeBlock->isStrictMode()) - return emitResolveBase(dst, property); - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); - if (!globalObject || requiresDynamicChecks) { - // We can't optimise at all :-( - emitOpcode(op_resolve_base); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - instructions().append(true); - return dst; - } - - // Global object is the base - RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject)); - emitOpcode(op_ensure_property_exists); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - return result.get(); -} - -RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property) -{ - size_t depth = 0; - int index = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) { - // We can't optimise at all :-( - emitOpcode(op_resolve_with_base); - instructions().append(baseDst->index()); - instructions().append(propDst->index()); - instructions().append(addConstant(property)); - return baseDst; - } - - bool forceGlobalResolve = false; - if (m_regeneratingForExceptionInfo) { -#if ENABLE(JIT) - forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInfoAtBytecodeOffset(instructions().size()); -#else - forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInstructionAtBytecodeOffset(instructions().size()); -#endif - } - - // Global object is the base - emitLoad(baseDst, JSValue(globalObject)); - - if (index != missingSymbolMarker() && !forceGlobalResolve) { - // Directly index the property lookup across multiple scopes. - emitGetScopedVar(propDst, depth, index, globalObject); - return baseDst; - } - -#if ENABLE(JIT) - m_codeBlock->addGlobalResolveInfo(instructions().size()); -#else - m_codeBlock->addGlobalResolveInstruction(instructions().size()); -#endif - emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); - instructions().append(propDst->index()); - instructions().append(addConstant(property)); - instructions().append(0); - instructions().append(0); - if (requiresDynamicChecks) - instructions().append(depth); - return baseDst; -} - -void BytecodeGenerator::emitMethodCheck() -{ - emitOpcode(op_method_check); -} - -RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property) -{ -#if ENABLE(JIT) - m_codeBlock->addStructureStubInfo(StructureStubInfo(access_get_by_id)); -#else - m_codeBlock->addPropertyAccessInstruction(instructions().size()); -#endif - - emitOpcode(op_get_by_id); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(addConstant(property)); - instructions().append(0); - instructions().append(0); - instructions().append(0); - instructions().append(0); - return dst; -} - -RegisterID* BytecodeGenerator::emitGetArgumentsLength(RegisterID* dst, RegisterID* base) -{ - emitOpcode(op_get_arguments_length); - instructions().append(dst->index()); - ASSERT(base->index() == m_codeBlock->argumentsRegister()); - instructions().append(base->index()); - instructions().append(addConstant(propertyNames().length)); - return dst; -} - -RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value) -{ -#if ENABLE(JIT) - m_codeBlock->addStructureStubInfo(StructureStubInfo(access_put_by_id)); -#else - m_codeBlock->addPropertyAccessInstruction(instructions().size()); -#endif - - emitOpcode(op_put_by_id); - instructions().append(base->index()); - instructions().append(addConstant(property)); - instructions().append(value->index()); - instructions().append(0); - instructions().append(0); - instructions().append(0); - instructions().append(0); - instructions().append(0); - return value; -} - -RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value) -{ -#if ENABLE(JIT) - m_codeBlock->addStructureStubInfo(StructureStubInfo(access_put_by_id)); -#else - m_codeBlock->addPropertyAccessInstruction(instructions().size()); -#endif - - emitOpcode(op_put_by_id); - instructions().append(base->index()); - instructions().append(addConstant(property)); - instructions().append(value->index()); - instructions().append(0); - instructions().append(0); - instructions().append(0); - instructions().append(0); - instructions().append(property != m_globalData->propertyNames->underscoreProto); - return value; -} - -RegisterID* BytecodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value) -{ - emitOpcode(op_put_getter); - instructions().append(base->index()); - instructions().append(addConstant(property)); - instructions().append(value->index()); - return value; -} - -RegisterID* BytecodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value) -{ - emitOpcode(op_put_setter); - instructions().append(base->index()); - instructions().append(addConstant(property)); - instructions().append(value->index()); - return value; -} - -RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property) -{ - emitOpcode(op_del_by_id); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(addConstant(property)); - return dst; -} - -RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property) -{ - emitOpcode(op_get_argument_by_val); - instructions().append(dst->index()); - ASSERT(base->index() == m_codeBlock->argumentsRegister()); - instructions().append(base->index()); - instructions().append(property->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property) -{ - for (size_t i = m_forInContextStack.size(); i > 0; i--) { - ForInContext& context = m_forInContextStack[i - 1]; - if (context.propertyRegister == property) { - emitOpcode(op_get_by_pname); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(property->index()); - instructions().append(context.expectedSubscriptRegister->index()); - instructions().append(context.iterRegister->index()); - instructions().append(context.indexRegister->index()); - return dst; - } - } - emitOpcode(op_get_by_val); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(property->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value) -{ - emitOpcode(op_put_by_val); - instructions().append(base->index()); - instructions().append(property->index()); - instructions().append(value->index()); - return value; -} - -RegisterID* BytecodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property) -{ - emitOpcode(op_del_by_val); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(property->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value) -{ - emitOpcode(op_put_by_index); - instructions().append(base->index()); - instructions().append(index); - instructions().append(value->index()); - return value; -} - -RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst) -{ - emitOpcode(op_new_object); - instructions().append(dst->index()); - return dst; -} - -RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements) -{ - Vector<RefPtr<RegisterID>, 16> argv; - for (ElementNode* n = elements; n; n = n->next()) { - if (n->elision()) - break; - argv.append(newTemporary()); - // op_new_array requires the initial values to be a sequential range of registers - ASSERT(argv.size() == 1 || argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1); - emitNode(argv.last().get(), n->value()); - } - emitOpcode(op_new_array); - instructions().append(dst->index()); - instructions().append(argv.size() ? argv[0]->index() : 0); // argv - instructions().append(argv.size()); // argc - return dst; -} - -RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function) -{ - return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)), false); -} - -RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function) -{ - std::pair<FunctionOffsetMap::iterator, bool> ptr = m_functionOffsets.add(function, 0); - if (ptr.second) - ptr.first->second = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)); - return emitNewFunctionInternal(dst, ptr.first->second, true); -} - -RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index, bool doNullCheck) -{ - createActivationIfNecessary(); - emitOpcode(op_new_func); - instructions().append(dst->index()); - instructions().append(index); - instructions().append(doNullCheck); - return dst; -} - -RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp) -{ - emitOpcode(op_new_regexp); - instructions().append(dst->index()); - instructions().append(addRegExp(regExp)); - return dst; -} - -RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n) -{ - FunctionBodyNode* function = n->body(); - unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function)); - - createActivationIfNecessary(); - emitOpcode(op_new_func_exp); - instructions().append(r0->index()); - instructions().append(index); - return r0; -} - -RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) -{ - return emitCall(op_call, dst, func, callArguments, divot, startOffset, endOffset); -} - -void BytecodeGenerator::createArgumentsIfNecessary() -{ - if (m_codeType != FunctionCode) - return; - - if (!m_codeBlock->usesArguments()) - return; - - // If we're in strict mode we tear off the arguments on function - // entry, so there's no need to check if we need to create them - // now - if (m_codeBlock->isStrictMode()) - return; - - emitOpcode(op_create_arguments); - instructions().append(m_codeBlock->argumentsRegister()); -} - -void BytecodeGenerator::createActivationIfNecessary() -{ - if (m_hasCreatedActivation) - return; - if (!m_codeBlock->needsFullScopeChain()) - return; - emitOpcode(op_create_activation); - instructions().append(m_activationRegister->index()); -} - -RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) -{ - return emitCall(op_call_eval, dst, func, callArguments, divot, startOffset, endOffset); -} - -RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) -{ - ASSERT(opcodeID == op_call || opcodeID == op_call_eval); - ASSERT(func->refCount()); - - if (m_shouldEmitProfileHooks) - emitMove(callArguments.profileHookRegister(), func); - - // Generate code for arguments. - unsigned argumentIndex = 0; - for (ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; n; n = n->m_next) - emitNode(callArguments.argumentRegister(argumentIndex++), n); - - // Reserve space for call frame. - Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame; - for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i) - callFrame.append(newTemporary()); - - if (m_shouldEmitProfileHooks) { - emitOpcode(op_profile_will_call); - instructions().append(callArguments.profileHookRegister()->index()); - } - - emitExpressionInfo(divot, startOffset, endOffset); - -#if ENABLE(JIT) - m_codeBlock->addCallLinkInfo(); -#endif - - // Emit call. - emitOpcode(opcodeID); - instructions().append(func->index()); // func - instructions().append(callArguments.count()); // argCount - instructions().append(callArguments.callFrame()); // registerOffset - if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); - instructions().append(dst->index()); // dst - } - - if (m_shouldEmitProfileHooks) { - emitOpcode(op_profile_did_call); - instructions().append(callArguments.profileHookRegister()->index()); - } - - return dst; -} - -RegisterID* BytecodeGenerator::emitLoadVarargs(RegisterID* argCountDst, RegisterID* thisRegister, RegisterID* arguments) -{ - ASSERT(argCountDst->index() < arguments->index()); - emitOpcode(op_load_varargs); - instructions().append(argCountDst->index()); - instructions().append(arguments->index()); - instructions().append(thisRegister->index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset - return argCountDst; -} - -RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCountRegister, unsigned divot, unsigned startOffset, unsigned endOffset) -{ - ASSERT(func->refCount()); - ASSERT(thisRegister->refCount()); - ASSERT(dst != func); - if (m_shouldEmitProfileHooks) { - emitOpcode(op_profile_will_call); - instructions().append(func->index()); - } - - emitExpressionInfo(divot, startOffset, endOffset); - - // Emit call. - emitOpcode(op_call_varargs); - instructions().append(func->index()); // func - instructions().append(argCountRegister->index()); // arg count - instructions().append(thisRegister->index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset - if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); - instructions().append(dst->index()); // dst - } - if (m_shouldEmitProfileHooks) { - emitOpcode(op_profile_did_call); - instructions().append(func->index()); - } - return dst; -} - -RegisterID* BytecodeGenerator::emitReturn(RegisterID* src) -{ - if (m_codeBlock->needsFullScopeChain()) { - emitOpcode(op_tear_off_activation); - instructions().append(m_activationRegister->index()); - instructions().append(m_codeBlock->argumentsRegister()); - } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1 - && !m_codeBlock->isStrictMode()) { // If there are no named parameters, there's nothing to tear off, since extra / unnamed parameters get copied to the arguments object at construct time. - emitOpcode(op_tear_off_arguments); - instructions().append(m_codeBlock->argumentsRegister()); - } - - // Constructors use op_ret_object_or_this to check the result is an - // object, unless we can trivially determine the check is not - // necessary (currently, if the return value is 'this'). - if (isConstructor() && (src->index() != m_thisRegister.index())) { - emitOpcode(op_ret_object_or_this); - instructions().append(src->index()); - instructions().append(m_thisRegister.index()); - return src; - } - return emitUnaryNoDstOp(op_ret, src); -} - -RegisterID* BytecodeGenerator::emitUnaryNoDstOp(OpcodeID opcodeID, RegisterID* src) -{ - emitOpcode(opcodeID); - instructions().append(src->index()); - return src; -} - -RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) -{ - ASSERT(func->refCount()); - - if (m_shouldEmitProfileHooks) - emitMove(callArguments.profileHookRegister(), func); - - // Generate code for arguments. - unsigned argumentIndex = 0; - if (ArgumentsNode* argumentsNode = callArguments.argumentsNode()) { - for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) - emitNode(callArguments.argumentRegister(argumentIndex++), n); - } - - if (m_shouldEmitProfileHooks) { - emitOpcode(op_profile_will_call); - instructions().append(callArguments.profileHookRegister()->index()); - } - - // Reserve space for call frame. - Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame; - for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i) - callFrame.append(newTemporary()); - - emitExpressionInfo(divot, startOffset, endOffset); - -#if ENABLE(JIT) - m_codeBlock->addCallLinkInfo(); -#endif - - emitOpcode(op_construct); - instructions().append(func->index()); // func - instructions().append(callArguments.count()); // argCount - instructions().append(callArguments.callFrame()); // registerOffset - if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); - instructions().append(dst->index()); // dst - } - - if (m_shouldEmitProfileHooks) { - emitOpcode(op_profile_did_call); - instructions().append(callArguments.profileHookRegister()->index()); - } - - return dst; -} - -RegisterID* BytecodeGenerator::emitStrcat(RegisterID* dst, RegisterID* src, int count) -{ - emitOpcode(op_strcat); - instructions().append(dst->index()); - instructions().append(src->index()); - instructions().append(count); - - return dst; -} - -void BytecodeGenerator::emitToPrimitive(RegisterID* dst, RegisterID* src) -{ - emitOpcode(op_to_primitive); - instructions().append(dst->index()); - instructions().append(src->index()); -} - -RegisterID* BytecodeGenerator::emitPushScope(RegisterID* scope) -{ - ASSERT(scope->isTemporary()); - ControlFlowContext context; - context.isFinallyBlock = false; - m_scopeContextStack.append(context); - m_dynamicScopeDepth++; - - return emitUnaryNoDstOp(op_push_scope, scope); -} - -void BytecodeGenerator::emitPopScope() -{ - ASSERT(m_scopeContextStack.size()); - ASSERT(!m_scopeContextStack.last().isFinallyBlock); - - emitOpcode(op_pop_scope); - - m_scopeContextStack.removeLast(); - m_dynamicScopeDepth--; -} - -void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine) -{ -#if ENABLE(DEBUG_WITH_BREAKPOINT) - if (debugHookID != DidReachBreakpoint) - return; -#else - if (!m_shouldEmitDebugHooks) - return; -#endif - emitOpcode(op_debug); - instructions().append(debugHookID); - instructions().append(firstLine); - instructions().append(lastLine); -} - -void BytecodeGenerator::pushFinallyContext(Label* target, RegisterID* retAddrDst) -{ - ControlFlowContext scope; - scope.isFinallyBlock = true; - FinallyContext context = { target, retAddrDst }; - scope.finallyContext = context; - m_scopeContextStack.append(scope); - m_finallyDepth++; -} - -void BytecodeGenerator::popFinallyContext() -{ - ASSERT(m_scopeContextStack.size()); - ASSERT(m_scopeContextStack.last().isFinallyBlock); - ASSERT(m_finallyDepth > 0); - m_scopeContextStack.removeLast(); - m_finallyDepth--; -} - -LabelScope* BytecodeGenerator::breakTarget(const Identifier& name) -{ - // Reclaim free label scopes. - // - // The condition was previously coded as 'm_labelScopes.size() && !m_labelScopes.last().refCount()', - // however sometimes this appears to lead to GCC going a little haywire and entering the loop with - // size 0, leading to segfaulty badness. We are yet to identify a valid cause within our code to - // cause the GCC codegen to misbehave in this fashion, and as such the following refactoring of the - // loop condition is a workaround. - while (m_labelScopes.size()) { - if (m_labelScopes.last().refCount()) - break; - m_labelScopes.removeLast(); - } - - if (!m_labelScopes.size()) - return 0; - - // We special-case the following, which is a syntax error in Firefox: - // label: - // break; - if (name.isEmpty()) { - for (int i = m_labelScopes.size() - 1; i >= 0; --i) { - LabelScope* scope = &m_labelScopes[i]; - if (scope->type() != LabelScope::NamedLabel) { - ASSERT(scope->breakTarget()); - return scope; - } - } - return 0; - } - - for (int i = m_labelScopes.size() - 1; i >= 0; --i) { - LabelScope* scope = &m_labelScopes[i]; - if (scope->name() && *scope->name() == name) { - ASSERT(scope->breakTarget()); - return scope; - } - } - return 0; -} - -LabelScope* BytecodeGenerator::continueTarget(const Identifier& name) -{ - // Reclaim free label scopes. - while (m_labelScopes.size() && !m_labelScopes.last().refCount()) - m_labelScopes.removeLast(); - - if (!m_labelScopes.size()) - return 0; - - if (name.isEmpty()) { - for (int i = m_labelScopes.size() - 1; i >= 0; --i) { - LabelScope* scope = &m_labelScopes[i]; - if (scope->type() == LabelScope::Loop) { - ASSERT(scope->continueTarget()); - return scope; - } - } - return 0; - } - - // Continue to the loop nested nearest to the label scope that matches - // 'name'. - LabelScope* result = 0; - for (int i = m_labelScopes.size() - 1; i >= 0; --i) { - LabelScope* scope = &m_labelScopes[i]; - if (scope->type() == LabelScope::Loop) { - ASSERT(scope->continueTarget()); - result = scope; - } - if (scope->name() && *scope->name() == name) - return result; // may be 0 - } - return 0; -} - -PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope) -{ - while (topScope > bottomScope) { - // First we count the number of dynamic scopes we need to remove to get - // to a finally block. - int nNormalScopes = 0; - while (topScope > bottomScope) { - if (topScope->isFinallyBlock) - break; - ++nNormalScopes; - --topScope; - } - - 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; - } - - // 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()); - } - - while (topScope > bottomScope && topScope->isFinallyBlock) { - emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr); - --topScope; - } - } - return emitJump(target); -} - -PassRefPtr<Label> BytecodeGenerator::emitJumpScopes(Label* target, 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); - - size_t begin = instructions().size(); - - emitOpcode(op_jmp_scopes); - instructions().append(scopeDelta); - instructions().append(target->bind(begin, instructions().size())); - return target; -} - -RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget) -{ - size_t begin = instructions().size(); - - emitOpcode(op_get_pnames); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(i->index()); - instructions().append(size->index()); - instructions().append(breakTarget->bind(begin, instructions().size())); - return dst; -} - -RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target) -{ - size_t begin = instructions().size(); - - emitOpcode(op_next_pname); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(i->index()); - instructions().append(size->index()); - instructions().append(iter->index()); - instructions().append(target->bind(begin, instructions().size())); - return dst; -} - -RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end) -{ - m_usesExceptions = true; -#if ENABLE(JIT) - HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() }; -#else - HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth }; -#endif - - m_codeBlock->addExceptionHandler(info); - emitOpcode(op_catch); - instructions().append(targetRegister->index()); - return targetRegister; -} - -void BytecodeGenerator::emitThrowReferenceError(const UString& message) -{ - emitOpcode(op_throw_reference_error); - instructions().append(addConstantValue(jsString(globalData(), message))->index()); -} - -void BytecodeGenerator::emitThrowSyntaxError(const UString& message) -{ - emitOpcode(op_throw_syntax_error); - instructions().append(addConstantValue(jsString(globalData(), message))->index()); -} - -PassRefPtr<Label> BytecodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, Label* finally) -{ - size_t begin = instructions().size(); - - emitOpcode(op_jsr); - instructions().append(retAddrDst->index()); - instructions().append(finally->bind(begin, instructions().size())); - emitLabel(newLabel().get()); // Record the fact that the next instruction is implicitly labeled, because op_sret will return to it. - return finally; -} - -void BytecodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc) -{ - emitOpcode(op_sret); - instructions().append(retAddrSrc->index()); -} - -void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value) -{ - ControlFlowContext context; - context.isFinallyBlock = false; - m_scopeContextStack.append(context); - m_dynamicScopeDepth++; - - emitOpcode(op_push_new_scope); - instructions().append(dst->index()); - instructions().append(addConstant(property)); - instructions().append(value->index()); -} - -void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type) -{ - SwitchInfo info = { instructions().size(), type }; - switch (type) { - case SwitchInfo::SwitchImmediate: - emitOpcode(op_switch_imm); - break; - case SwitchInfo::SwitchCharacter: - emitOpcode(op_switch_char); - break; - case SwitchInfo::SwitchString: - emitOpcode(op_switch_string); - break; - default: - ASSERT_NOT_REACHED(); - } - - instructions().append(0); // place holder for table index - instructions().append(0); // place holder for default target - instructions().append(scrutineeRegister->index()); - m_switchContextStack.append(info); -} - -static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max) -{ - UNUSED_PARAM(max); - ASSERT(node->isNumber()); - double value = static_cast<NumberNode*>(node)->value(); - int32_t key = static_cast<int32_t>(value); - ASSERT(key == value); - ASSERT(key >= min); - ASSERT(key <= max); - return key - min; -} - -static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max) -{ - jumpTable.min = min; - jumpTable.branchOffsets.resize(max - min + 1); - jumpTable.branchOffsets.fill(0); - for (uint32_t i = 0; i < clauseCount; ++i) { - // We're emitting this after the clause labels should have been fixed, so - // the labels should not be "forward" references - ASSERT(!labels[i]->isForward()); - jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3)); - } -} - -static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max) -{ - UNUSED_PARAM(max); - ASSERT(node->isString()); - StringImpl* clause = static_cast<StringNode*>(node)->value().impl(); - ASSERT(clause->length() == 1); - - int32_t key = clause->characters()[0]; - ASSERT(key >= min); - ASSERT(key <= max); - return key - min; -} - -static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max) -{ - jumpTable.min = min; - jumpTable.branchOffsets.resize(max - min + 1); - jumpTable.branchOffsets.fill(0); - for (uint32_t i = 0; i < clauseCount; ++i) { - // We're emitting this after the clause labels should have been fixed, so - // the labels should not be "forward" references - ASSERT(!labels[i]->isForward()); - jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3)); - } -} - -static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes) -{ - for (uint32_t i = 0; i < clauseCount; ++i) { - // We're emitting this after the clause labels should have been fixed, so - // the labels should not be "forward" references - ASSERT(!labels[i]->isForward()); - - ASSERT(nodes[i]->isString()); - StringImpl* clause = static_cast<StringNode*>(nodes[i])->value().impl(); - OffsetLocation location; - location.branchOffset = labels[i]->bind(switchAddress, switchAddress + 3); - jumpTable.offsetTable.add(clause, location); - } -} - -void BytecodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, Label* defaultLabel, int32_t min, int32_t max) -{ - SwitchInfo switchInfo = m_switchContextStack.last(); - m_switchContextStack.removeLast(); - if (switchInfo.switchType == SwitchInfo::SwitchImmediate) { - instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfImmediateSwitchJumpTables(); - instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); - - SimpleJumpTable& jumpTable = m_codeBlock->addImmediateSwitchJumpTable(); - prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max); - } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) { - instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfCharacterSwitchJumpTables(); - instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); - - SimpleJumpTable& jumpTable = m_codeBlock->addCharacterSwitchJumpTable(); - prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max); - } else { - ASSERT(switchInfo.switchType == SwitchInfo::SwitchString); - instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfStringSwitchJumpTables(); - instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); - - StringJumpTable& jumpTable = m_codeBlock->addStringSwitchJumpTable(); - prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes); - } -} - -RegisterID* BytecodeGenerator::emitThrowExpressionTooDeepException() -{ - // It would be nice to do an even better job of identifying exactly where the expression is. - // And we could make the caller pass the node pointer in, if there was some way of getting - // that from an arbitrary node. However, calling emitExpressionInfo without any useful data - // is still good enough to get us an accurate line number. - emitExpressionInfo(0, 0, 0); - emitThrowSyntaxError("Expression too deep"); - return newTemporary(); -} - -void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunction) -{ - m_codeBlock->setIsNumericCompareFunction(isNumericCompareFunction); -} - -int BytecodeGenerator::argumentNumberFor(const Identifier& ident) -{ - int parameterCount = m_parameters.size(); // includes 'this' - RegisterID* registerID = registerFor(ident); - if (!registerID) - return 0; - int index = registerID->index() + RegisterFile::CallFrameHeaderSize + parameterCount; - return (index > 0 && index < parameterCount) ? index : 0; -} - -} // namespace JSC diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/JavaScriptCore/bytecompiler/BytecodeGenerator.h deleted file mode 100644 index 37756fa..0000000 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ /dev/null @@ -1,588 +0,0 @@ -/* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> - * - * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 BytecodeGenerator_h -#define BytecodeGenerator_h - -#include "CodeBlock.h" -#include "HashTraits.h" -#include "Instruction.h" -#include "Label.h" -#include "LabelScope.h" -#include "Interpreter.h" -#include "RegisterID.h" -#include "SymbolTable.h" -#include "Debugger.h" -#include "Nodes.h" -#include <wtf/FastAllocBase.h> -#include <wtf/PassRefPtr.h> -#include <wtf/SegmentedVector.h> -#include <wtf/Vector.h> - -namespace JSC { - - class Identifier; - class ScopeChain; - class ScopeNode; - - class CallArguments { - public: - CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode); - - RegisterID* thisRegister() { return m_argv[0].get(); } - RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); } - unsigned callFrame() { return thisRegister()->index() + count() + RegisterFile::CallFrameHeaderSize; } - unsigned count() { return m_argv.size(); } - RegisterID* profileHookRegister() { return m_profileHookRegister.get(); } - ArgumentsNode* argumentsNode() { return m_argumentsNode; } - - private: - RefPtr<RegisterID> m_profileHookRegister; - ArgumentsNode* m_argumentsNode; - Vector<RefPtr<RegisterID>, 16> m_argv; - }; - - struct FinallyContext { - Label* finallyAddr; - RegisterID* retAddrDst; - }; - - struct ControlFlowContext { - bool isFinallyBlock; - FinallyContext finallyContext; - }; - - struct ForInContext { - RefPtr<RegisterID> expectedSubscriptRegister; - RefPtr<RegisterID> iterRegister; - RefPtr<RegisterID> indexRegister; - RefPtr<RegisterID> propertyRegister; - }; - - class BytecodeGenerator : public FastAllocBase { - public: - typedef DeclarationStacks::VarStack VarStack; - typedef DeclarationStacks::FunctionStack FunctionStack; - - static void setDumpsGeneratedCode(bool dumpsGeneratedCode); - static bool dumpsGeneratedCode(); - - BytecodeGenerator(ProgramNode*, const ScopeChain&, SymbolTable*, ProgramCodeBlock*); - BytecodeGenerator(FunctionBodyNode*, const ScopeChain&, SymbolTable*, CodeBlock*); - BytecodeGenerator(EvalNode*, const ScopeChain&, SymbolTable*, EvalCodeBlock*); - - JSGlobalData* globalData() const { return m_globalData; } - const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; } - - bool isConstructor() { return m_codeBlock->m_isConstructor; } - - void generate(); - - // Returns the register corresponding to a local variable, or 0 if no - // such register exists. Registers returned by registerFor do not - // require explicit reference counting. - RegisterID* registerFor(const Identifier&); - - // Returns the agument number if this is an argument, or 0 if not. - int argumentNumberFor(const Identifier&); - - void setIsNumericCompareFunction(bool isNumericCompareFunction); - - bool willResolveToArguments(const Identifier&); - RegisterID* uncheckedRegisterForArguments(); - - // Behaves as registerFor does, but ignores dynamic scope as - // dynamic scope should not interfere with const initialisation - RegisterID* constRegisterFor(const Identifier&); - - // Searches the scope chain in an attempt to statically locate the requested - // property. Returns false if for any reason the property cannot be safely - // optimised at all. Otherwise it will return the index and depth of the - // VariableObject that defines the property. If the property cannot be found - // statically, depth will contain the depth of the scope chain where dynamic - // lookup must begin. - bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, bool& includesDynamicScopes, JSObject*& globalObject); - - // Returns the register storing "this" - RegisterID* thisRegister() { return &m_thisRegister; } - - bool isLocal(const Identifier&); - bool isLocalConstant(const Identifier&); - - // Returns the next available temporary register. Registers returned by - // newTemporary require a modified form of reference counting: any - // register with a refcount of 0 is considered "available", meaning that - // the next instruction may overwrite it. - RegisterID* newTemporary(); - - RegisterID* highestUsedRegister(); - - // The same as newTemporary(), but this function returns "suggestion" if - // "suggestion" is a temporary. This function is helpful in situations - // where you've put "suggestion" in a RefPtr, but you'd like to allow - // the next instruction to overwrite it anyway. - RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); } - - // Functions for handling of dst register - - RegisterID* ignoredResult() { return &m_ignoredResultRegister; } - - // Returns a place to write intermediate values of an operation - // which reuses dst if it is safe to do so. - RegisterID* tempDestination(RegisterID* dst) - { - return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); - } - - // Returns the place to write the final output of an operation. - RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) - { - if (originalDst && originalDst != ignoredResult()) - return originalDst; - ASSERT(tempDst != ignoredResult()); - if (tempDst && tempDst->isTemporary()) - return tempDst; - return newTemporary(); - } - - // Returns the place to write the final output of an operation. - RegisterID* finalDestinationOrIgnored(RegisterID* originalDst, RegisterID* tempDst = 0) - { - if (originalDst) - return originalDst; - ASSERT(tempDst != ignoredResult()); - if (tempDst && tempDst->isTemporary()) - return tempDst; - return newTemporary(); - } - - RegisterID* destinationForAssignResult(RegisterID* dst) - { - if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain()) - return dst->isTemporary() ? dst : newTemporary(); - return 0; - } - - // Moves src to dst if dst is not null and is different from src, otherwise just returns src. - RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) - { - return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; - } - - PassRefPtr<LabelScope> 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) - { - // 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.recursionCheck() - ? n->emitBytecode(*this, dst) - : emitThrowExpressionTooDeepException(); - } - - RegisterID* emitNode(Node* n) - { - return emitNode(0, n); - } - - void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) - { - addLineInfo(n->lineNo()); - if (m_stack.recursionCheck()) - n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue); - else - emitThrowExpressionTooDeepException(); - } - - void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset) - { - if (!m_shouldEmitRichSourceInfo) - return; - - divot -= m_codeBlock->sourceOffset(); - 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); - } - - ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) - { - return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; - } - - ALWAYS_INLINE PassRefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) - { - if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { - PassRefPtr<RegisterID> dst = newTemporary(); - emitNode(dst.get(), n); - return dst; - } - - return PassRefPtr<RegisterID>(emitNode(n)); - } - - RegisterID* emitLoad(RegisterID* dst, bool); - RegisterID* emitLoad(RegisterID* dst, double); - RegisterID* emitLoad(RegisterID* dst, const Identifier&); - RegisterID* emitLoad(RegisterID* dst, JSValue); - - 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* emitNewObject(RegisterID* dst); - RegisterID* emitNewArray(RegisterID* dst, ElementNode*); // stops at first elision - - RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body); - RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body); - RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index, bool shouldNullCheck); - RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); - RegisterID* emitNewRegExp(RegisterID* dst, RegExp* regExp); - - 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); - - void emitCheckHasInstance(RegisterID* base); - RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, 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* emitResolve(RegisterID* dst, const Identifier& property); - RegisterID* emitGetScopedVar(RegisterID* dst, size_t skip, int index, JSValue globalObject); - RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValue globalObject); - - RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property); - RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property); - RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property); - - void emitMethodCheck(); - - RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); - RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base); - RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); - RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value); - RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); - RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); - RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property); - RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); - RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); - RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); - RegisterID* emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value); - RegisterID* emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value); - - RegisterID* emitCall(RegisterID* dst, RegisterID* func, 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* argCount, unsigned divot, unsigned startOffset, unsigned endOffset); - 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, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); - RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count); - void emitToPrimitive(RegisterID* dst, RegisterID* src); - - PassRefPtr<Label> emitLabel(Label*); - PassRefPtr<Label> emitJump(Label* target); - PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target); - 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); - - PassRefPtr<Label> emitJumpSubroutine(RegisterID* retAddrDst, Label*); - void emitSubroutineReturn(RegisterID* retAddrSrc); - - RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget); - RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target); - - RegisterID* emitCatch(RegisterID*, Label* start, Label* end); - void emitThrow(RegisterID* exc) - { - m_usesExceptions = true; - emitUnaryNoDstOp(op_throw, exc); - } - - void emitThrowReferenceError(const UString& message); - void emitThrowSyntaxError(const UString& message); - - void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value); - - RegisterID* emitPushScope(RegisterID* scope); - void emitPopScope(); - - void emitDebugHook(DebugHookID, int firstLine, int lastLine); - - int scopeDepth() { return m_dynamicScopeDepth + m_finallyDepth; } - bool hasFinaliser() { return m_finallyDepth != 0; } - - void pushFinallyContext(Label* target, RegisterID* returnAddrDst); - void popFinallyContext(); - - void pushOptimisedForIn(RegisterID* expectedBase, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister) - { - ForInContext context = { expectedBase, iter, index, propertyRegister }; - m_forInContextStack.append(context); - } - - void popOptimisedForIn() - { - m_forInContextStack.removeLast(); - } - - LabelScope* breakTarget(const Identifier&); - LabelScope* continueTarget(const Identifier&); - - void beginSwitch(RegisterID*, SwitchInfo::SwitchType); - void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range); - - CodeType codeType() const { return m_codeType; } - - void setRegeneratingForExceptionInfo(CodeBlock* originalCodeBlock) - { - m_regeneratingForExceptionInfo = true; - m_codeBlockBeingRegeneratedFrom = originalCodeBlock; - } - - bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; } - - bool isStrictMode() const { return m_codeBlock->isStrictMode(); } - - private: - void emitOpcode(OpcodeID); - 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); - - typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap; - - struct IdentifierMapIndexHashTraits { - typedef int TraitType; - typedef IdentifierMapIndexHashTraits StorageTraits; - static int emptyValue() { return std::numeric_limits<int>::max(); } - static const bool emptyValueIsZero = false; - static const bool needsDestruction = false; - static const bool needsRef = false; - }; - - typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap; - typedef HashMap<double, JSValue> NumberMap; - typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; - - RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); - - RegisterID* newRegister(); - - // Adds a var slot and maps it to the name ident in symbolTable(). - RegisterID* addVar(const Identifier& ident, bool isConstant) - { - RegisterID* local; - addVar(ident, isConstant, local); - return local; - } - - // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. - bool addVar(const Identifier&, bool isConstant, RegisterID*&); - - // Adds an anonymous var slot. To give this slot a name, add it to symbolTable(). - RegisterID* addVar() - { - ++m_codeBlock->m_numVars; - return newRegister(); - } - - // Returns the RegisterID corresponding to ident. - RegisterID* addGlobalVar(const Identifier& ident, bool isConstant) - { - RegisterID* local; - addGlobalVar(ident, isConstant, local); - return local; - } - // Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. - bool addGlobalVar(const Identifier&, bool isConstant, RegisterID*&); - - void addParameter(const Identifier&, int parameterIndex); - - void preserveLastVar(); - - RegisterID& registerFor(int index) - { - if (index >= 0) - return m_calleeRegisters[index]; - - if (m_parameters.size()) { - ASSERT(!m_globals.size()); - return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize]; - } - - return m_globals[-index - 1]; - } - - unsigned addConstant(const Identifier&); - RegisterID* addConstantValue(JSValue); - unsigned addRegExp(RegExp*); - - PassRefPtr<FunctionExecutable> makeFunction(ExecState* exec, FunctionBodyNode* body) - { - return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); - } - - PassRefPtr<FunctionExecutable> makeFunction(JSGlobalData* globalData, FunctionBodyNode* body) - { - return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); - } - - void addLineInfo(unsigned lineNo) - { -#if !ENABLE(OPCODE_SAMPLING) - if (m_shouldEmitRichSourceInfo) -#endif - m_codeBlock->addLineInfo(instructions().size(), lineNo); - } - - RegisterID* emitInitLazyRegister(RegisterID*); - - Vector<Instruction>& instructions() { return m_codeBlock->instructions(); } - SymbolTable& symbolTable() { return *m_symbolTable; } - - bool shouldOptimizeLocals() { return (m_codeType != EvalCode) && !m_dynamicScopeDepth; } - bool canOptimizeNonLocals() { return (m_codeType == FunctionCode) && !m_dynamicScopeDepth && !m_codeBlock->usesEval(); } - - RegisterID* emitThrowExpressionTooDeepException(); - - void createArgumentsIfNecessary(); - void createActivationIfNecessary(); - RegisterID* createLazyRegisterIfNecessary(RegisterID*); - - bool m_shouldEmitDebugHooks; - bool m_shouldEmitProfileHooks; - bool m_shouldEmitRichSourceInfo; - - const ScopeChain* m_scopeChain; - SymbolTable* m_symbolTable; - - ScopeNode* m_scopeNode; - CodeBlock* m_codeBlock; - - // Some of these objects keep pointers to one another. They are arranged - // to ensure a sane destruction order that avoids references to freed memory. - HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions; - RegisterID m_ignoredResultRegister; - RegisterID m_thisRegister; - RegisterID* m_activationRegister; - SegmentedVector<RegisterID, 32> m_constantPoolRegisters; - SegmentedVector<RegisterID, 32> m_calleeRegisters; - SegmentedVector<RegisterID, 32> m_parameters; - SegmentedVector<RegisterID, 32> m_globals; - SegmentedVector<Label, 32> m_labels; - SegmentedVector<LabelScope, 8> m_labelScopes; - RefPtr<RegisterID> m_lastVar; - int m_finallyDepth; - int m_dynamicScopeDepth; - int m_baseScopeDepth; - CodeType m_codeType; - - Vector<ControlFlowContext> m_scopeContextStack; - Vector<SwitchInfo> m_switchContextStack; - Vector<ForInContext> m_forInContextStack; - - int m_nextGlobalIndex; - int m_firstConstantIndex; - int m_nextConstantOffset; - unsigned m_globalConstantIndex; - - int m_globalVarStorageOffset; - - bool m_hasCreatedActivation; - int m_firstLazyFunction; - int m_lastLazyFunction; - HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int> > m_lazyFunctions; - typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap; - FunctionOffsetMap m_functionOffsets; - - // Constant pool - IdentifierMap m_identifierMap; - JSValueMap m_jsValueMap; - NumberMap m_numberMap; - IdentifierStringMap m_stringMap; - - JSGlobalData* m_globalData; - - OpcodeID m_lastOpcodeID; -#ifndef NDEBUG - size_t m_lastOpcodePosition; -#endif - - StackBounds m_stack; - - bool m_usesExceptions; - bool m_regeneratingForExceptionInfo; - CodeBlock* m_codeBlockBeingRegeneratedFrom; - }; - -} - -#endif // BytecodeGenerator_h diff --git a/JavaScriptCore/bytecompiler/Label.h b/JavaScriptCore/bytecompiler/Label.h deleted file mode 100644 index 8cab1db..0000000 --- a/JavaScriptCore/bytecompiler/Label.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 Label_h -#define Label_h - -#include "CodeBlock.h" -#include "Instruction.h" -#include <wtf/Assertions.h> -#include <wtf/Vector.h> -#include <limits.h> - -namespace JSC { - - class Label { - public: - explicit Label(CodeBlock* codeBlock) - : m_refCount(0) - , m_location(invalidLocation) - , m_codeBlock(codeBlock) - { - } - - void setLocation(unsigned location) - { - m_location = location; - - unsigned size = m_unresolvedJumps.size(); - for (unsigned i = 0; i < size; ++i) - m_codeBlock->instructions()[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first; - } - - int bind(int opcode, int offset) const - { - if (m_location == invalidLocation) { - m_unresolvedJumps.append(std::make_pair(opcode, offset)); - return 0; - } - return m_location - opcode; - } - - void ref() { ++m_refCount; } - void deref() - { - --m_refCount; - ASSERT(m_refCount >= 0); - } - int refCount() const { return m_refCount; } - - bool isForward() const { return m_location == invalidLocation; } - - private: - typedef Vector<std::pair<int, int>, 8> JumpVector; - - static const unsigned invalidLocation = UINT_MAX; - - int m_refCount; - unsigned m_location; - CodeBlock* m_codeBlock; - mutable JumpVector m_unresolvedJumps; - }; - -} // namespace JSC - -#endif // Label_h diff --git a/JavaScriptCore/bytecompiler/LabelScope.h b/JavaScriptCore/bytecompiler/LabelScope.h deleted file mode 100644 index cc21fff..0000000 --- a/JavaScriptCore/bytecompiler/LabelScope.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2008 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 LabelScope_h -#define LabelScope_h - -#include <wtf/PassRefPtr.h> -#include "Label.h" - -namespace JSC { - - class Identifier; - - class LabelScope { - public: - enum Type { Loop, Switch, NamedLabel }; - - LabelScope(Type type, const Identifier* name, int scopeDepth, PassRefPtr<Label> breakTarget, PassRefPtr<Label> continueTarget) - : m_refCount(0) - , m_type(type) - , m_name(name) - , m_scopeDepth(scopeDepth) - , m_breakTarget(breakTarget) - , 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(); } - Label* continueTarget() const { return m_continueTarget.get(); } - - Type type() const { return m_type; } - const Identifier* name() const { return m_name; } - int scopeDepth() const { return m_scopeDepth; } - - private: - int m_refCount; - Type m_type; - const Identifier* m_name; - int m_scopeDepth; - RefPtr<Label> m_breakTarget; - RefPtr<Label> m_continueTarget; - }; - -} // namespace JSC - -#endif // LabelScope_h diff --git a/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/JavaScriptCore/bytecompiler/NodesCodegen.cpp deleted file mode 100644 index a850c96..0000000 --- a/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ /dev/null @@ -1,2076 +0,0 @@ -/* -* 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 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> -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Library General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Library General Public License for more details. -* -* You should have received a copy of the GNU Library General Public License -* along with this library; see the file COPYING.LIB. If not, write to -* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -* Boston, MA 02110-1301, USA. -* -*/ - -#include "config.h" -#include "Nodes.h" -#include "NodeConstructors.h" - -#include "BytecodeGenerator.h" -#include "CallFrame.h" -#include "Debugger.h" -#include "JIT.h" -#include "JSFunction.h" -#include "JSGlobalObject.h" -#include "JSStaticScopeObject.h" -#include "LabelScope.h" -#include "Lexer.h" -#include "Operations.h" -#include "Parser.h" -#include "PropertyNameArray.h" -#include "RegExpCache.h" -#include "RegExpObject.h" -#include "SamplingTool.h" -#include "UStringConcatenate.h" -#include <wtf/Assertions.h> -#include <wtf/RefCountedLeakCounter.h> -#include <wtf/Threading.h> - -using namespace WTF; - -namespace JSC { - -/* - Details of the emitBytecode function. - - Return value: The register holding the production's value. - dst: An optional parameter specifying the most efficient destination at - which to store the production's value. The callee must honor dst. - - The dst argument provides for a crude form of copy propagation. For example, - - x = 1 - - becomes - - load r[x], 1 - - instead of - - load r0, 1 - mov r[x], r0 - - because the assignment node, "x =", passes r[x] as dst to the number node, "1". -*/ - -// ------------------------------ ThrowableExpressionData -------------------------------- - -RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const UString& message) -{ - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitThrowReferenceError(message); - return generator.newTemporary(); -} - -RegisterID* ThrowableExpressionData::emitThrowSyntaxError(BytecodeGenerator& generator, const UString& message) -{ - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitThrowSyntaxError(message); - return generator.newTemporary(); -} - -// ------------------------------ NullNode ------------------------------------- - -RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, jsNull()); -} - -// ------------------------------ BooleanNode ---------------------------------- - -RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); -} - -// ------------------------------ NumberNode ----------------------------------- - -RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); -} - -// ------------------------------ StringNode ----------------------------------- - -RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); -} - -// ------------------------------ RegExpNode ----------------------------------- - -RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), m_flags.ustring()); - if (!regExp->isValid()) - return emitThrowSyntaxError(generator, makeUString("Invalid regular expression: ", regExp->errorMessage())); - if (dst == generator.ignoredResult()) - return 0; - return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); -} - -// ------------------------------ ThisNode ------------------------------------- - -RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); -} - -// ------------------------------ ResolveNode ---------------------------------- - -bool ResolveNode::isPure(BytecodeGenerator& generator) const -{ - return generator.isLocal(m_ident); -} - -RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (dst == generator.ignoredResult()) - return 0; - return generator.moveToDestinationIfNeeded(dst, local); - } - - generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0); - return generator.emitResolve(generator.finalDestination(dst), m_ident); -} - -// ------------------------------ ArrayNode ------------------------------------ - -RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - // FIXME: Should we put all of this code into emitNewArray? - - unsigned length = 0; - ElementNode* firstPutElement; - for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { - if (firstPutElement->elision()) - break; - ++length; - } - - if (!firstPutElement && !m_elision) - return generator.emitNewArray(generator.finalDestination(dst), m_element); - - RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element); - - for (ElementNode* n = firstPutElement; n; n = n->next()) { - RegisterID* value = generator.emitNode(n->value()); - length += n->elision(); - generator.emitPutByIndex(array.get(), length++, value); - } - - if (m_elision) { - RegisterID* value = generator.emitLoad(0, jsNumber(m_elision + length)); - generator.emitPutById(array.get(), generator.propertyNames().length, value); - } - - return generator.moveToDestinationIfNeeded(dst, array.get()); -} - -bool ArrayNode::isSimpleArray() const -{ - if (m_elision || m_optional) - return false; - for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { - if (ptr->elision()) - return false; - } - return true; -} - -ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const -{ - ASSERT(!m_elision && !m_optional); - ElementNode* ptr = m_element; - if (!ptr) - return 0; - ArgumentListNode* head = new (globalData) ArgumentListNode(globalData, ptr->value()); - ArgumentListNode* tail = head; - ptr = ptr->next(); - for (; ptr; ptr = ptr->next()) { - ASSERT(!ptr->elision()); - tail = new (globalData) ArgumentListNode(globalData, tail, ptr->value()); - } - return head; -} - -// ------------------------------ ObjectLiteralNode ---------------------------- - -RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (!m_list) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitNewObject(generator.finalDestination(dst)); - } - return generator.emitNode(dst, m_list); -} - -// ------------------------------ PropertyListNode ----------------------------- - -RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> newObj = generator.tempDestination(dst); - - generator.emitNewObject(newObj.get()); - - for (PropertyListNode* p = this; p; p = p->m_next) { - RegisterID* value = generator.emitNode(p->m_node->m_assign); - - switch (p->m_node->m_type) { - case PropertyNode::Constant: { - generator.emitDirectPutById(newObj.get(), p->m_node->name(), value); - break; - } - case PropertyNode::Getter: { - generator.emitPutGetter(newObj.get(), p->m_node->name(), value); - break; - } - case PropertyNode::Setter: { - generator.emitPutSetter(newObj.get(), p->m_node->name(), value); - break; - } - default: - ASSERT_NOT_REACHED(); - } - } - - return generator.moveToDestinationIfNeeded(dst, newObj.get()); -} - -// ------------------------------ BracketAccessorNode -------------------------------- - -RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (m_base->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())) { - RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - 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()); - return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); -} - -// ------------------------------ DotAccessorNode -------------------------------- - -RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (m_ident == generator.propertyNames().length) { - if (!m_base->isResolveNode()) - goto nonArgumentsPath; - ResolveNode* resolveNode = static_cast<ResolveNode*>(m_base); - if (!generator.willResolveToArguments(resolveNode->identifier())) - goto nonArgumentsPath; - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments()); - } - -nonArgumentsPath: - RegisterID* base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitGetById(generator.finalDestination(dst), base, m_ident); -} - -// ------------------------------ ArgumentListNode ----------------------------- - -RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - ASSERT(m_expr); - return generator.emitNode(dst, m_expr); -} - -// ------------------------------ NewExprNode ---------------------------------- - -RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> func = generator.emitNode(m_expr); - CallArguments callArguments(generator, m_args); - return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), callArguments, divot(), startOffset(), endOffset()); -} - -CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode) - : m_argumentsNode(argumentsNode) -{ - if (generator.shouldEmitProfileHooks()) - m_profileHookRegister = generator.newTemporary(); - m_argv.append(generator.newTemporary()); - if (argumentsNode) { - for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) { - m_argv.append(generator.newTemporary()); - // op_call requires the arguments to be a sequential range of registers - ASSERT(m_argv[m_argv.size() - 1]->index() == m_argv[m_argv.size() - 2]->index() + 1); - } - } -} - -// ------------------------------ EvalFunctionCallNode ---------------------------------- - -RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> func = generator.tempDestination(dst); - CallArguments callArguments(generator, m_args); - generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); - generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), generator.propertyNames().eval); - return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); -} - -// ------------------------------ FunctionCallValueNode ---------------------------------- - -RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - 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(), callArguments, divot(), startOffset(), endOffset()); -} - -// ------------------------------ FunctionCallResolveNode ---------------------------------- - -RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) { - CallArguments callArguments(generator, m_args); - generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), local.get(), callArguments, divot(), startOffset(), endOffset()); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); - CallArguments callArguments(generator, m_args); - generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); - } - - RefPtr<RegisterID> func = generator.newTemporary(); - CallArguments callArguments(generator, m_args); - int identifierStart = divot() - startOffset(); - generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0); - generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), m_ident); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); -} - -// ------------------------------ FunctionCallBracketNode ---------------------------------- - -RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - 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(), callArguments, divot(), startOffset(), endOffset()); -} - -// ------------------------------ FunctionCallDotNode ---------------------------------- - -RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - 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.emitMethodCheck(); - generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset()); -} - -RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - 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); - 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()); - { - if (m_args->m_listNode && m_args->m_listNode->m_expr) { - ArgumentListNode* oldList = m_args->m_listNode; - 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(), callArguments, divot(), startOffset(), endOffset()); - generator.emitJump(end.get()); - - 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(), callArguments, divot(), startOffset(), endOffset()); - generator.emitJump(end.get()); - } - } - generator.emitLabel(realCall.get()); - { - CallArguments callArguments(generator, m_args); - generator.emitMove(callArguments.thisRegister(), base.get()); - generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset()); - } - generator.emitLabel(end.get()); - return finalDestinationOrIgnored.get(); -} - -static bool areTrivialApplyArguments(ArgumentsNode* args) -{ - return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next - || (!args->m_listNode->m_next->m_next && args->m_listNode->m_next->m_expr->isSimpleArray()); -} - -RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - // A few simple cases can be trivially handled as ordinary function calls. - // function.apply(), function.apply(arg) -> identical to function.call - // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation - bool mayBeCall = areTrivialApplyArguments(m_args); - - 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); - 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()); - { - if (mayBeCall) { - if (m_args->m_listNode && m_args->m_listNode->m_expr) { - ArgumentListNode* oldList = m_args->m_listNode; - 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()); - 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(), callArguments, divot(), startOffset(), endOffset()); - } 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(), callArguments, divot(), startOffset(), endOffset()); - } - 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(), callArguments, divot(), startOffset(), endOffset()); - } - } else { - ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); - RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get()); - RefPtr<RegisterID> argsCountRegister = generator.newTemporary(); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - RefPtr<RegisterID> argsRegister = generator.newTemporary(); - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); - ArgumentListNode* args = m_args->m_listNode->m_next; - bool isArgumentsApply = false; - if (args->m_expr->isResolveNode()) { - ResolveNode* resolveNode = static_cast<ResolveNode*>(args->m_expr); - isArgumentsApply = generator.willResolveToArguments(resolveNode->identifier()); - if (isArgumentsApply) - generator.emitMove(argsRegister.get(), generator.uncheckedRegisterForArguments()); - } - if (!isArgumentsApply) - generator.emitNode(argsRegister.get(), args->m_expr); - while ((args = args->m_next)) - generator.emitNode(args->m_expr); - - generator.emitLoadVarargs(argsCountRegister.get(), thisRegister.get(), argsRegister.get()); - generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset()); - } - generator.emitJump(end.get()); - } - generator.emitLabel(realCall.get()); - { - CallArguments callArguments(generator, m_args); - generator.emitMove(callArguments.thisRegister(), base.get()); - generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset()); - } - generator.emitLabel(end.get()); - return finalDestinationOrIgnored.get(); -} - -// ------------------------------ PostfixResolveNode ---------------------------------- - -static RegisterID* emitPreIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) -{ - return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(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); -} - -RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitToJSNumber(generator.finalDestination(dst), local); - } - - if (dst == generator.ignoredResult()) - return emitPreIncOrDec(generator, local, m_operator); - return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); - 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); - } - generator.emitPutScopedVar(depth, index, value.get(), globalObject); - return oldValue; - } - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RefPtr<RegisterID> value = generator.newTemporary(); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); - 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); - } - generator.emitPutById(base.get(), m_ident, value.get()); - return oldValue; -} - -// ------------------------------ PostfixBracketNode ---------------------------------- - -RegisterID* PostfixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - RefPtr<RegisterID> property = generator.emitNode(m_subscript); - - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); - RegisterID* oldValue; - if (dst == generator.ignoredResult()) { - oldValue = 0; - if (m_operator == OpPlusPlus) - generator.emitPreInc(value.get()); - else - generator.emitPreDec(value.get()); - } else { - oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); - } - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutByVal(base.get(), property.get(), value.get()); - return oldValue; -} - -// ------------------------------ PostfixDotNode ---------------------------------- - -RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); - RegisterID* oldValue; - if (dst == generator.ignoredResult()) { - oldValue = 0; - if (m_operator == OpPlusPlus) - generator.emitPreInc(value.get()); - else - generator.emitPreDec(value.get()); - } else { - oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); - } - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutById(base.get(), m_ident, value.get()); - return oldValue; -} - -// ------------------------------ PostfixErrorNode ----------------------------------- - -RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - return emitThrowReferenceError(generator, m_operator == OpPlusPlus - ? "Postfix ++ operator applied to value that is not a reference." - : "Postfix -- operator applied to value that is not a reference."); -} - -// ------------------------------ DeleteResolveNode ----------------------------------- - -RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (generator.registerFor(m_ident)) - return generator.emitLoad(generator.finalDestination(dst), false); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident); - return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); -} - -// ------------------------------ DeleteBracketNode ----------------------------------- - -RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> r0 = generator.emitNode(m_base); - RegisterID* r1 = generator.emitNode(m_subscript); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); -} - -// ------------------------------ DeleteDotNode ----------------------------------- - -RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RegisterID* r0 = generator.emitNode(m_base); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); -} - -// ------------------------------ DeleteValueNode ----------------------------------- - -RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitNode(generator.ignoredResult(), m_expr); - - // delete on a non-location expression ignores the value and returns true - return generator.emitLoad(generator.finalDestination(dst), true); -} - -// ------------------------------ VoidNode ------------------------------------- - -RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) { - generator.emitNode(generator.ignoredResult(), m_expr); - return 0; - } - RefPtr<RegisterID> r0 = generator.emitNode(m_expr); - return generator.emitLoad(dst, jsUndefined()); -} - -// ------------------------------ TypeOfValueNode ----------------------------------- - -RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitTypeOf(generator.finalDestination(dst), local); - } - - RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); - generator.emitGetById(scratch.get(), scratch.get(), m_ident); - if (dst == generator.ignoredResult()) - return 0; - return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); -} - -// ------------------------------ TypeOfValueNode ----------------------------------- - -RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) { - generator.emitNode(generator.ignoredResult(), m_expr); - return 0; - } - RefPtr<RegisterID> src = generator.emitNode(m_expr); - return generator.emitTypeOf(generator.finalDestination(dst), src.get()); -} - -// ------------------------------ PrefixResolveNode ---------------------------------- - -RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - if (dst == generator.ignoredResult()) - return 0; - RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0); - return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); - } - - emitPreIncOrDec(generator, local, m_operator); - return generator.moveToDestinationIfNeeded(dst, local); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); - emitPreIncOrDec(generator, propDst.get(), m_operator); - generator.emitPutScopedVar(depth, index, propDst.get(), globalObject); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); - } - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RefPtr<RegisterID> propDst = generator.tempDestination(dst); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident); - emitPreIncOrDec(generator, propDst.get(), m_operator); - generator.emitPutById(base.get(), m_ident, propDst.get()); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); -} - -// ------------------------------ PrefixBracketNode ---------------------------------- - -RegisterID* PrefixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - RefPtr<RegisterID> property = generator.emitNode(m_subscript); - RefPtr<RegisterID> propDst = generator.tempDestination(dst); - - generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset); - RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); - if (m_operator == OpPlusPlus) - generator.emitPreInc(value); - else - generator.emitPreDec(value); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutByVal(base.get(), property.get(), value); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); -} - -// ------------------------------ PrefixDotNode ---------------------------------- - -RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - RefPtr<RegisterID> propDst = generator.tempDestination(dst); - - generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset); - RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident); - if (m_operator == OpPlusPlus) - generator.emitPreInc(value); - else - generator.emitPreDec(value); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutById(base.get(), m_ident, value); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); -} - -// ------------------------------ PrefixErrorNode ----------------------------------- - -RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - return emitThrowReferenceError(generator, m_operator == OpPlusPlus - ? "Prefix ++ operator applied to value that is not a reference." - : "Prefix -- operator applied to value that is not a reference."); -} - -// ------------------------------ Unary Operation Nodes ----------------------------------- - -RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RegisterID* src = generator.emitNode(m_expr); - return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); -} - - -// ------------------------------ LogicalNotNode ----------------------------------- - -void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) -{ - ASSERT(expr()->hasConditionContextCodegen()); - - // reverse the true and false targets - generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, !fallThroughMeansTrue); -} - - -// ------------------------------ Binary Operation Nodes ----------------------------------- - -// BinaryOpNode::emitStrcat: -// -// This node generates an op_strcat operation. This opcode can handle concatenation of three or -// more values, where we can determine a set of separate op_add operations would be operating on -// string values. -// -// This function expects to be operating on a graph of AST nodes looking something like this: -// -// (a)... (b) -// \ / -// (+) (c) -// \ / -// [d] ((+)) -// \ / -// [+=] -// -// The assignment operation is optional, if it exists the register holding the value on the -// lefthand side of the assignment should be passing as the optional 'lhs' argument. -// -// The method should be called on the node at the root of the tree of regular binary add -// operations (marked in the diagram with a double set of parentheses). This node must -// be performing a string concatenation (determined by statically detecting that at least -// one child must be a string). -// -// Since the minimum number of values being concatenated together is expected to be 3, if -// a lhs to a concatenating assignment is not provided then the root add should have at -// least one left child that is also an add that can be determined to be operating on strings. -// -RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs, ReadModifyResolveNode* emitExpressionInfoForMe) -{ - ASSERT(isAdd()); - ASSERT(resultDescriptor().definitelyIsString()); - - // Create a list of expressions for all the adds in the tree of nodes we can convert into - // a string concatenation. The rightmost node (c) is added first. The rightmost node is - // added first, and the leftmost child is never added, so the vector produced for the - // example above will be [ c, b ]. - Vector<ExpressionNode*, 16> reverseExpressionList; - reverseExpressionList.append(m_expr2); - - // Examine the left child of the add. So long as this is a string add, add its right-child - // to the list, and keep processing along the left fork. - ExpressionNode* leftMostAddChild = m_expr1; - while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { - reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2); - leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1; - } - - Vector<RefPtr<RegisterID>, 16> temporaryRegisters; - - // If there is an assignment, allocate a temporary to hold the lhs after conversion. - // We could possibly avoid this (the lhs is converted last anyway, we could let the - // op_strcat node handle its conversion if required). - if (lhs) - temporaryRegisters.append(generator.newTemporary()); - - // Emit code for the leftmost node ((a) in the example). - temporaryRegisters.append(generator.newTemporary()); - RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); - generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); - - // Note on ordering of conversions: - // - // We maintain the same ordering of conversions as we would see if the concatenations - // was performed as a sequence of adds (otherwise this optimization could change - // behaviour should an object have been provided a valueOf or toString method). - // - // Considering the above example, the sequnce of execution is: - // * evaluate operand (a) - // * evaluate operand (b) - // * convert (a) to primitive <- (this would be triggered by the first add) - // * convert (b) to primitive <- (ditto) - // * evaluate operand (c) - // * convert (c) to primitive <- (this would be triggered by the second add) - // And optionally, if there is an assignment: - // * convert (d) to primitive <- (this would be triggered by the assigning addition) - // - // As such we do not plant an op to convert the leftmost child now. Instead, use - // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion - // once the second node has been generated. However, if the leftmost child is an - // immediate we can trivially determine that no conversion will be required. - // If this is the case - if (leftMostAddChild->isString()) - leftMostAddChildTempRegister = 0; - - while (reverseExpressionList.size()) { - ExpressionNode* node = reverseExpressionList.last(); - reverseExpressionList.removeLast(); - - // Emit the code for the current node. - temporaryRegisters.append(generator.newTemporary()); - generator.emitNode(temporaryRegisters.last().get(), node); - - // On the first iteration of this loop, when we first reach this point we have just - // generated the second node, which means it is time to convert the leftmost operand. - if (leftMostAddChildTempRegister) { - generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); - leftMostAddChildTempRegister = 0; // Only do this once. - } - // Plant a conversion for this node, if necessary. - if (!node->isString()) - generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); - } - ASSERT(temporaryRegisters.size() >= 3); - - // 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()); - - // If there is an assignment convert the lhs now. This will also copy lhs to - // the temporary register we allocated for it. - if (lhs) - generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); - - return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); -} - -RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - OpcodeID opcodeID = this->opcodeID(); - - if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) - return emitStrcat(generator, dst); - - if (opcodeID == op_neq) { - if (m_expr1->isNull() || m_expr2->isNull()) { - RefPtr<RegisterID> src = generator.tempDestination(dst); - generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); - return generator.emitUnaryOp(op_neq_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); - return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); -} - -RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (m_expr1->isNull() || m_expr2->isNull()) { - RefPtr<RegisterID> src = generator.tempDestination(dst); - generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); - 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); - 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); - return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2); -} - -RegisterID* ReverseBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor())); -} - -RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); -} - -RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitCheckHasInstance(src2.get()); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype); -} - -// ------------------------------ LogicalOpNode ---------------------------- - -RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> temp = generator.tempDestination(dst); - RefPtr<Label> target = generator.newLabel(); - - generator.emitNode(temp.get(), m_expr1); - if (m_operator == OpLogicalAnd) - generator.emitJumpIfFalse(temp.get(), target.get()); - else - generator.emitJumpIfTrue(temp.get(), target.get()); - generator.emitNode(temp.get(), m_expr2); - generator.emitLabel(target.get()); - - return generator.moveToDestinationIfNeeded(dst, temp.get()); -} - -void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) -{ - 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); - } - - 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); - } -} - -// ------------------------------ ConditionalNode ------------------------------ - -RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> newDst = generator.finalDestination(dst); - 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()); - } - - generator.emitNode(newDst.get(), m_expr1); - generator.emitJump(afterElse.get()); - - generator.emitLabel(beforeElse.get()); - generator.emitNode(newDst.get(), m_expr2); - - generator.emitLabel(afterElse.get()); - - return newDst.get(); -} - -// ------------------------------ ReadModifyResolveNode ----------------------------------- - -// FIXME: should this be moved to be a method on BytecodeGenerator? -static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, ExpressionNode* m_right, Operator oper, OperandTypes types, ReadModifyResolveNode* emitExpressionInfoForMe = 0) -{ - OpcodeID opcodeID; - switch (oper) { - case OpMultEq: - opcodeID = op_mul; - break; - case OpDivEq: - opcodeID = op_div; - break; - case OpPlusEq: - if (m_right->isAdd() && m_right->resultDescriptor().definitelyIsString()) - return static_cast<AddNode*>(m_right)->emitStrcat(generator, dst, src1, emitExpressionInfoForMe); - opcodeID = op_add; - break; - case OpMinusEq: - opcodeID = op_sub; - break; - case OpLShift: - opcodeID = op_lshift; - break; - case OpRShift: - opcodeID = op_rshift; - break; - case OpURShift: - opcodeID = op_urshift; - break; - case OpAndEq: - opcodeID = op_bitand; - break; - case OpXOrEq: - opcodeID = op_bitxor; - break; - case OpOrEq: - opcodeID = op_bitor; - break; - case OpModEq: - opcodeID = op_mod; - break; - default: - ASSERT_NOT_REACHED(); - return dst; - } - - RegisterID* src2 = generator.emitNode(m_right); - - // 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()); - - return generator.emitBinaryOp(opcodeID, dst, src1, src2, types); -} - -RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - } - - if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { - RefPtr<RegisterID> result = generator.newTemporary(); - generator.emitMove(result.get(), local); - emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitMove(local, result.get()); - return generator.moveToDestinationIfNeeded(dst, result.get()); - } - - RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - return generator.moveToDestinationIfNeeded(dst, result); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); - RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitPutScopedVar(depth, index, result, globalObject); - return result; - } - - RefPtr<RegisterID> src1 = generator.tempDestination(dst); - generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident); - RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); - return generator.emitPutById(base.get(), m_ident, result); -} - -// ------------------------------ AssignResolveNode ----------------------------------- - -RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) - return generator.emitNode(dst, m_right); - - RegisterID* result = generator.emitNode(local, m_right); - return generator.moveToDestinationIfNeeded(dst, result); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { - if (dst == generator.ignoredResult()) - dst = 0; - RegisterID* value = generator.emitNode(dst, m_right); - generator.emitPutScopedVar(depth, index, value, globalObject); - return value; - } - - RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident); - if (dst == generator.ignoredResult()) - dst = 0; - RegisterID* value = generator.emitNode(dst, m_right); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitPutById(base.get(), m_ident, value); -} - -// ------------------------------ AssignDotNode ----------------------------------- - -RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - 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.emitPutById(base.get(), m_ident, result); - return generator.moveToDestinationIfNeeded(dst, result); -} - -// ------------------------------ ReadModifyDotNode ----------------------------------- - -RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); - - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - 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()); - return generator.emitPutById(base.get(), m_ident, updatedValue); -} - -// ------------------------------ AssignErrorNode ----------------------------------- - -RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - return emitThrowReferenceError(generator, "Left side of assignment is not a reference."); -} - -// ------------------------------ AssignBracketNode ----------------------------------- - -RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - 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)); - RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); - RegisterID* result = generator.emitNode(value.get(), m_right); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutByVal(base.get(), property.get(), result); - return generator.moveToDestinationIfNeeded(dst, result); -} - -// ------------------------------ ReadModifyBracketNode ----------------------------------- - -RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - 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); - 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.emitPutByVal(base.get(), property.get(), updatedValue); - - return updatedValue; -} - -// ------------------------------ CommaNode ------------------------------------ - -RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - ASSERT(m_expressions.size() > 1); - for (size_t i = 0; i < m_expressions.size() - 1; i++) - generator.emitNode(generator.ignoredResult(), m_expressions[i]); - return generator.emitNode(dst, m_expressions.last()); -} - -// ------------------------------ ConstDeclNode ------------------------------------ - -RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) -{ - if (RegisterID* local = generator.constRegisterFor(m_ident)) { - if (!m_init) - return local; - - return generator.emitNode(local, m_init); - } - - if (generator.codeType() != EvalCode) { - if (m_init) - return generator.emitNode(m_init); - else - return generator.emitResolve(generator.newTemporary(), m_ident); - } - // FIXME: While this code should only be hit in eval code, it will potentially - // assign to the wrong base if m_ident exists in an intervening dynamic scope. - RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); - RegisterID* value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); - return generator.emitPutById(base.get(), m_ident, value); -} - -RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - RegisterID* result = 0; - for (ConstDeclNode* n = this; n; n = n->m_next) - result = n->emitCodeSingle(generator); - - return result; -} - -// ------------------------------ ConstStatementNode ----------------------------- - -RegisterID* ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - return generator.emitNode(m_next); -} - -// ------------------------------ SourceElements ------------------------------- - - -inline StatementNode* SourceElements::lastStatement() const -{ - size_t size = m_statements.size(); - return size ? m_statements[size - 1] : 0; -} - -inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - size_t size = m_statements.size(); - for (size_t i = 0; i < size; ++i) - generator.emitNode(dst, m_statements[i]); -} - -// ------------------------------ BlockNode ------------------------------------ - -inline StatementNode* BlockNode::lastStatement() const -{ - return m_statements ? m_statements->lastStatement() : 0; -} - -inline StatementNode* BlockNode::singleStatement() const -{ - return m_statements ? m_statements->singleStatement() : 0; -} - -RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (m_statements) - m_statements->emitBytecode(generator, dst); - return 0; -} - -// ------------------------------ EmptyStatementNode --------------------------- - -RegisterID* EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - return dst; -} - -// ------------------------------ DebuggerStatementNode --------------------------- - -RegisterID* DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine()); - return dst; -} - -// ------------------------------ ExprStatementNode ---------------------------- - -RegisterID* ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - ASSERT(m_expr); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - return generator.emitNode(dst, m_expr); -} - -// ------------------------------ VarStatementNode ---------------------------- - -RegisterID* VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - ASSERT(m_expr); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - return generator.emitNode(m_expr); -} - -// ------------------------------ IfNode --------------------------------------- - -RegisterID* IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<Label> afterThen = generator.newLabel(); - - 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()); - } - - generator.emitNode(dst, m_ifBlock); - generator.emitLabel(afterThen.get()); - - // FIXME: This should return the last statement executed so that it can be returned as a Completion. - return 0; -} - -// ------------------------------ IfElseNode --------------------------------------- - -RegisterID* IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - 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()); - } - - generator.emitNode(dst, m_ifBlock); - generator.emitJump(afterElse.get()); - - generator.emitLabel(beforeElse.get()); - - 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) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - RefPtr<Label> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); - 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.emitLabel(scope->breakTarget()); - return result.get(); -} - -// ------------------------------ WhileNode ------------------------------------ - -RegisterID* WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - generator.emitJump(scope->continueTarget()); - - RefPtr<Label> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); - - 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.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) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (m_expr1) - generator.emitNode(generator.ignoredResult(), m_expr1); - - RefPtr<Label> condition = generator.newLabel(); - generator.emitJump(condition.get()); - - RefPtr<Label> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - if (m_expr3) - generator.emitNode(generator.ignoredResult(), m_expr3); - - generator.emitLabel(condition.get()); - 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 - generator.emitJump(topOfLoop.get()); - - generator.emitLabel(scope->breakTarget()); - return result.get(); -} - -// ------------------------------ ForInNode ------------------------------------ - -RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - if (!m_lexpr->isLocation()) - return emitThrowReferenceError(generator, "Left side of for-in statement is not a reference."); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (m_init) - generator.emitNode(generator.ignoredResult(), m_init); - - RefPtr<RegisterID> base = generator.newTemporary(); - generator.emitNode(base.get(), m_expr); - RefPtr<RegisterID> i = generator.newTemporary(); - RefPtr<RegisterID> size = generator.newTemporary(); - RefPtr<RegisterID> expectedSubscript; - RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget()); - generator.emitJump(scope->continueTarget()); - - RefPtr<Label> loopStart = generator.newLabel(); - generator.emitLabel(loopStart.get()); - - RegisterID* propertyName; - bool optimizedForinAccess = false; - if (m_lexpr->isResolveNode()) { - const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); - propertyName = generator.registerFor(ident); - if (!propertyName) { - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; - RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), ident); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutById(base, ident, propertyName); - } else { - expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName); - generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName); - optimizedForinAccess = true; - } - } else if (m_lexpr->isDotAccessorNode()) { - DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); - const Identifier& ident = assignNode->identifier(); - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; - RegisterID* base = generator.emitNode(assignNode->base()); - - generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); - generator.emitPutById(base, ident, propertyName); - } else { - ASSERT(m_lexpr->isBracketAccessorNode()); - BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; - RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); - RegisterID* subscript = generator.emitNode(assignNode->subscript()); - - generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); - generator.emitPutByVal(base.get(), subscript, propertyName); - } - - generator.emitNode(dst, m_statement); - - if (optimizedForinAccess) - generator.popOptimisedForIn(); - - generator.emitLabel(scope->continueTarget()); - generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get()); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - generator.emitLabel(scope->breakTarget()); - return dst; -} - -// ------------------------------ ContinueNode --------------------------------- - -// ECMA 12.7 -RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - LabelScope* scope = generator.continueTarget(m_ident); - - if (!scope) { - if (m_ident.isEmpty()) - return emitThrowSyntaxError(generator, "Invalid continue statement."); - return emitThrowSyntaxError(generator, makeUString("Undefined label: '", m_ident.ustring(), "'.")); - } - - generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth()); - return dst; -} - -// ------------------------------ BreakNode ------------------------------------ - -// ECMA 12.8 -RegisterID* BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - LabelScope* scope = generator.breakTarget(m_ident); - - if (!scope) { - if (m_ident.isEmpty()) - return emitThrowSyntaxError(generator, "Invalid break statement."); - return emitThrowSyntaxError(generator, makeUString("Undefined label: '", m_ident.ustring(), "'.")); - } - - generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth()); - return dst; -} - -// ------------------------------ ReturnNode ----------------------------------- - -RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - if (generator.codeType() != FunctionCode) - return emitThrowSyntaxError(generator, "Invalid return statement."); - - if (dst == generator.ignoredResult()) - dst = 0; - RegisterID* r0 = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); - RefPtr<RegisterID> returnRegister; - if (generator.scopeDepth()) { - RefPtr<Label> l0 = generator.newLabel(); - if (generator.hasFinaliser() && !r0->isTemporary()) { - returnRegister = generator.emitMove(generator.newTemporary(), r0); - r0 = returnRegister.get(); - } - generator.emitJumpScopes(l0.get(), 0); - generator.emitLabel(l0.get()); - } - generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); - return generator.emitReturn(r0); -} - -// ------------------------------ WithNode ------------------------------------- - -RegisterID* WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<RegisterID> scope = generator.newTemporary(); - generator.emitNode(scope.get(), m_expr); // scope must be protected until popped - generator.emitExpressionInfo(m_divot, m_expressionLength, 0); - generator.emitPushScope(scope.get()); - RegisterID* result = 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); -} - -// ------------------------------ CaseBlockNode -------------------------------- - -enum SwitchKind { - SwitchUnset = 0, - SwitchNumber = 1, - SwitchString = 2, - SwitchNeither = 3 -}; - -static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) -{ - for (; list; list = list->getNext()) { - ExpressionNode* clauseExpression = list->getClause()->expr(); - literalVector.append(clauseExpression); - if (clauseExpression->isNumber()) { - double value = static_cast<NumberNode*>(clauseExpression)->value(); - int32_t intVal = static_cast<int32_t>(value); - if ((typeForTable & ~SwitchNumber) || (intVal != value)) { - typeForTable = SwitchNeither; - break; - } - if (intVal < min_num) - min_num = intVal; - if (intVal > max_num) - max_num = intVal; - typeForTable = SwitchNumber; - continue; - } - if (clauseExpression->isString()) { - if (typeForTable & ~SwitchString) { - typeForTable = SwitchNeither; - break; - } - const UString& value = static_cast<StringNode*>(clauseExpression)->value().ustring(); - if (singleCharacterSwitch &= value.length() == 1) { - int32_t intVal = value.impl()->characters()[0]; - if (intVal < min_num) - min_num = intVal; - if (intVal > max_num) - max_num = intVal; - } - typeForTable = SwitchString; - continue; - } - typeForTable = SwitchNeither; - break; - } -} - -SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) -{ - SwitchKind typeForTable = SwitchUnset; - bool singleCharacterSwitch = true; - - processClauseList(m_list1, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); - processClauseList(m_list2, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); - - if (typeForTable == SwitchUnset || typeForTable == SwitchNeither) - return SwitchInfo::SwitchNone; - - if (typeForTable == SwitchNumber) { - int32_t range = max_num - min_num; - if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) - return SwitchInfo::SwitchImmediate; - return SwitchInfo::SwitchNone; - } - - ASSERT(typeForTable == SwitchString); - - if (singleCharacterSwitch) { - int32_t range = max_num - min_num; - if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) - return SwitchInfo::SwitchCharacter; - } - - return SwitchInfo::SwitchString; -} - -RegisterID* 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); - - if (switchType != SwitchInfo::SwitchNone) { - // Prepare the various labels - for (uint32_t i = 0; i < literalVector.size(); i++) - labelVector.append(generator.newLabel()); - defaultLabel = generator.newLabel(); - generator.beginSwitch(switchExpression, switchType); - } else { - // Setup jumps - for (ClauseListNode* list = m_list1; list; list = list->getNext()) { - RefPtr<RegisterID> clauseVal = generator.newTemporary(); - generator.emitNode(clauseVal.get(), list->getClause()->expr()); - generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); - labelVector.append(generator.newLabel()); - generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); - } - - for (ClauseListNode* list = m_list2; list; list = list->getNext()) { - RefPtr<RegisterID> clauseVal = generator.newTemporary(); - generator.emitNode(clauseVal.get(), list->getClause()->expr()); - generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); - labelVector.append(generator.newLabel()); - generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); - } - defaultLabel = generator.newLabel(); - 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()); - list->getClause()->emitBytecode(generator, dst); - } - - if (m_defaultClause) { - generator.emitLabel(defaultLabel.get()); - m_defaultClause->emitBytecode(generator, dst); - } - - for (ClauseListNode* list = m_list2; list; list = list->getNext()) { - generator.emitLabel(labelVector[i++].get()); - list->getClause()->emitBytecode(generator, dst); - } - if (!m_defaultClause) - generator.emitLabel(defaultLabel.get()); - - ASSERT(i == labelVector.size()); - if (switchType != SwitchInfo::SwitchNone) { - 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) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); - - RefPtr<RegisterID> r0 = generator.emitNode(m_expr); - RegisterID* r1 = m_block->emitBytecodeForBlock(generator, r0.get(), dst); - - generator.emitLabel(scope->breakTarget()); - return r1; -} - -// ------------------------------ LabelNode ------------------------------------ - -RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (generator.breakTarget(m_name)) - return emitThrowSyntaxError(generator, makeUString("Duplicate label: ", m_name.ustring(), ".")); - - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); - RegisterID* r0 = generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->breakTarget()); - return r0; -} - -// ------------------------------ ThrowNode ------------------------------------ - -RegisterID* ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (dst == generator.ignoredResult()) - dst = 0; - RefPtr<RegisterID> expr = generator.emitNode(m_expr); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitThrow(expr.get()); - return 0; -} - -// ------------------------------ TryNode -------------------------------------- - -RegisterID* 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()); - - RefPtr<Label> tryStartLabel = generator.newLabel(); - RefPtr<Label> finallyStart; - RefPtr<RegisterID> finallyReturnAddr; - if (m_finallyBlock) { - finallyStart = generator.newLabel(); - finallyReturnAddr = generator.newTemporary(); - generator.pushFinallyContext(finallyStart.get(), finallyReturnAddr.get()); - } - - generator.emitLabel(tryStartLabel.get()); - generator.emitNode(dst, m_tryBlock); - - if (m_catchBlock) { - RefPtr<Label> catchEndLabel = generator.newLabel(); - - // Normal path: jump over the catch block. - generator.emitJump(catchEndLabel.get()); - - // Uncaught exception path: the catch block. - RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); - RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); - if (m_catchHasEval) { - RefPtr<RegisterID> dynamicScopeObject = generator.emitNewObject(generator.newTemporary()); - generator.emitPutById(dynamicScopeObject.get(), m_exceptionIdent, exceptionRegister.get()); - generator.emitMove(exceptionRegister.get(), dynamicScopeObject.get()); - generator.emitPushScope(exceptionRegister.get()); - } else - generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get()); - generator.emitNode(dst, m_catchBlock); - generator.emitPopScope(); - generator.emitLabel(catchEndLabel.get()); - } - - if (m_finallyBlock) { - generator.popFinallyContext(); - // there may be important registers live at the time we jump - // to a finally block (such as for a return or throw) so we - // ref the highest register ever used as a conservative - // approach to not clobbering anything important - RefPtr<RegisterID> highestUsedRegister = generator.highestUsedRegister(); - RefPtr<Label> finallyEndLabel = generator.newLabel(); - - // Normal path: invoke the finally block, then jump over it. - generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); - generator.emitJump(finallyEndLabel.get()); - - // Uncaught exception path: invoke the finally block, then re-throw the exception. - RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); - RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); - generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); - generator.emitThrow(tempExceptionRegister.get()); - - // The finally block. - generator.emitLabel(finallyStart.get()); - generator.emitNode(dst, m_finallyBlock); - generator.emitSubroutineReturn(finallyReturnAddr.get()); - - generator.emitLabel(finallyEndLabel.get()); - } - - return dst; -} - -// ------------------------------ ScopeNode ----------------------------- - -inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (m_data->m_statements) - m_data->m_statements->emitBytecode(generator, dst); -} - -// ------------------------------ ProgramNode ----------------------------- - -RegisterID* ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); - - RefPtr<RegisterID> dstRegister = generator.newTemporary(); - generator.emitLoad(dstRegister.get(), jsUndefined()); - emitStatementsBytecode(generator, dstRegister.get()); - - generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); - generator.emitEnd(dstRegister.get()); - return 0; -} - -// ------------------------------ EvalNode ----------------------------- - -RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); - - RefPtr<RegisterID> dstRegister = generator.newTemporary(); - generator.emitLoad(dstRegister.get(), jsUndefined()); - emitStatementsBytecode(generator, dstRegister.get()); - - generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); - generator.emitEnd(dstRegister.get()); - return 0; -} - -// ------------------------------ FunctionBodyNode ----------------------------- - -RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine()); - emitStatementsBytecode(generator, generator.ignoredResult()); - - StatementNode* singleStatement = this->singleStatement(); - ReturnNode* returnNode = 0; - - // Check for a return statement at the end of a function composed of a single block. - if (singleStatement && singleStatement->isBlock()) { - StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement(); - if (lastStatementInBlock && lastStatementInBlock->isReturnNode()) - returnNode = static_cast<ReturnNode*>(lastStatementInBlock); - } - - // 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()); - generator.emitReturn(r0); - return 0; - } - - // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare. - if (static_cast<BlockNode*>(singleStatement)->singleStatement()) { - ExpressionNode* returnValueExpression = returnNode->value(); - if (returnValueExpression && returnValueExpression->isSubtract()) { - ExpressionNode* lhsExpression = static_cast<SubNode*>(returnValueExpression)->lhs(); - ExpressionNode* rhsExpression = static_cast<SubNode*>(returnValueExpression)->rhs(); - if (lhsExpression->isResolveNode() && rhsExpression->isResolveNode()) { - generator.setIsNumericCompareFunction(generator.argumentNumberFor(static_cast<ResolveNode*>(lhsExpression)->identifier()) == 1 - && generator.argumentNumberFor(static_cast<ResolveNode*>(rhsExpression)->identifier()) == 2); - } - } - } - - return 0; -} - -// ------------------------------ FuncDeclNode --------------------------------- - -RegisterID* FuncDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - dst = 0; - return dst; -} - -// ------------------------------ FuncExprNode --------------------------------- - -RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); -} - -} // namespace JSC diff --git a/JavaScriptCore/bytecompiler/RegisterID.h b/JavaScriptCore/bytecompiler/RegisterID.h deleted file mode 100644 index 3532ad8..0000000 --- a/JavaScriptCore/bytecompiler/RegisterID.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2008 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 RegisterID_h -#define RegisterID_h - -#include <wtf/Assertions.h> -#include <wtf/Noncopyable.h> -#include <wtf/VectorTraits.h> - -namespace JSC { - - class RegisterID : public Noncopyable { - public: - RegisterID() - : m_refCount(0) - , m_isTemporary(false) -#ifndef NDEBUG - , m_didSetIndex(false) -#endif - { - } - - explicit RegisterID(int index) - : m_refCount(0) - , m_index(index) - , m_isTemporary(false) -#ifndef NDEBUG - , m_didSetIndex(true) -#endif - { - } - - void setIndex(int index) - { - ASSERT(!m_refCount); -#ifndef NDEBUG - m_didSetIndex = true; -#endif - m_index = index; - } - - void setTemporary() - { - m_isTemporary = true; - } - - int index() const - { - ASSERT(m_didSetIndex); - return m_index; - } - - bool isTemporary() - { - return m_isTemporary; - } - - void ref() - { - ++m_refCount; - } - - void deref() - { - --m_refCount; - ASSERT(m_refCount >= 0); - } - - int refCount() const - { - return m_refCount; - } - - private: - - int m_refCount; - int m_index; - bool m_isTemporary; -#ifndef NDEBUG - bool m_didSetIndex; -#endif - }; - -} // namespace JSC - -namespace WTF { - - template<> struct VectorTraits<JSC::RegisterID> : VectorTraitsBase<true, JSC::RegisterID> { - static const bool needsInitialization = true; - static const bool canInitializeWithMemset = true; // Default initialization just sets everything to 0 or false, so this is safe. - }; - -} // namespace WTF - -#endif // RegisterID_h |
