diff options
Diffstat (limited to 'JavaScriptCore/bytecompiler')
| -rw-r--r-- | JavaScriptCore/bytecompiler/BytecodeGenerator.cpp | 620 | ||||
| -rw-r--r-- | JavaScriptCore/bytecompiler/BytecodeGenerator.h | 172 | ||||
| -rw-r--r-- | JavaScriptCore/bytecompiler/NodesCodegen.cpp | 295 |
3 files changed, 722 insertions, 365 deletions
diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index b0a0877..26de0a1 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -152,13 +152,6 @@ void BytecodeGenerator::generate() 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(); } @@ -167,15 +160,14 @@ bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, Registe { int index = m_calleeRegisters.size(); SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); - pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry); + pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry); if (!result.second) { r0 = ®isterFor(result.first->second.getIndex()); return false; } - ++m_codeBlock->m_numVars; - r0 = newRegister(); + r0 = addVar(); return true; } @@ -183,7 +175,7 @@ bool BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, R { int index = m_nextGlobalIndex; SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); - pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry); + pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry); if (!result.second) index = result.first->second.getIndex(); @@ -202,9 +194,10 @@ 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) +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) @@ -217,9 +210,16 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d , 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.globalObject()->globalData()) , m_lastOpcodeID(op_end) +#ifndef NDEBUG + , m_lastOpcodePosition(0) +#endif , m_emitNodeDepth(0) + , m_usesExceptions(false) , m_regeneratingForExceptionInfo(false) , m_codeBlockBeingRegeneratedFrom(0) { @@ -286,24 +286,34 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d preserveLastVar(); } + codeBlock->m_numCapturedVars = codeBlock->m_numVars; } -BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock) - : m_shouldEmitDebugHooks(!!debugger) +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_globalData(&scopeChain.globalObject()->globalExec()->globalData()) + , 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_emitNodeDepth(0) + , m_usesExceptions(false) , m_regeneratingForExceptionInfo(false) , m_codeBlockBeingRegeneratedFrom(0) { @@ -311,68 +321,143 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug 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'. - if (usesArguments) { - emitOpcode(op_init_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) + 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(); - m_functions.add(ident.ustring().rep()); - emitNewFunction(addVar(ident, false), function); + 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); + } + } } - - const DeclarationStacks::VarStack& varStack = functionBody->varStack(); - for (size_t i = 0; i < varStack.size(); ++i) - addVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); + 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(); - m_nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1; + int nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1; m_parameters.grow(1 + parameterCount); // reserve space for "this" // Add "this" as a parameter - m_thisRegister.setIndex(m_nextParameterIndex); - ++m_nextParameterIndex; + m_thisRegister.setIndex(nextParameterIndex); ++m_codeBlock->m_numParameters; - - if (functionBody->usesThis() || m_shouldEmitDebugHooks) { - emitOpcode(op_convert_this); - instructions().append(m_thisRegister.index()); - } for (size_t i = 0; i < parameterCount; ++i) - addParameter(parameters[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 Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock) - : m_shouldEmitDebugHooks(!!debugger) +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) @@ -384,9 +469,16 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugge , 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.globalObject()->globalData()) , m_lastOpcodeID(op_end) +#ifndef NDEBUG + , m_lastOpcodePosition(0) +#endif , m_emitNodeDepth(0) + , m_usesExceptions(false) , m_regeneratingForExceptionInfo(false) , m_codeBlockBeingRegeneratedFrom(0) { @@ -408,27 +500,30 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugge 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) +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; } RegisterID* BytecodeGenerator::registerFor(const Identifier& ident) @@ -439,14 +534,14 @@ RegisterID* BytecodeGenerator::registerFor(const Identifier& ident) 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())); } bool BytecodeGenerator::willResolveToArguments(const Identifier& ident) @@ -457,7 +552,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; @@ -471,21 +566,29 @@ 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::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.ustring().rep()); + SymbolTableEntry entry = symbolTable().get(ident.impl()); if (entry.isNull()) return 0; - return ®isterFor(entry.getIndex()); + return createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); } bool BytecodeGenerator::isLocal(const Identifier& ident) @@ -493,12 +596,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() @@ -573,6 +676,11 @@ PassRefPtr<Label> BytecodeGenerator::emitLabel(Label* 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; } @@ -598,12 +706,14 @@ 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) @@ -633,7 +743,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar instructions().append(target->bind(begin, instructions().size())); return target; } - } else if (m_lastOpcodeID == op_lesseq && !target->isForward()) { + } else if (m_lastOpcodeID == op_lesseq) { int dstIndex; int src1Index; int src2Index; @@ -644,7 +754,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar rewindBinaryOp(); size_t begin = instructions().size(); - emitOpcode(op_loop_if_lesseq); + emitOpcode(target->isForward() ? op_jlesseq : op_loop_if_lesseq); instructions().append(src1Index); instructions().append(src2Index); instructions().append(target->bind(begin, instructions().size())); @@ -804,7 +914,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond unsigned BytecodeGenerator::addConstant(const Identifier& ident) { - UString::Rep* rep = ident.ustring().rep(); + 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)); @@ -967,16 +1077,16 @@ 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(globalData(), number)); + return emitLoad(dst, jsNumber(number)); JSValue& valueInMap = m_numberMap.add(number, JSValue()).first->second; if (!valueInMap) - valueInMap = jsNumber(globalData(), number); + valueInMap = jsNumber(number); return emitLoad(dst, valueInMap); } RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier) { - JSString*& stringInMap = m_stringMap.add(identifier.ustring().rep(), 0).first->second; + JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).first->second; if (!stringInMap) stringInMap = jsOwnedString(globalData(), identifier.ustring()); return emitLoad(dst, JSValue(stringInMap)); @@ -990,7 +1100,7 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v) return constantID; } -bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, JSObject*& globalObject) +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()) { @@ -1006,7 +1116,7 @@ bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& inde } size_t depth = 0; - + requiresDynamicChecks = false; ScopeChainIterator iter = m_scopeChain->begin(); ScopeChainIterator end = m_scopeChain->end(); for (; iter != end; ++iter, ++depth) { @@ -1014,7 +1124,7 @@ bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& inde if (!currentScope->isVariableObject()) break; JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); - SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.ustring().rep()); + SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); // Found the property if (!entry.isNull()) { @@ -1025,18 +1135,19 @@ bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& inde globalObject = currentVariableObject; return false; } - stackDepth = depth; + stackDepth = depth + m_codeBlock->needsFullScopeChain(); index = entry.getIndex(); if (++iter == end) globalObject = currentVariableObject; return true; } - if (currentVariableObject->isDynamicScope()) + 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; + stackDepth = depth + m_codeBlock->needsFullScopeChain(); index = missingSymbolMarker(); JSObject* scope = *iter; if (++iter == end) @@ -1044,6 +1155,12 @@ bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& inde 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); @@ -1059,7 +1176,8 @@ RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& pr size_t depth = 0; int index = 0; JSObject* globalObject = 0; - if (!findScopedProperty(property, index, depth, false, globalObject) && !globalObject) { + 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()); @@ -1077,7 +1195,7 @@ RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& pr #endif } - if (index != missingSymbolMarker() && !forceGlobalResolve) { + if (index != missingSymbolMarker() && !forceGlobalResolve && !requiresDynamicChecks) { // Directly index the property lookup across multiple scopes. return emitGetScopedVar(dst, depth, index, globalObject); } @@ -1087,12 +1205,21 @@ RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& pr #else m_codeBlock->addGlobalResolveInstruction(instructions().size()); #endif - emitOpcode(op_resolve_global); + emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); instructions().append(dst->index()); - instructions().append(globalObject); 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; } @@ -1115,7 +1242,6 @@ RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, i if (globalObject) { emitOpcode(op_get_global_var); instructions().append(dst->index()); - instructions().append(asCell(globalObject)); instructions().append(index); return dst; } @@ -1131,7 +1257,6 @@ RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, Registe { if (globalObject) { emitOpcode(op_put_global_var); - instructions().append(asCell(globalObject)); instructions().append(index); instructions().append(value->index()); return value; @@ -1148,12 +1273,14 @@ RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier size_t depth = 0; int index = 0; JSObject* globalObject = 0; - findScopedProperty(property, index, depth, false, globalObject); - if (!globalObject) { + 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; } @@ -1161,12 +1288,39 @@ RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier 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; - if (!findScopedProperty(property, index, depth, false, globalObject) || !globalObject) { + 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()); @@ -1198,12 +1352,13 @@ RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, Register #else m_codeBlock->addGlobalResolveInstruction(instructions().size()); #endif - emitOpcode(op_resolve_global); + emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); instructions().append(propDst->index()); - instructions().append(globalObject); instructions().append(addConstant(property)); instructions().append(0); instructions().append(0); + if (requiresDynamicChecks) + instructions().append(depth); return baseDst; } @@ -1231,6 +1386,16 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co 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) @@ -1247,6 +1412,27 @@ RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& p 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; } @@ -1277,6 +1463,16 @@ RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, 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--) { @@ -1353,11 +1549,24 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function) { - unsigned index = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, 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; } @@ -1369,64 +1578,66 @@ RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* 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, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset) +RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) { - return emitCall(op_call, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset); + return emitCall(op_call, dst, func, callArguments, divot, startOffset, endOffset); } void BytecodeGenerator::createArgumentsIfNecessary() { - if (m_codeBlock->usesArguments() && m_codeType == FunctionCode) - emitOpcode(op_create_arguments); + if (m_codeType != FunctionCode) + return; + ASSERT(m_codeBlock->usesArguments()); + + // 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, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset) +RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) { - createArgumentsIfNecessary(); - return emitCall(op_call_eval, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset); + return emitCall(op_call_eval, dst, func, callArguments, divot, startOffset, endOffset); } -RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned 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()); - ASSERT(thisRegister->refCount()); - RegisterID* originalFunc = func; - if (m_shouldEmitProfileHooks) { - // If codegen decided to recycle func as this call's destination register, - // we need to undo that optimization here so that func will still be around - // for the sake of op_profile_did_call. - if (dst == func) { - RefPtr<RegisterID> movedThisRegister = emitMove(newTemporary(), thisRegister); - RefPtr<RegisterID> movedFunc = emitMove(thisRegister, func); - - thisRegister = movedThisRegister.release().releaseRef(); - func = movedFunc.release().releaseRef(); - } - } + if (m_shouldEmitProfileHooks) + emitMove(callArguments.profileHookRegister(), func); // Generate code for arguments. - Vector<RefPtr<RegisterID>, 16> argv; - argv.append(thisRegister); - for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) { - argv.append(newTemporary()); - // op_call requires the arguments to be a sequential range of registers - ASSERT(argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1); - emitNode(argv.last().get(), n); - } + 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; @@ -1435,11 +1646,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi if (m_shouldEmitProfileHooks) { emitOpcode(op_profile_will_call); - instructions().append(func->index()); - -#if ENABLE(JIT) - m_codeBlock->addFunctionRegisterInfo(instructions().size(), func->index()); -#endif + instructions().append(callArguments.profileHookRegister()->index()); } emitExpressionInfo(divot, startOffset, endOffset); @@ -1450,30 +1657,29 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi // Emit call. emitOpcode(opcodeID); - instructions().append(dst->index()); // dst instructions().append(func->index()); // func - instructions().append(argv.size()); // argCount - instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset + 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(func->index()); - - if (dst == originalFunc) { - thisRegister->deref(); - func->deref(); - } + instructions().append(callArguments.profileHookRegister()->index()); } return dst; } -RegisterID* BytecodeGenerator::emitLoadVarargs(RegisterID* argCountDst, RegisterID* arguments) +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; } @@ -1485,20 +1691,19 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func if (m_shouldEmitProfileHooks) { emitOpcode(op_profile_will_call); instructions().append(func->index()); - -#if ENABLE(JIT) - m_codeBlock->addFunctionRegisterInfo(instructions().size(), func->index()); -#endif } emitExpressionInfo(divot, startOffset, endOffset); // Emit call. emitOpcode(op_call_varargs); - instructions().append(dst->index()); // dst 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()); @@ -1510,10 +1715,23 @@ RegisterID* BytecodeGenerator::emitReturn(RegisterID* src) { if (m_codeBlock->needsFullScopeChain()) { emitOpcode(op_tear_off_activation); - instructions().append(m_activationRegisterIndex); - } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1) + 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); } @@ -1524,43 +1742,25 @@ RegisterID* BytecodeGenerator::emitUnaryNoDstOp(OpcodeID opcodeID, RegisterID* s return src; } -RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset) +RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset) { ASSERT(func->refCount()); - RegisterID* originalFunc = func; - if (m_shouldEmitProfileHooks) { - // If codegen decided to recycle func as this call's destination register, - // we need to undo that optimization here so that func will still be around - // for the sake of op_profile_did_call. - if (dst == func) { - RefPtr<RegisterID> movedFunc = emitMove(newTemporary(), func); - func = movedFunc.release().releaseRef(); - } - } - - RefPtr<RegisterID> funcProto = newTemporary(); + if (m_shouldEmitProfileHooks) + emitMove(callArguments.profileHookRegister(), func); // Generate code for arguments. - Vector<RefPtr<RegisterID>, 16> argv; - argv.append(newTemporary()); // reserve space for "this" - for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode : 0; n; n = n->m_next) { - argv.append(newTemporary()); - // op_construct requires the arguments to be a sequential range of registers - ASSERT(argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1); - emitNode(argv.last().get(), n); + 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(func->index()); + instructions().append(callArguments.profileHookRegister()->index()); } - // Load prototype. - emitExpressionInfo(divot, startOffset, endOffset); - emitGetByIdExceptionInfo(op_construct); - emitGetById(funcProto.get(), func, globalData()->propertyNames->prototype); - // Reserve space for call frame. Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame; for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i) @@ -1573,23 +1773,17 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, #endif emitOpcode(op_construct); - instructions().append(dst->index()); // dst instructions().append(func->index()); // func - instructions().append(argv.size()); // argCount - instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset - instructions().append(funcProto->index()); // proto - instructions().append(argv[0]->index()); // thisRegister - - emitOpcode(op_construct_verify); - instructions().append(dst->index()); - instructions().append(argv[0]->index()); + 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(func->index()); - - if (dst == originalFunc) - func->deref(); + instructions().append(callArguments.profileHookRegister()->index()); } return dst; @@ -1619,7 +1813,6 @@ RegisterID* BytecodeGenerator::emitPushScope(RegisterID* scope) context.isFinallyBlock = false; m_scopeContextStack.append(context); m_dynamicScopeDepth++; - createArgumentsIfNecessary(); return emitUnaryNoDstOp(op_push_scope, scope); } @@ -1637,8 +1830,13 @@ void BytecodeGenerator::emitPopScope() 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); @@ -1834,6 +2032,7 @@ RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* 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 @@ -1846,13 +2045,16 @@ RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* star return targetRegister; } -RegisterID* BytecodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue message) +void BytecodeGenerator::emitThrowReferenceError(const UString& message) { - emitOpcode(op_new_error); - instructions().append(dst->index()); - instructions().append(static_cast<int>(type)); - instructions().append(addConstantValue(message)->index()); - return dst; + 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) @@ -1878,8 +2080,6 @@ void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& prop context.isFinallyBlock = false; m_scopeContextStack.append(context); m_dynamicScopeDepth++; - - createArgumentsIfNecessary(); emitOpcode(op_push_new_scope); instructions().append(dst->index()); @@ -1939,10 +2139,10 @@ static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t { UNUSED_PARAM(max); ASSERT(node->isString()); - UString::Rep* clause = static_cast<StringNode*>(node)->value().ustring().rep(); - ASSERT(clause->size() == 1); + StringImpl* clause = static_cast<StringNode*>(node)->value().impl(); + ASSERT(clause->length() == 1); - int32_t key = clause->data()[0]; + int32_t key = clause->characters()[0]; ASSERT(key >= min); ASSERT(key <= max); return key - min; @@ -1969,7 +2169,7 @@ static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t ASSERT(!labels[i]->isForward()); ASSERT(nodes[i]->isString()); - UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().ustring().rep(); + StringImpl* clause = static_cast<StringNode*>(nodes[i])->value().impl(); OffsetLocation location; location.branchOffset = labels[i]->bind(switchAddress, switchAddress + 3); jumpTable.offsetTable.add(clause, location); @@ -2009,9 +2209,23 @@ RegisterID* BytecodeGenerator::emitThrowExpressionTooDeepException() // 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); - RegisterID* exception = emitNewError(newTemporary(), SyntaxError, jsString(globalData(), "Expression too deep")); - emitThrow(exception); - return exception; + 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 index 8b6a425..a90f756 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -51,6 +51,23 @@ namespace JSC { 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; @@ -76,20 +93,27 @@ namespace JSC { static void setDumpsGeneratedCode(bool dumpsGeneratedCode); static bool dumpsGeneratedCode(); - BytecodeGenerator(ProgramNode*, const Debugger*, const ScopeChain&, SymbolTable*, ProgramCodeBlock*); - BytecodeGenerator(FunctionBodyNode*, const Debugger*, const ScopeChain&, SymbolTable*, CodeBlock*); - BytecodeGenerator(EvalNode*, const Debugger*, const ScopeChain&, SymbolTable*, EvalCodeBlock*); + 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(); @@ -103,10 +127,7 @@ namespace JSC { // 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. - // - // NB: depth does _not_ include the local scope. eg. a depth of 0 refers - // to the scope containing this codeblock. - bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, JSObject*& globalObject); + 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; } @@ -150,6 +171,17 @@ namespace JSC { 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()) @@ -175,10 +207,8 @@ namespace JSC { { // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); - if (!m_codeBlock->numberOfLineInfos() || m_codeBlock->lastLineInfo().lineNumber != n->lineNo()) { - LineInfo info = { instructions().size(), n->lineNo() }; - m_codeBlock->addLineInfo(info); - } + addLineInfo(n->lineNo()); + if (m_emitNodeDepth >= s_maxEmitNodeDepth) return emitThrowExpressionTooDeepException(); ++m_emitNodeDepth; @@ -194,19 +224,21 @@ namespace JSC { void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) { - if (!m_codeBlock->numberOfLineInfos() || m_codeBlock->lastLineInfo().lineNumber != n->lineNo()) { - LineInfo info = { instructions().size(), n->lineNo() }; - m_codeBlock->addLineInfo(info); - } - if (m_emitNodeDepth >= s_maxEmitNodeDepth) + addLineInfo(n->lineNo()); + if (m_emitNodeDepth >= s_maxEmitNodeDepth) { emitThrowExpressionTooDeepException(); + return; + } ++m_emitNodeDepth; n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue); --m_emitNodeDepth; } 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 @@ -234,17 +266,6 @@ namespace JSC { m_codeBlock->addExpressionInfo(info); } - void emitGetByIdExceptionInfo(OpcodeID opcodeID) - { - // Only op_construct and op_instanceof need exception info for - // a preceding op_get_by_id. - ASSERT(opcodeID == op_construct || opcodeID == op_instanceof); - GetByIdExceptionInfo info; - info.bytecodeOffset = instructions().size(); - info.isOpConstruct = (opcodeID == op_construct); - m_codeBlock->addGetByIdExceptionInfo(info); - } - ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) { return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; @@ -275,6 +296,8 @@ namespace JSC { 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); @@ -286,6 +309,7 @@ namespace JSC { 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()); } @@ -295,29 +319,33 @@ namespace JSC { 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, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); - RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + 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* args); + 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, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + 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); @@ -336,8 +364,15 @@ namespace JSC { 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) { emitUnaryNoDstOp(op_throw, exc); } - RegisterID* emitNewError(RegisterID* dst, ErrorType type, JSValue message); + 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); @@ -376,12 +411,16 @@ namespace JSC { 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); - void rewindBinaryOp(); - void rewindUnaryOp(); + ALWAYS_INLINE void rewindBinaryOp(); + ALWAYS_INLINE void rewindUnaryOp(); PassRefPtr<Label> emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope); @@ -396,23 +435,31 @@ namespace JSC { static const bool needsRef = false; }; - typedef HashMap<RefPtr<UString::Rep>, int, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap; + typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap; typedef HashMap<double, JSValue> NumberMap; - typedef HashMap<UString::Rep*, JSString*, IdentifierRepHash> IdentifierStringMap; - - RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; + RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); + RegisterID* newRegister(); - // Returns the RegisterID corresponding to ident. + // 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; } - // Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. + + // 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) @@ -424,7 +471,7 @@ namespace JSC { // Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. bool addGlobalVar(const Identifier&, bool isConstant, RegisterID*&); - RegisterID* addParameter(const Identifier&); + void addParameter(const Identifier&, int parameterIndex); void preserveLastVar(); @@ -433,9 +480,6 @@ namespace JSC { if (index >= 0) return m_calleeRegisters[index]; - if (index == RegisterFile::OptionalCalleeArguments) - return m_argumentsRegister; - if (m_parameters.size()) { ASSERT(!m_globals.size()); return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize]; @@ -450,14 +494,24 @@ namespace JSC { PassRefPtr<FunctionExecutable> makeFunction(ExecState* exec, FunctionBodyNode* body) { - return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); + 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->lineNo(), body->lastLine()); + 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; } @@ -467,9 +521,12 @@ namespace JSC { 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; @@ -479,11 +536,10 @@ namespace JSC { // 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<UString::Rep>, IdentifierRepHash> m_functions; + HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions; RegisterID m_ignoredResultRegister; RegisterID m_thisRegister; - RegisterID m_argumentsRegister; - int m_activationRegisterIndex; + RegisterID* m_activationRegister; SegmentedVector<RegisterID, 32> m_constantPoolRegisters; SegmentedVector<RegisterID, 32> m_calleeRegisters; SegmentedVector<RegisterID, 32> m_parameters; @@ -501,13 +557,19 @@ namespace JSC { Vector<ForInContext> m_forInContextStack; int m_nextGlobalIndex; - int m_nextParameterIndex; 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; @@ -517,9 +579,13 @@ namespace JSC { JSGlobalData* m_globalData; OpcodeID m_lastOpcodeID; +#ifndef NDEBUG + size_t m_lastOpcodePosition; +#endif unsigned m_emitNodeDepth; + bool m_usesExceptions; bool m_regeneratingForExceptionInfo; CodeBlock* m_codeBlockBeingRegeneratedFrom; diff --git a/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/JavaScriptCore/bytecompiler/NodesCodegen.cpp index b66c50d..a850c96 100644 --- a/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -39,8 +39,10 @@ #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> @@ -74,34 +76,18 @@ namespace JSC { // ------------------------------ ThrowableExpressionData -------------------------------- -static void substitute(UString& string, const UString& substring) -{ - int position = string.find("%s"); - ASSERT(position != -1); - string = makeString(string.substr(0, position), substring, string.substr(position + 2)); -} - -RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* message) +RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const UString& message) { generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message)); - generator.emitThrow(exception); - return exception; + generator.emitThrowReferenceError(message); + return generator.newTemporary(); } -RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const UString& label) +RegisterID* ThrowableExpressionData::emitThrowSyntaxError(BytecodeGenerator& generator, const UString& message) { - UString message = messageTemplate; - substitute(message, label); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message)); - generator.emitThrow(exception); - return exception; -} - -inline RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const Identifier& label) -{ - return emitThrowError(generator, type, messageTemplate, label.ustring()); + generator.emitThrowSyntaxError(message); + return generator.newTemporary(); } // ------------------------------ NullNode ------------------------------------- @@ -144,9 +130,9 @@ RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern.ustring(), m_flags.ustring()); + RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), m_flags.ustring()); if (!regExp->isValid()) - return emitThrowError(generator, SyntaxError, "Invalid regular expression: %s", regExp->errorMessage()); + return emitThrowSyntaxError(generator, makeUString("Invalid regular expression: ", regExp->errorMessage())); if (dst == generator.ignoredResult()) return 0; return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); @@ -176,7 +162,7 @@ RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* return generator.moveToDestinationIfNeeded(dst, local); } - generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0); + generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0); return generator.emitResolve(generator.finalDestination(dst), m_ident); } @@ -206,7 +192,7 @@ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds } if (m_elision) { - RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); + RegisterID* value = generator.emitLoad(0, jsNumber(m_elision + length)); generator.emitPutById(array.get(), generator.propertyNames().length, value); } @@ -265,7 +251,7 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe switch (p->m_node->m_type) { case PropertyNode::Constant: { - generator.emitPutById(newObj.get(), p->m_node->name(), value); + generator.emitDirectPutById(newObj.get(), p->m_node->name(), value); break; } case PropertyNode::Getter: { @@ -288,6 +274,12 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe 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()); @@ -298,6 +290,17 @@ RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, Regi 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); @@ -316,7 +319,23 @@ RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, Registe RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr<RegisterID> func = generator.emitNode(m_expr); - return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args, divot(), startOffset(), endOffset()); + 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 ---------------------------------- @@ -324,10 +343,10 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr<RegisterID> func = generator.tempDestination(dst); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); + CallArguments callArguments(generator, m_args); generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); - generator.emitResolveWithBase(thisRegister.get(), func.get(), generator.propertyNames().eval); - return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), generator.propertyNames().eval); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallValueNode ---------------------------------- @@ -335,8 +354,9 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr<RegisterID> func = generator.emitNode(m_expr); - RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); - return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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 ---------------------------------- @@ -344,25 +364,28 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) { - RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); - return generator.emitCall(generator.finalDestination(dst, thisRegister.get()), local.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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; - if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { + 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); - RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); - return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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(); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); + CallArguments callArguments(generator, m_args); int identifierStart = divot() - startOffset(); - generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); - generator.emitResolveWithBase(thisRegister.get(), func.get(), m_ident); - return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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 ---------------------------------- @@ -373,8 +396,9 @@ RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, 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); - RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); - return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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 ---------------------------------- @@ -382,12 +406,12 @@ RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr<RegisterID> function = generator.tempDestination(dst); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - generator.emitNode(thisRegister.get(), m_base); + 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(), thisRegister.get(), m_ident); - return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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) @@ -397,31 +421,39 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, 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> finalDestination = generator.finalDestination(dst, function.get()); + RefPtr<RegisterID> finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get()); generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); { - RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - ArgumentListNode* oldList = m_args->m_listNode; if (m_args->m_listNode && m_args->m_listNode->m_expr) { - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + ArgumentListNode* oldList = m_args->m_listNode; m_args->m_listNode = m_args->m_listNode->m_next; - } else - generator.emitLoad(thisRegister.get(), jsNull()); - generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - generator.emitJump(end.get()); - m_args->m_listNode = oldList; + 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()); { - RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); - generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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 finalDestination.get(); + return finalDestinationOrIgnored.get(); } - + static bool areTrivialApplyArguments(ArgumentsNode* args) { return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next @@ -440,25 +472,34 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, 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> finalDestination = generator.finalDestination(dst, function.get()); + RefPtr<RegisterID> finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get()); generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); { if (mayBeCall) { - RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - ArgumentListNode* oldList = m_args->m_listNode; if (m_args->m_listNode && m_args->m_listNode->m_expr) { - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); - m_args->m_listNode = m_args->m_listNode->m_next; - if (m_args->m_listNode) { - ASSERT(m_args->m_listNode->m_expr->isSimpleArray()); - ASSERT(!m_args->m_listNode->m_next); - m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_expr)->toArgumentList(generator.globalData()); + 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()); } - } else - generator.emitLoad(thisRegister.get(), jsNull()); - generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - m_args->m_listNode = oldList; + 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()); @@ -479,18 +520,19 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, while ((args = args->m_next)) generator.emitNode(args->m_expr); - generator.emitLoadVarargs(argsCountRegister.get(), argsRegister.get()); - generator.emitCallVarargs(finalDestination.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset()); + 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()); { - RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); - generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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 finalDestination.get(); + return finalDestinationOrIgnored.get(); } // ------------------------------ PostfixResolveNode ---------------------------------- @@ -524,7 +566,8 @@ RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, Regis int index = 0; size_t depth = 0; JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { + 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()) { @@ -602,7 +645,7 @@ RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterI RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus + 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."); } @@ -710,7 +753,8 @@ RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, Regist int index = 0; size_t depth = 0; JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { + 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); @@ -766,7 +810,7 @@ RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus + 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."); } @@ -972,7 +1016,9 @@ RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterI RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitGetByIdExceptionInfo(op_instanceof); + 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()); @@ -1132,7 +1178,8 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re int index = 0; size_t depth = 0; JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { + 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); @@ -1140,7 +1187,7 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re } RefPtr<RegisterID> src1 = generator.tempDestination(dst); - generator.emitExpressionInfo(divot() - startOffset() + m_ident.size(), m_ident.size(), 0); + 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); @@ -1161,7 +1208,8 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist int index = 0; size_t depth = 0; JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { + 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); @@ -1169,7 +1217,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist return value; } - RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); + RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident); if (dst == generator.ignoredResult()) dst = 0; RegisterID* value = generator.emitNode(dst, m_right); @@ -1207,7 +1255,7 @@ RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, Regist RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference."); + return emitThrowReferenceError(generator, "Left side of assignment is not a reference."); } // ------------------------------ AssignBracketNode ----------------------------------- @@ -1315,6 +1363,11 @@ 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) @@ -1512,7 +1565,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); if (!m_lexpr->isLocation()) - return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference."); + return emitThrowReferenceError(generator, "Left side of for-in statement is not a reference."); generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); @@ -1538,7 +1591,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds if (!propertyName) { propertyName = generator.newTemporary(); RefPtr<RegisterID> protect = propertyName; - RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident); + RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), ident); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); generator.emitPutById(base, ident, propertyName); @@ -1589,10 +1642,11 @@ RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* LabelScope* scope = generator.continueTarget(m_ident); - if (!scope) - return m_ident.isEmpty() - ? emitThrowError(generator, SyntaxError, "Invalid continue statement.") - : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", 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; @@ -1607,10 +1661,11 @@ RegisterID* BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds LabelScope* scope = generator.breakTarget(m_ident); - if (!scope) - return m_ident.isEmpty() - ? emitThrowError(generator, SyntaxError, "Invalid break statement.") - : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", 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; @@ -1622,7 +1677,7 @@ RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d { generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); if (generator.codeType() != FunctionCode) - return emitThrowError(generator, SyntaxError, "Invalid return statement."); + return emitThrowSyntaxError(generator, "Invalid return statement."); if (dst == generator.ignoredResult()) dst = 0; @@ -1698,8 +1753,8 @@ static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& break; } const UString& value = static_cast<StringNode*>(clauseExpression)->value().ustring(); - if (singleCharacterSwitch &= value.size() == 1) { - int32_t intVal = value.rep()->data()[0]; + if (singleCharacterSwitch &= value.length() == 1) { + int32_t intVal = value.impl()->characters()[0]; if (intVal < min_num) min_num = intVal; if (intVal > max_num) @@ -1828,7 +1883,7 @@ RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); if (generator.breakTarget(m_name)) - return emitThrowError(generator, SyntaxError, "Duplicate label: %s.", 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); @@ -1967,16 +2022,38 @@ RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, Registe { 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()) - return 0; + 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); + } + } } - RegisterID* r0 = generator.emitLoad(0, jsUndefined()); - generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); - generator.emitReturn(r0); return 0; } |
