X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..a253471d7f8e4d91bf6ebabab00155c3b387d3d0:/bytecompiler/BytecodeGenerator.cpp diff --git a/bytecompiler/BytecodeGenerator.cpp b/bytecompiler/BytecodeGenerator.cpp index 683372e..f43b4e6 100644 --- a/bytecompiler/BytecodeGenerator.cpp +++ b/bytecompiler/BytecodeGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich * * Redistribution and use in source and binary forms, with or without @@ -31,9 +31,11 @@ #include "BytecodeGenerator.h" #include "BatchedTransitionOptimizer.h" -#include "PrototypeFunction.h" #include "JSFunction.h" #include "Interpreter.h" +#include "LowLevelInterpreter.h" +#include "ScopeChain.h" +#include "StrongInlines.h" #include "UString.h" using namespace std; @@ -115,85 +117,73 @@ namespace JSC { expected by the callee. */ -#ifndef NDEBUG static bool s_dumpsGeneratedCode = false; -#endif + +void Label::setLocation(unsigned location) +{ + m_location = location; + + unsigned size = m_unresolvedJumps.size(); + for (unsigned i = 0; i < size; ++i) + m_generator->m_instructions[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first; +} 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() +JSObject* BytecodeGenerator::generate() { + SamplingRegion samplingRegion("Bytecode Generation"); + m_codeBlock->setThisRegister(m_thisRegister.index()); m_scopeNode->emitBytecode(*this); - -#ifndef NDEBUG - m_codeBlock->setInstructionCount(m_codeBlock->instructions().size()); + + m_codeBlock->instructions() = RefCountedArray(m_instructions); if (s_dumpsGeneratedCode) - m_codeBlock->dump(m_scopeChain->globalObject()->globalExec()); -#endif + m_codeBlock->dump(m_scopeChain->globalObject->globalExec()); if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode) symbolTable().clear(); - - m_codeBlock->setIsNumericCompareFunction(instructions() == m_globalData->numericCompareFunction(m_scopeChain->globalObject()->globalExec())); - -#if !ENABLE(OPCODE_SAMPLING) - if (!m_regeneratingForExceptionInfo && (m_codeType == FunctionCode || m_codeType == EvalCode)) - m_codeBlock->clearExceptionInfo(); -#endif m_codeBlock->shrinkToFit(); + + if (m_expressionTooDeep) + return createOutOfMemoryError(m_scopeChain->globalObject.get()); + return 0; } bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0) { int index = m_calleeRegisters.size(); SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); - pair result = symbolTable().add(ident.ustring().rep(), newEntry); + SymbolTable::AddResult result = symbolTable().add(ident.impl(), newEntry); - if (!result.second) { - r0 = ®isterFor(result.first->second.getIndex()); + if (!result.isNewEntry) { + r0 = ®isterFor(result.iterator->second.getIndex()); return false; } - ++m_codeBlock->m_numVars; - r0 = newRegister(); + r0 = addVar(); return true; } -bool BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0) +int BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant) { - int index = m_nextGlobalIndex; + int index = symbolTable().size(); SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); - pair result = symbolTable().add(ident.ustring().rep(), newEntry); - - if (!result.second) - index = result.first->second.getIndex(); - else { - --m_nextGlobalIndex; - m_globals.append(index + m_globalVarStorageOffset); - } - - r0 = ®isterFor(index); - return result.second; + SymbolTable::AddResult result = symbolTable().add(ident.impl(), newEntry); + if (!result.isNewEntry) + index = result.iterator->second.getIndex(); + return index; } void BytecodeGenerator::preserveLastVar() @@ -202,27 +192,34 @@ void BytecodeGenerator::preserveLastVar() m_lastVar = &m_calleeRegisters.last(); } -BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock) - : m_shouldEmitDebugHooks(!!debugger) - , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) - , m_scopeChain(&scopeChain) +BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock, CompilationKind compilationKind) + : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger()) + , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get())) + , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get())) + , m_scopeChain(*scopeChain->globalData, scopeChain) , m_symbolTable(symbolTable) , m_scopeNode(programNode) , m_codeBlock(codeBlock) - , m_thisRegister(RegisterFile::ProgramCodeThisRegister) + , m_thisRegister(CallFrame::thisArgumentOffset()) , m_finallyDepth(0) , m_dynamicScopeDepth(0) , m_baseScopeDepth(0) , m_codeType(GlobalCode) - , m_nextGlobalIndex(-1) , m_nextConstantOffset(0) , m_globalConstantIndex(0) - , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) + , m_hasCreatedActivation(true) + , m_firstLazyFunction(0) + , m_lastLazyFunction(0) + , m_globalData(scopeChain->globalData) , m_lastOpcodeID(op_end) - , m_emitNodeDepth(0) - , m_regeneratingForExceptionInfo(false) - , m_codeBlockBeingRegeneratedFrom(0) +#ifndef NDEBUG + , m_lastOpcodePosition(0) +#endif + , m_stack(wtfThreadData().stack()) + , m_usesExceptions(false) + , m_expressionTooDeep(false) { + m_globalData->startedCompiling(m_codeBlock); if (m_shouldEmitDebugHooks) m_codeBlock->setNeedsFullScopeChain(true); @@ -231,210 +228,313 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d // FIXME: Move code that modifies the global object to Interpreter::execute. - m_codeBlock->m_numParameters = 1; // Allocate space for "this" + m_codeBlock->setNumParameters(1); // Allocate space for "this" + codeBlock->m_numCapturedVars = codeBlock->m_numVars; + + if (compilationKind == OptimizingCompilation) + return; - JSGlobalObject* globalObject = scopeChain.globalObject(); + JSGlobalObject* globalObject = scopeChain->globalObject.get(); 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); + BatchedTransitionOptimizer optimizer(*m_globalData, 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) { - FuncDeclNode* funcDecl = functionStack[i]; - globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property. - emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl); - } - Vector 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)); + size_t newGlobals = varStack.size() + functionStack.size(); + if (!newGlobals) + return; + globalObject->resizeRegisters(symbolTable->size() + newGlobals); - preserveLastVar(); + for (size_t i = 0; i < functionStack.size(); ++i) { + FunctionBodyNode* function = functionStack[i]; + globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties. - for (size_t i = 0; i < newVars.size(); ++i) - emitLoad(newVars[i], jsUndefined()); - } else { - for (size_t i = 0; i < functionStack.size(); ++i) { - FuncDeclNode* funcDecl = functionStack[i]; - globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, 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); - } + JSValue value = JSFunction::create(exec, makeFunction(exec, function), scopeChain); + int index = addGlobalVar(function->ident(), false); + globalObject->registerAt(index).set(*m_globalData, globalObject, value); + } - preserveLastVar(); + for (size_t i = 0; i < varStack.size(); ++i) { + if (globalObject->hasProperty(exec, *varStack[i].first)) + continue; + addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); } } -BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock) - : m_shouldEmitDebugHooks(!!debugger) - , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) - , m_scopeChain(&scopeChain) +BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainNode* scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, CompilationKind) + : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger()) + , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get())) + , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get())) + , m_scopeChain(*scopeChain->globalData, scopeChain) , 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_globalData(&scopeChain.globalObject()->globalExec()->globalData()) + , m_hasCreatedActivation(false) + , m_firstLazyFunction(0) + , m_lastLazyFunction(0) + , m_globalData(scopeChain->globalData) , m_lastOpcodeID(op_end) - , m_emitNodeDepth(0) - , m_regeneratingForExceptionInfo(false) - , m_codeBlockBeingRegeneratedFrom(0) +#ifndef NDEBUG + , m_lastOpcodePosition(0) +#endif + , m_stack(wtfThreadData().stack()) + , m_usesExceptions(false) + , m_expressionTooDeep(false) { + m_globalData->startedCompiling(m_codeBlock); if (m_shouldEmitDebugHooks) m_codeBlock->setNeedsFullScopeChain(true); codeBlock->setGlobalData(m_globalData); - - bool usesArguments = functionBody->usesArguments(); - codeBlock->setUsesArguments(usesArguments); - if (usesArguments) { - m_argumentsRegister.setIndex(RegisterFile::OptionalCalleeArguments); - addVar(propertyNames().arguments, false); + + emitOpcode(op_enter); + if (m_codeBlock->needsFullScopeChain()) { + m_activationRegister = addVar(); + emitInitLazyRegister(m_activationRegister); + m_codeBlock->setActivationRegister(m_activationRegister->index()); } - if (m_codeBlock->needsFullScopeChain()) { - ++m_codeBlock->m_numVars; - m_activationRegisterIndex = newRegister()->index(); - emitOpcode(op_enter_with_activation); - instructions().append(m_activationRegisterIndex); - } else - emitOpcode(op_enter); + // 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())); - if (usesArguments) { - emitOpcode(op_init_arguments); + 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 (), // but for now we force eager creation of the arguments object when debugging. - if (m_shouldEmitDebugHooks) + 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) { - FuncDeclNode* funcDecl = functionStack[i]; - const Identifier& ident = funcDecl->m_ident; - m_functions.add(ident.ustring().rep()); - emitNewFunction(addVar(ident, false), funcDecl); + FunctionBodyNode* function = functionStack[i]; + const Identifier& ident = function->ident(); + if (!functionBody->captures(ident)) { + m_functions.add(ident.impl()); + RefPtr 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); } - const DeclarationStacks::VarStack& varStack = functionBody->varStack(); - for (size_t i = 0; i < varStack.size(); ++i) - addVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); + if (m_shouldEmitDebugHooks) + codeBlock->m_numCapturedVars = codeBlock->m_numVars; - const Identifier* parameters = functionBody->parameters(); - size_t parameterCount = functionBody->parameterCount(); - m_nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1; - m_parameters.grow(1 + parameterCount); // reserve space for "this" + FunctionParameters& parameters = *functionBody->parameters(); + m_parameters.grow(parameters.size() + 1); // reserve space for "this" // Add "this" as a parameter - m_thisRegister.setIndex(m_nextParameterIndex); - ++m_nextParameterIndex; - ++m_codeBlock->m_numParameters; + int nextParameterIndex = CallFrame::thisArgumentOffset(); + m_thisRegister.setIndex(nextParameterIndex--); + m_codeBlock->addParameter(); + + for (size_t i = 0; i < parameters.size(); ++i) + addParameter(parameters[i], nextParameterIndex--); + + preserveLastVar(); + + if (isConstructor()) { + RefPtr func = newTemporary(); + RefPtr funcProto = newTemporary(); - if (functionBody->usesThis() || m_shouldEmitDebugHooks) { + 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 (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) { emitOpcode(op_convert_this); instructions().append(m_thisRegister.index()); } - - for (size_t i = 0; i < parameterCount; ++i) - addParameter(parameters[i]); - - preserveLastVar(); } -BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock) - : m_shouldEmitDebugHooks(!!debugger) - , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) - , m_scopeChain(&scopeChain) +BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock, CompilationKind) + : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger()) + , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get())) + , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get())) + , m_scopeChain(*scopeChain->globalData, scopeChain) , m_symbolTable(symbolTable) , m_scopeNode(evalNode) , m_codeBlock(codeBlock) - , m_thisRegister(RegisterFile::ProgramCodeThisRegister) + , m_thisRegister(CallFrame::thisArgumentOffset()) , m_finallyDepth(0) , m_dynamicScopeDepth(0) , m_baseScopeDepth(codeBlock->baseScopeDepth()) , m_codeType(EvalCode) , m_nextConstantOffset(0) , m_globalConstantIndex(0) - , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) + , m_hasCreatedActivation(true) + , m_firstLazyFunction(0) + , m_lastLazyFunction(0) + , m_globalData(scopeChain->globalData) , m_lastOpcodeID(op_end) - , m_emitNodeDepth(0) - , m_regeneratingForExceptionInfo(false) - , m_codeBlockBeingRegeneratedFrom(0) +#ifndef NDEBUG + , m_lastOpcodePosition(0) +#endif + , m_stack(wtfThreadData().stack()) + , m_usesExceptions(false) + , m_expressionTooDeep(false) { + m_globalData->startedCompiling(m_codeBlock); 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" - + m_codeBlock->setNumParameters(1); + + 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 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::addParameter(const Identifier& ident) +BytecodeGenerator::~BytecodeGenerator() +{ + m_globalData->finishedCompiling(m_codeBlock); +} + +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. - RegisterID* result = 0; - UString::Rep* rep = ident.ustring().rep(); + StringImpl* rep = ident.impl(); if (!m_functions.contains(rep)) { - symbolTable().set(rep, m_nextParameterIndex); - RegisterID& parameter = registerFor(m_nextParameterIndex); - parameter.setIndex(m_nextParameterIndex); - result = ¶meter; + 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_nextParameterIndex; - ++m_codeBlock->m_numParameters; - return result; + m_codeBlock->addParameter(); } RegisterID* BytecodeGenerator::registerFor(const Identifier& ident) { if (ident == propertyNames().thisIdentifier) return &m_thisRegister; + + if (m_codeType == GlobalCode) + return 0; if (!shouldOptimizeLocals()) return 0; - SymbolTableEntry entry = symbolTable().get(ident.ustring().rep()); + SymbolTableEntry entry = symbolTable().get(ident.impl()); if (entry.isNull()) return 0; if (ident == propertyNames().arguments) createArgumentsIfNecessary(); - return ®isterFor(entry.getIndex()); + return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); +} + +RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident) +{ + if (m_codeType == EvalCode) + return 0; + + if (m_codeType == GlobalCode) + return 0; + + SymbolTableEntry entry = symbolTable().get(ident.impl()); + if (entry.isNull()) + return 0; + + return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); } bool BytecodeGenerator::willResolveToArguments(const Identifier& ident) @@ -445,7 +545,7 @@ bool BytecodeGenerator::willResolveToArguments(const Identifier& ident) if (!shouldOptimizeLocals()) return false; - SymbolTableEntry entry = symbolTable().get(ident.ustring().rep()); + SymbolTableEntry entry = symbolTable().get(ident.impl()); if (entry.isNull()) return false; @@ -459,20 +559,17 @@ RegisterID* BytecodeGenerator::uncheckedRegisterForArguments() { ASSERT(willResolveToArguments(propertyNames().arguments)); - SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.ustring().rep()); + SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.impl()); ASSERT(!entry.isNull()); return ®isterFor(entry.getIndex()); } -RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident) +RegisterID* BytecodeGenerator::createLazyRegisterIfNecessary(RegisterID* reg) { - if (m_codeType == EvalCode) - return 0; - - SymbolTableEntry entry = symbolTable().get(ident.ustring().rep()); - ASSERT(!entry.isNull()); - - return ®isterFor(entry.getIndex()); + if (m_lastLazyFunction <= reg->index() || reg->index() < m_firstLazyFunction) + return reg; + emitLazyNewFunction(reg, m_lazyFunctions.get(reg->index())); + return reg; } bool BytecodeGenerator::isLocal(const Identifier& ident) @@ -480,12 +577,12 @@ bool BytecodeGenerator::isLocal(const Identifier& ident) if (ident == propertyNames().thisIdentifier) return true; - return shouldOptimizeLocals() && symbolTable().contains(ident.ustring().rep()); + return shouldOptimizeLocals() && symbolTable().contains(ident.impl()); } bool BytecodeGenerator::isLocalConstant(const Identifier& ident) { - return symbolTable().get(ident.ustring().rep()).isReadOnly(); + return symbolTable().get(ident.impl()).isReadOnly(); } RegisterID* BytecodeGenerator::newRegister() @@ -521,7 +618,7 @@ PassRefPtr BytecodeGenerator::newLabelScope(LabelScope::Type type, c m_labelScopes.removeLast(); // Allocate new label scope. - LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : 0); // Only loops have continue targets. + LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : PassRefPtr