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