Commit a0caeaa4 authored by oliver@apple.com's avatar oliver@apple.com

fourthTier: DFG Nodes should be able to abstractly tell you what they read and what they write

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

Source/JavaScriptCore:

Reviewed by Sam Weinig.

Add the notion of AbstractHeap to the DFG. This is analogous to the AbstractHeap in
the FTL, except that the FTL's AbstractHeaps are used during LLVM lowering and are
engineered to obey LLVM TBAA logic. The FTL's AbstractHeaps are also engineered to
be inexpensive to use (they just give you a TBAA node) but expensive to create (you
create them all up front). FTL AbstractHeaps also don't actually give you the
ability to reason about aliasing; they are *just* a mechanism for lowering to TBAA.
The DFG's AbstractHeaps are engineered to be both cheap to create and cheap to use.
They also give you aliasing machinery. The DFG AbstractHeaps are represented
internally by a int64_t. Many comparisons between them are just integer comaprisons.
AbstractHeaps form a three-level hierarchy (World is the supertype of everything,
Kind with a TOP payload is a direct subtype of World, and Kind with a non-TOP
payload is the direct subtype of its corresponding TOP Kind).

Add the notion of a ClobberSet. This is the set of AbstractHeaps that you had
clobbered. It represents the set that results from unifying a bunch of
AbstractHeaps, and is intended to quickly answer overlap questions: does the given
AbstractHeap overlap any AbstractHeap in the ClobberSet? To this end, if you add an
AbstractHeap to a set, it "directly" adds the heap itself, and "super" adds all of
its ancestors. An AbstractHeap is said to overlap a set if any direct or super
member is equal to it, or if any of its ancestors are equal to a direct member.

Example #1:

    - I add Variables(5). I.e. Variables is the Kind and 5 is the payload. This
      is a subtype of Variables, which is a subtype of World.
    - You query Variables. I.e. Variables with a TOP payload, which is the
      supertype of Variables(X) for any X, and a subtype of World.

    The set will have Variables(5) as a direct member, and Variables and World as
    super members. The Variables query will immediately return true, because
    Variables is indeed a super member.

Example #2:

    - I add Variables(5)
    - You query NamedProperties

    NamedProperties is not a member at all (neither direct or super). We next
    query World. World is a member, but it's a super member, so we return false.

Example #3:

    - I add Variables
    - You query Variables(5)

    The set will have Variables as a direct member, and World as a super member.
    The Variables(5) query will not find Variables(5) in the set, but then it
    will query Variables. Variables is a direct member, so we return true.

Example #4:

    - I add Variables
    - You query NamedProperties(5)

    Neither NamedProperties nor NamedProperties(5) are members. We next query
    World. World is a member, but it's a super member, so we return false.

Overlap queries require that either the heap being queried is in the set (either
direct or super), or that one of its ancestors is a direct member. Another way to
think about how this works is that two heaps A and B are said to overlap if
A.isSubtypeOf(B) or B.isSubtypeOf(A). This is sound since heaps form a
single-inheritance heirarchy. Consider that we wanted to implement a set that holds
heaps and answers the question, "is any member in the set an ancestor (i.e.
supertype) of some other heap". We would have the set contain the heaps themselves,
and we would satisfy the query "A.isSubtypeOfAny(set)" by walking the ancestor
chain of A, and repeatedly querying its membership in the set. This is what the
"direct" members of our set do. Now consider the other part, where we want to ask if
any member of the set is a descendent of a heap, or "A.isSupertypeOfAny(set)". We
would implement this by implementing set.add(B) as adding not just B but also all of
B's ancestors; then we would answer A.isSupertypeOfAny(set) by just checking if A is
in the set. With two such sets - one that answers isSubtypeOfAny() and another that
answers isSupertypeOfAny() - we could answer the "do any of my heaps overlap your
heap" question. ClobberSet does this, but combines the two sets into a single
HashMap. The HashMap's value, "direct", means that the key is a member of both the
supertype set and the subtype set; if it's false then it's only a member of one of
them.

Finally, this adds a functorized clobberize() method that adds the read and write
clobbers of a DFG::Node to read and write functors. Common functors for adding to
ClobberSets, querying overlap, and doing nothing are provided. Convenient wrappers
are also provided. This allows you to say things like:

    ClobberSet set;
    addWrites(graph, node1, set);
    if (readsOverlap(graph, node2, set))
        // We know that node1 may write to something that node2 may read from.

