summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecompiler
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp556
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h182
-rw-r--r--Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp236
3 files changed, 582 insertions, 392 deletions
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index bfb1618a6..3d363354e 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
+ * Copyright (C) 2012 Igalia, S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -117,6 +118,39 @@ namespace JSC {
*/
#ifndef NDEBUG
+void ResolveResult::checkValidity()
+{
+ switch (m_type) {
+ case Register:
+ case ReadOnlyRegister:
+ ASSERT(m_local);
+ return;
+ case Lexical:
+ case ReadOnlyLexical:
+ case DynamicLexical:
+ case DynamicReadOnlyLexical:
+ ASSERT(m_index != missingSymbolMarker());
+ return;
+ case Global:
+ case DynamicGlobal:
+ ASSERT(m_globalObject);
+ return;
+ case IndexedGlobal:
+ case ReadOnlyIndexedGlobal:
+ case DynamicIndexedGlobal:
+ case DynamicReadOnlyIndexedGlobal:
+ ASSERT(m_index != missingSymbolMarker());
+ ASSERT(m_globalObject);
+ return;
+ case Dynamic:
+ return;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+#endif
+
+#ifndef NDEBUG
static bool s_dumpsGeneratedCode = false;
#endif
@@ -217,7 +251,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* s
#ifndef NDEBUG
, m_lastOpcodePosition(0)
#endif
- , m_stack(m_globalData->stack())
+ , m_stack(wtfThreadData().stack())
, m_usesExceptions(false)
, m_expressionTooDeep(false)
{
@@ -288,7 +322,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN
#ifndef NDEBUG
, m_lastOpcodePosition(0)
#endif
- , m_stack(m_globalData->stack())
+ , m_stack(wtfThreadData().stack())
, m_usesExceptions(false)
, m_expressionTooDeep(false)
{
@@ -449,7 +483,7 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeCh
#ifndef NDEBUG
, m_lastOpcodePosition(0)
#endif
- , m_stack(m_globalData->stack())
+ , m_stack(wtfThreadData().stack())
, m_usesExceptions(false)
, m_expressionTooDeep(false)
{
@@ -503,42 +537,6 @@ void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex
m_codeBlock->addParameter();
}
-RegisterID* BytecodeGenerator::registerFor(const Identifier& ident)
-{
- if (ident == propertyNames().thisIdentifier)
- return &m_thisRegister;
-
- if (m_codeType == GlobalCode)
- return 0;
-
- if (!shouldOptimizeLocals())
- return 0;
-
- SymbolTableEntry entry = symbolTable().get(ident.impl());
- if (entry.isNull())
- return 0;
-
- if (ident == propertyNames().arguments)
- createArgumentsIfNecessary();
-
- return createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
-}
-
-RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident)
-{
- if (m_codeType == EvalCode)
- return 0;
-
- if (m_codeType == GlobalCode)
- return 0;
-
- SymbolTableEntry entry = symbolTable().get(ident.impl());
- if (entry.isNull())
- return 0;
-
- return createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
-}
-
bool BytecodeGenerator::willResolveToArguments(const Identifier& ident)
{
if (ident != propertyNames().arguments)
@@ -668,6 +666,17 @@ void BytecodeGenerator::emitOpcode(OpcodeID opcodeID)
m_lastOpcodeID = opcodeID;
}
+ValueProfile* BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID)
+{
+#if ENABLE(VALUE_PROFILER)
+ ValueProfile* result = m_codeBlock->addValueProfile(instructions().size());
+#else
+ ValueProfile* result = 0;
+#endif
+ emitOpcode(opcodeID);
+ return result;
+}
+
void BytecodeGenerator::emitLoopHint()
{
#if ENABLE(DFG_JIT)
@@ -1159,59 +1168,109 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v)
return constantID;
}
-bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, bool& requiresDynamicChecks, JSObject*& globalObject)
+ResolveResult BytecodeGenerator::resolve(const Identifier& property)
{
+ if (property == propertyNames().thisIdentifier)
+ return ResolveResult::registerResolve(thisRegister(), ResolveResult::ReadOnlyFlag);
+
+ // Check if the property should be allocated in a register.
+ if (m_codeType != GlobalCode && shouldOptimizeLocals()) {
+ SymbolTableEntry entry = symbolTable().get(property.impl());
+ if (!entry.isNull()) {
+ if (property == propertyNames().arguments)
+ createArgumentsIfNecessary();
+ unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0;
+ RegisterID* local = createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
+ return ResolveResult::registerResolve(local, flags);
+ }
+ }
+
// Cases where we cannot statically optimize the lookup.
if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
- stackDepth = 0;
- index = missingSymbolMarker();
-
if (shouldOptimizeLocals() && m_codeType == GlobalCode) {
ScopeChainIterator iter = m_scopeChain->begin();
- globalObject = iter->get();
+ JSObject* globalObject = iter->get();
ASSERT((++iter) == m_scopeChain->end());
- }
- return false;
+ return ResolveResult::globalResolve(globalObject);
+ } else
+ return ResolveResult::dynamicResolve(0);
}
- size_t depth = 0;
- requiresDynamicChecks = false;
ScopeChainIterator iter = m_scopeChain->begin();
ScopeChainIterator end = m_scopeChain->end();
+ size_t depth = 0;
+ unsigned flags = 0;
for (; iter != end; ++iter, ++depth) {
JSObject* currentScope = iter->get();
- if (!currentScope->isVariableObject())
+ if (!currentScope->isVariableObject()) {
+ flags |= ResolveResult::DynamicFlag;
break;
+ }
JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl());
// Found the property
if (!entry.isNull()) {
- if (entry.isReadOnly() && forWriting) {
- stackDepth = 0;
- index = missingSymbolMarker();
- if (++iter == end)
- globalObject = currentVariableObject;
- return false;
+ if (entry.isReadOnly())
+ flags |= ResolveResult::ReadOnlyFlag;
+ depth += m_codeBlock->needsFullScopeChain();
+ if (++iter == end) {
+ if (flags & ResolveResult::DynamicFlag)
+ return ResolveResult::dynamicIndexedGlobalResolve(entry.getIndex(), depth, currentScope, flags);
+ return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentScope, flags);
}
- stackDepth = depth + m_codeBlock->needsFullScopeChain();
- index = entry.getIndex();
- if (++iter == end)
- globalObject = currentVariableObject;
- return true;
+ return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags);
}
bool scopeRequiresDynamicChecks = false;
if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks))
break;
- requiresDynamicChecks |= scopeRequiresDynamicChecks;
+ if (scopeRequiresDynamicChecks)
+ flags |= ResolveResult::DynamicFlag;
}
+
// Can't locate the property but we're able to avoid a few lookups.
- stackDepth = depth + m_codeBlock->needsFullScopeChain();
- index = missingSymbolMarker();
JSObject* scope = iter->get();
- if (++iter == end)
- globalObject = scope;
- return true;
+ depth += m_codeBlock->needsFullScopeChain();
+ if (++iter == end) {
+ if ((flags & ResolveResult::DynamicFlag) && depth)
+ return ResolveResult::dynamicGlobalResolve(depth, scope);
+ return ResolveResult::globalResolve(scope);
+ }
+ return ResolveResult::dynamicResolve(depth);
+}
+
+ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property)
+{
+ // Register-allocated const declarations.
+ if (m_codeType != EvalCode && m_codeType != GlobalCode) {
+ SymbolTableEntry entry = symbolTable().get(property.impl());
+ if (!entry.isNull()) {
+ unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0;
+ RegisterID* local = createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
+ return ResolveResult::registerResolve(local, flags);
+ }
+ }
+
+ // Const declarations in eval code or global code.
+ ScopeChainIterator iter = scopeChain()->begin();
+ ScopeChainIterator end = scopeChain()->end();
+ size_t depth = 0;
+ for (; iter != end; ++iter, ++depth) {
+ JSObject* currentScope = iter->get();
+ if (!currentScope->isVariableObject())
+ continue;
+ JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
+ SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl());
+ if (entry.isNull())
+ continue;
+ if (++iter == end)
+ return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentVariableObject, 0);
+ return ResolveResult::lexicalResolve(entry.getIndex(), depth + scopeDepth(), 0);
+ }
+
+ // FIXME: While this code should only be hit in an eval block, it will assign
+ // to the wrong base if property exists in an intervening with scope.
+ return ResolveResult::dynamicResolve(scopeDepth());
}
void BytecodeGenerator::emitCheckHasInstance(RegisterID* base)
@@ -1237,246 +1296,222 @@ bool BytecodeGenerator::shouldAvoidResolveGlobal()
return m_codeBlock->globalResolveInfoCount() > maxGlobalResolves && !m_labelScopes.size();
}
-RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
+RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
{
- size_t depth = 0;
- int index = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) && !globalObject) {
- // We can't optimise at all :-(
- emitOpcode(op_resolve);
- instructions().append(dst->index());
- instructions().append(addConstant(property));
- return dst;
- }
- if (shouldAvoidResolveGlobal()) {
- globalObject = 0;
- requiresDynamicChecks = true;
- }
-
- if (globalObject) {
- if (index != missingSymbolMarker() && !requiresDynamicChecks) {
- // Directly index the property lookup across multiple scopes.
- return emitGetScopedVar(dst, depth, index, globalObject);
- }
-
+ if (resolveResult.isStatic())
+ return emitGetStaticVar(dst, resolveResult);
+
+ if (resolveResult.isGlobal() && !shouldAvoidResolveGlobal()) {
#if ENABLE(JIT)
m_codeBlock->addGlobalResolveInfo(instructions().size());
#endif
#if ENABLE(INTERPRETER)
m_codeBlock->addGlobalResolveInstruction(instructions().size());
#endif
- emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
+ bool dynamic = resolveResult.isDynamic() && resolveResult.depth();
+ ValueProfile* profile = emitProfiledOpcode(dynamic ? op_resolve_global_dynamic : op_resolve_global);
instructions().append(dst->index());
instructions().append(addConstant(property));
instructions().append(0);
instructions().append(0);
- if (requiresDynamicChecks)
- instructions().append(depth);
+ if (dynamic)
+ instructions().append(resolveResult.depth());
+ instructions().append(profile);
return dst;
}
-
- if (requiresDynamicChecks) {
- // If we get here we have eval nested inside a |with| just give up
- emitOpcode(op_resolve);
+
+ if (resolveResult.type() == ResolveResult::Dynamic && resolveResult.depth()) {
+ // In this case we are at least able to drop a few scope chains from the
+ // lookup chain, although we still need to hash from then on.
+ ValueProfile* profile = emitProfiledOpcode(op_resolve_skip);
instructions().append(dst->index());
instructions().append(addConstant(property));
+ instructions().append(resolveResult.depth());
+ instructions().append(profile);
return dst;
}
- if (index != missingSymbolMarker()) {
- // Directly index the property lookup across multiple scopes.
- return emitGetScopedVar(dst, depth, index, globalObject);
- }
-
- // In this case we are at least able to drop a few scope chains from the
- // lookup chain, although we still need to hash from then on.
- emitOpcode(op_resolve_skip);
+ ValueProfile* profile = emitProfiledOpcode(op_resolve);
instructions().append(dst->index());
instructions().append(addConstant(property));
- instructions().append(depth);
+ instructions().append(profile);
return dst;
}
-RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue globalObject)
+RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
{
- if (globalObject) {
- if (m_lastOpcodeID == op_put_global_var) {
- int dstIndex;
- int srcIndex;
- retrieveLastUnaryOp(dstIndex, srcIndex);
-
- if (dstIndex == index && srcIndex == dst->index())
- return dst;
- }
+ if (resolveResult.isGlobal() && !resolveResult.isDynamic())
+ // Global object is the base
+ return emitLoad(dst, JSValue(resolveResult.globalObject()));
- emitOpcode(op_get_global_var);
- instructions().append(dst->index());
- instructions().append(index);
- return dst;
- }
-
- emitOpcode(op_get_scoped_var);
+ // We can't optimise at all :-(
+ ValueProfile* profile = emitProfiledOpcode(op_resolve_base);
instructions().append(dst->index());
- instructions().append(index);
- instructions().append(depth);
+ instructions().append(addConstant(property));
+ instructions().append(false);
+ instructions().append(profile);
return dst;
}
-RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue globalObject)
+RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
{
- if (globalObject) {
- emitOpcode(op_put_global_var);
- instructions().append(index);
- instructions().append(value->index());
- return value;
- }
- emitOpcode(op_put_scoped_var);
- instructions().append(index);
- instructions().append(depth);
- instructions().append(value->index());
- return value;
-}
+ if (!m_codeBlock->isStrictMode())
+ return emitResolveBase(dst, resolveResult, property);
-RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
-{
- size_t depth = 0;
- int index = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject);
- if (!globalObject || requiresDynamicChecks) {
- // We can't optimise at all :-(
- emitOpcode(op_resolve_base);
+ if (resolveResult.isGlobal() && !resolveResult.isDynamic()) {
+ // Global object is the base
+ RefPtr<RegisterID> result = emitLoad(dst, JSValue(resolveResult.globalObject()));
+ emitOpcode(op_ensure_property_exists);
instructions().append(dst->index());
instructions().append(addConstant(property));
- instructions().append(false);
- return dst;
+ return result.get();
}
- // Global object is the base
- return emitLoad(dst, JSValue(globalObject));
-}
-
-RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property)
-{
- if (!m_codeBlock->isStrictMode())
- return emitResolveBase(dst, property);
- size_t depth = 0;
- int index = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject);
- if (!globalObject || requiresDynamicChecks) {
- // We can't optimise at all :-(
- emitOpcode(op_resolve_base);
- instructions().append(dst->index());
- instructions().append(addConstant(property));
- instructions().append(true);
- return dst;
- }
-
- // Global object is the base
- RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject));
- emitOpcode(op_ensure_property_exists);
+ // We can't optimise at all :-(
+ ValueProfile* profile = emitProfiledOpcode(op_resolve_base);
instructions().append(dst->index());
instructions().append(addConstant(property));
- return result.get();
+ instructions().append(true);
+ instructions().append(profile);
+ return dst;
}
-RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
+RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property)
{
- size_t depth = 0;
- int index = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) {
- // We can't optimise at all :-(
- emitOpcode(op_resolve_with_base);
- instructions().append(baseDst->index());
- instructions().append(propDst->index());
- instructions().append(addConstant(property));
- return baseDst;
- }
+ if (resolveResult.isGlobal() && !resolveResult.isDynamic()) {
+ // Global object is the base
+ emitLoad(baseDst, JSValue(resolveResult.globalObject()));
- bool forceGlobalResolve = false;
+ if (resolveResult.isStatic()) {
+ // Directly index the property lookup across multiple scopes.
+ emitGetStaticVar(propDst, resolveResult);
+ return baseDst;
+ }
- // Global object is the base
- emitLoad(baseDst, JSValue(globalObject));
+ if (shouldAvoidResolveGlobal()) {
+ ValueProfile* profile = emitProfiledOpcode(op_resolve);
+ instructions().append(propDst->index());
+ instructions().append(addConstant(property));
+ instructions().append(profile);
+ return baseDst;
+ }
- if (index != missingSymbolMarker() && !forceGlobalResolve) {
- // Directly index the property lookup across multiple scopes.
- emitGetScopedVar(propDst, depth, index, globalObject);
- return baseDst;
- }
- if (shouldAvoidResolveGlobal()) {
- emitOpcode(op_resolve);
- instructions().append(propDst->index());
- instructions().append(addConstant(property));
- return baseDst;
- }
#if ENABLE(JIT)
- m_codeBlock->addGlobalResolveInfo(instructions().size());
+ m_codeBlock->addGlobalResolveInfo(instructions().size());
#endif
#if ENABLE(INTERPRETER)
- m_codeBlock->addGlobalResolveInstruction(instructions().size());
+ m_codeBlock->addGlobalResolveInstruction(instructions().size());
#endif
- emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
+ ValueProfile* profile = emitProfiledOpcode(op_resolve_global);
+ instructions().append(propDst->index());
+ instructions().append(addConstant(property));
+ instructions().append(0);
+ instructions().append(0);
+ instructions().append(profile);
+ return baseDst;
+ }
+
+
+
+
+ ValueProfile* profile = emitProfiledOpcode(op_resolve_with_base);
+ instructions().append(baseDst->index());
instructions().append(propDst->index());
instructions().append(addConstant(property));
- instructions().append(0);
- instructions().append(0);
- if (requiresDynamicChecks)
- instructions().append(depth);
+ instructions().append(profile);
return baseDst;
}
-RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
+RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property)
{
- size_t depth = 0;
- int index = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) {
+ if (resolveResult.isStatic()) {
+ emitLoad(baseDst, jsUndefined());
+ emitGetStaticVar(propDst, resolveResult);
+ return baseDst;
+ }
+
+ if (resolveResult.type() == ResolveResult::Dynamic) {
// We can't optimise at all :-(
- emitOpcode(op_resolve_with_this);
+ ValueProfile* profile = emitProfiledOpcode(op_resolve_with_this);
instructions().append(baseDst->index());
instructions().append(propDst->index());
instructions().append(addConstant(property));
+ instructions().append(profile);
return baseDst;
}
- bool forceGlobalResolve = false;
-
- // Global object is the base
emitLoad(baseDst, jsUndefined());
+ return emitResolve(propDst, resolveResult, property);
+}
- if (index != missingSymbolMarker() && !forceGlobalResolve) {
- // Directly index the property lookup across multiple scopes.
- emitGetScopedVar(propDst, depth, index, globalObject);
- return baseDst;
+RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult)
+{
+ ValueProfile* profile = 0;
+
+ switch (resolveResult.type()) {
+ case ResolveResult::Register:
+ case ResolveResult::ReadOnlyRegister:
+ if (dst == ignoredResult())
+ return 0;
+ return moveToDestinationIfNeeded(dst, resolveResult.local());
+
+ case ResolveResult::Lexical:
+ case ResolveResult::ReadOnlyLexical:
+ profile = emitProfiledOpcode(op_get_scoped_var);
+ instructions().append(dst->index());
+ instructions().append(resolveResult.index());
+ instructions().append(resolveResult.depth());
+ instructions().append(profile);
+ return dst;
+
+ case ResolveResult::IndexedGlobal:
+ case ResolveResult::ReadOnlyIndexedGlobal:
+ if (m_lastOpcodeID == op_put_global_var) {
+ int dstIndex;
+ int srcIndex;
+ retrieveLastUnaryOp(dstIndex, srcIndex);
+ if (dstIndex == resolveResult.index() && srcIndex == dst->index())
+ return dst;
+ }
+
+ profile = emitProfiledOpcode(op_get_global_var);
+ instructions().append(dst->index());
+ instructions().append(resolveResult.index());
+ instructions().append(profile);
+ return dst;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
}
- if (shouldAvoidResolveGlobal()) {
- emitOpcode(op_resolve);
- instructions().append(propDst->index());
- instructions().append(addConstant(property));
- return baseDst;
+}
+
+RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, RegisterID* value)
+{
+ switch (resolveResult.type()) {
+ case ResolveResult::Register:
+ case ResolveResult::ReadOnlyRegister:
+ return moveToDestinationIfNeeded(resolveResult.local(), value);
+
+ case ResolveResult::Lexical:
+ case ResolveResult::ReadOnlyLexical:
+ emitOpcode(op_put_scoped_var);
+ instructions().append(resolveResult.index());
+ instructions().append(resolveResult.depth());
+ instructions().append(value->index());
+ return value;
+
+ case ResolveResult::IndexedGlobal:
+ case ResolveResult::ReadOnlyIndexedGlobal:
+ emitOpcode(op_put_global_var);
+ instructions().append(resolveResult.index());
+ instructions().append(value->index());
+ return value;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
}
-#if ENABLE(JIT)
- m_codeBlock->addGlobalResolveInfo(instructions().size());
-#endif
-#if ENABLE(INTERPRETER)
- m_codeBlock->addGlobalResolveInstruction(instructions().size());
-#endif
- emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
- instructions().append(propDst->index());
- instructions().append(addConstant(property));
- instructions().append(0);
- instructions().append(0);
- if (requiresDynamicChecks)
- instructions().append(depth);
- return baseDst;
}
void BytecodeGenerator::emitMethodCheck()
@@ -1490,7 +1525,7 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co
m_codeBlock->addPropertyAccessInstruction(instructions().size());
#endif
- emitOpcode(op_get_by_id);
+ ValueProfile* profile = emitProfiledOpcode(op_get_by_id);
instructions().append(dst->index());
instructions().append(base->index());
instructions().append(addConstant(property));
@@ -1498,6 +1533,7 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co
instructions().append(0);
instructions().append(0);
instructions().append(0);
+ instructions().append(profile);
return dst;
}
@@ -1547,22 +1583,13 @@ RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identif
return value;
}
-RegisterID* BytecodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
+void BytecodeGenerator::emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter)
{
- emitOpcode(op_put_getter);
+ emitOpcode(op_put_getter_setter);
instructions().append(base->index());
instructions().append(addConstant(property));
- instructions().append(value->index());
- return value;
-}
-
-RegisterID* BytecodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
-{
- emitOpcode(op_put_setter);
- instructions().append(base->index());
- instructions().append(addConstant(property));
- instructions().append(value->index());
- return value;
+ instructions().append(getter->index());
+ instructions().append(setter->index());
}
RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
@@ -1576,11 +1603,12 @@ RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base,
RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
{
- emitOpcode(op_get_argument_by_val);
+ ValueProfile* profile = emitProfiledOpcode(op_get_argument_by_val);
instructions().append(dst->index());
ASSERT(base->index() == m_codeBlock->argumentsRegister());
instructions().append(base->index());
instructions().append(property->index());
+ instructions().append(profile);
return dst;
}
@@ -1599,10 +1627,11 @@ RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, R
return dst;
}
}
- emitOpcode(op_get_by_val);
+ ValueProfile* profile = emitProfiledOpcode(op_get_by_val);
instructions().append(dst->index());
instructions().append(base->index());
instructions().append(property->index());
+ instructions().append(profile);
return dst;
}
@@ -1824,8 +1853,9 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
instructions().append(0);
instructions().append(0);
if (dst != ignoredResult()) {
- emitOpcode(op_call_put_result);
+ ValueProfile* profile = emitProfiledOpcode(op_call_put_result);
instructions().append(dst->index()); // dst
+ instructions().append(profile);
}
if (m_shouldEmitProfileHooks) {
@@ -1853,8 +1883,9 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func
instructions().append(arguments->index());
instructions().append(firstFreeRegister->index());
if (dst != ignoredResult()) {
- emitOpcode(op_call_put_result);
+ ValueProfile* profile = emitProfiledOpcode(op_call_put_result);
instructions().append(dst->index());
+ instructions().append(profile);
}
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_did_call);
@@ -1926,8 +1957,9 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func,
instructions().append(0);
instructions().append(0);
if (dst != ignoredResult()) {
- emitOpcode(op_call_put_result);
+ ValueProfile* profile = emitProfiledOpcode(op_call_put_result);
instructions().append(dst->index()); // dst
+ instructions().append(profile);
}
if (m_shouldEmitProfileHooks) {
@@ -2362,7 +2394,7 @@ void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunctio
bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNumber)
{
- RegisterID* registerID = registerFor(ident);
+ RegisterID* registerID = resolve(ident).local();
if (!registerID || registerID->index() >= 0)
return 0;
return registerID->index() == CallFrame::argumentOffset(argumentNumber);
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 3ff5f2343..c9ec5d852 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
+ * Copyright (C) 2012 Igalia, S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -85,6 +86,144 @@ namespace JSC {
RefPtr<RegisterID> propertyRegister;
};
+ class ResolveResult {
+ public:
+ enum Flags {
+ // The property is locally bound, in a register.
+ RegisterFlag = 0x1,
+ // We need to traverse the scope chain at runtime, checking for
+ // non-strict eval and/or `with' nodes.
+ DynamicFlag = 0x2,
+ // The property was resolved to a definite location, and the
+ // identifier is not needed any more.
+ StaticFlag = 0x4,
+ // Once we have the base object, the property will be located at a
+ // known index.
+ IndexedFlag = 0x8,
+ // Skip some number of objects in the scope chain, given by "depth".
+ ScopedFlag = 0x10,
+ // The resolved binding is immutable.
+ ReadOnlyFlag = 0x20,
+ // The base object is the global object.
+ GlobalFlag = 0x40
+ };
+ enum Type {
+ // The property is local, and stored in a register.
+ Register = RegisterFlag | StaticFlag,
+ // A read-only local, created by "const".
+ ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag,
+ // The property is statically scoped free variable. Its coordinates
+ // are in "index" and "depth".
+ Lexical = IndexedFlag | ScopedFlag | StaticFlag,
+ // A read-only Lexical, created by "const".
+ ReadOnlyLexical = IndexedFlag | ScopedFlag | ReadOnlyFlag | StaticFlag,
+ // The property was not bound lexically, so at runtime we should
+ // look directly in the global object.
+ Global = GlobalFlag,
+ // Like Global, but we could actually resolve the property to a
+ // DontDelete property in the global object, for instance, any
+ // binding created with "var" at the top level. At runtime we'll
+ // just index into the global object.
+ IndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag,
+ // Like IndexedGlobal, but the property is also read-only, like NaN,
+ // Infinity, or undefined.
+ ReadOnlyIndexedGlobal = IndexedFlag | ReadOnlyFlag | GlobalFlag | StaticFlag,
+ // The property could not be resolved statically, due to the
+ // presence of `with' blocks. At runtime we'll have to walk the
+ // scope chain. ScopedFlag is set to indicate that "depth" will
+ // hold some number of nodes to skip in the scope chain, before
+ // beginning the search.
+ Dynamic = DynamicFlag | ScopedFlag,
+ // The property was located as a statically scoped free variable,
+ // but while traversing the scope chain, there was an intermediate
+ // activation that used non-strict `eval'. At runtime we'll have to
+ // check for the absence of this property in those intervening
+ // scopes.
+ DynamicLexical = DynamicFlag | IndexedFlag | ScopedFlag,
+ // Like ReadOnlyLexical, but with intervening non-strict `eval'.
+ DynamicReadOnlyLexical = DynamicFlag | IndexedFlag | ScopedFlag | ReadOnlyFlag,
+ // Like Global, but with intervening non-strict `eval'. As with
+ // Dynamic, ScopeFlag is set to indicate that "depth" does indeed
+ // store a number of frames to skip before doing the dynamic checks.
+ DynamicGlobal = DynamicFlag | GlobalFlag | ScopedFlag,
+ // Like IndexedGlobal, but with intervening non-strict `eval'.
+ DynamicIndexedGlobal = DynamicFlag | IndexedFlag | GlobalFlag | ScopedFlag,
+ // Like ReadOnlyIndexedGlobal, but with intervening non-strict
+ // `eval'.
+ DynamicReadOnlyIndexedGlobal = DynamicFlag | IndexedFlag | ReadOnlyFlag | GlobalFlag | ScopedFlag,
+ };
+
+ static ResolveResult registerResolve(RegisterID *local, unsigned flags)
+ {
+ return ResolveResult(Register | flags, local, missingSymbolMarker(), 0, 0);
+ }
+ static ResolveResult dynamicResolve(size_t depth)
+ {
+ return ResolveResult(Dynamic, 0, missingSymbolMarker(), depth, 0);
+ }
+ static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags)
+ {
+ unsigned type = (flags & DynamicFlag) ? DynamicLexical : Lexical;
+ return ResolveResult(type | flags, 0, index, depth, 0);
+ }
+ static ResolveResult indexedGlobalResolve(int index, JSObject *globalObject, unsigned flags)
+ {
+ return ResolveResult(IndexedGlobal | flags, 0, index, 0, globalObject);
+ }
+ static ResolveResult dynamicIndexedGlobalResolve(int index, size_t depth, JSObject *globalObject, unsigned flags)
+ {
+ return ResolveResult(DynamicIndexedGlobal | flags, 0, index, depth, globalObject);
+ }
+ static ResolveResult globalResolve(JSObject *globalObject)
+ {
+ return ResolveResult(Global, 0, missingSymbolMarker(), 0, globalObject);
+ }
+ static ResolveResult dynamicGlobalResolve(size_t dynamicDepth, JSObject *globalObject)
+ {
+ return ResolveResult(DynamicGlobal, 0, missingSymbolMarker(), dynamicDepth, globalObject);
+ }
+
+ unsigned type() const { return m_type; }
+ // Returns the register corresponding to a local variable, or 0 if no
+ // such register exists. Registers returned by ResolveResult::local() do
+ // not require explicit reference counting.
+ RegisterID* local() const { return m_local; }
+ int index() const { ASSERT (isIndexed() || isRegister()); return m_index; }
+ size_t depth() const { ASSERT(isScoped()); return m_depth; }
+ JSObject* globalObject() const { ASSERT(isGlobal()); ASSERT(m_globalObject); return m_globalObject; }
+
+ bool isRegister() const { return m_type & RegisterFlag; }
+ bool isDynamic() const { return m_type & DynamicFlag; }
+ bool isStatic() const { return m_type & StaticFlag; }
+ bool isIndexed() const { return m_type & IndexedFlag; }
+ bool isScoped() const { return m_type & ScopedFlag; }
+ bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); }
+ bool isGlobal() const { return m_type & GlobalFlag; }
+
+ private:
+ ResolveResult(unsigned type, RegisterID* local, int index, size_t depth, JSObject* globalObject)
+ : m_type(type)
+ , m_index(index)
+ , m_local(local)
+ , m_depth(depth)
+ , m_globalObject(globalObject)
+ {
+#ifndef NDEBUG
+ checkValidity();
+#endif
+ }
+
+#ifndef NDEBUG
+ void checkValidity();
+#endif
+
+ unsigned m_type;
+ int m_index; // Index in scope, if IndexedFlag is set
+ RegisterID* m_local; // Local register, if RegisterFlag is set
+ size_t m_depth; // Depth in scope chain, if ScopedFlag is set
+ JSObject* m_globalObject; // If GlobalFlag is set.
+ };
+
class BytecodeGenerator {
WTF_MAKE_FAST_ALLOCATED;
public:
@@ -107,11 +246,6 @@ namespace JSC {
JSObject* 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&);
-
bool isArgumentNumber(const Identifier&, int);
void setIsNumericCompareFunction(bool isNumericCompareFunction);
@@ -119,17 +253,11 @@ namespace JSC {
bool willResolveToArguments(const Identifier&);
RegisterID* uncheckedRegisterForArguments();
- // Behaves as registerFor does, but ignores dynamic scope as
+ // Resolve an identifier, given the current compile-time scope chain.
+ ResolveResult resolve(const Identifier&);
+ // Behaves as resolve does, but ignores dynamic scope as
// dynamic scope should not interfere with const initialisation
- RegisterID* constRegisterFor(const Identifier&);
-
- // Searches the scope chain in an attempt to statically locate the requested
- // property. Returns false if for any reason the property cannot be safely
- // optimised at all. Otherwise it will return the index and depth of the
- // VariableObject that defines the property. If the property cannot be found
- // statically, depth will contain the depth of the scope chain where dynamic
- // lookup must begin.
- bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, bool& includesDynamicScopes, JSObject*& globalObject);
+ ResolveResult resolveConstDecl(const Identifier&);
// Returns the register storing "this"
RegisterID* thisRegister() { return &m_thisRegister; }
@@ -274,7 +402,7 @@ namespace JSC {
return dst;
}
- return PassRefPtr<RegisterID>(emitNode(n));
+ return emitNode(n);
}
RegisterID* emitLoad(RegisterID* dst, bool);
@@ -309,14 +437,14 @@ namespace JSC {
RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
- RegisterID* emitResolve(RegisterID* dst, const Identifier& property);
- RegisterID* emitGetScopedVar(RegisterID* dst, size_t skip, int index, JSValue globalObject);
- RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValue globalObject);
+ RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&);
+ RegisterID* emitPutStaticVar(const ResolveResult&, RegisterID* value);
- RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property);
- RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property);
- RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);
- RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);
+ RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property);
+ RegisterID* emitResolveBase(RegisterID* dst, const ResolveResult&, const Identifier& property);
+ RegisterID* emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property);
+ RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property);
+ RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property);
void emitMethodCheck();
@@ -330,8 +458,7 @@ namespace JSC {
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);
+ void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter);
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);
@@ -409,6 +536,7 @@ namespace JSC {
private:
void emitOpcode(OpcodeID);
+ ValueProfile* emitProfiledOpcode(OpcodeID);
void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
void retrieveLastUnaryOp(int& dstIndex, int& srcIndex);
ALWAYS_INLINE void rewindBinaryOp();
@@ -466,12 +594,12 @@ namespace JSC {
FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body)
{
- return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
+ return FunctionExecutable::create(exec, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
}
FunctionExecutable* makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
{
- return FunctionExecutable::create(*globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
+ return FunctionExecutable::create(*globalData, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
}
JSString* addStringConstant(const Identifier&);
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index a0127d8d7..46ec698de 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -5,6 +5,7 @@
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2012 Igalia, S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -146,14 +147,15 @@ bool ResolveNode::isPure(BytecodeGenerator& generator) const
RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (RegisterID* local = generator.registerFor(m_ident)) {
+ ResolveResult resolveResult = generator.resolve(m_ident);
+ if (RegisterID* local = resolveResult.local()) {
if (dst == generator.ignoredResult())
return 0;
return generator.moveToDestinationIfNeeded(dst, local);
}
generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0);
- return generator.emitResolve(generator.finalDestination(dst), m_ident);
+ return generator.emitResolve(generator.finalDestination(dst), resolveResult, m_ident);
}
// ------------------------------ ArrayNode ------------------------------------
@@ -236,27 +238,79 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe
generator.emitNewObject(newObj.get());
- for (PropertyListNode* p = this; p; p = p->m_next) {
- RegisterID* value = generator.emitNode(p->m_node->m_assign);
-
- switch (p->m_node->m_type) {
- case PropertyNode::Constant: {
- generator.emitDirectPutById(newObj.get(), p->m_node->name(), value);
- break;
- }
- case PropertyNode::Getter: {
- generator.emitPutGetter(newObj.get(), p->m_node->name(), value);
- break;
+ // Fast case: this loop just handles regular value properties.
+ PropertyListNode* p = this;
+ for (; p && p->m_node->m_type == PropertyNode::Constant; p = p->m_next)
+ generator.emitDirectPutById(newObj.get(), p->m_node->name(), generator.emitNode(p->m_node->m_assign));
+
+ // Were there any get/set properties?
+ if (p) {
+ typedef std::pair<PropertyNode*, PropertyNode*> GetterSetterPair;
+ typedef HashMap<StringImpl*, GetterSetterPair> GetterSetterMap;
+ GetterSetterMap map;
+
+ // Build a map, pairing get/set values together.
+ for (PropertyListNode* q = p; q; q = q->m_next) {
+ PropertyNode* node = q->m_node;
+ if (node->m_type == PropertyNode::Constant)
+ continue;
+
+ GetterSetterPair pair(node, 0);
+ std::pair<GetterSetterMap::iterator, bool> result = map.add(node->name().impl(), pair);
+ if (!result.second)
+ result.first->second.second = node;
+ }
+
+ // Iterate over the remaining properties in the list.
+ for (; p; p = p->m_next) {
+ PropertyNode* node = p->m_node;
+ RegisterID* value = generator.emitNode(node->m_assign);
+
+ // Handle regular values.
+ if (node->m_type == PropertyNode::Constant) {
+ generator.emitDirectPutById(newObj.get(), node->name(), value);
+ continue;
}
- case PropertyNode::Setter: {
- generator.emitPutSetter(newObj.get(), p->m_node->name(), value);
- break;
+
+ // This is a get/set property, find its entry in the map.
+ ASSERT(node->m_type == PropertyNode::Getter || node->m_type == PropertyNode::Setter);
+ GetterSetterMap::iterator it = map.find(node->name().impl());
+ ASSERT(it != map.end());
+ GetterSetterPair& pair = it->second;
+
+ // Was this already generated as a part of its partner?
+ if (pair.second == node)
+ continue;
+
+ // Generate the paired node now.
+ RefPtr<RegisterID> getterReg;
+ RefPtr<RegisterID> setterReg;
+
+ if (node->m_type == PropertyNode::Getter) {
+ getterReg = value;
+ if (pair.second) {
+ ASSERT(pair.second->m_type == PropertyNode::Setter);
+ setterReg = generator.emitNode(pair.second->m_assign);
+ } else {
+ setterReg = generator.newTemporary();
+ generator.emitLoad(setterReg.get(), jsUndefined());
+ }
+ } else {
+ ASSERT(node->m_type == PropertyNode::Setter);
+ setterReg = value;
+ if (pair.second) {
+ ASSERT(pair.second->m_type == PropertyNode::Getter);
+ getterReg = generator.emitNode(pair.second->m_assign);
+ } else {
+ getterReg = generator.newTemporary();
+ generator.emitLoad(getterReg.get(), jsUndefined());
+ }
}
- default:
- ASSERT_NOT_REACHED();
+
+ generator.emitPutGetterSetter(newObj.get(), node->name(), getterReg.get(), setterReg.get());
}
}
-
+
return generator.moveToDestinationIfNeeded(dst, newObj.get());
}
@@ -346,7 +400,7 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg
RefPtr<RegisterID> func = generator.tempDestination(dst);
CallArguments callArguments(generator, m_args);
generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0);
- generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.propertyNames().eval);
+ generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.resolve(generator.propertyNames().eval), generator.propertyNames().eval);
return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
@@ -364,19 +418,19 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re
RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) {
+ ResolveResult resolveResult = generator.resolve(m_ident);
+
+ if (RegisterID* local = resolveResult.local()) {
+ RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local);
CallArguments callArguments(generator, m_args);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), local.get(), callArguments, divot(), startOffset(), endOffset());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
- int index = 0;
- size_t depth = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) {
- RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
+ if (resolveResult.isStatic()) {
+ RefPtr<RegisterID> func = generator.newTemporary();
CallArguments callArguments(generator, m_args);
+ generator.emitGetStaticVar(func.get(), resolveResult);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
@@ -384,8 +438,9 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
RefPtr<RegisterID> func = generator.newTemporary();
CallArguments callArguments(generator, m_args);
int identifierStart = divot() - startOffset();
+
generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0);
- generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), m_ident);
+ generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), resolveResult, m_ident);
return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
@@ -505,6 +560,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
RefPtr<RegisterID> profileHookRegister;
if (generator.shouldEmitProfileHooks())
profileHookRegister = generator.newTemporary();
+ RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
RefPtr<RegisterID> thisRegister = generator.emitNode(m_args->m_listNode->m_expr);
RefPtr<RegisterID> argsRegister;
ArgumentListNode* args = m_args->m_listNode->m_next;
@@ -518,7 +574,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
while ((args = args->m_next))
generator.emitNode(args->m_expr);
- generator.emitCallVarargs(finalDestinationOrIgnored.get(), base.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), startOffset(), endOffset());
+ generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), startOffset(), endOffset());
}
generator.emitJump(end.get());
}
@@ -548,24 +604,21 @@ static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* ds
RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (RegisterID* local = generator.registerFor(m_ident)) {
- if (generator.isLocalConstant(m_ident)) {
+ ResolveResult resolveResult = generator.resolve(m_ident);
+
+ if (RegisterID* local = resolveResult.local()) {
+ if (resolveResult.isReadOnly()) {
if (dst == generator.ignoredResult())
return 0;
return generator.emitToJSNumber(generator.finalDestination(dst), local);
}
-
if (dst == generator.ignoredResult())
return emitPreIncOrDec(generator, local, m_operator);
return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator);
}
- int index = 0;
- size_t depth = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) {
- RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
+ if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
+ RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult);
RegisterID* oldValue;
if (dst == generator.ignoredResult()) {
oldValue = 0;
@@ -573,13 +626,13 @@ RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, Regis
} else {
oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
}
- generator.emitPutScopedVar(depth, index, value.get(), globalObject);
+ generator.emitPutStaticVar(resolveResult, value.get());
return oldValue;
}
-
+
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RefPtr<RegisterID> value = generator.newTemporary();
- RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, m_ident);
RegisterID* oldValue;
if (dst == generator.ignoredResult()) {
oldValue = 0;
@@ -651,11 +704,12 @@ RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, Registe
RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (generator.registerFor(m_ident))
+ ResolveResult resolveResult = generator.resolve(m_ident);
+ if (resolveResult.isRegister())
return generator.emitLoad(generator.finalDestination(dst), false);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
- RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident);
+ RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident);
return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident);
}
@@ -706,13 +760,14 @@ RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst
RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (RegisterID* local = generator.registerFor(m_ident)) {
+ ResolveResult resolveResult = generator.resolve(m_ident);
+ if (RegisterID* local = resolveResult.local()) {
if (dst == generator.ignoredResult())
return 0;
return generator.emitTypeOf(generator.finalDestination(dst), local);
}
- RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident);
+ RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident);
generator.emitGetById(scratch.get(), scratch.get(), m_ident);
if (dst == generator.ignoredResult())
return 0;
@@ -735,32 +790,28 @@ RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, Register
RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (RegisterID* local = generator.registerFor(m_ident)) {
+ ResolveResult resolveResult = generator.resolve(m_ident);
+ if (RegisterID* local = resolveResult.local()) {
if (generator.isLocalConstant(m_ident)) {
if (dst == generator.ignoredResult())
return 0;
RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0);
return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes());
}
-
emitPreIncOrDec(generator, local, m_operator);
return generator.moveToDestinationIfNeeded(dst, local);
}
- int index = 0;
- size_t depth = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) {
- RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject);
+ if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
+ RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult);
emitPreIncOrDec(generator, propDst.get(), m_operator);
- generator.emitPutScopedVar(depth, index, propDst.get(), globalObject);
+ generator.emitPutStaticVar(resolveResult, propDst.get());
return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RefPtr<RegisterID> propDst = generator.tempDestination(dst);
- RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, m_ident);
emitPreIncOrDec(generator, propDst.get(), m_operator);
generator.emitPutById(base.get(), m_ident, propDst.get());
return generator.moveToDestinationIfNeeded(dst, propDst.get());
@@ -1148,10 +1199,11 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& gen
RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (RegisterID* local = generator.registerFor(m_ident)) {
- if (generator.isLocalConstant(m_ident)) {
+ ResolveResult resolveResult = generator.resolve(m_ident);
+
+ if (RegisterID *local = resolveResult.local()) {
+ if (resolveResult.isReadOnly())
return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
- }
if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
RefPtr<RegisterID> result = generator.newTemporary();
@@ -1165,20 +1217,16 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
return generator.moveToDestinationIfNeeded(dst, result);
}
- int index = 0;
- size_t depth = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) {
- RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject);
+ if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
+ RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult);
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);
+ generator.emitPutStaticVar(resolveResult, result);
return result;
}
RefPtr<RegisterID> src1 = generator.tempDestination(dst);
generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0);
- RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), resolveResult, 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);
}
@@ -1187,27 +1235,24 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (RegisterID* local = generator.registerFor(m_ident)) {
- if (generator.isLocalConstant(m_ident))
+ ResolveResult resolveResult = generator.resolve(m_ident);
+
+ if (RegisterID *local = resolveResult.local()) {
+ if (resolveResult.isReadOnly())
return generator.emitNode(dst, m_right);
-
RegisterID* result = generator.emitNode(local, m_right);
return generator.moveToDestinationIfNeeded(dst, result);
}
- int index = 0;
- size_t depth = 0;
- JSObject* globalObject = 0;
- bool requiresDynamicChecks = false;
- if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) {
+ if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
if (dst == generator.ignoredResult())
dst = 0;
RegisterID* value = generator.emitNode(dst, m_right);
- generator.emitPutScopedVar(depth, index, value, globalObject);
+ generator.emitPutStaticVar(resolveResult, value);
return value;
}
- RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident);
if (dst == generator.ignoredResult())
dst = 0;
RegisterID* value = generator.emitNode(dst, m_right);
@@ -1295,8 +1340,10 @@ RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
{
+ ResolveResult resolveResult = generator.resolveConstDecl(m_ident);
+
// FIXME: This code does not match the behavior of const in Firefox.
- if (RegisterID* local = generator.constRegisterFor(m_ident)) {
+ if (RegisterID* local = resolveResult.local()) {
if (!m_init)
return local;
@@ -1305,27 +1352,15 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined());
- ScopeChainIterator iter = generator.scopeChain()->begin();
- ScopeChainIterator end = generator.scopeChain()->end();
- size_t depth = 0;
- for (; iter != end; ++iter, ++depth) {
- JSObject* currentScope = iter->get();
- if (!currentScope->isVariableObject())
- continue;
- JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
- SymbolTableEntry entry = currentVariableObject->symbolTable().get(m_ident.impl());
- if (entry.isNull())
- continue;
-
- return generator.emitPutScopedVar(generator.scopeDepth() + depth, entry.getIndex(), value.get(), currentVariableObject->isGlobalObject() ? currentVariableObject : 0);
- }
-
+ if (resolveResult.isStatic())
+ return generator.emitPutStaticVar(resolveResult, value.get());
+
if (generator.codeType() != EvalCode)
return value.get();
// FIXME: While this code should only be hit in an eval block, it will assign
// to the wrong base if m_ident exists in an intervening with scope.
- RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), resolveResult, m_ident);
return generator.emitPutById(base.get(), m_ident, value.get());
}
@@ -1596,11 +1631,12 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
bool optimizedForinAccess = false;
if (m_lexpr->isResolveNode()) {
const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier();
- propertyName = generator.registerFor(ident);
+ ResolveResult resolveResult = generator.resolve(ident);
+ propertyName = resolveResult.local();
if (!propertyName) {
propertyName = generator.newTemporary();
RefPtr<RegisterID> protect = propertyName;
- RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), ident);
+ RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
generator.emitPutById(base, ident, propertyName);
@@ -1933,13 +1969,7 @@ RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
// Uncaught exception path: the catch block.
RefPtr<Label> here = generator.emitLabel(generator.newLabel().get());
RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get());
- if (m_catchHasEval) {
- RefPtr<RegisterID> dynamicScopeObject = generator.emitNewObject(generator.newTemporary());
- generator.emitPutById(dynamicScopeObject.get(), m_exceptionIdent, exceptionRegister.get());
- generator.emitMove(exceptionRegister.get(), dynamicScopeObject.get());
- generator.emitPushScope(exceptionRegister.get());
- } else
- generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get());
+ generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get());
generator.emitNode(dst, m_catchBlock);
generator.emitPopScope();
generator.emitLabel(catchEndLabel.get());