Bytecode should not have responsibility for determining how to perform non-local...
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Oct 2012 23:37:40 +0000 (23:37 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Oct 2012 23:37:40 +0000 (23:37 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@131822 268f45cc-cd09-0410-ab3c-d52691b4dbfc

49 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/Opcode.h
Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp
Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractState.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.h
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOSRExit.cpp
Source/JavaScriptCore/dfg/DFGOSRExit.h
Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGRepatch.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/jit/JITStubs.h
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/JSScope.cpp
Source/JavaScriptCore/runtime/JSScope.h
Source/JavaScriptCore/runtime/JSVariableObject.cpp
Source/JavaScriptCore/runtime/JSVariableObject.h
Source/JavaScriptCore/runtime/Structure.h

index c2c3da0..8314ecf 100644 (file)
-2012-10-18  Mark Hahnenberg  <mhahnenberg@apple.com>
-
-        Live oversize copied blocks should count toward overall heap fragmentation
-        https://bugs.webkit.org/show_bug.cgi?id=99548
-
-        Reviewed by Filip Pizlo.
-
-        The CopiedSpace uses overall heap fragmentation to determine whether or not it should do any copying. 
-        Currently it doesn't include live oversize CopiedBlocks in the calculation, but it should. We should 
-        treat them as 100% utilized, since running a copying phase won't be able to free/compact any of their 
-        memory. We can also free any dead oversize CopiedBlocks while we're iterating over them, rather than 
-        iterating over them again at the end of the copying phase.
-
-        * heap/CopiedSpace.cpp:
-        (JSC::CopiedSpace::doneFillingBlock):
-        (JSC::CopiedSpace::startedCopying):
-        (JSC::CopiedSpace::doneCopying): Also removed a branch when iterating over from-space at the end of 
-        copying. Since we eagerly recycle blocks as soon as they're fully evacuated, we should see no
-        unpinned blocks in from-space at the end of copying.
-        * heap/CopiedSpaceInlineMethods.h:
-        (JSC::CopiedSpace::recycleBorrowedBlock):
-        * heap/CopyVisitorInlineMethods.h:
-        (JSC::CopyVisitor::checkIfShouldCopy):
-
-2012-10-18  Roger Fong  <roger_fong@apple.com>
-
-        Unreviewed. Build fix after r131701 and r131777.
-
-        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
-
-2012-10-18  Mark Hahnenberg  <mhahnenberg@apple.com>
-
-        Race condition between GCThread and main thread during copying phase
-        https://bugs.webkit.org/show_bug.cgi?id=99641
-
-        Reviewed by Filip Pizlo.
-
-        When a GCThread returns from copyFromShared(), it then calls doneCopying(), which returns 
-        its borrowed CopiedBlock to the CopiedSpace. This final block allows the CopiedSpace to 
-        continue and finish the cleanup of the copying phase. However, the GCThread can loop back 
-        around, see that m_currentPhase is still "Copy", and try to go through the copying phase again. 
-        This can cause all sorts of issues. To fix this, we should add a cyclic barrier to GCThread::waitForNextPhase().
-
-        * heap/GCThread.cpp:
-        (JSC::GCThread::waitForNextPhase): All GCThreads will wait when they finish one iteration until the main thread 
-        notifies them to move down to the second while loop, where they wait for the next GCPhase to start. They also 
-        decrement the m_numberOfActiveGCThreads counter as they begin to wait for the next phase and increment it as 
-        they enter the next phase. This allows the main thread to wait in endCurrentPhase() until all the threads have 
-        finished the current phase and are waiting on the next phase to begin. Without the counter, there would be 
-        no way to ensure that every thread was available for each GCPhase.
-        (JSC::GCThread::gcThreadMain): We now use the m_phaseLock to synchronize with the main thread when we're being created.
-        * heap/GCThreadSharedData.cpp:
-        (JSC::GCThreadSharedData::GCThreadSharedData): As we create each GCThread, we increment the m_numberOfActiveGCThreads
-        counter. When we are done creating the threads, we wait until they're all waiting for the next GCPhase. This prevents 
-        us from leaving some GCThreads behind during the first GCPhase, which could hurt us on our very short-running 
-        benchmarks (e.g. SunSpider).
-        (JSC::GCThreadSharedData::~GCThreadSharedData):
-        (JSC::GCThreadSharedData::startNextPhase): We atomically swap the two flags, m_gcThreadsShouldWait and m_currentPhase, 
-        so that if the threads finish very quickly, they will wait until the main thread is ready to end the current phase.
-        (JSC::GCThreadSharedData::endCurrentPhase): Here atomically we swap the two flags again to allow the threads to 
-        advance to waiting on the next GCPhase. We wait until all of the GCThreads have settled into the second wait loop
-        before allowing the main thread to continue. This prevents us from leaving one of the GCThreads stuck in the first 
-        wait loop if we were to call startNextPhase() before it had time to wake up and move on to the second wait loop.
-        (JSC):
-        (JSC::GCThreadSharedData::didStartMarking): We now use startNextPhase() to properly swap the flags.
-        (JSC::GCThreadSharedData::didFinishMarking): Ditto for endCurrentPhase().
-        (JSC::GCThreadSharedData::didStartCopying): Ditto.
-        (JSC::GCThreadSharedData::didFinishCopying): Ditto.
-        * heap/GCThreadSharedData.h:
-        (GCThreadSharedData):
-        * heap/Heap.cpp: 
-        (JSC::Heap::copyBackingStores): No reason to use the extra reference.
-
-2012-10-18  Pablo Flouret  <pablof@motorola.com>
-
-        Implement css3-conditional's @supports rule
-        https://bugs.webkit.org/show_bug.cgi?id=86146
-
-        Reviewed by Antti Koivisto.
-
-        * Configurations/FeatureDefines.xcconfig:
-            Add an ENABLE_CSS3_CONDITIONAL_RULES flag.
-
-2012-10-18  Michael Saboff  <msaboff@apple.com>
-
-        Make conversion between JSStringRef and WKStringRef work without character size conversions
-        https://bugs.webkit.org/show_bug.cgi?id=99727
-
-        Reviewed by Anders Carlsson.
-
-        Export the string() method for use in WebKit.
-
-        * API/OpaqueJSString.h:
-        (OpaqueJSString::string):
-
-2012-10-18  Raphael Kubo da Costa  <raphael.kubo.da.costa@intel.com>
-
-        [CMake] Avoid unnecessarily running the LLInt generation commands.
-        https://bugs.webkit.org/show_bug.cgi?id=99708
-
-        Reviewed by Rob Buis.
+2012-10-18  Oliver Hunt  <oliver@apple.com>
 
-        As described in the comments in the change itself, in some cases
-        the Ruby generation scripts used when LLInt is on would each be
-        run twice in every build even if nothing had changed.
-
-        Fix that by not setting the OBJECT_DEPENDS property of some source
-        files to depend on the generated headers; instead, they are now
-        just part of the final binaries/libraries which use them.
-
-        * CMakeLists.txt:
-
-2012-10-17  Zoltan Horvath  <zoltan@webkit.org>
-
-        Remove the JSHeap memory measurement of the PageLoad performacetests since it creates bogus JSGlobalDatas
-        https://bugs.webkit.org/show_bug.cgi?id=99609 
-
-        Reviewed by Ryosuke Niwa.
-
-        Remove the implementation since it creates bogus JSGlobalDatas in the layout tests.
+        Bytecode should not have responsibility for determining how to perform non-local resolves
+        https://bugs.webkit.org/show_bug.cgi?id=99349
 
-        * heap/HeapStatistics.cpp:
-        (JSC):
-        * heap/HeapStatistics.h:
-        (HeapStatistics):
+        Reviewed by Gavin Barraclough.
 
-2012-10-17  Sam Weinig  <sam@webkit.org>
+        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.
 
-        Attempt to fix the build.
+        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.
 
-        * bytecode/GlobalResolveInfo.h: Copied from bytecode/GlobalResolveInfo.h.
+        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".
 
-2012-10-17  Oliver Hunt  <oliver@apple.com>
+        Basic browsing seems to work.
 
-        Roll out r131645 as it causes random site crashes.
-        
         * GNUmakefile.list.am:
         * JavaScriptCore.xcodeproj/project.pbxproj:
         * bytecode/CodeBlock.cpp:
-        (JSC):
-        (JSC::isGlobalResolve):
-        (JSC::instructionOffsetForNth):
-        (JSC::printGlobalResolveInfo):
         (JSC::CodeBlock::printStructures):
         (JSC::CodeBlock::dump):
         (JSC::CodeBlock::CodeBlock):
         (JSC::CodeBlock::visitStructures):
+        (JSC):
         (JSC::CodeBlock::finalizeUnconditionally):
-        (JSC::CodeBlock::hasGlobalResolveInfoAtBytecodeOffset):
-        (JSC::CodeBlock::globalResolveInfoForBytecodeOffset):
         (JSC::CodeBlock::shrinkToFit):
         * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::addResolve):
+        (JSC::CodeBlock::addPutToBase):
         (CodeBlock):
-        (JSC::CodeBlock::addGlobalResolveInstruction):
-        (JSC::CodeBlock::addGlobalResolveInfo):
-        (JSC::CodeBlock::globalResolveInfo):
-        (JSC::CodeBlock::numberOfGlobalResolveInfos):
-        (JSC::CodeBlock::globalResolveInfoCount):
+        (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):
         (JSC::computeForStructure):
-        (JSC::computeForLLInt):
         (JSC::ResolveGlobalStatus::computeFor):
         * bytecode/ResolveGlobalStatus.h:
         (JSC):
         (ResolveGlobalStatus):
         * bytecompiler/BytecodeGenerator.cpp:
         (JSC::ResolveResult::checkValidity):
-        (JSC::ResolveResult::registerPointer):
         (JSC):
         (JSC::BytecodeGenerator::BytecodeGenerator):
         (JSC::BytecodeGenerator::resolve):
         (JSC::BytecodeGenerator::emitResolve):
         (JSC::BytecodeGenerator::emitResolveBase):
         (JSC::BytecodeGenerator::emitResolveBaseForPut):
-        (JSC::BytecodeGenerator::emitResolveWithBase):
+        (JSC::BytecodeGenerator::emitResolveWithBaseForPut):
         (JSC::BytecodeGenerator::emitResolveWithThis):
-        (JSC::BytecodeGenerator::emitGetStaticVar):
+        (JSC::BytecodeGenerator::emitGetLocalVar):
         (JSC::BytecodeGenerator::emitInitGlobalConst):
-        (JSC::BytecodeGenerator::emitPutStaticVar):
+        (JSC::BytecodeGenerator::emitPutToBase):
         * bytecompiler/BytecodeGenerator.h:
         (JSC::ResolveResult::registerResolve):
         (JSC::ResolveResult::dynamicResolve):
-        (JSC::ResolveResult::lexicalResolve):
-        (JSC::ResolveResult::indexedGlobalResolve):
-        (JSC::ResolveResult::dynamicIndexedGlobalResolve):
-        (JSC::ResolveResult::globalResolve):
-        (JSC::ResolveResult::dynamicGlobalResolve):
-        (JSC::ResolveResult::type):
-        (JSC::ResolveResult::index):
-        (JSC::ResolveResult::depth):
-        (JSC::ResolveResult::globalObject):
         (ResolveResult):
-        (JSC::ResolveResult::isStatic):
-        (JSC::ResolveResult::isIndexed):
-        (JSC::ResolveResult::isScoped):
-        (JSC::ResolveResult::isGlobal):
         (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):
         (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::OSRExitCompiler::compileExit):
         * dfg/DFGOperations.cpp:
         * dfg/DFGOperations.h:
-        (JSC):
         * dfg/DFGPredictionPropagationPhase.cpp:
         (JSC::DFG::PredictionPropagationPhase::propagate):
         * dfg/DFGRepatch.cpp:
         * 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):
         (JSC::JIT::privateCompileSlowCases):
         * jit/JIT.h:
         (JIT):
-        (JSC::JIT::emit_op_get_global_var_watchable):
         * jit/JITOpcodes.cpp:
-        (JSC::JIT::emit_op_resolve):
+        (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::emit_op_resolve_skip):
-        (JSC::JIT::emit_op_resolve_global):
-        (JSC::JIT::emitSlow_op_resolve_global):
+        (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::emit_op_resolve_global_dynamic):
-        (JSC::JIT::emitSlow_op_resolve_global_dynamic):
+        (JSC::JIT::emitSlow_op_resolve_with_this):
+        (JSC::JIT::emitSlow_op_put_to_base):
         * jit/JITOpcodes32_64.cpp:
-        (JSC::JIT::emit_op_resolve):
+        (JSC::JIT::emit_op_put_to_base):
         (JSC):
-        (JSC::JIT::emit_op_resolve_base):
-        (JSC::JIT::emit_op_resolve_skip):
-        (JSC::JIT::emit_op_resolve_global):
-        (JSC::JIT::emitSlow_op_resolve_global):
-        (JSC::JIT::emit_op_resolve_with_base):
-        (JSC::JIT::emit_op_resolve_with_this):
         * jit/JITPropertyAccess.cpp:
-        (JSC::JIT::emit_op_get_scoped_var):
-        (JSC):
-        (JSC::JIT::emit_op_put_scoped_var):
-        (JSC::JIT::emit_op_get_global_var):
-        (JSC::JIT::emit_op_put_global_var):
-        (JSC::JIT::emit_op_put_global_var_check):
-        (JSC::JIT::emitSlow_op_put_global_var_check):
+        (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_get_scoped_var):
-        (JSC):
-        (JSC::JIT::emit_op_put_scoped_var):
-        (JSC::JIT::emit_op_get_global_var):
-        (JSC::JIT::emit_op_put_global_var):
-        (JSC::JIT::emit_op_put_global_var_check):
-        (JSC::JIT::emitSlow_op_put_global_var_check):
+        (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):
         * 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::resolveSkip):
-        (JSC::JSScope::resolveGlobal):
-        (JSC::JSScope::resolveGlobalDynamic):
         (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):
+
+2012-10-18  Mark Hahnenberg  <mhahnenberg@apple.com>
+
+        Live oversize copied blocks should count toward overall heap fragmentation
+        https://bugs.webkit.org/show_bug.cgi?id=99548
+
+        Reviewed by Filip Pizlo.
+
+        The CopiedSpace uses overall heap fragmentation to determine whether or not it should do any copying. 
+        Currently it doesn't include live oversize CopiedBlocks in the calculation, but it should. We should 
+        treat them as 100% utilized, since running a copying phase won't be able to free/compact any of their 
+        memory. We can also free any dead oversize CopiedBlocks while we're iterating over them, rather than 
+        iterating over them again at the end of the copying phase.
+
+        * heap/CopiedSpace.cpp:
+        (JSC::CopiedSpace::doneFillingBlock):
+        (JSC::CopiedSpace::startedCopying):
+        (JSC::CopiedSpace::doneCopying): Also removed a branch when iterating over from-space at the end of 
+        copying. Since we eagerly recycle blocks as soon as they're fully evacuated, we should see no
+        unpinned blocks in from-space at the end of copying.
+        * heap/CopiedSpaceInlineMethods.h:
+        (JSC::CopiedSpace::recycleBorrowedBlock):
+        * heap/CopyVisitorInlineMethods.h:
+        (JSC::CopyVisitor::checkIfShouldCopy):
+
+2012-10-18  Roger Fong  <roger_fong@apple.com>
+
+        Unreviewed. Build fix after r131701 and r131777.
+
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+
+2012-10-18  Mark Hahnenberg  <mhahnenberg@apple.com>
+
+        Race condition between GCThread and main thread during copying phase
+        https://bugs.webkit.org/show_bug.cgi?id=99641
+
+        Reviewed by Filip Pizlo.
+
+        When a GCThread returns from copyFromShared(), it then calls doneCopying(), which returns 
+        its borrowed CopiedBlock to the CopiedSpace. This final block allows the CopiedSpace to 
+        continue and finish the cleanup of the copying phase. However, the GCThread can loop back 
+        around, see that m_currentPhase is still "Copy", and try to go through the copying phase again. 
+        This can cause all sorts of issues. To fix this, we should add a cyclic barrier to GCThread::waitForNextPhase().
+
+        * heap/GCThread.cpp:
+        (JSC::GCThread::waitForNextPhase): All GCThreads will wait when they finish one iteration until the main thread 
+        notifies them to move down to the second while loop, where they wait for the next GCPhase to start. They also 
+        decrement the m_numberOfActiveGCThreads counter as they begin to wait for the next phase and increment it as 
+        they enter the next phase. This allows the main thread to wait in endCurrentPhase() until all the threads have 
+        finished the current phase and are waiting on the next phase to begin. Without the counter, there would be 
+        no way to ensure that every thread was available for each GCPhase.
+        (JSC::GCThread::gcThreadMain): We now use the m_phaseLock to synchronize with the main thread when we're being created.
+        * heap/GCThreadSharedData.cpp:
+        (JSC::GCThreadSharedData::GCThreadSharedData): As we create each GCThread, we increment the m_numberOfActiveGCThreads
+        counter. When we are done creating the threads, we wait until they're all waiting for the next GCPhase. This prevents 
+        us from leaving some GCThreads behind during the first GCPhase, which could hurt us on our very short-running 
+        benchmarks (e.g. SunSpider).
+        (JSC::GCThreadSharedData::~GCThreadSharedData):
+        (JSC::GCThreadSharedData::startNextPhase): We atomically swap the two flags, m_gcThreadsShouldWait and m_currentPhase, 
+        so that if the threads finish very quickly, they will wait until the main thread is ready to end the current phase.
+        (JSC::GCThreadSharedData::endCurrentPhase): Here atomically we swap the two flags again to allow the threads to 
+        advance to waiting on the next GCPhase. We wait until all of the GCThreads have settled into the second wait loop
+        before allowing the main thread to continue. This prevents us from leaving one of the GCThreads stuck in the first 
+        wait loop if we were to call startNextPhase() before it had time to wake up and move on to the second wait loop.
+        (JSC):
+        (JSC::GCThreadSharedData::didStartMarking): We now use startNextPhase() to properly swap the flags.
+        (JSC::GCThreadSharedData::didFinishMarking): Ditto for endCurrentPhase().
+        (JSC::GCThreadSharedData::didStartCopying): Ditto.
+        (JSC::GCThreadSharedData::didFinishCopying): Ditto.
+        * heap/GCThreadSharedData.h:
+        (GCThreadSharedData):
+        * heap/Heap.cpp: 
+        (JSC::Heap::copyBackingStores): No reason to use the extra reference.
+
+2012-10-18  Pablo Flouret  <pablof@motorola.com>
+
+        Implement css3-conditional's @supports rule
+        https://bugs.webkit.org/show_bug.cgi?id=86146
+
+        Reviewed by Antti Koivisto.
+
+        * Configurations/FeatureDefines.xcconfig:
+            Add an ENABLE_CSS3_CONDITIONAL_RULES flag.
+
+2012-10-18  Michael Saboff  <msaboff@apple.com>
+
+        Make conversion between JSStringRef and WKStringRef work without character size conversions
+        https://bugs.webkit.org/show_bug.cgi?id=99727
+
+        Reviewed by Anders Carlsson.
+
+        Export the string() method for use in WebKit.
+
+        * API/OpaqueJSString.h:
+        (OpaqueJSString::string):
+
+2012-10-18  Raphael Kubo da Costa  <raphael.kubo.da.costa@intel.com>
+
+        [CMake] Avoid unnecessarily running the LLInt generation commands.
+        https://bugs.webkit.org/show_bug.cgi?id=99708
+
+        Reviewed by Rob Buis.
+
+        As described in the comments in the change itself, in some cases
+        the Ruby generation scripts used when LLInt is on would each be
+        run twice in every build even if nothing had changed.
+
+        Fix that by not setting the OBJECT_DEPENDS property of some source
+        files to depend on the generated headers; instead, they are now
+        just part of the final binaries/libraries which use them.
+
+        * CMakeLists.txt:
+
+2012-10-17  Zoltan Horvath  <zoltan@webkit.org>
+
+        Remove the JSHeap memory measurement of the PageLoad performacetests since it creates bogus JSGlobalDatas
+        https://bugs.webkit.org/show_bug.cgi?id=99609 
+
+        Reviewed by Ryosuke Niwa.
+
+        Remove the implementation since it creates bogus JSGlobalDatas in the layout tests.
+
+        * heap/HeapStatistics.cpp:
+        (JSC):
+        * heap/HeapStatistics.h:
+        (HeapStatistics):
+
+2012-10-17  Sam Weinig  <sam@webkit.org>
+
+        Attempt to fix the build.
+
+        * bytecode/GlobalResolveInfo.h: Copied from bytecode/GlobalResolveInfo.h.
 
 2012-10-17  Filip Pizlo  <fpizlo@apple.com>
 
index ae5854b..3b57427 100644 (file)
@@ -106,7 +106,6 @@ javascriptcore_sources += \
        Source/JavaScriptCore/bytecode/ExpressionRangeInfo.h \
        Source/JavaScriptCore/bytecode/GetByIdStatus.cpp \
        Source/JavaScriptCore/bytecode/GetByIdStatus.h \
-       Source/JavaScriptCore/bytecode/GlobalResolveInfo.h \
        Source/JavaScriptCore/bytecode/HandlerInfo.h \
        Source/JavaScriptCore/bytecode/Instruction.h \
        Source/JavaScriptCore/bytecode/JumpTable.cpp \
@@ -133,6 +132,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/bytecode/PutKind.h \
        Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp \
        Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h \
+       Source/JavaScriptCore/bytecode/ResolveOperation.h \
        Source/JavaScriptCore/bytecode/SamplingTool.cpp \
        Source/JavaScriptCore/bytecode/SamplingTool.h \
        Source/JavaScriptCore/bytecode/SpecialPointer.cpp \
index 28c2746..1cf109a 100644 (file)
@@ -71,7 +71,6 @@
                0F0B83B114BCF71800885B4F /* CallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83AF14BCF71400885B4F /* CallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0B83B414BCF86000885B4F /* MethodCallLinkInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0B83B214BCF85E00885B4F /* MethodCallLinkInfo.cpp */; };
                0F0B83B514BCF86200885B4F /* MethodCallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83B314BCF85E00885B4F /* MethodCallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               0F0B83B714BCF8E100885B4F /* GlobalResolveInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83B614BCF8DF00885B4F /* GlobalResolveInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0B83B914BCF95F00885B4F /* CallReturnOffsetToBytecodeOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0CD4C415F6B6BB0032F1C0 /* SparseArrayValueMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */; };
                A76F54A313B28AAB00EF2BCE /* JITWriteBarrier.h in Headers */ = {isa = PBXBuildFile; fileRef = A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */; };
                A784A26111D16622005776AC /* ASTBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */; };
                A784A26411D16622005776AC /* SyntaxChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */; };
+               A7AFC17915F7EFE30048F57B /* ResolveOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = A7AFC17715F7EFE30048F57B /* ResolveOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */; };
                A7B4ACAF1484C9CE00B38A36 /* JSExportMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A7C1E8E4112E72EF00A37F98 /* JITPropertyAccess32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7C1E8C8112E701C00A37F98 /* JITPropertyAccess32_64.cpp */; };
                0F0B83AF14BCF71400885B4F /* CallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallLinkInfo.h; sourceTree = "<group>"; };
                0F0B83B214BCF85E00885B4F /* MethodCallLinkInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MethodCallLinkInfo.cpp; sourceTree = "<group>"; };
                0F0B83B314BCF85E00885B4F /* MethodCallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodCallLinkInfo.h; sourceTree = "<group>"; };
-               0F0B83B614BCF8DF00885B4F /* GlobalResolveInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GlobalResolveInfo.h; sourceTree = "<group>"; };
                0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallReturnOffsetToBytecodeOffset.h; sourceTree = "<group>"; };
                0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutDirectIndexMode.h; sourceTree = "<group>"; };
                0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SparseArrayValueMap.cpp; sourceTree = "<group>"; };
                A79EDB0811531CD60019E912 /* JSObjectRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSObjectRefPrivate.h; sourceTree = "<group>"; };
                A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTBuilder.h; sourceTree = "<group>"; };
                A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyntaxChecker.h; sourceTree = "<group>"; };
+               A7AFC17715F7EFE30048F57B /* ResolveOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResolveOperation.h; sourceTree = "<group>"; };
                A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableAllocator.h; sourceTree = "<group>"; };
                A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableAllocator.cpp; sourceTree = "<group>"; };
                A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSExportMacros.h; sourceTree = "<group>"; };
                                0F0B83AF14BCF71400885B4F /* CallLinkInfo.h */,
                                0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */,
                                0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */,
+                               0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
+                               0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
+                               0F93329714CA7DC10085F3C6 /* MethodCallLinkStatus.cpp */,
+                               0F93329814CA7DC10085F3C6 /* MethodCallLinkStatus.h */,
+                               0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
+                               0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
+                               A7AFC17715F7EFE30048F57B /* ResolveOperation.h */,
+                               0F93329B14CA7DC10085F3C6 /* StructureSet.h */,
                                0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */,
                                969A07900ED1D3AE00F1F681 /* CodeBlock.cpp */,
                                969A07910ED1D3AE00F1F681 /* CodeBlock.h */,
                                0F0B83AA14BCF5B900885B4F /* ExpressionRangeInfo.h */,
                                0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
                                0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
-                               0F0B83B614BCF8DF00885B4F /* GlobalResolveInfo.h */,
                                0F0B83A814BCF55E00885B4F /* HandlerInfo.h */,
                                969A07930ED1D3AE00F1F681 /* Instruction.h */,
                                BCFD8C900EEB2EE700283848 /* JumpTable.cpp */,
                                0F0B83AD14BCF60400885B4F /* LineInfo.h in Headers */,
                                0F0B83B114BCF71800885B4F /* CallLinkInfo.h in Headers */,
                                0F0B83B514BCF86200885B4F /* MethodCallLinkInfo.h in Headers */,
-                               0F0B83B714BCF8E100885B4F /* GlobalResolveInfo.h in Headers */,
                                0F0B83B914BCF95F00885B4F /* CallReturnOffsetToBytecodeOffset.h in Headers */,
                                0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */,
                                0F21C26814BE5F6800ADC64B /* JITDriver.h in Headers */,
                                14874AE615EBDE4A002E3587 /* JSScope.h in Headers */,
                                FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */,
                                1442566215EDE98D0066A49B /* JSWithScope.h in Headers */,
+                               A7AFC17915F7EFE30048F57B /* ResolveOperation.h in Headers */,
                                0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */,
                                0FB7F39615ED8E4600F167B2 /* ArrayStorage.h in Headers */,
                                0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */,
index d115148..7f86186 100644 (file)
@@ -439,34 +439,6 @@ void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction
     it += 5;
 }
 
-#if ENABLE(JIT)
-static bool isGlobalResolve(OpcodeID opcodeID)
-{
-    return opcodeID == op_resolve_global || opcodeID == op_resolve_global_dynamic;
-}
-
-static unsigned instructionOffsetForNth(ExecState* exec, const RefCountedArray<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID))
-{
-    size_t i = 0;
-    while (i < instructions.size()) {
-        OpcodeID currentOpcode = exec->interpreter()->getOpcodeID(instructions[i].u.opcode);
-        if (predicate(currentOpcode)) {
-            if (!--nth)
-                return i;
-        }
-        i += opcodeLengths[currentOpcode];
-    }
-
-    ASSERT_NOT_REACHED();
-    return 0;
-}
-
-static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigned instructionOffset)
-{
-    dataLog("  [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).utf8().data());
-}
-#endif
-
 void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand)
 {
     unsigned instructionOffset = vPC - instructions().begin();
@@ -506,14 +478,6 @@ void CodeBlock::printStructures(const Instruction* vPC)
         printStructure("put_by_id_replace", vPC, 4);
         return;
     }
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
-        printStructure("resolve_global", vPC, 4);
-        return;
-    }
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global_dynamic)) {
-        printStructure("resolve_global_dynamic", vPC, 4);
-        return;
-    }
 
     // These m_instructions doesn't ref Structures.
     ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_call) || vPC[0].u.opcode == interpreter->getOpcode(op_call_eval) || vPC[0].u.opcode == interpreter->getOpcode(op_construct));
@@ -577,16 +541,8 @@ void CodeBlock::dump(ExecState* exec)
     }
 
 #if ENABLE(JIT)
-    if (!m_globalResolveInfos.isEmpty() || !m_structureStubInfos.isEmpty())
+    if (!m_structureStubInfos.isEmpty())
         dataLog("\nStructures:\n");
-
-    if (!m_globalResolveInfos.isEmpty()) {
-        size_t i = 0;
-        do {
-             printGlobalResolveInfo(m_globalResolveInfos[i], instructionOffsetForNth(exec, instructions(), i + 1, isGlobalResolve));
-             ++i;
-        } while (i < m_globalResolveInfos.size());
-    }
 #endif
 
     if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
@@ -909,92 +865,30 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printBinaryOp(exec, location, it, "in");
             break;
         }
