From 43a42f108af6bcbd91f2672731c3047c26213af1 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 22 Oct 2012 15:40:17 +0200 Subject: Imported WebKit commit 302e7806bff028bd1167a1ec7c86a1ee00ecfb49 (http://svn.webkit.org/repository/webkit/trunk@132067) New snapshot that fixes build without QtWidgets --- .../bytecompiler/BytecodeGenerator.cpp | 358 ++++----------------- .../bytecompiler/BytecodeGenerator.h | 226 +++++++------ .../JavaScriptCore/bytecompiler/NodesCodegen.cpp | 81 ++--- 3 files changed, 209 insertions(+), 456 deletions(-) (limited to 'Source/JavaScriptCore/bytecompiler') 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* ResolveResult::registerPointer() const -{ - return &jsCast(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(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(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(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 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* 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(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(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* 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 NumberMap; typedef HashMap IdentifierStringMap; + typedef struct { + int resolveOperations; + int putOperations; + } ResolveCacheEntry; + typedef HashMap IdentifierResolvePutMap; + typedef HashMap 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 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 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 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 value = generator.newTemporary(); - RefPtr base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, ident); + NonlocalResolveInfo resolveInfo; + RefPtr 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 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 propDst = generator.tempDestination(dst); - RefPtr base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, ident); + NonlocalResolveInfo resolveVerifier; + RefPtr 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 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 src1 = generator.tempDestination(dst); generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0); - RefPtr base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), resolveResult, m_ident); + NonlocalResolveInfo resolveVerifier; + RefPtr 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 base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident); + NonlocalResolveInfo resolveVerifier; + RefPtr 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 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 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 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); -- cgit v1.2.1