Currently this facility is only used to improve graph dumping, but it will be
instrumental in both LICM and GVN. In the future, I want to completely kill the
NodeClobbersWorld and NodeMightClobber flags, and eradicate CSEPhase's hackish way
of accomplishing almost exactly what AbstractHeap gives you.

* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractHeap.cpp: Added.
(DFG):
(JSC::DFG::AbstractHeap::Payload::dump):
(JSC::DFG::AbstractHeap::dump):
(WTF):
(WTF::printInternal):
* dfg/DFGAbstractHeap.h: Added.
(DFG):
(AbstractHeap):
(Payload):
(JSC::DFG::AbstractHeap::Payload::Payload):
(JSC::DFG::AbstractHeap::Payload::top):
(JSC::DFG::AbstractHeap::Payload::isTop):
(JSC::DFG::AbstractHeap::Payload::value):
(JSC::DFG::AbstractHeap::Payload::valueImpl):
(JSC::DFG::AbstractHeap::Payload::operator==):
(JSC::DFG::AbstractHeap::Payload::operator!=):
(JSC::DFG::AbstractHeap::Payload::operator<):
(JSC::DFG::AbstractHeap::Payload::isDisjoint):
(JSC::DFG::AbstractHeap::Payload::overlaps):
(JSC::DFG::AbstractHeap::AbstractHeap):
(JSC::DFG::AbstractHeap::operator!):
(JSC::DFG::AbstractHeap::kind):
(JSC::DFG::AbstractHeap::payload):
(JSC::DFG::AbstractHeap::isDisjoint):
(JSC::DFG::AbstractHeap::overlaps):
(JSC::DFG::AbstractHeap::supertype):
(JSC::DFG::AbstractHeap::hash):
(JSC::DFG::AbstractHeap::operator==):
(JSC::DFG::AbstractHeap::operator!=):
(JSC::DFG::AbstractHeap::operator<):
(JSC::DFG::AbstractHeap::isHashTableDeletedValue):
(JSC::DFG::AbstractHeap::payloadImpl):
(JSC::DFG::AbstractHeap::encode):
(JSC::DFG::AbstractHeapHash::hash):
(JSC::DFG::AbstractHeapHash::equal):
(AbstractHeapHash):
(WTF):
* dfg/DFGClobberSet.cpp: Added.
(DFG):
(JSC::DFG::ClobberSet::ClobberSet):
(JSC::DFG::ClobberSet::~ClobberSet):
(JSC::DFG::ClobberSet::add):
(JSC::DFG::ClobberSet::addAll):
(JSC::DFG::ClobberSet::contains):
(JSC::DFG::ClobberSet::overlaps):
(JSC::DFG::ClobberSet::clear):
(JSC::DFG::ClobberSet::direct):
(JSC::DFG::ClobberSet::super):
(JSC::DFG::ClobberSet::dump):
(JSC::DFG::ClobberSet::setOf):
(JSC::DFG::addReads):
(JSC::DFG::addWrites):
(JSC::DFG::addReadsAndWrites):
(JSC::DFG::readsOverlap):
(JSC::DFG::writesOverlap):
* dfg/DFGClobberSet.h: Added.
(DFG):
(ClobberSet):
(JSC::DFG::ClobberSet::isEmpty):
(ClobberSetAdd):
(JSC::DFG::ClobberSetAdd::ClobberSetAdd):
(JSC::DFG::ClobberSetAdd::operator()):
(ClobberSetOverlaps):
(JSC::DFG::ClobberSetOverlaps::ClobberSetOverlaps):
(JSC::DFG::ClobberSetOverlaps::operator()):
(JSC::DFG::ClobberSetOverlaps::result):
* dfg/DFGClobberize.cpp: Added.
(DFG):
(JSC::DFG::didWrites):
* dfg/DFGClobberize.h: Added.
(DFG):
(JSC::DFG::clobberize):
(NoOpClobberize):
(JSC::DFG::NoOpClobberize::NoOpClobberize):
(JSC::DFG::NoOpClobberize::operator()):
(CheckClobberize):
(JSC::DFG::CheckClobberize::CheckClobberize):
(JSC::DFG::CheckClobberize::operator()):
(JSC::DFG::CheckClobberize::result):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):