-        case op_resolve: {
-            int r0 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            dataLog("[%4d] resolve\t\t %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
-            dumpBytecodeCommentAndNewLine(location);
-            it++;
-            break;
-        }
-        case op_resolve_skip: {
-            int r0 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            int skipLevels = (++it)->u.operand;
-            dataLog("[%4d] resolve_skip\t %s, %s, %d", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), skipLevels);
-            dumpBytecodeCommentAndNewLine(location);
-            it++;
-            break;
-        }
-        case op_resolve_global: {
-            int r0 = (++it)->u.operand;
+        case op_put_to_base_variable:
+        case op_put_to_base: {
+            int base = (++it)->u.operand;
             int id0 = (++it)->u.operand;
-            dataLog("[%4d] resolve_global\t %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
+            int value = (++it)->u.operand;
+            int resolveInfo = (++it)->u.operand;
+            dataLog("[%4d] put_to_base\t %s, %s, %s, %d", location, registerName(exec, base).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, value).data(), resolveInfo);
             dumpBytecodeCommentAndNewLine(location);
-            it += 3;
             break;
         }
-        case op_resolve_global_dynamic: {
+        case op_resolve:
+        case op_resolve_global_property:
+        case op_resolve_global_var:
+        case op_resolve_scoped_var:
+        case op_resolve_scoped_var_on_top_scope:
+        case op_resolve_scoped_var_with_top_scope_check: {
             int r0 = (++it)->u.operand;
             int id0 = (++it)->u.operand;
-            JSValue scope = JSValue((++it)->u.jsCell.get());
-            ++it;
-            int depth = (++it)->u.operand;
-            dataLog("[%4d] resolve_global_dynamic\t %s, %s, %s, %d", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).utf8().data(), idName(id0, m_identifiers[id0]).data(), depth);
-            dumpBytecodeCommentAndNewLine(location);
-            ++it;
-            break;
-        }
-        case op_get_scoped_var: {
-            int r0 = (++it)->u.operand;
-            int index = (++it)->u.operand;
-            int skipLevels = (++it)->u.operand;
-            dataLog("[%4d] get_scoped_var\t %s, %d, %d", location, registerName(exec, r0).data(), index, skipLevels);
-            dumpBytecodeCommentAndNewLine(location);
-            it++;
-            break;
-        }
-        case op_put_scoped_var: {
-            int index = (++it)->u.operand;
-            int skipLevels = (++it)->u.operand;
-            int r0 = (++it)->u.operand;
-            dataLog("[%4d] put_scoped_var\t %d, %d, %s", location, index, skipLevels, registerName(exec, r0).data());
-            dumpBytecodeCommentAndNewLine(location);
-            break;
-        }
-        case op_get_global_var: {
-            int r0 = (++it)->u.operand;
-            WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
-            dataLog("[%4d] get_global_var\t %s, g%d(%p)", location, registerName(exec, r0).data(), m_globalObject->findRegisterIndex(registerPointer), registerPointer);
+            int resolveInfo = (++it)->u.operand;
+            dataLog("[%4d] resolve\t\t %s, %s, %d", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo);
             dumpBytecodeCommentAndNewLine(location);
             it++;
             break;
         }
-        case op_get_global_var_watchable: {
-            int r0 = (++it)->u.operand;
-            WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
-            dataLog("[%4d] get_global_var_watchable\t %s, g%d(%p)", location, registerName(exec, r0).data(), m_globalObject->findRegisterIndex(registerPointer), registerPointer);
-            dumpBytecodeCommentAndNewLine(location);
-            it++;
-            it++;
-            break;
-        }
-        case op_put_global_var: {
-            WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
-            int r0 = (++it)->u.operand;
-            dataLog("[%4d] put_global_var\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
-            dumpBytecodeCommentAndNewLine(location);
-            break;
-        }
-        case op_put_global_var_check: {
-            WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
-            int r0 = (++it)->u.operand;
-            dataLog("[%4d] put_global_var_check\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
-            dumpBytecodeCommentAndNewLine(location);
-            it++;
-            it++;
-            break;
-        }
         case op_init_global_const: {
             WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
             int r0 = (++it)->u.operand;
@@ -1011,11 +905,17 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             it++;
             break;
         }
+        case op_resolve_base_to_global:
+        case op_resolve_base_to_global_dynamic:
+        case op_resolve_base_to_scope:
+        case op_resolve_base_to_scope_with_top_scope_check:
         case op_resolve_base: {
             int r0 = (++it)->u.operand;
             int id0 = (++it)->u.operand;
             int isStrict = (++it)->u.operand;
-            dataLog("[%4d] resolve_base%s\t %s, %s", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
+            int resolveInfo = (++it)->u.operand;
+            int putToBaseInfo = (++it)->u.operand;
+            dataLog("[%4d] resolve_base%s\t %s, %s, %d, %d", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo);
             dumpBytecodeCommentAndNewLine(location);
             it++;
             break;
@@ -1031,7 +931,9 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
             int id0 = (++it)->u.operand;
-            dataLog("[%4d] resolve_with_base %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
+            int resolveInfo = (++it)->u.operand;
+            int putToBaseInfo = (++it)->u.operand;
+            dataLog("[%4d] resolve_with_base %s, %s, %s, %d, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo);
             dumpBytecodeCommentAndNewLine(location);
             it++;
             break;
@@ -1040,7 +942,8 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
             int id0 = (++it)->u.operand;
-            dataLog("[%4d] resolve_with_this %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
+            int resolveInfo = (++it)->u.operand;
+            dataLog("[%4d] resolve_with_this %s, %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo);
             dumpBytecodeCommentAndNewLine(location);
             it++;
             break;
@@ -1704,6 +1607,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
     , m_thisRegister(other.m_thisRegister)
     , m_argumentsRegister(other.m_argumentsRegister)
     , m_activationRegister(other.m_activationRegister)
+    , m_globalObjectConstant(other.m_globalObjectConstant)
     , m_needsFullScopeChain(other.m_needsFullScopeChain)
     , m_usesEval(other.m_usesEval)
     , m_isNumericCompareFunction(other.m_isNumericCompareFunction)
@@ -1711,9 +1615,6 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
     , m_codeType(other.m_codeType)
     , m_source(other.m_source)
     , m_sourceOffset(other.m_sourceOffset)
-#if ENABLE(JIT)
-    , m_globalResolveInfos(other.m_globalResolveInfos.size())
-#endif
 #if ENABLE(VALUE_PROFILER)
     , m_executionEntryCount(0)
 #endif
@@ -1728,6 +1629,8 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
     , m_optimizationDelayCounter(0)
     , m_reoptimizationRetryCounter(0)
     , m_lineInfo(other.m_lineInfo)
+    , m_resolveOperations(other.m_resolveOperations)
+    , m_putToBaseOperations(other.m_putToBaseOperations)
 #if ENABLE(BYTECODE_COMMENTS)
     , m_bytecodeCommentIterator(0)
 #endif
@@ -1739,11 +1642,6 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
     optimizeAfterWarmUp();
     jitAfterWarmUp();
 
-#if ENABLE(JIT)
-    for (unsigned i = m_globalResolveInfos.size(); i--;)
-        m_globalResolveInfos[i] = GlobalResolveInfo(other.m_globalResolveInfos[i].bytecodeOffset);
-#endif
-
     if (other.m_rareData) {
         createRareDataIfNecessary();
         
@@ -1787,13 +1685,16 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo
 #endif
 {
     ASSERT(m_source);
-    
+
     optimizeAfterWarmUp();
     jitAfterWarmUp();
 
 #if DUMP_CODE_BLOCK_STATISTICS
     liveCodeBlockSet.add(this);
 #endif
+    // We have a stub putToBase operation to allow resolve_base to
+    // remain branchless
+    m_putToBaseOperations.append(PutToBaseOperation(isStrictMode()));
 }
 
 CodeBlock::~CodeBlock()
@@ -1892,11 +1793,6 @@ void CodeBlock::visitStructures(SlotVisitor& visitor, Instruction* vPC)
         visitor.append(&vPC[4].u.structure);
         return;
     }
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global) || vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global_dynamic)) {
-        if (vPC[3].u.structure)
-            visitor.append(&vPC[3].u.structure);
-        return;
-    }
 
     // These instructions don't ref their Structures.
     ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_get_array_length) || vPC[0].u.opcode == interpreter->getOpcode(op_get_string_length));
@@ -2048,7 +1944,7 @@ static const bool verboseUnlinking = true;
 #else
 static const bool verboseUnlinking = false;
 #endif
-    
+
 void CodeBlock::finalizeUnconditionally()
 {
 #if ENABLE(LLINT)
@@ -2093,17 +1989,7 @@ void CodeBlock::finalizeUnconditionally()
                 ASSERT_NOT_REACHED();
             }
         }
-        for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i) {
-            Instruction* curInstruction = &instructions()[m_globalResolveInstructions[i]];
-            ASSERT(interpreter->getOpcodeID(curInstruction[0].u.opcode) == op_resolve_global
-                   || interpreter->getOpcodeID(curInstruction[0].u.opcode) == op_resolve_global_dynamic);
-            if (!curInstruction[3].u.structure || Heap::isMarked(curInstruction[3].u.structure.get()))
-                continue;
-            if (verboseUnlinking)
-                dataLog("Clearing LLInt global resolve cache with structure %p.\n", curInstruction[3].u.structure.get());
-            curInstruction[3].u.structure.clear();
-            curInstruction[4].u.operand = 0;
-        }
+
         for (unsigned i = 0; i < m_llintCallLinkInfos.size(); ++i) {
             if (m_llintCallLinkInfos[i].isLinked() && !Heap::isMarked(m_llintCallLinkInfos[i].callee.get())) {
                 if (verboseUnlinking)
@@ -2130,7 +2016,29 @@ void CodeBlock::finalizeUnconditionally()
         return;
     }
 #endif // ENABLE(DFG_JIT)
-    
+
+    for (size_t size = m_putToBaseOperations.size(), i = 0; i < size; ++i) {
+        if (m_putToBaseOperations[i].m_structure && !Heap::isMarked(m_putToBaseOperations[i].m_structure.get())) {
+            if (verboseUnlinking)
+                dataLog("Clearing putToBase info in %p.\n", this);
+            m_putToBaseOperations[i].m_structure.clear();
+        }
+    }
+    for (size_t size = m_resolveOperations.size(), i = 0; i < size; ++i) {
+        if (m_resolveOperations[i].isEmpty())
+            continue;
+#ifndef NDEBUG
+        for (size_t insnSize = m_resolveOperations[i].size() - 1, k = 0; k < insnSize; ++k)
+            ASSERT(!m_resolveOperations[i][k].m_structure);
+#endif
+        m_resolveOperations[i].last().m_structure.clear();
+        if (m_resolveOperations[i].last().m_structure && !Heap::isMarked(m_resolveOperations[i].last().m_structure.get())) {
+            if (verboseUnlinking)
+                dataLog("Clearing resolve info in %p.\n", this);
+            m_resolveOperations[i].last().m_structure.clear();
+        }
+    }
+
 #if ENABLE(JIT)
     // Handle inline caches.
     if (!!getJITCode()) {
@@ -2145,14 +2053,6 @@ void CodeBlock::finalizeUnconditionally()
                 && !Heap::isMarked(callLinkInfo(i).lastSeenCallee.get()))
                 callLinkInfo(i).lastSeenCallee.clear();
         }
-        for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
-            if (m_globalResolveInfos[i].structure && !Heap::isMarked(m_globalResolveInfos[i].structure.get())) {
-                if (verboseUnlinking)
-                    dataLog("Clearing resolve info in %p.\n", this);
-                m_globalResolveInfos[i].structure.clear();
-            }
-        }
-
         for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i) {
             StructureStubInfo& stubInfo = m_structureStubInfos[i];
             
@@ -2422,43 +2322,14 @@ void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& d
     return;
 }
 
-#if ENABLE(JIT)
-bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
-{
-    if (m_globalResolveInfos.isEmpty())
-        return false;
-
-    int low = 0;
-    int high = m_globalResolveInfos.size();
-    while (low < high) {
-        int mid = low + (high - low) / 2;
-        if (m_globalResolveInfos[mid].bytecodeOffset <= bytecodeOffset)
-            low = mid + 1;
-        else
-            high = mid;
-    }
-
-    if (!low || m_globalResolveInfos[low - 1].bytecodeOffset != bytecodeOffset)
-        return false;
-    return true;
-}
-GlobalResolveInfo& CodeBlock::globalResolveInfoForBytecodeOffset(unsigned bytecodeOffset)
-{
-    return *(binarySearch<GlobalResolveInfo, unsigned, getGlobalResolveInfoBytecodeOffset>(m_globalResolveInfos.begin(), m_globalResolveInfos.size(), bytecodeOffset));
-}
-#endif
-
 void CodeBlock::shrinkToFit(ShrinkMode shrinkMode)
 {
     m_propertyAccessInstructions.shrinkToFit();
-    m_globalResolveInstructions.shrinkToFit();
 #if ENABLE(LLINT)
     m_llintCallLinkInfos.shrinkToFit();
 #endif
 #if ENABLE(JIT)
     m_structureStubInfos.shrinkToFit();
-    if (shrinkMode == EarlyShrink)
-        m_globalResolveInfos.shrinkToFit();
     m_callLinkInfos.shrinkToFit();
     m_methodCallLinkInfos.shrinkToFit();
 #endif
@@ -2477,6 +2348,7 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode)
         m_constantRegisters.shrinkToFit();
     } // else don't shrink these, because we would have already pointed pointers into these tables.
 
+    m_resolveOperations.shrinkToFit();
     m_lineInfo.shrinkToFit();
     if (m_rareData) {
         m_rareData->m_exceptionHandlers.shrinkToFit();
index 01a8ef4..fe588c7 100644 (file)
@@ -49,7 +49,6 @@
 #include "EvalCodeCache.h"
 #include "ExecutionCounter.h"
 #include "ExpressionRangeInfo.h"
-#include "GlobalResolveInfo.h"
 #include "HandlerInfo.h"
 #include "MethodCallLinkInfo.h"
 #include "Options.h"
@@ -64,6 +63,7 @@
 #include "LineInfo.h"
 #include "Nodes.h"
 #include "RegExpObject.h"
+#include "ResolveOperation.h"
 #include "StructureStubInfo.h"
 #include "UnconditionalFinalizer.h"
 #include "ValueProfile.h"
@@ -197,6 +197,30 @@ namespace JSC {
         int lineNumberForBytecodeOffset(unsigned bytecodeOffset);
         void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset);
 
+        uint32_t addResolve()
+        {
+            m_resolveOperations.grow(m_resolveOperations.size() + 1);
+            return m_resolveOperations.size() - 1;
+        }
+        uint32_t addPutToBase()
+        {
+            m_putToBaseOperations.append(PutToBaseOperation(isStrictMode()));
+            return m_putToBaseOperations.size() - 1;
+        }
+
+        ResolveOperations* resolveOperations(uint32_t i)
+        {
+            return &m_resolveOperations[i];
+        }
+
+        PutToBaseOperation* putToBaseOperation(uint32_t i)
+        {
+            return &m_putToBaseOperations[i];
+        }
+
+        size_t numberOfResolveOperations() const { return m_resolveOperations.size(); }
+        size_t numberOfPutToBaseOperations() const { return m_putToBaseOperations.size(); }
+
 #if ENABLE(JIT)
 
         StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress)
@@ -600,11 +624,6 @@ namespace JSC {
         {
             m_propertyAccessInstructions.append(propertyAccessInstruction);
         }
-        void addGlobalResolveInstruction(unsigned globalResolveInstruction)
-        {
-            m_globalResolveInstructions.append(globalResolveInstruction);
-        }
-        bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset);
 #if ENABLE(LLINT)
         LLIntCallLinkInfo* addLLIntCallLinkInfo()
         {
@@ -621,15 +640,6 @@ namespace JSC {
         size_t numberOfByValInfos() const { return m_byValInfos.size(); }
         ByValInfo& byValInfo(size_t index) { return m_byValInfos[index]; }
 
-        void addGlobalResolveInfo(unsigned globalResolveInstruction)
-        {
-            m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction));
-        }
-        GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; }
-        bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset);
-        GlobalResolveInfo& globalResolveInfoForBytecodeOffset(unsigned bytecodeOffset);
-        unsigned numberOfGlobalResolveInfos() { return m_globalResolveInfos.size(); }
-
         void setNumberOfCallLinkInfos(size_t size) { m_callLinkInfos.grow(size); }
         size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); }
         CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; }
@@ -781,15 +791,6 @@ namespace JSC {
         ArrayProfile* getArrayProfile(unsigned bytecodeOffset);
         ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset);
 #endif
-        
-        unsigned globalResolveInfoCount() const
-        {
-#if ENABLE(JIT)    
-            if (m_globalData->canUseJIT())
-                return m_globalResolveInfos.size();
-#endif
-            return 0;
-        }
 
         // Exception handling support
 
@@ -1215,13 +1216,16 @@ namespace JSC {
         int m_numVars;
         bool m_isConstructor;
 
+        int globalObjectConstant() const { return m_globalObjectConstant; }
+        void setGlobalObjectConstant(int globalRegister) { m_globalObjectConstant = globalRegister; }
+
     protected:
 #if ENABLE(JIT)
         virtual bool jitCompileImpl(ExecState*) = 0;
 #endif
         virtual void visitWeakReferences(SlotVisitor&);
         virtual void finalizeUnconditionally();
-        
+
     private:
         friend class DFGCodeBlocks;
         
@@ -1294,6 +1298,7 @@ namespace JSC {
         int m_thisRegister;
         int m_argumentsRegister;
         int m_activationRegister;
+        int m_globalObjectConstant;
 
         bool m_needsFullScopeChain;
         bool m_usesEval;
@@ -1306,7 +1311,6 @@ namespace JSC {
         unsigned m_sourceOffset;
 
         Vector<unsigned> m_propertyAccessInstructions;
-        Vector<unsigned> m_globalResolveInstructions;
 #if ENABLE(LLINT)
         SegmentedVector<LLIntCallLinkInfo, 8> m_llintCallLinkInfos;
         SentinelLinkedList<LLIntCallLinkInfo, BasicRawSentinelNode<LLIntCallLinkInfo> > m_incomingLLIntCalls;
@@ -1314,7 +1318,6 @@ namespace JSC {
 #if ENABLE(JIT)
         Vector<StructureStubInfo> m_structureStubInfos;
         Vector<ByValInfo> m_byValInfos;
-        Vector<GlobalResolveInfo> m_globalResolveInfos;
         Vector<CallLinkInfo> m_callLinkInfos;
         Vector<MethodCallLinkInfo> m_methodCallLinkInfos;
         JITCode m_jitCode;
@@ -1406,6 +1409,8 @@ namespace JSC {
         Vector<Comment>  m_bytecodeComments;
         size_t m_bytecodeCommentIterator;
 #endif
+        Vector<ResolveOperations> m_resolveOperations;
+        Vector<PutToBaseOperation> m_putToBaseOperations;
 
         struct RareData {
            WTF_MAKE_FAST_ALLOCATED;
index dd62df7..3ce56c8 100644 (file)
@@ -96,22 +96,30 @@ namespace JSC {
         macro(op_is_function, 3) \
         macro(op_in, 4) \
         \
-        macro(op_resolve, 4) /* has value profiling */  \
-        macro(op_resolve_skip, 5) /* has value profiling */ \
-        macro(op_resolve_global, 6) /* has value profiling */ \
-        macro(op_resolve_global_dynamic, 7) /* has value profiling */ \
-        macro(op_get_scoped_var, 5) /* has value profiling */ \
-        macro(op_put_scoped_var, 4) \
-        macro(op_get_global_var, 4) /* has value profiling */ \
-        macro(op_get_global_var_watchable, 5) /* has value profiling */ \
-        macro(op_put_global_var, 3) \
-        macro(op_put_global_var_check, 5) \
+        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 */  \
+        macro(op_resolve_scoped_var, 5) /* has value profiling */  \
+        macro(op_resolve_scoped_var_on_top_scope, 5) /* has value profiling */  \
+        macro(op_resolve_scoped_var_with_top_scope_check, 5) /* has value profiling */  \
+        \
+        macro(op_resolve_base_to_global, 7) /* has value profiling */ \
+        macro(op_resolve_base_to_global_dynamic, 7) /* has value profiling */ \
+        macro(op_resolve_base_to_scope, 7) /* has value profiling */ \
+        macro(op_resolve_base_to_scope_with_top_scope_check, 7) /* has value profiling */ \
+        macro(op_resolve_base, 7) /* has value profiling */ \
+        \
+        macro(op_ensure_property_exists, 3) \
+        \
+        macro(op_resolve_with_base, 7) /* has value profiling */ \
+        \
+        macro(op_resolve_with_this, 6) /* has value profiling */ \
+        \
+        macro(op_put_to_base, 5) \
+        macro(op_put_to_base_variable, 5) \
+        \
         macro(op_init_global_const, 3) \
         macro(op_init_global_const_check, 5) \
-        macro(op_resolve_base, 5) /* has value profiling */ \
-        macro(op_ensure_property_exists, 3) \
-        macro(op_resolve_with_base, 5) /* has value profiling */ \
-        macro(op_resolve_with_this, 5) /* has value profiling */ \
         macro(op_get_by_id, 9) /* has value profiling */ \
         macro(op_get_by_id_out_of_line, 9) /* has value profiling */ \
         macro(op_get_by_id_self, 9) /* has value profiling */ \
index c9fd7dc..7814f8c 100644 (file)
 
 namespace JSC {
 
-#if ENABLE(LLINT) || (ENABLE(JIT) && ENABLE(VALUE_PROFILER))
 static ResolveGlobalStatus computeForStructure(CodeBlock* codeBlock, Structure* structure, Identifier& identifier)
 {
     unsigned attributesIgnored;
     JSCell* specificValue;
-    PropertyOffset offset = structure->get(
-        *codeBlock->globalData(), identifier, attributesIgnored, specificValue);
+    PropertyOffset offset = structure->get(*codeBlock->globalData(), identifier, attributesIgnored, specificValue);
     if (structure->isDictionary())
         specificValue = 0;
     if (!isValidOffset(offset))
@@ -46,46 +44,14 @@ static ResolveGlobalStatus computeForStructure(CodeBlock* codeBlock, Structure*
     
     return ResolveGlobalStatus(ResolveGlobalStatus::Simple, structure, offset, specificValue);
 }
-#endif // ENABLE(LLINT) || ENABLE(JIT)
 
-static ResolveGlobalStatus computeForLLInt(CodeBlock* codeBlock, unsigned bytecodeIndex, Identifier& identifier)
+ResolveGlobalStatus ResolveGlobalStatus::computeFor(CodeBlock* codeBlock, int, ResolveOperation* operation, Identifier& identifier)
 {
-#if ENABLE(LLINT)
-    Instruction* instruction = codeBlock->instructions().begin() + bytecodeIndex;
-
-    ASSERT(instruction[0].u.opcode == LLInt::getOpcode(op_resolve_global));
-    
-    Structure* structure = instruction[3].u.structure.get();
-    if (!structure)
+    ASSERT(operation->m_operation == ResolveOperation::GetAndReturnGlobalProperty);
+    if (!operation->m_structure)
         return ResolveGlobalStatus();
     
-    return computeForStructure(codeBlock, structure, identifier);
-#else
-    UNUSED_PARAM(codeBlock);
-    UNUSED_PARAM(bytecodeIndex);
-    UNUSED_PARAM(identifier);
-    return ResolveGlobalStatus();
-#endif
-}
-
-ResolveGlobalStatus ResolveGlobalStatus::computeFor(CodeBlock* codeBlock, unsigned bytecodeIndex, Identifier& identifier)
-{
-#if ENABLE(JIT) && ENABLE(VALUE_PROFILER)
-    if (!codeBlock->numberOfGlobalResolveInfos())
-        return computeForLLInt(codeBlock, bytecodeIndex, identifier);
-    
-    if (codeBlock->likelyToTakeSlowCase(bytecodeIndex))
-        return ResolveGlobalStatus(TakesSlowPath);
-    
-    GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfoForBytecodeOffset(bytecodeIndex);
-    
-    if (!globalResolveInfo.structure)
-        return computeForLLInt(codeBlock, bytecodeIndex, identifier);
-    
-    return computeForStructure(codeBlock, globalResolveInfo.structure.get(), identifier);
-#else
-    return computeForLLInt(codeBlock, bytecodeIndex, identifier);
-#endif
+    return computeForStructure(codeBlock, operation->m_structure.get(), identifier);
 }
 
 } // namespace JSC
index cbe4d3b..46a9254 100644 (file)
@@ -34,6 +34,7 @@ namespace JSC {
 
 class CodeBlock;
 class Identifier;
+struct ResolveOperation;
 class Structure;
 
 class ResolveGlobalStatus {
@@ -61,7 +62,7 @@ public:
     {
     }
     
-    static ResolveGlobalStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
+    static ResolveGlobalStatus computeFor(CodeBlock*, int bytecodeIndex, ResolveOperation*, Identifier&);
     
     State state() const { return m_state; }
     
index 1160a18..2282773 100644 (file)
@@ -137,25 +137,8 @@ void ResolveResult::checkValidity()
     case ReadOnlyRegister:
         ASSERT(m_local);
         return;
-    case Lexical:
-    case ReadOnlyLexical:
-    case DynamicLexical:
-    case DynamicReadOnlyLexical:
-        ASSERT(m_index != missingSymbolMarker());
-        return;
-    case Global:
-    case DynamicGlobal:
-        ASSERT(m_globalObject);
-        return;
-    case IndexedGlobal:
-    case ReadOnlyIndexedGlobal:
-    case WatchedIndexedGlobal:
-    case DynamicIndexedGlobal:
-    case DynamicReadOnlyIndexedGlobal:
-        ASSERT(m_index != missingSymbolMarker());
-        ASSERT(m_globalObject);
-        return;
     case Dynamic:
+        ASSERT(!m_local);
         return;
     default:
         ASSERT_NOT_REACHED();
@@ -163,11 +146,6 @@ void ResolveResult::checkValidity()
 }
 #endif
 
-WriteBarrier<Unknown>* ResolveResult::registerPointer() const
-{
-    return &jsCast<JSGlobalObject*>(globalObject())->registerAt(index());
-}
-
 static bool s_dumpsGeneratedCode = false;
 
 void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode)
@@ -292,6 +270,8 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, S
     , m_expressionTooDeep(false)
 {
     m_globalData->startedCompiling(m_codeBlock);
+    m_codeBlock->setGlobalObjectConstant(emitLoad(0, JSValue(m_codeBlock->globalObject()))->index());
+    
     if (m_shouldEmitDebugHooks)
         m_codeBlock->setNeedsFullScopeChain(true);
 
@@ -324,7 +304,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, S
         FunctionBodyNode* function = functionStack[i];
         bool propertyDidExist = 
             globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
-        
+
         JSValue value = JSFunction::create(exec, FunctionExecutable::create(*m_globalData, function), scope);
         int index = addGlobalVar(
             function->ident(), IsVariable,
@@ -374,6 +354,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc
     , m_expressionTooDeep(false)
 {
     m_globalData->startedCompiling(m_codeBlock);
+    m_codeBlock->setGlobalObjectConstant(emitLoad(0, JSValue(m_codeBlock->globalObject()))->index());
+
     if (m_shouldEmitDebugHooks)
         m_codeBlock->setNeedsFullScopeChain(true);
 
@@ -588,6 +570,8 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, JSScope* scope, SharedS
     , m_expressionTooDeep(false)
 {
     m_globalData->startedCompiling(m_codeBlock);
+    m_codeBlock->setGlobalObjectConstant(emitLoad(0, JSValue(m_codeBlock->globalObject()))->index());
+
     if (m_shouldEmitDebugHooks || m_baseScopeDepth)
         m_codeBlock->setNeedsFullScopeChain(true);
 
@@ -1365,67 +1349,7 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property)
             return ResolveResult::registerResolve(local, flags);
         }
     }
-
-    // Cases where we cannot statically optimize the lookup.
-    if (property == propertyNames().arguments || !canOptimizeNonLocals())
-        return ResolveResult::dynamicResolve(0);
-
-    ScopeChainIterator iter = m_scope->begin();
-    ScopeChainIterator end = m_scope->end();
-    size_t depth = 0;
-    size_t depthOfFirstScopeWithDynamicChecks = 0;
-    unsigned flags = 0;
-    for (; iter != end; ++iter, ++depth) {
-        JSObject* currentScope = iter.get();
-        if (!currentScope->isVariableObject()) {
-            flags |= ResolveResult::DynamicFlag;
-            break;
-        }
-        JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope);
-        SymbolTableEntry entry = currentVariableObject->symbolTable()->get(property.impl());
-
-        // Found the property
-        if (!entry.isNull()) {
-            if (entry.isReadOnly())
-                flags |= ResolveResult::ReadOnlyFlag;
-            depth += m_codeBlock->needsFullScopeChain();
-            if (++iter == end) {
-                if (flags & ResolveResult::DynamicFlag)
-                    return ResolveResult::dynamicIndexedGlobalResolve(entry.getIndex(), depth, currentScope, flags);
-                return ResolveResult::indexedGlobalResolve(
-                    entry.getIndex(), currentScope,
-                    flags | (entry.couldBeWatched() ? ResolveResult::WatchedFlag : 0));
-            }
-#if !ASSERT_DISABLED
-            if (JSActivation* activation = jsDynamicCast<JSActivation*>(currentVariableObject))
-                ASSERT(activation->isValid(entry));
-#endif
-            return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags);
-        }
-        bool scopeRequiresDynamicChecks = false;
-        if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks))
-            break;
-        if (!(flags & ResolveResult::DynamicFlag)) {
-            if (scopeRequiresDynamicChecks)
-                flags |= ResolveResult::DynamicFlag;
-            else
-                ++depthOfFirstScopeWithDynamicChecks;
-        }
-    }
-
-    // Can't locate the property but we're able to avoid a few lookups.
-    JSObject* scope = iter.get();
-    // Step over the function's activation, if it needs one. At this point we
-    // know there is no dynamic scope in the function itself, so this is safe to
-    // do.
-    depth += m_codeBlock->needsFullScopeChain();
-    depthOfFirstScopeWithDynamicChecks += m_codeBlock->needsFullScopeChain();
-    if (++iter == end) {
-        if ((flags & ResolveResult::DynamicFlag) && depth)
-            return ResolveResult::dynamicGlobalResolve(depth, scope);
-        return ResolveResult::globalResolve(scope);
-    }
-    return ResolveResult::dynamicResolve(depthOfFirstScopeWithDynamicChecks);
+    return ResolveResult::dynamicResolve();
 }
 
 ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property)
@@ -1440,26 +1364,7 @@ ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property)
         }
     }
 
-    // Const declarations in eval code or global code.
-    ScopeChainIterator iter = scope()->begin();
-    ScopeChainIterator end = scope()->end();
-    size_t depth = 0;
-    for (; iter != end; ++iter, ++depth) {
-        JSObject* currentScope = iter.get();
-        if (!currentScope->isVariableObject())
-            continue;
-        JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope);
-        SymbolTableEntry entry = currentVariableObject->symbolTable()->get(property.impl());
-        if (entry.isNull())
-            continue;
-        if (++iter == end)
-            return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentVariableObject, 0);
-        return ResolveResult::lexicalResolve(entry.getIndex(), depth + scopeDepth(), 0);
-    }
-
-    // FIXME: While this code should only be hit in an eval block, it will assign
-    // to the wrong base if property exists in an intervening with scope.
-    return ResolveResult::dynamicResolve(scopeDepth());
+    return ResolveResult::dynamicResolve();
 }
 
 void BytecodeGenerator::emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target)
@@ -1481,158 +1386,89 @@ RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value
     return dst;
 }
 
-static const unsigned maxGlobalResolves = 128;
-
 bool BytecodeGenerator::shouldAvoidResolveGlobal()
 {
-    return m_codeBlock->globalResolveInfoCount() > maxGlobalResolves && !m_labelScopes.size();
+    return !m_labelScopes.size();
 }
 
 RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
 {
-    if (resolveResult.isStatic())
-        return emitGetStaticVar(dst, resolveResult, property);
-    
-    if (resolveResult.isGlobal() && !shouldAvoidResolveGlobal()) {
-#if ENABLE(JIT)
-        m_codeBlock->addGlobalResolveInfo(instructions().size());
-#endif
-        m_codeBlock->addGlobalResolveInstruction(instructions().size());
-        bool dynamic = resolveResult.isDynamic() && resolveResult.depth();
-        ValueProfile* profile = emitProfiledOpcode(dynamic ? op_resolve_global_dynamic : op_resolve_global);
-        instructions().append(dst->index());
-        instructions().append(addConstant(property));
-        instructions().append(0);
-        instructions().append(0);
-        if (dynamic)
-            instructions().append(resolveResult.depth());
-        instructions().append(profile);
-        return dst;
-    }
-        
-    if (resolveResult.type() == ResolveResult::Dynamic && resolveResult.depth()) {
-        // In this case we are at least able to drop a few scope chains from the
-        // lookup chain, although we still need to hash from then on.
-        ValueProfile* profile = emitProfiledOpcode(op_resolve_skip);
-        instructions().append(dst->index());
-        instructions().append(addConstant(property));
-        instructions().append(resolveResult.depth());
-        instructions().append(profile);
-        return dst;
-    }
+
+    if (resolveResult.isRegister())
+        return emitGetLocalVar(dst, resolveResult, property);
 
     ValueProfile* profile = emitProfiledOpcode(op_resolve);
     instructions().append(dst->index());
     instructions().append(addConstant(property));
+    instructions().append(getResolveOperations(property));
     instructions().append(profile);
     return dst;
 }
 
 RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
 {
-    if (resolveResult.isGlobal() && !resolveResult.isDynamic())
-        // Global object is the base
-        return emitLoad(dst, JSValue(resolveResult.globalObject()));
-
+    ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
     // We can't optimise at all :-(
     ValueProfile* profile = emitProfiledOpcode(op_resolve_base);
     instructions().append(dst->index());
     instructions().append(addConstant(property));
     instructions().append(false);
+    instructions().append(getResolveBaseOperations(property));
+    instructions().append(0);
     instructions().append(profile);
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
+RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier)
 {
-    if (!m_codeBlock->isStrictMode())
-        return emitResolveBase(dst, resolveResult, property);
-
-    if (resolveResult.isGlobal() && !resolveResult.isDynamic()) {
-        // Global object is the base
-        RefPtr<RegisterID> result = emitLoad(dst, JSValue(resolveResult.globalObject()));
-        emitOpcode(op_ensure_property_exists);
-        instructions().append(dst->index());
-        instructions().append(addConstant(property));
-        return result.get();
-    }
-
+    ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
     // We can't optimise at all :-(
     ValueProfile* profile = emitProfiledOpcode(op_resolve_base);
     instructions().append(dst->index());
     instructions().append(addConstant(property));
-    instructions().append(true);
+    instructions().append(m_codeBlock->isStrictMode());
+    uint32_t putToBaseIndex = 0;
+    instructions().append(getResolveBaseForPutOperations(property, putToBaseIndex));
+    verifier.resolved(putToBaseIndex);
+    instructions().append(putToBaseIndex);
     instructions().append(profile);
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property)
+RegisterID* BytecodeGenerator::emitResolveWithBaseForPut(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier)
 {
-    if (resolveResult.isGlobal() && !resolveResult.isDynamic()) {
-        // Global object is the base
-        emitLoad(baseDst, JSValue(resolveResult.globalObject()));
-
-        if (resolveResult.isStatic()) {
-            // Directly index the property lookup across multiple scopes.
-            emitGetStaticVar(propDst, resolveResult, property);
-            return baseDst;
-        }
-
-        if (shouldAvoidResolveGlobal()) {
-            ValueProfile* profile = emitProfiledOpcode(op_resolve);
-            instructions().append(propDst->index());
-            instructions().append(addConstant(property));
-            instructions().append(profile);
-            return baseDst;
-        }
-
-#if ENABLE(JIT)
-        m_codeBlock->addGlobalResolveInfo(instructions().size());
-#endif
-        m_codeBlock->addGlobalResolveInstruction(instructions().size());
-        ValueProfile* profile = emitProfiledOpcode(op_resolve_global);
-        instructions().append(propDst->index());
-        instructions().append(addConstant(property));
-        instructions().append(0);
-        instructions().append(0);
-        instructions().append(profile);
-        return baseDst;
-    }
-
+    ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
     ValueProfile* profile = emitProfiledOpcode(op_resolve_with_base);
     instructions().append(baseDst->index());
     instructions().append(propDst->index());
     instructions().append(addConstant(property));
+    uint32_t putToBaseIndex = 0;
+    instructions().append(getResolveWithBaseForPutOperations(property, putToBaseIndex));
+    verifier.resolved(putToBaseIndex);
+    instructions().append(putToBaseIndex);
     instructions().append(profile);
     return baseDst;
 }
 
 RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property)
 {
-    if (resolveResult.isStatic()) {
+    if (resolveResult.isRegister()) {
         emitLoad(baseDst, jsUndefined());
-        emitGetStaticVar(propDst, resolveResult, property);
+        emitGetLocalVar(propDst, resolveResult, property);
         return baseDst;
     }
 
-    if (resolveResult.type() == ResolveResult::Dynamic) {
-        // We can't optimise at all :-(
-        ValueProfile* profile = emitProfiledOpcode(op_resolve_with_this);
-        instructions().append(baseDst->index());
-        instructions().append(propDst->index());
-        instructions().append(addConstant(property));
-        instructions().append(profile);
-        return baseDst;
-    }
-
-    emitLoad(baseDst, jsUndefined());
-    return emitResolve(propDst, resolveResult, property);
+    ValueProfile* profile = emitProfiledOpcode(op_resolve_with_this);
+    instructions().append(baseDst->index());
+    instructions().append(propDst->index());
+    instructions().append(addConstant(property));
+    instructions().append(getResolveWithThisOperations(property));
+    instructions().append(profile);
+    return baseDst;
 }
 
-RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& identifier)
+RegisterID* BytecodeGenerator::emitGetLocalVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier&)
 {
-    ValueProfile* profile = 0;
-
     switch (resolveResult.type()) {
     case ResolveResult::Register:
     case ResolveResult::ReadOnlyRegister:
@@ -1640,107 +1476,33 @@ RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveRe
             return 0;
         return moveToDestinationIfNeeded(dst, resolveResult.local());
 
-    case ResolveResult::Lexical:
-    case ResolveResult::ReadOnlyLexical:
-        profile = emitProfiledOpcode(op_get_scoped_var);
-        instructions().append(dst->index());
-        instructions().append(resolveResult.index());
-        instructions().append(resolveResult.depth());
-        instructions().append(profile);
-        return dst;
-
-    case ResolveResult::IndexedGlobal:
-    case ResolveResult::ReadOnlyIndexedGlobal:
-        if (m_lastOpcodeID == op_put_global_var) {
-            WriteBarrier<Unknown>* dstPointer;
-            int srcIndex;
-            retrieveLastUnaryOp(dstPointer, srcIndex);
-            if (dstPointer == resolveResult.registerPointer() && srcIndex == dst->index())
-                return dst;
-        }
-
-        profile = emitProfiledOpcode(op_get_global_var);
-        instructions().append(dst->index());
-        instructions().append(resolveResult.registerPointer());
-        instructions().append(profile);
-        return dst;
-
-    case ResolveResult::WatchedIndexedGlobal:
-        // Skip the peephole for now. It's not clear that it's profitable given
-        // the DFG's capabilities, and the fact that if it's watchable then we
-        // don't expect to see any put_global_var's anyway.
-        profile = emitProfiledOpcode(op_get_global_var_watchable);
-        instructions().append(dst->index());
-        instructions().append(resolveResult.registerPointer());
-        instructions().append(addConstant(identifier)); // For the benefit of the DFG.
-        instructions().append(profile);
-        return dst;
-
     default:
         ASSERT_NOT_REACHED();
         return 0;
     }
 }
 
