Bytecode should not have responsibility for determining how to perform non-local resolves
https://bugs.webkit.org/show_bug.cgi?id=99349

Reviewed by Gavin Barraclough.

This patch removes lexical analysis from the bytecode generation.  This allows
us to delay lookup of a non-local variables until the lookup is actually necessary,
and simplifies a lot of the resolve logic in BytecodeGenerator.

Once a lookup is performed we cache the lookup information in a set of out-of-line
buffers in CodeBlock.  This allows subsequent lookups to avoid unnecessary hashing,
etc, and allows the respective JITs to recreated optimal lookup code.

This is currently still a performance regression in LLInt, but most of the remaining
regression is caused by a lot of indirection that I'll remove in future work, as well
as some work necessary to allow LLInt to perform in line instruction repatching.
We will also want to improve the behaviour of the baseline JIT for some of the lookup
operations, however this patch was getting quite large already so I'm landing it now
that we've reached the bar of "performance-neutral".

Basic browsing seems to work.

* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printStructures):
(JSC::CodeBlock::dump):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::visitStructures):
(JSC):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::shrinkToFit):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::addResolve):
(JSC::CodeBlock::addPutToBase):
(CodeBlock):
(JSC::CodeBlock::resolveOperations):
(JSC::CodeBlock::putToBaseOperation):
(JSC::CodeBlock::numberOfResolveOperations):
(JSC::CodeBlock::numberOfPutToBaseOperations):
(JSC::CodeBlock::addPropertyAccessInstruction):
(JSC::CodeBlock::globalObjectConstant):
(JSC::CodeBlock::setGlobalObjectConstant):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecode/ResolveGlobalStatus.cpp:
(JSC::computeForStructure):
(JSC::ResolveGlobalStatus::computeFor):
* bytecode/ResolveGlobalStatus.h:
(JSC):
(ResolveGlobalStatus):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::ResolveResult::checkValidity):
(JSC):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::resolve):
(JSC::BytecodeGenerator::resolveConstDecl):
(JSC::BytecodeGenerator::shouldAvoidResolveGlobal):
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveBase):
(JSC::BytecodeGenerator::emitResolveBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithThis):
(JSC::BytecodeGenerator::emitGetLocalVar):
(JSC::BytecodeGenerator::emitInitGlobalConst):
(JSC::BytecodeGenerator::emitPutToBase):
* bytecompiler/BytecodeGenerator.h:
(JSC::ResolveResult::registerResolve):
(JSC::ResolveResult::dynamicResolve):
(ResolveResult):
(JSC::ResolveResult::ResolveResult):
(JSC):
(NonlocalResolveInfo):
(JSC::NonlocalResolveInfo::NonlocalResolveInfo):
(JSC::NonlocalResolveInfo::~NonlocalResolveInfo):
(JSC::NonlocalResolveInfo::resolved):
(JSC::NonlocalResolveInfo::put):
(BytecodeGenerator):
(JSC::BytecodeGenerator::getResolveOperations):
(JSC::BytecodeGenerator::getResolveWithThisOperations):
(JSC::BytecodeGenerator::getResolveBaseOperations):
(JSC::BytecodeGenerator::getResolveBaseForPutOperations):
(JSC::BytecodeGenerator::getResolveWithBaseForPutOperations):
(JSC::BytecodeGenerator::getPutToBaseOperation):
* bytecompiler/NodesCodegen.cpp:
(JSC::ResolveNode::isPure):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
(JSC::ForInNode::emitBytecode):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(ByteCodeParser):
(InlineStackEntry):
(JSC::DFG::ByteCodeParser::handleGetByOffset):
(DFG):
(JSC::DFG::ByteCodeParser::parseResolveOperations):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGCapabilities.h:
(JSC::DFG::canInlineResolveOperations):
(DFG):
(JSC::DFG::canCompileOpcode):
(JSC::DFG::canInlineOpcode):
* dfg/DFGGraph.h:
(ResolveGlobalData):
(ResolveOperationData):
(DFG):
(PutToBaseOperationData):
(Graph):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasIdentifier):
(JSC::DFG::Node::resolveOperationsDataIndex):
(Node):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOSRExit.cpp:
(JSC::DFG::OSRExit::OSRExit):
* dfg/DFGOSRExit.h:
(OSRExit):
* dfg/DFGOSRExitCompiler.cpp:
* dfg/DFGOSRExitCompiler32_64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGOSRExitCompiler64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryCacheGetByID):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::convertLastOSRExitToForward):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::resolveOperations):
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::putToBaseOperation):
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureCheckHoistingPhase.cpp:
(JSC::DFG::StructureCheckHoistingPhase::run):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
(JIT):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_put_to_base):
(JSC):
(JSC::JIT::emit_resolve_operations):
(JSC::JIT::emitSlow_link_resolve_operations):
(JSC::JIT::emit_op_resolve):
(JSC::JIT::emitSlow_op_resolve):
(JSC::JIT::emit_op_resolve_base):
(JSC::JIT::emitSlow_op_resolve_base):
(JSC::JIT::emit_op_resolve_with_base):
(JSC::JIT::emitSlow_op_resolve_with_base):
(JSC::JIT::emit_op_resolve_with_this):
(JSC::JIT::emitSlow_op_resolve_with_this):
(JSC::JIT::emitSlow_op_put_to_base):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_put_to_base):
(JSC):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_init_global_const):
(JSC::JIT::emit_op_init_global_const_check):
(JSC::JIT::emitSlow_op_init_global_const_check):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_init_global_const):
(JSC::JIT::emit_op_init_global_const_check):
(JSC::JIT::emitSlow_op_init_global_const_check):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
(JSC):
* jit/JITStubs.h:
* llint/LLIntSlowPaths.cpp:
(LLInt):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
(LLInt):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/JSScope.cpp:
(JSC::LookupResult::base):
(JSC::LookupResult::value):
(JSC::LookupResult::setBase):
(JSC::LookupResult::setValue):
(LookupResult):
(JSC):
(JSC::setPutPropertyAccessOffset):
(JSC::executeResolveOperations):
(JSC::JSScope::resolveContainingScopeInternal):
(JSC::JSScope::resolveContainingScope):
(JSC::JSScope::resolve):
(JSC::JSScope::resolveBase):
(JSC::JSScope::resolveWithBase):
(JSC::JSScope::resolveWithThis):
(JSC::JSScope::resolvePut):
(JSC::JSScope::resolveGlobal):
* runtime/JSScope.h:
(JSScope):
* runtime/JSVariableObject.cpp:
(JSC):
* runtime/JSVariableObject.h:
(JSVariableObject):
* runtime/Structure.h:
(JSC::Structure::propertyAccessesAreCacheable):
(Structure):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@131822 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 10a873d..6881195 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -141,7 +141,7 @@
 
 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 @@
         return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
     }
 
