DFG should not have code that directly decodes the states of old JIT inline
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 22 Jan 2012 01:36:23 +0000 (01:36 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 22 Jan 2012 01:36:23 +0000 (01:36 +0000)
cache data structures
https://bugs.webkit.org/show_bug.cgi?id=76768

Reviewed by Sam Weinig.

Introduced new classes (like GetByIdStatus) that encapsulate the set of things
that the DFG would like to know about property accesses and calls. Whereas it
previously got this information by directly decoding the data structures used
by the old JIT for inline caching, it now uses these classes, which do the work
for it. This should make it somewhat more straight forward to introduce new
ways of profiling the same information.

Also hoisted StructureSet into bytecode/ from dfg/, because it's now used by
code in bytecode/.

Making this work right involved carefully ensuring that the heuristics for
choosing how to handle property accesses was at least as good as what we had
before, since I completely restructured that code. Currently the performance
looks neutral. Since I rewrote the code I did change some things that I never
liked before, like previously if a put_bu_id had executed exactly once then
we'd compile it as if it had taken slow-path. Executing once is special because
then the inline cache is not baked in, so there is no information about how the
DFG should optimize the code. Now this is rationalized: if the put_by_id does
not offer enough information to be optimized (i.e. had executed 0 or 1 times)
then we turn it into a forced OSR exit (i.e. a patch point). However, get_by_id
still has the old behavior; I left it that way because I didn't want to make
too many changes at once.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CallLinkStatus.cpp: Added.
(JSC::CallLinkStatus::computeFor):
* bytecode/CallLinkStatus.h: Added.
(JSC::CallLinkStatus::CallLinkStatus):
(JSC::CallLinkStatus::isSet):
(JSC::CallLinkStatus::operator!):
(JSC::CallLinkStatus::couldTakeSlowPath):
(JSC::CallLinkStatus::callTarget):
* bytecode/GetByIdStatus.cpp: Added.
(JSC::GetByIdStatus::computeFor):
* bytecode/GetByIdStatus.h: Added.
(JSC::GetByIdStatus::GetByIdStatus):
(JSC::GetByIdStatus::state):
(JSC::GetByIdStatus::isSet):
(JSC::GetByIdStatus::operator!):
(JSC::GetByIdStatus::isSimpleDirect):
(JSC::GetByIdStatus::takesSlowPath):
(JSC::GetByIdStatus::makesCalls):
(JSC::GetByIdStatus::structureSet):
(JSC::GetByIdStatus::offset):
* bytecode/MethodCallLinkStatus.cpp: Added.
(JSC::MethodCallLinkStatus::computeFor):
* bytecode/MethodCallLinkStatus.h: Added.
(JSC::MethodCallLinkStatus::MethodCallLinkStatus):
(JSC::MethodCallLinkStatus::isSet):
(JSC::MethodCallLinkStatus::operator!):
(JSC::MethodCallLinkStatus::needsPrototypeCheck):
(JSC::MethodCallLinkStatus::structure):
(JSC::MethodCallLinkStatus::prototypeStructure):
(JSC::MethodCallLinkStatus::function):
(JSC::MethodCallLinkStatus::prototype):
* bytecode/PutByIdStatus.cpp: Added.
(JSC::PutByIdStatus::computeFor):
* bytecode/PutByIdStatus.h: Added.
(JSC::PutByIdStatus::PutByIdStatus):
(JSC::PutByIdStatus::state):
(JSC::PutByIdStatus::isSet):
(JSC::PutByIdStatus::operator!):
(JSC::PutByIdStatus::isSimpleReplace):
(JSC::PutByIdStatus::isSimpleTransition):
(JSC::PutByIdStatus::takesSlowPath):
(JSC::PutByIdStatus::oldStructure):
(JSC::PutByIdStatus::newStructure):
(JSC::PutByIdStatus::structureChain):
(JSC::PutByIdStatus::offset):
* bytecode/StructureSet.h: Added.
(JSC::StructureSet::StructureSet):
(JSC::StructureSet::clear):
(JSC::StructureSet::add):
(JSC::StructureSet::addAll):
(JSC::StructureSet::remove):
(JSC::StructureSet::contains):
(JSC::StructureSet::isSubsetOf):
(JSC::StructureSet::isSupersetOf):
(JSC::StructureSet::size):
(JSC::StructureSet::at):
(JSC::StructureSet::operator[]):
(JSC::StructureSet::last):
(JSC::StructureSet::predictionFromStructures):
(JSC::StructureSet::operator==):
(JSC::StructureSet::dump):
* dfg/DFGAbstractValue.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGStructureSet.h: Removed.

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

17 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/bytecode/CallLinkStatus.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/CallLinkStatus.h [new file with mode: 0644]
Source/JavaScriptCore/bytecode/GetByIdStatus.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/GetByIdStatus.h [new file with mode: 0644]
Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h [new file with mode: 0644]
Source/JavaScriptCore/bytecode/PutByIdStatus.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/PutByIdStatus.h [new file with mode: 0644]
Source/JavaScriptCore/bytecode/StructureSet.h [moved from Source/JavaScriptCore/dfg/DFGStructureSet.h with 94% similarity]
Source/JavaScriptCore/dfg/DFGAbstractValue.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

index db56a3b..8317997 100644 (file)
@@ -35,12 +35,16 @@ SET(JavaScriptCore_SOURCES
     API/OpaqueJSString.cpp
 
     bytecode/CallLinkInfo.cpp
+    bytecode/CallLinkStatus.cpp
     bytecode/CodeBlock.cpp
     bytecode/DFGExitProfile.cpp
+    bytecode/GetByIdStatus.cpp
     bytecode/JumpTable.cpp
     bytecode/MethodCallLinkInfo.cpp
+    bytecode/MethodCallLinkStatus.cpp
     bytecode/Opcode.cpp
     bytecode/PredictedType.cpp
+    bytecode/PutByIdStatus.cpp
     bytecode/SamplingTool.cpp
     bytecode/StructureStubInfo.cpp
     bytecode/ValueProfile.cpp
index 7aaf6d7..cfc6691 100644 (file)
@@ -1,5 +1,108 @@
 2012-01-20  Filip Pizlo  <fpizlo@apple.com>
 
+        DFG should not have code that directly decodes the states of old JIT inline
+        cache data structures
+        https://bugs.webkit.org/show_bug.cgi?id=76768
+
+        Reviewed by Sam Weinig.
+        
+        Introduced new classes (like GetByIdStatus) that encapsulate the set of things
+        that the DFG would like to know about property accesses and calls. Whereas it
+        previously got this information by directly decoding the data structures used
+        by the old JIT for inline caching, it now uses these classes, which do the work
+        for it. This should make it somewhat more straight forward to introduce new
+        ways of profiling the same information.
+        
+        Also hoisted StructureSet into bytecode/ from dfg/, because it's now used by
+        code in bytecode/.
+        
+        Making this work right involved carefully ensuring that the heuristics for
+        choosing how to handle property accesses was at least as good as what we had
+        before, since I completely restructured that code. Currently the performance
+        looks neutral. Since I rewrote the code I did change some things that I never
+        liked before, like previously if a put_bu_id had executed exactly once then
+        we'd compile it as if it had taken slow-path. Executing once is special because
+        then the inline cache is not baked in, so there is no information about how the
+        DFG should optimize the code. Now this is rationalized: if the put_by_id does
+        not offer enough information to be optimized (i.e. had executed 0 or 1 times)
+        then we turn it into a forced OSR exit (i.e. a patch point). However, get_by_id
+        still has the old behavior; I left it that way because I didn't want to make
+        too many changes at once.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * bytecode/CallLinkStatus.cpp: Added.
+        (JSC::CallLinkStatus::computeFor):
+        * bytecode/CallLinkStatus.h: Added.
+        (JSC::CallLinkStatus::CallLinkStatus):
+        (JSC::CallLinkStatus::isSet):
+        (JSC::CallLinkStatus::operator!):
+        (JSC::CallLinkStatus::couldTakeSlowPath):
+        (JSC::CallLinkStatus::callTarget):
+        * bytecode/GetByIdStatus.cpp: Added.
+        (JSC::GetByIdStatus::computeFor):
+        * bytecode/GetByIdStatus.h: Added.
+        (JSC::GetByIdStatus::GetByIdStatus):
+        (JSC::GetByIdStatus::state):
+        (JSC::GetByIdStatus::isSet):
+        (JSC::GetByIdStatus::operator!):
+        (JSC::GetByIdStatus::isSimpleDirect):
+        (JSC::GetByIdStatus::takesSlowPath):
+        (JSC::GetByIdStatus::makesCalls):
+        (JSC::GetByIdStatus::structureSet):
+        (JSC::GetByIdStatus::offset):
+        * bytecode/MethodCallLinkStatus.cpp: Added.
+        (JSC::MethodCallLinkStatus::computeFor):
+        * bytecode/MethodCallLinkStatus.h: Added.
+        (JSC::MethodCallLinkStatus::MethodCallLinkStatus):
+        (JSC::MethodCallLinkStatus::isSet):
+        (JSC::MethodCallLinkStatus::operator!):
+        (JSC::MethodCallLinkStatus::needsPrototypeCheck):
+        (JSC::MethodCallLinkStatus::structure):
+        (JSC::MethodCallLinkStatus::prototypeStructure):
+        (JSC::MethodCallLinkStatus::function):
+        (JSC::MethodCallLinkStatus::prototype):
+        * bytecode/PutByIdStatus.cpp: Added.
+        (JSC::PutByIdStatus::computeFor):
+        * bytecode/PutByIdStatus.h: Added.
+        (JSC::PutByIdStatus::PutByIdStatus):
+        (JSC::PutByIdStatus::state):
+        (JSC::PutByIdStatus::isSet):
+        (JSC::PutByIdStatus::operator!):
+        (JSC::PutByIdStatus::isSimpleReplace):
+        (JSC::PutByIdStatus::isSimpleTransition):
+        (JSC::PutByIdStatus::takesSlowPath):
+        (JSC::PutByIdStatus::oldStructure):
+        (JSC::PutByIdStatus::newStructure):
+        (JSC::PutByIdStatus::structureChain):
+        (JSC::PutByIdStatus::offset):
+        * bytecode/StructureSet.h: Added.
+        (JSC::StructureSet::StructureSet):
+        (JSC::StructureSet::clear):
+        (JSC::StructureSet::add):
+        (JSC::StructureSet::addAll):
+        (JSC::StructureSet::remove):
+        (JSC::StructureSet::contains):
+        (JSC::StructureSet::isSubsetOf):
+        (JSC::StructureSet::isSupersetOf):
+        (JSC::StructureSet::size):
+        (JSC::StructureSet::at):
+        (JSC::StructureSet::operator[]):
+        (JSC::StructureSet::last):
+        (JSC::StructureSet::predictionFromStructures):
+        (JSC::StructureSet::operator==):
+        (JSC::StructureSet::dump):
+        * dfg/DFGAbstractValue.h:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleCall):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGStructureSet.h: Removed.
+
+2012-01-20  Filip Pizlo  <fpizlo@apple.com>
+
         JIT compilation should not require ExecState
         https://bugs.webkit.org/show_bug.cgi?id=76729
         <rdar://problem/10731545>
index 27b8684..ebd5ce1 100644 (file)
@@ -83,6 +83,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/assembler/X86Assembler.h \
        Source/JavaScriptCore/bytecode/CallLinkInfo.cpp \
        Source/JavaScriptCore/bytecode/CallLinkInfo.h \
+       Source/JavaScriptCore/bytecode/CallLinkStatus.cpp \
+       Source/JavaScriptCore/bytecode/CallLinkStatus.h \
        Source/JavaScriptCore/bytecode/CallReturnOffsetToBytecodeOffset.h \
        Source/JavaScriptCore/bytecode/CodeType.h \
        Source/JavaScriptCore/bytecode/CodeBlock.cpp \
@@ -93,6 +95,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/bytecode/DFGExitProfile.h \
        Source/JavaScriptCore/bytecode/EvalCodeCache.h \
        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 \
@@ -101,11 +105,15 @@ javascriptcore_sources += \
        Source/JavaScriptCore/bytecode/LineInfo.h \
        Source/JavaScriptCore/bytecode/MethodCallLinkInfo.cpp \
        Source/JavaScriptCore/bytecode/MethodCallLinkInfo.h \
+       Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp \
+       Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h \
        Source/JavaScriptCore/bytecode/Opcode.cpp \
        Source/JavaScriptCore/bytecode/Opcode.h \
        Source/JavaScriptCore/bytecode/PredictedType.cpp \
        Source/JavaScriptCore/bytecode/PredictedType.h \
        Source/JavaScriptCore/bytecode/PredictionTracker.h \
+       Source/JavaScriptCore/bytecode/PutByIdStatus.cpp \
+       Source/JavaScriptCore/bytecode/PutByIdStatus.h \
        Source/JavaScriptCore/bytecode/SamplingTool.cpp \
        Source/JavaScriptCore/bytecode/SamplingTool.h \
        Source/JavaScriptCore/bytecode/StructureStubInfo.cpp \
index 3862212..f4a5785 100644 (file)
                        Name="bytecode"
                        >
                        <File
+                               RelativePath="..\..\bytecode\GetByIdStatus.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\PutByIdStatus.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\CallLinkStatus.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\MethodCallLinkStatus.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\GetByIdStatus.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\PutByIdStatus.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\CallLinkStatus.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\MethodCallLinkStatus.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\bytecode\HandlerInfo.h"
                                >
                        </File>
index a6f629a..508fee3 100644 (file)
                0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F7B294C14C3CD43007C3DB1 /* DFGByteCodeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0977E1469EBC400CF2442 /* DFGCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */; };