Source/WTF:

Reviewed by Sam Weinig.

Fix compile goof in sortedListDump().

* wtf/ListDump.h:
(WTF::sortedListDump):

Conflicts:
	Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153294 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 78a7c627
2013-07-21 Filip Pizlo <fpizlo@apple.com>
fourthTier: DFG Nodes should be able to abstractly tell you what they read and what they write
https://bugs.webkit.org/show_bug.cgi?id=118910
Reviewed by Sam Weinig.
Add the notion of AbstractHeap to the DFG. This is analogous to the AbstractHeap in
the FTL, except that the FTL's AbstractHeaps are used during LLVM lowering and are
engineered to obey LLVM TBAA logic. The FTL's AbstractHeaps are also engineered to
be inexpensive to use (they just give you a TBAA node) but expensive to create (you
create them all up front). FTL AbstractHeaps also don't actually give you the
ability to reason about aliasing; they are *just* a mechanism for lowering to TBAA.
The DFG's AbstractHeaps are engineered to be both cheap to create and cheap to use.
They also give you aliasing machinery. The DFG AbstractHeaps are represented
internally by a int64_t. Many comparisons between them are just integer comaprisons.
AbstractHeaps form a three-level hierarchy (World is the supertype of everything,
Kind with a TOP payload is a direct subtype of World, and Kind with a non-TOP
payload is the direct subtype of its corresponding TOP Kind).
Add the notion of a ClobberSet. This is the set of AbstractHeaps that you had
clobbered. It represents the set that results from unifying a bunch of
AbstractHeaps, and is intended to quickly answer overlap questions: does the given
AbstractHeap overlap any AbstractHeap in the ClobberSet? To this end, if you add an
AbstractHeap to a set, it "directly" adds the heap itself, and "super" adds all of
its ancestors. An AbstractHeap is said to overlap a set if any direct or super
member is equal to it, or if any of its ancestors are equal to a direct member.
Example #1:
- I add Variables(5). I.e. Variables is the Kind and 5 is the payload. This
is a subtype of Variables, which is a subtype of World.
- You query Variables. I.e. Variables with a TOP payload, which is the
supertype of Variables(X) for any X, and a subtype of World.
The set will have Variables(5) as a direct member, and Variables and World as
super members. The Variables query will immediately return true, because
Variables is indeed a super member.
Example #2:
- I add Variables(5)
- You query NamedProperties
NamedProperties is not a member at all (neither direct or super). We next
query World. World is a member, but it's a super member, so we return false.
Example #3:
- I add Variables
- You query Variables(5)
The set will have Variables as a direct member, and World as a super member.
The Variables(5) query will not find Variables(5) in the set, but then it
will query Variables. Variables is a direct member, so we return true.
Example #4:
- I add Variables
- You query NamedProperties(5)
Neither NamedProperties nor NamedProperties(5) are members. We next query
World. World is a member, but it's a super member, so we return false.
Overlap queries require that either the heap being queried is in the set (either
direct or super), or that one of its ancestors is a direct member. Another way to
think about how this works is that two heaps A and B are said to overlap if
A.isSubtypeOf(B) or B.isSubtypeOf(A). This is sound since heaps form a
single-inheritance heirarchy. Consider that we wanted to implement a set that holds
heaps and answers the question, "is any member in the set an ancestor (i.e.
supertype) of some other heap". We would have the set contain the heaps themselves,
and we would satisfy the query "A.isSubtypeOfAny(set)" by walking the ancestor
chain of A, and repeatedly querying its membership in the set. This is what the
"direct" members of our set do. Now consider the other part, where we want to ask if
any member of the set is a descendent of a heap, or "A.isSupertypeOfAny(set)". We
would implement this by implementing set.add(B) as adding not just B but also all of
B's ancestors; then we would answer A.isSupertypeOfAny(set) by just checking if A is
in the set. With two such sets - one that answers isSubtypeOfAny() and another that
answers isSupertypeOfAny() - we could answer the "do any of my heaps overlap your
heap" question. ClobberSet does this, but combines the two sets into a single
HashMap. The HashMap's value, "direct", means that the key is a member of both the
supertype set and the subtype set; if it's false then it's only a member of one of
them.
Finally, this adds a functorized clobberize() method that adds the read and write
clobbers of a DFG::Node to read and write functors. Common functors for adding to
ClobberSets, querying overlap, and doing nothing are provided. Convenient wrappers
are also provided. This allows you to say things like:
ClobberSet set;
addWrites(graph, node1, set);
if (readsOverlap(graph, node2, set))
// We know that node1 may write to something that node2 may read from.
Currently this facility is only used to improve graph dumping, but it will be
instrumental in both LICM and GVN. In the future, I want to completely kill the
NodeClobbersWorld and NodeMightClobber flags, and eradicate CSEPhase's hackish way
of accomplishing almost exactly what AbstractHeap gives you.
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractHeap.cpp: Added.
(DFG):
(JSC::DFG::AbstractHeap::Payload::dump):
(JSC::DFG::AbstractHeap::dump):
(WTF):
(WTF::printInternal):
* dfg/DFGAbstractHeap.h: Added.
(DFG):
(AbstractHeap):
(Payload):
(JSC::DFG::AbstractHeap::Payload::Payload):
(JSC::DFG::AbstractHeap::Payload::top):
(JSC::DFG::AbstractHeap::Payload::isTop):
(JSC::DFG::AbstractHeap::Payload::value):
(JSC::DFG::AbstractHeap::Payload::valueImpl):
(JSC::DFG::AbstractHeap::Payload::operator==):
(JSC::DFG::AbstractHeap::Payload::operator!=):
(JSC::DFG::AbstractHeap::Payload::operator<):
(JSC::DFG::AbstractHeap::Payload::isDisjoint):
(JSC::DFG::AbstractHeap::Payload::overlaps):
(JSC::DFG::AbstractHeap::AbstractHeap):
(JSC::DFG::AbstractHeap::operator!):
(JSC::DFG::AbstractHeap::kind):
(JSC::DFG::AbstractHeap::payload):
(JSC::DFG::AbstractHeap::isDisjoint):
(JSC::DFG::AbstractHeap::overlaps):
(JSC::DFG::AbstractHeap::supertype):
(JSC::DFG::AbstractHeap::hash):
(JSC::DFG::AbstractHeap::operator==):
(JSC::DFG::AbstractHeap::operator!=):
(JSC::DFG::AbstractHeap::operator<):
(JSC::DFG::AbstractHeap::isHashTableDeletedValue):
(JSC::DFG::AbstractHeap::payloadImpl):
(JSC::DFG::AbstractHeap::encode):
(JSC::DFG::AbstractHeapHash::hash):
(JSC::DFG::AbstractHeapHash::equal):
(AbstractHeapHash):
(WTF):
* dfg/DFGClobberSet.cpp: Added.
(DFG):
(JSC::DFG::ClobberSet::ClobberSet):
(JSC::DFG::ClobberSet::~ClobberSet):
(JSC::DFG::ClobberSet::add):
(JSC::DFG::ClobberSet::addAll):
(JSC::DFG::ClobberSet::contains):
(JSC::DFG::ClobberSet::overlaps):
(JSC::DFG::ClobberSet::clear):
(JSC::DFG::ClobberSet::direct):
(JSC::DFG::ClobberSet::super):
(JSC::DFG::ClobberSet::dump):
(JSC::DFG::ClobberSet::setOf):
(JSC::DFG::addReads):
(JSC::DFG::addWrites):
(JSC::DFG::addReadsAndWrites):
(JSC::DFG::readsOverlap):
(JSC::DFG::writesOverlap):
* dfg/DFGClobberSet.h: Added.
(DFG):
(ClobberSet):
(JSC::DFG::ClobberSet::isEmpty):
(ClobberSetAdd):
(JSC::DFG::ClobberSetAdd::ClobberSetAdd):
(JSC::DFG::ClobberSetAdd::operator()):
(ClobberSetOverlaps):
(JSC::DFG::ClobberSetOverlaps::ClobberSetOverlaps):
(JSC::DFG::ClobberSetOverlaps::operator()):
(JSC::DFG::ClobberSetOverlaps::result):
* dfg/DFGClobberize.cpp: Added.
(DFG):
(JSC::DFG::didWrites):
* dfg/DFGClobberize.h: Added.
(DFG):
(JSC::DFG::clobberize):
(NoOpClobberize):
(JSC::DFG::NoOpClobberize::NoOpClobberize):
(JSC::DFG::NoOpClobberize::operator()):
(CheckClobberize):
(JSC::DFG::CheckClobberize::CheckClobberize):
(JSC::DFG::CheckClobberize::operator()):
(JSC::DFG::CheckClobberize::result):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
2013-07-21 Filip Pizlo <fpizlo@apple.com>
fourthTier: It should be easy to figure out which blocks nodes belong to
......
......@@ -779,6 +779,13 @@
A76C51761182748D00715B05 /* JSInterfaceJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = A76C51741182748D00715B05 /* JSInterfaceJIT.h */; settings = {ATTRIBUTES = (Private, ); }; };
A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A79E781E15EECBA80047C855 /* UnlinkedCodeBlock.cpp */; };
A76F54A313B28AAB00EF2BCE /* JITWriteBarrier.h in Headers */ = {isa = PBXBuildFile; fileRef = A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */; settings = {ATTRIBUTES = (Private, ); }; };
A77A423D17A0BBFD00A8DB81 /* DFGAbstractHeap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A77A423617A0BBFD00A8DB81 /* DFGAbstractHeap.cpp */; };
A77A423E17A0BBFD00A8DB81 /* DFGAbstractHeap.h in Headers */ = {isa = PBXBuildFile; fileRef = A77A423717A0BBFD00A8DB81 /* DFGAbstractHeap.h */; settings = {ATTRIBUTES = (Private, ); }; };
A77A423F17A0BBFD00A8DB81 /* DFGClobberize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A77A423817A0BBFD00A8DB81 /* DFGClobberize.cpp */; };
A77A424017A0BBFD00A8DB81 /* DFGClobberize.h in Headers */ = {isa = PBXBuildFile; fileRef = A77A423917A0BBFD00A8DB81 /* DFGClobberize.h */; settings = {ATTRIBUTES = (Private, ); }; };
A77A424117A0BBFD00A8DB81 /* DFGClobberSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A77A423A17A0BBFD00A8DB81 /* DFGClobberSet.cpp */; };
A77A424217A0BBFD00A8DB81 /* DFGClobberSet.h in Headers */ = {isa = PBXBuildFile; fileRef = A77A423B17A0BBFD00A8DB81 /* DFGClobberSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
A77A424317A0BBFD00A8DB81 /* DFGSafeToExecute.h in Headers */ = {isa = PBXBuildFile; fileRef = A77A423C17A0BBFD00A8DB81 /* DFGSafeToExecute.h */; settings = {ATTRIBUTES = (Private, ); }; };
A77F1821164088B200640A47 /* CodeCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A77F181F164088B200640A47 /* CodeCache.cpp */; };
A77F1822164088B200640A47 /* CodeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = A77F1820164088B200640A47 /* CodeCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
A77F1825164192C700640A47 /* ParserModes.h in Headers */ = {isa = PBXBuildFile; fileRef = A77F18241641925400640A47 /* ParserModes.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -1846,6 +1853,13 @@
A767FF9F14F4502900789059 /* JSCTypedArrayStubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCTypedArrayStubs.h; sourceTree = "<group>"; };
A76C51741182748D00715B05 /* JSInterfaceJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInterfaceJIT.h; sourceTree = "<group>"; };
A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITWriteBarrier.h; sourceTree = "<group>"; };
A77A423617A0BBFD00A8DB81 /* DFGAbstractHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGAbstractHeap.cpp; path = dfg/DFGAbstractHeap.cpp; sourceTree = "<group>"; };
A77A423717A0BBFD00A8DB81 /* DFGAbstractHeap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAbstractHeap.h; path = dfg/DFGAbstractHeap.h; sourceTree = "<group>"; };
A77A423817A0BBFD00A8DB81 /* DFGClobberize.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGClobberize.cpp; path = dfg/DFGClobberize.cpp; sourceTree = "<group>"; };
A77A423917A0BBFD00A8DB81 /* DFGClobberize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGClobberize.h; path = dfg/DFGClobberize.h; sourceTree = "<group>"; };
A77A423A17A0BBFD00A8DB81 /* DFGClobberSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGClobberSet.cpp; path = dfg/DFGClobberSet.cpp; sourceTree = "<group>"; };
A77A423B17A0BBFD00A8DB81 /* DFGClobberSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGClobberSet.h; path = dfg/DFGClobberSet.h; sourceTree = "<group>"; };
A77A423C17A0BBFD00A8DB81 /* DFGSafeToExecute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSafeToExecute.h; path = dfg/DFGSafeToExecute.h; sourceTree = "<group>"; };
A77F181F164088B200640A47 /* CodeCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeCache.cpp; sourceTree = "<group>"; };
A77F1820164088B200640A47 /* CodeCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeCache.h; sourceTree = "<group>"; };
A77F18241641925400640A47 /* ParserModes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParserModes.h; sourceTree = "<group>"; };
......@@ -3048,6 +3062,8 @@
86EC9DB31328DF44002B2AD7 /* dfg */ = {
isa = PBXGroup;
children = (
A77A423617A0BBFD00A8DB81 /* DFGAbstractHeap.cpp */,
A77A423717A0BBFD00A8DB81 /* DFGAbstractHeap.h */,
A704D8FE17A0BAA8006BA554 /* DFGAbstractInterpreter.h */,
A704D8FF17A0BAA8006BA554 /* DFGAbstractInterpreterInlines.h */,
0F55C19317276E4600CEABFD /* DFGAbstractValue.cpp */,
......@@ -3083,6 +3099,10 @@
0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */,
0F3B3A241544C991003ED0FF /* DFGCFGSimplificationPhase.cpp */,
0F3B3A251544C991003ED0FF /* DFGCFGSimplificationPhase.h */,
A77A423817A0BBFD00A8DB81 /* DFGClobberize.cpp */,
A77A423917A0BBFD00A8DB81 /* DFGClobberize.h */,
A77A423A17A0BBFD00A8DB81 /* DFGClobberSet.cpp */,
A77A423B17A0BBFD00A8DB81 /* DFGClobberSet.h */,
0FB4B51A16B62772003F696B /* DFGCommon.cpp */,
0FC0977E1469EBC400CF2442 /* DFGCommon.h */,
0FEA0A2D170D40BF00BB722C /* DFGCommonData.cpp */,
......@@ -3192,6 +3212,7 @@
0F766D4215B2A3BD008F363E /* DFGRegisterSet.h */,
86BB09BE138E381B0056702F /* DFGRepatch.cpp */,
86BB09BF138E381B0056702F /* DFGRepatch.h */,
A77A423C17A0BBFD00A8DB81 /* DFGSafeToExecute.h */,
A741017E179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h */,
86ECA3F9132DF25A002B2AD7 /* DFGScoreBoard.h */,
0F766D4515B3701D008F363E /* DFGScratchRegisterAllocator.h */,
......@@ -3495,6 +3516,7 @@
BC3135640F302FA3003DFD3A /* DebuggerActivation.h in Headers */,
BC18C3FB0E16F5CD00B34460 /* DebuggerCallFrame.h in Headers */,
0F136D4D174AD69E0075B354 /* DeferGC.h in Headers */,
A77A423E17A0BBFD00A8DB81 /* DFGAbstractHeap.h in Headers */,
A704D90317A0BAA8006BA554 /* DFGAbstractInterpreter.h in Headers */,
A704D90417A0BAA8006BA554 /* DFGAbstractInterpreterInlines.h in Headers */,
0F620177143FCD3F0068B77C /* DFGAbstractValue.h in Headers */,
......@@ -3518,6 +3540,8 @@
0F7B294A14C3CD29007C3DB1 /* DFGCCallHelpers.h in Headers */,
0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */,
0F3B3A281544C997003ED0FF /* DFGCFGSimplificationPhase.h in Headers */,
A77A424017A0BBFD00A8DB81 /* DFGClobberize.h in Headers */,
A77A424217A0BBFD00A8DB81 /* DFGClobberSet.h in Headers */,
0F2C556F14738F3100121E4F /* DFGCodeBlocks.h in Headers */,
0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */,
0FEA0A32170D40BF00BB722C /* DFGCommonData.h in Headers */,
......@@ -3581,6 +3605,7 @@
86EC9DD11328DF82002B2AD7 /* DFGRegisterBank.h in Headers */,
0F766D4415B2A3C0008F363E /* DFGRegisterSet.h in Headers */,
86BB09C1138E381B0056702F /* DFGRepatch.h in Headers */,
A77A424317A0BBFD00A8DB81 /* DFGSafeToExecute.h in Headers */,
A741017F179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h in Headers */,
86ECA3FA132DF25A002B2AD7 /* DFGScoreBoard.h in Headers */,
0F766D4615B3701F008F363E /* DFGScratchRegisterAllocator.h in Headers */,
......@@ -4364,6 +4389,7 @@
14280823107EC02C0013E7B2 /* Debugger.cpp in Sources */,
BC3135650F302FA3003DFD3A /* DebuggerActivation.cpp in Sources */,
149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */,
A77A423D17A0BBFD00A8DB81 /* DFGAbstractHeap.cpp in Sources */,
0F55C19417276E4600CEABFD /* DFGAbstractValue.cpp in Sources */,
0F16015D156198C900C2587C /* DFGArgumentsSimplificationPhase.cpp in Sources */,
0F63948415E48118006A597C /* DFGArrayMode.cpp in Sources */,
......@@ -4376,6 +4402,8 @@
0FD82E2114172CE300179C94 /* DFGCapabilities.cpp in Sources */,
0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */,
0F3B3A271544C995003ED0FF /* DFGCFGSimplificationPhase.cpp in Sources */,
A77A423F17A0BBFD00A8DB81 /* DFGClobberize.cpp in Sources */,
A77A424117A0BBFD00A8DB81 /* DFGClobberSet.cpp in Sources */,
0F2C557014738F3500121E4F /* DFGCodeBlocks.cpp in Sources */,
0FF0F19D16B72A08005DF95B /* DFGCommon.cpp in Sources */,
0FEA0A31170D40BF00BB722C /* DFGCommonData.cpp in Sources */,
......
/*
* Copyright (C) 2013 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 "DFGAbstractHeap.h"
#if ENABLE(DFG_JIT)
namespace JSC { namespace DFG {
void AbstractHeap::Payload::dump(PrintStream& out) const
{
if (isTop())
out.print("TOP");
else
out.print(value());
}
void AbstractHeap::dump(PrintStream& out) const
{
out.print(kind());
if (kind() == InvalidAbstractHeap || kind() == World || payload().isTop())
return;
out.print("(", payload(), ")");
}
} } // namespace JSC::DFG
namespace WTF {
using namespace JSC::DFG;
void printInternal(PrintStream& out, AbstractHeapKind kind)
{
switch (kind) {
#define ABSTRACT_HEAP_DUMP(name) \
case name: \
out.print(#name); \
return;
FOR_EACH_ABSTRACT_HEAP_KIND(ABSTRACT_HEAP_DUMP)
#undef ABSTRACT_HEAP_DUMP
}
RELEASE_ASSERT_NOT_REACHED();
}
} // namespace WTF
#endif // ENABLE(DFG_JIT)
/*
* Copyright (C) 2013 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 DFGAbstractHeap_h
#define DFGAbstractHeap_h
#include <wtf/Platform.h>
#if ENABLE(DFG_JIT)
#include "VirtualRegister.h"
#include <wtf/HashMap.h>
#include <wtf/PrintStream.h>
namespace JSC { namespace DFG {
// Implements a three-level type hierarchy:
// - World is the supertype of all of the things.
// - Kind with TOP payload is the direct subtype of World.
// - Kind with non-TOP payload is the direct subtype of its corresponding TOP Kind.
#define FOR_EACH_ABSTRACT_HEAP_KIND(macro) \
macro(InvalidAbstractHeap) \
macro(World) \
macro(Arguments_numArguments) \
macro(Arguments_overrideLength) \
macro(Arguments_registers) \
macro(Arguments_slowArguments) \
macro(Butterfly_publicLength) \
macro(Butterfly_vectorLength) \
macro(JSCell_structure) \
macro(JSFunction_executable) \
macro(JSFunction_scopeChain) \
macro(JSObject_butterfly) \
macro(JSVariableObject_registers) \
macro(NamedProperties) \
macro(IndexedInt32Properties) \
macro(IndexedDoubleProperties) \
macro(IndexedContiguousProperties) \
macro(ArrayStorageProperties) \
macro(Variables) \
macro(TypedArrayStoragePointer) \
macro(TypedArrayProperties) \
macro(TypedArrayLength) \
macro(GCState) \
macro(RegExpState) \
macro(InternalState) \
macro(Absolute) \
/* Use this for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\
macro(MiscFields) \
/* Use this for writes only, just to indicate that hoisting the node is invalid. This works because we don't hoist anything that has any side effects at all. */\
macro(SideState)
enum AbstractHeapKind {
#define ABSTRACT_HEAP_DECLARATION(name) name,
FOR_EACH_ABSTRACT_HEAP_KIND(ABSTRACT_HEAP_DECLARATION)
#undef ABSTRACT_HEAP_DECLARATION
};
class AbstractHeap {
public:
class Payload {
public:
Payload()
: m_isTop(false)
, m_value(0)
{
}
Payload(bool isTop, int64_t value)
: m_isTop(isTop)
, m_value(value)
{
ASSERT(!(isTop && value));
}
Payload(int64_t value)
: m_isTop(false)
, m_value(value)
{
}
Payload(const void* pointer)
: m_isTop(false)
, m_value(bitwise_cast<intptr_t>(pointer))
{
}
Payload(VirtualRegister operand)
: m_isTop(false)
, m_value(static_cast<int>(operand))
{
}
static Payload top() { return Payload(true, 0); }
bool isTop() const { return m_isTop; }
int64_t value() const
{
ASSERT(!isTop());
return valueImpl();
}
int64_t valueImpl() const
{
return m_value;
}
bool operator==(const Payload& other) const
{
return m_isTop == other.m_isTop
&& m_value == other.m_value;
}
bool operator!=(const Payload& other) const
{
return !(*this == other);
}
bool operator<(const Payload& other) const
{
if (isTop())
return !other.isTop();
if (other.isTop())
return false;
return value() < other.value();
}
bool isDisjoint(const Payload& other) const
{
if (isTop())
return false;
if (other.isTop())
return false;
return m_value != other.m_value;
}
bool overlaps(const Payload& other) const
{
return !isDisjoint(other);
}
void dump(PrintStream&) const;
private:
bool m_isTop;
int64_t m_value;
};
AbstractHeap()
{
m_value = encode(InvalidAbstractHeap, Payload());
}
AbstractHeap(AbstractHeapKind kind)
{
ASSERT(kind != InvalidAbstractHeap);
m_value = encode(kind, Payload::top());
}
AbstractHeap(AbstractHeapKind kind, Payload payload)
{
ASSERT(kind != InvalidAbstractHeap && kind != World);
m_value = encode(kind, payload);
}
AbstractHeap(WTF::HashTableDeletedValueType)
{
m_value = encode(InvalidAbstractHeap, Payload::top());
}
bool operator!() const { return kind() == InvalidAbstractHeap && !payloadImpl().isTop(); }
AbstractHeapKind kind() const { return static_cast<AbstractHeapKind>(m_value & ((1 << topShift) - 1)); }
Payload payload() const
{
ASSERT(kind() != World && kind() != InvalidAbstractHeap);
return payloadImpl();
}
bool isDisjoint(const AbstractHeap& other)
{
ASSERT(kind() != InvalidAbstractHeap);
ASSERT(other.kind() != InvalidAbstractHeap);
if (kind() == World)
return false;
if (other.kind() == World)
return false;
if (kind() != other.kind())
return true;
return payload().isDisjoint(other.payload());
}
bool overlaps(const AbstractHeap& other)
{
return !isDisjoint(other);
}
AbstractHeap supertype() const
{
ASSERT(kind() != InvalidAbstractHeap);
if (kind() == World)
return AbstractHeap();
if (payload().isTop())
return World;
return AbstractHeap(kind());
}
unsigned hash() const
{
return WTF::IntHash<int64_t>::hash(m_value);
}
bool operator==(const AbstractHeap& other) const
{
return m_value == other.m_value;
}
bool operator!=(const AbstractHeap& other) const
{
return !(*this == other);
}
bool operator<(const AbstractHeap& other) const
{
if (kind() != other.kind())
return kind() < other.kind();
return payload() < other.payload();
}
bool isHashTableDeletedValue() const
{
return kind() == InvalidAbstractHeap && payloadImpl().isTop();
}
void dump(PrintStream& out) const;
private:
static const unsigned valueShift = 15;
static const unsigned topShift = 14;
Payload payloadImpl() const
{
return Payload((m_value >> topShift) &