Fix overflow when subtracting -2^31 (bug 610652, r=dmandelin).
authorDavid Anderson <danderson@mozilla.com>
Fri, 12 Nov 2010 17:55:11 -0800
changeset 57809 95f3ef09d58ee2b8c146b4a7936cc2f430e1caf1
parent 57808 5b757ec177b164b3f7d1d77d3b9043fec81ffbc2
child 57810 fa18694814e761e875acdcd47a8e839f9325761e
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersdmandelin
bugs610652
milestone2.0b8pre
Fix overflow when subtracting -2^31 (bug 610652, r=dmandelin).
js/src/jit-test/tests/jaeger/bug610652.js
js/src/methodjit/FastArithmetic.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug610652.js
@@ -0,0 +1,5 @@
+function a1(a2) {
+    return 10 - a2;
+}
+a3 = a1(-2147483648);
+assertEq(a3, 2147483658);
--- a/js/src/methodjit/FastArithmetic.cpp
+++ b/js/src/methodjit/FastArithmetic.cpp
@@ -553,27 +553,31 @@ mjit::Compiler::jsop_binary_full(FrameEn
         /* We'll link this back up later, at the bottom of the op. */
         doublePathDone = stubcc.masm.jump();
     }
 
     /* Time to do the integer path. Figure out the immutable side. */
     int32 value = 0;
     JSOp origOp = op;
     MaybeRegisterID reg;
+    MaybeJump preOverflow;
     if (!regs.resultHasRhs) {
         if (!regs.rhsData.isSet())
             value = rhs->getValue().toInt32();
         else
             reg = regs.rhsData.reg();
     } else {
         if (!regs.lhsData.isSet())
             value = lhs->getValue().toInt32();
         else
             reg = regs.lhsData.reg();
         if (op == JSOP_SUB) {
+            // If the RHS is 0x80000000, the smallest negative value, neg does
+            // not work. Guard against this and treat it as an overflow.
+            preOverflow = masm.branch32(Assembler::Equal, regs.result, Imm32(0x80000000));
             masm.neg32(regs.result);
             op = JSOP_ADD;
         }
     }
 
     /* Okay - good to emit the integer fast-path. */
     MaybeJump overflow, negZeroDone;
     switch (op) {
@@ -653,16 +657,18 @@ mjit::Compiler::jsop_binary_full(FrameEn
     
     JS_ASSERT(overflow.isSet());
 
     /*
      * Integer overflow path. Separate from the first double path, since we
      * know never to try and convert back to integer.
      */
     MaybeJump overflowDone;
+    if (preOverflow.isSet())
+        stubcc.linkExitDirect(preOverflow.get(), stubcc.masm.label());
     stubcc.linkExitDirect(overflow.get(), stubcc.masm.label());
     {
         if (regs.lhsNeedsRemat) {
             Address address = masm.payloadOf(frame.addressForDataRemat(lhs));
             stubcc.masm.convertInt32ToDouble(address, fpLeft);
         } else if (!lhs->isConstant()) {
             stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), fpLeft);
         } else {