+               0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F93329F14CA7DCA0085F3C6 /* GetByIdStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */; };
+               0F9332A014CA7DCD0085F3C6 /* GetByIdStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F9332A114CA7DD10085F3C6 /* MethodCallLinkStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329714CA7DC10085F3C6 /* MethodCallLinkStatus.cpp */; };
+               0F9332A214CA7DD30085F3C6 /* MethodCallLinkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329814CA7DC10085F3C6 /* MethodCallLinkStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F9332A314CA7DD70085F3C6 /* PutByIdStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */; };
+               0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329B14CA7DC10085F3C6 /* StructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F963B2713F753BB0002D9B2 /* RedBlackTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B2613F753990002D9B2 /* RedBlackTree.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F963B2C13F853EC0002D9B2 /* MetaAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F963B2B13F853C70002D9B2 /* MetaAllocator.cpp */; settings = {COMPILER_FLAGS = "-fno-strict-aliasing"; }; };
                0F963B2D13F854020002D9B2 /* MetaAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B2A13F853BD0002D9B2 /* MetaAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FD82F4B142806A100179C94 /* BitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82F491428069200179C94 /* BitVector.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.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 */; };
                0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; };
                0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; };
                0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCCallHelpers.h; path = dfg/DFGCCallHelpers.h; sourceTree = "<group>"; };
