Commit 75f804e0 authored by oliver@apple.com's avatar oliver@apple.com

Bring back eager resolution of function scoped variables

https://bugs.webkit.org/show_bug.cgi?id=111497

Reviewed by Geoffrey Garen.

This reverts the get/put_scoped_var part of the great non-local
variable resolution refactoring.  This still leaves all the lazy
variable resolution logic as it's necessary for global property
resolution, and i don't want to make the patch bigger than it
already is.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
(CodeBlock):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::codeBlockFor):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC):
(UnlinkedFunctionExecutable):
(UnlinkedCodeBlock):
(JSC::UnlinkedCodeBlock::usesGlobalObject):
(JSC::UnlinkedCodeBlock::setGlobalObjectRegister):
(JSC::UnlinkedCodeBlock::globalObjectRegister):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::ResolveResult::checkValidity):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitLoadGlobalObject):
(JSC):
(JSC::BytecodeGenerator::resolve):
(JSC::BytecodeGenerator::resolveConstDecl):
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveBase):
(JSC::BytecodeGenerator::emitResolveBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithThis):
(JSC::BytecodeGenerator::emitGetStaticVar):
(JSC::BytecodeGenerator::emitPutStaticVar):
* bytecompiler/BytecodeGenerator.h:
(JSC::ResolveResult::lexicalResolve):
(JSC::ResolveResult::isStatic):
(JSC::ResolveResult::depth):
(JSC::ResolveResult::index):
(ResolveResult):
(JSC::ResolveResult::ResolveResult):
(BytecodeGenerator):
* bytecompiler/NodesCodegen.cpp:
(JSC::ResolveNode::isPure):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::TypeOfResolveNode::emitBytecode):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::debugFail):
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
(JSC::DFG::canInlineOpcode):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
(JIT):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_scoped_var):
(JSC):
(JSC::JIT::emit_op_put_scoped_var):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_scoped_var):
(JSC):
(JSC::JIT::emit_op_put_scoped_var):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CodeCache.cpp:
(JSC::CodeCache::getCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):
* runtime/CodeCache.h:
(JSC):
(CodeCache):
* runtime/Executable.cpp:
(JSC::EvalExecutable::compileInternal):
(JSC::FunctionExecutable::produceCodeBlockFor):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::createEvalCodeBlock):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
* runtime/Options.cpp:
(JSC::Options::initialize):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@145000 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ffd46d7d
2013-03-05 Oliver Hunt <oliver@apple.com>
Bring back eager resolution of function scoped variables
https://bugs.webkit.org/show_bug.cgi?id=111497
Reviewed by Geoffrey Garen.
This reverts the get/put_scoped_var part of the great non-local
variable resolution refactoring. This still leaves all the lazy
variable resolution logic as it's necessary for global property
resolution, and i don't want to make the patch bigger than it
already is.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
(CodeBlock):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::codeBlockFor):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC):
(UnlinkedFunctionExecutable):
(UnlinkedCodeBlock):
(JSC::UnlinkedCodeBlock::usesGlobalObject):
(JSC::UnlinkedCodeBlock::setGlobalObjectRegister):
(JSC::UnlinkedCodeBlock::globalObjectRegister):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::ResolveResult::checkValidity):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitLoadGlobalObject):
(JSC):
(JSC::BytecodeGenerator::resolve):
(JSC::BytecodeGenerator::resolveConstDecl):
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveBase):
(JSC::BytecodeGenerator::emitResolveBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithThis):
(JSC::BytecodeGenerator::emitGetStaticVar):
(JSC::BytecodeGenerator::emitPutStaticVar):
* bytecompiler/BytecodeGenerator.h:
(JSC::ResolveResult::lexicalResolve):
(JSC::ResolveResult::isStatic):
(JSC::ResolveResult::depth):
(JSC::ResolveResult::index):
(ResolveResult):
(JSC::ResolveResult::ResolveResult):
(BytecodeGenerator):
* bytecompiler/NodesCodegen.cpp:
(JSC::ResolveNode::isPure):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::TypeOfResolveNode::emitBytecode):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::debugFail):
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
(JSC::DFG::canInlineOpcode):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
(JIT):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_scoped_var):
(JSC):
(JSC::JIT::emit_op_put_scoped_var):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_scoped_var):
(JSC):
(JSC::JIT::emit_op_put_scoped_var):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CodeCache.cpp:
(JSC::CodeCache::getCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):
* runtime/CodeCache.h:
(JSC):
(CodeCache):
* runtime/Executable.cpp:
(JSC::EvalExecutable::compileInternal):
(JSC::FunctionExecutable::produceCodeBlockFor):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::createEvalCodeBlock):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
* runtime/Options.cpp:
(JSC::Options::initialize):
2013-03-06 Filip Pizlo <fpizlo@apple.com>
Unreviewed, roll out http://trac.webkit.org/changeset/144989
......
......@@ -980,6 +980,21 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
dumpValueProfiling(out, it, hasPrintedProfiling);
break;
}
case op_get_scoped_var: {
int r0 = (++it)->u.operand;
int index = (++it)->u.operand;
int skipLevels = (++it)->u.operand;
out.printf("[%4d] get_scoped_var\t %s, %d, %d", location, registerName(exec, r0).data(), index, skipLevels);
dumpValueProfiling(out, it, hasPrintedProfiling);
break;
}
case op_put_scoped_var: {
int index = (++it)->u.operand;
int skipLevels = (++it)->u.operand;
int r0 = (++it)->u.operand;
out.printf("[%4d] put_scoped_var\t %d, %d, %s", location, index, skipLevels, registerName(exec, r0).data());
break;
}
case op_init_global_const_nop: {
out.printf("[%4d] init_global_const_nop\t", location);
it++;
......@@ -1644,8 +1659,10 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
, m_argumentsRegister(other.m_argumentsRegister)
, m_activationRegister(other.m_activationRegister)
, m_isStrictMode(other.m_isStrictMode)
, m_needsActivation(other.m_needsActivation)
, m_source(other.m_source)
, m_sourceOffset(other.m_sourceOffset)
, m_codeType(other.m_codeType)
, m_identifiers(other.m_identifiers)
, m_constantRegisters(other.m_constantRegisters)
, m_functionDecls(other.m_functionDecls)
......@@ -1687,8 +1704,10 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
, m_argumentsRegister(unlinkedCodeBlock->argumentsRegister())
, m_activationRegister(unlinkedCodeBlock->activationRegister())
, m_isStrictMode(unlinkedCodeBlock->isStrictMode())
, m_needsActivation(unlinkedCodeBlock->needsFullScopeChain())
, m_source(sourceProvider)
, m_sourceOffset(sourceOffset)
, m_codeType(unlinkedCodeBlock->codeType())
, m_alternative(alternative)
, m_osrExitCounter(0)
, m_optimizationDelayCounter(0)
......@@ -1704,7 +1723,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
#endif
setIdentifiers(unlinkedCodeBlock->identifiers());
setConstantRegisters(unlinkedCodeBlock->constantRegisters());
if (unlinkedCodeBlock->usesGlobalObject())
m_constantRegisters[unlinkedCodeBlock->globalObjectRegister()].set(*m_globalData, ownerExecutable, globalObject);
m_functionDecls.grow(unlinkedCodeBlock->numberOfFunctionDecls());
for (size_t count = unlinkedCodeBlock->numberOfFunctionDecls(), i = 0; i < count; ++i) {
UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionDecl(i);
......@@ -1920,6 +1940,16 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
break;
}
case op_get_scoped_var: {
#if ENABLE(DFG_JIT)
ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand];
ASSERT(profile->m_bytecodeOffset == -1);
profile->m_bytecodeOffset = i;
instructions[i + opLength - 1] = profile;
#endif
break;
}
case op_call:
case op_call_eval: {
#if ENABLE(DFG_JIT)
......
......@@ -532,7 +532,7 @@ namespace JSC {
{
return needsFullScopeChain() && codeType() != GlobalCode;
}
bool isCaptured(int operand, InlineCallFrame* inlineCallFrame = 0) const
{
if (operandIsArgument(operand))
......@@ -1155,9 +1155,11 @@ namespace JSC {
int m_activationRegister;
bool m_isStrictMode;
bool m_needsActivation;
RefPtr<SourceProvider> m_source;
unsigned m_sourceOffset;
unsigned m_codeType;
#if ENABLE(LLINT)
SegmentedVector<LLIntCallLinkInfo, 8> m_llintCallLinkInfos;
......
......@@ -97,6 +97,9 @@ namespace JSC {
macro(op_is_function, 3) \
macro(op_in, 4) \
\
macro(op_get_scoped_var, 5) /* has value profiling */ \
macro(op_put_scoped_var, 4) \
\
macro(op_resolve, 5) /* has value profiling */ \
macro(op_resolve_global_property, 5) /* has value profiling */ \
macro(op_resolve_global_var, 5) /* has value profiling */ \
......
......@@ -47,7 +47,7 @@ const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock",
const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) };
const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) };
static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(JSGlobalData& globalData, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(JSGlobalData& globalData, JSScope* scope, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
{
RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(&globalData, source, executable->parameters(), executable->name(), executable->isInStrictContext() ? JSParseStrict : JSParseNormal, JSParseFunctionCode, error);
......@@ -62,7 +62,7 @@ static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(JSGlobalData& global
executable->recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&globalData, FunctionCode, ExecutableInfo(body->needsActivation(), body->usesEval(), body->isStrictMode(), kind == CodeForConstruct));
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, body.get(), result, debuggerMode, profilerMode)));
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, scope, body.get(), result, debuggerMode, profilerMode)));
error = generator->generate();
body->destroyData();
if (error.m_type != ParserError::ErrorNone)
......@@ -139,7 +139,7 @@ UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(const Ide
return executable;
}
UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData& globalData, const SourceCode& source, CodeSpecializationKind specializationKind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData& globalData, JSScope* scope, const SourceCode& source, CodeSpecializationKind specializationKind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
{
switch (specializationKind) {
case CodeForCall:
......@@ -152,7 +152,7 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData
break;
}
UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(globalData, this, source, specializationKind, debuggerMode, profilerMode, error);
UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(globalData, scope, this, source, specializationKind, debuggerMode, profilerMode, error);
if (error.m_type != ParserError::ErrorNone)
return 0;
......@@ -189,6 +189,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(JSGlobalData* globalData, Structure* struct
, m_numParameters(0)
, m_globalData(globalData)
, m_argumentsRegister(-1)
, m_globalObjectRegister(-1)
, m_needsFullScopeChain(info.m_needsActivation)
, m_usesEval(info.m_usesEval)
, m_isNumericCompareFunction(false)
......
......@@ -49,6 +49,7 @@ class Debugger;
class FunctionBodyNode;
class FunctionExecutable;
class FunctionParameters;
class JSScope;
struct ParserError;
class ScriptExecutable;
class SourceCode;
......@@ -107,7 +108,7 @@ public:
String paramString() const;
UnlinkedFunctionCodeBlock* codeBlockFor(JSGlobalData&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&);
UnlinkedFunctionCodeBlock* codeBlockFor(JSGlobalData&, JSScope*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&);
static UnlinkedFunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
......@@ -268,6 +269,11 @@ public:
bool usesArguments() const { return m_argumentsRegister != -1; }
int argumentsRegister() const { return m_argumentsRegister; }
bool usesGlobalObject() const { return m_globalObjectRegister != -1; }
void setGlobalObjectRegister(int globalObjectRegister) { m_globalObjectRegister = globalObjectRegister; }
int globalObjectRegister() const { return m_globalObjectRegister; }
// Parameter information
void setNumParameters(int newValue) { m_numParameters = newValue; }
void addParameter() { m_numParameters++; }
......@@ -493,6 +499,7 @@ private:
int m_thisRegister;
int m_argumentsRegister;
int m_activationRegister;
int m_globalObjectRegister;
bool m_needsFullScopeChain : 1;
bool m_usesEval : 1;
......
......@@ -141,6 +141,10 @@ void ResolveResult::checkValidity()
case Dynamic:
ASSERT(!m_local);
return;
case Lexical:
case ReadOnlyLexical:
ASSERT(!m_local);
return;
default:
RELEASE_ASSERT_NOT_REACHED();
}
......@@ -226,7 +230,7 @@ void BytecodeGenerator::preserveLastVar()
m_lastVar = &m_calleeRegisters.last();
}
BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, JSScope*, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
: m_shouldEmitDebugHooks(debuggerMode == DebuggerOn)
, m_shouldEmitProfileHooks(profilerMode == ProfilerOn)
, m_symbolTable(0)
......@@ -234,6 +238,7 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog
, m_codeBlock(globalData, codeBlock)
, m_thisRegister(CallFrame::thisArgumentOffset())
, m_emptyValueRegister(0)
, m_globalObjectRegister(0)
, m_finallyDepth(0)
, m_dynamicScopeDepth(0)
, m_codeType(GlobalCode)
......@@ -273,14 +278,16 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog
}
BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, JSScope* scope, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
: m_shouldEmitDebugHooks(debuggerMode == DebuggerOn)
, m_shouldEmitProfileHooks(profilerMode == ProfilerOn)
, m_symbolTable(codeBlock->symbolTable())
, m_scopeNode(functionBody)
, m_scope(globalData, scope)
, m_codeBlock(globalData, codeBlock)
, m_activationRegister(0)
, m_emptyValueRegister(0)
, m_globalObjectRegister(0)
, m_finallyDepth(0)
, m_dynamicScopeDepth(0)
, m_codeType(FunctionCode)
......@@ -468,14 +475,16 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode*
}
}
BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, JSScope* scope, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
: m_shouldEmitDebugHooks(debuggerMode == DebuggerOn)
, m_shouldEmitProfileHooks(profilerMode == ProfilerOn)
, m_symbolTable(codeBlock->symbolTable())
, m_scopeNode(evalNode)
, m_scope(globalData, scope)
, m_codeBlock(globalData, codeBlock)
, m_thisRegister(CallFrame::thisArgumentOffset())
, m_emptyValueRegister(0)
, m_globalObjectRegister(0)
, m_finallyDepth(0)
, m_dynamicScopeDepth(0)
, m_codeType(EvalCode)
......@@ -1227,6 +1236,21 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v)
return constantID;
}
RegisterID* BytecodeGenerator::emitLoadGlobalObject(RegisterID* dst)
{
if (!m_globalObjectRegister) {
int index = m_nextConstantOffset;
m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
++m_nextConstantOffset;
m_codeBlock->addConstant(JSValue());
m_globalObjectRegister = &m_constantPoolRegisters[index];
m_codeBlock->setGlobalObjectRegister(index);
}
if (dst)
emitMove(dst, m_globalObjectRegister);
return m_globalObjectRegister;
}
ResolveResult BytecodeGenerator::resolve(const Identifier& property)
{
if (property == propertyNames().thisIdentifier)
......@@ -1243,13 +1267,51 @@ 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();
if (!m_scope || m_codeType != FunctionCode)
return ResolveResult::dynamicResolve();
ScopeChainIterator iter = m_scope->begin();
ScopeChainIterator end = m_scope->end();
size_t depth = m_codeBlock->needsFullScopeChain();
unsigned flags = 0;
for (; iter != end; ++iter, ++depth) {
JSObject* currentScope = iter.get();
if (!currentScope->isVariableObject())
return ResolveResult::dynamicResolve();
JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope);
SymbolTableEntry entry = currentVariableObject->symbolTable()->get(property.impl());
// Found the property
if (!entry.isNull()) {
if (entry.isReadOnly())
flags |= ResolveResult::ReadOnlyFlag;
if (++iter == end)
return ResolveResult::dynamicResolve();
#if !ASSERT_DISABLED
if (JSActivation* activation = jsDynamicCast<JSActivation*>(currentVariableObject))
ASSERT(activation->isValid(entry));
#endif
return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags);
}
bool scopeRequiresDynamicChecks = false;
if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks))
break;
if (scopeRequiresDynamicChecks)
flags |= ResolveResult::DynamicFlag;
}
return ResolveResult::dynamicResolve();
}
ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property)
{
// Register-allocated const declarations.
if (m_codeType != EvalCode && m_codeType != GlobalCode && m_symbolTable) {
if (m_codeType == FunctionCode && m_symbolTable) {
SymbolTableEntry entry = symbolTable().get(property.impl());
if (!entry.isNull()) {
unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0;
......@@ -1288,8 +1350,8 @@ bool BytecodeGenerator::shouldAvoidResolveGlobal()
RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
{
if (resolveResult.isRegister())
return emitGetLocalVar(dst, resolveResult, property);
if (resolveResult.isStatic())
return emitGetStaticVar(dst, resolveResult, property);
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve);
instructions().append(kill(dst));
......@@ -1301,7 +1363,11 @@ RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult&
RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
{
ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
if (!resolveResult.isDynamic()) {
// Global object is the base
return emitLoadGlobalObject(dst);
}
// We can't optimise at all :-(
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_base);
instructions().append(kill(dst));
......@@ -1313,9 +1379,8 @@ RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveRes
return dst;
}
RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier)
RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo& verifier)
{
ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
// We can't optimise at all :-(
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_base);
instructions().append(kill(dst));
......@@ -1331,7 +1396,7 @@ RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Reso
RegisterID* BytecodeGenerator::emitResolveWithBaseForPut(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier)
{
ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
ASSERT_UNUSED(resolveResult, !resolveResult.isStatic());
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_with_base);
instructions().append(kill(baseDst));
instructions().append(propDst->index());
......@@ -1346,9 +1411,9 @@ RegisterID* BytecodeGenerator::emitResolveWithBaseForPut(RegisterID* baseDst, Re
RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property)
{
if (resolveResult.isRegister()) {
if (resolveResult.isStatic()) {
emitLoad(baseDst, jsUndefined());
emitGetLocalVar(propDst, resolveResult, property);
emitGetStaticVar(propDst, resolveResult, property);
return baseDst;
}
......@@ -1361,8 +1426,9 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register
return baseDst;
}
RegisterID* BytecodeGenerator::emitGetLocalVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier&)
RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier&)
{
ASSERT(m_codeType == FunctionCode);
switch (resolveResult.type()) {
case ResolveResult::Register:
case ResolveResult::ReadOnlyRegister:
......@@ -1370,6 +1436,16 @@ RegisterID* BytecodeGenerator::emitGetLocalVar(RegisterID* dst, const ResolveRes
return 0;
return moveToDestinationIfNeeded(dst, resolveResult.local());
case ResolveResult::Lexical:
case ResolveResult::ReadOnlyLexical: {
UnlinkedValueProfile profile = emitProfiledOpcode(op_get_scoped_var);
instructions().append(dst->index());
instructions().append(resolveResult.index());
instructions().append(resolveResult.depth());
instructions().append(profile);
return dst;
}
default:
RELEASE_ASSERT_NOT_REACHED();
return 0;
......@@ -1387,6 +1463,28 @@ RegisterID* BytecodeGenerator::emitInitGlobalConst(const Identifier& identifier,
return value;
}
RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, const Identifier&, RegisterID* value)
{
ASSERT(m_codeType == FunctionCode);
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;
default:
RELEASE_ASSERT_NOT_REACHED();
return 0;
}
}
RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
{
m_codeBlock->addPropertyAccessInstruction(instructions().size());
......
......@@ -128,14 +128,22 @@ namespace JSC {
DynamicFlag = 0x2,
// The resolved binding is immutable.
ReadOnlyFlag = 0x4,
// The property has a static location
StaticFlag = 0x8,
// Entry at scope distance "m_depth" and located at "m_index"
ScopedFlag = 0x10
};
enum Type {
// The property is local, and stored in a register.
Register = RegisterFlag,
Register = RegisterFlag | StaticFlag,
// A read-only local, created by "const".
ReadOnlyRegister = RegisterFlag | ReadOnlyFlag,
// Any form of non-local lookup
ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag,
// Lexically fixed location in the scope chain
Lexical = ScopedFlag | StaticFlag,
// A read-only Lexical, created by "const".
ReadOnlyLexical = ScopedFlag | ReadOnlyFlag | StaticFlag,
// Any other form of lookup
Dynamic = DynamicFlag,
};
......@@ -147,6 +155,12 @@ namespace JSC {
{
return ResolveResult(Dynamic, 0);
}
static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags)
{
if (flags & DynamicFlag)
return dynamicResolve();
return ResolveResult(Lexical | flags, index, depth);
}
unsigned type() const { return m_type; }
// Returns the register corresponding to a local variable, or 0 if no
......@@ -155,13 +169,30 @@ namespace JSC {
RegisterID* local() const { return m_local; }
bool isRegister() const { return m_type & RegisterFlag; }
bool isStatic() const { return (m_type & StaticFlag) && !isDynamic(); }
bool isDynamic() const { return m_type & DynamicFlag; }
bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); }
unsigned depth() const { ASSERT(isStatic()); return m_depth; }
int32_t index() const { ASSERT(isStatic()); return m_index; }
private:
ResolveResult(unsigned type, RegisterID* local)
: m_type(type)
, m_local(local)
, m_index(0)
, m_depth(0)
{
#ifndef NDEBUG
checkValidity();
#endif
}
ResolveResult(unsigned type, int index, unsigned depth)
: m_type(type)
, m_local(0)
, m_index(index)
, m_depth(depth)
{
#ifndef NDEBUG
checkValidity();
......@@ -174,6 +205,8 @@ namespace JSC {
unsigned m_type;
RegisterID* m_local; // Local register, if RegisterFlag is set
int m_index;
unsigned m_depth;
};
struct NonlocalResolveInfo {
......@@ -211,9 +244,9 @@ namespace JSC {
typedef <