-RegisterID* BytecodeGenerator::emitInitGlobalConst(const ResolveResult& resolveResult, const Identifier& identifier, RegisterID* value)
+RegisterID* BytecodeGenerator::emitInitGlobalConst(const Identifier& identifier, RegisterID* value)
 {
     ASSERT(m_codeType == GlobalCode);
-    switch (resolveResult.type()) {
-    case ResolveResult::IndexedGlobal:
-    case ResolveResult::ReadOnlyIndexedGlobal:
-        emitOpcode(op_init_global_const);
-        instructions().append(resolveResult.registerPointer());
-        instructions().append(value->index());
-        return value;
-
-    case ResolveResult::WatchedIndexedGlobal:
-        emitOpcode(op_init_global_const_check);
-        instructions().append(resolveResult.registerPointer());
-        instructions().append(value->index());
-        instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable()->get(identifier.impl()).addressOfIsWatched());
-        instructions().append(addConstant(identifier));
-        return value;
-        
-    default:
-        ASSERT_NOT_REACHED();
+    JSGlobalObject* globalObject = m_codeBlock->globalObject();
+    SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl());
+    if (entry.isNull())
         return 0;
-    }
-}
-
-RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, const Identifier& identifier, RegisterID* value)
-{
-    switch (resolveResult.type()) {
-    case ResolveResult::Register:
-    case ResolveResult::ReadOnlyRegister:
-        return moveToDestinationIfNeeded(resolveResult.local(), value);
-
-    case ResolveResult::Lexical:
-    case ResolveResult::ReadOnlyLexical:
-        emitOpcode(op_put_scoped_var);
-        instructions().append(resolveResult.index());
-        instructions().append(resolveResult.depth());
-        instructions().append(value->index());
-        return value;
-
-    case ResolveResult::IndexedGlobal:
-    case ResolveResult::ReadOnlyIndexedGlobal:
-        emitOpcode(op_put_global_var);
-        instructions().append(resolveResult.registerPointer());
-        instructions().append(value->index());
-        return value;
-        
-    case ResolveResult::WatchedIndexedGlobal:
-        emitOpcode(op_put_global_var_check);
-        instructions().append(resolveResult.registerPointer());
+    
+    if (entry.couldBeWatched()) {
+        emitOpcode(op_init_global_const_check);
+        instructions().append(&globalObject->registerAt(entry.getIndex()));
         instructions().append(value->index());
-        instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable()->get(identifier.impl()).addressOfIsWatched());
+        instructions().append(entry.addressOfIsWatched());
         instructions().append(addConstant(identifier));
         return value;
-
-    default:
-        ASSERT_NOT_REACHED();
-        return 0;
     }
+    
+    emitOpcode(op_init_global_const);
+    instructions().append(&globalObject->registerAt(entry.getIndex()));
+    instructions().append(value->index());
+    return value;
 }
 
 void BytecodeGenerator::emitMethodCheck()
@@ -1790,6 +1552,16 @@ RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& p
     return value;
 }
 
+RegisterID* BytecodeGenerator::emitPutToBase(RegisterID* base, const Identifier& property, RegisterID* value, NonlocalResolveInfo& resolveInfo)
+{
+    emitOpcode(op_put_to_base);
+    instructions().append(base->index());
+    instructions().append(addConstant(property));
+    instructions().append(value->index());
+    instructions().append(resolveInfo.put());
+    return value;
+}
+
 RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value)
 {
     m_codeBlock->addPropertyAccessInstruction(instructions().size());
index ae79a13..a08e93a 100644 (file)
@@ -123,124 +123,42 @@ namespace JSC {
             // We need to traverse the scope chain at runtime, checking for
             // non-strict eval and/or `with' nodes.
             DynamicFlag = 0x2,
-            // The property was resolved to a definite location, and the
-            // identifier is not needed any more.
-            StaticFlag = 0x4,
-            // Once we have the base object, the property will be located at a
-            // known index.
-            IndexedFlag = 0x8,
-            // Skip some number of objects in the scope chain, given by "depth".
-            ScopedFlag = 0x10,
             // The resolved binding is immutable.
-            ReadOnlyFlag = 0x20,
-            // The base object is the global object.
-            GlobalFlag = 0x40,
-            // The property is being watched, so writes should be special.
-            WatchedFlag = 0x80
+            ReadOnlyFlag = 0x4,
         };
+
         enum Type {
             // The property is local, and stored in a register.
-            Register = RegisterFlag | StaticFlag,
+            Register = RegisterFlag,
             // A read-only local, created by "const".
-            ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag,
-            // The property is statically scoped free variable. Its coordinates
-            // are in "index" and "depth".
-            Lexical = IndexedFlag | ScopedFlag | StaticFlag,
-            // A read-only Lexical, created by "const".
-            ReadOnlyLexical = IndexedFlag | ScopedFlag | ReadOnlyFlag | StaticFlag,
-            // The property was not bound lexically, so at runtime we should
-            // look directly in the global object.
-            Global = GlobalFlag,
-            // Like Global, but we could actually resolve the property to a
-            // DontDelete property in the global object, for instance, any
-            // binding created with "var" at the top level. At runtime we'll
-            // just index into the global object.
-            IndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag,
-            // Like IndexedGlobal, but the property is being watched.
-            WatchedIndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag | WatchedFlag,
-            // Like IndexedGlobal, but the property is also read-only, like NaN,
-            // Infinity, or undefined.
-            ReadOnlyIndexedGlobal = IndexedFlag | ReadOnlyFlag | GlobalFlag | StaticFlag,
-            // The property could not be resolved statically, due to the
-            // presence of `with' blocks. At runtime we'll have to walk the
-            // scope chain. ScopedFlag is set to indicate that "depth" will
-            // hold some number of nodes to skip in the scope chain, before
-            // beginning the search.
-            Dynamic = DynamicFlag | ScopedFlag,
-            // The property was located as a statically scoped free variable,
-            // but while traversing the scope chain, there was an intermediate
-            // activation that used non-strict `eval'. At runtime we'll have to
-            // check for the absence of this property in those intervening
-            // scopes.
-            DynamicLexical = DynamicFlag | IndexedFlag | ScopedFlag,
-            // Like ReadOnlyLexical, but with intervening non-strict `eval'.
-            DynamicReadOnlyLexical = DynamicFlag | IndexedFlag | ScopedFlag | ReadOnlyFlag,
-            // Like Global, but with intervening non-strict `eval'. As with 
-            // Dynamic, ScopeFlag is set to indicate that "depth" does indeed
-            // store a number of frames to skip before doing the dynamic checks.
-            DynamicGlobal = DynamicFlag | GlobalFlag | ScopedFlag,
-            // Like IndexedGlobal, but with intervening non-strict `eval'.
-            DynamicIndexedGlobal = DynamicFlag | IndexedFlag | GlobalFlag | ScopedFlag,
-            // Like ReadOnlyIndexedGlobal, but with intervening non-strict
-            // `eval'.
-            DynamicReadOnlyIndexedGlobal = DynamicFlag | IndexedFlag | ReadOnlyFlag | GlobalFlag | ScopedFlag,
+            ReadOnlyRegister = RegisterFlag | ReadOnlyFlag,
+            // Any form of non-local lookup
+            Dynamic = DynamicFlag,
         };
 
         static ResolveResult registerResolve(RegisterID *local, unsigned flags)
         {
-            return ResolveResult(Register | flags, local, missingSymbolMarker(), 0, 0);
-        }
-        static ResolveResult dynamicResolve(size_t depth)
-        {
-            return ResolveResult(Dynamic, 0, missingSymbolMarker(), depth, 0);
-        }
-        static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags)
-        {
-            unsigned type = (flags & DynamicFlag) ? DynamicLexical : Lexical;
-            return ResolveResult(type | flags, 0, index, depth, 0);
-        }
-        static ResolveResult indexedGlobalResolve(int index, JSObject *globalObject, unsigned flags)
-        {
-            return ResolveResult(IndexedGlobal | flags, 0, index, 0, globalObject);
+            return ResolveResult(Register | flags, local);
         }
-        static ResolveResult dynamicIndexedGlobalResolve(int index, size_t depth, JSObject *globalObject, unsigned flags)
+        static ResolveResult dynamicResolve()
         {
-            return ResolveResult(DynamicIndexedGlobal | flags, 0, index, depth, globalObject);
+            return ResolveResult(Dynamic, 0);
         }
-        static ResolveResult globalResolve(JSObject *globalObject)
-        {
-            return ResolveResult(Global, 0, missingSymbolMarker(), 0, globalObject);
-        }
-        static ResolveResult dynamicGlobalResolve(size_t dynamicDepth, JSObject *globalObject)
-        {
-            return ResolveResult(DynamicGlobal, 0, missingSymbolMarker(), dynamicDepth, globalObject);
-        }
-
         unsigned type() const { return m_type; }
+
         // Returns the register corresponding to a local variable, or 0 if no
         // such register exists. Registers returned by ResolveResult::local() do
         // not require explicit reference counting.
         RegisterID* local() const { return m_local; }
-        int index() const { ASSERT (isIndexed() || isRegister()); return m_index; }
-        size_t depth() const { ASSERT(isScoped()); return m_depth; }
-        JSObject* globalObject() const { ASSERT(isGlobal()); ASSERT(m_globalObject); return m_globalObject; }
-        WriteBarrier<Unknown>* registerPointer() const;
 
         bool isRegister() const { return m_type & RegisterFlag; }
         bool isDynamic() const { return m_type & DynamicFlag; }
-        bool isStatic() const { return m_type & StaticFlag; }
-        bool isIndexed() const { return m_type & IndexedFlag; }
-        bool isScoped() const { return m_type & ScopedFlag; }
         bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); }
-        bool isGlobal() const { return m_type & GlobalFlag; }
 
     private:
-        ResolveResult(unsigned type, RegisterID* local, int index, size_t depth, JSObject* globalObject)
+        ResolveResult(unsigned type, RegisterID* local)
             : m_type(type)
-            , m_index(index)
             , m_local(local)
-            , m_depth(depth)
-            , m_globalObject(globalObject)
         {
 #ifndef NDEBUG
             checkValidity();
@@ -252,10 +170,36 @@ namespace JSC {
 #endif
 
         unsigned m_type;
-        int m_index; // Index in scope, if IndexedFlag is set
         RegisterID* m_local; // Local register, if RegisterFlag is set
-        size_t m_depth; // Depth in scope chain, if ScopedFlag is set
-        JSObject* m_globalObject; // If GlobalFlag is set.
+    };
+
+    struct NonlocalResolveInfo {
+        friend class BytecodeGenerator;
+        NonlocalResolveInfo()
+            : m_state(Unused)
+        {
+        }
+        ~NonlocalResolveInfo()
+        {
+            ASSERT(m_state == Put);
+        }
+    private:
+        void resolved(uint32_t putToBaseIndex)
+        {
+            ASSERT(putToBaseIndex);
+            ASSERT(m_state == Unused);
+            m_state = Resolved;
+            m_putToBaseIndex = putToBaseIndex;
+        }
+        uint32_t put()
+        {
+            ASSERT(m_state == Resolved);
+            m_state = Put;
+            return m_putToBaseIndex;
+        }
+        enum State { Unused, Resolved, Put };
+        State m_state;
+        uint32_t m_putToBaseIndex;
     };
 
     class BytecodeGenerator {
@@ -466,16 +410,17 @@ namespace JSC {
         RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
         RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
 
-        RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&, const Identifier&);
-        RegisterID* emitPutStaticVar(const ResolveResult&, const Identifier&, RegisterID* value);
-        RegisterID* emitInitGlobalConst(const ResolveResult&, const Identifier&, RegisterID* value);
+        RegisterID* emitGetLocalVar(RegisterID* dst, const ResolveResult&, const Identifier&);
+        RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value);
 
         RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property);
         RegisterID* emitResolveBase(RegisterID* dst, const ResolveResult&, const Identifier& property);
-        RegisterID* emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property);
-        RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property);
+        RegisterID* emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo&);
+        RegisterID* emitResolveWithBaseForPut(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo&);
         RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property);
 
+        RegisterID* emitPutToBase(RegisterID* base, const Identifier&, RegisterID* value, NonlocalResolveInfo&);
+
         void emitMethodCheck();
 
         RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
@@ -596,6 +541,12 @@ namespace JSC {
 
         typedef HashMap<double, JSValue> NumberMap;
         typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap;
+        typedef struct {
+            int resolveOperations;
+            int putOperations;
+        } ResolveCacheEntry;
+        typedef HashMap<StringImpl*, ResolveCacheEntry, IdentifierRepHash> IdentifierResolvePutMap;
+        typedef HashMap<StringImpl*, uint32_t, IdentifierRepHash> IdentifierResolveMap;
         
         // Helper for emitCall() and emitConstruct(). This works because the set of
         // expected functions have identical behavior for both call and construct
@@ -766,6 +717,75 @@ namespace JSC {
         NumberMap m_numberMap;
         IdentifierStringMap m_stringMap;
 
+        uint32_t getResolveOperations(const Identifier& property)
+        {
+            if (m_dynamicScopeDepth)
+                return m_codeBlock->addResolve();
+            IdentifierResolveMap::AddResult result = m_resolveCacheMap.add(property.impl(), 0);
+            if (result.isNewEntry)
+                result.iterator->value = m_codeBlock->addResolve();
+            return result.iterator->value;
+        }
+
+        uint32_t getResolveWithThisOperations(const Identifier& property)
+        {
+            if (m_dynamicScopeDepth)
+                return m_codeBlock->addResolve();
+            IdentifierResolveMap::AddResult result = m_resolveWithThisCacheMap.add(property.impl(), 0);
+            if (result.isNewEntry)
+                result.iterator->value = m_codeBlock->addResolve();
+            return result.iterator->value;
+        }
+
+        uint32_t getResolveBaseOperations(IdentifierResolvePutMap& map, const Identifier& property, uint32_t& putToBaseOperation)
+        {
+            if (m_dynamicScopeDepth) {
+                putToBaseOperation = m_codeBlock->addPutToBase();
+                return m_codeBlock->addResolve();
+            }
+            ResolveCacheEntry entry = {-1, -1};
+            IdentifierResolvePutMap::AddResult result = map.add(property.impl(), entry);
+            if (result.isNewEntry)
+                result.iterator->value.resolveOperations = m_codeBlock->addResolve();
+            if (result.iterator->value.putOperations == -1)
+                result.iterator->value.putOperations = getPutToBaseOperation(property);
+            putToBaseOperation = result.iterator->value.putOperations;
+            return result.iterator->value.resolveOperations;
+        }
+
+        uint32_t getResolveBaseOperations(const Identifier& property)
+        {
+            uint32_t scratch;
+            return getResolveBaseOperations(m_resolveBaseMap, property, scratch);
+        }
+
+        uint32_t getResolveBaseForPutOperations(const Identifier& property, uint32_t& putToBaseOperation)
+        {
+            return getResolveBaseOperations(m_resolveBaseForPutMap, property, putToBaseOperation);
+        }
+
+        uint32_t getResolveWithBaseForPutOperations(const Identifier& property, uint32_t& putToBaseOperation)
+        {
+            return getResolveBaseOperations(m_resolveWithBaseForPutMap, property, putToBaseOperation);
+        }
+
+        uint32_t getPutToBaseOperation(const Identifier& property)
+        {
+            if (m_dynamicScopeDepth)
+                return m_codeBlock->addPutToBase();
+            IdentifierResolveMap::AddResult result = m_putToBaseMap.add(property.impl(), 0);
+            if (result.isNewEntry)
+                result.iterator->value = m_codeBlock->addPutToBase();
+            return result.iterator->value;
+        }
+
+        IdentifierResolveMap m_putToBaseMap;
+        IdentifierResolveMap m_resolveCacheMap;
+        IdentifierResolveMap m_resolveWithThisCacheMap;
+        IdentifierResolvePutMap m_resolveBaseMap;
+        IdentifierResolvePutMap m_resolveBaseForPutMap;
+        IdentifierResolvePutMap m_resolveWithBaseForPutMap;
+
         JSGlobalData* m_globalData;
 
         OpcodeID m_lastOpcodeID;
index 10a873d..6881195 100644 (file)
@@ -141,7 +141,7 @@ RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst
 
 bool ResolveNode::isPure(BytecodeGenerator& generator) const
 {
-    return generator.resolve(m_ident).isStatic();
+    return generator.resolve(m_ident).isRegister();
 }
 
 RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -439,14 +439,6 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
         return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
     }
 
-    if (resolveResult.isStatic()) {
-        RefPtr<RegisterID> func = generator.newTemporary();
-        CallArguments callArguments(generator, m_args);
-        generator.emitGetStaticVar(func.get(), resolveResult, m_ident);
-        generator.emitLoad(callArguments.thisRegister(), jsUndefined());
-        return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset());
-    }
-
     RefPtr<RegisterID> func = generator.newTemporary();
     CallArguments callArguments(generator, m_args);
     int identifierStart = divot() - startOffset();
@@ -631,29 +623,18 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
             return emitPreIncOrDec(generator, local, m_operator);
         return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator);
     }
-
-    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
-        RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, ident);
-        RegisterID* oldValue;
-        if (dst == generator.ignoredResult()) {
-            oldValue = 0;
-            emitPreIncOrDec(generator, value.get(), m_operator);
-        } else
-            oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
-        generator.emitPutStaticVar(resolveResult, ident, value.get());
-        return oldValue;
-    }
     
     generator.emitExpressionInfo(divot(), startOffset(), endOffset());
     RefPtr<RegisterID> value = generator.newTemporary();
-    RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, ident);
+    NonlocalResolveInfo resolveInfo;
+    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), value.get(), resolveResult, ident, resolveInfo);
     RegisterID* oldValue;
     if (dst == generator.ignoredResult()) {
         oldValue = 0;
         emitPreIncOrDec(generator, value.get(), m_operator);
     } else
         oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
-    generator.emitPutById(base.get(), ident, value.get());
+    generator.emitPutToBase(base.get(), ident, value.get(), resolveInfo);
     return oldValue;
 }
 
@@ -828,18 +809,12 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
         return generator.moveToDestinationIfNeeded(dst, local);
     }
 
-    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
-        RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, ident);
-        emitPreIncOrDec(generator, propDst.get(), m_operator);
-        generator.emitPutStaticVar(resolveResult, ident, propDst.get());
-        return generator.moveToDestinationIfNeeded(dst, propDst.get());
-    }
-
     generator.emitExpressionInfo(divot(), startOffset(), endOffset());
     RefPtr<RegisterID> propDst = generator.tempDestination(dst);
-    RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, ident);
+    NonlocalResolveInfo resolveVerifier;
+    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), propDst.get(), resolveResult, ident, resolveVerifier);
     emitPreIncOrDec(generator, propDst.get(), m_operator);
-    generator.emitPutById(base.get(), ident, propDst.get());
+    generator.emitPutToBase(base.get(), ident, propDst.get(), resolveVerifier);
     return generator.moveToDestinationIfNeeded(dst, propDst.get());
 }
 
@@ -1265,18 +1240,12 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
         return generator.moveToDestinationIfNeeded(dst, result);
     }
 
-    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
-        RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
-        RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
-        generator.emitPutStaticVar(resolveResult, m_ident, result);
-        return result;
-    }
-
     RefPtr<RegisterID> src1 = generator.tempDestination(dst);
     generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0);
-    RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), resolveResult, m_ident);
+    NonlocalResolveInfo resolveVerifier;
+    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), src1.get(), resolveResult, m_ident, resolveVerifier);
     RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
-    return generator.emitPutById(base.get(), m_ident, result);
+    return generator.emitPutToBase(base.get(), m_ident, result, resolveVerifier);
 }
 
 // ------------------------------ AssignResolveNode -----------------------------------
@@ -1285,7 +1254,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
 {
     ResolveResult resolveResult = generator.resolve(m_ident);
 
-    if (RegisterID *local = resolveResult.local()) {
+    if (RegisterIDlocal = resolveResult.local()) {
         if (resolveResult.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded();
             return generator.emitNode(dst, m_right);
@@ -1294,20 +1263,13 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
         return generator.moveToDestinationIfNeeded(dst, result);
     }
 
-    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
-        if (dst == generator.ignoredResult())
-            dst = 0;
-        RegisterID* value = generator.emitNode(dst, m_right);
-        generator.emitPutStaticVar(resolveResult, m_ident, value);
-        return value;
-    }
-
-    RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident);
+    NonlocalResolveInfo resolveVerifier;
+    RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident, resolveVerifier);
     if (dst == generator.ignoredResult())
         dst = 0;
     RegisterID* value = generator.emitNode(dst, m_right);
     generator.emitExpressionInfo(divot(), startOffset(), endOffset());
-    return generator.emitPutById(base.get(), m_ident, value);
+    return generator.emitPutToBase(base.get(), m_ident, value, resolveVerifier);
 }
 
 // ------------------------------ AssignDotNode -----------------------------------
@@ -1402,16 +1364,14 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
 
     RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined());
 
-    if (resolveResult.isStatic()) {
-        if (generator.codeType() == GlobalCode)
-            return generator.emitInitGlobalConst(resolveResult, m_ident, value.get());
-        return generator.emitPutStaticVar(resolveResult, m_ident, value.get());
+    if (generator.codeType() == GlobalCode) {
+        if (RegisterID* result = generator.emitInitGlobalConst(m_ident, value.get()))
+            return result;
     }
     if (generator.codeType() != EvalCode)
         return value.get();
 
-    // FIXME: While this code should only be hit in an eval block, it will assign
-    // to the wrong base if m_ident exists in an intervening with scope.
+    // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope.
     RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), resolveResult, m_ident);
     return generator.emitPutById(base.get(), m_ident, value.get());
 }
@@ -1699,10 +1659,11 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
         if (!propertyName) {
             propertyName = generator.newTemporary();
             RefPtr<RegisterID> protect = propertyName;
-            RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident);
+            NonlocalResolveInfo resolveVerifier;
+            RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident, resolveVerifier);
 
             generator.emitExpressionInfo(divot(), startOffset(), endOffset());
-            generator.emitPutById(base, ident, propertyName);
+            generator.emitPutToBase(base, ident, propertyName, resolveVerifier);
         } else {
             expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
             generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);
index da5682f..f34582b 100644 (file)
@@ -1524,7 +1524,12 @@ bool AbstractState::execute(unsigned indexInBlock)
         clobberWorld(node.codeOrigin, indexInBlock);
         forNode(nodeIndex).makeTop();
         break;
-            
+
+    case GarbageValue:
+        clobberWorld(node.codeOrigin, indexInBlock);
+        forNode(nodeIndex).makeTop();
+        break;
+
     case ForceOSRExit:
         node.setCanExit(true);
         m_isValid = false;
index 4869cf8..af0f280 100644 (file)
@@ -169,12 +169,17 @@ private:
     // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
     bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction);
     bool handleConstantInternalFunction(bool usesResult, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind);
+    NodeIndex handleGetByOffset(SpeculatedType, NodeIndex base, unsigned identifierNumber, PropertyOffset);
     void handleGetByOffset(
         int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
         PropertyOffset);
     void handleGetById(
         int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
         const GetByIdStatus&);
+
+    // Convert a set of ResolveOperations into graph nodes
+    bool parseResolveOperations(SpeculatedType, unsigned identifierNumber, unsigned operations, unsigned putToBaseOperation, NodeIndex* base, NodeIndex* value);
+
     // Prepare to parse a block.
     void prepareToParseBlock();
     // Parse a single basic block of bytecode instructions.
@@ -1143,6 +1148,8 @@ private:
         Vector<unsigned> m_identifierRemap;
         Vector<unsigned> m_constantRemap;
         Vector<unsigned> m_constantBufferRemap;
+        Vector<unsigned> m_resolveOperationRemap;
+        Vector<unsigned> m_putToBaseOperationRemap;
         
         // Blocks introduced by this code block, which need successor linking.
         // May include up to one basic block that includes the continuation after
@@ -1779,24 +1786,28 @@ bool ByteCodeParser::handleConstantInternalFunction(
     return false;
 }
 
-void ByteCodeParser::handleGetByOffset(
-    int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
-    PropertyOffset offset)
+NodeIndex ByteCodeParser::handleGetByOffset(SpeculatedType prediction, NodeIndex base, unsigned identifierNumber, PropertyOffset offset)
 {
     NodeIndex propertyStorage;
     if (isInlineOffset(offset))
         propertyStorage = base;
     else
         propertyStorage = addToGraph(GetButterfly, base);
-    set(destinationOperand,
-        addToGraph(
-            GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
-            propertyStorage));
-        
+    NodeIndex getByOffset = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage);
+
     StorageAccessData storageAccessData;
     storageAccessData.offset = indexRelativeToBase(offset);
     storageAccessData.identifierNumber = identifierNumber;
     m_graph.m_storageAccessData.append(storageAccessData);
+
+    return getByOffset;
+}
+
+void ByteCodeParser::handleGetByOffset(
+    int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
+    PropertyOffset offset)
+{
+    set(destinationOperand, handleGetByOffset(prediction, base, identifierNumber, offset));
 }
 
 void ByteCodeParser::handleGetById(
@@ -1860,10 +1871,174 @@ void ByteCodeParser::prepareToParseBlock()
     m_cellConstantNodes.clear();
 }
 
+bool ByteCodeParser::parseResolveOperations(SpeculatedType prediction, unsigned identifier, unsigned operations, unsigned putToBaseOperation, NodeIndex* base, NodeIndex* value)
+{
+    ResolveOperations* resolveOperations = m_codeBlock->resolveOperations(operations);
+    if (resolveOperations->isEmpty()) {
+        addToGraph(ForceOSRExit);
+        return false;
+    }
+    JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
+    int skipCount = 0;
+    bool skippedScopes = false;
+    bool setBase = false;
+    ResolveOperation* pc = resolveOperations->data();
+    NodeIndex localBase = 0;
+    bool resolvingBase = true;
+    while (resolvingBase) {
+        switch (pc->m_operation) {
+        case ResolveOperation::ReturnGlobalObjectAsBase:
+            *base = get(m_codeBlock->globalObjectConstant());
+            ASSERT(!value);
+            return true;
+
+        case ResolveOperation::SetBaseToGlobal:
+            *base = get(m_codeBlock->globalObjectConstant());
+            setBase = true;
+            resolvingBase = false;
+            ++pc;
+            break;
+
+        case ResolveOperation::SetBaseToUndefined:
+            *base = constantUndefined();
+            setBase = true;
+            resolvingBase = false;
+            ++pc;
+            break;
+
+        case ResolveOperation::SetBaseToScope:
+            localBase = addToGraph(GetScope, OpInfo(skipCount));
+            *base = localBase;
+            setBase = true;
+
+            resolvingBase = false;
+
+            // Reset the scope skipping as we've already loaded it
+            skippedScopes = false;
+            ++pc;
+            break;
+        case ResolveOperation::ReturnScopeAsBase:
+            *base = addToGraph(GetScope, OpInfo(skipCount));
+            ASSERT(!value);
+            return true;
+
+        case ResolveOperation::SkipTopScopeNode:
+            if (m_inlineStackTop->m_inlineCallFrame)
+                return false;
+            skipCount = 1;
+            skippedScopes = true;
+            ++pc;
+            break;
+
+        case ResolveOperation::SkipScopes:
+            if (m_inlineStackTop->m_inlineCallFrame)
+                return false;
+            skipCount += pc->m_scopesToSkip;
+            skippedScopes = true;
+            ++pc;
+            break;
+
+        case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope:
+            return false;
+
+        case ResolveOperation::Fail:
+            return false;
+
+        default:
+            resolvingBase = false;
+        }
+    }
+    if (skippedScopes)
+        localBase = addToGraph(GetScope, OpInfo(skipCount));
+
+    if (base && !setBase)
+        *base = localBase;
+
+    ASSERT(value);
+    ResolveOperation* resolveValueOperation = pc;
+    switch (resolveValueOperation->m_operation) {
+    case ResolveOperation::GetAndReturnGlobalProperty: {
+        ResolveGlobalStatus status = ResolveGlobalStatus::computeFor(m_inlineStackTop->m_profiledBlock, m_currentIndex, resolveValueOperation, m_codeBlock->identifier(identifier));
+        if (status.isSimple()) {
+            ASSERT(status.structure());
+
+            NodeIndex globalObjectNode = addStructureTransitionCheck(globalObject, status.structure());
+
+            if (status.specificValue()) {
+                ASSERT(status.specificValue().isCell());
+                *value = cellConstant(status.specificValue().asCell());
+            } else
+                *value = handleGetByOffset(prediction, globalObjectNode, identifier, status.offset());
+            return true;
+        }
+
+        NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction));
+        m_graph.m_resolveGlobalData.append(ResolveGlobalData());
+        ResolveGlobalData& data = m_graph.m_resolveGlobalData.last();
+        data.identifierNumber = identifier;
+        data.resolveOperationsIndex = operations;
+        data.putToBaseOperationIndex = putToBaseOperation;
+        data.resolvePropertyIndex = resolveValueOperation - resolveOperations->data();
+        *value = resolve;
+        return true;
+    }
+    case ResolveOperation::GetAndReturnGlobalVar: {
+        *value = addToGraph(GetGlobalVar,
+                            OpInfo(globalObject->assertRegisterIsInThisObject(pc->m_registerAddress)),
+                            OpInfo(prediction));
+        return true;
+    }
+    case ResolveOperation::GetAndReturnGlobalVarWatchable: {
+        SpeculatedType prediction = getPrediction();
+
+        JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
+
+        Identifier ident = m_codeBlock->identifier(identifier);
+        SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl());
+        if (!entry.couldBeWatched()) {
+            *value = addToGraph(GetGlobalVar, OpInfo(globalObject->assertRegisterIsInThisObject(pc->m_registerAddress)), OpInfo(prediction));
+            return true;
+        }
+
+        // The watchpoint is still intact! This means that we will get notified if the
+        // current value in the global variable changes. So, we can inline that value.
+        // Moreover, currently we can assume that this value is a JSFunction*, which
+        // implies that it's a cell. This simplifies things, since in general we'd have
+        // to use a JSConstant for non-cells and a WeakJSConstant for cells. So instead
+        // of having both cases we just assert that the value is a cell.
+
+        // NB. If it wasn't for CSE, GlobalVarWatchpoint would have no need for the
+        // register pointer. But CSE tracks effects on global variables by comparing
+        // register pointers. Because CSE executes multiple times while the backend
+        // executes once, we use the following performance trade-off:
+        // - The node refers directly to the register pointer to make CSE super cheap.
+        // - To perform backend code generation, the node only contains the identifier
+        //   number, from which it is possible to get (via a few average-time O(1)
+        //   lookups) to the WatchpointSet.
+
+        addToGraph(GlobalVarWatchpoint, OpInfo(globalObject->assertRegisterIsInThisObject(pc->m_registerAddress)), OpInfo(identifier));
+
+        JSValue specificValue = globalObject->registerAt(entry.getIndex()).get();
+        ASSERT(specificValue.isCell());
+        *value = cellConstant(specificValue.asCell());
+        return true;
+    }
+    case ResolveOperation::GetAndReturnScopedVar: {
+        NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, localBase);
+        *value = addToGraph(GetScopedVar, OpInfo(resolveValueOperation->m_offset), OpInfo(prediction), getScopeRegisters);
+        return true;
+    }
+    default:
+        CRASH();
+        return false;
+    }
+
+}
+
 bool ByteCodeParser::parseBlock(unsigned limit)
 {
     bool shouldContinueParsing = true;
-    
+
     Interpreter* interpreter = m_globalData->interpreter;
     Instruction* instructionsBegin = m_inlineStackTop->m_codeBlock->instructions().begin();
     unsigned blockBegin = m_currentIndex;
@@ -2364,26 +2539,6 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id);
             continue;
         }