+               0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallLinkStatus.cpp; sourceTree = "<group>"; };
+               0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallLinkStatus.h; sourceTree = "<group>"; };
+               0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetByIdStatus.cpp; sourceTree = "<group>"; };
+               0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetByIdStatus.h; sourceTree = "<group>"; };
+               0F93329714CA7DC10085F3C6 /* MethodCallLinkStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MethodCallLinkStatus.cpp; sourceTree = "<group>"; };
+               0F93329814CA7DC10085F3C6 /* MethodCallLinkStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodCallLinkStatus.h; sourceTree = "<group>"; };
+               0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByIdStatus.cpp; sourceTree = "<group>"; };
+               0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdStatus.h; sourceTree = "<group>"; };
+               0F93329B14CA7DC10085F3C6 /* StructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureSet.h; sourceTree = "<group>"; };
                0F963B2613F753990002D9B2 /* RedBlackTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RedBlackTree.h; sourceTree = "<group>"; };
                0F963B2A13F853BD0002D9B2 /* MetaAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MetaAllocator.h; sourceTree = "<group>"; };
                0F963B2B13F853C70002D9B2 /* MetaAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MetaAllocator.cpp; sourceTree = "<group>"; };
                0FD82F491428069200179C94 /* BitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitVector.h; sourceTree = "<group>"; };
                0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; };
                0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.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>"; };
                                86EC9DC31328DF82002B2AD7 /* DFGSpeculativeJIT.h */,
                                86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */,
                                86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */,
