js/src/jit-test/tests/jaeger/loops/multiply-by-int32min.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 function foo()
michael@0 2 {
michael@0 3 // Range analysis incorrectly computes a range for the multiplication. Once
michael@0 4 // that incorrect range is computed, the goal is to compute a new value whose
michael@0 5 // range analysis *thinks* is in int32_t range, but which goes past it using
michael@0 6 // JS semantics.
michael@0 7 //
michael@0 8 // On the final iteration, in JS semantics, the multiplication produces 0, and
michael@0 9 // the next addition 0x7fffffff. Adding any positive integer to that goes
michael@0 10 // past int32_t range: here, (0x7fffffff + 5) or 2147483652.
michael@0 11 //
michael@0 12 // Range analysis instead thinks the multiplication produces a value in the
michael@0 13 // range [INT32_MIN, INT32_MIN], and the next addition a value in the range
michael@0 14 // [-1, -1]. Adding any positive value to that doesn't overflow int32_t range
michael@0 15 // but *does* overflow the actual range in JS semantics. Thus omitting
michael@0 16 // overflow checks produces the value 0x80000004, which interpreting as signed
michael@0 17 // is (INT32_MIN + 4) or -2147483644.
michael@0 18 //
michael@0 19 // For this test to trigger the bug it was supposed to trigger:
michael@0 20 //
michael@0 21 // * 0x7fffffff must be the LHS, not RHS, of the addition in the loop, and
michael@0 22 // * i must not be incremented using ++
michael@0 23 //
michael@0 24 // The first is required because JM LoopState doesn't treat *both* V + mul and
michael@0 25 // mul + V as not overflowing, when V is known to be int32_t -- only V + mul.
michael@0 26 // (JM pessimally assumes V's type might change before it's evaluated. This
michael@0 27 // obviously can't happen if V is a constant, but JM's puny little mind
michael@0 28 // doesn't detect this possibility now.)
michael@0 29 //
michael@0 30 // The second is required because JM LoopState only ignores integer overflow
michael@0 31 // on multiplications if the enclosing loop is a "constrainedLoop" (the name
michael@0 32 // of the relevant field). Loops become unconstrained when unhandled ops are
michael@0 33 // found in the loop. Increment operators generate a DUP op, which is not
michael@0 34 // presently a handled op, causing the loop to become unconstrained.
michael@0 35 for (var i = 0; i < 15; i = i + 1) {
michael@0 36 var y = (0x7fffffff + ((i & 1) * -2147483648)) + 5;
michael@0 37 }
michael@0 38 return y;
michael@0 39 }
michael@0 40 assertEq(foo(), (0x7fffffff + ((14 & 1) * -2147483648)) + 5);
michael@0 41
michael@0 42 function bar()
michael@0 43 {
michael@0 44 // Variation on the theme of the above test with -1 as the other half of the
michael@0 45 // INT32_MIN multiplication, which *should* result in -INT32_MIN on multiply
michael@0 46 // (exceeding int32_t range).
michael@0 47 //
michael@0 48 // Here, range analysis again thinks the range of the multiplication is
michael@0 49 // INT32_MIN. We'd overflow-check except that adding zero (on the LHS, see
michael@0 50 // above) prevents overflow checking, so range analysis thinks the range is
michael@0 51 // [INT32_MIN, INT32_MIN] when -INT32_MIN is actually possible. This direct
michael@0 52 // result of the multiplication is already out of int32_t range, so no need to
michael@0 53 // add anything to bias it outside int32_t range to get a wrong result.
michael@0 54 for (var i = 0; i < 17; i = i + 1) {
michael@0 55 var y = (0 + ((-1 + (i & 1)) * -2147483648));
michael@0 56 }
michael@0 57 return y;
michael@0 58 }
michael@0 59 assertEq(bar(), (0 + ((-1 + (16 & 1)) * -2147483648)));

mercurial