Title: [180656] trunk/Source/_javascript_Core
Revision
180656
Author
[email protected]
Date
2015-02-25 20:29:26 -0800 (Wed, 25 Feb 2015)

Log Message

DFG abstract heaps should respect the difference between heap and stack
https://bugs.webkit.org/show_bug.cgi?id=142022

Reviewed by Geoffrey Garen.
        
We will soon (https://bugs.webkit.org/show_bug.cgi?id=141174) be in a world where a "world
clobbering" operation cannot write to our stack, but may be able to read from it. This
means that we need to change the DFG abstract heap hierarchy to have a notion of Heap that
subsumes all that World previously subsumed, and a new notion of Stack that is a subtype
of World and a sibling of Heap.

So, henceforth "clobbering the world" means reading World and writing Heap.
        
This makes a bunch of changes to make this work, including changing the implementation of
disjointness in AbstractHeap to make it support a more general hierarchy. I was expecting
a slow-down, but I measured the heck out of this and found no perf difference.

* dfg/DFGAbstractHeap.cpp:
(JSC::DFG::AbstractHeap::dump):
* dfg/DFGAbstractHeap.h:
(JSC::DFG::AbstractHeap::supertype):
(JSC::DFG::AbstractHeap::isStrictSubtypeOf):
(JSC::DFG::AbstractHeap::isSubtypeOf):
(JSC::DFG::AbstractHeap::overlaps):
(JSC::DFG::AbstractHeap::isDisjoint):
* dfg/DFGClobberize.cpp:
(JSC::DFG::clobbersHeap):
(JSC::DFG::clobbersWorld): Deleted.
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (180655 => 180656)


--- trunk/Source/_javascript_Core/ChangeLog	2015-02-26 04:18:47 UTC (rev 180655)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-02-26 04:29:26 UTC (rev 180656)
@@ -1,3 +1,38 @@
+2015-02-25  Filip Pizlo  <[email protected]>
+
+        DFG abstract heaps should respect the difference between heap and stack
+        https://bugs.webkit.org/show_bug.cgi?id=142022
+
+        Reviewed by Geoffrey Garen.
+        
+        We will soon (https://bugs.webkit.org/show_bug.cgi?id=141174) be in a world where a "world
+        clobbering" operation cannot write to our stack, but may be able to read from it. This
+        means that we need to change the DFG abstract heap hierarchy to have a notion of Heap that
+        subsumes all that World previously subsumed, and a new notion of Stack that is a subtype
+        of World and a sibling of Heap.
+
+        So, henceforth "clobbering the world" means reading World and writing Heap.
+        
+        This makes a bunch of changes to make this work, including changing the implementation of
+        disjointness in AbstractHeap to make it support a more general hierarchy. I was expecting
+        a slow-down, but I measured the heck out of this and found no perf difference.
+
+        * dfg/DFGAbstractHeap.cpp:
+        (JSC::DFG::AbstractHeap::dump):
+        * dfg/DFGAbstractHeap.h:
+        (JSC::DFG::AbstractHeap::supertype):
+        (JSC::DFG::AbstractHeap::isStrictSubtypeOf):
+        (JSC::DFG::AbstractHeap::isSubtypeOf):
+        (JSC::DFG::AbstractHeap::overlaps):
+        (JSC::DFG::AbstractHeap::isDisjoint):
+        * dfg/DFGClobberize.cpp:
+        (JSC::DFG::clobbersHeap):
+        (JSC::DFG::clobbersWorld): Deleted.
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+
 2015-02-25  Ryosuke Niwa  <[email protected]>
 
         REGRESSION(r180595): construct varargs fails in FTL

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractHeap.cpp (180655 => 180656)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractHeap.cpp	2015-02-26 04:18:47 UTC (rev 180655)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractHeap.cpp	2015-02-26 04:29:26 UTC (rev 180656)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -43,7 +43,7 @@
 void AbstractHeap::dump(PrintStream& out) const
 {
     out.print(kind());
-    if (kind() == InvalidAbstractHeap || kind() == World || payload().isTop())
+    if (kind() == InvalidAbstractHeap || kind() == World || kind() == Heap || payload().isTop())
         return;
     out.print("(", payload(), ")");
 }

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractHeap.h (180655 => 180656)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractHeap.h	2015-02-26 04:18:47 UTC (rev 180655)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractHeap.h	2015-02-26 04:29:26 UTC (rev 180656)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,14 +34,19 @@
 
 namespace JSC { namespace DFG {
 
-// Implements a three-level type hierarchy:
+// Implements a four-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.
+// - Stack with a TOP payload is a direct subtype of World
+// - Stack with a non-TOP payload is a direct subtype of Stack with a TOP payload.
+// - Heap is a direct subtype of World.
+// - Any other kind with TOP payload is the direct subtype of Heap.
+// - Any other kind with non-TOP payload is the direct subtype of the same kind with a TOP payload.
 
 #define FOR_EACH_ABSTRACT_HEAP_KIND(macro) \
     macro(InvalidAbstractHeap) \
     macro(World) \
+    macro(Stack) \
+    macro(Heap) \
     macro(Arguments_registers) \
     macro(Butterfly_publicLength) \
     macro(Butterfly_vectorLength) \
@@ -204,32 +209,48 @@
         return payloadImpl();
     }
     
-    bool isDisjoint(const AbstractHeap& other) const
+    AbstractHeap supertype() const
     {
         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());
+        switch (kind()) {
+        case World:
+            return AbstractHeap();
+        case Heap:
+            return World;
+        default:
+            if (payload().isTop()) {
+                if (kind() == Stack)
+                    return World;
+                return Heap;
+            }
+            return AbstractHeap(kind());
+        }
     }
     
+    bool isStrictSubtypeOf(const AbstractHeap& other) const
+    {
+        AbstractHeap current = *this;
+        while (current.kind() != World) {
+            current = current.supertype();
+            if (current == other)
+                return true;
+        }
+        return false;
+    }
+    
+    bool isSubtypeOf(const AbstractHeap& other) const
+    {
+        return *this == other || isStrictSubtypeOf(other);
+    }
+    
     bool overlaps(const AbstractHeap& other) const
     {
-        return !isDisjoint(other);
+        return *this == other || isStrictSubtypeOf(other) || other.isStrictSubtypeOf(*this);
     }
     
-    AbstractHeap supertype() const
+    bool isDisjoint(const AbstractHeap& other) const
     {
-        ASSERT(kind() != InvalidAbstractHeap);
-        if (kind() == World)
-            return AbstractHeap();
-        if (payload().isTop())
-            return World;
-        return AbstractHeap(kind());
+        return !overlaps(other);
     }
     
     unsigned hash() const

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.cpp (180655 => 180656)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.cpp	2015-02-26 04:18:47 UTC (rev 180655)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.cpp	2015-02-26 04:29:26 UTC (rev 180656)
@@ -56,14 +56,20 @@
     return addWrite.result();
 }
 
-bool clobbersWorld(Graph& graph, Node* node)
+bool clobbersHeap(Graph& graph, Node* node)
 {
     bool result = false;
     clobberize(
         graph, node, NoOpClobberize(),
         [&] (AbstractHeap heap) {
-            if (heap == AbstractHeap(World))
+            switch (heap.kind()) {
+            case World:
+            case Heap:
                 result = true;
+                break;
+            default:
+                break;
+            }
         },
         NoOpClobberize());
     return result;

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (180655 => 180656)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-02-26 04:18:47 UTC (rev 180655)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-02-26 04:29:26 UTC (rev 180656)
@@ -41,6 +41,12 @@
 {
     // Some notes:
     //
+    // - The canonical way of clobbering the world is to read world and write
+    //   heap. This is because World subsumes Heap and Stack, and Stack can be
+    //   read by anyone but only written to by explicit stack writing operations.
+    //   Of course, claiming to also write World is not wrong; it'll just
+    //   pessimise some important optimizations.
+    //
     // - We cannot hoist, or sink, anything that has effects. This means that the
     //   easiest way of indicating that something cannot be hoisted is to claim
     //   that it side-effects some miscellaneous thing.
@@ -53,9 +59,9 @@
     //   versions of those nodes that backward-exit instead, but I'm not convinced
     //   of the soundness.
     //
-    // - Some nodes lie, and claim that they do not read the JSCell_structureID, JSCell_typeInfoFlags, etc.
-    //   These are nodes that use the structure in a way that does not depend on
-    //   things that change under structure transitions.
+    // - Some nodes lie, and claim that they do not read the JSCell_structureID,
+    //   JSCell_typeInfoFlags, etc. These are nodes that use the structure in a way
+    //   that does not depend on things that change under structure transitions.
     //
     // - It's implicitly understood that OSR exits read the world. This is why we
     //   generally don't move or eliminate stores. Every node can exit, so the
@@ -157,16 +163,16 @@
     case GetEnumerableLength:
     case GetStructurePropertyEnumerator:
     case GetGenericPropertyEnumerator: {
-        read(World);
+        read(Heap);
         write(SideState);
         return;
     }
 
     case GetDirectPname: {
-        // This reads and writes world because it can end up calling a generic getByVal 
+        // This reads and writes heap because it can end up calling a generic getByVal 
         // if the Structure changed, which could in turn end up calling a getter.
         read(World);
-        write(World);
+        write(Heap);
         return;
     }
 
@@ -187,7 +193,7 @@
                 def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), node);
                 return;
             }