-                               0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */,
                                0FC0979F146B28C700CF2442 /* DFGThunks.cpp */,
                                0FC097A0146B28C700CF2442 /* DFGThunks.h */,
                                0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */,
                969A078F0ED1D3AE00F1F681 /* bytecode */ = {
                        isa = PBXGroup;
                        children = (
+                               0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */,
+                               0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */,
+                               0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
+                               0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
+                               0F93329714CA7DC10085F3C6 /* MethodCallLinkStatus.cpp */,
+                               0F93329814CA7DC10085F3C6 /* MethodCallLinkStatus.h */,
+                               0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
+                               0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
+                               0F93329B14CA7DC10085F3C6 /* StructureSet.h */,
                                0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */,
                                0F0B83B614BCF8DF00885B4F /* GlobalResolveInfo.h */,
                                0F0B83B214BCF85E00885B4F /* MethodCallLinkInfo.cpp */,
                                86BB09C1138E381B0056702F /* DFGRepatch.h in Headers */,
                                86ECA3FA132DF25A002B2AD7 /* DFGScoreBoard.h in Headers */,
                                86EC9DD31328DF82002B2AD7 /* DFGSpeculativeJIT.h in Headers */,
-                               0FFF4BB4143955E900655BC0 /* DFGStructureSet.h in Headers */,
                                0FC097A2146B28CC00CF2442 /* DFGThunks.h in Headers */,
                                0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */,
                                BC18C3FD0E16F5CD00B34460 /* DisallowCType.h in Headers */,
                                0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */,
                                91A3905614C0F47200F67901 /* Uint8ClampedArray.h in Headers */,
                                F69E86C414C6E551002C2C62 /* NumberOfCores.h in Headers */,
+                               0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */,
+                               0F9332A014CA7DCD0085F3C6 /* GetByIdStatus.h in Headers */,
+                               0F9332A214CA7DD30085F3C6 /* MethodCallLinkStatus.h in Headers */,
+                               0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */,
+                               0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                0F0B83B014BCF71600885B4F /* CallLinkInfo.cpp in Sources */,
                                0F0B83B414BCF86000885B4F /* MethodCallLinkInfo.cpp in Sources */,
                                F69E86C314C6E551002C2C62 /* NumberOfCores.cpp in Sources */,
+                               0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */,
+                               0F93329F14CA7DCA0085F3C6 /* GetByIdStatus.cpp in Sources */,
+                               0F9332A114CA7DD10085F3C6 /* MethodCallLinkStatus.cpp in Sources */,
+                               0F9332A314CA7DD70085F3C6 /* PutByIdStatus.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 002b48d..3ef6ab9 100644 (file)
@@ -50,12 +50,16 @@ SOURCES += \
     assembler/MacroAssemblerARM.cpp \
     assembler/MacroAssemblerSH4.cpp \
     bytecode/CallLinkInfo.cpp \
+    bytecode/CallLinkStatus.cpp \
     bytecode/CodeBlock.cpp \
     bytecode/DFGExitProfile.cpp \
+    bytecode/GetByIdStatus.cpp \
     bytecode/JumpTable.cpp \
     bytecode/MethodCallLinkInfo.cpp \
+    bytecode/MethodCallLinkStatus.cpp \
     bytecode/Opcode.cpp \
     bytecode/PredictedType.cpp \
+    bytecode/PutByIdStatus.cpp \
     bytecode/SamplingTool.cpp \
     bytecode/StructureStubInfo.cpp \
     bytecode/ValueProfile.cpp \
diff --git a/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp b/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
new file mode 100644 (file)
index 0000000..abedc84
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 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. 
+ */
+
+#include "config.h"
+#include "CallLinkStatus.h"
+
+#include "CodeBlock.h"
+
+namespace JSC {
+
+CallLinkStatus CallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex)
+{
+#if ENABLE(JIT)
+    return CallLinkStatus(
+        profiledBlock->getCallLinkInfo(bytecodeIndex).lastSeenCallee.get(),
+        profiledBlock->couldTakeSlowCase(bytecodeIndex));
+#else
+    return CallLinkStatus(0, false);
+#endif
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/CallLinkStatus.h b/Source/JavaScriptCore/bytecode/CallLinkStatus.h
new file mode 100644 (file)
index 0000000..e1c7410
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 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 CallLinkStatus_h
+#define CallLinkStatus_h
+
+namespace JSC {
+
+class JSFunction;
+class CodeBlock;
+
+class CallLinkStatus {
+public:
+    CallLinkStatus()
+        : m_callTarget(0)
+        , m_couldTakeSlowPath(false)
+    {
+    }
+    
+    CallLinkStatus(JSFunction* callTarget, bool couldTakeSlowPath)
+        : m_callTarget(callTarget)
+        , m_couldTakeSlowPath(couldTakeSlowPath)
+    {
+    }
+    
+    static CallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex);
+    
+    bool isSet() const { return !!m_callTarget; }
+    
+    bool operator!() const { return !m_callTarget; }
+    
+    bool couldTakeSlowPath() const { return m_couldTakeSlowPath; }
+    
+    JSFunction* callTarget() const { return m_callTarget; }
+    
+private:
+    JSFunction* m_callTarget;
+    bool m_couldTakeSlowPath;
+};
+
+} // namespace JSC
+
+#endif // CallLinkStatus_h
+
diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
new file mode 100644 (file)
index 0000000..a001e82
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 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. 
+ */
+
+#include "config.h"
+#include "GetByIdStatus.h"
+
+#include "CodeBlock.h"
+
+namespace JSC {
+
+GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident)
+{
+#if ENABLE(JIT)
+    // First check if it makes either calls, in which case we want to be super careful, or
+    // if it's not set at all, in which case we punt.
+    StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex);
+    if (!stubInfo.seen)
+        return GetByIdStatus(NoInformation, StructureSet(), notFound);
+    
+    PolymorphicAccessStructureList* list;
+    int listSize;
+    switch (stubInfo.accessType) {
+    case access_get_by_id_self_list:
+        list = stubInfo.u.getByIdSelfList.structureList;
+        listSize = stubInfo.u.getByIdSelfList.listSize;
+        break;
+    case access_get_by_id_proto_list:
+        list = stubInfo.u.getByIdProtoList.structureList;
+        listSize = stubInfo.u.getByIdProtoList.listSize;
+        break;
+    default:
+        list = 0;
+        listSize = 0;
+        break;
+    }
+    for (int i = 0; i < listSize; ++i) {
+        if (!list->list[i].isDirect)
+            return GetByIdStatus(MakesCalls, StructureSet(), notFound);
+    }
+    
+    // Next check if it takes slow case, in which case we want to be kind of careful.
+    if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex))
+        return GetByIdStatus(TakesSlowPath, StructureSet(), notFound);
+    
+    // Finally figure out if we can derive an access strategy.
+    GetByIdStatus result;
+    switch (stubInfo.accessType) {
+    case access_unset:
+        return GetByIdStatus(NoInformation, StructureSet(), notFound);
+        
+    case access_get_by_id_self: {
+        Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
+        result.m_offset = structure->get(*profiledBlock->globalData(), ident);
+        
+        if (result.m_offset != notFound)
+            result.m_structureSet.add(structure);
+        
+        if (result.m_offset != notFound)
+            ASSERT(result.m_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) {
+            ASSERT(list->list[i].isDirect);
+            
+            Structure* structure = list->list[i].base.get();
+            if (result.m_structureSet.contains(structure))
+                continue;
+            
+            size_t myOffset = structure->get(*profiledBlock->globalData(), ident);
+            
+            if (myOffset == notFound) {
+                result.m_offset = notFound;
+                break;
+            }
+                    
+            if (!i)
+                result.m_offset = myOffset;
+            else if (result.m_offset != myOffset) {
+                result.m_offset = notFound;
+                break;
+            }
+                    
+            result.m_structureSet.add(structure);
+        }
+                    
+        if (result.m_offset != notFound)
+            ASSERT(result.m_structureSet.size());
+        break;
+    }
+        
+    default:
+        ASSERT(result.m_offset == notFound);
+        break;
+    }
+    
+    if (result.m_offset == notFound) {
+        result.m_state = TakesSlowPath;
+        result.m_structureSet.clear();
+    } else
+        result.m_state = SimpleDirect;
+    
+    return result;
+#else // ENABLE(JIT)
+    return GetByIdStatus(NoInformation, StructureSet(), notFound);
+#endif // ENABLE(JIT)
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.h b/Source/JavaScriptCore/bytecode/GetByIdStatus.h
new file mode 100644 (file)
index 0000000..00e50e7
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012 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 GetByIdStatus_h
+#define GetByIdStatus_h
+
+#include "StructureSet.h"
+#include <wtf/NotFound.h>
+
+namespace JSC {
+
+class CodeBlock;
+class Identifier;
+
+class GetByIdStatus {
+public:
+    enum State {
+        NoInformation,  // It's uncached so we have no information.
+        SimpleDirect,   // It's cached for a direct access to a known object property.
+        TakesSlowPath,  // It's known to often take slow path.
+        MakesCalls      // It's known to take paths that make calls.
+    };
+
+    GetByIdStatus()
+        : m_state(NoInformation)
+        , m_offset(notFound)
+    {
+    }
+    
+    GetByIdStatus(State state, const StructureSet& structureSet, size_t offset)
+        : m_state(state)
+        , m_structureSet(structureSet)
+        , m_offset(offset)
+    {
+        ASSERT((state == SimpleDirect) == (offset != notFound));
+    }
+    
+    static GetByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
+    
+    State state() const { return m_state; }
+    
+    bool isSet() const { return m_state != NoInformation; }
+    bool operator!() const { return !isSet(); }
+    bool isSimpleDirect() const { return m_state == SimpleDirect; }
+    bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; }
+    bool makesCalls() const { return m_state == MakesCalls; }
+    
+    const StructureSet& structureSet() const { return m_structureSet; }
+    size_t offset() const { return m_offset; }
+    
+private:
+    State m_state;
+    StructureSet m_structureSet;
+    size_t m_offset;
+};
+
+} // namespace JSC
+
+#endif // PropertyAccessStatus_h
+
diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp
new file mode 100644 (file)
index 0000000..44704ef
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 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. 
+ */
+
+#include "config.h"
+#include "MethodCallLinkStatus.h"
+
+#include "CodeBlock.h"
+
+namespace JSC {
+
+MethodCallLinkStatus MethodCallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex)
+{
+#if ENABLE(JIT)
+    MethodCallLinkInfo& methodCall = profiledBlock->getMethodCallLinkInfo(bytecodeIndex);
+    
+    if (!methodCall.seen || !methodCall.cachedStructure)
+        return MethodCallLinkStatus();
+    
+    if (methodCall.cachedPrototype.get() == profiledBlock->globalObject()->methodCallDummy()) {
+        return MethodCallLinkStatus(
+            methodCall.cachedStructure.get(),
+            0,
+            methodCall.cachedFunction.get(),
+            0);
+    }
+    
+    return MethodCallLinkStatus(
+        methodCall.cachedStructure.get(),
+        methodCall.cachedPrototypeStructure.get(),
+        methodCall.cachedFunction.get(),
+        methodCall.cachedPrototype.get());
+#else // ENABLE(JIT)
+    return MethodCallLinkStatus();
+#endif // ENABLE(JIT)
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h
new file mode 100644 (file)
index 0000000..c3d11a1
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 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 MethodCallLinkStatus_h
+#define MethodCallLinkStatus_h
+
+namespace JSC {
+
+class CodeBlock;
+class JSObject;
+class Structure;
+
+class MethodCallLinkStatus {
+public:
+    MethodCallLinkStatus()
+        : m_structure(0)
+        , m_prototypeStructure(0)
+        , m_function(0)
+        , m_prototype(0)
+    {
+    }
+    
+    MethodCallLinkStatus(
+        Structure* structure,
+        Structure* prototypeStructure,
+        JSObject* function,
+        JSObject* prototype)
+        : m_structure(structure)
+        , m_prototypeStructure(prototypeStructure)
+        , m_function(function)
+        , m_prototype(prototype)
+    {
+        if (!m_function) {
+            ASSERT(!m_structure);
+            ASSERT(!m_prototypeStructure);
+            ASSERT(!m_prototype);
+        } else
+            ASSERT(m_structure);
+        
+        ASSERT(!m_prototype == !m_prototypeStructure);
+    }
+    
+    static MethodCallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex);
+
+    bool isSet() const { return !!m_function; }
+    bool operator!() const { return !m_function; }
+    
+    bool needsPrototypeCheck() const { return !!m_prototype; }
+    
+    Structure* structure() { return m_structure; }
+    Structure* prototypeStructure() { return m_prototypeStructure; }
+    JSObject* function() const { return m_function; }
+    JSObject* prototype() const { return m_prototype; }
+    
+private:
+    Structure* m_structure;
+    Structure* m_prototypeStructure;
+    JSObject* m_function;
+    JSObject* m_prototype;
+};
+
+} // namespace JSC
+
+#endif // MethodCallLinkStatus_h
+
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
new file mode 100644 (file)
index 0000000..aa0e5f6
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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. 
+ */
+
+#include "config.h"
+#include "PutByIdStatus.h"
+
+#include "CodeBlock.h"
+#include "Structure.h"
+#include "StructureChain.h"
+
+namespace JSC {
+
+PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident)
+{
+#if ENABLE(JIT)
+    if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex))
+        return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound);
+    
+    StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex);
+    if (!stubInfo.seen)
+        return PutByIdStatus(NoInformation, 0, 0, 0, notFound);
+    
+    switch (stubInfo.accessType) {
+    case access_unset:
+        return PutByIdStatus(NoInformation, 0, 0, 0, notFound);
+        
+    case access_put_by_id_replace: {
+        size_t offset = stubInfo.u.putByIdReplace.baseObjectStructure->get(
+            *profiledBlock->globalData(), ident);
+        if (offset != notFound) {
+            return PutByIdStatus(
+                SimpleReplace,
+                stubInfo.u.putByIdReplace.baseObjectStructure.get(),
+                0, 0,
+                offset);
+        }
+        return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound);
+    }
+        
+    case access_put_by_id_transition_normal:
+    case access_put_by_id_transition_direct: {
+        size_t offset = stubInfo.u.putByIdTransition.structure->get(
+            *profiledBlock->globalData(), ident);
+        if (offset != notFound) {
+            return PutByIdStatus(
+                SimpleTransition,
+                stubInfo.u.putByIdTransition.previousStructure.get(),
+                stubInfo.u.putByIdTransition.structure.get(),
+                stubInfo.u.putByIdTransition.chain.get(),
+                offset);
+        }
+        return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound);
+    }
+        
+    default:
+        return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound);
+    }
+#else // ENABLE(JIT)
+    return PutByIdStatus(NoInformation, 0, 0, 0, notFound);
+#endif // ENABLE(JIT)
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.h b/Source/JavaScriptCore/bytecode/PutByIdStatus.h
new file mode 100644 (file)
index 0000000..b33f4d0
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 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 PutByIdStatus_h
+#define PutByIdStatus_h
+
+#include <wtf/NotFound.h>
+
+namespace JSC {
+
+class CodeBlock;
+class Identifier;
+class Structure;
+class StructureChain;
+
+class PutByIdStatus {
+public:
+    enum State {
+        // It's uncached so we have no information.
+        NoInformation,
+        // It's cached as a direct store into an object property for cases where the object
+        // already has the property.
+        SimpleReplace,
+        // It's cached as a transition from one structure that lacks the property to one that
+        // includes the property, and a direct store to this new property.
+        SimpleTransition,
+        // It's known to often take slow path.
+        TakesSlowPath
+    };
+    
+    PutByIdStatus()
+        : m_state(NoInformation)
+        , m_oldStructure(0)
+        , m_newStructure(0)
+        , m_structureChain(0)
+        , m_offset(notFound)
+    {
+    }
+    
+    PutByIdStatus(
+        State state,
+        Structure* oldStructure,
+        Structure* newStructure,
+        StructureChain* structureChain,
+        size_t offset)
+        : m_state(state)
+        , m_oldStructure(oldStructure)
+        , m_newStructure(newStructure)
+        , m_structureChain(structureChain)
+        , m_offset(offset)
+    {
+        ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == !m_oldStructure);
+        ASSERT((m_state != SimpleTransition) == !m_newStructure);
+        ASSERT((m_state != SimpleTransition) == !m_structureChain);
+        ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == (m_offset == notFound));
+    }
+    
+    static PutByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
+    
+    State state() const { return m_state; }
+    
+    bool isSet() const { return m_state != NoInformation; }
+    bool operator!() const { return m_state == NoInformation; }
+    bool isSimpleReplace() const { return m_state == SimpleReplace; }
+    bool isSimpleTransition() const { return m_state == SimpleTransition; }
+    bool takesSlowPath() const { return m_state == TakesSlowPath; }
+    
+    Structure* oldStructure() const { return m_oldStructure; }
+    Structure* newStructure() const { return m_newStructure; }
+    StructureChain* structureChain() const { return m_structureChain; }
+    size_t offset() const { return m_offset; }
+    
+private:
+    State m_state;
+    Structure* m_oldStructure;
+    Structure* m_newStructure;
+    StructureChain* m_structureChain;
+    size_t m_offset;
+};
+
+} // namespace JSC
+
+#endif // PutByIdStatus_h
+
similarity index 94%
rename from Source/JavaScriptCore/dfg/DFGStructureSet.h
rename to Source/JavaScriptCore/bytecode/StructureSet.h
index 181c329..344183b 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#ifndef DFGStructureSet_h
-#define DFGStructureSet_h
-
-#include <wtf/Platform.h>
-
-#if ENABLE(DFG_JIT)
+#ifndef StructureSet_h
+#define StructureSet_h
 
 #include "PredictedType.h"
 #include <stdio.h>
