Title: [208311] trunk
Revision
208311
Author
sbar...@apple.com
Date
2016-11-02 16:15:33 -0700 (Wed, 02 Nov 2016)

Log Message

Allocation elimination of rest parameter doesn't take into account indexed properties on Array.prototype/Object.prototype
https://bugs.webkit.org/show_bug.cgi?id=164301

Reviewed by Geoffrey Garen.

JSTests:

* stress/rest-parameter-allocation-elimination-watchpoints-2.js: Added.
(assert):
(foo):
* stress/rest-parameter-allocation-elimination-watchpoints-3.js: Added.
(assert):
(foo):
* stress/rest-parameter-allocation-elimination-watchpoints-4.js: Added.
(assert):
(foo):
* stress/rest-parameter-allocation-elimination-watchpoints-5.js: Added.
(assert):
(foo):
* stress/rest-parameter-allocation-elimination-watchpoints-6.js: Added.
(assert):
(foo):
* stress/rest-parameter-allocation-elimination-watchpoints.js: Added.
(assert):
(foo):

Source/_javascript_Core:

We weren't taking into account indexed properties on the __proto__
of the rest parameter. This made the code for doing out of bound
accesses incorrect since it just assumed it's safe for the result of
an out of bound access to be undefined. This broke the semantics
of JS code when there was an indexed property on the Array.prototype
or Object.prototype.

This patch makes sure we set up the proper watchpoints for making
sure out of bound accesses are safe to return undefined.

* dfg/DFGArgumentsEliminationPhase.cpp:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (208310 => 208311)


--- trunk/JSTests/ChangeLog	2016-11-02 23:04:22 UTC (rev 208310)
+++ trunk/JSTests/ChangeLog	2016-11-02 23:15:33 UTC (rev 208311)
@@ -1,3 +1,29 @@
+2016-11-02  Saam Barati  <sbar...@apple.com>
+
+        Allocation elimination of rest parameter doesn't take into account indexed properties on Array.prototype/Object.prototype
+        https://bugs.webkit.org/show_bug.cgi?id=164301
+
+        Reviewed by Geoffrey Garen.
+
+        * stress/rest-parameter-allocation-elimination-watchpoints-2.js: Added.
+        (assert):
+        (foo):
+        * stress/rest-parameter-allocation-elimination-watchpoints-3.js: Added.
+        (assert):
+        (foo):
+        * stress/rest-parameter-allocation-elimination-watchpoints-4.js: Added.
+        (assert):
+        (foo):
+        * stress/rest-parameter-allocation-elimination-watchpoints-5.js: Added.
+        (assert):
+        (foo):
+        * stress/rest-parameter-allocation-elimination-watchpoints-6.js: Added.
+        (assert):
+        (foo):
+        * stress/rest-parameter-allocation-elimination-watchpoints.js: Added.
+        (assert):
+        (foo):
+
 2016-11-01  Saam Barati  <sbar...@apple.com>
 
         We should be able to eliminate rest parameter allocations

Added: trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-2.js (0 => 208311)


--- trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-2.js	                        (rev 0)
+++ trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-2.js	2016-11-02 23:15:33 UTC (rev 208311)
@@ -0,0 +1,19 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+noInline(assert);
+
+function foo(...args) {
+    return args[0];
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    // Warm it up on in bound accesses.
+    assert(foo(i) === i);
+}
+
+Array.prototype[0] = 50;
+for (let i = 0; i < 10000; i++)
+    assert(foo() === 50);

Added: trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-3.js (0 => 208311)


--- trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-3.js	                        (rev 0)
+++ trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-3.js	2016-11-02 23:15:33 UTC (rev 208311)
@@ -0,0 +1,22 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+noInline(assert);
+
+function foo(...args) {
+    return args[0];
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    // Warm it up on both in bound and out of bound accesses.
+    if (i % 2)
+        assert(foo(i) === i);
+    else
+        assert(foo() === undefined);
+}
+
+Object.prototype[0] = 50;
+for (let i = 0; i < 10000; i++)
+    assert(foo() === 50);

Added: trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-4.js (0 => 208311)


--- trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-4.js	                        (rev 0)
+++ trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-4.js	2016-11-02 23:15:33 UTC (rev 208311)
@@ -0,0 +1,20 @@
+
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+noInline(assert);
+
+function foo(...args) {
+    return args[0];
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    // Warm it up on in bound accesses.
+    assert(foo(i) === i);
+}
+
+Object.prototype[0] = 50;
+for (let i = 0; i < 10000; i++)
+    assert(foo() === 50);

Added: trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-5.js (0 => 208311)


--- trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-5.js	                        (rev 0)
+++ trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-5.js	2016-11-02 23:15:33 UTC (rev 208311)
@@ -0,0 +1,25 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+noInline(assert);
+
+function foo(...args) {
+    return args[0];
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    // Warm it up on both in bound and out of bound accesses.
+    if (i % 2)
+        assert(foo(i) === i);
+    else
+        assert(foo() === undefined);
+}
+
+let newProto = [50];
+newProto.__proto__ = null;
+
+Array.prototype.__proto__ = newProto;
+for (let i = 0; i < 10000; i++)
+    assert(foo() === 50);