-        case op_get_scoped_var: {
-            SpeculatedType prediction = getPrediction();
-            int dst = currentInstruction[1].u.operand;
-            int slot = currentInstruction[2].u.operand;
-            int depth = currentInstruction[3].u.operand;
-            NodeIndex getScope = addToGraph(GetScope, OpInfo(depth));
-            NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
-            NodeIndex getScopedVar = addToGraph(GetScopedVar, OpInfo(slot), OpInfo(prediction), getScopeRegisters);
-            set(dst, getScopedVar);
-            NEXT_OPCODE(op_get_scoped_var);
-        }
-        case op_put_scoped_var: {
-            int slot = currentInstruction[1].u.operand;
-            int depth = currentInstruction[2].u.operand;
-            int source = currentInstruction[3].u.operand;
-            NodeIndex getScope = addToGraph(GetScope, OpInfo(depth));
-            NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
-            addToGraph(PutScopedVar, OpInfo(slot), getScope, getScopeRegisters, get(source));
-            NEXT_OPCODE(op_put_scoped_var);
-        }
         case op_get_by_id:
         case op_get_by_id_out_of_line:
         case op_get_array_length: {
@@ -2510,75 +2665,15 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_put_by_id);
         }
 
-        case op_get_global_var: {
-            SpeculatedType prediction = getPrediction();
-            
-            JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
-
-            NodeIndex getGlobalVar = addToGraph(
-                GetGlobalVar,
-                OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)),
-                OpInfo(prediction));
-            set(currentInstruction[1].u.operand, getGlobalVar);
-            NEXT_OPCODE(op_get_global_var);
-        }
-                    
-        case op_get_global_var_watchable: {
-            SpeculatedType prediction = getPrediction();
-            
-            JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
-            
-            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
-            Identifier identifier = m_codeBlock->identifier(identifierNumber);
-            SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl());
-            if (!entry.couldBeWatched()) {
-                NodeIndex getGlobalVar = addToGraph(
-                    GetGlobalVar,
-                    OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)),
-                    OpInfo(prediction));
-                set(currentInstruction[1].u.operand, getGlobalVar);
-                NEXT_OPCODE(op_get_global_var_watchable);
-            }
-            
-            // The watchpoint is still intact! This means that we will get notified if the
-            // current value in the global variable changes. So, we can inline that value.
-            // Moreover, currently we can assume that this value is a JSFunction*, which
-            // implies that it's a cell. This simplifies things, since in general we'd have
-            // to use a JSConstant for non-cells and a WeakJSConstant for cells. So instead
-            // of having both cases we just assert that the value is a cell.
-            
-            // NB. If it wasn't for CSE, GlobalVarWatchpoint would have no need for the
-            // register pointer. But CSE tracks effects on global variables by comparing
-            // register pointers. Because CSE executes multiple times while the backend
-            // executes once, we use the following performance trade-off:
-            // - The node refers directly to the register pointer to make CSE super cheap.
-            // - To perform backend code generation, the node only contains the identifier
-            //   number, from which it is possible to get (via a few average-time O(1)
-            //   lookups) to the WatchpointSet.
-            
-            addToGraph(
-                GlobalVarWatchpoint,
-                OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)),
-                OpInfo(identifierNumber));
-            
-            JSValue specificValue = globalObject->registerAt(entry.getIndex()).get();
-            ASSERT(specificValue.isCell());
-            set(currentInstruction[1].u.operand, cellConstant(specificValue.asCell()));
-            
-            NEXT_OPCODE(op_get_global_var_watchable);
-        }
-
-        case op_put_global_var:
         case op_init_global_const: {
             NodeIndex value = get(currentInstruction[2].u.operand);
             addToGraph(
                 PutGlobalVar,
                 OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)),
                 value);
-            NEXT_OPCODE(op_put_global_var);
+            NEXT_OPCODE(op_init_global_const);
         }
 
-        case op_put_global_var_check:
         case op_init_global_const_check: {
             NodeIndex value = get(currentInstruction[2].u.operand);
             CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
@@ -2591,16 +2686,17 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                     PutGlobalVar,
                     OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)),
                     value);
-                NEXT_OPCODE(op_put_global_var_check);
+                NEXT_OPCODE(op_init_global_const_check);
             }
             addToGraph(
                 PutGlobalVarCheck,
                 OpInfo(codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)),
                 OpInfo(identifierNumber),
                 value);
-            NEXT_OPCODE(op_put_global_var_check);
+            NEXT_OPCODE(op_init_global_const_check);
         }
 
+
         // === Block terminators. ===
 
         case op_jmp: {
@@ -2869,69 +2965,175 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             addToGraph(Jump, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_ptr)));
             LAST_OPCODE(op_jneq_ptr);
 
-        case op_resolve: {
+        case op_resolve:
+        case op_resolve_global_property:
+        case op_resolve_global_var:
+        case op_resolve_scoped_var:
+        case op_resolve_scoped_var_on_top_scope:
+        case op_resolve_scoped_var_with_top_scope_check: {
             SpeculatedType prediction = getPrediction();
             
             unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
+            unsigned operations = m_inlineStackTop->m_resolveOperationRemap[currentInstruction[3].u.operand];
+            NodeIndex value = 0;
+            if (parseResolveOperations(prediction, identifier, operations, 0, 0, &value)) {
+                set(currentInstruction[1].u.operand, value);
+                NEXT_OPCODE(op_resolve);
+            }
+
+            NodeIndex resolve = addToGraph(Resolve, OpInfo(m_graph.m_resolveOperationsData.size()), OpInfo(prediction));
+            m_graph.m_resolveOperationsData.append(ResolveOperationData());
+            ResolveOperationData& data = m_graph.m_resolveOperationsData.last();
+            data.identifierNumber = identifier;
+            data.resolveOperationsIndex = operations;
 
-            NodeIndex resolve = addToGraph(Resolve, OpInfo(identifier), OpInfo(prediction));
             set(currentInstruction[1].u.operand, resolve);
 
             NEXT_OPCODE(op_resolve);
         }
 
+        case op_put_to_base_variable:
+        case op_put_to_base: {
+            unsigned base = currentInstruction[1].u.operand;
+            unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
+            unsigned value = currentInstruction[3].u.operand;
+            unsigned operation = m_inlineStackTop->m_putToBaseOperationRemap[currentInstruction[4].u.operand];
+            PutToBaseOperation* putToBase = m_codeBlock->putToBaseOperation(operation);
+
+            if (putToBase->m_isDynamic) {
+                addToGraph(Phantom, get(base));
+                addToGraph(ForceOSRExit);
+                NEXT_OPCODE(op_put_to_base);
+            }
+
+            switch (putToBase->m_kind) {
+            case PutToBaseOperation::Uninitialised:
+                addToGraph(Phantom, get(base));
+                addToGraph(ForceOSRExit);
+                break;
+
+            case PutToBaseOperation::GlobalVariablePutChecked: {
+                CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
+                JSGlobalObject* globalObject = codeBlock->globalObject();
+                SymbolTableEntry entry = globalObject->symbolTable()->get(m_codeBlock->identifier(identifier).impl());
+                if (entry.couldBeWatched()) {
+                    addToGraph(PutGlobalVarCheck,
+                               OpInfo(codeBlock->globalObject()->assertRegisterIsInThisObject(putToBase->m_registerAddress)),
+                               OpInfo(identifier),
+                               get(value));
+                    break;
+                }
+            }
+            case PutToBaseOperation::GlobalVariablePut:
+                addToGraph(PutGlobalVar,
+                           OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(putToBase->m_registerAddress)),
+                           get(value));
+                break;
+            case PutToBaseOperation::VariablePut: {
+                addToGraph(Phantom, get(base));
+                NodeIndex getScope = addToGraph(GetScope, OpInfo(putToBase->m_scopeDepth));
+                NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
+                addToGraph(PutScopedVar, OpInfo(putToBase->m_offset), getScope, getScopeRegisters, get(value));
+                break;
+            }
+            case PutToBaseOperation::GlobalPropertyPut: {
+                if (!putToBase->m_structure) {
+                    addToGraph(Phantom, get(base));
+                    addToGraph(ForceOSRExit);
+                    NEXT_OPCODE(op_put_to_base);
+                }
+                NodeIndex baseNode = get(base);
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putToBase->m_structure.get())), baseNode);
+                NodeIndex propertyStorage;
+                if (isInlineOffset(putToBase->m_offset))
+                    propertyStorage = baseNode;
+                else
+                    propertyStorage = addToGraph(GetButterfly, baseNode);
+                addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), propertyStorage, baseNode, get(value));
+
+                StorageAccessData storageAccessData;
+                storageAccessData.offset = indexRelativeToBase(putToBase->m_offset);
+                storageAccessData.identifierNumber = identifier;
+                m_graph.m_storageAccessData.append(storageAccessData);
+                break;
+            }
+            case PutToBaseOperation::Readonly:
+            case PutToBaseOperation::Generic:
+                addToGraph(Phantom, get(base));
+                addToGraph(PutById, OpInfo(identifier), get(base), get(value));
+            }
+            NEXT_OPCODE(op_put_to_base);
+        }
+
+        case op_resolve_base_to_global:
+        case op_resolve_base_to_global_dynamic:
+        case op_resolve_base_to_scope:
+        case op_resolve_base_to_scope_with_top_scope_check:
         case op_resolve_base: {
             SpeculatedType prediction = getPrediction();
             
             unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
+            unsigned operations = m_inlineStackTop->m_resolveOperationRemap[currentInstruction[4].u.operand];
+            unsigned putToBaseOperation = m_inlineStackTop->m_putToBaseOperationRemap[currentInstruction[5].u.operand];
 
-            NodeIndex resolve = addToGraph(currentInstruction[3].u.operand ? ResolveBaseStrictPut : ResolveBase, OpInfo(identifier), OpInfo(prediction));
+            NodeIndex base = 0;
+            if (parseResolveOperations(prediction, identifier, operations, 0, &base, 0)) {
+                set(currentInstruction[1].u.operand, base);
+                NEXT_OPCODE(op_resolve_base);
+            }
+
+            NodeIndex resolve = addToGraph(currentInstruction[3].u.operand ? ResolveBaseStrictPut : ResolveBase, OpInfo(m_graph.m_resolveOperationsData.size()), OpInfo(prediction));
+            m_graph.m_resolveOperationsData.append(ResolveOperationData());
+            ResolveOperationData& data = m_graph.m_resolveOperationsData.last();
+            data.identifierNumber = identifier;
+            data.resolveOperationsIndex = operations;
+            data.putToBaseOperationIndex = putToBaseOperation;
+        
             set(currentInstruction[1].u.operand, resolve);
 
             NEXT_OPCODE(op_resolve_base);
         }
-            
-        case op_resolve_global: {
+        case op_resolve_with_base: {
             SpeculatedType prediction = getPrediction();
-            
-            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[
-                currentInstruction[2].u.operand];
-            
-            ResolveGlobalStatus status = ResolveGlobalStatus::computeFor(
-                m_inlineStackTop->m_profiledBlock, m_currentIndex,
-                m_codeBlock->identifier(identifierNumber));
-            if (status.isSimple()) {
-                ASSERT(status.structure());
-                
-                NodeIndex globalObject = addStructureTransitionCheck(
-                    m_inlineStackTop->m_codeBlock->globalObject(), status.structure());
-                
-                if (status.specificValue()) {
-                    ASSERT(status.specificValue().isCell());
-                    
-                    set(currentInstruction[1].u.operand,
-                        cellConstant(status.specificValue().asCell()));
-                } else {
-                    handleGetByOffset(
-                        currentInstruction[1].u.operand, prediction, globalObject,
-                        identifierNumber, status.offset());
-                }
-                
-                m_globalResolveNumber++; // Skip over the unused global resolve info.
-                
-                NEXT_OPCODE(op_resolve_global);
+            unsigned baseDst = currentInstruction[1].u.operand;
+            unsigned valueDst = currentInstruction[2].u.operand;
+            unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
+            unsigned operations = m_inlineStackTop->m_resolveOperationRemap[currentInstruction[4].u.operand];
+            unsigned putToBaseOperation = m_inlineStackTop->m_putToBaseOperationRemap[currentInstruction[5].u.operand];
+
+            NodeIndex base = 0;
+            NodeIndex value = 0;
+            if (parseResolveOperations(prediction, identifier, operations, putToBaseOperation, &base, &value)) {
+                set(baseDst, base);
+                set(valueDst, value);
+            } else {
+                addToGraph(ForceOSRExit);
+                set(baseDst, addToGraph(GarbageValue));
+                set(valueDst, addToGraph(GarbageValue));
             }
-            
-            NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction));
-            m_graph.m_resolveGlobalData.append(ResolveGlobalData());
-            ResolveGlobalData& data = m_graph.m_resolveGlobalData.last();
-            data.identifierNumber = identifierNumber;
-            data.resolveInfoIndex = m_globalResolveNumber++;
-            set(currentInstruction[1].u.operand, resolve);
 
-            NEXT_OPCODE(op_resolve_global);
+            NEXT_OPCODE(op_resolve_with_base);
         }
+        case op_resolve_with_this: {
+            SpeculatedType prediction = getPrediction();
+            unsigned baseDst = currentInstruction[1].u.operand;
+            unsigned valueDst = currentInstruction[2].u.operand;
+            unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
+            unsigned operations = m_inlineStackTop->m_resolveOperationRemap[currentInstruction[4].u.operand];
+
+            NodeIndex base = 0;
+            NodeIndex value = 0;
+            if (parseResolveOperations(prediction, identifier, operations, 0, &base, &value)) {
+                set(baseDst, base);
+                set(valueDst, value);
+            } else {
+                addToGraph(ForceOSRExit);
+                set(baseDst, addToGraph(GarbageValue));
+                set(valueDst, addToGraph(GarbageValue));
+            }
 
+            NEXT_OPCODE(op_resolve_with_this);
+        }
         case op_loop_hint: {
             // Baseline->DFG OSR jumps between loop hints. The DFG assumes that Baseline->DFG
             // OSR can only happen at basic block boundaries. Assert that these two statements
@@ -2943,7 +3145,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             // block. Hence, machine code block = true code block = not inline code block.
             if (!m_inlineStackTop->m_caller)
                 m_currentBlock->isOSRTarget = true;
-            
+
             // Emit a phantom node to ensure that there is a placeholder node for this bytecode
             // op.
             addToGraph(Phantom);
@@ -3331,6 +3533,8 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
         m_identifierRemap.resize(codeBlock->numberOfIdentifiers());
         m_constantRemap.resize(codeBlock->numberOfConstantRegisters());
         m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers());
+        m_resolveOperationRemap.resize(codeBlock->numberOfResolveOperations());
+        m_putToBaseOperationRemap.resize(codeBlock->numberOfPutToBaseOperations());
 
         for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i) {
             StringImpl* rep = codeBlock->identifier(i).impl();
@@ -3357,8 +3561,11 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
             }
             m_constantRemap[i] = result.iterator->value;
         }
-        for (unsigned i = 0; i < codeBlock->numberOfGlobalResolveInfos(); ++i)
-            byteCodeParser->m_codeBlock->addGlobalResolveInfo(std::numeric_limits<unsigned>::max());
+        for (size_t i = 0; i < codeBlock->numberOfResolveOperations(); i++) {
+            uint32_t newResolve = byteCodeParser->m_codeBlock->addResolve();
+            m_resolveOperationRemap[i] = newResolve;
+            byteCodeParser->m_codeBlock->resolveOperations(newResolve)->append(*codeBlock->resolveOperations(i));
+        }
         for (unsigned i = 0; i < codeBlock->numberOfConstantBuffers(); ++i) {
             // If we inline the same code block multiple times, we don't want to needlessly
             // duplicate its constant buffers.
@@ -3373,6 +3580,11 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
             m_constantBufferRemap[i] = newIndex;
             byteCodeParser->m_constantBufferCache.add(ConstantBufferKey(codeBlock, i), newIndex);
         }
+        for (size_t i = 0; i < codeBlock->numberOfPutToBaseOperations(); i++) {
+            uint32_t putToBaseResolve = byteCodeParser->m_codeBlock->addPutToBase();
+            m_putToBaseOperationRemap[i] = putToBaseResolve;
+            *byteCodeParser->m_codeBlock->putToBaseOperation(putToBaseResolve) = *codeBlock->putToBaseOperation(i);
+        }
         
         m_callsiteBlockHeadNeedsLinking = true;
     } else {
@@ -3389,6 +3601,8 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
         m_identifierRemap.resize(codeBlock->numberOfIdentifiers());
         m_constantRemap.resize(codeBlock->numberOfConstantRegisters());
         m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers());
+        m_resolveOperationRemap.resize(codeBlock->numberOfResolveOperations());
+        m_putToBaseOperationRemap.resize(codeBlock->numberOfPutToBaseOperations());
 
         for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i)
             m_identifierRemap[i] = i;
@@ -3396,6 +3610,10 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
             m_constantRemap[i] = i + FirstConstantRegisterIndex;
         for (size_t i = 0; i < codeBlock->numberOfConstantBuffers(); ++i)
             m_constantBufferRemap[i] = i;
+        for (size_t i = 0; i < codeBlock->numberOfResolveOperations(); ++i)
+            m_resolveOperationRemap[i] = i;
+        for (size_t i = 0; i < codeBlock->numberOfPutToBaseOperations(); ++i)
+            m_putToBaseOperationRemap[i] = i;
 
         m_callsiteBlockHeadNeedsLinking = false;
     }
index dc6f7aa..e80cc28 100644 (file)
@@ -68,6 +68,48 @@ inline bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
 }
 
 // Opcode checking.
+inline bool canInlineResolveOperations(OpcodeID opcode, ResolveOperations* operations)
+{
+    // Don't try to inline a resolve for which we have no information
+    if (operations->isEmpty())
+        return false;
+
+    for (unsigned i = 0; i < operations->size(); i++) {
+        switch (operations->data()[i].m_operation) {
+        case ResolveOperation::ReturnGlobalObjectAsBase:
+        case ResolveOperation::SetBaseToGlobal:
+        case ResolveOperation::SetBaseToUndefined:
+        case ResolveOperation::GetAndReturnGlobalProperty:
+        case ResolveOperation::GetAndReturnGlobalVar:
+        case ResolveOperation::GetAndReturnGlobalVarWatchable:
+            continue;
+
+        case ResolveOperation::Fail:
+            // The DFG can handle generic cases of failed resolves
+            ASSERT(opcode != op_resolve_base_to_global_dynamic);
+            ASSERT(opcode != op_resolve_base_to_scope_with_top_scope_check);
+            ASSERT(opcode != op_resolve_base_to_global);
+            ASSERT(opcode != op_resolve_base_to_scope);
+            if (opcode != op_resolve && opcode != op_resolve_base)
+                return false;
+
+        case ResolveOperation::SkipTopScopeNode:
+        case ResolveOperation::SkipScopes:
+        case ResolveOperation::SetBaseToScope:
+        case ResolveOperation::ReturnScopeAsBase:
+        case ResolveOperation::GetAndReturnScopedVar:
+            // These opcodes would be easy to support with inlining, but we currently don't do it.
+            // The issue is that the scope chain will not be set correctly.
+            return false;
+
+        case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope:
+            // This would be easy to support in all cases.
+            return false;
+        }
+    }
+    return true;
+}
+
 inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instruction*)
 {
     switch (opcodeID) {
@@ -116,8 +158,6 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi
     case op_get_by_val:
     case op_put_by_val:
     case op_method_check:
-    case op_get_scoped_var:
-    case op_put_scoped_var:
     case op_get_by_id:
     case op_get_by_id_out_of_line:
     case op_get_array_length:
@@ -127,10 +167,6 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi
     case op_put_by_id_transition_direct_out_of_line:
     case op_put_by_id_transition_normal:
     case op_put_by_id_transition_normal_out_of_line:
-    case op_get_global_var:
-    case op_get_global_var_watchable:
-    case op_put_global_var:
-    case op_put_global_var_check:
     case op_init_global_const:
     case op_init_global_const_check:
     case op_jmp:
@@ -157,9 +193,6 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi
     case op_ret:
     case op_end:
     case op_call_put_result:
-    case op_resolve:
-    case op_resolve_base:
-    case op_resolve_global:
     case op_new_object:
     case op_new_array:
     case op_new_array_with_size:
@@ -181,11 +214,30 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi
     case op_get_argument_by_val:
     case op_get_arguments_length:
     case op_jneq_ptr:
+    case op_put_to_base_variable:
+    case op_put_to_base:
         return CanCompile;
         
     case op_call_varargs:
         return ShouldProfile;
 
+    case op_resolve:
+    case op_resolve_global_property:
+    case op_resolve_global_var:
+    case op_resolve_scoped_var:
+    case op_resolve_scoped_var_on_top_scope:
+    case op_resolve_scoped_var_with_top_scope_check:
+        return CanCompile;
+
+    case op_resolve_base_to_global:
+    case op_resolve_base_to_global_dynamic:
+    case op_resolve_base_to_scope:
+    case op_resolve_base_to_scope_with_top_scope_check:
+    case op_resolve_base:
+    case op_resolve_with_base:
+    case op_resolve_with_this:
+        return CanCompile;
+
     default:
         return CannotCompile;
     }
@@ -194,13 +246,22 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi
 inline bool canInlineOpcode(OpcodeID opcodeID, CodeBlock* codeBlock, Instruction* pc)
 {
     switch (opcodeID) {
-        
-    // These opcodes would be easy to support with inlining, but we currently don't do it.
-    // The issue is that the scope chain will not be set correctly.
-    case op_get_scoped_var:
-    case op_put_scoped_var:
     case op_resolve:
+    case op_resolve_global_property:
+    case op_resolve_global_var:
+    case op_resolve_scoped_var:
+    case op_resolve_scoped_var_on_top_scope:
+    case op_resolve_scoped_var_with_top_scope_check:
+        return canInlineResolveOperations(opcodeID, codeBlock->resolveOperations(pc[3].u.operand));
+
+    case op_resolve_base_to_global:
+    case op_resolve_base_to_global_dynamic:
+    case op_resolve_base_to_scope:
+    case op_resolve_base_to_scope_with_top_scope_check:
     case op_resolve_base:
+    case op_resolve_with_base:
+    case op_resolve_with_this:
+        return canInlineResolveOperations(opcodeID, codeBlock->resolveOperations(pc[4].u.operand));
         
     // Inlining doesn't correctly remap regular expression operands.
     case op_new_regexp:
index 212c8bb..b2c754f 100644 (file)
@@ -57,10 +57,23 @@ struct StorageAccessData {
 
 struct ResolveGlobalData {
     unsigned identifierNumber;
-    unsigned resolveInfoIndex;
+    unsigned resolveOperationsIndex;
+    unsigned putToBaseOperationIndex;
+    unsigned resolvePropertyIndex;
 };
 
-// 
+struct ResolveOperationData {
+    unsigned identifierNumber;
+    unsigned resolveOperationsIndex;
+    unsigned putToBaseOperationIndex;
+};
+
+struct PutToBaseOperationData {
+    unsigned putToBaseOperationIndex;
+};
+
+
+//
 // === Graph ===
 //
 // The dataflow graph is an ordered vector of nodes.
@@ -669,6 +682,8 @@ public:
     Vector<Edge, 16> m_varArgChildren;
     Vector<StorageAccessData> m_storageAccessData;
     Vector<ResolveGlobalData> m_resolveGlobalData;
+    Vector<ResolveOperationData> m_resolveOperationsData;
+    Vector<PutToBaseOperationData> m_putToBaseOperationData;
     Vector<NodeIndex, 8> m_arguments;
     SegmentedVector<VariableAccessData, 16> m_variableAccessData;
     SegmentedVector<ArgumentPosition, 8> m_argumentPositions;
index df6191e..40b3ed7 100644 (file)
@@ -352,9 +352,6 @@ struct Node {
         case GetByIdFlush:
         case PutById:
         case PutByIdDirect:
-        case Resolve:
-        case ResolveBase:
-        case ResolveBaseStrictPut:
             return true;
         default:
             return false;
@@ -373,6 +370,12 @@ struct Node {
         return m_opInfo;
     }
 
+    unsigned resolveOperationsDataIndex()
+    {
+        ASSERT(op() == Resolve || op() == ResolveBase || op() == ResolveBaseStrictPut);
+        return m_opInfo;
+    }
+
     bool hasArithNodeFlags()
     {
         switch (op()) {
index 9c93a8b..1d24606 100644 (file)
@@ -234,6 +234,8 @@ namespace JSC { namespace DFG {
     macro(Throw, NodeMustGenerate) \
     macro(ThrowReferenceError, NodeMustGenerate) \
     \
+    macro(GarbageValue, NodeResultJS | NodeClobbersWorld) \
+    \
     /* This is a pseudo-terminal. It means that execution should fall out of DFG at */\
     /* this point, but execution does continue in the basic block - just in a */\
     /* different compiler. */\
index b370172..6560088 100644 (file)
@@ -45,9 +45,9 @@ OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAVal
     , m_kind(kind)
     , m_count(0)
     , m_streamIndex(streamIndex)
-    , m_lastSetOperand(jit->m_lastSetOperand)
 {
     ASSERT(m_codeOrigin.isSet());
+    m_setOperands.append(jit->m_lastSetOperand);
 }
 
 bool OSRExit::considerAddingAsFrequentExitSiteSlow(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock)
index cd2434c..0ecefe3 100644 (file)
@@ -110,9 +110,9 @@ struct OSRExit {
     }
     
     unsigned m_streamIndex;
-    int m_lastSetOperand;
+    Vector<int, 1> m_setOperands;
     
-    RefPtr<ValueRecoveryOverride> m_valueRecoveryOverride;
+    Vector<RefPtr<ValueRecoveryOverride>, 1> m_valueRecoveryOverrides;
 
 private:
     bool considerAddingAsFrequentExitSiteSlow(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock);
index 2ce1c88..55a903c 100644 (file)
@@ -70,11 +70,10 @@ void compileOSRExit(ExecState* exec)
     Operands<ValueRecovery> operands;
     codeBlock->variableEventStream().reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->minifiedDFG(), exit.m_streamIndex, operands);
     
-    // There may be an override, for forward speculations.
-    if (!!exit.m_valueRecoveryOverride) {
-        operands.setOperand(
-            exit.m_valueRecoveryOverride->operand, exit.m_valueRecoveryOverride->recovery);
-    }
+    // There may be overrides, for forward speculations.
+    for (size_t i = 0; i < exit.m_valueRecoveryOverrides.size(); i++)
+        operands.setOperand(exit.m_valueRecoveryOverrides[i]->operand, exit.m_valueRecoveryOverrides[i]->recovery);
+
     
     SpeculationRecovery* recovery = 0;
     if (exit.m_recoveryIndex)
index cb13dcc..98779a8 100644 (file)
@@ -675,9 +675,9 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
     
     // 15) Load the result of the last bytecode operation into regT0.
     
-    if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) {
-        m_jit.load32(AssemblyHelpers::payloadFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister);
-        m_jit.load32(AssemblyHelpers::tagFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister2);
+    for (size_t i = 0; i < exit.m_setOperands.size(); i++) {
+        m_jit.load32(AssemblyHelpers::payloadFor((VirtualRegister)exit.m_setOperands[i]), GPRInfo::cachedResultRegister);
+        m_jit.load32(AssemblyHelpers::tagFor((VirtualRegister)exit.m_setOperands[i]), GPRInfo::cachedResultRegister2);
     }
     
     // 16) Adjust the call frame pointer.
index 968e56f..03355b2 100644 (file)
@@ -633,10 +633,9 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
     }
     
     // 16) Load the result of the last bytecode operation into regT0.
-    
-    if (exit.m_lastSetOperand != std::numeric_limits<int>::max())
-        m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister);
-    
+    for (size_t i = 0; i < exit.m_setOperands.size(); i++)
+        m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_setOperands[i]), GPRInfo::cachedResultRegister);
+
     // 17) Adjust the call frame pointer.
     
     if (exit.m_codeOrigin.inlineCallFrame)
index db736fe..11c2c1c 100644 (file)
@@ -1059,35 +1059,38 @@ void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet)
     watchpointSet->notifyWrite();
 }
 
-EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName)
+EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName, ResolveOperations* operations)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
-    return JSValue::encode(JSScope::resolve(exec, *propertyName));
+    return JSValue::encode(JSScope::resolve(exec, *propertyName, operations));
 }
 
-EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* propertyName)
+EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* propertyName, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
     
-    return JSValue::encode(JSScope::resolveBase(exec, *propertyName, false));
+    return JSValue::encode(JSScope::resolveBase(exec, *propertyName, false, operations, putToBaseOperations));
 }
 
-EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName)
+EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
     
-    return JSValue::encode(JSScope::resolveBase(exec, *propertyName, true));
+    return JSValue::encode(JSScope::resolveBase(exec, *propertyName, true, operations, putToBaseOperations));
 }
 
-EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, GlobalResolveInfo* resolveInfo, JSGlobalObject* globalObject, Identifier* propertyName)
+EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, ResolveOperation* resolveOperation, JSGlobalObject* globalObject, Identifier* propertyName)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
-
-    return JSValue::encode(JSScope::resolveGlobal(exec, *propertyName, globalObject, &resolveInfo->structure, &resolveInfo->offset));
+    ASSERT(globalObject);
+    UNUSED_PARAM(resolveOperation);
+    UNUSED_PARAM(globalObject);
+    ASSERT(resolveOperation->m_operation == ResolveOperation::GetAndReturnGlobalProperty);
+    return JSValue::encode(JSScope::resolveGlobal(exec, *propertyName, globalObject, resolveOperation));
 }
 
 EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
