Bug 1532262: OBJECT_FLAG_NON_PACKED only implies packed elements, not a packed array. r=jandem
authorAndré Bargull <andre.bargull@gmail.com>
Sun, 17 Mar 2019 23:56:01 +0100
changeset 464708 7e435fbdd0371098d80e7e0aed46bc71f8bda618
parent 464707 1735fe85436911fca7c7e5837e4cbc94040b8825
child 464709 61d17d514b98a4e0ac101d48c87b1711836b4f73
push id112468
push userarchaeopteryx@coole-files.de
push dateSun, 17 Mar 2019 22:59:17 +0000
treeherdermozilla-inbound@7e435fbdd037 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1532262
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1532262: OBJECT_FLAG_NON_PACKED only implies packed elements, not a packed array. r=jandem Summary: Add MIsPackedArray to ensure the array's length matches its initialised length. Differential Revision: https://phabricator.services.mozilla.com/D23673
js/src/jit-test/tests/ion/spreadcall-not-optimized-dynamic-2.js
js/src/jit-test/tests/ion/spreadcall-not-optimized-dynamic-2a.js
js/src/jit-test/tests/ion/spreadcall-not-optimized-dynamic-2b.js
js/src/jit-test/tests/ion/spreadcall-not-optimized-static-2.js
js/src/jit-test/tests/ion/spreadcall-not-optimized-static-2a.js
js/src/jit-test/tests/ion/spreadcall-not-optimized-static-2b.js
js/src/jit/IonBuilder.cpp
rename from js/src/jit-test/tests/ion/spreadcall-not-optimized-dynamic-2.js
rename to js/src/jit-test/tests/ion/spreadcall-not-optimized-dynamic-2a.js
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/spreadcall-not-optimized-dynamic-2b.js
@@ -0,0 +1,37 @@
+// Tests when JSOP_OPTIMIZE_SPREADCALL no longer apply after the initial Ion
+// compilation.
+
+// JSOP_OPTIMIZE_SPREADCALL can be optimised when the following conditions
+// are fulfilled:
+//   (1) the argument is an array
+//   (2) the array has no hole
+//   (3) array[@@iterator] is not modified
+//   (4) the array's prototype is Array.prototype
+//   (5) Array.prototype[@@iterator] is not modified
+//   (6) %ArrayIteratorPrototype%.next is not modified
+
+function add(a, b, c = 0, d = 0) {
+    return a + b + c + d;
+}
+
+// The rest argument is a packed array.
+function test() {
+    function maybeInvalidate(rest) {
+        // Use a WithStatement to prevent Ion-inlining. This ensures any
+        // bailouts due to type changes don't occur in this function, but
+        // instead in the caller.
+        with ({});
+
+        if (i >= 1900) {
+            rest.length = 3;
+        }
+    }
+    function fn(...rest) {
+        maybeInvalidate(rest);
+        return add(...rest);
+    }
+    for (var i = 0; i < 4000; ++i) {
+        assertEq(fn(1, 2), 3);
+    }
+}
+test();
rename from js/src/jit-test/tests/ion/spreadcall-not-optimized-static-2.js
rename to js/src/jit-test/tests/ion/spreadcall-not-optimized-static-2a.js
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/spreadcall-not-optimized-static-2b.js
@@ -0,0 +1,27 @@
+// Tests when JSOP_OPTIMIZE_SPREADCALL can't be applied during the initial
+// Ion compilation.
+
+// JSOP_OPTIMIZE_SPREADCALL can be optimised when the following conditions
+// are fulfilled:
+//   (1) the argument is an array
+//   (2) the array has no hole
+//   (3) array[@@iterator] is not modified
+//   (4) the array's prototype is Array.prototype
+//   (5) Array.prototype[@@iterator] is not modified
+//   (6) %ArrayIteratorPrototype%.next is not modified
+
+function add(a, b, c = 0, d = 0) {
+    return a + b + c + d;
+}
+
+// The rest argument is a packed array.
+function test() {
+    function fn(...rest) {
+        rest.length = 3;
+        return add(...rest);
+    }
+    for (var i = 0; i < 2000; ++i) {
+        assertEq(fn(1, 2), 3);
+    }
+}
+test();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5676,17 +5676,17 @@ bool IonBuilder::ensureArrayIteratorProt
 AbortReasonOr<Ok> IonBuilder::jsop_optimize_spreadcall() {
   MDefinition* arr = current->peek(-1);
   arr->setImplicitlyUsedUnchecked();
 
   // Assuming optimization isn't available doesn't affect correctness.
   // TODO: Investigate dynamic checks.
   bool result = false;
   do {
-    // Inline with a constant if the conditions described in
+    // Inline with MIsPackedArray if the conditions described in
     // js::OptimizeSpreadCall() are all met or can be expressed through
     // compiler constraints.
 
     // The argument is an array.
     TemporaryTypeSet* types = arr->resultTypeSet();
     if (!types || types->getKnownClass(constraints()) != &ArrayObject::class_) {
       break;
     }
@@ -5722,17 +5722,23 @@ AbortReasonOr<Ok> IonBuilder::jsop_optim
     // %ArrayIteratorPrototype%.next is not modified.
     if (!ensureArrayIteratorPrototypeNextNotModified()) {
       break;
     }
 
     result = true;
   } while (false);
 
-  pushConstant(BooleanValue(result));
+  if (result) {
+    auto* ins = MIsPackedArray::New(alloc(), arr);
+    current->add(ins);
+    current->push(ins);
+  } else {
+    pushConstant(BooleanValue(false));
+  }
   return Ok();
 }
 
 AbortReasonOr<Ok> IonBuilder::jsop_funapplyarray(uint32_t argc) {
   MOZ_ASSERT(argc == 2);
 
   int funcDepth = -((int)argc + 1);