DFG should speculate more aggressively on obvious cases on
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Oct 2011 19:25:16 +0000 (19:25 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Oct 2011 19:25:16 +0000 (19:25 +0000)
polymorphic get_by_id
https://bugs.webkit.org/show_bug.cgi?id=69235

Reviewed by Oliver Hunt.

This implements trivial polymorphic get_by_id. It also fixes
problems in the CSE for CheckStructure in the put_by_id
transition case.

Doing this required knowing whether a polymorphic get_by_id stub
was doing a direct access rather than a call of some kind.

Slight speed-up on Kraken and SunSpider. 0.5% speed-up in the
scaled mean of all benchmarks.

* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/Instruction.h:
(JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::set):
(JSC::PolymorphicAccessStructureList::PolymorphicAccessStructureList):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::cellConstant):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::addStructureSet):
(JSC::DFG::Graph::addStructureTransitionData):
* dfg/DFGNode.h:
(JSC::DFG::StructureTransitionData::StructureTransitionData):
(JSC::DFG::Node::hasStructureTransitionData):
(JSC::DFG::Node::structureTransitionData):
(JSC::DFG::Node::hasStructureSet):
(JSC::DFG::Node::structureSet):
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::checkStructureLoadElimination):
(JSC::DFG::Propagator::performNodeCSE):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryBuildGetByIDList):
(JSC::DFG::tryBuildGetByIDProtoList):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureSet.h: Added.
(JSC::DFG::StructureSet::StructureSet):
(JSC::DFG::StructureSet::add):
(JSC::DFG::StructureSet::addAll):
(JSC::DFG::StructureSet::remove):
(JSC::DFG::StructureSet::contains):
(JSC::DFG::StructureSet::isSubsetOf):
(JSC::DFG::StructureSet::isSupersetOf):
(JSC::DFG::StructureSet::size):
(JSC::DFG::StructureSet::at):
(JSC::DFG::StructureSet::operator[]):
(JSC::DFG::StructureSet::last):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
(JSC::getPolymorphicAccessStructureListSlot):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@96527 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/Instruction.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGPropagator.cpp
Source/JavaScriptCore/dfg/DFGRepatch.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStructureSet.h [new file with mode: 0644]
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/jit/JITStubs.cpp

index 81e0a3b..526eee4 100644 (file)
@@ -1,3 +1,74 @@
+2011-10-02  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should speculate more aggressively on obvious cases on
+        polymorphic get_by_id
+        https://bugs.webkit.org/show_bug.cgi?id=69235
+
+        Reviewed by Oliver Hunt.
+        
+        This implements trivial polymorphic get_by_id. It also fixes
+        problems in the CSE for CheckStructure in the put_by_id
+        transition case.
+        
+        Doing this required knowing whether a polymorphic get_by_id stub
+        was doing a direct access rather than a call of some kind.
+        
+        Slight speed-up on Kraken and SunSpider. 0.5% speed-up in the
+        scaled mean of all benchmarks.
+
+        * GNUmakefile.list.am:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/Instruction.h:
+        (JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::set):
+        (JSC::PolymorphicAccessStructureList::PolymorphicAccessStructureList):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::cellConstant):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::addStructureSet):
+        (JSC::DFG::Graph::addStructureTransitionData):
+        * dfg/DFGNode.h:
+        (JSC::DFG::StructureTransitionData::StructureTransitionData):
+        (JSC::DFG::Node::hasStructureTransitionData):
+        (JSC::DFG::Node::structureTransitionData):
+        (JSC::DFG::Node::hasStructureSet):
+        (JSC::DFG::Node::structureSet):
+        * dfg/DFGPropagator.cpp:
+        (JSC::DFG::Propagator::checkStructureLoadElimination):
+        (JSC::DFG::Propagator::performNodeCSE):
+        * dfg/DFGRepatch.cpp:
+        (JSC::DFG::tryBuildGetByIDList):
+        (JSC::DFG::tryBuildGetByIDProtoList):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStructureSet.h: Added.
+        (JSC::DFG::StructureSet::StructureSet):
+        (JSC::DFG::StructureSet::add):
+        (JSC::DFG::StructureSet::addAll):
+        (JSC::DFG::StructureSet::remove):
+        (JSC::DFG::StructureSet::contains):
+        (JSC::DFG::StructureSet::isSubsetOf):
+        (JSC::DFG::StructureSet::isSupersetOf):
+        (JSC::DFG::StructureSet::size):
+        (JSC::DFG::StructureSet::at):
+        (JSC::DFG::StructureSet::operator[]):
+        (JSC::DFG::StructureSet::last):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::privateCompileGetByIdSelfList):
+        (JSC::JIT::privateCompileGetByIdProtoList):
+        (JSC::JIT::privateCompileGetByIdChainList):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::privateCompileGetByIdSelfList):
+        (JSC::JIT::privateCompileGetByIdProtoList):
+        (JSC::JIT::privateCompileGetByIdChainList):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        (JSC::getPolymorphicAccessStructureListSlot):
+
 2011-10-03  Jer Noble  <jer.noble@apple.com>
 
         Enable WEB_AUDIO by default in the WebKit/mac port.