Added: trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-6.js (0 => 208311)


--- trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-6.js	                        (rev 0)
+++ trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints-6.js	2016-11-02 23:15:33 UTC (rev 208311)
@@ -0,0 +1,24 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+noInline(assert);
+
+function foo(...args) {
+    return args[0];
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    // Warm it up on both in bound and out of bound accesses.
+    if (i % 2)
+        assert(foo(i) === i);
+    else
+        assert(foo() === undefined);
+}
+
+let newProto = [50];
+newProto.__proto__ = null;
+Object.prototype.__proto__ = newProto;
+for (let i = 0; i < 10000; i++)
+    assert(foo() === 50);

Added: trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints.js (0 => 208311)


--- trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints.js	                        (rev 0)
+++ trunk/JSTests/stress/rest-parameter-allocation-elimination-watchpoints.js	2016-11-02 23:15:33 UTC (rev 208311)
@@ -0,0 +1,22 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+noInline(assert);
+
+function foo(...args) {
+    return args[0];
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    // Warm it up on both in bound and out of bound accesses.
+    if (i % 2)
+        assert(foo(i) === i);
+    else
+        assert(foo() === undefined);
+}
+
+Array.prototype[0] = 50;
+for (let i = 0; i < 10000; i++)
+    assert(foo() === 50);

Modified: trunk/Source/_javascript_Core/ChangeLog (208310 => 208311)


--- trunk/Source/_javascript_Core/ChangeLog	2016-11-02 23:04:22 UTC (rev 208310)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-11-02 23:15:33 UTC (rev 208311)
@@ -1,3 +1,22 @@
+2016-11-02  Saam Barati  <sbar...@apple.com>
+
+        Allocation elimination of rest parameter doesn't take into account indexed properties on Array.prototype/Object.prototype
+        https://bugs.webkit.org/show_bug.cgi?id=164301
+
+        Reviewed by Geoffrey Garen.
+
+        We weren't taking into account indexed properties on the __proto__
+        of the rest parameter. This made the code for doing out of bound
+        accesses incorrect since it just assumed it's safe for the result of
+        an out of bound access to be undefined. This broke the semantics
+        of JS code when there was an indexed property on the Array.prototype
+        or Object.prototype.
+
+        This patch makes sure we set up the proper watchpoints for making
+        sure out of bound accesses are safe to return undefined.
+
+        * dfg/DFGArgumentsEliminationPhase.cpp:
+
 2016-11-02  Geoffrey Garen  <gga...@apple.com>
 
         One file per class for CodeBlock.h/.cpp

Modified: trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp (208310 => 208311)


--- trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp	2016-11-02 23:04:22 UTC (rev 208310)
+++ trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp	2016-11-02 23:15:33 UTC (rev 208311)
@@ -28,6 +28,7 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "ArrayPrototype.h"
 #include "BytecodeLivenessAnalysisInlines.h"
 #include "ClonedArguments.h"
 #include "DFGArgumentsUtilities.h"
@@ -154,13 +155,25 @@
                 if (mode.isInBounds())
                     break;
                 
-                // If we're out-of-bounds then we proceed only if the object prototype is
-                // sane (i.e. doesn't have indexed properties).
+                // If we're out-of-bounds then we proceed only if the prototype chain
+                // for the allocation is sane (i.e. doesn't have indexed properties).
                 JSGlobalObject* globalObject = m_graph.globalObjectFor(edge->origin.semantic);
-                if (globalObject->objectPrototypeIsSane()) {
-                    m_graph.watchpoints().addLazily(globalObject->objectPrototype()->structure()->transitionWatchpointSet());
-                    if (globalObject->objectPrototypeIsSane())
+                InlineWatchpointSet& objectPrototypeTransition = globalObject->objectPrototype()->structure()->transitionWatchpointSet();
+                if (edge->op() == CreateRest) {
+                    InlineWatchpointSet& arrayPrototypeTransition = globalObject->arrayPrototype()->structure()->transitionWatchpointSet();
+                    if (arrayPrototypeTransition.isStillValid() 
+                        && objectPrototypeTransition.isStillValid() 
+                        && globalObject->arrayPrototypeChainIsSane()) {
+                        m_graph.watchpoints().addLazily(arrayPrototypeTransition);
+                        m_graph.watchpoints().addLazily(objectPrototypeTransition);
                         break;
+                    }
+                } else {
+                    if (objectPrototypeTransition.isStillValid() 
+                        && globalObject->objectPrototypeIsSane()) {
+                        m_graph.watchpoints().addLazily(objectPrototypeTransition);
+                        break;
+                    }
                 }
                 escape(edge, source);
                 break;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to