-            read(World);
+            read(Heap);
             return;
         }
             
@@ -198,7 +204,7 @@
                 def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), node);
                 return;
             }
-            read(World);
+            read(Heap);
             return;
         }
             
@@ -209,7 +215,7 @@
                 def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), node);
                 return;
             }
-            read(World);
+            read(Heap);
             return;
         }
 
@@ -219,13 +225,13 @@
                 read(IndexedArrayStorageProperties);
                 return;
             }
-            read(World);
+            read(Heap);
             return;
         }
 
         default: {
             read(World);
-            write(World);
+            write(Heap);
             return;
         }
         }
@@ -376,7 +382,7 @@
     case GetMyArgumentByValSafe:
     case ValueAdd:
         read(World);
-        write(World);
+        write(Heap);
         return;
         
     case GetGetter:
@@ -425,7 +431,7 @@
         case Array::Undecided:
             // Assume the worst since we don't have profiling yet.
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         case Array::ForceExit:
@@ -434,13 +440,13 @@
             
         case Array::Generic:
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         case Array::String:
             if (mode.isOutOfBounds()) {
                 read(World);
-                write(World);
+                write(Heap);
                 return;
             }
             // This appears to read nothing because it's only reading immutable data.
@@ -461,7 +467,7 @@
                 return;
             }
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         case Array::Double:
@@ -472,7 +478,7 @@
                 return;
             }
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         case Array::Contiguous:
@@ -483,7 +489,7 @@
                 return;
             }
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         case Array::ArrayStorage:
@@ -494,7 +500,7 @@
                 return;
             }
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         case Array::Int8Array:
@@ -529,7 +535,7 @@
         case Array::String:
             // Assume the worst since we don't have profiling yet.
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         case Array::ForceExit:
@@ -538,7 +544,7 @@
             
         case Array::Generic:
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         case Array::Arguments:
@@ -551,7 +557,7 @@
         case Array::Int32:
             if (node->arrayMode().isOutOfBounds()) {
                 read(World);
-                write(World);
+                write(Heap);
                 return;
             }
             read(Butterfly_publicLength);