index 50750e9..6c46770 100644 (file)
@@ -134,6 +134,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/dfg/DFGScoreBoard.h \
        Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp \
        Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h \
+       Source/JavaScriptCore/dfg/DFGStructureSet.h \
        Source/JavaScriptCore/heap/AllocationSpace.cpp \
        Source/JavaScriptCore/heap/AllocationSpace.h \
        Source/JavaScriptCore/heap/CardSet.h \
index 63ec5be..e2f9b49 100644 (file)
@@ -83,6 +83,7 @@
                0FD82F4B142806A100179C94 /* BitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82F491428069200179C94 /* BitVector.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228ED1436AB2700196C48 /* Heuristics.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Heuristics.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228EE1436AB2C00196C48 /* Heuristics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Heuristics.cpp */; };
+               0FFF4BB4143955E900655BC0 /* DFGStructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1400067712A6F7830064D123 /* OSAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1400067612A6F7830064D123 /* OSAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1400069312A6F9E10064D123 /* OSAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */; };
                140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */; };
                0FD82F491428069200179C94 /* BitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitVector.h; sourceTree = "<group>"; };
                0FE228EA1436AB2300196C48 /* Heuristics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Heuristics.cpp; sourceTree = "<group>"; };
                0FE228EB1436AB2300196C48 /* Heuristics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Heuristics.h; sourceTree = "<group>"; };
+               0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureSet.h; path = dfg/DFGStructureSet.h; sourceTree = "<group>"; };
                1400067612A6F7830064D123 /* OSAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSAllocator.h; sourceTree = "<group>"; };
                1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSAllocatorPosix.cpp; sourceTree = "<group>"; };
                140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBasePrivate.h; sourceTree = "<group>"; };
                86EC9DB31328DF44002B2AD7 /* dfg */ = {
                        isa = PBXGroup;
                        children = (
+                               0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */,
                                86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */,
                                86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */,
                                0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */,
                                0FD52AAE143035A00026DC9F /* UnionFind.h in Headers */,
                                86880F1E14328BB900B08D42 /* DFGJITCompilerInlineMethods.h in Headers */,
                                0FE228ED1436AB2700196C48 /* Heuristics.h in Headers */,
+                               0FFF4BB4143955E900655BC0 /* DFGStructureSet.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index c2d02fa..88d48fb 100644 (file)
@@ -58,6 +58,7 @@ namespace JSC {
     public:
         struct PolymorphicStubInfo {
             bool isChain;
+            bool isDirect;
             PolymorphicAccessStructureListStubRoutineType stubRoutine;
             WriteBarrier<Structure> base;
             union {
@@ -70,44 +71,47 @@ namespace JSC {
                 u.proto.clear();
             }
 
-            void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base)
+            void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, bool isDirect)
             {
                 stubRoutine = _stubRoutine;
                 base.set(globalData, owner, _base);
                 u.proto.clear();
                 isChain = false;
+                this->isDirect = isDirect;
             }
             
-            void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, Structure* _proto)
+            void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, Structure* _proto, bool isDirect)
             {
                 stubRoutine = _stubRoutine;
                 base.set(globalData, owner, _base);
                 u.proto.set(globalData, owner, _proto);
                 isChain = false;
+                this->isDirect = isDirect;
             }
             
-            void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, StructureChain* _chain)
+            void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, StructureChain* _chain, bool isDirect)
             {
                 stubRoutine = _stubRoutine;
                 base.set(globalData, owner, _base);
                 u.chain.set(globalData, owner, _chain);
                 isChain = true;
+                this->isDirect = isDirect;
             }
         } list[POLYMORPHIC_LIST_CACHE_SIZE];
         
-        PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase)
+        PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, bool isDirect)
         {
-            list[0].set(globalData, owner, stubRoutine, firstBase);
+            list[0].set(globalData, owner, stubRoutine, firstBase, isDirect);
         }
 
-        PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, Structure* firstProto)
+        PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, Structure* firstProto, bool isDirect)
         {
-            list[0].set(globalData, owner, stubRoutine, firstBase, firstProto);
+            list[0].set(globalData, owner, stubRoutine, firstBase, firstProto, isDirect);
         }
 
-        PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, StructureChain* firstChain)
+        PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, StructureChain* firstChain, bool isDirect)
         {
-            list[0].set(globalData, owner, stubRoutine, firstBase, firstChain);
+            list[0].set(globalData, owner, stubRoutine, firstBase, firstChain, isDirect);
         }
 
         void visitAggregate(SlotVisitor& visitor, int count)
index d6a9f77..d742cde 100644 (file)
@@ -415,6 +415,8 @@ private:
         m_constants.append(ConstantRecord());
         ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
         
+        m_cellConstants.add(cell, m_codeBlock->numberOfConstantRegisters() - 1);
+        
         return getJSConstant(m_codeBlock->numberOfConstantRegisters() - 1);
     }
     
@@ -1160,29 +1162,74 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NodeIndex base = get(currentInstruction[2].u.operand);
             unsigned identifierNumber = currentInstruction[3].u.operand;
             
+            Identifier identifier = m_codeBlock->identifier(identifierNumber);
             StructureStubInfo& stubInfo = m_profiledBlock->getStubInfo(m_currentIndex);
             
-            NodeIndex getById = NoNode;
-            if (stubInfo.seen && stubInfo.accessType == access_get_by_id_self) {
-                Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
-                Identifier identifier = m_codeBlock->identifier(identifierNumber);
-                size_t offset = structure->get(*m_globalData, identifier);
-                
-                if (offset != notFound) {
-                    addToGraph(CheckStructure, OpInfo(structure), base);
-                    getById = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), addToGraph(GetPropertyStorage, base));
+            size_t offset = notFound;
+            StructureSet structureSet;
+            if (stubInfo.seen) {
+                switch (stubInfo.accessType) {
+                case access_get_by_id_self: {
+                    Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
+                    offset = structure->get(*m_globalData, identifier);
                     
-                    StorageAccessData storageAccessData;
-                    storageAccessData.offset = offset;
-                    storageAccessData.identifierNumber = identifierNumber;
-                    m_graph.m_storageAccessData.append(storageAccessData);
+                    if (offset != notFound)
+                        structureSet.add(structure);
+
+                    if (offset != notFound)
+                        ASSERT(structureSet.size());
+                    break;
+                }
+                    
+                case access_get_by_id_self_list: {
+                    PolymorphicAccessStructureList* list = stubInfo.u.getByIdProtoList.structureList;
+                    unsigned size = stubInfo.u.getByIdProtoList.listSize;
+                    for (unsigned i = 0; i < size; ++i) {
+                        if (!list->list[i].isDirect) {
+                            offset = notFound;
+                            break;
+                        }
+                        
+                        Structure* structure = list->list[i].base.get();
+                        size_t myOffset = structure->get(*m_globalData, identifier);
+                    
+                        if (myOffset == notFound) {
+                            offset = notFound;
+                            break;
+                        }
+                    
+                        if (!i)
+                            offset = myOffset;
+                        else if (offset != myOffset) {
+                            offset = notFound;
+                            break;
+                        }
+                    
+                        structureSet.add(structure);
+                    }
+                    
+                    if (offset != notFound)
+                        ASSERT(structureSet.size());
+                    break;
+                }
+                    
+                default:
+                    ASSERT(offset == notFound);
+                    break;
                 }
             }
-            
-            if (getById == NoNode)
-                getById = addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base);
-            
-            set(currentInstruction[1].u.operand, getById);
+                        
+            if (offset != notFound) {
+                ASSERT(structureSet.size());
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), base);
+                set(currentInstruction[1].u.operand, addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), addToGraph(GetPropertyStorage, base)));
+                
+                StorageAccessData storageAccessData;
+                storageAccessData.offset = offset;
+                storageAccessData.identifierNumber = identifierNumber;
+                m_graph.m_storageAccessData.append(storageAccessData);
+            } else
+                set(currentInstruction[1].u.operand, addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base));
 
             NEXT_OPCODE(op_get_by_id);
         }
@@ -1207,7 +1254,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                     size_t offset = structure->get(*m_globalData, identifier);
                     
                     if (offset != notFound) {
-                        addToGraph(CheckStructure, OpInfo(structure), base);
+                        addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), base);
                         addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value);
                         
                         StorageAccessData storageAccessData;
@@ -1233,17 +1280,17 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                     size_t offset = newStructure->get(*m_globalData, identifier);
                     
                     if (offset != notFound) {
-                        addToGraph(CheckStructure, OpInfo(previousStructure), base);
+                        addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(previousStructure)), base);
                         if (!direct) {
                             for (WriteBarrier<Structure>* it = structureChain->head(); *it; ++it) {
                                 JSValue prototype = (*it)->storedPrototype();
                                 if (prototype.isNull())
                                     continue;
                                 ASSERT(prototype.isCell());
-                                addToGraph(CheckStructure, OpInfo(prototype.asCell()->structure()), cellConstant(prototype.asCell()));
+                                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())), cellConstant(prototype.asCell()));
                             }
                         }
-                        addToGraph(PutStructure, OpInfo(newStructure), base);
+                        addToGraph(PutStructure, OpInfo(m_graph.addStructureTransitionData(StructureTransitionData(previousStructure, newStructure))), base);
                         
                         addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value);
                         
index 3575858..6ab93ab 100644 (file)
@@ -149,8 +149,14 @@ void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock)
             printf("%sid%u", hasPrinted ? ", " : "", node.identifierNumber());
         hasPrinted = true;
     }
-    if (node.hasStructure()) {
-        printf("%sstruct(%p)", hasPrinted ? ", " : "", node.structure());
+    if (node.hasStructureSet()) {
+        for (size_t i = 0; i < node.structureSet().size(); ++i) {
+            printf("%sstruct(%p)", hasPrinted ? ", " : "", node.structureSet()[i]);
+            hasPrinted = true;
+        }
+    }
+    if (node.hasStructureTransitionData()) {
+        printf("%sstruct(%p -> %p)", hasPrinted ? ", " : "", node.structureTransitionData().previousStructure, node.structureTransitionData().newStructure);
         hasPrinted = true;
     }
     if (node.hasStorageAccessData()) {
index 9f66a08..fe5b1cf 100644 (file)
@@ -329,6 +329,19 @@ public:
 #endif
 
     void predictArgumentTypes(ExecState*, CodeBlock*);
+    
+    StructureSet* addStructureSet(const StructureSet& structureSet)
+    {
+        ASSERT(structureSet.size());
+        m_structureSet.append(structureSet);
+        return &m_structureSet.last();
+    }
+    
+    StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData)
+    {
+        m_structureTransitionData.append(structureTransitionData);
+        return &m_structureTransitionData.last();
+    }
 
     Vector< OwnPtr<BasicBlock> , 8> m_blocks;
     Vector<NodeIndex, 16> m_varArgChildren;
@@ -337,6 +350,8 @@ public:
     Vector<ResolveGlobalData> m_resolveGlobalData;
     Vector<NodeIndex, 8> m_arguments;
     SegmentedVector<VariableAccessData, 16> m_variableAccessData;
+    SegmentedVector<StructureSet, 16> m_structureSet;
+    SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
     unsigned m_preservedVars;
     unsigned m_localVars;
     unsigned m_parameterSlots;
index 63b7f50..6ae7c8d 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef DFGNode_h
 #define DFGNode_h
 
+#include "DFGStructureSet.h"
 #include <wtf/BoundsCheckedPointer.h>
 #include <wtf/Platform.h>
 #include <wtf/UnionFind.h>
@@ -154,6 +155,19 @@ private:
     PredictedType m_prediction;
 };
 
+struct StructureTransitionData {
+    Structure* previousStructure;
+    Structure* newStructure;
+    
+    StructureTransitionData() { }
+    
+    StructureTransitionData(Structure* previousStructure, Structure* newStructure)
+        : previousStructure(previousStructure)
+        , newStructure(newStructure)
+    {
+    }
+};
+
 typedef unsigned ArithNodeFlags;
 #define NodeUseBottom      0x00
 #define NodeUsedAsNumber   0x01
@@ -784,14 +798,26 @@ struct Node {
         return m_opInfo2;
     }
     
-    bool hasStructure()
+    bool hasStructureTransitionData()
+    {
+        return op == PutStructure;
+    }
+    
+    StructureTransitionData& structureTransitionData()
+    {
+        ASSERT(hasStructureTransitionData());
+        return *reinterpret_cast<StructureTransitionData*>(m_opInfo);
+    }
+    
+    bool hasStructureSet()
     {
-        return op == CheckStructure || op == PutStructure;
+        return op == CheckStructure;
     }
     
-    Structure* structure()
+    StructureSet& structureSet()
     {
-        return reinterpret_cast<Structure*>(m_opInfo);
+        ASSERT(hasStructureSet());
+        return *reinterpret_cast<StructureSet*>(m_opInfo);
     }
     
     bool hasStorageAccessData()
index 1885191..13d23a0 100644 (file)
@@ -1013,7 +1013,7 @@ private:
         return NoNode;
     }
     
-    bool checkStructureLoadElimination(Structure* structure, NodeIndex child1)
+    bool checkStructureLoadElimination(const StructureSet& structureSet, NodeIndex child1)
     {
         NodeIndex start = startIndexForChildren(child1);
         for (NodeIndex index = m_compileIndex; index-- > start;) {
@@ -1021,15 +1021,17 @@ private:
             switch (node.op) {
             case CheckStructure:
                 if (node.child1() == child1
-                    && node.structure() == structure)
+                    && structureSet.isSupersetOf(node.structureSet()))
                     return true;
                 break;
                 
             case PutStructure:
                 if (node.child1() == child1
-                    && node.structure() == structure)
+                    && structureSet.contains(node.structureTransitionData().newStructure))
                     return true;
-                return false;
+                if (structureSet.contains(node.structureTransitionData().previousStructure))
+                    return false;
+                break;
                 
             case PutByOffset:
                 // Setting a property cannot change the structure.
@@ -1293,7 +1295,7 @@ private:
             break;
             
         case CheckStructure:
-            if (checkStructureLoadElimination(node.structure(), node.child1()))
+            if (checkStructureLoadElimination(node.structureSet(), node.child1()))
                 eliminate();
             break;
             
index e5341b1..a7966dc 100644 (file)
@@ -347,7 +347,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
     
     if (stubInfo.accessType == access_get_by_id_self) {
         ASSERT(!stubInfo.stubRoutine);
-        polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), MacroAssemblerCodeRef::createSelfManagedCodeRef(stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase)), stubInfo.u.getByIdSelf.baseObjectStructure.get());
+        polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), MacroAssemblerCodeRef::createSelfManagedCodeRef(stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase)), stubInfo.u.getByIdSelf.baseObjectStructure.get(), true);
         stubInfo.initGetByIdSelfList(polymorphicStructureList, 1);
     } else {
         polymorphicStructureList = stubInfo.u.getByIdSelfList.structureList;
@@ -387,7 +387,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
         
         MacroAssemblerCodeRef stubRoutine = patchBuffer.finalizeCode();
         
-        polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure);
+        polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, true);
         
         CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck);
         RepatchBuffer repatchBuffer(codeBlock);
@@ -434,7 +434,7 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
     
     if (stubInfo.accessType == access_get_by_id_chain) {
         ASSERT(!!stubInfo.stubRoutine);
-        polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), stubInfo.stubRoutine, stubInfo.u.getByIdChain.baseObjectStructure.get(), stubInfo.u.getByIdChain.chain.get());
+        polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), stubInfo.stubRoutine, stubInfo.u.getByIdChain.baseObjectStructure.get(), stubInfo.u.getByIdChain.chain.get(), true);
         stubInfo.stubRoutine = MacroAssemblerCodeRef();
         stubInfo.initGetByIdProtoList(polymorphicStructureList, 1);
     } else {
@@ -453,7 +453,7 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
         
         generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone), lastProtoBegin, stubRoutine);
         
-        polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure);
+        polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, true);
         
         CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck);
         RepatchBuffer repatchBuffer(codeBlock);
index e62f6d3..c561328 100644 (file)
@@ -1674,9 +1674,24 @@ void SpeculativeJIT::compile(Node& node)
     case CheckStructure: {
         SpeculateCellOperand base(this, node.child1());
         
-        GPRReg baseGPR = base.gpr();
+        ASSERT(node.structureSet().size());
         
-        speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structure())));
+        if (node.structureSet().size() == 1)
+            speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(base.gpr(), JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structureSet()[0])));
+        else {
+            GPRTemporary structure(this);
+            
+            m_jit.loadPtr(JITCompiler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
+            
+            JITCompiler::JumpList done;
+            
+            for (size_t i = 0; i < node.structureSet().size() - 1; ++i)
+                done.append(m_jit.branchPtr(JITCompiler::Equal, structure.gpr(), JITCompiler::TrustedImmPtr(node.structureSet()[i])));
+            
+            speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, structure.gpr(), JITCompiler::TrustedImmPtr(node.structureSet().last())));
+            
+            done.link(&m_jit);
+        }
         
         noResult(m_compileIndex);
         break;
index 22de008..1ddafcd 100644 (file)
@@ -1734,9 +1734,24 @@ void SpeculativeJIT::compile(Node& node)
     case CheckStructure: {
         SpeculateCellOperand base(this, node.child1());
         
-        GPRReg baseGPR = base.gpr();
+        ASSERT(node.structureSet().size());
         
-        speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structure())));
+        if (node.structureSet().size() == 1)
+            speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(base.gpr(), JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structureSet()[0])));
+        else {
+            GPRTemporary structure(this);
+            
+            m_jit.loadPtr(JITCompiler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
+            
+            JITCompiler::JumpList done;
+            
+            for (size_t i = 0; i < node.structureSet().size() - 1; ++i)
+                done.append(m_jit.branchPtr(JITCompiler::Equal, structure.gpr(), JITCompiler::TrustedImmPtr(node.structureSet()[i])));
+            
+            speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, structure.gpr(), JITCompiler::TrustedImmPtr(node.structureSet().last())));
+            
+            done.link(&m_jit);
+        }
         
         noResult(m_compileIndex);
         break;
@@ -1748,10 +1763,10 @@ void SpeculativeJIT::compile(Node& node)
         
 #if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
         // Must always emit this write barrier as the structure transition itself requires it
-        writeBarrier(baseGPR, node.structure(), WriteBarrierForGenericAccess);
+        writeBarrier(baseGPR, node.structureTransitionData().newStructure, WriteBarrierForGenericAccess);
 #endif
         
-        m_jit.storePtr(MacroAssembler::TrustedImmPtr(node.structure()), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
+        m_jit.storePtr(MacroAssembler::TrustedImmPtr(node.structureTransitionData().newStructure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
         
         noResult(m_compileIndex);
         break;
diff --git a/Source/JavaScriptCore/dfg/DFGStructureSet.h b/Source/JavaScriptCore/dfg/DFGStructureSet.h
new file mode 100644 (file)
index 0000000..7afd01d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGStructureSet_h
+#define DFGStructureSet_h
+
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class Structure;
+
+namespace DFG {
+
+class StructureSet {
+public:
+    StructureSet() { }
+    
+    StructureSet(Structure* structure)
+    {
+        m_structures.append(structure);
+    }
+    
+    void add(Structure* structure)
+    {
+        ASSERT(!contains(structure));
+        m_structures.append(structure);
+    }
+    
+    bool addAll(const StructureSet& other)
+    {
+        bool changed = false;
+        for (size_t i = 0; i < other.size(); ++i) {
+            if (contains(other[i]))
+                continue;
+            add(other[i]);
+            changed = true;
+        }
+        return changed;
+    }
+    
+    void remove(Structure* structure)
+    {
+        for (size_t i = 0; i < m_structures.size(); ++i) {
+            if (m_structures[i] != structure)
+                continue;
+            
+            m_structures[i] = m_structures.last();
+            m_structures.removeLast();
+            return;
+        }
+    }
+    
+    bool contains(Structure* structure) const
+    {
+        for (size_t i = 0; i < m_structures.size(); ++i) {
+            if (m_structures[i] == structure)
+                return true;
+        }
+        return false;
+    }
+    
+    bool isSubsetOf(const StructureSet& other) const
+    {
+        for (size_t i = 0; i < m_structures.size(); ++i) {
+            if (!other.contains(m_structures[i]))
+                return false;
+        }
+        return true;
+    }
+    
+    bool isSupersetOf(const StructureSet& other) const
+    {
+        return other.isSubsetOf(*this);
+    }
+    
+    size_t size() const { return m_structures.size(); }
+    
+    Structure* at(size_t i) const { return m_structures.at(i); }
+    
+    Structure* operator[](size_t i) const { return at(i); }
+    
+    Structure* last() const { return m_structures.last(); }
+
+private:
+    Vector<Structure*, 2> m_structures;
+};
+
+} } // namespace JSC::DFG
+
+#endif // DFGStructureSet_h
index d6e5daa..a46a8e8 100644 (file)
@@ -702,6 +702,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
 {
     Jump failureCase = checkStructure(regT0, structure);
     bool needsStubLink = false;
+    bool isDirect = false;
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
         needsStubLink = true;
         compileGetDirectOffset(regT0, regT1, cachedOffset);
@@ -718,8 +719,10 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
         stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
         stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
-    } else
+    } else {
+        isDirect = true;
         compileGetDirectOffset(regT0, regT0, cachedOffset);
+    }
     Jump success = jump();
 
     LinkBuffer patchBuffer(*m_globalData, this);
@@ -743,7 +746,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
 
     MacroAssemblerCodeRef stubCode = patchBuffer.finalizeCode();
 
-    polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubCode, structure);
+    polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubCode, structure, isDirect);
 
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -766,6 +769,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
 
     // Checks out okay!
     bool needsStubLink = false;
+    bool isDirect = false;
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
         needsStubLink = true;
         compileGetDirectOffset(protoObject, regT1, cachedOffset);
@@ -782,8 +786,10 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
         stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
         stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
-    } else
+    } else {
+        isDirect = true;
         compileGetDirectOffset(protoObject, regT0, cachedOffset);
+    }
 
     Jump success = jump();
 
@@ -805,7 +811,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
     patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
 
     MacroAssemblerCodeRef stubCode = patchBuffer.finalizeCode();
-    prototypeStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubCode, structure, prototypeStructure);
+    prototypeStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubCode, structure, prototypeStructure, isDirect);
 
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -833,6 +839,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
     ASSERT(protoObject);
     
     bool needsStubLink = false;
+    bool isDirect = false;
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
         needsStubLink = true;
         compileGetDirectOffset(protoObject, regT1, cachedOffset);
@@ -849,8 +856,10 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
         stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
         stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
-    } else
+    } else {
+        isDirect = true;
         compileGetDirectOffset(protoObject, regT0, cachedOffset);
+    }
     Jump success = jump();
 
     LinkBuffer patchBuffer(*m_globalData, this);
@@ -873,7 +882,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
     CodeRef stubRoutine = patchBuffer.finalizeCode();
 
     // Track the stub we have created so that it will be deleted later.
-    prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, chain);
+    prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, chain, isDirect);
 
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
index 56a910d..16366a2 100644 (file)
@@ -700,6 +700,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
     // regT0 holds a JSCell*
     Jump failureCase = checkStructure(regT0, structure);
     bool needsStubLink = false;
+    bool isDirect = false;
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
         needsStubLink = true;
         compileGetDirectOffset(regT0, regT2, regT1, cachedOffset);
@@ -716,8 +717,10 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
         stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
         stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
-    } else
+    } else {
+        isDirect = true;
         compileGetDirectOffset(regT0, regT1, regT0, cachedOffset);
+    }
 
     Jump success = jump();
     
@@ -740,7 +743,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
 
     CodeRef stubRoutine = patchBuffer.finalizeCode();
 
-    polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubRoutine, structure);
+    polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubRoutine, structure, isDirect);
     
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -764,6 +767,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
     Jump failureCases2 = branchPtr(NotEqual, Address(regT3, JSCell::structureOffset()), TrustedImmPtr(prototypeStructure));
     
     bool needsStubLink = false;
+    bool isDirect = false;
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
         needsStubLink = true;
         compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset);
@@ -780,8 +784,10 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
         stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
         stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
-    } else
+    } else {
+        isDirect = true;
         compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
+    }
     
     Jump success = jump();
     
@@ -802,7 +808,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
     
     CodeRef stubRoutine = patchBuffer.finalizeCode();
 
-    prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, prototypeStructure);
+    prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, prototypeStructure, isDirect);
     
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -831,6 +837,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
     ASSERT(protoObject);
     
     bool needsStubLink = false;
+    bool isDirect = false;
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
         needsStubLink = true;
         compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset);
@@ -847,8 +854,10 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
         stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
         stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
-    } else
+    } else {
+        isDirect = true;
         compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
+    }
 
     Jump success = jump();
     
@@ -870,7 +879,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
     CodeRef stubRoutine = patchBuffer.finalizeCode();
     
     // Track the stub we have created so that it will be deleted later.
-    prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, chain);
+    prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, chain, isDirect);
     
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
index 4c05ba1..d7d305c 100644 (file)
@@ -1698,7 +1698,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
 
         if (stubInfo->accessType == access_get_by_id_self) {
             ASSERT(!stubInfo->stubRoutine);
-            polymorphicStructureList = new PolymorphicAccessStructureList(callFrame->globalData(), codeBlock->ownerExecutable(), MacroAssemblerCodeRef(), stubInfo->u.getByIdSelf.baseObjectStructure.get());
+            polymorphicStructureList = new PolymorphicAccessStructureList(callFrame->globalData(), codeBlock->ownerExecutable(), MacroAssemblerCodeRef(), stubInfo->u.getByIdSelf.baseObjectStructure.get(), true);
             stubInfo->initGetByIdSelfList(polymorphicStructureList, 1);
         } else {
             polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList;
@@ -1723,12 +1723,12 @@ static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(JSG
 
     switch (stubInfo->accessType) {
     case access_get_by_id_proto:
-        prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure.get(), stubInfo->u.getByIdProto.prototypeStructure.get());
+        prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure.get(), stubInfo->u.getByIdProto.prototypeStructure.get(), true);
         stubInfo->stubRoutine = MacroAssemblerCodeRef();
         stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
         break;
     case access_get_by_id_chain:
-        prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure.get(), stubInfo->u.getByIdChain.chain.get());
+        prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure.get(), stubInfo->u.getByIdChain.chain.get(), true);
         stubInfo->stubRoutine = MacroAssemblerCodeRef();
         stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
         break;