index b6530b7..8d2beac 100644 (file)
@@ -33,8 +33,6 @@
 
 namespace JSC {
 
-struct GlobalResolveInfo;
-
 namespace DFG {
 
 extern "C" {
@@ -66,8 +64,10 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EAZ)(ExecState*, JSArray*,
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
-typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGriJsgI)(ExecState*, GlobalResolveInfo*, JSGlobalObject*, Identifier*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGriJsgI)(ExecState*, ResolveOperation*, JSGlobalObject*, Identifier*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EI)(ExecState*, Identifier*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EIRo)(ExecState*, Identifier*, ResolveOperations*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EIRoPtbo)(ExecState*, Identifier*, ResolveOperations*, PutToBaseOperation*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJ)(ExecState*, EncodedJSValue);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJI)(ExecState*, EncodedJSValue, Identifier*);
@@ -131,10 +131,10 @@ EncodedJSValue DFG_OPERATION operationGetByIdOptimize(ExecState*, EncodedJSValue
 EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState*, JSCell*, PropertySlot::GetValueFunc, Identifier*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationCallGetter(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
 void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) WTF_INTERNAL;
-EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*) WTF_INTERNAL;
-EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*) WTF_INTERNAL;
-EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifier*) WTF_INTERNAL;
-EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, JSGlobalObject*, Identifier*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*, ResolveOperations*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*, ResolveOperations*, PutToBaseOperation*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifier*, ResolveOperations*, PutToBaseOperation*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, ResolveOperation*, JSGlobalObject*, Identifier*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t) WTF_INTERNAL;
 char* DFG_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
index d76fd80..f6b7e55 100644 (file)
@@ -674,6 +674,7 @@ private:
         case CheckNumber:
         case CheckArgumentsNotCreated:
         case GlobalVarWatchpoint:
+        case GarbageValue:
             changed |= mergeDefaultFlags(node);
             break;
             
index 6fb185c..8a83043 100644 (file)
@@ -299,7 +299,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
     Structure* structure = baseCell->structure();
     if (!slot.isCacheable())
         return false;
-    if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching())
+    if (!structure->propertyAccessesAreCacheable())
         return false;
 
     // Optimize self access.
index 850d5aa..95c39d5 100644 (file)
@@ -163,7 +163,9 @@ void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecov
 #endif
     
     unsigned setLocalIndexInBlock = m_indexInBlock + 1;
-    
+
+    OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
+
     Node* setLocal = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock));
     bool hadInt32ToDouble = false;
     
@@ -173,7 +175,7 @@ void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecov
     }
     if (setLocal->op() == Flush || setLocal->op() == Phantom)
         setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
-        
+    
     if (!!valueRecovery) {
         if (hadInt32ToDouble)
             ASSERT(at(setLocal->child1()).child1() == m_compileIndex);
@@ -188,16 +190,34 @@ void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecov
         // We're at an inlined return. Use a backward speculation instead.
         return;
     }
+
+    exit.m_setOperands[0] = setLocal->local();
+    while (nextNode->codeOrigin == at(m_compileIndex).codeOrigin) {
+        ++setLocalIndexInBlock;
+        Node* nextSetLocal = nextNode;
+        if (nextSetLocal->op() == Int32ToDouble)
+            nextSetLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
+
+        if (nextSetLocal->op() == Flush || nextSetLocal->op() == Phantom)
+            nextSetLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
+
+        nextNode = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 1));
+        ASSERT(nextNode->op() != Jump || nextNode->codeOrigin != at(m_compileIndex).codeOrigin);
+        ASSERT(nextSetLocal->op() == SetLocal);
+        exit.m_setOperands.append(nextSetLocal->local());
+    }
+
     ASSERT(nextNode->codeOrigin != at(m_compileIndex).codeOrigin);
-        
-    OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
+
     exit.m_codeOrigin = nextNode->codeOrigin;
         
     if (!valueRecovery)
         return;
-    exit.m_lastSetOperand = setLocal->local();
-    exit.m_valueRecoveryOverride = adoptRef(
-        new ValueRecoveryOverride(setLocal->local(), valueRecovery));
+
+    ASSERT(exit.m_setOperands.size() == 1);
+    for (size_t i = 0; i < exit.m_setOperands.size(); i++)
+        exit.m_valueRecoveryOverrides.append(adoptRef(new ValueRecoveryOverride(exit.m_setOperands[i], valueRecovery)));
+
 }
 
 JumpReplacementWatchpoint* SpeculativeJIT::forwardSpeculationWatchpoint(ExitKind kind)
index 90b6d48..5070a63 100644 (file)
@@ -830,6 +830,16 @@ public:
         return &m_jit.codeBlock()->identifier(index);
     }
 
+    ResolveOperations* resolveOperations(unsigned index)
+    {
+        return m_jit.codeBlock()->resolveOperations(index);
+    }
+
+    PutToBaseOperation* putToBaseOperation(unsigned index)
+    {
+        return m_jit.codeBlock()->putToBaseOperation(index);
+    }
+
     // Spill all VirtualRegisters back to the JSStack.
     void flushRegisters()
     {
@@ -1209,6 +1219,16 @@ public:
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier));
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(J_DFGOperation_EIRo operation, GPRReg result, Identifier* identifier, ResolveOperations* operations)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier), TrustedImmPtr(operations));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(J_DFGOperation_EIRoPtbo operation, GPRReg result, Identifier* identifier, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier), TrustedImmPtr(operations), TrustedImmPtr(putToBaseOperations));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(J_DFGOperation_EA operation, GPRReg result, GPRReg arg1)
     {
         m_jit.setupArgumentsWithExecState(arg1);
@@ -1707,6 +1727,19 @@ public:
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG imm, TrustedImm32(JSValue::Int32Tag), arg2Payload, arg2Tag);
         return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
     }
+
+    JITCompiler::Call callOperation(J_DFGOperation_EIRo operation, GPRReg resultTag, GPRReg resultPayload, Identifier* identifier, ResolveOperations* operations)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier), TrustedImmPtr(operations));
+        return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+    }
+
+    JITCompiler::Call callOperation(J_DFGOperation_EIRoPtbo operation, GPRReg resultTag, GPRReg resultPayload, Identifier* identifier, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier), TrustedImmPtr(operations), TrustedImmPtr(putToBaseOperations));
+        return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+    }
+
     JITCompiler::Call callOperation(J_DFGOperation_ECJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag);
index 41fe8db..0887317 100644 (file)
@@ -4288,7 +4288,8 @@ void SpeculativeJIT::compile(Node& node)
         flushRegisters();
         GPRResult resultPayload(this);
         GPRResult2 resultTag(this);
-        callOperation(operationResolve, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
+        ResolveOperationData& data = m_jit.graph().m_resolveOperationsData[node.resolveOperationsDataIndex()];
+        callOperation(operationResolve, resultTag.gpr(), resultPayload.gpr(), identifier(data.identifierNumber), resolveOperations(data.resolveOperationsIndex));
         jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
         break;
     }
@@ -4297,7 +4298,8 @@ void SpeculativeJIT::compile(Node& node)
         flushRegisters();
         GPRResult resultPayload(this);
         GPRResult2 resultTag(this);
-        callOperation(operationResolveBase, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
+        ResolveOperationData& data = m_jit.graph().m_resolveOperationsData[node.resolveOperationsDataIndex()];
+        callOperation(operationResolveBase, resultTag.gpr(), resultPayload.gpr(), identifier(data.identifierNumber), resolveOperations(data.resolveOperationsIndex), putToBaseOperation(data.putToBaseOperationIndex));
         jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
         break;
     }
@@ -4306,7 +4308,8 @@ void SpeculativeJIT::compile(Node& node)
         flushRegisters();
         GPRResult resultPayload(this);
         GPRResult2 resultTag(this);
-        callOperation(operationResolveBaseStrictPut, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
+        ResolveOperationData& data = m_jit.graph().m_resolveOperationsData[node.resolveOperationsDataIndex()];
+        callOperation(operationResolveBaseStrictPut, resultTag.gpr(), resultPayload.gpr(), identifier(data.identifierNumber), resolveOperations(data.resolveOperationsIndex), putToBaseOperation(data.putToBaseOperationIndex));
         jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
         break;
     }
@@ -4323,18 +4326,18 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg resultPayloadGPR = resultPayload.gpr();
 
         ResolveGlobalData& data = m_jit.graph().m_resolveGlobalData[node.resolveGlobalDataIndex()];
-        GlobalResolveInfo* resolveInfoAddress = &(m_jit.codeBlock()->globalResolveInfo(data.resolveInfoIndex));
+        ResolveOperation* resolveOperationAddress = &(m_jit.codeBlock()->resolveOperations(data.resolveOperationsIndex)->data()[data.resolvePropertyIndex]);
 
         // Check Structure of global object
         m_jit.move(JITCompiler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectGPR);
-        m_jit.move(JITCompiler::TrustedImmPtr(resolveInfoAddress), resolveInfoGPR);
-        m_jit.loadPtr(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), resultPayloadGPR);
+        m_jit.move(JITCompiler::TrustedImmPtr(resolveOperationAddress), resolveInfoGPR);
+        m_jit.loadPtr(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(ResolveOperation, m_structure)), resultPayloadGPR);
 
         JITCompiler::Jump structuresNotMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultPayloadGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
 
         // Fast case
         m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::butterflyOffset()), resultPayloadGPR);
-        m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
+        m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(ResolveOperation, m_offset)), resolveInfoGPR);
 #if DFG_ENABLE(JIT_ASSERT)
         JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(firstOutOfLineOffset));
         m_jit.breakpoint();
@@ -4739,6 +4742,11 @@ void SpeculativeJIT::compile(Node& node)
         compileNewFunctionExpression(node);
         break;
 
+    case GarbageValue:
+        // We should never get to the point of code emission for a GarbageValue
+        CRASH();
+        break;
+
     case ForceOSRExit: {
         terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
         break;
index daca71d..6796561 100644 (file)
@@ -4263,7 +4263,8 @@ void SpeculativeJIT::compile(Node& node)
     case Resolve: {
         flushRegisters();
         GPRResult result(this);
-        callOperation(operationResolve, result.gpr(), identifier(node.identifierNumber()));
+        ResolveOperationData& data = m_jit.graph().m_resolveOperationsData[node.resolveOperationsDataIndex()];
+        callOperation(operationResolve, result.gpr(), identifier(data.identifierNumber), resolveOperations(data.resolveOperationsIndex));
         jsValueResult(result.gpr(), m_compileIndex);
         break;
     }
@@ -4271,7 +4272,8 @@ void SpeculativeJIT::compile(Node& node)
     case ResolveBase: {
         flushRegisters();
         GPRResult result(this);
-        callOperation(operationResolveBase, result.gpr(), identifier(node.identifierNumber()));
+        ResolveOperationData& data = m_jit.graph().m_resolveOperationsData[node.resolveOperationsDataIndex()];
+        callOperation(operationResolveBase, result.gpr(), identifier(data.identifierNumber), resolveOperations(data.resolveOperationsIndex), putToBaseOperation(data.putToBaseOperationIndex));
         jsValueResult(result.gpr(), m_compileIndex);
         break;
     }
@@ -4279,7 +4281,8 @@ void SpeculativeJIT::compile(Node& node)
     case ResolveBaseStrictPut: {
         flushRegisters();
         GPRResult result(this);
-        callOperation(operationResolveBaseStrictPut, result.gpr(), identifier(node.identifierNumber()));
+        ResolveOperationData& data = m_jit.graph().m_resolveOperationsData[node.resolveOperationsDataIndex()];
+        callOperation(operationResolveBaseStrictPut, result.gpr(), identifier(data.identifierNumber), resolveOperations(data.resolveOperationsIndex), putToBaseOperation(data.putToBaseOperationIndex));
         jsValueResult(result.gpr(), m_compileIndex);
         break;
     }
@@ -4294,16 +4297,16 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg resultGPR = result.gpr();
 
         ResolveGlobalData& data = m_jit.graph().m_resolveGlobalData[node.resolveGlobalDataIndex()];
-        GlobalResolveInfo* resolveInfoAddress = &(m_jit.codeBlock()->globalResolveInfo(data.resolveInfoIndex));
+        ResolveOperation* resolveOperationAddress = &(m_jit.codeBlock()->resolveOperations(data.resolveOperationsIndex)->data()[data.resolvePropertyIndex]);
 
         // Check Structure of global object
         m_jit.move(JITCompiler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectGPR);
-        m_jit.move(JITCompiler::TrustedImmPtr(resolveInfoAddress), resolveInfoGPR);
-        m_jit.loadPtr(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), resultGPR);
+        m_jit.move(JITCompiler::TrustedImmPtr(resolveOperationAddress), resolveInfoGPR);
+        m_jit.loadPtr(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(ResolveOperation, m_structure)), resultGPR);
         JITCompiler::Jump structuresDontMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
 
         // Fast case
-        m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
+        m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(ResolveOperation, m_offset)), resolveInfoGPR);
 #if DFG_ENABLE(JIT_ASSERT)
         JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(firstOutOfLineOffset));
         m_jit.breakpoint();
@@ -4672,6 +4675,11 @@ void SpeculativeJIT::compile(Node& node)
         compileNewFunctionExpression(node);
         break;
 
+    case GarbageValue:
+        // We should never get to the point of code emission for a GarbageValue
+        CRASH();
+        break;
+
     case ForceOSRExit: {
         terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
         break;
index 2e44af2..22b9395 100644 (file)
@@ -144,6 +144,8 @@ public:
                     m_graph.vote(node, VoteOther);
                     break;
                 }
+                case GarbageValue:
+                    break;
                     
                 default:
                     m_graph.vote(node, VoteOther);
index 4eab176..bce4107 100644 (file)
@@ -270,10 +270,7 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_get_by_val)
         DEFINE_OP(op_get_argument_by_val)
         DEFINE_OP(op_get_by_pname)
-        DEFINE_OP(op_get_global_var_watchable)
-        DEFINE_OP(op_get_global_var)
         DEFINE_OP(op_get_pnames)
-        DEFINE_OP(op_get_scoped_var)
         DEFINE_OP(op_check_has_instance)
         DEFINE_OP(op_instanceof)
         DEFINE_OP(op_is_undefined)
@@ -339,17 +336,26 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_put_by_index)
         DEFINE_OP(op_put_by_val)
         DEFINE_OP(op_put_getter_setter)
-        case op_init_global_const:
-        DEFINE_OP(op_put_global_var)
-        case op_init_global_const_check:
-        DEFINE_OP(op_put_global_var_check)
-        DEFINE_OP(op_put_scoped_var)
+        DEFINE_OP(op_init_global_const)
+        DEFINE_OP(op_init_global_const_check)
+
+        case op_resolve_global_property:
+        case op_resolve_global_var:
+        case op_resolve_scoped_var:
+        case op_resolve_scoped_var_on_top_scope:
+        case op_resolve_scoped_var_with_top_scope_check:
         DEFINE_OP(op_resolve)
+
+        case op_resolve_base_to_global:
+        case op_resolve_base_to_global_dynamic:
+        case op_resolve_base_to_scope:
+        case op_resolve_base_to_scope_with_top_scope_check:
         DEFINE_OP(op_resolve_base)
+
+        case op_put_to_base_variable:
+        DEFINE_OP(op_put_to_base)
+
         DEFINE_OP(op_ensure_property_exists)
-        DEFINE_OP(op_resolve_global)
-        DEFINE_OP(op_resolve_global_dynamic)
-        DEFINE_OP(op_resolve_skip)
         DEFINE_OP(op_resolve_with_base)
         DEFINE_OP(op_resolve_with_this)
         DEFINE_OP(op_ret)
@@ -503,16 +509,32 @@ void JIT::privateCompileSlowCases()
         case op_put_by_id_transition_normal_out_of_line:
         DEFINE_SLOWCASE_OP(op_put_by_id)
         DEFINE_SLOWCASE_OP(op_put_by_val)
-        case op_init_global_const_check:
-        DEFINE_SLOWCASE_OP(op_put_global_var_check);
-        DEFINE_SLOWCASE_OP(op_resolve_global)
-        DEFINE_SLOWCASE_OP(op_resolve_global_dynamic)
+        DEFINE_SLOWCASE_OP(op_init_global_const_check);
         DEFINE_SLOWCASE_OP(op_rshift)
         DEFINE_SLOWCASE_OP(op_urshift)
         DEFINE_SLOWCASE_OP(op_stricteq)
         DEFINE_SLOWCASE_OP(op_sub)
         DEFINE_SLOWCASE_OP(op_to_jsnumber)
         DEFINE_SLOWCASE_OP(op_to_primitive)
+
+        case op_resolve_global_property:
+        case op_resolve_global_var:
+        case op_resolve_scoped_var:
+        case op_resolve_scoped_var_on_top_scope:
+        case op_resolve_scoped_var_with_top_scope_check:
+        DEFINE_SLOWCASE_OP(op_resolve)
+
+        case op_resolve_base_to_global:
+        case op_resolve_base_to_global_dynamic:
+        case op_resolve_base_to_scope:
+        case op_resolve_base_to_scope_with_top_scope_check:
+        DEFINE_SLOWCASE_OP(op_resolve_base)
+        DEFINE_SLOWCASE_OP(op_resolve_with_base)
+        DEFINE_SLOWCASE_OP(op_resolve_with_this)
+
+        case op_put_to_base_variable:
+        DEFINE_SLOWCASE_OP(op_put_to_base)
+
         default:
             ASSERT_NOT_REACHED();
         }
index 0547185..ecc382b 100644 (file)
@@ -676,9 +676,6 @@ namespace JSC {
         void emit_op_get_by_val(Instruction*);
         void emit_op_get_argument_by_val(Instruction*);
         void emit_op_get_by_pname(Instruction*);
-        void emit_op_get_global_var(Instruction*);
-        void emit_op_get_global_var_watchable(Instruction* instruction) { emit_op_get_global_var(instruction); }
-        void emit_op_get_scoped_var(Instruction*);
         void emit_op_init_lazy_reg(Instruction*);
         void emit_op_check_has_instance(Instruction*);
         void emit_op_instanceof(Instruction*);
@@ -741,17 +738,16 @@ namespace JSC {
         void emit_op_put_by_index(Instruction*);
         void emit_op_put_by_val(Instruction*);
         void emit_op_put_getter_setter(Instruction*);
-        void emit_op_put_global_var(Instruction*);
-        void emit_op_put_global_var_check(Instruction*);
-        void emit_op_put_scoped_var(Instruction*);
+        void emit_op_init_global_const(Instruction*);
+        void emit_op_init_global_const_check(Instruction*);
+        void emit_resolve_operations(ResolveOperations*, const int* base, const int* value);
+        void emitSlow_link_resolve_operations(ResolveOperations*, Vector<SlowCaseEntry>::iterator&);
         void emit_op_resolve(Instruction*);
         void emit_op_resolve_base(Instruction*);
         void emit_op_ensure_property_exists(Instruction*);
-        void emit_op_resolve_global(Instruction*, bool dynamic = false);
-        void emit_op_resolve_global_dynamic(Instruction*);
-        void emit_op_resolve_skip(Instruction*);
         void emit_op_resolve_with_base(Instruction*);
         void emit_op_resolve_with_this(Instruction*);
+        void emit_op_put_to_base(Instruction*);
         void emit_op_ret(Instruction*);
         void emit_op_ret_object_or_this(Instruction*);
         void emit_op_rshift(Instruction*);
@@ -820,9 +816,7 @@ namespace JSC {
         void emitSlow_op_pre_inc(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_put_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_put_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
-        void emitSlow_op_put_global_var_check(Instruction*, Vector<SlowCaseEntry>::iterator&);
-        void emitSlow_op_resolve_global(Instruction*, Vector<SlowCaseEntry>::iterator&);
-        void emitSlow_op_resolve_global_dynamic(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_init_global_const_check(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_rshift(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_stricteq(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_sub(Instruction*, Vector<SlowCaseEntry>::iterator&);
@@ -830,7 +824,13 @@ namespace JSC {
         void emitSlow_op_to_primitive(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_urshift(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_new_array(Instruction*, Vector<SlowCaseEntry>::iterator&);
-        
+
+        void emitSlow_op_resolve(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_resolve_base(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_resolve_with_base(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_resolve_with_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_put_to_base(Instruction*, Vector<SlowCaseEntry>::iterator&);
+
         void emitRightShift(Instruction*, bool isUnsigned);
         void emitRightShiftSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&, bool isUnsigned);
 
index c187e47..adbbe94 100644 (file)
@@ -631,13 +631,6 @@ void JIT::emit_op_ret_object_or_this(Instruction* currentInstruction)
     ret();
 }
 
-void JIT::emit_op_resolve(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_resolve);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
-    stubCall.callWithValueProfiling(currentInstruction[1].u.operand);
-}
-
 void JIT::emit_op_to_primitive(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
@@ -662,13 +655,6 @@ void JIT::emit_op_strcat(Instruction* currentInstruction)
     stubCall.call(currentInstruction[1].u.operand);
 }
 
-void JIT::emit_op_resolve_base(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
-    stubCall.callWithValueProfiling(currentInstruction[1].u.operand);
-}
-
 void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction)
 {
     JITStubCall stubCall(this, cti_op_ensure_property_exists);
@@ -677,50 +663,6 @@ void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction)
     stubCall.call(currentInstruction[1].u.operand);
 }
 
-void JIT::emit_op_resolve_skip(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_resolve_skip);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
-    stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
-    stubCall.callWithValueProfiling(currentInstruction[1].u.operand);
-}
-
-void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool)
-{
-    // Fast case
-    void* globalObject = m_codeBlock->globalObject();
-    unsigned currentIndex = m_globalResolveInfoIndex++;
-    GlobalResolveInfo* resolveInfoAddress = &(m_codeBlock->globalResolveInfo(currentIndex));
-
-    // Check Structure of global object
-    move(TrustedImmPtr(globalObject), regT0);
-    move(TrustedImmPtr(resolveInfoAddress), regT2);
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), regT1);
-    addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, JSCell::structureOffset()))); // Structures don't match
-
-    // Load cached property
-    // Assume that the global object always uses external storage.
-    load32(Address(regT2, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT1);
-    compileGetDirectOffset(regT0, regT0, regT1, regT0, KnownNotFinal);
-    emitValueProfilingSite();
-    emitPutVirtualRegister(currentInstruction[1].u.operand);
-}
-
-void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
-    unsigned dst = currentInstruction[1].u.operand;
-    Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
-    
-    unsigned currentIndex = m_globalResolveInfoIndex++;
-    
-    linkSlowCase(iter);
-    JITStubCall stubCall(this, cti_op_resolve_global);
-    stubCall.addArgument(TrustedImmPtr(ident));
-    stubCall.addArgument(TrustedImm32(currentIndex));
-    stubCall.addArgument(regT0);
-    stubCall.callWithValueProfiling(dst);
-}
-
 void JIT::emit_op_not(Instruction* currentInstruction)
 {
     emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
@@ -814,22 +756,6 @@ void JIT::emit_op_eq(Instruction* currentInstruction)
     emitPutVirtualRegister(currentInstruction[1].u.operand);
 }
 
-void JIT::emit_op_resolve_with_base(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_resolve_with_base);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
-    stubCall.addArgument(TrustedImm32(currentInstruction[1].u.operand));
-    stubCall.callWithValueProfiling(currentInstruction[2].u.operand);
-}
-
-void JIT::emit_op_resolve_with_this(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_resolve_with_this);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
-    stubCall.addArgument(TrustedImm32(currentInstruction[1].u.operand));
-    stubCall.callWithValueProfiling(currentInstruction[2].u.operand);
-}
-
 void JIT::emit_op_jtrue(Instruction* currentInstruction)
 {
     unsigned target = currentInstruction[2].u.operand;
@@ -1571,51 +1497,405 @@ void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vecto
     stubCall.callWithValueProfiling(dst);
 }
 
+void JIT::emit_op_put_to_base(Instruction* currentInstruction)
+{
+    int base = currentInstruction[1].u.operand;
+    int id = currentInstruction[2].u.operand;
+    int value = currentInstruction[3].u.operand;
+
+    PutToBaseOperation* operation = m_codeBlock->putToBaseOperation(currentInstruction[4].u.operand);
+    switch (operation->m_kind) {
+    case PutToBaseOperation::GlobalVariablePutChecked:
+        addSlowCase(branchTest8(NonZero, AbsoluteAddress(operation->m_predicatePointer)));
+    case PutToBaseOperation::GlobalVariablePut: {
+        JSGlobalObject* globalObject = m_codeBlock->globalObject();
+        if (operation->m_isDynamic) {
+            emitGetVirtualRegister(base, regT0);
+            addSlowCase(branchPtr(NotEqual, regT0, TrustedImmPtr(globalObject)));
+        }
+        emitGetVirtualRegister(value, regT0);
+        storePtr(regT0, operation->m_registerAddress);
+        if (Heap::isWriteBarrierEnabled())
+            emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
+        return;
+    }
+    case PutToBaseOperation::VariablePut: {
+        emitGetVirtualRegisters(base, regT0, value, regT1);
+        loadPtr(Address(regT0, JSVariableObject::offsetOfRegisters()), regT2);
+        storePtr(regT1, Address(regT2, operation->m_offset * sizeof(Register)));
+        if (Heap::isWriteBarrierEnabled())
+            emitWriteBarrier(regT0, regT1, regT2, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess);
+        return;
+    }
+
+    case PutToBaseOperation::GlobalPropertyPut: {
+        emitGetVirtualRegisters(base, regT0, value, regT1);
+        loadPtr(&operation->m_structure, regT2);
+        addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), regT2));
+        ASSERT(!operation->m_structure || !operation->m_structure->inlineCapacity());
+        loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
+        load32(&operation->m_offsetInButterfly, regT3);
+        signExtend32ToPtr(regT3, regT3);
+        storePtr(regT1, BaseIndex(regT2, regT3, TimesEight));
+        if (Heap::isWriteBarrierEnabled())
+            emitWriteBarrier(regT0, regT1, regT2, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess);
+        return;
+    }
+
+    case PutToBaseOperation::Uninitialised:
+    case PutToBaseOperation::Readonly:
+    case PutToBaseOperation::Generic:
+        JITStubCall stubCall(this, cti_op_put_to_base);
+
+        stubCall.addArgument(TrustedImm32(base));
+        stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(id)));
+        stubCall.addArgument(TrustedImm32(value));
+        stubCall.addArgument(TrustedImmPtr(operation));
+        stubCall.call();
+        return;
+    }
+}
+
 #endif // USE(JSVALUE64)
 
-void JIT::emit_op_resolve_global_dynamic(Instruction* currentInstruction)
+void JIT::emit_resolve_operations(ResolveOperations* resolveOperations, const int* baseVR, const int* valueVR)
 {
-    int skip = currentInstruction[5].u.operand;
-    
-    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT0);
-    
-    bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
-    ASSERT(skip || !checkTopLevel);
-    if (checkTopLevel && skip--) {
-        Jump activationNotCreated;
-        if (checkTopLevel)
-            activationNotCreated = branchTestPtr(Zero, addressFor(m_codeBlock->activationRegister()));
-        addSlowCase(checkStructure(regT0, m_codeBlock->globalObject()->activationStructure()));
-        loadPtr(Address(regT0, JSScope::offsetOfNext()), regT0);
-        activationNotCreated.link(this);
+
+#if USE(JSVALUE32_64)
+    unmap();
+#else
+    killLastResultRegister();
+#endif
+
+    if (resolveOperations->isEmpty()) {
+        addSlowCase(jump());
+        return;
     }
-    while (skip--) {
-        addSlowCase(checkStructure(regT0, m_codeBlock->globalObject()->activationStructure()));
-        loadPtr(Address(regT0, JSScope::offsetOfNext()), regT0);
+
+    const RegisterID value = regT0;
+#if USE(JSVALUE32_64)
+    const RegisterID valueTag = regT1;
+#endif
+    const RegisterID scope = regT2;
+    const RegisterID scratch = regT3;
+
+    JSGlobalObject* globalObject = m_codeBlock->globalObject();
+    ResolveOperation* pc = resolveOperations->data();
+    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, scope);
+    bool setBase = false;
+    bool resolvingBase = true;
+    while (resolvingBase) {
+        switch (pc->m_operation) {
+        case ResolveOperation::ReturnGlobalObjectAsBase:
+            move(TrustedImmPtr(globalObject), value);
+#if USE(JSVALUE32_64)
+            move(TrustedImm32(JSValue::CellTag), valueTag);
+#endif
+            emitValueProfilingSite();
+            emitStoreCell(*baseVR, value);
+            return;
+        case ResolveOperation::SetBaseToGlobal:
+            ASSERT(baseVR);
+            setBase = true;
+            move(TrustedImmPtr(globalObject), scratch);
+            emitStoreCell(*baseVR, scratch);
+            resolvingBase = false;
+            ++pc;
+            break;
+        case ResolveOperation::SetBaseToUndefined: {
+            ASSERT(baseVR);
+            setBase = true;
+#if USE(JSVALUE64)
+            move(TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(jsUndefined()))), scratch);
+            emitPutVirtualRegister(*baseVR, scratch);
+#else
+            emitStore(*baseVR, jsUndefined());
+#endif
+            resolvingBase = false;
+            ++pc;
+            break;
+        }
+        case ResolveOperation::SetBaseToScope:
+            ASSERT(baseVR);
+            setBase = true;
+            emitStoreCell(*baseVR, scope);
+            resolvingBase = false;
+            ++pc;
+            break;
+        case ResolveOperation::ReturnScopeAsBase:
+            emitStoreCell(*baseVR, scope);
+            ASSERT(!value);
+            move(scope, value);
+#if USE(JSVALUE32_64)
+            move(TrustedImm32(JSValue::CellTag), valueTag);
+#endif
+            emitValueProfilingSite();
+            return;
+        case ResolveOperation::SkipTopScopeNode: {
+            Jump activationNotCreated = branchTestPtr(Zero, payloadFor(m_codeBlock->activationRegister()));
+            loadPtr(Address(scope, JSScope::offsetOfNext()), scope);
+            activationNotCreated.link(this);
+            ++pc;
+            break;
+        }
+        case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope: {
+            move(scope, regT3);
+            loadPtr(Address(regT3, JSScope::offsetOfNext()), regT1);
+            Jump atTopOfScope = branchTestPtr(Zero, regT1);
+            Label loopStart = label();
+            loadPtr(Address(regT3, JSCell::structureOffset()), regT2);
+            Jump isActivation = branchPtr(Equal, regT2, TrustedImmPtr(globalObject->activationStructure()));
+            addSlowCase(branchPtr(NotEqual, regT2, TrustedImmPtr(globalObject->nameScopeStructure())));
+            isActivation.link(this);
+            move(regT1, regT3);
+            loadPtr(Address(regT3, JSScope::offsetOfNext()), regT1);
+            branchTestPtr(NonZero, regT1, loopStart);
+            atTopOfScope.link(this);
+            ++pc;
+            break;
+        }
+        case ResolveOperation::SkipScopes: {
+            for (int i = 0; i < pc->m_scopesToSkip; i++)
+                loadPtr(Address(scope, JSScope::offsetOfNext()), scope);
+            ++pc;
+            break;
+        }
+        case ResolveOperation::Fail:
+            addSlowCase(jump());
+            return;
+        default:
+            resolvingBase = false;
+        }
     }
-    emit_op_resolve_global(currentInstruction, true);
+    if (baseVR && !setBase)
+        emitStoreCell(*baseVR, scope);
+
+    ASSERT(valueVR);
+    ResolveOperation* resolveValueOperation = pc;
+    switch (resolveValueOperation->m_operation) {
+    case ResolveOperation::GetAndReturnGlobalProperty: {
+        // Verify structure.
+        move(TrustedImmPtr(globalObject), regT2);
+        move(TrustedImmPtr(resolveValueOperation), regT3);
+        loadPtr(Address(regT3, OBJECT_OFFSETOF(ResolveOperation, m_structure)), regT1);
+        addSlowCase(branchPtr(NotEqual, regT1, Address(regT2, JSCell::structureOffset())));
+
+        // Load property.
+        load32(Address(regT3, OBJECT_OFFSETOF(ResolveOperation, m_offset)), regT3);
+
+        // regT2: GlobalObject
+        // regT3: offset
+#if USE(JSVALUE32_64)
+        compileGetDirectOffset(regT2, valueTag, value, regT3, KnownNotFinal);
+#else
+        compileGetDirectOffset(regT2, value, regT3, regT1, KnownNotFinal);
+#endif
+        break;
+    }
+    case ResolveOperation::GetAndReturnGlobalVarWatchable:
+    case ResolveOperation::GetAndReturnGlobalVar: {
+#if USE(JSVALUE32_64)
+        loadPtr(reinterpret_cast<char*>(pc->m_registerAddress) + OBJECT_OFFSETOF(JSValue, u.asBits.tag), valueTag);
+#endif
+        loadPtr(reinterpret_cast<char*>(pc->m_registerAddress) + OBJECT_OFFSETOF(JSValue, u.asBits.payload), value);
+        break;
+    }
+    case ResolveOperation::GetAndReturnScopedVar: {
+        loadPtr(Address(scope, JSVariableObject::offsetOfRegisters()), scope);
+#if USE(JSVALUE32_64)
+        loadPtr(Address(scope, pc->m_offset * sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), valueTag);
+#endif
+        loadPtr(Address(scope, pc->m_offset * sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value);
+        break;
+    }
+    default:
+        CRASH();
+        return;
+    }
+
+#if USE(JSVALUE32_64)
+    emitStore(*valueVR, valueTag, value);
+#else
+    emitPutVirtualRegister(*valueVR, value);
+#endif
+    emitValueProfilingSite();
 }
 