@@ -566,7 +572,7 @@
         case Array::Double:
             if (node->arrayMode().isOutOfBounds()) {
                 read(World);
-                write(World);
+                write(Heap);
                 return;
             }
             read(Butterfly_publicLength);
@@ -581,7 +587,7 @@
         case Array::Contiguous:
             if (node->arrayMode().isOutOfBounds()) {
                 read(World);
-                write(World);
+                write(Heap);
                 return;
             }
             read(Butterfly_publicLength);
@@ -597,7 +603,7 @@
         case Array::SlowPutArrayStorage:
             // Give up on life for now.
             read(World);
-            write(World);
+            write(Heap);
             return;
 
         case Array::Int8Array:
@@ -813,7 +819,7 @@
     case StringCharAt:
         if (node->arrayMode().isOutOfBounds()) {
             read(World);
-            write(World);
+            write(Heap);
             return;
         }
         def(PureValue(node));
@@ -829,7 +835,7 @@
             return;
         }
         read(World);
-        write(World);
+        write(Heap);
         return;
         
     case ToString:
@@ -843,7 +849,7 @@
         case CellUse:
         case UntypedUse:
             read(World);
-            write(World);
+            write(Heap);
             return;
             
         default:
@@ -945,7 +951,7 @@
 bool accessesOverlap(Graph&, Node*, AbstractHeap);
 bool writesOverlap(Graph&, Node*, AbstractHeap);
 
-bool clobbersWorld(Graph&, Node*);
+bool clobbersHeap(Graph&, Node*);
 
 // We would have used bind() for these, but because of the overlaoding that we are doing,
 // it's quite a bit of clearer to just write this out the traditional way.

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (180655 => 180656)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-02-26 04:18:47 UTC (rev 180655)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-02-26 04:29:26 UTC (rev 180656)
@@ -37,7 +37,7 @@
 
 bool doesGC(Graph& graph, Node* node)
 {
-    if (clobbersWorld(graph, node))
+    if (clobbersHeap(graph, node))
         return true;
     
     // Now consider nodes that don't clobber the world but that still may GC. This includes all
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to