-    if (resolveResult.isStatic()) {
-        RefPtr<RegisterID> func = generator.newTemporary();
-        CallArguments callArguments(generator, m_args);
-        generator.emitGetStaticVar(func.get(), resolveResult, m_ident);
-        generator.emitLoad(callArguments.thisRegister(), jsUndefined());
-        return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset());
-    }
-
     RefPtr<RegisterID> func = generator.newTemporary();
     CallArguments callArguments(generator, m_args);
     int identifierStart = divot() - startOffset();
@@ -631,29 +623,18 @@
             return emitPreIncOrDec(generator, local, m_operator);
         return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator);
     }
-
-    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
-        RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, ident);
-        RegisterID* oldValue;
-        if (dst == generator.ignoredResult()) {
-            oldValue = 0;
-            emitPreIncOrDec(generator, value.get(), m_operator);
-        } else
-            oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
-        generator.emitPutStaticVar(resolveResult, ident, value.get());
-        return oldValue;
-    }
     
     generator.emitExpressionInfo(divot(), startOffset(), endOffset());
     RefPtr<RegisterID> value = generator.newTemporary();
-    RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, ident);
+    NonlocalResolveInfo resolveInfo;
+    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), value.get(), resolveResult, ident, resolveInfo);
     RegisterID* oldValue;
     if (dst == generator.ignoredResult()) {
         oldValue = 0;
         emitPreIncOrDec(generator, value.get(), m_operator);
     } else
         oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
