summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/bytecompiler
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/bytecompiler')
-rw-r--r--JavaScriptCore/bytecompiler/BytecodeGenerator.cpp620
-rw-r--r--JavaScriptCore/bytecompiler/BytecodeGenerator.h172
-rw-r--r--JavaScriptCore/bytecompiler/NodesCodegen.cpp295
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 = &registerFor(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 = &parameter;
+ 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 &registerFor(entry.getIndex());
+ return createLazyRegisterIfNecessary(&registerFor(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 &registerFor(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 &registerFor(entry.getIndex());
+ return createLazyRegisterIfNecessary(&registerFor(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;
}