summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecompiler
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-22 15:40:17 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-22 15:40:17 +0200
commit43a42f108af6bcbd91f2672731c3047c26213af1 (patch)
tree7fa092e5f5d873c72f2486a70e26be26f7a38bec /Source/JavaScriptCore/bytecompiler
parentd9cf437c840c6eb7417bdd97e6c40979255d3158 (diff)
downloadqtwebkit-43a42f108af6bcbd91f2672731c3047c26213af1.tar.gz
Imported WebKit commit 302e7806bff028bd1167a1ec7c86a1ee00ecfb49 (http://svn.webkit.org/repository/webkit/trunk@132067)
New snapshot that fixes build without QtWidgets
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp358
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h226
-rw-r--r--Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp81
3 files changed, 209 insertions, 456 deletions
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 1160a1888..228277328 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -137,25 +137,8 @@ void ResolveResult::checkValidity()
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 WatchedIndexedGlobal:
- case DynamicIndexedGlobal:
- case DynamicReadOnlyIndexedGlobal:
- ASSERT(m_index != missingSymbolMarker());
- ASSERT(m_globalObject);
- return;
case Dynamic:
+ ASSERT(!m_local);
return;
default:
ASSERT_NOT_REACHED();
@@ -163,11 +146,6 @@ void ResolveResult::checkValidity()
}
#endif
-WriteBarrier<Unknown>* ResolveResult::registerPointer() const
-{
- return &jsCast<JSGlobalObject*>(globalObject())->registerAt(index());
-}
-
static bool s_dumpsGeneratedCode = false;
void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode)
@@ -292,6 +270,8 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, S
, m_expressionTooDeep(false)
{
m_globalData->startedCompiling(m_codeBlock);
+ m_codeBlock->setGlobalObjectConstant(emitLoad(0, JSValue(m_codeBlock->globalObject()))->index());
+
if (m_shouldEmitDebugHooks)
m_codeBlock->setNeedsFullScopeChain(true);
@@ -324,7 +304,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, S
FunctionBodyNode* function = functionStack[i];
bool propertyDidExist =
globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
-
+
JSValue value = JSFunction::create(exec, FunctionExecutable::create(*m_globalData, function), scope);
int index = addGlobalVar(
function->ident(), IsVariable,
@@ -374,6 +354,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc
, m_expressionTooDeep(false)
{
m_globalData->startedCompiling(m_codeBlock);
+ m_codeBlock->setGlobalObjectConstant(emitLoad(0, JSValue(m_codeBlock->globalObject()))->index());
+
if (m_shouldEmitDebugHooks)
m_codeBlock->setNeedsFullScopeChain(true);
@@ -588,6 +570,8 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, JSScope* scope, SharedS
, m_expressionTooDeep(false)
{
m_globalData->startedCompiling(m_codeBlock);
+ m_codeBlock->setGlobalObjectConstant(emitLoad(0, JSValue(m_codeBlock->globalObject()))->index());
+
if (m_shouldEmitDebugHooks || m_baseScopeDepth)
m_codeBlock->setNeedsFullScopeChain(true);
@@ -1365,67 +1349,7 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property)
return ResolveResult::registerResolve(local, flags);
}
}
-
- // Cases where we cannot statically optimize the lookup.
- if (property == propertyNames().arguments || !canOptimizeNonLocals())
- return ResolveResult::dynamicResolve(0);
-
- ScopeChainIterator iter = m_scope->begin();
- ScopeChainIterator end = m_scope->end();
- size_t depth = 0;
- size_t depthOfFirstScopeWithDynamicChecks = 0;
- unsigned flags = 0;
- for (; iter != end; ++iter, ++depth) {
- JSObject* currentScope = iter.get();
- if (!currentScope->isVariableObject()) {
- flags |= ResolveResult::DynamicFlag;
- break;
- }
- JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope);
- SymbolTableEntry entry = currentVariableObject->symbolTable()->get(property.impl());
-
- // Found the property
- if (!entry.isNull()) {
- 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 | (entry.couldBeWatched() ? ResolveResult::WatchedFlag : 0));
- }
-#if !ASSERT_DISABLED
- if (JSActivation* activation = jsDynamicCast<JSActivation*>(currentVariableObject))
- ASSERT(activation->isValid(entry));
-#endif
- return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags);
- }
- bool scopeRequiresDynamicChecks = false;
- if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks))
- break;
- if (!(flags & ResolveResult::DynamicFlag)) {
- if (scopeRequiresDynamicChecks)
- flags |= ResolveResult::DynamicFlag;
- else
- ++depthOfFirstScopeWithDynamicChecks;
- }
- }
-
- // Can't locate the property but we're able to avoid a few lookups.
- JSObject* scope = iter.get();
- // Step over the function's activation, if it needs one. At this point we
- // know there is no dynamic scope in the function itself, so this is safe to
- // do.
- depth += m_codeBlock->needsFullScopeChain();
- depthOfFirstScopeWithDynamicChecks += m_codeBlock->needsFullScopeChain();
- if (++iter == end) {
- if ((flags & ResolveResult::DynamicFlag) && depth)
- return ResolveResult::dynamicGlobalResolve(depth, scope);
- return ResolveResult::globalResolve(scope);
- }
- return ResolveResult::dynamicResolve(depthOfFirstScopeWithDynamicChecks);
+ return ResolveResult::dynamicResolve();
}
ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property)
@@ -1440,26 +1364,7 @@ ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property)
}
}
- // Const declarations in eval code or global code.
- ScopeChainIterator iter = scope()->begin();
- ScopeChainIterator end = scope()->end();
- size_t depth = 0;
- for (; iter != end; ++iter, ++depth) {
- JSObject* currentScope = iter.get();
- if (!currentScope->isVariableObject())
- continue;
- JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(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());
+ return ResolveResult::dynamicResolve();
}
void BytecodeGenerator::emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target)
@@ -1481,158 +1386,89 @@ RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value
return dst;
}
-static const unsigned maxGlobalResolves = 128;
-
bool BytecodeGenerator::shouldAvoidResolveGlobal()
{
- return m_codeBlock->globalResolveInfoCount() > maxGlobalResolves && !m_labelScopes.size();
+ return !m_labelScopes.size();
}
RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
{
- if (resolveResult.isStatic())
- return emitGetStaticVar(dst, resolveResult, property);
-
- if (resolveResult.isGlobal() && !shouldAvoidResolveGlobal()) {
-#if ENABLE(JIT)
- m_codeBlock->addGlobalResolveInfo(instructions().size());
-#endif
- m_codeBlock->addGlobalResolveInstruction(instructions().size());
- 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 (dynamic)
- instructions().append(resolveResult.depth());
- instructions().append(profile);
- return dst;
- }
-
- 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 (resolveResult.isRegister())
+ return emitGetLocalVar(dst, resolveResult, property);
ValueProfile* profile = emitProfiledOpcode(op_resolve);
instructions().append(dst->index());
instructions().append(addConstant(property));
+ instructions().append(getResolveOperations(property));
instructions().append(profile);
return dst;
}
RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
{
- if (resolveResult.isGlobal() && !resolveResult.isDynamic())
- // Global object is the base
- return emitLoad(dst, JSValue(resolveResult.globalObject()));
-
+ ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
// We can't optimise at all :-(
ValueProfile* profile = emitProfiledOpcode(op_resolve_base);
instructions().append(dst->index());
instructions().append(addConstant(property));
instructions().append(false);
+ instructions().append(getResolveBaseOperations(property));
+ instructions().append(0);
instructions().append(profile);
return dst;
}
-RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
+RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier)
{
- if (!m_codeBlock->isStrictMode())
- return emitResolveBase(dst, resolveResult, property);
-
- 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));
- return result.get();
- }
-
+ ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
// We can't optimise at all :-(
ValueProfile* profile = emitProfiledOpcode(op_resolve_base);
instructions().append(dst->index());
instructions().append(addConstant(property));
- instructions().append(true);
+ instructions().append(m_codeBlock->isStrictMode());
+ uint32_t putToBaseIndex = 0;
+ instructions().append(getResolveBaseForPutOperations(property, putToBaseIndex));
+ verifier.resolved(putToBaseIndex);
+ instructions().append(putToBaseIndex);
instructions().append(profile);
return dst;
}
-RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property)
+RegisterID* BytecodeGenerator::emitResolveWithBaseForPut(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier)
{
- if (resolveResult.isGlobal() && !resolveResult.isDynamic()) {
- // Global object is the base
- emitLoad(baseDst, JSValue(resolveResult.globalObject()));
-
- if (resolveResult.isStatic()) {
- // Directly index the property lookup across multiple scopes.
- emitGetStaticVar(propDst, resolveResult, property);
- return baseDst;
- }
-
- if (shouldAvoidResolveGlobal()) {
- ValueProfile* profile = emitProfiledOpcode(op_resolve);
- instructions().append(propDst->index());
- instructions().append(addConstant(property));
- instructions().append(profile);
- return baseDst;
- }
-
-#if ENABLE(JIT)
- m_codeBlock->addGlobalResolveInfo(instructions().size());
-#endif
- m_codeBlock->addGlobalResolveInstruction(instructions().size());
- 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;
- }
-
+ ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
ValueProfile* profile = emitProfiledOpcode(op_resolve_with_base);
instructions().append(baseDst->index());
instructions().append(propDst->index());
instructions().append(addConstant(property));
+ uint32_t putToBaseIndex = 0;
+ instructions().append(getResolveWithBaseForPutOperations(property, putToBaseIndex));
+ verifier.resolved(putToBaseIndex);
+ instructions().append(putToBaseIndex);
instructions().append(profile);
return baseDst;
}
RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property)
{
- if (resolveResult.isStatic()) {
+ if (resolveResult.isRegister()) {
emitLoad(baseDst, jsUndefined());
- emitGetStaticVar(propDst, resolveResult, property);
+ emitGetLocalVar(propDst, resolveResult, property);
return baseDst;
}
- if (resolveResult.type() == ResolveResult::Dynamic) {
- // We can't optimise at all :-(
- ValueProfile* profile = emitProfiledOpcode(op_resolve_with_this);
- instructions().append(baseDst->index());
- instructions().append(propDst->index());
- instructions().append(addConstant(property));
- instructions().append(profile);
- return baseDst;
- }
-
- emitLoad(baseDst, jsUndefined());
- return emitResolve(propDst, resolveResult, property);
+ ValueProfile* profile = emitProfiledOpcode(op_resolve_with_this);
+ instructions().append(baseDst->index());
+ instructions().append(propDst->index());
+ instructions().append(addConstant(property));
+ instructions().append(getResolveWithThisOperations(property));
+ instructions().append(profile);
+ return baseDst;
}
-RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& identifier)
+RegisterID* BytecodeGenerator::emitGetLocalVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier&)
{
- ValueProfile* profile = 0;
-
switch (resolveResult.type()) {
case ResolveResult::Register:
case ResolveResult::ReadOnlyRegister:
@@ -1640,107 +1476,33 @@ RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveRe
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) {
- WriteBarrier<Unknown>* dstPointer;
- int srcIndex;
- retrieveLastUnaryOp(dstPointer, srcIndex);
- if (dstPointer == resolveResult.registerPointer() && srcIndex == dst->index())
- return dst;
- }
-
- profile = emitProfiledOpcode(op_get_global_var);
- instructions().append(dst->index());
- instructions().append(resolveResult.registerPointer());
- instructions().append(profile);
- return dst;
-
- case ResolveResult::WatchedIndexedGlobal:
- // Skip the peephole for now. It's not clear that it's profitable given
- // the DFG's capabilities, and the fact that if it's watchable then we
- // don't expect to see any put_global_var's anyway.
- profile = emitProfiledOpcode(op_get_global_var_watchable);
- instructions().append(dst->index());
- instructions().append(resolveResult.registerPointer());
- instructions().append(addConstant(identifier)); // For the benefit of the DFG.
- instructions().append(profile);
- return dst;
-
default:
ASSERT_NOT_REACHED();
return 0;
}
}
-RegisterID* BytecodeGenerator::emitInitGlobalConst(const ResolveResult& resolveResult, const Identifier& identifier, RegisterID* value)
+RegisterID* BytecodeGenerator::emitInitGlobalConst(const Identifier& identifier, RegisterID* value)
{
ASSERT(m_codeType == GlobalCode);
- switch (resolveResult.type()) {
- case ResolveResult::IndexedGlobal:
- case ResolveResult::ReadOnlyIndexedGlobal:
- emitOpcode(op_init_global_const);
- instructions().append(resolveResult.registerPointer());
- instructions().append(value->index());
- return value;
-
- case ResolveResult::WatchedIndexedGlobal:
- emitOpcode(op_init_global_const_check);
- instructions().append(resolveResult.registerPointer());
- instructions().append(value->index());
- instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable()->get(identifier.impl()).addressOfIsWatched());
- instructions().append(addConstant(identifier));
- return value;
-
- default:
- ASSERT_NOT_REACHED();
+ JSGlobalObject* globalObject = m_codeBlock->globalObject();
+ SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl());
+ if (entry.isNull())
return 0;
- }
-}
-
-RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, const Identifier& identifier, 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.registerPointer());
- instructions().append(value->index());
- return value;
-
- case ResolveResult::WatchedIndexedGlobal:
- emitOpcode(op_put_global_var_check);
- instructions().append(resolveResult.registerPointer());
+
+ if (entry.couldBeWatched()) {
+ emitOpcode(op_init_global_const_check);
+ instructions().append(&globalObject->registerAt(entry.getIndex()));
instructions().append(value->index());
- instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable()->get(identifier.impl()).addressOfIsWatched());
+ instructions().append(entry.addressOfIsWatched());
instructions().append(addConstant(identifier));
return value;
-
- default:
- ASSERT_NOT_REACHED();
- return 0;
}
+
+ emitOpcode(op_init_global_const);
+ instructions().append(&globalObject->registerAt(entry.getIndex()));
+ instructions().append(value->index());
+ return value;
}
void BytecodeGenerator::emitMethodCheck()
@@ -1790,6 +1552,16 @@ RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& p
return value;
}
+RegisterID* BytecodeGenerator::emitPutToBase(RegisterID* base, const Identifier& property, RegisterID* value, NonlocalResolveInfo& resolveInfo)
+{
+ emitOpcode(op_put_to_base);
+ instructions().append(base->index());
+ instructions().append(addConstant(property));
+ instructions().append(value->index());
+ instructions().append(resolveInfo.put());
+ return value;
+}
+
RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value)
{
m_codeBlock->addPropertyAccessInstruction(instructions().size());
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index ae79a13ae..246530ab2 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -123,124 +123,42 @@ namespace JSC {
// 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,
- // The property is being watched, so writes should be special.
- WatchedFlag = 0x80
+ ReadOnlyFlag = 0x4,
};
+
enum Type {
// The property is local, and stored in a register.
- Register = RegisterFlag | StaticFlag,
+ Register = RegisterFlag,
// 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 being watched.
- WatchedIndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag | WatchedFlag,
- // 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,
+ ReadOnlyRegister = RegisterFlag | ReadOnlyFlag,
+ // Any form of non-local lookup
+ Dynamic = DynamicFlag,
};
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);
+ return ResolveResult(Register | flags, local);
}
- static ResolveResult dynamicIndexedGlobalResolve(int index, size_t depth, JSObject *globalObject, unsigned flags)
+ static ResolveResult dynamicResolve()
{
- return ResolveResult(DynamicIndexedGlobal | flags, 0, index, depth, globalObject);
+ return ResolveResult(Dynamic, 0);
}
- 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; }
- WriteBarrier<Unknown>* registerPointer() const;
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)
+ ResolveResult(unsigned type, RegisterID* local)
: m_type(type)
- , m_index(index)
, m_local(local)
- , m_depth(depth)
- , m_globalObject(globalObject)
{
#ifndef NDEBUG
checkValidity();
@@ -252,10 +170,36 @@ namespace JSC {
#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.
+ };
+
+ struct NonlocalResolveInfo {
+ friend class BytecodeGenerator;
+ NonlocalResolveInfo()
+ : m_state(Unused)
+ {
+ }
+ ~NonlocalResolveInfo()
+ {
+ ASSERT(m_state == Put);
+ }
+ private:
+ void resolved(uint32_t putToBaseIndex)
+ {
+ ASSERT(putToBaseIndex);
+ ASSERT(m_state == Unused);
+ m_state = Resolved;
+ m_putToBaseIndex = putToBaseIndex;
+ }
+ uint32_t put()
+ {
+ ASSERT(m_state == Resolved);
+ m_state = Put;
+ return m_putToBaseIndex;
+ }
+ enum State { Unused, Resolved, Put };
+ State m_state;
+ uint32_t m_putToBaseIndex;
};
class BytecodeGenerator {
@@ -367,7 +311,7 @@ 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());
addLineInfo(n->lineNo());
- return m_stack.recursionCheck()
+ return m_stack.isSafeToRecurse()
? n->emitBytecode(*this, dst)
: emitThrowExpressionTooDeepException();
}
@@ -380,7 +324,7 @@ namespace JSC {
void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue)
{
addLineInfo(n->lineNo());
- if (m_stack.recursionCheck())
+ if (m_stack.isSafeToRecurse())
n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue);
else
emitThrowExpressionTooDeepException();
@@ -466,16 +410,17 @@ 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* emitGetStaticVar(RegisterID* dst, const ResolveResult&, const Identifier&);
- RegisterID* emitPutStaticVar(const ResolveResult&, const Identifier&, RegisterID* value);
- RegisterID* emitInitGlobalConst(const ResolveResult&, const Identifier&, RegisterID* value);
+ RegisterID* emitGetLocalVar(RegisterID* dst, const ResolveResult&, const Identifier&);
+ RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value);
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* emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo&);
+ RegisterID* emitResolveWithBaseForPut(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo&);
RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property);
+ RegisterID* emitPutToBase(RegisterID* base, const Identifier&, RegisterID* value, NonlocalResolveInfo&);
+
void emitMethodCheck();
RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
@@ -596,6 +541,12 @@ namespace JSC {
typedef HashMap<double, JSValue> NumberMap;
typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap;
+ typedef struct {
+ int resolveOperations;
+ int putOperations;
+ } ResolveCacheEntry;
+ typedef HashMap<StringImpl*, ResolveCacheEntry, IdentifierRepHash> IdentifierResolvePutMap;
+ typedef HashMap<StringImpl*, uint32_t, IdentifierRepHash> IdentifierResolveMap;
// Helper for emitCall() and emitConstruct(). This works because the set of
// expected functions have identical behavior for both call and construct
@@ -766,6 +717,75 @@ namespace JSC {
NumberMap m_numberMap;
IdentifierStringMap m_stringMap;
+ uint32_t getResolveOperations(const Identifier& property)
+ {
+ if (m_dynamicScopeDepth)
+ return m_codeBlock->addResolve();
+ IdentifierResolveMap::AddResult result = m_resolveCacheMap.add(property.impl(), 0);
+ if (result.isNewEntry)
+ result.iterator->value = m_codeBlock->addResolve();
+ return result.iterator->value;
+ }
+
+ uint32_t getResolveWithThisOperations(const Identifier& property)
+ {
+ if (m_dynamicScopeDepth)
+ return m_codeBlock->addResolve();
+ IdentifierResolveMap::AddResult result = m_resolveWithThisCacheMap.add(property.impl(), 0);
+ if (result.isNewEntry)
+ result.iterator->value = m_codeBlock->addResolve();
+ return result.iterator->value;
+ }
+
+ uint32_t getResolveBaseOperations(IdentifierResolvePutMap& map, const Identifier& property, uint32_t& putToBaseOperation)
+ {
+ if (m_dynamicScopeDepth) {
+ putToBaseOperation = m_codeBlock->addPutToBase();
+ return m_codeBlock->addResolve();
+ }
+ ResolveCacheEntry entry = {-1, -1};
+ IdentifierResolvePutMap::AddResult result = map.add(property.impl(), entry);
+ if (result.isNewEntry)
+ result.iterator->value.resolveOperations = m_codeBlock->addResolve();
+ if (result.iterator->value.putOperations == -1)
+ result.iterator->value.putOperations = getPutToBaseOperation(property);
+ putToBaseOperation = result.iterator->value.putOperations;
+ return result.iterator->value.resolveOperations;
+ }
+
+ uint32_t getResolveBaseOperations(const Identifier& property)
+ {
+ uint32_t scratch;
+ return getResolveBaseOperations(m_resolveBaseMap, property, scratch);
+ }
+
+ uint32_t getResolveBaseForPutOperations(const Identifier& property, uint32_t& putToBaseOperation)
+ {
+ return getResolveBaseOperations(m_resolveBaseForPutMap, property, putToBaseOperation);
+ }
+
+ uint32_t getResolveWithBaseForPutOperations(const Identifier& property, uint32_t& putToBaseOperation)
+ {
+ return getResolveBaseOperations(m_resolveWithBaseForPutMap, property, putToBaseOperation);
+ }
+
+ uint32_t getPutToBaseOperation(const Identifier& property)
+ {
+ if (m_dynamicScopeDepth)
+ return m_codeBlock->addPutToBase();
+ IdentifierResolveMap::AddResult result = m_putToBaseMap.add(property.impl(), 0);
+ if (result.isNewEntry)
+ result.iterator->value = m_codeBlock->addPutToBase();
+ return result.iterator->value;
+ }
+
+ IdentifierResolveMap m_putToBaseMap;
+ IdentifierResolveMap m_resolveCacheMap;
+ IdentifierResolveMap m_resolveWithThisCacheMap;
+ IdentifierResolvePutMap m_resolveBaseMap;
+ IdentifierResolvePutMap m_resolveBaseForPutMap;
+ IdentifierResolvePutMap m_resolveWithBaseForPutMap;
+
JSGlobalData* m_globalData;
OpcodeID m_lastOpcodeID;
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 10a873d1c..68811955f 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -141,7 +141,7 @@ RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst
bool ResolveNode::isPure(BytecodeGenerator& generator) const
{
- return generator.resolve(m_ident).isStatic();
+ return generator.resolve(m_ident).isRegister();
}
RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -439,14 +439,6 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
- if (resolveResult.isStatic()) {
- RefPtr<RegisterID> func = generator.newTemporary();
- CallArguments callArguments(generator, m_args);
- generator.emitGetStaticVar(func.get(), resolveResult, m_ident);
- generator.emitLoad(callArguments.thisRegister(), jsUndefined());
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset());
- }
-
RefPtr<RegisterID> func = generator.newTemporary();
CallArguments callArguments(generator, m_args);
int identifierStart = divot() - startOffset();
@@ -631,29 +623,18 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
return emitPreIncOrDec(generator, local, m_operator);
return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator);
}
-
- if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
- RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, ident);
- RegisterID* oldValue;
- if (dst == generator.ignoredResult()) {
- oldValue = 0;
- emitPreIncOrDec(generator, value.get(), m_operator);
- } else
- oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
- generator.emitPutStaticVar(resolveResult, ident, value.get());
- return oldValue;
- }
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RefPtr<RegisterID> value = generator.newTemporary();
- RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, ident);
+ NonlocalResolveInfo resolveInfo;
+ RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), value.get(), resolveResult, ident, resolveInfo);
RegisterID* oldValue;
if (dst == generator.ignoredResult()) {
oldValue = 0;
emitPreIncOrDec(generator, value.get(), m_operator);
} else
oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
- generator.emitPutById(base.get(), ident, value.get());
+ generator.emitPutToBase(base.get(), ident, value.get(), resolveInfo);
return oldValue;
}
@@ -828,18 +809,12 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
return generator.moveToDestinationIfNeeded(dst, local);
}
- if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
- RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, ident);
- emitPreIncOrDec(generator, propDst.get(), m_operator);
- generator.emitPutStaticVar(resolveResult, ident, 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(), resolveResult, ident);
+ NonlocalResolveInfo resolveVerifier;
+ RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), propDst.get(), resolveResult, ident, resolveVerifier);
emitPreIncOrDec(generator, propDst.get(), m_operator);
- generator.emitPutById(base.get(), ident, propDst.get());
+ generator.emitPutToBase(base.get(), ident, propDst.get(), resolveVerifier);
return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
@@ -1265,18 +1240,12 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
return generator.moveToDestinationIfNeeded(dst, result);
}
- if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
- RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
- RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
- generator.emitPutStaticVar(resolveResult, m_ident, 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(), resolveResult, m_ident);
+ NonlocalResolveInfo resolveVerifier;
+ RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), src1.get(), resolveResult, m_ident, resolveVerifier);
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);
+ return generator.emitPutToBase(base.get(), m_ident, result, resolveVerifier);
}
// ------------------------------ AssignResolveNode -----------------------------------
@@ -1285,7 +1254,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
{
ResolveResult resolveResult = generator.resolve(m_ident);
- if (RegisterID *local = resolveResult.local()) {
+ if (RegisterID* local = resolveResult.local()) {
if (resolveResult.isReadOnly()) {
generator.emitReadOnlyExceptionIfNeeded();
return generator.emitNode(dst, m_right);
@@ -1294,20 +1263,13 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
return generator.moveToDestinationIfNeeded(dst, result);
}
- if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
- if (dst == generator.ignoredResult())
- dst = 0;
- RegisterID* value = generator.emitNode(dst, m_right);
- generator.emitPutStaticVar(resolveResult, m_ident, value);
- return value;
- }
-
- RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident);
+ NonlocalResolveInfo resolveVerifier;
+ RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident, resolveVerifier);
if (dst == generator.ignoredResult())
dst = 0;
RegisterID* value = generator.emitNode(dst, m_right);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
- return generator.emitPutById(base.get(), m_ident, value);
+ return generator.emitPutToBase(base.get(), m_ident, value, resolveVerifier);
}
// ------------------------------ AssignDotNode -----------------------------------
@@ -1402,16 +1364,14 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined());
- if (resolveResult.isStatic()) {
- if (generator.codeType() == GlobalCode)
- return generator.emitInitGlobalConst(resolveResult, m_ident, value.get());
- return generator.emitPutStaticVar(resolveResult, m_ident, value.get());
+ if (generator.codeType() == GlobalCode) {
+ if (RegisterID* result = generator.emitInitGlobalConst(m_ident, value.get()))
+ return result;
}
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.
+ // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope.
RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), resolveResult, m_ident);
return generator.emitPutById(base.get(), m_ident, value.get());
}
@@ -1699,10 +1659,11 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
if (!propertyName) {
propertyName = generator.newTemporary();
RefPtr<RegisterID> protect = propertyName;
- RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident);
+ NonlocalResolveInfo resolveVerifier;
+ RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident, resolveVerifier);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
- generator.emitPutById(base, ident, propertyName);
+ generator.emitPutToBase(base, ident, propertyName, resolveVerifier);
} else {
expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);