[INFER] OOL path for truncating doubles slightly outside the int32 range, bug 643037.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 18 Mar 2011 16:42:00 -0700
changeset 74810 f1dff744b6c8f04c4f750a547209eac9c37da2b5
parent 74809 b48f1d51c6f59dee7a0540b654f17b1106ae25e6
child 74811 9ee17aa5f93892227d777ab9c37ce6aef59a81b6
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs643037
milestone2.0b13pre
[INFER] OOL path for truncating doubles slightly outside the int32 range, bug 643037.
js/src/jit-test/tests/basic/truncateDouble.js
js/src/jsinfer.cpp
js/src/methodjit/FastOps.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/truncateDouble.js
@@ -0,0 +1,10 @@
+
+// check correctness of truncation of doubles slightly outside the int32 range.
+
+function truncate(x) {
+  return x | 0;
+}
+
+assertEq(truncate(0xffffffff), -1);
+assertEq(truncate(0xffffffff + 5000.5), 4999);
+assertEq(truncate(-0xffffffff - 5000.5), -4999);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2526,16 +2526,20 @@ TypeObject::markUnknown(JSContext *cx)
 
 void
 TypeObject::print(JSContext *cx)
 {
     printf("%s : %s", name(), proto ? proto->getType()->name() : "(null)");
 
     if (unknownProperties)
         printf(" unknown");
+    else if (isPackedArray)
+        printf(" packed");
+    else if (isDenseArray)
+        printf(" dense");
 
     if (propertyCount == 0) {
         printf(" {}\n");
         return;
     }
 
     printf(" {");
 
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -123,21 +123,45 @@ mjit::Compiler::ensureInteger(FrameEntry
 {
     if (fe->isConstant()) {
         if (!fe->isType(JSVAL_TYPE_INT32)) {
             JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
             fe->convertConstantDoubleToInt32(cx);
         }
     } else if (fe->isType(JSVAL_TYPE_DOUBLE)) {
         FPRegisterID fpreg = frame.tempFPRegForData(fe);
-
+        FPRegisterID fptemp = frame.allocFPReg();
         RegisterID data = frame.allocReg();
         Jump truncateGuard = masm.branchTruncateDoubleToInt32(fpreg, data);
-        stubcc.linkExit(truncateGuard, uses);
+
+        Label syncPath = stubcc.syncExitAndJump(uses);
+        stubcc.linkExitDirect(truncateGuard, stubcc.masm.label());
+
+        /*
+         * Try an OOL path to convert doubles representing integers within 2^32
+         * of a signed integer, by adding/subtracting 2^32 and then trying to
+         * convert to int32. This has to be an exact conversion, as otherwise
+         * the truncation works incorrectly on the modified value.
+         */
 
+        stubcc.masm.zeroDouble(fptemp);
+        Jump positive = stubcc.masm.branchDouble(Assembler::DoubleGreaterThan, fpreg, fptemp);
+        stubcc.masm.slowLoadConstantDouble(double(4294967296.0), fptemp);
+        Jump skip = stubcc.masm.jump();
+        positive.linkTo(stubcc.masm.label(), &stubcc.masm);
+        stubcc.masm.slowLoadConstantDouble(double(-4294967296.0), fptemp);
+        skip.linkTo(stubcc.masm.label(), &stubcc.masm);
+
+        JumpList isDouble;
+        stubcc.masm.addDouble(fpreg, fptemp);
+        stubcc.masm.branchConvertDoubleToInt32(fptemp, data, isDouble, Registers::FPConversionTemp);
+        stubcc.crossJump(stubcc.masm.jump(), masm.label());
+        isDouble.linkTo(syncPath, &stubcc.masm);
+
+        frame.freeReg(fptemp);
         frame.learnType(fe, JSVAL_TYPE_INT32, data);
     } else if (!fe->isType(JSVAL_TYPE_INT32)) {
         RegisterID typeReg = frame.tempRegForType(fe);
         frame.pinReg(typeReg);
         RegisterID dataReg = frame.copyDataIntoReg(fe);
         frame.unpinReg(typeReg);
 
         Jump intGuard = masm.testInt32(Assembler::Equal, typeReg);