Support pre-SSE2 CPUs in JaegerMonkey (bug 696291, r=bhackett).
authorDavid Anderson <danderson@mozilla.com>
Fri, 13 Jan 2012 13:33:56 -0800
changeset 85996 095649e65552b1ab61c63d81539f8b295effda42
parent 85995 04890cad686c7ab392a27a7db897b18cbe269682
child 85997 5f522d3446578d5db2a2fc63bf32a2f43cdfc5f3
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs696291
milestone12.0a1
Support pre-SSE2 CPUs in JaegerMonkey (bug 696291, r=bhackett).
js/src/jscntxt.cpp
js/src/jsinfer.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastArithmetic.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameState.cpp
js/src/methodjit/PolyIC.cpp
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1673,23 +1673,17 @@ IsJITBrokenHere()
     return isBroken;
 }
 #endif
 
 void
 JSContext::updateJITEnabled()
 {
 #ifdef JS_METHODJIT
-    methodJitEnabled = (runOptions & JSOPTION_METHODJIT) &&
-                       !IsJITBrokenHere()
-# if defined JS_CPU_X86 || defined JS_CPU_X64
-                       && JSC::MacroAssemblerX86Common::getSSEState() >=
-                          JSC::MacroAssemblerX86Common::HasSSE2
-# endif
-                        ;
+    methodJitEnabled = (runOptions & JSOPTION_METHODJIT) && !IsJITBrokenHere();
 #endif
 }
 
 size_t
 JSContext::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
 {
     /*
      * There are other JSContext members that could be measured; the following
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -54,16 +54,19 @@
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jsiter.h"
 
 #include "frontend/TokenStream.h"
 #include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Retcon.h"
+#ifdef JS_METHODJIT
+# include "assembler/assembler/MacroAssembler.h"
+#endif
 
 #include "jsatominlines.h"
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 #include "vm/Stack-inl.h"
 
@@ -1956,18 +1959,23 @@ TypeSet::needsBarrier(JSContext *cx)
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
 void
 TypeCompartment::init(JSContext *cx)
 {
     PodZero(this);
 
-    if (cx && cx->getRunOptions() & JSOPTION_TYPE_INFERENCE)
-        inferenceEnabled = true;
+    if (cx && cx->getRunOptions() & JSOPTION_TYPE_INFERENCE) {
+#ifdef JS_METHODJIT
+        JSC::MacroAssembler masm;
+        if (masm.supportsFloatingPoint())
+#endif
+            inferenceEnabled = true;
+    }
 }
 
 TypeObject *
 TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
                                JSProtoKey key, JSObject *proto, bool unknown)
 {
     RootObject root(cx, &proto);
 
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -633,16 +633,17 @@ private:
     bool jsop_xname(PropertyName *name);
     void enterBlock(JSObject *obj);
     void leaveBlock();
     void emitEval(uint32_t argc);
     void jsop_arguments(RejoinState rejoin);
     bool jsop_tableswitch(jsbytecode *pc);
 
     /* Fast arithmetic. */
+    bool jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type, FrameEntry *lhs, FrameEntry *rhs);
     bool jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet);
     void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
                           JSValueType type, bool cannotOverflow, bool ignoreOverflow);
     void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub,
                                  JSValueType type);
     void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
                             JSValueType type);
     void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
--- a/js/src/methodjit/FastArithmetic.cpp
+++ b/js/src/methodjit/FastArithmetic.cpp
@@ -171,16 +171,31 @@ mjit::Compiler::maybeJumpIfNotDouble(Ass
         else
             mj.setJump(masm.testDouble(Assembler::NotEqual, frame.addressOf(fe)));
     } else if (fe->getKnownType() != JSVAL_TYPE_DOUBLE) {
         mj.setJump(masm.jump());
     }
 }
 
 bool