@@ -39,8 +35,8 @@ namespace JSC {
 class Structure;
 
 namespace DFG {
-
 class StructureAbstractValue;
+}
 
 class StructureSet {
 public:
@@ -140,7 +136,6 @@ public:
         return true;
     }
     
-#ifndef NDEBUG
     void dump(FILE* out)
     {
         fprintf(out, "[");
@@ -151,16 +146,13 @@ public:
         }
         fprintf(out, "]");
     }
-#endif
     
 private:
-    friend class StructureAbstractValue;
+    friend class DFG::StructureAbstractValue;
     
     Vector<Structure*, 2> m_structures;
 };
 
-} } // namespace JSC::DFG
-
-#endif // ENABLE(DFG_JIT)
+} // namespace JSC
 
-#endif // DFGStructureSet_h
+#endif // StructureSet_h
index ee43b6c..15bc0d4 100644 (file)
@@ -30,9 +30,9 @@
 
 #if ENABLE(DFG_JIT)
 
-#include "DFGStructureSet.h"
 #include "JSCell.h"
 #include "PredictedType.h"
+#include "StructureSet.h"
 
 namespace JSC { namespace DFG {
 
index 51a8a0c..5452b4b 100644 (file)
 
 #if ENABLE(DFG_JIT)
 
+#include "CallLinkStatus.h"
+#include "CodeBlock.h"
 #include "DFGByteCodeCache.h"
 #include "DFGCapabilities.h"
-#include "CodeBlock.h"
+#include "GetByIdStatus.h"
+#include "MethodCallLinkStatus.h"
+#include "PutByIdStatus.h"
 #include <wtf/HashMap.h>
 #include <wtf/MathExtras.h>
 
@@ -703,22 +707,6 @@ private:
         return nodeIndex;
     }
     
-    bool structureChainIsStillValid(bool direct, Structure* previousStructure, StructureChain* chain)
-    {
-        if (direct)
-            return true;
-        
-        if (!previousStructure->storedPrototype().isNull() && previousStructure->storedPrototype().asCell()->structure() != chain->head()->get())
-            return false;
-        
-        for (WriteBarrier<Structure>* it = chain->head(); *it; ++it) {
-            if (!(*it)->storedPrototype().isNull() && (*it)->storedPrototype().asCell()->structure() != it[1].get())
-                return false;
-        }
-        
-        return true;
-    }
-    
     bool willNeedFlush(StructureStubInfo& stubInfo)
     {
         PolymorphicAccessStructureList* list;
@@ -742,6 +730,22 @@ private:
         return false;
     }
     
+    bool structureChainIsStillValid(bool direct, Structure* previousStructure, StructureChain* chain)
+    {
+        if (direct)
+            return true;
+        
+        if (!previousStructure->storedPrototype().isNull() && previousStructure->storedPrototype().asCell()->structure() != chain->head()->get())
+            return false;
+        
+        for (WriteBarrier<Structure>* it = chain->head(); *it; ++it) {
+            if (!(*it)->storedPrototype().isNull() && (*it)->storedPrototype().asCell()->structure() != it[1].get())
+                return false;
+        }
+        
+        return true;
+    }
+    
     void buildOperandMapsIfNecessary();
     
     JSGlobalData* m_globalData;
@@ -918,6 +922,7 @@ private:
     m_currentIndex += OPCODE_LENGTH(name); \
     return shouldContinueParsing
 
+
 void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentInstruction, NodeType op, CodeSpecializationKind kind)
 {
     ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
@@ -928,11 +933,13 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn
 #if DFG_ENABLE(DEBUG_VERBOSE)
     printf("Slow case count for call at @%zu bc#%u: %u/%u; exit profile: %d.\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_profiledBlock->executionEntryCount(), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache));
 #endif
-            
+    
+    CallLinkStatus callLinkStatus = CallLinkStatus::computeFor(
+        m_inlineStackTop->m_profiledBlock, m_currentIndex);
+    
     if (m_graph.isFunctionConstant(m_codeBlock, callTarget))
         callType = ConstantFunction;
-    else if (!!m_inlineStackTop->m_profiledBlock->getCallLinkInfo(m_currentIndex).lastSeenCallee
-             && !m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex)
+    else if (callLinkStatus.isSet() && !callLinkStatus.couldTakeSlowPath()
              && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache))
         callType = LinkedFunction;
     else
@@ -963,7 +970,7 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn
             certainAboutExpectedFunction = true;
         } else {
             ASSERT(callType == LinkedFunction);
-            expectedFunction = m_inlineStackTop->m_profiledBlock->getCallLinkInfo(m_currentIndex).lastSeenCallee.get();
+            expectedFunction = callLinkStatus.callTarget();
             intrinsic = expectedFunction->executable()->intrinsicFor(kind);
             certainAboutExpectedFunction = false;
         }
