diff options
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp | 556 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h | 182 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp | 236 |
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(®isterFor(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(®isterFor(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(®isterFor(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(®isterFor(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()); |