-void JIT::emitSlow_op_resolve_global_dynamic(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+void JIT::emitSlow_link_resolve_operations(ResolveOperations* resolveOperations, Vector<SlowCaseEntry>::iterator& iter)
 {
-    unsigned dst = currentInstruction[1].u.operand;
-    Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
-    int skip = currentInstruction[5].u.operand;
-    while (skip--)
+    if (resolveOperations->isEmpty()) {
         linkSlowCase(iter);
-    JITStubCall resolveStubCall(this, cti_op_resolve);
-    resolveStubCall.addArgument(TrustedImmPtr(ident));
-    resolveStubCall.call(dst);
-    emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_resolve_global_dynamic));
-    
-    unsigned currentIndex = m_globalResolveInfoIndex++;
-    
-    linkSlowCase(iter); // We managed to skip all the nodes in the scope chain, but the cache missed.
-    JITStubCall stubCall(this, cti_op_resolve_global);
-    stubCall.addArgument(TrustedImmPtr(ident));
-    stubCall.addArgument(TrustedImm32(currentIndex));
-    stubCall.addArgument(regT0);
-    stubCall.callWithValueProfiling(dst);
+        return;
+    }
+
+    ResolveOperation* pc = resolveOperations->data();
+    bool resolvingBase = true;
+    while (resolvingBase) {
+        switch (pc->m_operation) {
+        case ResolveOperation::ReturnGlobalObjectAsBase:
+            return;
+        case ResolveOperation::SetBaseToGlobal:
+            resolvingBase = false;
+            ++pc;
+            break;
+        case ResolveOperation::SetBaseToUndefined: {
+            resolvingBase = false;
+            ++pc;
+            break;
+        }
+        case ResolveOperation::SetBaseToScope:
+            resolvingBase = false;
+            ++pc;
+            break;
+        case ResolveOperation::ReturnScopeAsBase:
+            return;
+        case ResolveOperation::SkipTopScopeNode: {
+            ++pc;
+            break;
+        }
+        case ResolveOperation::SkipScopes:
+            ++pc;
+            break;
+        case ResolveOperation::Fail:
+            linkSlowCase(iter);
+            return;
+        case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope: {
+            linkSlowCase(iter);
+            ++pc;
+            break;
+        }
+        default:
+            resolvingBase = false;
+        }
+    }
+    ResolveOperation* resolveValueOperation = pc;
+    switch (resolveValueOperation->m_operation) {
+    case ResolveOperation::GetAndReturnGlobalProperty: {
+        linkSlowCase(iter);
+        break;
+    }
+    case ResolveOperation::GetAndReturnGlobalVarWatchable:
+    case ResolveOperation::GetAndReturnGlobalVar:
+        break;
+    case ResolveOperation::GetAndReturnScopedVar:
+        break;
+    default:
+        CRASH();
+        return;
+    }
+}
+
+void JIT::emit_op_resolve(Instruction* currentInstruction)
+{
+    ResolveOperations* operations = m_codeBlock->resolveOperations(currentInstruction[3].u.operand);
+    int dst = currentInstruction[1].u.operand;
+    emit_resolve_operations(operations, 0, &dst);
+}
+
+void JIT::emitSlow_op_resolve(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    ResolveOperations* operations = m_codeBlock->resolveOperations(currentInstruction[3].u.operand);
+    emitSlow_link_resolve_operations(operations, iter);
+    JITStubCall stubCall(this, cti_op_resolve);
+    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+    stubCall.addArgument(TrustedImmPtr(m_codeBlock->resolveOperations(currentInstruction[3].u.operand)));
+    stubCall.callWithValueProfiling(currentInstruction[1].u.operand);
+}
+
+void JIT::emit_op_resolve_base(Instruction* currentInstruction)
+{
+    ResolveOperations* operations = m_codeBlock->resolveOperations(currentInstruction[4].u.operand);
+    int dst = currentInstruction[1].u.operand;
+    emit_resolve_operations(operations, &dst, 0);
+}
+
+void JIT::emitSlow_op_resolve_base(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    ResolveOperations* operations = m_codeBlock->resolveOperations(currentInstruction[4].u.operand);
+    emitSlow_link_resolve_operations(operations, iter);
+    JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base);
+    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+    stubCall.addArgument(TrustedImmPtr(m_codeBlock->resolveOperations(currentInstruction[4].u.operand)));
+    stubCall.addArgument(TrustedImmPtr(m_codeBlock->putToBaseOperation(currentInstruction[5].u.operand)));
+    stubCall.callWithValueProfiling(currentInstruction[1].u.operand);
+}
+
+void JIT::emit_op_resolve_with_base(Instruction* currentInstruction)
+{
+    ResolveOperations* operations = m_codeBlock->resolveOperations(currentInstruction[4].u.operand);
+    int base = currentInstruction[1].u.operand;
+    int value = currentInstruction[2].u.operand;
+    emit_resolve_operations(operations, &base, &value);
+}
+
+void JIT::emitSlow_op_resolve_with_base(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    ResolveOperations* operations = m_codeBlock->resolveOperations(currentInstruction[4].u.operand);
+    emitSlow_link_resolve_operations(operations, iter);
+    JITStubCall stubCall(this, cti_op_resolve_with_base);
+    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
+    stubCall.addArgument(TrustedImm32(currentInstruction[1].u.operand));
+    stubCall.addArgument(TrustedImmPtr(m_codeBlock->resolveOperations(currentInstruction[4].u.operand)));
+    stubCall.addArgument(TrustedImmPtr(m_codeBlock->putToBaseOperation(currentInstruction[5].u.operand)));
+    stubCall.callWithValueProfiling(currentInstruction[2].u.operand);
+}
+
+void JIT::emit_op_resolve_with_this(Instruction* currentInstruction)
+{
+    ResolveOperations* operations = m_codeBlock->resolveOperations(currentInstruction[4].u.operand);
+    int base = currentInstruction[1].u.operand;
+    int value = currentInstruction[2].u.operand;
+    emit_resolve_operations(operations, &base, &value);
+}
+
+void JIT::emitSlow_op_resolve_with_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    ResolveOperations* operations = m_codeBlock->resolveOperations(currentInstruction[4].u.operand);
+    emitSlow_link_resolve_operations(operations, iter);
+    JITStubCall stubCall(this, cti_op_resolve_with_this);
+    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
+    stubCall.addArgument(TrustedImm32(currentInstruction[1].u.operand));
+    stubCall.addArgument(TrustedImmPtr(m_codeBlock->resolveOperations(currentInstruction[4].u.operand)));
+    stubCall.callWithValueProfiling(currentInstruction[2].u.operand);
+}
+
+void JIT::emitSlow_op_put_to_base(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    int base = currentInstruction[1].u.operand;
+    int id = currentInstruction[2].u.operand;
+    int value = currentInstruction[3].u.operand;
+    int operation = currentInstruction[4].u.operand;
+
+    PutToBaseOperation* putToBaseOperation = m_codeBlock->putToBaseOperation(currentInstruction[4].u.operand);
+    switch (putToBaseOperation->m_kind) {
+    case PutToBaseOperation::VariablePut:
+        return;
+
+    case PutToBaseOperation::GlobalVariablePut:
+        if (!putToBaseOperation->m_isDynamic)
+            return;
+        linkSlowCase(iter);
+        break;
+
+    case PutToBaseOperation::Uninitialised:
+    case PutToBaseOperation::Readonly:
+    case PutToBaseOperation::Generic:
+        return;
+
+    case PutToBaseOperation::GlobalVariablePutChecked:
+    case PutToBaseOperation::GlobalPropertyPut:
+        linkSlowCase(iter);
+        break;
+
+    }
+
+    JITStubCall stubCall(this, cti_op_put_to_base);
+
+    stubCall.addArgument(TrustedImm32(base));
+    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(id)));
+    stubCall.addArgument(TrustedImm32(value));
+    stubCall.addArgument(TrustedImmPtr(m_codeBlock->putToBaseOperation(operation)));
+    stubCall.call();
 }
 
 void JIT::emit_op_new_regexp(Instruction* currentInstruction)
index db53655..44123be 100644 (file)
@@ -36,6 +36,7 @@
 #include "JSCell.h"
 #include "JSFunction.h"
 #include "JSPropertyNameIterator.h"
+#include "JSVariableObject.h"
 #include "LinkBuffer.h"
 
 namespace JSC {
@@ -718,13 +719,6 @@ void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
     argsNotCreated.link(this);
 }
 
-void JIT::emit_op_resolve(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_resolve);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
-    stubCall.callWithValueProfiling(currentInstruction[1].u.operand);
-}
-
 void JIT::emit_op_to_primitive(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
@@ -760,13 +754,6 @@ void JIT::emit_op_strcat(Instruction* currentInstruction)
     stubCall.call(currentInstruction[1].u.operand);
 }
 
-void JIT::emit_op_resolve_base(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
-    stubCall.callWithValueProfiling(currentInstruction[1].u.operand);
-}
-
 void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction)
 {
     JITStubCall stubCall(this, cti_op_ensure_property_exists);
@@ -775,53 +762,6 @@ void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction)
     stubCall.call(currentInstruction[1].u.operand);
 }
 
-void JIT::emit_op_resolve_skip(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_resolve_skip);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
-    stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
-    stubCall.callWithValueProfiling(currentInstruction[1].u.operand);
-}
-
-void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic)
-{
-    // FIXME: Optimize to use patching instead of so many memory accesses.
-
-    unsigned dst = currentInstruction[1].u.operand;
-    void* globalObject = m_codeBlock->globalObject();
-
-    unsigned currentIndex = m_globalResolveInfoIndex++;
-    GlobalResolveInfo* resolveInfoAddress = &m_codeBlock->globalResolveInfo(currentIndex);
-
-
-    // Verify structure.
-    move(TrustedImmPtr(globalObject), regT2);
-    move(TrustedImmPtr(resolveInfoAddress), regT3);
-    loadPtr(Address(regT3, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), regT1);
-    addSlowCase(branchPtr(NotEqual, regT1, Address(regT2, JSCell::structureOffset())));
-
-    // Load property.
-    load32(Address(regT3, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT3);
-    compileGetDirectOffset(regT2, regT1, regT0, regT3, KnownNotFinal);
-    emitValueProfilingSite();
-    emitStore(dst, regT1, regT0);
-    map(m_bytecodeOffset + (dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global)), dst, regT1, regT0);
-}
-
-void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
-    unsigned dst = currentInstruction[1].u.operand;
-    Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
-
-    unsigned currentIndex = m_globalResolveInfoIndex++;
-
-    linkSlowCase(iter);
-    JITStubCall stubCall(this, cti_op_resolve_global);
-    stubCall.addArgument(TrustedImmPtr(ident));
-    stubCall.addArgument(TrustedImm32(currentIndex));
-    stubCall.callWithValueProfiling(dst);
-}
-
 void JIT::emit_op_not(Instruction* currentInstruction)
 {
     unsigned dst = currentInstruction[1].u.operand;
@@ -1214,22 +1154,6 @@ void JIT::emit_op_neq_null(Instruction* currentInstruction)
     emitStoreBool(dst, regT1);
 }
 
-void JIT::emit_op_resolve_with_base(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_resolve_with_base);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
-    stubCall.addArgument(TrustedImm32(currentInstruction[1].u.operand));
-    stubCall.callWithValueProfiling(currentInstruction[2].u.operand);
-}
-
-void JIT::emit_op_resolve_with_this(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_resolve_with_this);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
-    stubCall.addArgument(TrustedImm32(currentInstruction[1].u.operand));
-    stubCall.callWithValueProfiling(currentInstruction[2].u.operand);
-}
-
 void JIT::emit_op_throw(Instruction* currentInstruction)
 {
     unsigned exception = currentInstruction[1].u.operand;
@@ -1686,6 +1610,71 @@ void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vecto
     stubCall.callWithValueProfiling(dst);
 }
 
+void JIT::emit_op_put_to_base(Instruction* currentInstruction)
+{
+    int base = currentInstruction[1].u.operand;
+    int id = currentInstruction[2].u.operand;
+    int value = currentInstruction[3].u.operand;
+
+    PutToBaseOperation* operation = m_codeBlock->putToBaseOperation(currentInstruction[4].u.operand);
+
+
+    switch (operation->m_kind) {
+    case PutToBaseOperation::GlobalVariablePutChecked:
+        addSlowCase(branchTest8(NonZero, AbsoluteAddress(operation->m_predicatePointer)));
+    case PutToBaseOperation::GlobalVariablePut: {
+        JSGlobalObject* globalObject = m_codeBlock->globalObject();
+        if (operation->m_isDynamic)
+            addSlowCase(branchPtr(NotEqual, payloadFor(base), TrustedImmPtr(globalObject)));
+
+        emitLoad(value, regT1, regT0);
+        storePtr(regT0, reinterpret_cast<char*>(operation->m_registerAddress) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
+        storePtr(regT1, reinterpret_cast<char*>(operation->m_registerAddress) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
+        if (Heap::isWriteBarrierEnabled())
+            emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
+        break;
+    }
+    case PutToBaseOperation::VariablePut: {
+        loadPtr(payloadFor(base), regT3);
+        emitLoad(value, regT1, regT0);
+        loadPtr(Address(regT3, JSVariableObject::offsetOfRegisters()), regT2);
+        store32(regT0, Address(regT2, operation->m_offset * sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+        store32(regT1, Address(regT2, operation->m_offset * sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+        if (Heap::isWriteBarrierEnabled())
+            emitWriteBarrier(regT3, regT1, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
+        break;
+    }
+
+    case PutToBaseOperation::GlobalPropertyPut: {
+        JSGlobalObject* globalObject = m_codeBlock->globalObject();
+        loadPtr(payloadFor(base), regT3);
+        emitLoad(value, regT1, regT0);
+        loadPtr(&operation->m_structure, regT2);
+        addSlowCase(branchPtr(NotEqual, Address(regT3, JSCell::structureOffset()), regT2));
+        ASSERT(!operation->m_structure || !operation->m_structure->inlineCapacity());
+        loadPtr(Address(regT3, JSObject::butterflyOffset()), regT2);
+        load32(&operation->m_offsetInButterfly, regT3);
+        storePtr(regT0, BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+        storePtr(regT1, BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+        if (Heap::isWriteBarrierEnabled())
+            emitWriteBarrier(globalObject, regT1, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
+        break;
+    }
+
+    case PutToBaseOperation::Uninitialised:
+    case PutToBaseOperation::Readonly:
+    case PutToBaseOperation::Generic:
+        JITStubCall stubCall(this, cti_op_put_to_base);
+
+        stubCall.addArgument(TrustedImm32(base));
+        stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(id)));
+        stubCall.addArgument(TrustedImm32(value));
+        stubCall.addArgument(TrustedImmPtr(operation));
+        stubCall.call();
+        break;
+    }
+}
+
 } // namespace JSC
 
 #endif // USE(JSVALUE32_64)
index 8a4017f..7099c28 100644 (file)
@@ -1190,90 +1190,35 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
 }
 
-void JIT::emit_op_get_scoped_var(Instruction* currentInstruction)
-{
-    int skip = currentInstruction[3].u.operand;
-
-    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT0);
-    bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
-    ASSERT(skip || !checkTopLevel);
-    if (checkTopLevel && skip--) {
-        Jump activationNotCreated;
-        if (checkTopLevel)
-            activationNotCreated = branchTestPtr(Zero, addressFor(m_codeBlock->activationRegister()));
-        loadPtr(Address(regT0, JSScope::offsetOfNext()), regT0);
-        activationNotCreated.link(this);
-    }
-    while (skip--)
-        loadPtr(Address(regT0, JSScope::offsetOfNext()), regT0);
-
-    loadPtr(Address(regT0, JSVariableObject::offsetOfRegisters()), regT0);
-    loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0);
-    emitValueProfilingSite();
-    emitPutVirtualRegister(currentInstruction[1].u.operand);
-}
-
-void JIT::emit_op_put_scoped_var(Instruction* currentInstruction)
-{
-    int skip = currentInstruction[2].u.operand;
-
-    emitGetVirtualRegister(currentInstruction[3].u.operand, regT0);
-
-    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT1);
-    bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
-    ASSERT(skip || !checkTopLevel);
-    if (checkTopLevel && skip--) {
-        Jump activationNotCreated;
-        if (checkTopLevel)
-            activationNotCreated = branchTestPtr(Zero, addressFor(m_codeBlock->activationRegister()));
-        loadPtr(Address(regT1, JSScope::offsetOfNext()), regT1);
-        activationNotCreated.link(this);
-    }
-    while (skip--)
-        loadPtr(Address(regT1, JSScope::offsetOfNext()), regT1);
-
-    emitWriteBarrier(regT1, regT0, regT2, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess);
-
-    loadPtr(Address(regT1, JSVariableObject::offsetOfRegisters()), regT1);
-    storePtr(regT0, Address(regT1, currentInstruction[1].u.operand * sizeof(Register)));
-}
-
-void JIT::emit_op_get_global_var(Instruction* currentInstruction)
-{
-    loadPtr(currentInstruction[2].u.registerPointer, regT0);
-    emitValueProfilingSite();
-    emitPutVirtualRegister(currentInstruction[1].u.operand);
-}
-
-void JIT::emit_op_put_global_var(Instruction* currentInstruction)
+void JIT::emit_op_init_global_const(Instruction* currentInstruction)
 {
     JSGlobalObject* globalObject = m_codeBlock->globalObject();
 
     emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
-    
+
     storePtr(regT0, currentInstruction[1].u.registerPointer);
     if (Heap::isWriteBarrierEnabled())
         emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
 }
 
-void JIT::emit_op_put_global_var_check(Instruction* currentInstruction)
+void JIT::emit_op_init_global_const_check(Instruction* currentInstruction)
 {
     emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
-    
+
     addSlowCase(branchTest8(NonZero, AbsoluteAddress(currentInstruction[3].u.predicatePointer)));
 
     JSGlobalObject* globalObject = m_codeBlock->globalObject();
-    
+
     storePtr(regT0, currentInstruction[1].u.registerPointer);
     if (Heap::isWriteBarrierEnabled())
         emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
 }
 
-void JIT::emitSlow_op_put_global_var_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+void JIT::emitSlow_op_init_global_const_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     linkSlowCase(iter);
-    
-    JITStubCall stubCall(this, cti_op_put_global_var_check);
+
+    JITStubCall stubCall(this, cti_op_init_global_const_check);
     stubCall.addArgument(regT0);
     stubCall.addArgument(TrustedImm32(currentInstruction[4].u.operand));
     stubCall.call();
index a4a5478..5d619b9 100644 (file)
@@ -1232,72 +1232,7 @@ void JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowC
     stubCall.call(dst);
 }
 
-void JIT::emit_op_get_scoped_var(Instruction* currentInstruction)
-{
-    int dst = currentInstruction[1].u.operand;
-    int index = currentInstruction[2].u.operand;
-    int skip = currentInstruction[3].u.operand;
-
-    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT2);
-    bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
-    ASSERT(skip || !checkTopLevel);
-    if (checkTopLevel && skip--) {
-        Jump activationNotCreated;
-        if (checkTopLevel)
-            activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), TrustedImm32(JSValue::EmptyValueTag));
-        loadPtr(Address(regT2, JSScope::offsetOfNext()), regT2);
-        activationNotCreated.link(this);
-    }
-    while (skip--)
-        loadPtr(Address(regT2, JSScope::offsetOfNext()), regT2);
-
-    loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT2);
-
-    emitLoad(index, regT1, regT0, regT2);
-    emitValueProfilingSite();
-    emitStore(dst, regT1, regT0);
-    map(m_bytecodeOffset + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0);
-}
-
-void JIT::emit_op_put_scoped_var(Instruction* currentInstruction)
-{
-    int index = currentInstruction[1].u.operand;
-    int skip = currentInstruction[2].u.operand;
-    int value = currentInstruction[3].u.operand;
-
-    emitLoad(value, regT1, regT0);
-
-    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT2);
-    bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
-    ASSERT(skip || !checkTopLevel);
-    if (checkTopLevel && skip--) {
-        Jump activationNotCreated;
-        if (checkTopLevel)
-            activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), TrustedImm32(JSValue::EmptyValueTag));
-        loadPtr(Address(regT2, JSScope::offsetOfNext()), regT2);
-        activationNotCreated.link(this);
-    }
-    while (skip--)
-        loadPtr(Address(regT2, JSScope::offsetOfNext()), regT2);
-
-    loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT3);
-    emitStore(index, regT1, regT0, regT3);
-    emitWriteBarrier(regT2, regT1, regT0, regT1, ShouldFilterImmediates, WriteBarrierForVariableAccess);
-}
-
-void JIT::emit_op_get_global_var(Instruction* currentInstruction)
-{
-    int dst = currentInstruction[1].u.operand;
-    WriteBarrier<Unknown>* registerPointer = currentInstruction[2].u.registerPointer;
-
-    load32(registerPointer->tagPointer(), regT1);
-    load32(registerPointer->payloadPointer(), regT0);
-    emitValueProfilingSite();
-    emitStore(dst, regT1, regT0);
-    map(m_bytecodeOffset + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0);
-}
-
-void JIT::emit_op_put_global_var(Instruction* currentInstruction)
+void JIT::emit_op_init_global_const(Instruction* currentInstruction)
 {
     WriteBarrier<Unknown>* registerPointer = currentInstruction[1].u.registerPointer;
     int value = currentInstruction[2].u.operand;
@@ -1314,10 +1249,10 @@ void JIT::emit_op_put_global_var(Instruction* currentInstruction)
 
     store32(regT1, registerPointer->tagPointer());
     store32(regT0, registerPointer->payloadPointer());
-    map(m_bytecodeOffset + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0);
+    map(m_bytecodeOffset + OPCODE_LENGTH(op_init_global_const), value, regT1, regT0);
 }
 
-void JIT::emit_op_put_global_var_check(Instruction* currentInstruction)
+void JIT::emit_op_init_global_const_check(Instruction* currentInstruction)
 {
     WriteBarrier<Unknown>* registerPointer = currentInstruction[1].u.registerPointer;
     int value = currentInstruction[2].u.operand;
@@ -1338,11 +1273,11 @@ void JIT::emit_op_put_global_var_check(Instruction* currentInstruction)
     unmap();
 }
 
-void JIT::emitSlow_op_put_global_var_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+void JIT::emitSlow_op_init_global_const_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     linkSlowCase(iter);
     
-    JITStubCall stubCall(this, cti_op_put_global_var_check);
+    JITStubCall stubCall(this, cti_op_init_global_const_check);
     stubCall.addArgument(regT1, regT0);
     stubCall.addArgument(TrustedImm32(currentInstruction[4].u.operand));
     stubCall.call();
index f1f2f4c..a16b328 100644 (file)
@@ -2375,7 +2375,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer)
     return constructArray(stackFrame.callFrame, stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
 }
 
-DEFINE_STUB_FUNCTION(void, op_put_global_var_check)
+DEFINE_STUB_FUNCTION(void, op_init_global_const_check)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
     
@@ -2390,11 +2390,22 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
 
     CallFrame* callFrame = stackFrame.callFrame;
 
-    JSValue result = JSScope::resolve(callFrame, stackFrame.args[0].identifier());
+    JSValue result = JSScope::resolve(callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].resolveOperations());
     CHECK_FOR_EXCEPTION_AT_END();
     return JSValue::encode(result);
 }
 
+DEFINE_STUB_FUNCTION(void, op_put_to_base)
+{
+    STUB_INIT_STACK_FRAME(stackFrame);
+
+    CallFrame* callFrame = stackFrame.callFrame;
+    JSValue base = callFrame->r(stackFrame.args[0].int32()).jsValue();
+    JSValue value = callFrame->r(stackFrame.args[2].int32()).jsValue();
+    JSScope::resolvePut(callFrame, base, stackFrame.args[1].identifier(), value, stackFrame.args[3].putToBaseOperation());
+    CHECK_FOR_EXCEPTION_AT_END();
+}
+
 DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
@@ -2719,14 +2730,14 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
 
-    return JSValue::encode(JSScope::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), false));
+    return JSValue::encode(JSScope::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), false, stackFrame.args[1].resolveOperations(), stackFrame.args[2].putToBaseOperation()));
 }
 
 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
 
-    if (JSValue result = JSScope::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), true))
+    if (JSValue result = JSScope::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), true, stackFrame.args[1].resolveOperations(), stackFrame.args[2].putToBaseOperation()))
         return JSValue::encode(result);
     VM_THROW_EXCEPTION();
 }
@@ -2745,36 +2756,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_ensure_property_exists)
 
     return JSValue::encode(base);
 }
-    
-DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip)
-{
-    STUB_INIT_STACK_FRAME(stackFrame);
-
-    JSValue result = JSScope::resolveSkip(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].int32());
-    CHECK_FOR_EXCEPTION_AT_END();
-    return JSValue::encode(result);
-}
-
-DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global)
-{
-    STUB_INIT_STACK_FRAME(stackFrame);
-
-    CallFrame* callFrame = stackFrame.callFrame;
-    Identifier& ident = stackFrame.args[0].identifier();
-    CodeBlock* codeBlock = callFrame->codeBlock();
-    unsigned globalResolveInfoIndex = stackFrame.args[1].int32();
-    GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfo(globalResolveInfoIndex);
-
-    JSValue result = JSScope::resolveGlobal(
-        callFrame,
-        ident,
-        callFrame->lexicalGlobalObject(),
-        &globalResolveInfo.structure,
-        &globalResolveInfo.offset
-    );
-    CHECK_FOR_EXCEPTION();
-    return JSValue::encode(result);
-}
 
 DEFINE_STUB_FUNCTION(EncodedJSValue, op_div)
 {
@@ -3055,7 +3036,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base)
     STUB_INIT_STACK_FRAME(stackFrame);
 
     CallFrame* callFrame = stackFrame.callFrame;
-    JSValue result = JSScope::resolveWithBase(callFrame, stackFrame.args[0].identifier(), &callFrame->registers()[stackFrame.args[1].int32()]);
+    JSValue result = JSScope::resolveWithBase(callFrame, stackFrame.args[0].identifier(), &callFrame->registers()[stackFrame.args[1].int32()], stackFrame.args[2].resolveOperations(), stackFrame.args[3].putToBaseOperation());
     CHECK_FOR_EXCEPTION_AT_END();
     return JSValue::encode(result);
 }
@@ -3065,7 +3046,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_this)
     STUB_INIT_STACK_FRAME(stackFrame);
 
     CallFrame* callFrame = stackFrame.callFrame;
-    JSValue result = JSScope::resolveWithThis(callFrame, stackFrame.args[0].identifier(), &callFrame->registers()[stackFrame.args[1].int32()]);
+    JSValue result = JSScope::resolveWithThis(callFrame, stackFrame.args[0].identifier(), &callFrame->registers()[stackFrame.args[1].int32()], stackFrame.args[2].resolveOperations());
     CHECK_FOR_EXCEPTION_AT_END();
     return JSValue::encode(result);
 }
index 4a3b252..6e3141e 100644 (file)
@@ -35,6 +35,7 @@
 #include "LowLevelInterpreter.h"
 #include "MacroAssemblerCodeRef.h"
 #include "Register.h"
+#include "ResolveOperation.h"
 #include "ThunkGenerators.h"
 #include <wtf/HashMap.h>
 