@@ -1726,23 +1733,26 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 
             // Check if the method_check was monomorphic. If so, emit a CheckXYZMethod
             // node, which is a lot more efficient.
-            StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex);
-            MethodCallLinkInfo& methodCall = m_inlineStackTop->m_profiledBlock->getMethodCallLinkInfo(m_currentIndex);
+            GetByIdStatus getByIdStatus = GetByIdStatus::computeFor(
+                m_inlineStackTop->m_profiledBlock,
+                m_currentIndex,
+                m_codeBlock->identifier(identifier));
+            MethodCallLinkStatus methodCallStatus = MethodCallLinkStatus::computeFor(
+                m_inlineStackTop->m_profiledBlock, m_currentIndex);
             
-            if (methodCall.seen
-                && !!methodCall.cachedStructure
-                && !stubInfo.seen
+            if (methodCallStatus.isSet()
+                && !getByIdStatus.isSet()
                 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) {
                 // It's monomorphic as far as we can tell, since the method_check was linked
                 // but the slow path (i.e. the normal get_by_id) never fired.
 
-                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCall.cachedStructure.get())), base);
-                if (methodCall.cachedPrototype.get() != m_inlineStackTop->m_profiledBlock->globalObject()->methodCallDummy())
-                    addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCall.cachedPrototypeStructure.get())), cellConstant(methodCall.cachedPrototype.get()));
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.structure())), base);
+                if (methodCallStatus.needsPrototypeCheck())
+                    addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.prototypeStructure())), cellConstant(methodCallStatus.prototype()));
                 
