Bug 883789 - Use baseline fallback stubs to track double-overflow of BinaryArith and UnaryArith ops. r=h4writer
authorKannan Vijayan <kvijayan@mozilla.com>
Wed, 19 Jun 2013 14:29:43 -0400
changeset 147147 6d4a482b6aa77194d489ea8f9b483696a2b587c4
parent 147146 61b6312cfab23a38dc75c4ce24570f9f9c881760
child 147148 4be8af5b96c7e3f65afab0c97489533e933d56e7
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs883789
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 883789 - Use baseline fallback stubs to track double-overflow of BinaryArith and UnaryArith ops. r=h4writer
js/src/ion/BaselineIC.cpp
js/src/ion/BaselineIC.h
js/src/ion/BaselineInspector.cpp
js/src/ion/BaselineInspector.h
js/src/ion/MIR.cpp
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -2463,16 +2463,19 @@ DoBinaryArithFallback(JSContext *cx, Bas
             return false;
         break;
       }
       default:
         JS_NOT_REACHED("Unhandled baseline arith op");
         return false;
     }
 
+    if (ret.isDouble())
+        stub->setSawDoubleResult();
+
     // Check to see if a new stub should be generated.
     if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
         // But for now we just bail.
         return true;
     }
 
     // Handle string concat.
@@ -2965,16 +2968,19 @@ DoUnaryArithFallback(JSContext *cx, Base
         if (!NegOperation(cx, script, pc, val, res))
             return false;
         break;
       default:
         JS_NOT_REACHED("Unexpected op");
         return false;
     }
 
+    if (res.isDouble())
+        stub->setSawDoubleResult();
+
     if (stub->numOptimizedStubs() >= ICUnaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard/replace stubs.
         return true;
     }
 
     if (val.isInt32() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32 => Int32) stub", js_CodeName[op]);
         ICUnaryArith_Int32::Compiler compiler(cx, op);
--- a/js/src/ion/BaselineIC.h
+++ b/js/src/ion/BaselineIC.h
@@ -2370,27 +2370,37 @@ class ICToNumber_Fallback : public ICFal
 //      JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR
 //      JSOP_LSH, JSOP_RSH, JSOP_URSH
 
 class ICBinaryArith_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     ICBinaryArith_Fallback(IonCode *stubCode)
-      : ICFallbackStub(BinaryArith_Fallback, stubCode) {}
+      : ICFallbackStub(BinaryArith_Fallback, stubCode)
+    {
+        extra_ = 0;
+    }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
     static inline ICBinaryArith_Fallback *New(ICStubSpace *space, IonCode *code) {
         if (!code)
             return NULL;
         return space->allocate<ICBinaryArith_Fallback>(code);
     }
 
+    bool sawDoubleResult() {
+        return extra_;
+    }
+    void setSawDoubleResult() {
+        extra_ = 1;
+    }
+
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::BinaryArith_Fallback) {}
@@ -2658,27 +2668,37 @@ class ICBinaryArith_DoubleWithInt32 : pu
 //     JSOP_BITNOT
 //     JSOP_NEG
 
 class ICUnaryArith_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     ICUnaryArith_Fallback(IonCode *stubCode)
-      : ICFallbackStub(UnaryArith_Fallback, stubCode) {}
+      : ICFallbackStub(UnaryArith_Fallback, stubCode)
+    {
+        extra_ = 0;
+    }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
     static inline ICUnaryArith_Fallback *New(ICStubSpace *space, IonCode *code) {
         if (!code)
             return NULL;
         return space->allocate<ICUnaryArith_Fallback>(code);
     }
 
+    bool sawDoubleResult() {
+        return extra_;
+    }
+    void setSawDoubleResult() {
+        extra_ = 1;
+    }
+
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::UnaryArith_Fallback)
--- a/js/src/ion/BaselineInspector.cpp
+++ b/js/src/ion/BaselineInspector.cpp
@@ -160,19 +160,19 @@ BaselineInspector::expectedResultType(js
 
     switch (stub->kind()) {
       case ICStub::BinaryArith_Int32:
         if (stub->toBinaryArith_Int32()->allowDouble())
             return MIRType_Double;
         return MIRType_Int32;
       case ICStub::BinaryArith_BooleanWithInt32:
       case ICStub::UnaryArith_Int32:
+      case ICStub::BinaryArith_DoubleWithInt32:
         return MIRType_Int32;
       case ICStub::BinaryArith_Double:
-      case ICStub::BinaryArith_DoubleWithInt32:
       case ICStub::UnaryArith_Double:
         return MIRType_Double;
       case ICStub::BinaryArith_StringConcat:
       case ICStub::BinaryArith_StringObjectConcat:
         return MIRType_String;
       default:
         return MIRType_None;
     }
@@ -306,8 +306,27 @@ BaselineInspector::hasSeenAccessedGetter
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     if (stub->isGetProp_Fallback())
         return stub->toGetProp_Fallback()->hasAccessedGetter();
     return false;
 }
+
+bool
+BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
+{
+    if (!hasBaselineScript())
+        return false;
+
+    const ICEntry &entry = icEntryFromPC(pc);
+    ICStub *stub = entry.fallbackStub();
+
+    JS_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback());
+
+    if (stub->isUnaryArith_Fallback())
+        return stub->toUnaryArith_Fallback()->sawDoubleResult();
+    else
+        return stub->toBinaryArith_Fallback()->sawDoubleResult();
+
+    return false;
+}
--- a/js/src/ion/BaselineInspector.h
+++ b/js/src/ion/BaselineInspector.h
@@ -103,16 +103,17 @@ class BaselineInspector
     }
 
     MIRType expectedResultType(jsbytecode *pc);
     MCompare::CompareType expectedCompareType(jsbytecode *pc);
     MIRType expectedBinaryArithSpecialization(jsbytecode *pc);
 
     bool hasSeenNonNativeGetElement(jsbytecode *pc);
     bool hasSeenAccessedGetter(jsbytecode *pc);
+    bool hasSeenDoubleResult(jsbytecode *pc);
 };
 
 } // namespace ion
 } // namespace js
 
 #endif // JS_ION
 
 #endif // jsion_baseline_inspector_h__
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -950,17 +950,17 @@ void
 MUrsh::infer(BaselineInspector *inspector, jsbytecode *pc)
 {
     if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object)) {
         specialization_ = MIRType_None;
         setResultType(MIRType_Value);
         return;
     }
 
-    if (inspector->expectedResultType(pc) == MIRType_Double) {
+    if (inspector->hasSeenDoubleResult(pc)) {
         specialization_ = MIRType_Double;
         setResultType(MIRType_Double);
         return;
     }
 
     specialization_ = MIRType_Int32;
     setResultType(MIRType_Int32);
 }
@@ -1304,17 +1304,17 @@ MBinaryArithInstruction::infer(BaselineI
     if (lhs == MIRType_Int32 && rhs == MIRType_Int32)
         setResultType(MIRType_Int32);
     else if (lhs == MIRType_Double || rhs == MIRType_Double)
         setResultType(MIRType_Double);
     else
         return inferFallback(inspector, pc);
 
     // If the operation has ever overflowed, use a double specialization.
-    if (inspector->expectedResultType(pc) == MIRType_Double)
+    if (inspector->hasSeenDoubleResult(pc))
         setResultType(MIRType_Double);
 
     // If the operation will always overflow on its constant operands, use a
     // double specialization so that it can be constant folded later.
     if ((isMul() || isDiv()) && lhs == MIRType_Int32 && rhs == MIRType_Int32) {
         bool typeChange = false;
         EvaluateConstantOperands(this, &typeChange);
         if (typeChange)