-    generator.emitPutById(base.get(), ident, value.get());
+    generator.emitPutToBase(base.get(), ident, value.get(), resolveInfo);
     return oldValue;
 }
 
@@ -828,18 +809,12 @@
         return generator.moveToDestinationIfNeeded(dst, local);
     }
 
-    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
-        RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, ident);
-        emitPreIncOrDec(generator, propDst.get(), m_operator);
-        generator.emitPutStaticVar(resolveResult, ident, propDst.get());
-        return generator.moveToDestinationIfNeeded(dst, propDst.get());
-    }
-
     generator.emitExpressionInfo(divot(), startOffset(), endOffset());
     RefPtr<RegisterID> propDst = generator.tempDestination(dst);
-    RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, ident);
+    NonlocalResolveInfo resolveVerifier;
+    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), propDst.get(), resolveResult, ident, resolveVerifier);
     emitPreIncOrDec(generator, propDst.get(), m_operator);
-    generator.emitPutById(base.get(), ident, propDst.get());
+    generator.emitPutToBase(base.get(), ident, propDst.get(), resolveVerifier);
     return generator.moveToDestinationIfNeeded(dst, propDst.get());
 }
 
@@ -1265,18 +1240,12 @@
         return generator.moveToDestinationIfNeeded(dst, result);
     }
 
-    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
-        RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
-        RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
-        generator.emitPutStaticVar(resolveResult, m_ident, result);
-        return result;
-    }
-
     RefPtr<RegisterID> src1 = generator.tempDestination(dst);
     generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0);
-    RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), resolveResult, m_ident);
+    NonlocalResolveInfo resolveVerifier;
+    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), src1.get(), resolveResult, m_ident, resolveVerifier);
     RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
-    return generator.emitPutById(base.get(), m_ident, result);
+    return generator.emitPutToBase(base.get(), m_ident, result, resolveVerifier);
 }
 
 // ------------------------------ AssignResolveNode -----------------------------------
@@ -1285,7 +1254,7 @@
 {
     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 @@
         return generator.moveToDestinationIfNeeded(dst, result);
     }
 
-    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
-        if (dst == generator.ignoredResult())
-            dst = 0;
-        RegisterID* value = generator.emitNode(dst, m_right);
-        generator.emitPutStaticVar(resolveResult, m_ident, value);
-        return value;
-    }
-
-    RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident);
+    NonlocalResolveInfo resolveVerifier;
+    RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident, resolveVerifier);
     if (dst == generator.ignoredResult())
         dst = 0;
     RegisterID* value = generator.emitNode(dst, m_right);
     generator.emitExpressionInfo(divot(), startOffset(), endOffset());
-    return generator.emitPutById(base.get(), m_ident, value);
+    return generator.emitPutToBase(base.get(), m_ident, value, resolveVerifier);
 }
 
 // ------------------------------ AssignDotNode -----------------------------------
@@ -1402,16 +1364,14 @@
 
     RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined());
 
-    if (resolveResult.isStatic()) {
-        if (generator.codeType() == GlobalCode)
-            return generator.emitInitGlobalConst(resolveResult, m_ident, value.get());
-        return generator.emitPutStaticVar(resolveResult, m_ident, value.get());
+    if (generator.codeType() == GlobalCode) {
+        if (RegisterID* result = generator.emitInitGlobalConst(m_ident, value.get()))
+            return result;
     }
     if (generator.codeType() != EvalCode)
         return value.get();
 
-    // FIXME: While this code should only be hit in an eval block, it will assign
-    // to the wrong base if m_ident exists in an intervening with scope.
+    // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope.
     RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), resolveResult, m_ident);
     return generator.emitPutById(base.get(), m_ident, value.get());
 }
@@ -1699,10 +1659,11 @@
         if (!propertyName) {
             propertyName = generator.newTemporary();
             RefPtr<RegisterID> protect = propertyName;
-            RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident);
+            NonlocalResolveInfo resolveVerifier;
+            RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident, resolveVerifier);
 
             generator.emitExpressionInfo(divot(), startOffset(), endOffset());
-            generator.emitPutById(base, ident, propertyName);
+            generator.emitPutToBase(base, ident, propertyName, resolveVerifier);
         } else {
             expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
             generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);