-                set(getInstruction[1].u.operand, cellConstant(methodCall.cachedFunction.get()));
+                set(getInstruction[1].u.operand, cellConstant(methodCallStatus.function()));
             } else
-                set(getInstruction[1].u.operand, addToGraph(willNeedFlush(stubInfo) ? GetByIdFlush : GetById, OpInfo(identifier), OpInfo(prediction), base));
+                set(getInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifier), OpInfo(prediction), base));
             
             m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id);
             continue;
@@ -1772,178 +1782,109 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
             
             Identifier identifier = m_codeBlock->identifier(identifierNumber);
-            StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex);
+            GetByIdStatus getByIdStatus = GetByIdStatus::computeFor(
+                m_inlineStackTop->m_profiledBlock, m_currentIndex, identifier);
             
 #if DFG_ENABLE(DEBUG_VERBOSE)
             printf("Slow case count for GetById @%zu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache));
 #endif
             
-            size_t offset = notFound;
-            StructureSet structureSet;
-            if (stubInfo.seen
-                && !m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)
+            if (getByIdStatus.isSimpleDirect()
                 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) {
-                switch (stubInfo.accessType) {
-                case access_get_by_id_self: {
-                    Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
-                    offset = structure->get(*m_globalData, identifier);
-                    
-                    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();
-                        if (structureSet.contains(structure))
-                            continue;
-                        
-                        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 (offset != notFound) {
-                ASSERT(structureSet.size());
+                ASSERT(getByIdStatus.structureSet().size());
                 
                 // The implementation of GetByOffset does not know to terminate speculative
                 // execution if it doesn't have a prediction, so we do it manually.
                 if (prediction == PredictNone)
                     addToGraph(ForceOSRExit);
                 
-                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), base);
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.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.offset = getByIdStatus.offset();
                 storageAccessData.identifierNumber = identifierNumber;
                 m_graph.m_storageAccessData.append(storageAccessData);
             } else
-                set(currentInstruction[1].u.operand, addToGraph(willNeedFlush(stubInfo) ? GetByIdFlush : GetById, OpInfo(identifierNumber), OpInfo(prediction), base));
+                set(currentInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifierNumber), OpInfo(prediction), base));
 
             NEXT_OPCODE(op_get_by_id);
         }