@@ -82,6 +83,8 @@ namespace JSC {
         JSString* jsString() { return static_cast<JSString*>(asPointer); }
         Structure* structure() { return static_cast<Structure*>(asPointer); }
         ReturnAddressPtr returnAddress() { return ReturnAddressPtr(asPointer); }
+        ResolveOperations* resolveOperations() { return static_cast<ResolveOperations*>(asPointer); }
+        PutToBaseOperation* putToBaseOperation() { return static_cast<PutToBaseOperation*>(asPointer); }
     };
     
     struct TrampolineStructure {
@@ -398,11 +401,9 @@ extern "C" {
     EncodedJSValue JIT_STUB cti_op_resolve_base(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     EncodedJSValue JIT_STUB cti_op_resolve_base_strict_put(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     EncodedJSValue JIT_STUB cti_op_ensure_property_exists(STUB_ARGS_DECLARATION) WTF_INTERNAL;
-    EncodedJSValue JIT_STUB cti_op_resolve_global(STUB_ARGS_DECLARATION) WTF_INTERNAL;
-    EncodedJSValue JIT_STUB cti_op_resolve_global_dynamic(STUB_ARGS_DECLARATION) WTF_INTERNAL;
-    EncodedJSValue JIT_STUB cti_op_resolve_skip(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     EncodedJSValue JIT_STUB cti_op_resolve_with_base(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     EncodedJSValue JIT_STUB cti_op_resolve_with_this(STUB_ARGS_DECLARATION) WTF_INTERNAL;
+    void JIT_STUB cti_op_put_to_base(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     EncodedJSValue JIT_STUB cti_op_rshift(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     EncodedJSValue JIT_STUB cti_op_strcat(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     EncodedJSValue JIT_STUB cti_op_stricteq(STUB_ARGS_DECLARATION) WTF_INTERNAL;
@@ -450,7 +451,7 @@ extern "C" {
     void JIT_STUB cti_op_put_by_val(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     void JIT_STUB cti_op_put_by_val_generic(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     void JIT_STUB cti_op_put_getter_setter(STUB_ARGS_DECLARATION) WTF_INTERNAL;
-    void JIT_STUB cti_op_put_global_var_check(STUB_ARGS_DECLARATION) WTF_INTERNAL;
+    void JIT_STUB cti_op_init_global_const_check(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     void JIT_STUB cti_op_tear_off_activation(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     void JIT_STUB cti_op_throw_reference_error(STUB_ARGS_DECLARATION) WTF_INTERNAL;
index fbf5b85..74beae9 100644 (file)
@@ -119,12 +119,20 @@ namespace JSC { namespace LLInt {
         JSValue __rp_returnValue = (value);                     \
         LLINT_CHECK_EXCEPTION();                                \
         LLINT_OP(1) = __rp_returnValue;                         \
-        pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \
-            JSValue::encode(__rp_returnValue);                  \
+        LLINT_PROFILE_VALUE(opcode, __rp_returnValue);          \
         LLINT_END_IMPL();                                       \
     } while (false)
+
+#define LLINT_PROFILE_VALUE(opcode, value) do { \
+        pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \
+        JSValue::encode(value);                  \
+    } while (false)
+
 #else // ENABLE(VALUE_PROFILER)
 #define LLINT_RETURN_PROFILED(opcode, value) LLINT_RETURN(value)
+
+#define LLINT_PROFILE_VALUE(opcode, value) do { } while (false)
+
 #endif // ENABLE(VALUE_PROFILER)
 
 #define LLINT_CALL_END_IMPL(exec, callTarget) LLINT_RETURN_TWO((callTarget), (exec))
@@ -777,52 +785,84 @@ LLINT_SLOW_PATH_DECL(slow_path_in)
 LLINT_SLOW_PATH_DECL(slow_path_resolve)
 {
     LLINT_BEGIN();
-    LLINT_RETURN_PROFILED(op_resolve, JSScope::resolve(exec, exec->codeBlock()->identifier(pc[2].u.operand)));
-}
+    Identifier ident = exec->codeBlock()->identifier(pc[2].u.operand);
+    ResolveOperations* operations = exec->codeBlock()->resolveOperations(pc[3].u.operand);
+    JSValue result = JSScope::resolve(exec, ident, operations);
+    ASSERT(operations->size());
+    ASSERT(operations == exec->codeBlock()->resolveOperations(pc[3].u.operand));
+    switch (operations->data()[0].m_operation) {
+    case ResolveOperation::GetAndReturnGlobalProperty:
+        pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_global_property);
+        break;
 
-LLINT_SLOW_PATH_DECL(slow_path_resolve_skip)
-{
-    LLINT_BEGIN();
-    LLINT_RETURN_PROFILED(
-        op_resolve_skip,
-        JSScope::resolveSkip(
-            exec,
-            exec->codeBlock()->identifier(pc[2].u.operand),
-            pc[3].u.operand));
-}
+    case ResolveOperation::GetAndReturnGlobalVar:
+        pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_global_var);
+        break;
 
-LLINT_SLOW_PATH_DECL(slow_path_resolve_global)
-{
-    LLINT_BEGIN();
-    Identifier& ident = exec->codeBlock()->identifier(pc[2].u.operand);
-    LLINT_RETURN_PROFILED(op_resolve_global, JSScope::resolveGlobal(exec, ident, exec->lexicalGlobalObject(), &pc[3].u.structure, &pc[4].u.operand));
-}
+    case ResolveOperation::SkipTopScopeNode:
+        pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var_with_top_scope_check);
+        break;
 
-LLINT_SLOW_PATH_DECL(slow_path_resolve_global_dynamic)
-{
-    // FIXME: <rdar://problem/12185487> LLInt resolve_global_dynamic doesn't check intervening scopes for modification
-    LLINT_BEGIN();
-    Identifier& ident = exec->codeBlock()->identifier(pc[2].u.operand);
-    LLINT_RETURN_PROFILED(op_resolve_global_dynamic, JSScope::resolveGlobal(exec, ident, exec->lexicalGlobalObject(), &pc[3].u.structure, &pc[4].u.operand));
+    case ResolveOperation::SkipScopes:
+        if (operations->data()[0].m_scopesToSkip)
+            pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var);
+        else
+            pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var_on_top_scope);
+        break;
+
+    default:
+        break;
+    }
+    LLINT_RETURN_PROFILED(op_resolve, result);
 }
 
-LLINT_SLOW_PATH_DECL(slow_path_resolve_for_resolve_global_dynamic)
+LLINT_SLOW_PATH_DECL(slow_path_put_to_base)
 {
     LLINT_BEGIN();
-    LLINT_RETURN_PROFILED(op_resolve_global_dynamic, JSScope::resolve(exec, exec->codeBlock()->identifier(pc[2].u.operand)));
+    PutToBaseOperation* operation = exec->codeBlock()->putToBaseOperation(pc[4].u.operand);
+    JSScope::resolvePut(exec, LLINT_OP_C(1).jsValue(), exec->codeBlock()->identifier(pc[2].u.operand), LLINT_OP_C(3).jsValue(), operation);
+    switch (operation->m_kind) {
+    case PutToBaseOperation::VariablePut:
+        pc[0].u.opcode = LLInt::getOpcode(llint_op_put_to_base_variable);
+        break;
+
+    default:
+        break;
+    }
+    LLINT_END();
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_resolve_base)
 {
     LLINT_BEGIN();
     Identifier& ident = exec->codeBlock()->identifier(pc[2].u.operand);
+    ResolveOperations* operations = exec->codeBlock()->resolveOperations(pc[4].u.operand);
+    JSValue result;
     if (pc[3].u.operand) {
-        if (JSValue result = JSScope::resolveBase(exec, ident, true))
-            LLINT_RETURN(result);
-        LLINT_THROW(globalData.exception);
+        result = JSScope::resolveBase(exec, ident, true, operations, exec->codeBlock()->putToBaseOperation(pc[5].u.operand));
+        if (!result)
+            LLINT_THROW(globalData.exception);
+    } else
+        result = JSScope::resolveBase(exec, ident, false, operations, exec->codeBlock()->putToBaseOperation(pc[5].u.operand));
+    ASSERT(operations->size());
+    switch (operations->data()[0].m_operation) {
+    case ResolveOperation::ReturnGlobalObjectAsBase:
+        pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_global);
+        break;
+
+    case ResolveOperation::SkipTopScopeNode:
+        pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_scope_with_top_scope_check);
+        break;
+
+    case ResolveOperation::SkipScopes:
+        pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_scope);
+        break;
+
+    default:
+        break;
     }
-
-    LLINT_RETURN_PROFILED(op_resolve_base, JSScope::resolveBase(exec, ident, false));
+    LLINT_PROFILE_VALUE(op_resolve_base, result);
+    LLINT_RETURN(result);
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_ensure_property_exists)
@@ -839,24 +879,26 @@ LLINT_SLOW_PATH_DECL(slow_path_ensure_property_exists)
 LLINT_SLOW_PATH_DECL(slow_path_resolve_with_base)
 {
     LLINT_BEGIN();
-    JSValue result = JSScope::resolveWithBase(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1));
+    ResolveOperations* operations = exec->codeBlock()->resolveOperations(pc[4].u.operand);
+    JSValue result = JSScope::resolveWithBase(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1), operations, exec->codeBlock()->putToBaseOperation(pc[5].u.operand));
     LLINT_CHECK_EXCEPTION();
     LLINT_OP(2) = result;
-    // FIXME: technically should have profiling, but we don't do it because the DFG won't use it.
+    LLINT_PROFILE_VALUE(op_resolve_with_base, result);
     LLINT_END();
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_resolve_with_this)
 {
     LLINT_BEGIN();
-    JSValue result = JSScope::resolveWithThis(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1));
+    ResolveOperations* operations = exec->codeBlock()->resolveOperations(pc[4].u.operand);
+    JSValue result = JSScope::resolveWithThis(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1), operations);
     LLINT_CHECK_EXCEPTION();
     LLINT_OP(2) = result;
-    // FIXME: technically should have profiling, but we don't do it because the DFG won't use it.
+    LLINT_PROFILE_VALUE(op_resolve_with_this, result);
     LLINT_END();
 }
 
-LLINT_SLOW_PATH_DECL(slow_path_put_global_var_check)
+LLINT_SLOW_PATH_DECL(slow_path_init_global_const_check)
 {
     LLINT_BEGIN();
     CodeBlock* codeBlock = exec->codeBlock();
index 3d770f3..f784768 100644 (file)
@@ -157,15 +157,12 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_is_object);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_is_function);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_in);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_skip);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_global);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_global_dynamic);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_for_resolve_global_dynamic);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_to_base);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_base);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_ensure_property_exists);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_with_base);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_with_this);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_global_var_check);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_init_global_const_check);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_arguments_length);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id);
index ad509e0..2895cab 100644 (file)
@@ -54,8 +54,28 @@ if JSVALUE64
     const PB = t6
     const tagTypeNumber = csr1
     const tagMask = csr2
+    
+    macro loadisFromInstruction(offset, dest)
+        loadis offset * 8[PB, PC, 8], dest
+    end
+    
+    macro loadpFromInstruction(offset, dest)
+        loadp offset * 8[PB, PC, 8], dest
+    end
+    
+    macro storepToInstruction(value, offset)
+        storep value, offset * 8[PB, PC, 8]
+    end
+
 else
     const PC = t4
+    macro loadisFromInstruction(offset, dest)
+        loadis offset * 4[PC], dest
+    end
+    
+    macro loadpFromInstruction(offset, dest)
+        loadp offset * 4[PC], dest
+    end
 end
 
 # Constants for reasoning about value representation.
@@ -100,6 +120,29 @@ const HashFlags8BitBuffer = 64
 # Copied from PropertyOffset.h
 const firstOutOfLineOffset = 100
 
+# From ResolveOperations.h
+const ResolveOperationFail = 0
+const ResolveOperationSetBaseToUndefined = 1
+const ResolveOperationReturnScopeAsBase = 2
+const ResolveOperationSetBaseToScope = 3
+const ResolveOperationSetBaseToGlobal = 4
+const ResolveOperationGetAndReturnScopedVar = 5
+const ResolveOperationGetAndReturnGlobalVar = 6
+const ResolveOperationGetAndReturnGlobalVarWatchable = 7
+const ResolveOperationSkipTopScopeNode = 8
+const ResolveOperationSkipScopes = 9
+const ResolveOperationReturnGlobalObjectAsBase = 10
+const ResolveOperationGetAndReturnGlobalProperty = 11
+const ResolveOperationCheckForDynamicEntriesBeforeGlobalScope = 12
+
+const PutToBaseOperationKindUninitialised = 0
+const PutToBaseOperationKindGeneric = 1
+const PutToBaseOperationKindReadonly = 2
+const PutToBaseOperationKindGlobalVariablePut = 3
+const PutToBaseOperationKindGlobalVariablePutChecked = 4
+const PutToBaseOperationKindGlobalPropertyPut = 5
+const PutToBaseOperationKindVariablePut = 6
+
 # Allocation constants
 if JSVALUE64
     const JSFinalObjectSizeClassIndex = 1
@@ -499,41 +542,417 @@ _llint_op_in:
     callSlowPath(_llint_slow_path_in)
     dispatch(4)
 
+macro getPutToBaseOperationField(scratch, scratch1, fieldOffset, fieldGetter)
+    loadisFromInstruction(4, scratch)
+    mulp sizeof PutToBaseOperation, scratch, scratch
+    loadp CodeBlock[cfr], scratch1
+    loadp VectorBufferOffset + CodeBlock::m_putToBaseOperations[scratch1], scratch1
+    fieldGetter(fieldOffset[scratch1, scratch, 1])
+end
+
+macro moveJSValueFromRegisterWithoutProfiling(value, destBuffer, destOffsetReg)
+    storep value, [destBuffer, destOffsetReg, 8]
+end
+
+
+macro moveJSValueFromRegistersWithoutProfiling(tag, payload, destBuffer, destOffsetReg)
+    storep tag, TagOffset[destBuffer, destOffsetReg, 8]
+    storep payload, PayloadOffset[destBuffer, destOffsetReg, 8]
+end
+
+macro putToBaseVariableBody(variableOffset, scratch1, scratch2, scratch3)
+    loadisFromInstruction(1, scratch1)
+    loadp PayloadOffset[cfr, scratch1, 8], scratch1
+    loadp JSVariableObject::m_registers[scratch1], scratch1
+    loadisFromInstruction(3, scratch2)
+    if JSVALUE64
+        loadConstantOrVariable(scratch2, scratch3)
+        moveJSValueFromRegisterWithoutProfiling(scratch3, scratch1, variableOffset)
+    else
+        loadConstantOrVariable(scratch2, scratch3, scratch2) # scratch3=tag, scratch2=payload
+        moveJSValueFromRegistersWithoutProfiling(scratch3, scratch2, scratch1, variableOffset)
+    end
+end
+
+_llint_op_put_to_base_variable:
+    traceExecution()
+    getPutToBaseOperationField(t0, t1, PutToBaseOperation::m_offset, macro(addr)
+                                              loadis  addr, t0
+                                          end)
+    putToBaseVariableBody(t0, t1, t2, t3)
+    dispatch(5)
+
+_llint_op_put_to_base:
+    traceExecution()
+    getPutToBaseOperationField(t0, t1, 0, macro(addr)
+                                              leap addr, t0
+                                              bbneq PutToBaseOperation::m_kindAsUint8[t0], PutToBaseOperationKindVariablePut, .notPutToBaseVariable
+                                              loadis PutToBaseOperation::m_offset[t0], t0
+                                              putToBaseVariableBody(t0, t1, t2, t3)
+                                              dispatch(5)
+                                              .notPutToBaseVariable:
+                                          end)
+    callSlowPath(_llint_slow_path_put_to_base)
+    dispatch(5)
+
+macro getResolveOperation(resolveOperationIndex, dest, scratch)
+    loadisFromInstruction(resolveOperationIndex, dest)
+    mulp sizeof ResolveOperations, dest, dest
+    loadp CodeBlock[cfr], scratch
+    loadp VectorBufferOffset + CodeBlock::m_resolveOperations[scratch], scratch
+    loadp VectorBufferOffset[scratch, dest, 1], dest
+end
+
+macro getScope(loadInitialScope, scopeCount, dest, scratch)
+    loadInitialScope(dest)
+    loadi scopeCount, scratch
+
+    btiz scratch, .done
+.loop:
+    loadp JSScope::m_next[dest], dest
+    subi 1, scratch
+    btinz scratch, .loop
+
+.done:
+end
+
+macro moveJSValue(sourceBuffer, sourceOffsetReg, destBuffer, destOffsetReg, profileOffset, scratchRegister)
+    if JSVALUE64
+        loadp [sourceBuffer, sourceOffsetReg, 8], scratchRegister
+        storep scratchRegister, [destBuffer, destOffsetReg, 8]
+        loadpFromInstruction(profileOffset, destOffsetReg)
+        valueProfile(scratchRegister, destOffsetReg)
+    else
+        loadp PayloadOffset[sourceBuffer, sourceOffsetReg, 8], scratchRegister
+        storep scratchRegister, PayloadOffset[destBuffer, destOffsetReg, 8]
+        loadp TagOffset[sourceBuffer, sourceOffsetReg, 8], sourceOffsetReg
+        storep sourceOffsetReg, TagOffset[destBuffer, destOffsetReg, 8]
+        loadpFromInstruction(profileOffset, destOffsetReg)
+        valueProfile(sourceOffsetReg, scratchRegister, destOffsetReg)
+    end
+end
+
+macro moveJSValueFromSlot(slot, destBuffer, destOffsetReg, profileOffset, scratchRegister)
+    if JSVALUE64
+        loadp [slot], scratchRegister
+        storep scratchRegister, [destBuffer, destOffsetReg, 8]
+        loadpFromInstruction(profileOffset, destOffsetReg)
+        valueProfile(scratchRegister, destOffsetReg)
+    else
+        loadp PayloadOffset[slot], scratchRegister
+        storep scratchRegister, PayloadOffset[destBuffer, destOffsetReg, 8]
+        loadp TagOffset[slot], slot
+        storep slot, TagOffset[destBuffer, destOffsetReg, 8]
+        loadpFromInstruction(profileOffset, destOffsetReg)
+        valueProfile(slot, scratchRegister, destOffsetReg)
+    end
+end
+
+macro moveJSValueFromRegister(value, destBuffer, destOffsetReg, profileOffset)
+    storep value, [destBuffer, destOffsetReg, 8]
+    loadpFromInstruction(profileOffset, destOffsetReg)
+    valueProfile(value, destOffsetReg)
+end
+
+macro moveJSValueFromRegisters(tag, payload, destBuffer, destOffsetReg, profileOffset)
+    storep tag, TagOffset[destBuffer, destOffsetReg, 8]
+    storep payload, PayloadOffset[destBuffer, destOffsetReg, 8]
+    loadpFromInstruction(profileOffset, destOffsetReg)
+    valueProfile(tag, payload, destOffsetReg)
+end
+
+_llint_op_resolve_global_property:
+    traceExecution()
+    getResolveOperation(3, t0, t1)
+    loadp CodeBlock[cfr], t1
+    loadp CodeBlock::m_globalObject[t1], t1
+    loadp ResolveOperation::m_structure[t0], t2
+    bpneq JSCell::m_structure[t1], t2, _llint_op_resolve
+    loadis ResolveOperation::m_offset[t0], t0
+    if JSVALUE64
+        loadPropertyAtVariableOffsetKnownNotInline(t0, t1, t2)
+        loadisFromInstruction(1, t0)
+        moveJSValueFromRegister(t2, cfr, t0, 4)
+    else
+        loadPropertyAtVariableOffsetKnownNotInline(t0, t1, t2, t3)
+        loadisFromInstruction(1, t0)
+        moveJSValueFromRegisters(t2, t3, cfr, t0, 4)
+    end
+    dispatch(5)
+
+_llint_op_resolve_global_var:
+    traceExecution()
+    getResolveOperation(3, t0, t1)
+    loadp ResolveOperation::m_registerAddress[t0], t0
+    loadisFromInstruction(1, t1)
+    moveJSValueFromSlot(t0, cfr, t1, 4, t3)
+    dispatch(5)
+
+macro resolveScopedVarBody(resolveOperations)
+    # First ResolveOperation is to skip scope chain nodes
+    getScope(macro(dest)
+                 loadp ScopeChain + PayloadOffset[cfr], dest
+             end,
+             ResolveOperation::m_scopesToSkip[resolveOperations], t1, t2)
+    loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers
+    
+    # Second ResolveOperation tells us what offset to use
+    loadis ResolveOperation::m_offset + sizeof ResolveOperation[resolveOperations], t2
+    loadisFromInstruction(1, t3)
+    moveJSValue(t1, t2, cfr, t3, 4, t0)
+end
+
+_llint_op_resolve_scoped_var:
+    traceExecution()
+    getResolveOperation(3, t0, t1)
+    resolveScopedVarBody(t0)
+    dispatch(5)
+    
+_llint_op_resolve_scoped_var_on_top_scope:
+    traceExecution()
+    getResolveOperation(3, t0, t1)
+
+    # Load destination index
+    loadisFromInstruction(1, t3)
+
+    # We know we want the top scope chain entry
+    loadp ScopeChain + PayloadOffset[cfr], t1
+    loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers
+    
+    # Second ResolveOperation tells us what offset to use
+    loadis ResolveOperation::m_offset + sizeof ResolveOperation[t0], t2
+
+    moveJSValue(t1, t2, cfr, t3, 4, t0)
+    dispatch(5)
+
+_llint_op_resolve_scoped_var_with_top_scope_check:
+    traceExecution()
+    getResolveOperation(3, t0, t1)
+    # First ResolveOperation tells us what register to check
+    loadis ResolveOperation::m_activationRegister[t0], t1
+
+    loadp PayloadOffset[cfr, t1, 8], t1
+
+    getScope(macro(dest)
+                 btpz t1, .scopeChainNotCreated
+                     loadp JSScope::m_next[t1], dest
+                 jmp .done
+                 .scopeChainNotCreated:
+                     loadp ScopeChain + PayloadOffset[cfr], dest
+                 .done:
+             end, 
+             # Second ResolveOperation tells us how many more nodes to skip
+             ResolveOperation::m_scopesToSkip + sizeof ResolveOperation[t0], t1, t2)
+    loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers
+    
+    # Third operation tells us what offset to use
+    loadis ResolveOperation::m_offset + 2 * sizeof ResolveOperation[t0], t2
+    loadisFromInstruction(1, t3)
+    moveJSValue(t1, t2, cfr, t3, 4, t0)
+    dispatch(5)
 
 _llint_op_resolve:
     traceExecution()
+    getResolveOperation(3, t0, t1)
+    btpz t0, .noInstructions
+    loadis ResolveOperation::m_operation[t0], t1
+    bineq t1, ResolveOperationSkipScopes, .notSkipScopes
+        resolveScopedVarBody(t0)
+        dispatch(5)
+.notSkipScopes:
+    bineq t1, ResolveOperationGetAndReturnGlobalVar, .notGetAndReturnGlobalVar
+        loadp ResolveOperation::m_registerAddress[t0], t0
+        loadisFromInstruction(1, t1)
+        moveJSValueFromSlot(t0, cfr, t1, 4, t3)
+        dispatch(5)
+.notGetAndReturnGlobalVar:
+
+.noInstructions:
     callSlowPath(_llint_slow_path_resolve)
-    dispatch(4)
+    dispatch(5)
+
+_llint_op_resolve_base_to_global:
+    traceExecution()
+    loadp CodeBlock[cfr], t1
+    loadp CodeBlock::m_globalObject[t1], t1
+    loadisFromInstruction(1, t3)
+    if JSVALUE64
+        moveJSValueFromRegister(t1, cfr, t3, 6)
+    else
+        move CellTag, t2
+        moveJSValueFromRegisters(t2, t1, cfr, t3, 6)
+    end
+    dispatch(7)
 
+_llint_op_resolve_base_to_global_dynamic:
+    jmp _llint_op_resolve_base
 
-_llint_op_resolve_skip:
+_llint_op_resolve_base_to_scope:
     traceExecution()
-    callSlowPath(_llint_slow_path_resolve_skip)
-    dispatch(5)
+    getResolveOperation(4, t0, t1)
+    # First ResolveOperation is to skip scope chain nodes
+    getScope(macro(dest)
+                 loadp ScopeChain + PayloadOffset[cfr], dest
+             end,
+             ResolveOperation::m_scopesToSkip[t0], t1, t2)
+    loadisFromInstruction(1, t3)
+    if JSVALUE64
+        moveJSValueFromRegister(t1, cfr, t3, 6)
+    else
+        move CellTag, t2
+        moveJSValueFromRegisters(t2, t1, cfr, t3, 6)
+    end
+    dispatch(7)
 
+_llint_op_resolve_base_to_scope_with_top_scope_check:
+    traceExecution()
+    getResolveOperation(4, t0, t1)
+    # First ResolveOperation tells us what register to check
+    loadis ResolveOperation::m_activationRegister[t0], t1
+
+    loadp PayloadOffset[cfr, t1, 8], t1
+
+    getScope(macro(dest)
+                 btpz t1, .scopeChainNotCreated
+                     loadp JSScope::m_next[t1], dest
+                 jmp .done
+                 .scopeChainNotCreated:
+                     loadp ScopeChain + PayloadOffset[cfr], dest
+                 .done:
+             end, 
+             # Second ResolveOperation tells us how many more nodes to skip
+             ResolveOperation::m_scopesToSkip + sizeof ResolveOperation[t0], t1, t2)
+
+    loadisFromInstruction(1, t3)
+    if JSVALUE64
+        moveJSValueFromRegister(t1, cfr, t3, 6)
+    else
+        move CellTag, t2
+        moveJSValueFromRegisters(t2, t1, cfr, t3, 6)
+    end
+    dispatch(7)
 
 _llint_op_resolve_base:
     traceExecution()
     callSlowPath(_llint_slow_path_resolve_base)
-    dispatch(5)
-
+    dispatch(7)
 
 _llint_op_ensure_property_exists:
     traceExecution()
     callSlowPath(_llint_slow_path_ensure_property_exists)
     dispatch(3)
 
+macro interpretResolveWithBase(opcodeLength, slowPath)
+    traceExecution()
+    getResolveOperation(4, t0, t1)
+    btpz t0, .slowPath
+
+    loadp ScopeChain[cfr], t3
+    # Get the base
+    loadis ResolveOperation::m_operation[t0], t2
+
+    bineq t2, ResolveOperationSkipScopes, .notSkipScopes
+        getScope(macro(dest) move t3, dest end,
+                 ResolveOperation::m_scopesToSkip[t0], t1, t2)
+        move t1, t3
+        addp sizeof ResolveOperation, t0, t0
+        jmp .haveCorrectScope
+
+    .notSkipScopes:
+
+    bineq t2, ResolveOperationSkipTopScopeNode, .notSkipTopScopeNode
+        loadis ResolveOperation::m_activationRegister[t0], t1
+        loadp PayloadOffset[cfr, t1, 8], t1
+
+        getScope(macro(dest)
+                     btpz t1, .scopeChainNotCreated
+                         loadp JSScope::m_next[t1], dest
+                     jmp .done
+                     .scopeChainNotCreated:
+                         loadp ScopeChain + PayloadOffset[cfr], dest
+                     .done:
+                 end,
+                 sizeof ResolveOperation + ResolveOperation::m_scopesToSkip[t0], t1, t2)
+        move t1, t3
+        # We've handled two opcodes here
+        addp 2 * sizeof ResolveOperation, t0, t0
+
+    .notSkipTopScopeNode:
+
+    .haveCorrectScope:
+
+    # t3 now contains the correct Scope
+    # t0 contains a pointer to the current ResolveOperation
+
+    loadis ResolveOperation::m_operation[t0], t2
+    # t2 contains the next instruction
+
+    loadisFromInstruction(1, t1)
+    # t1 now contains the index for the base register
+
+    bineq t2, ResolveOperationSetBaseToScope, .notSetBaseToScope
+        storep t3, PayloadOffset[cfr, t1, 8]
+        if JSVALUE64
+        else
+            storep CellTag, TagOffset[cfr, t1, 8]
+        end
+        jmp .haveSetBase
+
+    .notSetBaseToScope:
+
+    bineq t2, ResolveOperationSetBaseToUndefined, .notSetBaseToUndefined
+        if JSVALUE64
+            storep ValueUndefined, PayloadOffset[cfr, t1, 8]
+        else
+            storep 0, PayloadOffset[cfr, t1, 8]
+            storep UndefinedTag, TagOffset[cfr, t1, 8]
+        end
+        jmp .haveSetBase
+
+    .notSetBaseToUndefined:
+    bineq t2, ResolveOperationSetBaseToGlobal, .slowPath
+        loadp JSCell::m_structure[t3], t2
+        loadp Structure::m_globalObject[t2], t2
+        storep t2, PayloadOffset[cfr, t1, 8]
+        if JSVALUE64
+        else
+            storep CellTag, TagOffset[cfr, t1, 8]
+        end
+
+    .haveSetBase:
+
+    # Get the value
+
+    # Load the operation into t2
+    loadis ResolveOperation::m_operation + sizeof ResolveOperation[t0], t2
+
+    # Load the index for the value register into t1
+    loadisFromInstruction(2, t1)
+
+    bineq t2, ResolveOperationGetAndReturnScopedVar, .notGetAndReturnScopedVar
+        loadp JSVariableObject::m_registers[t3], t3 # t3 now contains the activation registers
+
+        # Second ResolveOperation tells us what offset to use
+        loadis ResolveOperation::m_offset + sizeof ResolveOperation[t0], t2
+        moveJSValue(t3, t2, cfr, t1, opcodeLength - 1, t0)
+        dispatch(opcodeLength)
+
+    .notGetAndReturnScopedVar:
+    bineq t2, ResolveOperationGetAndReturnGlobalProperty, .slowPath
+        callSlowPath(slowPath)
+        dispatch(opcodeLength)
+
+.slowPath:
+    callSlowPath(slowPath)
+    dispatch(opcodeLength)
+end
 
 _llint_op_resolve_with_base:
-    traceExecution()
-    callSlowPath(_llint_slow_path_resolve_with_base)
-    dispatch(5)
+    interpretResolveWithBase(7, _llint_slow_path_resolve_with_base)
 
 
 _llint_op_resolve_with_this:
-    traceExecution()
-    callSlowPath(_llint_slow_path_resolve_with_this)
-    dispatch(5)
+    interpretResolveWithBase(6, _llint_slow_path_resolve_with_this)
 
 
 macro withInlineStorage(object, propertyStorage, continuation)
index f0d45eb..d0072d7 100644 (file)
@@ -976,126 +976,7 @@ macro resolveGlobal(size, slow)
     valueProfile(t2, t3, t0)
 end
 
-_llint_op_resolve_global:
-    traceExecution()
-    resolveGlobal(6, .opResolveGlobalSlow)
-    dispatch(6)
-
-.opResolveGlobalSlow:
-    callSlowPath(_llint_slow_path_resolve_global)
-    dispatch(6)
-
-
-# Gives you the scope in t0, while allowing you to optionally perform additional checks on the
-# scopes as they are traversed. scopeCheck() is called with two arguments: the register
-# holding the scope, and a register that can be used for scratch. Note that this does not
-# use t3, so you can hold stuff in t3 if need be.
-macro getScope(deBruijinIndexOperand, scopeCheck)
-    loadp ScopeChain + PayloadOffset[cfr], t0
-    loadi deBruijinIndexOperand, t2
-    
-    btiz t2, .done
-    
-    loadp CodeBlock[cfr], t1
-    bineq CodeBlock::m_codeType[t1], FunctionCode, .loop
-    btbz CodeBlock::m_needsFullScopeChain[t1], .loop
-    
-    loadi CodeBlock::m_activationRegister[t1], t1
-
-    # Need to conditionally skip over one scope.
-    bieq TagOffset[cfr, t1, 8], EmptyValueTag, .noActivation
-    scopeCheck(t0, t1)
-    loadp JSScope::m_next[t0], t0
-.noActivation:
-    subi 1, t2
-    
-    btiz t2, .done
-.loop:
-    scopeCheck(t0, t1)
-    loadp JSScope::m_next[t0], t0
-    subi 1, t2
-    btinz t2, .loop
-
-.done:
-end
-
-_llint_op_resolve_global_dynamic:
-    traceExecution()
-    loadp CodeBlock[cfr], t3
-    loadp CodeBlock::m_globalObject[t3], t3
-    loadp JSGlobalObject::m_activationStructure[t3], t3
-    getScope(
-        20[PC],
-        macro (scope, scratch)
-            bpneq JSCell::m_structure[scope], t3, .opResolveGlobalDynamicSuperSlow
-        end)
-    resolveGlobal(7, .opResolveGlobalDynamicSlow)
-    dispatch(7)
-
-.opResolveGlobalDynamicSuperSlow:
-    callSlowPath(_llint_slow_path_resolve_for_resolve_global_dynamic)
-    dispatch(7)
-
-.opResolveGlobalDynamicSlow:
-    callSlowPath(_llint_slow_path_resolve_global_dynamic)
-    dispatch(7)
-
-
-_llint_op_get_scoped_var:
-    traceExecution()
-    # Operands are as follows:
-    # 4[PC]   Destination for the load.
-    # 8[PC]   Index of register in the scope.
-    # 12[PC]  De Bruijin index.
-    getScope(12[PC], macro (scope, scratch) end)
-    loadi 4[PC], t1
-    loadi 8[PC], t2
-    loadp JSVariableObject::m_registers[t0], t0
-    loadi TagOffset[t0, t2, 8], t3
-    loadi PayloadOffset[t0, t2, 8], t0
-    storei t3, TagOffset[cfr, t1, 8]
-    storei t0, PayloadOffset[cfr, t1, 8]
-    loadi 16[PC], t1
-    valueProfile(t3, t0, t1)
-    dispatch(5)
-
-
-_llint_op_put_scoped_var:
-    traceExecution()
-    getScope(8[PC], macro (scope, scratch) end)
-    loadi 12[PC], t1
-    loadConstantOrVariable(t1, t3, t2)
-    loadi 4[PC], t1
-    writeBarrier(t3, t2)
-    loadp JSVariableObject::m_registers[t0], t0
-    storei t3, TagOffset[t0, t1, 8]
-    storei t2, PayloadOffset[t0, t1, 8]
-    dispatch(4)
-
-
-macro getGlobalVar(size)
-    traceExecution()
-    loadp 8[PC], t0
-    loadi 4[PC], t3
-    loadi TagOffset[t0], t2
-    loadi PayloadOffset[t0], t1
-    storei t2, TagOffset[cfr, t3, 8]
-    storei t1, PayloadOffset[cfr, t3, 8]
-    loadi (size - 1) * 4[PC], t3
-    valueProfile(t2, t1, t3)
-    dispatch(size)
-end
-
-_llint_op_get_global_var:
-    getGlobalVar(4)
-
-
-_llint_op_get_global_var_watchable:
-    getGlobalVar(5)
-
-
 _llint_op_init_global_const:
-_llint_op_put_global_var:
     traceExecution()
     loadi 8[PC], t1
     loadi 4[PC], t0
@@ -1107,22 +988,20 @@ _llint_op_put_global_var:
 
 
 _llint_op_init_global_const_check:
-_llint_op_put_global_var_check:
     traceExecution()
     loadp 12[PC], t2
     loadi 8[PC], t1
     loadi 4[PC], t0
-    btbnz [t2], .opPutGlobalVarCheckSlow
+    btbnz [t2], .opInitGlobalConstCheckSlow
     loadConstantOrVariable(t1, t2, t3)
     writeBarrier(t2, t3)
     storei t2, TagOffset[t0]
     storei t3, PayloadOffset[t0]
     dispatch(5)
-.opPutGlobalVarCheckSlow:
-    callSlowPath(_llint_slow_path_put_global_var_check)
+.opInitGlobalConstCheckSlow:
+    callSlowPath(_llint_slow_path_init_global_const_check)
     dispatch(5)
 
-
 # We only do monomorphic get_by_id caching for now, and we do not modify the
 # opcode. We do, however, allow for the cache to change anytime if fails, since
 # ping-ponging is free. At best we get lucky and the get_by_id will continue
index 8b72674..59fa18c 100644 (file)
@@ -815,139 +815,7 @@ macro loadPropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, value)
     loadp (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8], value
 end
 
