Support pre-SSE2 CPUs in JaegerMonkey (bug 696291, r=bhackett).
authorDavid Anderson <danderson@mozilla.com>
Fri, 13 Jan 2012 13:33:56 -0800
changeset 84771 095649e65552b1ab61c63d81539f8b295effda42
parent 84770 04890cad686c7ab392a27a7db897b18cbe269682
child 84772 5f522d3446578d5db2a2fc63bf32a2f43cdfc5f3
push id21873
push usermlamouri@mozilla.com
push dateWed, 18 Jan 2012 10:29:07 +0000
treeherdermozilla-central@7538f4d4697c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs696291
milestone12.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
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) {