-
         case op_put_by_id: {
             NodeIndex value = get(currentInstruction[3].u.operand);
             NodeIndex base = get(currentInstruction[1].u.operand);
             unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
             bool direct = currentInstruction[8].u.operand;
 
-            StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex);
-            if (!stubInfo.seen)
+            PutByIdStatus putByIdStatus = PutByIdStatus::computeFor(
+                m_inlineStackTop->m_profiledBlock,
+                m_currentIndex,
+                m_codeBlock->identifier(identifierNumber));
+            if (!putByIdStatus.isSet())
                 addToGraph(ForceOSRExit);
             
-            bool alreadyGenerated = false;
+            bool hasExitSite = m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache);
             
 #if DFG_ENABLE(DEBUG_VERBOSE)
             printf("Slow case count for PutById @%zu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache));
 #endif            
 
-            if (stubInfo.seen
-                && !m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)
-                && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) {
-                switch (stubInfo.accessType) {
-                case access_put_by_id_replace: {
-                    Structure* structure = stubInfo.u.putByIdReplace.baseObjectStructure.get();
-                    Identifier identifier = m_codeBlock->identifier(identifierNumber);
-                    size_t offset = structure->get(*m_globalData, identifier);
-                    
-                    if (offset != notFound) {
-                        addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), base);
-                        addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value);
-                        
-                        StorageAccessData storageAccessData;
-                        storageAccessData.offset = offset;
-                        storageAccessData.identifierNumber = identifierNumber;
-                        m_graph.m_storageAccessData.append(storageAccessData);
-                        
-                        alreadyGenerated = true;
-                    }
-                    break;
-                }
-                    
-                case access_put_by_id_transition_normal:
-                case access_put_by_id_transition_direct: {
-                    Structure* previousStructure = stubInfo.u.putByIdTransition.previousStructure.get();
-                    Structure* newStructure = stubInfo.u.putByIdTransition.structure.get();
-                    
-                    if (previousStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
-                        break;
-                    
-                    StructureChain* structureChain = stubInfo.u.putByIdTransition.chain.get();
-                    
-                    Identifier identifier = m_codeBlock->identifier(identifierNumber);
-                    size_t offset = newStructure->get(*m_globalData, identifier);
+            if (!hasExitSite && putByIdStatus.isSimpleReplace()) {
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base);
+                addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value);
+                
+                StorageAccessData storageAccessData;
+                storageAccessData.offset = putByIdStatus.offset();
+                storageAccessData.identifierNumber = identifierNumber;
+                m_graph.m_storageAccessData.append(storageAccessData);
+            } else if (!hasExitSite
+                       && putByIdStatus.isSimpleTransition()
+                       && putByIdStatus.oldStructure()->propertyStorageCapacity() == putByIdStatus.newStructure()->propertyStorageCapacity()
+                       && structureChainIsStillValid(
+                           direct,
+                           putByIdStatus.oldStructure(),
+                           putByIdStatus.structureChain())) {
+
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base);
+                if (!direct) {
+                    if (!putByIdStatus.oldStructure()->storedPrototype().isNull())
+                        addToGraph(
+                            CheckStructure,
+                            OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure()->storedPrototype().asCell()->structure())),
+                            cellConstant(putByIdStatus.oldStructure()->storedPrototype().asCell()));
                     
-                    if (offset != notFound && structureChainIsStillValid(direct, previousStructure, structureChain)) {
-                        addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(previousStructure)), base);
-                        if (!direct) {
-                            if (!previousStructure->storedPrototype().isNull())
-                                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(previousStructure->storedPrototype().asCell()->structure())), cellConstant(previousStructure->storedPrototype().asCell()));
-                            
-                            for (WriteBarrier<Structure>* it = structureChain->head(); *it; ++it) {
-                                JSValue prototype = (*it)->storedPrototype();
-                                if (prototype.isNull())
-                                    continue;
-                                ASSERT(prototype.isCell());
-                                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())), cellConstant(prototype.asCell()));
-                            }
-                        }
-                        addToGraph(PutStructure, OpInfo(m_graph.addStructureTransitionData(StructureTransitionData(previousStructure, newStructure))), base);
-                        
-                        addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value);
-                        
-                        StorageAccessData storageAccessData;
-                        storageAccessData.offset = offset;
-                        storageAccessData.identifierNumber = identifierNumber;
-                        m_graph.m_storageAccessData.append(storageAccessData);
-                        
-                        alreadyGenerated = true;
+                    for (WriteBarrier<Structure>* it = putByIdStatus.structureChain()->head(); *it; ++it) {
+                        JSValue prototype = (*it)->storedPrototype();
+                        if (prototype.isNull())
+                            continue;
+                        ASSERT(prototype.isCell());
+                        addToGraph(
+                            CheckStructure,
+                            OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())),
+                            cellConstant(prototype.asCell()));
                     }
-                    break;
                 }
-                    
-                default:
-                    break;
-                }
-            }
-            
-            if (!alreadyGenerated) {
+                addToGraph(
+                    PutStructure,
+                    OpInfo(
+                        m_graph.addStructureTransitionData(
+                            StructureTransitionData(
+                                putByIdStatus.oldStructure(),
+                                putByIdStatus.newStructure()))),
+                    base);
+                
+                addToGraph(
+                    PutByOffset,
+                    OpInfo(m_graph.m_storageAccessData.size()),
+                    base,
+                    addToGraph(GetPropertyStorage, base),
+                    value);
+                
+                StorageAccessData storageAccessData;
+                storageAccessData.offset = putByIdStatus.offset();
+                storageAccessData.identifierNumber = identifierNumber;
+                m_graph.m_storageAccessData.append(storageAccessData);
+            } else {
                 if (direct)
                     addToGraph(PutByIdDirect, OpInfo(identifierNumber), base, value);
                 else