-macro resolveGlobal(size, slow)
-    # Operands are as follows:
-    # 8[PB, PC, 8]   Destination for the load.
-    # 16[PB, PC, 8]  Property identifier index in the code block.
-    # 24[PB, PC, 8]  Structure pointer, initialized to 0 by bytecode generator.
-    # 32[PB, PC, 8]  Offset in global object, initialized to 0 by bytecode generator.
-    loadp CodeBlock[cfr], t0
-    loadp CodeBlock::m_globalObject[t0], t0
-    loadp JSCell::m_structure[t0], t1
-    bpneq t1, 24[PB, PC, 8], slow
-    loadis 32[PB, PC, 8], t1
-    loadPropertyAtVariableOffsetKnownNotInline(t1, t0, t2)
-    loadis 8[PB, PC, 8], t0
-    storep t2, [cfr, t0, 8]
-    loadp (size - 1) * 8[PB, PC, 8], t0
-    valueProfile(t2, t0)
-end
-
-_llint_op_resolve_global:
-    traceExecution()
-    resolveGlobal(6, .opResolveGlobalSlow)
-    dispatch(6)
-
-.opResolveGlobalSlow:
-    callSlowPath(_llint_slow_path_resolve_global)
-    dispatch(6)
-
-
-# Gives you the scope in t0, while allowing you to optionally perform additional checks on the
-# scopes as they are traversed. scopeCheck() is called with two arguments: the register
-# holding the scope, and a register that can be used for scratch. Note that this does not
-# use t3, so you can hold stuff in t3 if need be.
-macro getScope(deBruijinIndexOperand, scopeCheck)
-    loadp ScopeChain[cfr], t0
-    loadis deBruijinIndexOperand, t2
-    
-    btiz t2, .done
-    
-    loadp CodeBlock[cfr], t1
-    bineq CodeBlock::m_codeType[t1], FunctionCode, .loop
-    btbz CodeBlock::m_needsFullScopeChain[t1], .loop
-    
-    loadis CodeBlock::m_activationRegister[t1], t1
-
-    # Need to conditionally skip over one scope.
-    btpz [cfr, t1, 8], .noActivation
-    scopeCheck(t0, t1)
-    loadp JSScope::m_next[t0], t0
-.noActivation:
-    subi 1, t2
-    
-    btiz t2, .done
-.loop:
-    scopeCheck(t0, t1)
-    loadp JSScope::m_next[t0], t0
-    subi 1, t2
-    btinz t2, .loop
-
-.done:
-end
-
-_llint_op_resolve_global_dynamic:
-    traceExecution()
-    loadp CodeBlock[cfr], t3
-    loadp CodeBlock::m_globalObject[t3], t3
-    loadp JSGlobalObject::m_activationStructure[t3], t3
-    getScope(
-        40[PB, PC, 8],
-        macro (scope, scratch)
-            bpneq JSCell::m_structure[scope], t3, .opResolveGlobalDynamicSuperSlow
-        end)
-    resolveGlobal(7, .opResolveGlobalDynamicSlow)
-    dispatch(7)
-
-.opResolveGlobalDynamicSuperSlow:
-    callSlowPath(_llint_slow_path_resolve_for_resolve_global_dynamic)
-    dispatch(7)
-
-.opResolveGlobalDynamicSlow:
-    callSlowPath(_llint_slow_path_resolve_global_dynamic)
-    dispatch(7)
-
-
-_llint_op_get_scoped_var:
-    traceExecution()
-    # Operands are as follows:
-    # 8[PB, PC, 8]   Destination for the load
-    # 16[PB, PC, 8]  Index of register in the scope
-    # 24[PB, PC, 8]  De Bruijin index.
-    getScope(24[PB, PC, 8], macro (scope, scratch) end)
-    loadis 8[PB, PC, 8], t1
-    loadis 16[PB, PC, 8], t2
-    loadp JSVariableObject::m_registers[t0], t0
-    loadp [t0, t2, 8], t3
-    storep t3, [cfr, t1, 8]
-    loadp 32[PB, PC, 8], t1
-    valueProfile(t3, t1)
-    dispatch(5)
-
-
-_llint_op_put_scoped_var:
-    traceExecution()
-    getScope(16[PB, PC, 8], macro (scope, scratch) end)
-    loadis 24[PB, PC, 8], t1
-    loadConstantOrVariable(t1, t3)
-    loadis 8[PB, PC, 8], t1
-    writeBarrier(t3)
-    loadp JSVariableObject::m_registers[t0], t0
-    storep t3, [t0, t1, 8]
-    dispatch(4)
-
-
-macro getGlobalVar(size)
-    traceExecution()
-    loadp 16[PB, PC, 8], t0
-    loadis 8[PB, PC, 8], t3
-    loadp [t0], t1
-    storep t1, [cfr, t3, 8]
-    loadp (size - 1) * 8[PB, PC, 8], t0
-    valueProfile(t1, t0)
-    dispatch(size)
-end
-
-_llint_op_get_global_var:
-    getGlobalVar(4)
-
-
-_llint_op_get_global_var_watchable:
-    getGlobalVar(5)
-
-
 _llint_op_init_global_const:
-_llint_op_put_global_var:
     traceExecution()
     loadis 16[PB, PC, 8], t1
     loadp 8[PB, PC, 8], t0
@@ -958,21 +826,19 @@ _llint_op_put_global_var:
 
 
 _llint_op_init_global_const_check:
-_llint_op_put_global_var_check:
     traceExecution()
     loadp 24[PB, PC, 8], t2
     loadis 16[PB, PC, 8], t1
     loadp 8[PB, PC, 8], t0
-    btbnz [t2], .opPutGlobalVarCheckSlow
+    btbnz [t2], .opInitGlobalConstCheckSlow
     loadConstantOrVariable(t1, t2)
     writeBarrier(t2)
     storep t2, [t0]
     dispatch(5)
-.opPutGlobalVarCheckSlow:
-    callSlowPath(_llint_slow_path_put_global_var_check)
+.opInitGlobalConstCheckSlow:
+    callSlowPath(_llint_slow_path_init_global_const_check)
     dispatch(5)
 
-
 macro getById(getPropertyStorage)
     traceExecution()
     # We only do monomorphic get_by_id caching for now, and we do not modify the
index 8fd49b8..508a905 100644 (file)
@@ -86,126 +86,388 @@ int JSScope::localDepth()
     return scopeDepth;
 }
 
-JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier)
-{
-    JSScope* scope = callFrame->scope();
-    ASSERT(scope);
+struct LookupResult {
+    JSValue base() const { return m_base; }
+    JSValue value() const { return m_value; }
+    void setBase(JSValue base) { ASSERT(base); m_base = base; }
+    void setValue(JSValue value) { ASSERT(value); m_value = value; }
 
-    do {
-        JSObject* object = JSScope::objectAtScope(scope);
-        PropertySlot slot(object);
-        if (object->getPropertySlot(callFrame, identifier, slot))
-            return slot.getValue(callFrame, identifier);
-    } while ((scope = scope->next()));
+private:
+    JSValue m_base;
+    JSValue m_value;
+};
 
-    return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
+
+static void setPutPropertyAccessOffset(PutToBaseOperation* operation, PropertyOffset offset)
+{
+    ASSERT(isOutOfLineOffset(offset));
+    operation->m_offset = offset;
+    operation->m_offsetInButterfly = offsetInButterfly(offset);
+}
+
+static bool executeResolveOperations(CallFrame* callFrame, JSScope* scope, const Identifier& propertyName, ResolveOperation* pc, LookupResult& result)
+{
+    while (true) {
+        switch (pc->m_operation) {
+        case ResolveOperation::Fail:
+            return false;
+        case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope: {
+            while (JSScope* nextScope = scope->next()) {
+                if (scope->isActivationObject() && scope->structure() != scope->globalObject()->activationStructure())
+                    return false;
+                ASSERT(scope->isNameScopeObject() || scope->isVariableObject() || scope->isGlobalObject());
+                scope = nextScope;
+            }
+            pc++;
+            break;
+        }
+        case ResolveOperation::SetBaseToUndefined:
+            result.setBase(jsUndefined());
+            pc++;
+            continue;
+        case ResolveOperation::SetBaseToScope:
+            result.setBase(scope);
+            pc++;
+            continue;
+        case ResolveOperation::ReturnScopeAsBase:
+            result.setBase(scope);
+            return true;
+        case ResolveOperation::SetBaseToGlobal:
+            result.setBase(scope->globalObject());
+            pc++;
+            continue;
+        case ResolveOperation::SkipScopes: {
+            int count = pc->m_scopesToSkip;
+            while (count--)
+                scope = scope->next();
+            ASSERT(scope);
+            pc++;
+            continue;
+        }
+        case ResolveOperation::SkipTopScopeNode:
+            if (callFrame->r(pc->m_activationRegister).jsValue())
+                scope = scope->next();
+            ASSERT(scope);
+            pc++;
+            continue;
+        case ResolveOperation::GetAndReturnScopedVar:
+            ASSERT(jsCast<JSVariableObject*>(scope)->registerAt(pc->m_offset).get());
+            result.setValue(jsCast<JSVariableObject*>(scope)->registerAt(pc->m_offset).get());
+            return true;
+        case ResolveOperation::GetAndReturnGlobalVar:
+            result.setValue(pc->m_registerAddress->get());
+            return true;
+        case ResolveOperation::GetAndReturnGlobalVarWatchable:
+            result.setValue(pc->m_registerAddress->get());
+            return true;
+        case ResolveOperation::ReturnGlobalObjectAsBase:
+            result.setBase(callFrame->lexicalGlobalObject());
+            return true;
+        case ResolveOperation::GetAndReturnGlobalProperty: {
+            JSGlobalObject* globalObject = scope->globalObject();
+            if (globalObject->structure() == pc->m_structure.get()) {
+                result.setValue(globalObject->getDirectOffset(pc->m_offset));
+                return true;
+            }
+
+            PropertySlot slot(globalObject);
+            if (!globalObject->getPropertySlot(callFrame, propertyName, slot))
+                return false;
+
+            JSValue value = slot.getValue(callFrame, propertyName);
+            if (callFrame->hadException())
+                return false;
+
+            Structure* structure = globalObject->structure();
+
+            // Don't try to cache prototype lookups
+            if (globalObject != slot.slotBase() || !slot.isCacheableValue() || !structure->propertyAccessesAreCacheable()) {
+                result.setValue(value);
+                return true;
+            }
+
+            pc->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), structure);
+            pc->m_offset = slot.cachedOffset();
+            result.setValue(value);
+            return true;
+        }
+        }
+    }
 }
 
-JSValue JSScope::resolveSkip(CallFrame* callFrame, const Identifier& identifier, int skip)
+template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScopeInternal(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool )
 {
     JSScope* scope = callFrame->scope();
     ASSERT(scope);
-
+    int scopeCount = 0;
+    bool seenGenericObjectScope = false;
+    bool requiresDynamicChecks = false;
+    bool skipTopScopeNode = false;
+    int activationRegister = 0;
     CodeBlock* codeBlock = callFrame->codeBlock();
-
-    bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
-    ASSERT(skip || !checkTopLevel);
-    if (checkTopLevel && skip--) {
-        if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
-            scope = scope->next();
-    }
-    while (skip--) {
-        scope = scope->next();
-        ASSERT(scope);
-    }
+    if (mode == UnknownResolve) {
+        ASSERT(operations->isEmpty());
+        if (codeBlock->codeType() == FunctionCode && codeBlock->needsActivation()) {
+            activationRegister = codeBlock->activationRegister();
+            JSValue activation = callFrame->r(activationRegister).jsValue();
+            
+            // If the activation register doesn't match our actual scope, a dynamic
+            // scope has been inserted so we shouldn't skip the top scope node.
+            if (activation == scope) {
+                jsCast<JSActivation*>(activation.asCell())->isDynamicScope(requiresDynamicChecks);
+                if (!requiresDynamicChecks) {
+                    ASSERT(jsCast<JSActivation*>(activation.asCell())->symbolTable()->get(identifier.impl()).isNull());
+                    scope = scope->next();
+                    ASSERT(scope);
+                    skipTopScopeNode = true;
+                }
+            } else if (!activation)
+                skipTopScopeNode = true;
+        }
+    } else
+        ASSERT(operations->size());
+
+    if (codeBlock->codeType() == EvalCode && scope->next())
+        requiresDynamicChecks = true;
+
+    if (mode == UnknownResolve && putToBaseOperation)
+        putToBaseOperation->m_kind = PutToBaseOperation::Generic;
 
     do {
         JSObject* object = JSScope::objectAtScope(scope);
-        PropertySlot slot(object);
-        if (object->getPropertySlot(callFrame, identifier, slot))
-            return slot.getValue(callFrame, identifier);
+        slot = PropertySlot(object);
+
+        bool currentScopeNeedsDynamicChecks = false;
+        if (!(scope->isVariableObject() || scope->isNameScopeObject()) || (scope->next() && scope->isDynamicScope(currentScopeNeedsDynamicChecks)))
+            seenGenericObjectScope = true;
+
+        requiresDynamicChecks = requiresDynamicChecks || currentScopeNeedsDynamicChecks;
+
+        if (object->getPropertySlot(callFrame, identifier, slot)) {
+            if (mode == UnknownResolve) {
+                if (seenGenericObjectScope)
+                    goto fail;
+                if (putToBaseOperation)
+                    putToBaseOperation->m_isDynamic = requiresDynamicChecks;
+                if (!scope->next()) {
+                    // Global lookup of some kind
+                    JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(scope);
+                    SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl());
+                    if (!entry.isNull()) {
+                        if (requiresDynamicChecks)
+                            operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
+
+                        if (putToBaseOperation) {
+                            putToBaseOperation->m_isDynamic = requiresDynamicChecks;
+                            if (entry.isReadOnly())
+                                putToBaseOperation->m_kind = PutToBaseOperation::Readonly;
+                            else if (entry.couldBeWatched()) {
+                                putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePutChecked;
+                                putToBaseOperation->m_predicatePointer = entry.addressOfIsWatched();
+                            } else
+                                putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePut;
+                            putToBaseOperation->m_registerAddress = &globalObject->registerAt(entry.getIndex());
+                        }
+                        // Override custom accessor behaviour that the DOM introduces for some
+                        // event handlers declared on function declarations.
+                        if (!requiresDynamicChecks)
+                            slot.setValue(globalObject, globalObject->registerAt(entry.getIndex()).get());
+                        switch (returnValues) {
+                        case ReturnValue:
+                            ASSERT(!putToBaseOperation);
+                            operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
+                            break;
+                        case ReturnBase:
+                            ASSERT(putToBaseOperation);
+                            operations->append(ResolveOperation::returnGlobalObjectAsBase());
+                            break;
+                        case ReturnBaseAndValue:
+                            ASSERT(putToBaseOperation);
+                            operations->append(ResolveOperation::setBaseToGlobal());
+                            operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
+                            break;
+                        case ReturnThisAndValue:
+                            ASSERT(!putToBaseOperation);
+                            operations->append(ResolveOperation::setBaseToUndefined());
+                            operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
+                            break;
+                        }
+                    } else {
+                        if (!slot.isCacheableValue() || slot.slotBase() != globalObject)
+                            goto fail;
+
+                        if (requiresDynamicChecks)
+                            operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
+
+                        if (putToBaseOperation) {
+                            putToBaseOperation->m_isDynamic = requiresDynamicChecks;
+                            putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut;
+                            putToBaseOperation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure());
+                            setPutPropertyAccessOffset(putToBaseOperation, slot.cachedOffset());
+                        }
+                        switch (returnValues) {
+                        case ReturnValue:
+                            ASSERT(!putToBaseOperation);
+                            operations->append(ResolveOperation::getAndReturnGlobalProperty());
+                            break;
+                        case ReturnBase:
+                            ASSERT(putToBaseOperation);
+                            operations->append(ResolveOperation::returnGlobalObjectAsBase());
+                            break;
+                        case ReturnBaseAndValue:
+                            ASSERT(putToBaseOperation);
+                            operations->append(ResolveOperation::setBaseToGlobal());
+                            operations->append(ResolveOperation::getAndReturnGlobalProperty());
+                            break;
+                        case ReturnThisAndValue:
+                            ASSERT(!putToBaseOperation);
+                            operations->append(ResolveOperation::setBaseToUndefined());
+                            operations->append(ResolveOperation::getAndReturnGlobalProperty());
+                            break;
+                        }
+                    }
+                    return object;
+                }
+                if (!requiresDynamicChecks) {
+                    // Normal lexical lookup
+                    JSVariableObject* variableObject = jsCast<JSVariableObject*>(scope);
+                    ASSERT(variableObject);
+                    ASSERT(variableObject->symbolTable());
+                    SymbolTableEntry entry = variableObject->symbolTable()->get(identifier.impl());
+                    // Variable was actually inserted by eval
+                    if (entry.isNull()) {
+                        ASSERT(!jsDynamicCast<JSNameScope*>(variableObject));
+                        goto fail;
+                    }
+
+                    if (putToBaseOperation) {
+                        putToBaseOperation->m_kind = entry.isReadOnly() ? PutToBaseOperation::Readonly : PutToBaseOperation::VariablePut;
+                        putToBaseOperation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), callFrame->lexicalGlobalObject()->activationStructure());
+                        putToBaseOperation->m_offset = entry.getIndex();
+                        putToBaseOperation->m_scopeDepth = (skipTopScopeNode ? 1 : 0) + scopeCount;
+                    }
+
+                    if (skipTopScopeNode)
+                        operations->append(ResolveOperation::skipTopScopeNode(activationRegister));
+
+                    operations->append(ResolveOperation::skipScopes(scopeCount));
+                    switch (returnValues) {
+                    case ReturnBaseAndValue:
+                        operations->append(ResolveOperation::setBaseToScope());
+                        operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex()));
+                        break;
+
+                    case ReturnBase:
+                        operations->append(ResolveOperation::returnScopeAsBase());
+                        break;
+
+                    case ReturnThisAndValue:
+                        operations->append(ResolveOperation::setBaseToUndefined());
+                        // fallthrough
+                    case ReturnValue:
+                        operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex()));
+                        break;
+                    }
+                    return object;
+                }
+            fail:
+                if (!operations->size())
+                    operations->append(ResolveOperation::resolveFail());
+            }
+            return object;
+        }
+        scopeCount++;
     } while ((scope = scope->next()));
-
-    return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
+    
+    if (mode == UnknownResolve) {
+        ASSERT(operations->isEmpty());
+        if (seenGenericObjectScope) {
+            operations->append(ResolveOperation::resolveFail());
+            return 0;
+        }
+        if (putToBaseOperation) {
+            putToBaseOperation->m_isDynamic = requiresDynamicChecks;
+            putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut;
+            putToBaseOperation->m_structure.clear();
+            putToBaseOperation->m_offset = -1;
+        }
+        if (requiresDynamicChecks)
+            operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
+        switch (returnValues) {
+        case ReturnValue:
+            ASSERT(!putToBaseOperation);
+            operations->append(ResolveOperation::getAndReturnGlobalProperty());
+            break;
+        case ReturnBase:
+            ASSERT(putToBaseOperation);
+            operations->append(ResolveOperation::returnGlobalObjectAsBase());
+            break;
+        case ReturnBaseAndValue:
+            ASSERT(putToBaseOperation);
+            operations->append(ResolveOperation::setBaseToGlobal());
+            operations->append(ResolveOperation::getAndReturnGlobalProperty());
+            break;
+        case ReturnThisAndValue:
+            ASSERT(!putToBaseOperation);
+            operations->append(ResolveOperation::setBaseToUndefined());
+            operations->append(ResolveOperation::getAndReturnGlobalProperty());
+            break;
+        }
+    }
+    return 0;
 }
 
-JSValue JSScope::resolveGlobal(
-    CallFrame* callFrame,
-    const Identifier& identifier,
-    JSGlobalObject* globalObject,
-    WriteBarrierBase<Structure>* cachedStructure,
-    PropertyOffset* cachedOffset
-)
+template <JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScope(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool isStrict)
 {
-    if (globalObject->structure() == cachedStructure->get())
-        return globalObject->getDirectOffset(*cachedOffset);
-
-    PropertySlot slot(globalObject);
-    if (!globalObject->getPropertySlot(callFrame, identifier, slot))
-        return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
-
-    JSValue result = slot.getValue(callFrame, identifier);
-    if (callFrame->globalData().exception)
-        return JSValue();
-
-    if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
-        cachedStructure->set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure());
-        *cachedOffset = slot.cachedOffset();
-    }
+    if (operations->size())
+        return resolveContainingScopeInternal<KnownResolve, returnValues>(callFrame, identifier, slot, operations, putToBaseOperation, isStrict);
+    JSObject* result = resolveContainingScopeInternal<UnknownResolve, returnValues>(callFrame, identifier, slot, operations, putToBaseOperation, isStrict);
+    operations->shrinkToFit();
     return result;
 }
 
-JSValue JSScope::resolveGlobalDynamic(
-    CallFrame* callFrame,
-    const Identifier& identifier,
-    int skip,
-    WriteBarrierBase<Structure>* cachedStructure,
-    PropertyOffset* cachedOffset
-)
+JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier, ResolveOperations* operations)
 {
-    JSScope* scope = callFrame->scope();
-    ASSERT(scope);
-
-    CodeBlock* codeBlock = callFrame->codeBlock();
-
-    bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
-    ASSERT(skip || !checkTopLevel);
-    if (checkTopLevel && skip--) {
-        if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
-            scope = scope->next();
+    ASSERT(operations);
+    LookupResult fastResult;
+    if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
+        ASSERT(fastResult.value());
+        ASSERT(!callFrame->hadException());
+        return fastResult.value();
     }
-    while (skip--) {
-        JSObject* object = JSScope::objectAtScope(scope);
-        if (!object->hasCustomProperties())
-            continue;
 
-        PropertySlot slot(object);
-        if (!object->getPropertySlot(callFrame, identifier, slot))
-            continue;
+    if (callFrame->hadException())
+        return JSValue();
 
-        JSValue result = slot.getValue(callFrame, identifier);
-        if (callFrame->globalData().exception)
-            return JSValue();
-        return result;
+    PropertySlot slot;
+    if (JSScope::resolveContainingScope<ReturnValue>(callFrame, identifier, slot, operations, 0, false)) {
+        ASSERT(operations->size());
+        return slot.getValue(callFrame, identifier);
     }
+    ASSERT(operations->size());
 
-    return resolveGlobal(callFrame, identifier, callFrame->lexicalGlobalObject(), cachedStructure, cachedOffset);
+    return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
 }
 
-JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict)
+JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
 {
-    JSScope* scope = callFrame->scope();
-    ASSERT(scope);
-
-    do {
-        JSObject* object = JSScope::objectAtScope(scope);
+    ASSERT(operations);
+    ASSERT_UNUSED(putToBaseOperations, putToBaseOperations);
+    LookupResult fastResult;
+    if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
+        ASSERT(fastResult.base());
+        ASSERT(!callFrame->hadException());
+        return fastResult.base();
+    }
 
-        PropertySlot slot(object);
-        if (!object->getPropertySlot(callFrame, identifier, slot))
-            continue;
+    if (callFrame->hadException())
+        return JSValue();
 
-        return JSValue(object);
-    } while ((scope = scope->next()));
+    PropertySlot slot;
+    if (JSObject* base = JSScope::resolveContainingScope<ReturnBase>(callFrame, identifier, slot, operations, putToBaseOperations, isStrict)) {
+        ASSERT(operations->size());
+        return base;
+    }
 
     if (!isStrict)
         return callFrame->lexicalGlobalObject();
@@ -213,50 +475,157 @@ JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier,
     return throwError(callFrame, createErrorForInvalidGlobalAssignment(callFrame, identifier.string()));
 }
 
-JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base)
+JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
 {
-    JSScope* scope = callFrame->scope();
-    ASSERT(scope);
-
-    do {
-        JSObject* object = JSScope::objectAtScope(scope);
+    ASSERT(operations);
+    ASSERT_UNUSED(putToBaseOperations, putToBaseOperations);
+    LookupResult fastResult;
+    if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
+        ASSERT(fastResult.base());
+        ASSERT(fastResult.value());
+        ASSERT(!callFrame->hadException());
+        *base = fastResult.base();
+        return fastResult.value();
+    }
 
-        PropertySlot slot(object);
-        if (!object->getPropertySlot(callFrame, identifier, slot))
-            continue;
+    if (callFrame->hadException())
+        return JSValue();
 
+    PropertySlot slot;
+    if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnBaseAndValue>(callFrame, identifier, slot, operations, putToBaseOperations, false)) {
+        ASSERT(operations->size());
         JSValue value = slot.getValue(callFrame, identifier);
         if (callFrame->globalData().exception)
             return JSValue();
 
-        *base = JSValue(object);
+        *base = propertyBase;
         return value;
-    } while ((scope = scope->next()));
+    }
+    ASSERT(operations->size());
 
     return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
 }
 
-JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base)
+JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations)
 {
-    JSScope* scope = callFrame->scope();
-    ASSERT(scope);
-
-    do {
-        JSObject* object = JSScope::objectAtScope(scope);
+    ASSERT(operations);
+    LookupResult fastResult;
+    if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
+        ASSERT(fastResult.base());
+        ASSERT(fastResult.value());
+        ASSERT(!callFrame->hadException());
+        *base = fastResult.base();
+        return fastResult.value();
+    }
 
-        PropertySlot slot(object);
-        if (!object->getPropertySlot(callFrame, identifier, slot))
-            continue;
+    if (callFrame->hadException())
+        return JSValue();
 
+    PropertySlot slot;
+    if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnThisAndValue>(callFrame, identifier, slot, operations, 0, false)) {
+        ASSERT(operations->size());
         JSValue value = slot.getValue(callFrame, identifier);
         if (callFrame->globalData().exception)
             return JSValue();
-
-        *base = object->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(object);
+        ASSERT(value);
+        *base = propertyBase->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(propertyBase);
         return value;
-    } while ((scope = scope->next()));
+    }
+    ASSERT(operations->size());
+
+    return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
+}
+
+void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& property, JSValue value, PutToBaseOperation* operation)
+{
+    ASSERT_UNUSED(operation, operation);
+    ASSERT(base);
+    ASSERT(value);
+    switch (operation->m_kind) {
+    case PutToBaseOperation::Uninitialised:
+        CRASH();
+
+    case PutToBaseOperation::Readonly:
+        return;
+
+    case PutToBaseOperation::GlobalVariablePutChecked:
+        if (*operation->m_predicatePointer)
+            goto genericHandler;
+    case PutToBaseOperation::GlobalVariablePut:
+        if (operation->m_isDynamic) {
+            JSObject* baseObject = jsCast<JSObject*>(base);
+            if (baseObject != callFrame->lexicalGlobalObject()) {
+                if (baseObject->isGlobalObject())
+                    ASSERT(!jsCast<JSGlobalObject*>(baseObject)->assertRegisterIsInThisObject(operation->m_registerAddress));
+                goto genericHandler;
+            }
+        }
+        operation->m_registerAddress->set(callFrame->globalData(), base.asCell(), value);
+        return;
+
+    case PutToBaseOperation::VariablePut: {
+        if (operation->m_isDynamic) {
+            JSObject* baseObject = jsCast<JSObject*>(base);
+            if (baseObject->structure() != operation->m_structure.get())
+                goto genericHandler;
+        }
+        JSVariableObject* variableObject = jsCast<JSVariableObject*>(base);
+        variableObject->registerAt(operation->m_offset).set(callFrame->globalData(), variableObject, value);
+        return;
+    }
+
+    case PutToBaseOperation::GlobalPropertyPut: {
+        JSObject* object = jsCast<JSObject*>(base);
+        if (operation->m_structure.get() != object->structure())
+            break;
+        object->putDirectOffset(callFrame->globalData(), operation->m_offset, value);
+        return;
+    }
+
+    genericHandler:
+    case PutToBaseOperation::Generic:
+        PutPropertySlot slot(operation->m_isStrict);
+        base.put(callFrame, property, value, slot);
+        return;
+    }
+    ASSERT(operation->m_kind == PutToBaseOperation::GlobalPropertyPut);
+    PutPropertySlot slot(operation->m_isStrict);
+    base.put(callFrame, property, value, slot);
+    if (!slot.isCacheable())
+        return;
+    if (callFrame->hadException())
+        return;
+    JSObject* baseObject = jsCast<JSObject*>(base);
+    if (!baseObject->structure()->propertyAccessesAreCacheable())
+        return;
+    if (slot.base() != callFrame->lexicalGlobalObject())
+        return;
+    if (slot.base() != baseObject)
+        return;
+    ASSERT(!baseObject->hasInlineStorage());
+    operation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), baseObject->structure());
+    setPutPropertyAccessOffset(operation, slot.cachedOffset());
+    return;
+}
+
+JSValue JSScope::resolveGlobal(CallFrame* callFrame, const Identifier& identifier, JSGlobalObject* globalObject, ResolveOperation* resolveOperation)
+{
+    ASSERT(resolveOperation);
+    ASSERT(resolveOperation->m_operation == ResolveOperation::GetAndReturnGlobalProperty);
+    ASSERT_UNUSED(globalObject, callFrame->lexicalGlobalObject() == globalObject);
+
+    LookupResult fastResult;
+    if (executeResolveOperations(callFrame, callFrame->scope(), identifier, resolveOperation, fastResult)) {
+        ASSERT(fastResult.value());
+        ASSERT(!callFrame->hadException());
+        return fastResult.value();
+    }
+
+    if (callFrame->hadException())
+        return JSValue();
 
     return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
 }
 
+
 } // namespace JSC
index 011aff5..a9a9dd8 100644 (file)
@@ -27,6 +27,7 @@
 #define JSScope_h
 
 #include "JSObject.h"
+#include "ResolveOperation.h"
 
 namespace JSC {
 
@@ -41,25 +42,12 @@ public:
 
     JS_EXPORT_PRIVATE static JSObject* objectAtScope(JSScope*);
 
-    static JSValue resolve(CallFrame*, const Identifier&);
-    static JSValue resolveSkip(CallFrame*, const Identifier&, int skip);
-    static JSValue resolveGlobal(
-        CallFrame*,
-        const Identifier&,
-        JSGlobalObject* globalObject,
-        WriteBarrierBase<Structure>* cachedStructure,
-        PropertyOffset* cachedOffset
-    );
-    static JSValue resolveGlobalDynamic(
-        CallFrame*,
-        const Identifier&,
-        int skip,
-        WriteBarrierBase<Structure>* cachedStructure,
-        PropertyOffset* cachedOffset
-    );
-    static JSValue resolveBase(CallFrame*, const Identifier&, bool isStrict);
-    static JSValue resolveWithBase(CallFrame*, const Identifier&, Register* base);
-    static JSValue resolveWithThis(CallFrame*, const Identifier&, Register* base);
+    static JSValue resolve(CallFrame*, const Identifier&, ResolveOperations*);
+    static JSValue resolveBase(CallFrame*, const Identifier&, bool isStrict, ResolveOperations*, PutToBaseOperation*);
+    static JSValue resolveWithBase(CallFrame*, const Identifier&, Register* base, ResolveOperations*, PutToBaseOperation*);
+    static JSValue resolveWithThis(CallFrame*, const Identifier&, Register* base, ResolveOperations*);
+    static JSValue resolveGlobal(CallFrame*, const Identifier&, JSGlobalObject*, ResolveOperation*);
+    static void resolvePut(CallFrame*, JSValue base, const Identifier&, JSValue, PutToBaseOperation*);
 
     static void visitChildren(JSCell*, SlotVisitor&);
 
@@ -80,6 +68,16 @@ protected:
 
 private:
     WriteBarrier<JSScope> m_next;
+    enum ReturnValues {
+        ReturnValue = 1,
+        ReturnBase = 2,
+        ReturnThis = 4,
+        ReturnBaseAndValue = ReturnValue | ReturnBase,
+        ReturnThisAndValue = ReturnValue | ReturnThis,
+    };
+    enum LookupMode { UnknownResolve, KnownResolve };
+    template <LookupMode, ReturnValues> static JSObject* resolveContainingScopeInternal(CallFrame*, const Identifier&, PropertySlot&, ResolveOperations*, PutToBaseOperation*, bool isStrict);
+    template <ReturnValues> static JSObject* resolveContainingScope(CallFrame*, const Identifier&, PropertySlot&, ResolveOperations*, PutToBaseOperation*, bool isStrict);
 };
 
 inline JSScope::JSScope(JSGlobalData& globalData, Structure* structure, JSScope* next)
index c815dcd..9b03a2c 100644 (file)
@@ -31,4 +31,6 @@
 
 namespace JSC {
 
+const ClassInfo JSVariableObject::s_info = { "VariableObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSVariableObject) };
+
 } // namespace JSC
index 25961dc..3ff7aa8 100644 (file)
@@ -53,6 +53,8 @@ namespace JSC {
         WriteBarrierBase<Unknown>* const * addressOfRegisters() const { return &m_registers; }
         static size_t offsetOfRegisters() { return OBJECT_OFFSETOF(JSVariableObject, m_registers); }
 
+        static const ClassInfo s_info;
+
     protected:
         static const unsigned StructureFlags = Base::StructureFlags;
 
index f45e9f1..5f12997 100644 (file)
@@ -140,6 +140,8 @@ namespace JSC {
         bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
         bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
 
+        bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
+
         // Type accessors.
         const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
         bool isObject() const { return typeInfo().isObject(); }