AI rule for MultiPutByOffset executes its effects in the wrong order
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Sep 2018 21:00:08 +0000 (21:00 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Sep 2018 21:00:08 +0000 (21:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189757
<rdar://problem/43535257>

Reviewed by Michael Saboff.

JSTests:

* stress/multi-put-by-offset-must-filter-value-before-filtering-base.js: Added.
(foo):
(Foo):
(g):

Source/JavaScriptCore:

The AI rule for MultiPutByOffset was executing effects in the wrong order.
It first executed the transition effects and the effects on the base, and
then executed the filtering effects on the value being stored. However, you
can end up with the wrong type when the base and the value being stored
are the same. E.g, in a program like `o.f = o`. These effects need to happen
in the opposite order, modeling what happens in the runtime executing of
MultiPutByOffset.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

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

JSTests/ChangeLog
JSTests/stress/multi-put-by-offset-must-filter-value-before-filtering-base.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

index 7213b67..03e7f24 100644 (file)
@@ -1,3 +1,16 @@
+2018-09-19  Saam barati  <sbarati@apple.com>
+
+        AI rule for MultiPutByOffset executes its effects in the wrong order
+        https://bugs.webkit.org/show_bug.cgi?id=189757
+        <rdar://problem/43535257>
+
+        Reviewed by Michael Saboff.
+
+        * stress/multi-put-by-offset-must-filter-value-before-filtering-base.js: Added.
+        (foo):
+        (Foo):
+        (g):
+
 2018-09-17  Mark Lam  <mark.lam@apple.com>
 
         Ensure that ForInContexts are invalidated if their loop local is over-written.
diff --git a/JSTests/stress/multi-put-by-offset-must-filter-value-before-filtering-base.js b/JSTests/stress/multi-put-by-offset-must-filter-value-before-filtering-base.js
new file mode 100644 (file)
index 0000000..b623e04
--- /dev/null
@@ -0,0 +1,25 @@
+//@ runDefault("--collectContinuously=1", "--useConcurrentJIT=0", "--useConcurrentGC=1")
+
+function foo(oo) {
+    oo.x = 4;
+    oo.y = 4;
+    oo.e = oo;
+    oo.e = 7;
+    oo.f = 8;
+}
+noInline(foo);
+
+function Foo() {
+    foo(this);
+}
+
+for (var i = 0; i < 100000; i++) {
+    g();
+}
+
+function g(){
+    foo({f:8});
+    new Foo();
+    new Foo();
+    new Foo();
+}
index 86a03a5..8c42e01 100644 (file)
@@ -1,3 +1,22 @@
+2018-09-19  Saam barati  <sbarati@apple.com>
+
+        AI rule for MultiPutByOffset executes its effects in the wrong order
+        https://bugs.webkit.org/show_bug.cgi?id=189757
+        <rdar://problem/43535257>
+
+        Reviewed by Michael Saboff.
+
+        The AI rule for MultiPutByOffset was executing effects in the wrong order.
+        It first executed the transition effects and the effects on the base, and
+        then executed the filtering effects on the value being stored. However, you
+        can end up with the wrong type when the base and the value being stored
+        are the same. E.g, in a program like `o.f = o`. These effects need to happen
+        in the opposite order, modeling what happens in the runtime executing of
+        MultiPutByOffset.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+
 2018-09-18  Mark Lam  <mark.lam@apple.com>
 
         Ensure that ForInContexts are invalidated if their loop local is over-written.
index e53dd96..f845c58 100644 (file)
@@ -3299,12 +3299,17 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             }
         }
         
-        observeTransitions(clobberLimit, transitions);
-        if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
-            m_state.setIsValid(false);
+        // We need to order AI executing these effects in the same order as they're executed
+        // at runtime. This is critical when you have JS code like `o.f = o;`. We first
+        // filter types on o, then transition o. Not the other way around. If we got
+        // this ordering wrong, we could end up with the wrong type representing o.
         setForNode(node->child2(), resultingValue);
         if (!!originalValue && !resultingValue)
             m_state.setIsValid(false);
+
+        observeTransitions(clobberLimit, transitions);
+        if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
+            m_state.setIsValid(false);
         break;
     }