Bug 1132888 part 3 - Fix assertRecoveredOnBailout optimization assertion. r=h4writer
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Tue, 08 Nov 2016 14:06:38 +0000
changeset 321511 5c1b90a1926d9210471d5f411ffad85ac9295e5f
parent 321510 40ae0b40fd73c224b9e1a3b9f187c98aaab523ed
child 321512 8daddd6054f2bc3c1c563a257cbaf720032bea95
push id83626
push usernpierron@mozilla.com
push dateTue, 08 Nov 2016 14:06:58 +0000
treeherdermozilla-inbound@8daddd6054f2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1132888
milestone52.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 1132888 part 3 - Fix assertRecoveredOnBailout optimization assertion. r=h4writer
js/src/jit-test/tests/ion/dce-with-rinstructions.js
js/src/jit-test/tests/ion/recover-objects.js
js/src/jit/ValueNumbering.cpp
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -1,13 +1,14 @@
 setJitCompilerOption("baseline.warmup.trigger", 10);
 setJitCompilerOption("ion.warmup.trigger", 20);
 var i;
 
 var config = getBuildConfiguration();
+var max = 200;
 
 // Check that we are able to remove the operation inside recover test functions (denoted by "rop..."),
 // when we inline the first version of uceFault, and ensure that the bailout is correct
 // when uceFault is replaced (which cause an invalidation bailout)
 
 var uceFault = function (i) {
     if (i > 98)
         uceFault = function (i) { return true; };
@@ -1286,33 +1287,22 @@ function rhypot_object_4args(i) {
         assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2) + (i + 3) * (i + 3)));
     assertRecoveredOnBailout(x, false);
     return i;
 }
 
 var uceFault_random = eval(uneval(uceFault).replace('uceFault', 'uceFault_random'));
 function rrandom(i) {
     // setRNGState() exists only in debug builds
+    if(config.debug) setRNGState(2, 1+i);
 
-    if(config.debug) {
-        setRNGState(2, 0);
-        var x = Math.random();
-        if (uceFault_random(i) || uceFault_random(i)) {
-            setRNGState(2, 0);
-            assertEq(x, Math.random());
-        }
-        assertRecoveredOnBailout(x, true);
-    } else {
-        var x = Math.random();
-        if (uceFault_random(i) || uceFault_random(i)) {
-            Math.random();
-        }
-        assertRecoveredOnBailout(x, true);
-    }
-
+    var x = Math.random();
+    if (uceFault_random(i) || uceFault_random(i))
+        assertEq(x, config.debug ? setRNGState(2, 1+i) || Math.random() : x);
+    assertRecoveredOnBailout(x, true);
     return i;
 }
 
 var uceFault_sin_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_sin_number'));
 function rsin_number(i) {
     var x = Math.sin(i);
     if (uceFault_sin_number(i) || uceFault_sin_number(i))
         assertEq(x, Math.sin(i));
@@ -1348,17 +1338,18 @@ function rlog_object(i) {
     var x = Math.log(o); /* Evaluated with t == i, not t == 1000 */
     t = 1000;
     if (uceFault_log_object(i) || uceFault_log_object(i))
         assertEq(x, Math.log(99) /* log(99) */);
     assertRecoveredOnBailout(x, false);
     return i;
 }
 
-for (i = 0; i < 100; i++) {
+for (j = 100 - max; j < 100; j++) {
+    let i = j < 2 ? (Math.abs(j) % 50) + 2 : j;
     rbitnot_number(i);
     rbitnot_object(i);
     rbitand_number(i);
     rbitand_object(i);
     rbitor_number(i);
     rbitor_object(i);
     rbitxor_number(i);
     rbitxor_object(i);
--- a/js/src/jit-test/tests/ion/recover-objects.js
+++ b/js/src/jit-test/tests/ion/recover-objects.js
@@ -1,29 +1,35 @@
 // |jit-test| test-join=--no-unboxed-objects; --ion-pgo=on
 //
 // Unboxed object optimization might not trigger in all cases, thus we ensure
 // that Scalar Replacement optimization is working well independently of the
 // object representation.
 
+var max = 200;
+
 // Ion eager fails the test below because we have not yet created any
 // template object in baseline before running the content of the top-level
 // function.
-if (getJitCompilerOptions()["ion.warmup.trigger"] <= 90)
-    setJitCompilerOption("ion.warmup.trigger", 90);
+if (getJitCompilerOptions()["ion.warmup.trigger"] <= max - 10)
+    setJitCompilerOption("ion.warmup.trigger", max - 10);
+
+// Force Inlining heuristics to always inline the functions which have the same
+// number of use count.
+setJitCompilerOption("ion.warmup.trigger", getJitCompilerOptions()["ion.warmup.trigger"]);
 
 // This test checks that we are able to remove the getprop & setprop with scalar
 // replacement, so we should not force inline caches, as this would skip the
 // generation of getprop & setprop instructions.
 if (getJitCompilerOptions()["ion.forceinlineCaches"])
     setJitCompilerOption("ion.forceinlineCaches", 0);
 
 function resumeHere() {}
 var uceFault = function (i) {
-    if (i > 98)
+    if (i > max - 2)
         uceFault = function (i) { return true; };
     return false;
 };
 
 
 // Without "use script" in the inner function, the arguments might be
 // observable.
 function inline_notSoEmpty1(a, b, c, d) {
@@ -79,17 +85,17 @@ function notSoEmpty2(i) {
     // This can only be recovered on bailout iff either we have type
     // information for the property access in the branch, or the branch is
     // removed before scalar replacement.
     assertRecoveredOnBailout(res, true);
 }
 
 // Check that we can recover objects with their content.
 var argFault_observeArg = function (i) {
-    if (i > 98)
+    if (i > max - 2)
         return inline_observeArg.arguments[0];
     return { test : i };
 };
 function inline_observeArg(obj, i) {
     return argFault_observeArg(i);
 }
 function observeArg(i) {
     var obj = { test: i };
@@ -130,36 +136,36 @@ function withinIf(i) {
         obj = undefined;
     }
     assertEq(x, i);
 }
 
 // Check case where one successor can have multiple times the same predecessor.
 function unknownLoad(i) {
     var obj = { foo: i };
+    // Unknown properties are inlined as undefined.
     assertEq(obj.bar, undefined);
-    // Unknown properties are using GetPropertyCache.
-    assertRecoveredOnBailout(obj, false);
+    assertRecoveredOnBailout(obj, true);
 }
 
 // Check with dynamic slots.
 function dynamicSlots(i) {
     var obj = {
         p0: i + 0, p1: i + 1, p2: i + 2, p3: i + 3, p4: i + 4, p5: i + 5, p6: i + 6, p7: i + 7, p8: i + 8, p9: i + 9, p10: i + 10,
         p11: i + 11, p12: i + 12, p13: i + 13, p14: i + 14, p15: i + 15, p16: i + 16, p17: i + 17, p18: i + 18, p19: i + 19, p20: i + 20,
         p21: i + 21, p22: i + 22, p23: i + 23, p24: i + 24, p25: i + 25, p26: i + 26, p27: i + 27, p28: i + 28, p29: i + 29, p30: i + 30,
         p31: i + 31, p32: i + 32, p33: i + 33, p34: i + 34, p35: i + 35, p36: i + 36, p37: i + 37, p38: i + 38, p39: i + 39, p40: i + 40,
         p41: i + 41, p42: i + 42, p43: i + 43, p44: i + 44, p45: i + 45, p46: i + 46, p47: i + 47, p48: i + 48, p49: i + 49, p50: i + 50
     };
     // Add a function call to capture a resumepoint at the end of the call or
     // inside the inlined block, such as the bailout does not rewind to the
     // beginning of the function.
     resumeHere(); bailout();
     assertEq(obj.p0 + obj.p10 + obj.p20 + obj.p30 + obj.p40, 5 * i + 100);
-    assertRecoveredOnBailout(obj, true);
+    assertRecoveredOnBailout(obj, false);
 }
 
 // Check that we can correctly recover allocations of new objects.
 function Point(x, y)
 {
     this.x = x;
     this.y = y;
 }
@@ -167,17 +173,17 @@ function Point(x, y)
 function createThisWithTemplate(i)
 {
     var p = new Point(i - 1, i + 1);
     bailout();
     assertEq(p.y - p.x, 2);
     assertRecoveredOnBailout(p, true);
 }
 
-for (var i = 0; i < 100; i++) {
+for (var i = 0; i < max; i++) {
     notSoEmpty1(i);
     notSoEmpty2(i);
     observeArg(i);
     complexPhi(i);
     withinIf(i);
     unknownLoad(i);
     dynamicSlots(i);
     createThisWithTemplate(i);
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -722,17 +722,18 @@ ValueNumberer::visitDefinition(MDefiniti
 
         // The Nop is introduced to capture the result and make sure the operands
         // are not live anymore when there are no further uses. Though when
         // all operands are still needed the Nop doesn't decrease the liveness
         // and can get removed.
         MResumePoint* rp = nop->resumePoint();
         if (rp && rp->numOperands() > 0 &&
             rp->getOperand(rp->numOperands() - 1) == prev &&
-            !nop->block()->lastIns()->isThrow())
+            !nop->block()->lastIns()->isThrow() &&
+            !prev->isAssertRecoveredOnBailout())
         {
             size_t numOperandsLive = 0;
             for (size_t j = 0; j < prev->numOperands(); j++) {
                 for (size_t i = 0; i < rp->numOperands(); i++) {
                     if (prev->getOperand(j) == rp->getOperand(i)) {
                         numOperandsLive++;
                         break;
                     }