+mjit::Compiler::jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type,
+                                 FrameEntry *lhs, FrameEntry *rhs)
+{
+    bool isStringResult = (op == JSOP_ADD) &&
+                          (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING));
+    JS_ASSERT_IF(isStringResult && type != JSVAL_TYPE_UNKNOWN, type == JSVAL_TYPE_STRING);
+
+    prepareStubCall(Uses(2));
+    INLINE_STUBCALL(stub, REJOIN_BINARY);
+    frame.popn(2);
+    frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : type);
+    return true;
+}
+
+bool
 mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     Value v;
     if (tryBinaryConstantFold(cx, frame, op, lhs, rhs, &v)) {
         if (!v.isInt32() && typeSet && !typeSet->hasType(types::Type::DoubleType())) {
@@ -200,26 +215,17 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
     /*
      * Bail out if there are unhandled types or ops.
      * This is temporary while ops are still being implemented.
      */
     if ((lhs->isConstant() && rhs->isConstant()) ||
         (lhs->isTypeKnown() && (lhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)) ||
         (rhs->isTypeKnown() && (rhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)))
     {
-        bool isStringResult = (op == JSOP_ADD) &&
-                              (lhs->isType(JSVAL_TYPE_STRING) ||
-                               rhs->isType(JSVAL_TYPE_STRING));
-        JS_ASSERT_IF(isStringResult && type != JSVAL_TYPE_UNKNOWN, type == JSVAL_TYPE_STRING);
-
-        prepareStubCall(Uses(2));
-        INLINE_STUBCALL(stub, REJOIN_BINARY);
-        frame.popn(2);
-        frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : type);
-        return true;
+        return jsop_binary_slow(op, stub, type, lhs, rhs);
     }
 
     /*
      * If this is an operation on which integer overflows can be ignored, treat
      * the result as an integer even if it has been marked as overflowing by
      * the interpreter. Doing this changes the values we maintain on the stack
      * from those the interpreter would maintain; this is OK as values derived
      * from ignored overflows are not live across points where the interpreter
@@ -233,16 +239,19 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
         op == JSOP_ADD && ignoreOverflow) {
         type = JSVAL_TYPE_INT32;
     }
 
     /* Can do int math iff there is no double constant and the op is not division. */
     bool canDoIntMath = op != JSOP_DIV && type != JSVAL_TYPE_DOUBLE &&
                         !(rhs->isType(JSVAL_TYPE_DOUBLE) || lhs->isType(JSVAL_TYPE_DOUBLE));
 
+    if (!masm.supportsFloatingPoint() && (!canDoIntMath || frame.haveSameBacking(lhs, rhs)))
+        return jsop_binary_slow(op, stub, type, lhs, rhs);
+
     if (canDoIntMath)
         jsop_binary_full(lhs, rhs, op, stub, type, cannotOverflow, ignoreOverflow);
     else
         jsop_binary_double(lhs, rhs, op, stub, type);
 
     return true;
 }
 
@@ -567,17 +576,17 @@ mjit::Compiler::jsop_binary_full(FrameEn
         emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
 
     MaybeJump rhsNotNumber2;
     if (!rhs->isTypeKnown())
         emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2);
 
     /* Perform the double addition. */
     MaybeJump doublePathDone;
