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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit-test/tests/jaeger/loops/multiply-by-int32min.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,59 @@
     1.4 +function foo()
     1.5 +{
     1.6 +  // Range analysis incorrectly computes a range for the multiplication.  Once
     1.7 +  // that incorrect range is computed, the goal is to compute a new value whose
     1.8 +  // range analysis *thinks* is in int32_t range, but which goes past it using
     1.9 +  // JS semantics.
    1.10 +  //
    1.11 +  // On the final iteration, in JS semantics, the multiplication produces 0, and
    1.12 +  // the next addition 0x7fffffff.  Adding any positive integer to that goes
    1.13 +  // past int32_t range: here, (0x7fffffff + 5) or 2147483652.
    1.14 +  //
    1.15 +  // Range analysis instead thinks the multiplication produces a value in the
    1.16 +  // range [INT32_MIN, INT32_MIN], and the next addition a value in the range
    1.17 +  // [-1, -1].  Adding any positive value to that doesn't overflow int32_t range
    1.18 +  // but *does* overflow the actual range in JS semantics.  Thus omitting
    1.19 +  // overflow checks produces the value 0x80000004, which interpreting as signed
    1.20 +  // is (INT32_MIN + 4) or -2147483644.
    1.21 +  //
    1.22 +  // For this test to trigger the bug it was supposed to trigger:
    1.23 +  //
    1.24 +  //   * 0x7fffffff must be the LHS, not RHS, of the addition in the loop, and
    1.25 +  //   * i must not be incremented using ++
    1.26 +  //
    1.27 +  // The first is required because JM LoopState doesn't treat *both* V + mul and
    1.28 +  // mul + V as not overflowing, when V is known to be int32_t -- only V + mul.
    1.29 +  // (JM pessimally assumes V's type might change before it's evaluated.  This
    1.30 +  // obviously can't happen if V is a constant, but JM's puny little mind
    1.31 +  // doesn't detect this possibility now.)
    1.32 +  //
    1.33 +  // The second is required because JM LoopState only ignores integer overflow
    1.34 +  // on multiplications if the enclosing loop is a "constrainedLoop" (the name
    1.35 +  // of the relevant field).  Loops become unconstrained when unhandled ops are
    1.36 +  // found in the loop.  Increment operators generate a DUP op, which is not
    1.37 +  // presently a handled op, causing the loop to become unconstrained.
    1.38 +  for (var i = 0; i < 15; i = i + 1) {
    1.39 +    var y = (0x7fffffff + ((i & 1) * -2147483648)) + 5;
    1.40 +  }
    1.41 +  return y;
    1.42 +}
    1.43 +assertEq(foo(), (0x7fffffff + ((14 & 1) * -2147483648)) + 5);
    1.44 +
    1.45 +function bar()
    1.46 +{
    1.47 +  // Variation on the theme of the above test with -1 as the other half of the
    1.48 +  // INT32_MIN multiplication, which *should* result in -INT32_MIN on multiply
    1.49 +  // (exceeding int32_t range).
    1.50 +  //
    1.51 +  // Here, range analysis again thinks the range of the multiplication is
    1.52 +  // INT32_MIN.  We'd overflow-check except that adding zero (on the LHS, see
    1.53 +  // above) prevents overflow checking, so range analysis thinks the range is
    1.54 +  // [INT32_MIN, INT32_MIN] when -INT32_MIN is actually possible.  This direct
    1.55 +  // result of the multiplication is already out of int32_t range, so no need to
    1.56 +  // add anything to bias it outside int32_t range to get a wrong result.
    1.57 +  for (var i = 0; i < 17; i = i + 1) {
    1.58 +    var y = (0 + ((-1 + (i & 1)) * -2147483648));
    1.59 +  }
    1.60 +  return y;
    1.61 +}
    1.62 +assertEq(bar(), (0 + ((-1 + (16 & 1)) * -2147483648)));

mercurial