-    if (!rhs->isTypeKnown() || lhsUnknownDone.isSet()) {
+    if (masm.supportsFloatingPoint() && (!rhs->isTypeKnown() || !lhs->isTypeKnown())) {
         /* If the LHS type was not known, link its path here. */
         if (lhsUnknownDone.isSet())
             lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
         
         /* Perform the double operation. */
         EmitDoubleOp(op, regs.rhsFP, regs.lhsFP, stubcc.masm);
 
         /* Force the double back to memory. */
@@ -785,29 +794,32 @@ mjit::Compiler::jsop_binary_full(FrameEn
 }
 
 void
 mjit::Compiler::jsop_neg()
 {
     FrameEntry *fe = frame.peek(-1);
     JSValueType type = knownPushedType(0);
 
-    if (fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) {
+    if ((fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) ||
+        !masm.supportsFloatingPoint())
+    {
         prepareStubCall(Uses(1));
         INLINE_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
         frame.pop();
         frame.pushSynced(type);
         return;
     }
 
     JS_ASSERT(!fe->isConstant());
 
     /* Handle negation of a known double, or of a known integer which has previously overflowed. */
     if (fe->isType(JSVAL_TYPE_DOUBLE) ||
-        (fe->isType(JSVAL_TYPE_INT32) && type == JSVAL_TYPE_DOUBLE)) {
+        (fe->isType(JSVAL_TYPE_INT32) && type == JSVAL_TYPE_DOUBLE))
+    {
         FPRegisterID fpreg;
         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
             fpreg = frame.tempFPRegForData(fe);
         } else {
             fpreg = frame.allocFPReg();
             frame.convertInt32ToDouble(masm, fe, fpreg);
         }
 
@@ -1304,16 +1316,21 @@ void
 mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
                                    MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
                                    MaybeJump &lhsUnknownDone)
 {
     /* If the LHS is not a 32-bit integer, take OOL path. */
     Jump lhsNotInt32 = masm.testInt32(Assembler::NotEqual, regs.lhsType.reg());
     stubcc.linkExitDirect(lhsNotInt32, stubcc.masm.label());
 
+    if (!masm.supportsFloatingPoint()) {
+        lhsNotDouble = stubcc.masm.jump();
+        return;
+    }
+
     /* OOL path for LHS as a double - first test LHS is double. */
     lhsNotDouble = stubcc.masm.testDouble(Assembler::NotEqual, regs.lhsType.reg());
 
     /* Ensure the RHS is a number. */
     MaybeJump rhsIsDouble;
     if (!rhs->isTypeKnown()) {
         rhsIsDouble = stubcc.masm.testDouble(Assembler::Equal, regs.rhsType.reg());
         rhsNotNumber = stubcc.masm.testInt32(Assembler::NotEqual, regs.rhsType.reg());
@@ -1349,16 +1366,21 @@ mjit::Compiler::emitLeftDoublePath(Frame
 void
 mjit::Compiler::emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
                                     MaybeJump &rhsNotNumber2)
 {
     /* If the RHS is not a double, take OOL path. */
     Jump notInt32 = masm.testInt32(Assembler::NotEqual, regs.rhsType.reg());
     stubcc.linkExitDirect(notInt32, stubcc.masm.label());
 
+    if (!masm.supportsFloatingPoint()) {
+        rhsNotNumber2 = stubcc.masm.jump();
+        return;
+    }
+
     /* Now test if RHS is a double. */
     rhsNotNumber2 = stubcc.masm.testDouble(Assembler::NotEqual, regs.rhsType.reg());
 
     /* We know LHS is an integer. */
     if (lhs->isConstant())
         slowLoadConstantDouble(stubcc.masm, lhs, regs.lhsFP);
     else
         stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), regs.lhsFP);
@@ -1566,17 +1588,17 @@ mjit::Compiler::jsop_relational_full(JSO
         emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
 
     MaybeJump rhsNotNumber2;
     if (!rhs->isTypeKnown())
         emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2);
 
     /* Both double paths will join here. */
     bool hasDoublePath = false;
-    if (!rhs->isTypeKnown() || lhsUnknownDone.isSet())
+    if (masm.supportsFloatingPoint() && (!rhs->isTypeKnown() || !lhs->isTypeKnown()))
         hasDoublePath = true;
 
     /* Integer path - figure out the immutable side. */
     JSOp cmpOp = op;
     int32_t value = 0;
     RegisterID cmpReg;
     MaybeRegisterID reg;
     if (regs.lhsData.isSet()) {
@@ -1607,35 +1629,35 @@ mjit::Compiler::jsop_relational_full(JSO
         MaybeJump doubleTest, doubleFall;
         Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused);
         if (hasDoublePath) {
             if (lhsUnknownDone.isSet())
                 lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
             frame.sync(stubcc.masm, Uses(frame.frameSlots()));
             doubleTest = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
             doubleFall = stubcc.masm.jump();
-
-            /* Link all incoming slow paths to here. */
-            if (lhsNotDouble.isSet()) {
-                lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-                if (rhsNotNumber.isSet())
-                    rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-            }
-            if (rhsNotNumber2.isSet())
-                rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+        }
 
-            /*
-             * For fusions, spill the tracker state. xmm* remain intact. Note
-             * that frame.sync() must be used directly, to avoid syncExit()'s
-             * jumping logic.
-             */
-            frame.sync(stubcc.masm, Uses(frame.frameSlots()));
-            stubcc.leave();
-            OOL_STUBCALL(stub, REJOIN_BRANCH);
+        /* Link all incoming slow paths to here. */
+        if (lhsNotDouble.isSet()) {
+            lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+            if (rhsNotNumber.isSet())
+                rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
         }
+        if (rhsNotNumber2.isSet())
+            rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+
+        /*
+         * For fusions, spill the tracker state. xmm* remain intact. Note
+         * that frame.sync() must be used directly, to avoid syncExit()'s
+         * jumping logic.
+         */
+        frame.sync(stubcc.masm, Uses(frame.frameSlots()));
+        stubcc.leave();
+        OOL_STUBCALL(stub, REJOIN_BRANCH);
 
         /* Forget the world, preserving data. */
         frame.pinReg(cmpReg);
         if (reg.isSet())
             frame.pinReg(reg.reg());
         
         frame.popn(2);
 
@@ -1696,31 +1718,31 @@ mjit::Compiler::jsop_relational_full(JSO
             /* :FIXME: Use SET if we can? */
             Jump test = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
             stubcc.masm.move(Imm32(0), regs.result);
             Jump skip = stubcc.masm.jump();
             test.linkTo(stubcc.masm.label(), &stubcc.masm);
             stubcc.masm.move(Imm32(1), regs.result);
             skip.linkTo(stubcc.masm.label(), &stubcc.masm);
             doubleDone = stubcc.masm.jump();
+        }
 
-            /* Link all incoming slow paths to here. */
-            if (lhsNotDouble.isSet()) {
-                lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-                if (rhsNotNumber.isSet())
-                    rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-            }
-            if (rhsNotNumber2.isSet())
-                rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+        /* Link all incoming slow paths to here. */
+        if (lhsNotDouble.isSet()) {
+            lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+            if (rhsNotNumber.isSet())
+                rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+        }
+        if (rhsNotNumber2.isSet())
+            rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
 
-            /* Emit the slow path - note full frame syncage. */
-            frame.sync(stubcc.masm, Uses(2));
-            stubcc.leave();
-            OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
-        }
+        /* Emit the slow path - note full frame syncage. */
+        frame.sync(stubcc.masm, Uses(2));
+        stubcc.leave();
+        OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
 
         /* Get an integer comparison condition. */
         Assembler::Condition i32Cond = GetCompareCondition(cmpOp, fused);
 
         /* Emit the compare & set. */
         if (reg.isSet())
             masm.branchValue(i32Cond, cmpReg, reg.reg(), regs.result);
         else
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -96,38 +96,52 @@ mjit::Compiler::ensureInteger(FrameEntry
         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)) {
-        FPRegisterID fptemp = frame.allocFPReg();
-        RegisterID typeReg = frame.tempRegForType(fe);
-        frame.pinReg(typeReg);
-        RegisterID dataReg = frame.copyDataIntoReg(fe);
-        frame.unpinReg(typeReg);
-
-        Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
-
-        Label syncPath = stubcc.syncExitAndJump(uses);
-        stubcc.linkExitDirect(intGuard, stubcc.masm.label());
-
-        /* Try an OOL path to truncate doubles representing int32s. */
-        Jump doubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, typeReg);
-        doubleGuard.linkTo(syncPath, &stubcc.masm);
-
-        frame.loadDouble(fe, fptemp, stubcc.masm);
-        Jump truncateGuard = stubcc.masm.branchTruncateDoubleToInt32(fptemp, dataReg);
-        truncateGuard.linkTo(syncPath, &stubcc.masm);
-        stubcc.crossJump(stubcc.masm.jump(), masm.label());
-
-        frame.freeReg(fptemp);
-        frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+        if (masm.supportsFloatingPoint()) {
+            FPRegisterID fptemp = frame.allocFPReg();
+            RegisterID typeReg = frame.tempRegForType(fe);
+            frame.pinReg(typeReg);
+            RegisterID dataReg = frame.copyDataIntoReg(fe);
+            frame.unpinReg(typeReg);
+
+            Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
+
+            Label syncPath = stubcc.syncExitAndJump(uses);
+            stubcc.linkExitDirect(intGuard, stubcc.masm.label());
+
+            /* Try an OOL path to truncate doubles representing int32s. */
+            Jump doubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, typeReg);
+            doubleGuard.linkTo(syncPath, &stubcc.masm);
+
+            frame.loadDouble(fe, fptemp, stubcc.masm);
+            Jump truncateGuard = stubcc.masm.branchTruncateDoubleToInt32(fptemp, dataReg);
+            truncateGuard.linkTo(syncPath, &stubcc.masm);
+            stubcc.crossJump(stubcc.masm.jump(), masm.label());
+
+            frame.freeReg(fptemp);
+            frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+        } else {
+            RegisterID typeReg = frame.tempRegForType(fe);
+            frame.pinReg(typeReg);
+            RegisterID dataReg = frame.copyDataIntoReg(fe);
+            frame.unpinReg(typeReg);
+
+            Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
+
+            Label syncPath = stubcc.syncExitAndJump(uses);
+            stubcc.linkExitDirect(intGuard, syncPath);
+
+            frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+        }
     }
 }
 
 void
 mjit::Compiler::jsop_bitnot()
 {
     FrameEntry *top = frame.peek(-1);
 
@@ -557,16 +571,18 @@ mjit::Compiler::jsop_relational(JSOp op,
         }
     }
 
     if (frame.haveSameBacking(lhs, rhs)) {
         return emitStubCmpOp(stub, target, fused);
     } else if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) {
         return emitStubCmpOp(stub, target, fused);
     } else if (lhs->isType(JSVAL_TYPE_DOUBLE) || rhs->isType(JSVAL_TYPE_DOUBLE)) {
+        if (!masm.supportsFloatingPoint())
+            return emitStubCmpOp(stub, target, fused);
         return jsop_relational_double(op, stub, target, fused);
     } else if (cx->typeInferenceEnabled() &&
                lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32)) {
         return jsop_relational_int(op, target, fused);
     } else {
         return jsop_relational_full(op, stub, target, fused);
     }
 }
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -1525,20 +1525,22 @@ FrameState::merge(Assembler &masm, Chang
      */
 
     /*
      * For any changed values we are merging back which we consider to be doubles,
      * ensure they actually are doubles.  They must be doubles or ints, but we
      * do not require stub paths to always generate a double when needed.
      * :FIXME: we check this on OOL stub calls, but not inline stub calls.
      */
-    for (unsigned i = 0; i < changes.nchanges; i++) {
-        FrameEntry *fe = a->sp - 1 - i;
-        if (fe->isTracked() && fe->isType(JSVAL_TYPE_DOUBLE))
-            masm.ensureInMemoryDouble(addressOf(fe));
+    if (cx->typeInferenceEnabled()) {
+        for (unsigned i = 0; i < changes.nchanges; i++) {
+            FrameEntry *fe = a->sp - 1 - i;
+            if (fe->isTracked() && fe->isType(JSVAL_TYPE_DOUBLE))
+                masm.ensureInMemoryDouble(addressOf(fe));
+        }
     }
 
     uint32_t mask = Registers::AvailAnyRegs & ~freeRegs.freeMask;
     Registers search(mask);
 
     while (!search.empty(mask)) {
         AnyRegisterID reg = search.peekReg(mask);
         FrameEntry *fe = regstate(reg).usedBy();
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2532,16 +2532,24 @@ GetElementIC::attachTypedArray(VMFrame &
     // Load the array's packed data vector.
     masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
 
     Int32Key key = idRemat.isConstant()
                  ? Int32Key::FromConstant(v.toInt32())
                  : Int32Key::FromRegister(idRemat.dataReg());
 
     JSObject *tarray = js::TypedArray::getTypedArray(obj);
+    if (!masm.supportsFloatingPoint() &&
+        (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
+         TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64 ||
+         TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT32))
+    {
+        return disable(cx, "fpu not supported");
+    }
+
     MaybeRegisterID tempReg;
     masm.loadFromTypedArray(TypedArray::getType(tarray), objReg, key, typeReg, objReg, tempReg);
 
     Jump done = masm.jump();
 
     updatePCCounters(cx, masm);
 
     PICLinker buffer(masm, *this);
@@ -2824,16 +2832,23 @@ SetElementIC::attachTypedArray(VMFrame &
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(keyValue));
     else
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, keyReg);
 
     // Load the array's packed data vector.
     masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
 
     JSObject *tarray = js::TypedArray::getTypedArray(obj);
+    if (!masm.supportsFloatingPoint() &&
+        (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
+         TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64))
+    {
+        return disable(cx, "fpu not supported");
+    }
+
     int shift = js::TypedArray::slotWidth(obj);
     if (hasConstantKey) {
         Address addr(objReg, keyValue * shift);
         if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask))
             return error(cx);
     } else {
         Assembler::Scale scale = Assembler::TimesOne;
         switch (shift) {