diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.cpp b/js/src/assembler/assembler/MacroAssemblerX86Common.cpp index 6b1a1bbcd146..b94a345ff649 100644 --- a/js/src/assembler/assembler/MacroAssemblerX86Common.cpp +++ b/js/src/assembler/assembler/MacroAssemblerX86Common.cpp @@ -14,5 +14,9 @@ using namespace JSC; MacroAssemblerX86Common::SSECheckState MacroAssemblerX86Common::s_sseCheckState = NotCheckedSSE; +#ifdef DEBUG +bool MacroAssemblerX86Common::s_floatingPointDisabled = false; +#endif + #endif /* WTF_CPU_X86 || WTF_CPU_X86_64 */ diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h index d1c2b08c2523..30bb1ed26afc 100644 --- a/js/src/assembler/assembler/MacroAssemblerX86Common.h +++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h @@ -1374,6 +1374,15 @@ private: ); #endif #endif + +#ifdef DEBUG + if (s_floatingPointDisabled) { + // Disable SSE2. + s_sseCheckState = HasSSE; + return; + } +#endif + static const int SSEFeatureBit = 1 << 25; static const int SSE2FeatureBit = 1 << 26; static const int SSE3FeatureBit = 1 << 0; @@ -1407,6 +1416,10 @@ private: static bool isSSE2Present() { +#ifdef DEBUG + if (s_floatingPointDisabled) + return false; +#endif return true; } @@ -1489,6 +1502,15 @@ private: return s_sseCheckState >= HasSSE4_2; } + +#ifdef DEBUG + static bool s_floatingPointDisabled; + + public: + static void SetFloatingPointDisabled() { + s_floatingPointDisabled = true; + } +#endif }; } // namespace JSC diff --git a/js/src/ion/BaselineIC.cpp b/js/src/ion/BaselineIC.cpp index 680550281d8a..77ad553d42f5 100644 --- a/js/src/ion/BaselineIC.cpp +++ b/js/src/ion/BaselineIC.cpp @@ -1662,6 +1662,9 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, return true; } + if (!cx->runtime->jitSupportsFloatingPoint && (lhs.isNumber() || rhs.isNumber())) + return true; + if (lhs.isNumber() && rhs.isNumber()) { IonSpew(IonSpew_BaselineIC, " Generating %s(Number, Number) stub", js_CodeName[op]); @@ -2070,7 +2073,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H return true; } - if (arg.isDouble()) { + if (arg.isDouble() && cx->runtime->jitSupportsFloatingPoint) { IonSpew(IonSpew_BaselineIC, " Generating ToBool(Double) stub."); ICToBool_Double::Compiler compiler(cx); ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script)); @@ -2456,6 +2459,9 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac JS_ASSERT(ret.isNumber()); if (lhs.isDouble() || rhs.isDouble() || ret.isDouble()) { + if (!cx->runtime->jitSupportsFloatingPoint) + return true; + switch (op) { case JSOP_ADD: case JSOP_SUB: @@ -2912,7 +2918,10 @@ DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback return true; } - if (val.isNumber() && res.isNumber() && op == JSOP_NEG) { + if (val.isNumber() && res.isNumber() && + op == JSOP_NEG && + cx->runtime->jitSupportsFloatingPoint) + { IonSpew(IonSpew_BaselineIC, " Generating %s(Number => Number) stub", js_CodeName[op]); // Unlink int32 stubs, the double stub handles both cases and TI specializes for both. stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32); @@ -3255,6 +3264,15 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, return true; } +static bool +TypedArrayRequiresFloatingPoint(JSObject *obj) +{ + uint32_t type = TypedArray::type(obj); + return (type == TypedArray::TYPE_UINT32 || + type == TypedArray::TYPE_FLOAT32 || + type == TypedArray::TYPE_FLOAT64); +} + static bool TryAttachGetElemStub(JSContext *cx, HandleScript script, ICGetElem_Fallback *stub, HandleValue lhs, HandleValue rhs, HandleValue res) @@ -3303,6 +3321,9 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, ICGetElem_Fallback *stu if (obj->isTypedArray() && rhs.isInt32() && res.isNumber() && !TypedArrayGetElemStubExists(stub, obj)) { + if (!cx->runtime->jitSupportsFloatingPoint && TypedArrayRequiresFloatingPoint(obj)) + return true; + IonSpew(IonSpew_BaselineIC, " Generating GetElem(TypedArray[Int32]) stub"); ICGetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(), TypedArray::type(obj)); ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script)); @@ -3828,6 +3849,9 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub, } if (obj->isTypedArray() && index.isInt32() && rhs.isNumber()) { + if (!cx->runtime->jitSupportsFloatingPoint && TypedArrayRequiresFloatingPoint(obj)) + return true; + uint32_t len = TypedArray::length(obj); int32_t idx = index.toInt32(); bool expectOutOfBounds = (idx < 0) || (static_cast(idx) >= len); @@ -3980,9 +4004,14 @@ ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm) masm.storeValue(R0, element); EmitReturnFromIC(masm); - // Convert to double and jump back. + // Convert to double and jump back. Note that double arrays are only + // created by IonMonkey, so if we have no floating-point support + // Ion is disabled and there should be no double arrays. masm.bind(&convertDoubles); - masm.convertInt32ValueToDouble(valueAddr, R0.scratchReg(), &convertDoublesDone); + if (cx->runtime->jitSupportsFloatingPoint) + masm.convertInt32ValueToDouble(valueAddr, R0.scratchReg(), &convertDoublesDone); + else + masm.breakpoint(); masm.jump(&convertDoublesDone); // Failure case - fail but first unstow R0 and R1 @@ -4143,9 +4172,14 @@ ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm) masm.storeValue(R0, element); EmitReturnFromIC(masm); - // Convert to double and jump back. + // Convert to double and jump back. Note that double arrays are only + // created by IonMonkey, so if we have no floating-point support + // Ion is disabled and there should be no double arrays. masm.bind(&convertDoubles); - masm.convertInt32ValueToDouble(valueAddr, R0.scratchReg(), &convertDoublesDone); + if (cx->runtime->jitSupportsFloatingPoint) + masm.convertInt32ValueToDouble(valueAddr, R0.scratchReg(), &convertDoublesDone); + else + masm.breakpoint(); masm.jump(&convertDoublesDone); // Failure case - fail but first unstow R0 and R1 @@ -4218,10 +4252,14 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm) // If the value is a double, clamp to uint8 and jump back. // Else, jump to failure. masm.bind(¬Int32); - masm.branchTestDouble(Assembler::NotEqual, value, &failure); - masm.unboxDouble(value, FloatReg0); - masm.clampDoubleToUint8(FloatReg0, secondScratch); - masm.jump(&clamped); + if (cx->runtime->jitSupportsFloatingPoint) { + masm.branchTestDouble(Assembler::NotEqual, value, &failure); + masm.unboxDouble(value, FloatReg0); + masm.clampDoubleToUint8(FloatReg0, secondScratch); + masm.jump(&clamped); + } else { + masm.jump(&failure); + } } else { Label notInt32; masm.branchTestInt32(Assembler::NotEqual, value, ¬Int32); @@ -4236,10 +4274,14 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm) // Else, jump to failure. Label failureRestoreRegs; masm.bind(¬Int32); - masm.branchTestDouble(Assembler::NotEqual, value, &failure); - masm.unboxDouble(value, FloatReg0); - masm.branchTruncateDouble(FloatReg0, secondScratch, &failureRestoreRegs); - masm.jump(&isInt32); + if (cx->runtime->jitSupportsFloatingPoint) { + masm.branchTestDouble(Assembler::NotEqual, value, &failure); + masm.unboxDouble(value, FloatReg0); + masm.branchTruncateDouble(FloatReg0, secondScratch, &failureRestoreRegs); + masm.jump(&isInt32); + } else { + masm.jump(&failure); + } // Writing to secondScratch may have clobbered R0 or R1, restore them // first. @@ -6511,6 +6553,18 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler &masm) return true; } +static JSBool +DoubleValueToInt32ForSwitch(Value *v) +{ + double d = v->toDouble(); + int32_t truncated = int32_t(d); + if (d != double(truncated)) + return false; + + v->setInt32(truncated); + return true; +} + bool ICTableSwitch::Compiler::generateStubCode(MacroAssembler &masm) { @@ -6537,10 +6591,27 @@ ICTableSwitch::Compiler::generateStubCode(MacroAssembler &masm) masm.bind(¬Int32); masm.branchTestDouble(Assembler::NotEqual, R0, &outOfRange); - masm.unboxDouble(R0, FloatReg0); + if (cx->runtime->jitSupportsFloatingPoint) { + masm.unboxDouble(R0, FloatReg0); - // N.B. -0 === 0, so convert -0 to a 0 int32. - masm.convertDoubleToInt32(FloatReg0, key, &outOfRange, /* negativeZeroCheck = */ false); + // N.B. -0 === 0, so convert -0 to a 0 int32. + masm.convertDoubleToInt32(FloatReg0, key, &outOfRange, /* negativeZeroCheck = */ false); + } else { + // Pass pointer to double value. + masm.pushValue(R0); + masm.movePtr(StackPointer, R0.scratchReg()); + + masm.setupUnalignedABICall(1, scratch); + masm.passABIArg(R0.scratchReg()); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, DoubleValueToInt32ForSwitch)); + + // If the function returns |true|, the value has been converted to + // int32. + masm.mov(ReturnReg, scratch); + masm.popValue(R0); + masm.branchTest32(Assembler::Zero, scratch, scratch, &outOfRange); + masm.unboxInt32(R0, key); + } masm.jump(&isInt32); masm.bind(&outOfRange); diff --git a/js/src/ion/BaselineJIT.h b/js/src/ion/BaselineJIT.h index 435d72d749a6..2c9e914c5042 100644 --- a/js/src/ion/BaselineJIT.h +++ b/js/src/ion/BaselineJIT.h @@ -249,7 +249,8 @@ struct BaselineScript } }; -inline bool IsBaselineEnabled(JSContext *cx) +inline bool +IsBaselineEnabled(JSContext *cx) { return cx->hasOption(JSOPTION_BASELINE); } diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp index f34c93408410..aa98642c6836 100644 --- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -198,23 +198,30 @@ IonRuntime::initialize(JSContext *cx) if (!functionWrappers_ || !functionWrappers_->init()) return false; - if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId())) - return false; + if (cx->runtime->jitSupportsFloatingPoint) { + // Initialize some Ion-only stubs that require floating-point support. + if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId())) + return false; - for (uint32_t id = 0;; id++) { - FrameSizeClass class_ = FrameSizeClass::FromClass(id); - if (class_ == FrameSizeClass::ClassLimit()) - break; - bailoutTables_.infallibleAppend((IonCode *)NULL); - bailoutTables_[id] = generateBailoutTable(cx, id); - if (!bailoutTables_[id]) + for (uint32_t id = 0;; id++) { + FrameSizeClass class_ = FrameSizeClass::FromClass(id); + if (class_ == FrameSizeClass::ClassLimit()) + break; + bailoutTables_.infallibleAppend((IonCode *)NULL); + bailoutTables_[id] = generateBailoutTable(cx, id); + if (!bailoutTables_[id]) + return false; + } + + bailoutHandler_ = generateBailoutHandler(cx); + if (!bailoutHandler_) + return false; + + invalidator_ = generateInvalidator(cx); + if (!invalidator_) return false; } - bailoutHandler_ = generateBailoutHandler(cx); - if (!bailoutHandler_) - return false; - argumentsRectifier_ = generateArgumentsRectifier(cx, SequentialExecution, &argumentsRectifierReturnAddr_); if (!argumentsRectifier_) return false; @@ -225,10 +232,6 @@ IonRuntime::initialize(JSContext *cx) return false; #endif - invalidator_ = generateInvalidator(cx); - if (!invalidator_) - return false; - enterJIT_ = generateEnterJIT(cx, EnterJitOptimized); if (!enterJIT_) return false; diff --git a/js/src/ion/shared/Assembler-x86-shared.h b/js/src/ion/shared/Assembler-x86-shared.h index 1fff30bd405b..41cb8e0bc5da 100644 --- a/js/src/ion/shared/Assembler-x86-shared.h +++ b/js/src/ion/shared/Assembler-x86-shared.h @@ -278,9 +278,11 @@ class AssemblerX86Shared } void movsd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.movsd_rr(src.code(), dest.code()); } void movsd(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::FPREG: masm.movsd_rr(src.fpu(), dest.code()); @@ -296,6 +298,7 @@ class AssemblerX86Shared } } void movsd(const FloatRegister &src, const Operand &dest) { + JS_ASSERT(HasSSE2()); switch (dest.kind()) { case Operand::FPREG: masm.movsd_rr(src.code(), dest.fpu()); @@ -311,6 +314,7 @@ class AssemblerX86Shared } } void movss(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::REG_DISP: masm.movss_mr(src.disp(), src.base(), dest.code()); @@ -323,6 +327,7 @@ class AssemblerX86Shared } } void movss(const FloatRegister &src, const Operand &dest) { + JS_ASSERT(HasSSE2()); switch (dest.kind()) { case Operand::REG_DISP: masm.movss_rm(src.code(), dest.disp(), dest.base()); @@ -335,6 +340,7 @@ class AssemblerX86Shared } } void movdqa(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::REG_DISP: masm.movdqa_mr(src.disp(), src.base(), dest.code()); @@ -347,6 +353,7 @@ class AssemblerX86Shared } } void movdqa(const FloatRegister &src, const Operand &dest) { + JS_ASSERT(HasSSE2()); switch (dest.kind()) { case Operand::REG_DISP: masm.movdqa_rm(src.code(), dest.disp(), dest.base()); @@ -359,9 +366,11 @@ class AssemblerX86Shared } } void cvtss2sd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.cvtss2sd_rr(src.code(), dest.code()); } void cvtsd2ss(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.cvtsd2ss_rr(src.code(), dest.code()); } void movzbl(const Operand &src, const Register &dest) { @@ -655,6 +664,9 @@ class AssemblerX86Shared masm.int3(); } + static bool HasSSE2() { + return JSC::MacroAssembler::getSSEState() >= JSC::MacroAssembler::HasSSE2; + } static bool HasSSE41() { return JSC::MacroAssembler::getSSEState() >= JSC::MacroAssembler::HasSSE4_1; } @@ -1052,12 +1064,15 @@ class AssemblerX86Shared } void unpcklps(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.unpcklps_rr(src.code(), dest.code()); } void pinsrd(const Register &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.pinsrd_rr(src.code(), dest.code()); } void pinsrd(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::REG: masm.pinsrd_rr(src.reg(), dest.code()); @@ -1070,16 +1085,20 @@ class AssemblerX86Shared } } void psrldq(Imm32 shift, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.psrldq_rr(dest.code(), shift.value); } void psllq(Imm32 shift, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.psllq_rr(dest.code(), shift.value); } void psrlq(Imm32 shift, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.psrlq_rr(dest.code(), shift.value); } void cvtsi2sd(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::REG: masm.cvtsi2sd_rr(src.reg(), dest.code()); @@ -1095,12 +1114,15 @@ class AssemblerX86Shared } } void cvttsd2si(const FloatRegister &src, const Register &dest) { + JS_ASSERT(HasSSE2()); masm.cvttsd2si_rr(src.code(), dest.code()); } void cvtsi2sd(const Register &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.cvtsi2sd_rr(src.code(), dest.code()); } void movmskpd(const FloatRegister &src, const Register &dest) { + JS_ASSERT(HasSSE2()); masm.movmskpd_rr(src.code(), dest.code()); } void ptest(const FloatRegister &lhs, const FloatRegister &rhs) { @@ -1108,21 +1130,27 @@ class AssemblerX86Shared masm.ptest_rr(rhs.code(), lhs.code()); } void ucomisd(const FloatRegister &lhs, const FloatRegister &rhs) { + JS_ASSERT(HasSSE2()); masm.ucomisd_rr(rhs.code(), lhs.code()); } void pcmpeqw(const FloatRegister &lhs, const FloatRegister &rhs) { + JS_ASSERT(HasSSE2()); masm.pcmpeqw_rr(rhs.code(), lhs.code()); } void movd(const Register &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.movd_rr(src.code(), dest.code()); } void movd(const FloatRegister &src, const Register &dest) { + JS_ASSERT(HasSSE2()); masm.movd_rr(src.code(), dest.code()); } void addsd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.addsd_rr(src.code(), dest.code()); } void addsd(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::FPREG: masm.addsd_rr(src.fpu(), dest.code()); @@ -1140,9 +1168,11 @@ class AssemblerX86Shared } } void subsd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.subsd_rr(src.code(), dest.code()); } void subsd(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::FPREG: masm.subsd_rr(src.fpu(), dest.code()); @@ -1155,9 +1185,11 @@ class AssemblerX86Shared } } void mulsd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.mulsd_rr(src.code(), dest.code()); } void mulsd(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::FPREG: masm.mulsd_rr(src.fpu(), dest.code()); @@ -1170,9 +1202,11 @@ class AssemblerX86Shared } } void divsd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.divsd_rr(src.code(), dest.code()); } void divsd(const Operand &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::FPREG: masm.divsd_rr(src.fpu(), dest.code()); @@ -1185,20 +1219,25 @@ class AssemblerX86Shared } } void xorpd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.xorpd_rr(src.code(), dest.code()); } void orpd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.orpd_rr(src.code(), dest.code()); } void andpd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.andpd_rr(src.code(), dest.code()); } void sqrtsd(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.sqrtsd_rr(src.code(), dest.code()); } void roundsd(const FloatRegister &src, const FloatRegister &dest, JSC::X86Assembler::RoundingMode mode) { + JS_ASSERT(HasSSE41()); masm.roundsd_rr(src.code(), dest.code(), mode); } void fstp(const Operand &src) { diff --git a/js/src/ion/x86/Assembler-x86.h b/js/src/ion/x86/Assembler-x86.h index 7b8200caa66c..22a9a2a9b224 100644 --- a/js/src/ion/x86/Assembler-x86.h +++ b/js/src/ion/x86/Assembler-x86.h @@ -432,6 +432,7 @@ class Assembler : public AssemblerX86Shared } void movsd(const double *dp, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); masm.movsd_mr((const void *)dp, dest.code()); } @@ -448,6 +449,7 @@ class Assembler : public AssemblerX86Shared return masm.currentOffset(); } CodeOffsetLabel movsdWithPatch(void *addr, FloatRegister dest) { + JS_ASSERT(HasSSE2()); masm.movsd_mr(addr, dest.code()); return masm.currentOffset(); } @@ -458,6 +460,7 @@ class Assembler : public AssemblerX86Shared return masm.currentOffset(); } CodeOffsetLabel movsdWithPatch(FloatRegister dest, void *addr) { + JS_ASSERT(HasSSE2()); masm.movsd_rm(dest.code(), addr); return masm.currentOffset(); } @@ -484,10 +487,12 @@ class Assembler : public AssemblerX86Shared return masm.currentOffset(); } CodeOffsetLabel movssWithPatch(Address src, FloatRegister dest) { + JS_ASSERT(HasSSE2()); masm.movss_mr_disp32(src.offset, src.base.code(), dest.code()); return masm.currentOffset(); } CodeOffsetLabel movsdWithPatch(Address src, FloatRegister dest) { + JS_ASSERT(HasSSE2()); masm.movsd_mr_disp32(src.offset, src.base.code(), dest.code()); return masm.currentOffset(); } @@ -506,10 +511,12 @@ class Assembler : public AssemblerX86Shared return masm.currentOffset(); } CodeOffsetLabel movssWithPatch(FloatRegister src, Address dest) { + JS_ASSERT(HasSSE2()); masm.movss_rm_disp32(src.code(), dest.offset, dest.base.code()); return masm.currentOffset(); } CodeOffsetLabel movsdWithPatch(FloatRegister src, Address dest) { + JS_ASSERT(HasSSE2()); masm.movsd_rm_disp32(src.code(), dest.offset, dest.base.code()); return masm.currentOffset(); } diff --git a/js/src/ion/x86/Trampoline-x86.cpp b/js/src/ion/x86/Trampoline-x86.cpp index b813fa4162ad..7da46e0834b2 100644 --- a/js/src/ion/x86/Trampoline-x86.cpp +++ b/js/src/ion/x86/Trampoline-x86.cpp @@ -665,8 +665,14 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type) { MacroAssembler masm; - RegisterSet save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask), - FloatRegisterSet(FloatRegisters::VolatileMask)); + RegisterSet save; + if (cx->runtime->jitSupportsFloatingPoint) { + save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask), + FloatRegisterSet(FloatRegisters::VolatileMask)); + } else { + save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask), + FloatRegisterSet()); + } masm.PushRegsInMask(save); JS_ASSERT(PreBarrierReg == edx); diff --git a/js/src/jit-test/jit_test.py b/js/src/jit-test/jit_test.py index 0f4bdc855966..348c80cb672c 100755 --- a/js/src/jit-test/jit_test.py +++ b/js/src/jit-test/jit_test.py @@ -147,7 +147,7 @@ def main(argv): ['--no-baseline'], ['--no-baseline', '--ion-eager'], ['--baseline-eager'], - ['--baseline-eager', '--no-ti'], + ['--baseline-eager', '--no-ti', '--no-fpu'], # Below, equivalents the old shell flags: ,m,am,amd,n,mn,amn,amdn,mdn ['--no-baseline', '--no-ion', '--no-jm', '--no-ti'], ['--no-baseline', '--no-ion', '--no-ti'], diff --git a/js/src/jit-test/tests/asm.js/testCall.js b/js/src/jit-test/tests/asm.js/testCall.js index a8b7524e1832..8913c574d715 100644 --- a/js/src/jit-test/tests/asm.js/testCall.js +++ b/js/src/jit-test/tests/asm.js/testCall.js @@ -46,4 +46,4 @@ var rec = asmLink(asmCompile(USE_ASM+"function rec(i) { i=i|0; if (!i) return 0; assertEq(rec(100), 100); assertEq(rec(1000), 1000); assertThrowsInstanceOf(function() rec(100000000000), InternalError); -assertEq(rec(10000), 10000); +assertEq(rec(2000), 2000); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 3b343061ee63..3180e7f3e55e 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -686,6 +686,24 @@ JS_FRIEND_API(bool) JS::isGCEnabled() { return true; } static const JSSecurityCallbacks NullSecurityCallbacks = { }; +static bool +JitSupportsFloatingPoint() +{ +#if defined(JS_METHODJIT) || defined(JS_ION) + if (!JSC::MacroAssembler().supportsFloatingPoint()) + return false; + +#if defined(JS_ION) && WTF_ARM_ARCH_VERSION == 6 + if (!js::ion::hasVFP()) + return false; +#endif + + return true; +#else + return false; +#endif +} + PerThreadData::PerThreadData(JSRuntime *runtime) : PerThreadDataFriendFields(), runtime_(runtime), @@ -893,6 +911,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) noGCOrAllocationCheck(0), #endif jitHardening(false), + jitSupportsFloatingPoint(false), ionPcScriptCache(NULL), threadPool(this), ctypesActivityCallback(NULL), @@ -990,6 +1009,8 @@ JSRuntime::init(uint32_t maxbytes) return false; nativeStackBase = GetNativeStackBase(); + + jitSupportsFloatingPoint = JitSupportsFloatingPoint(); return true; } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 3294cb3d1777..b3b0fad13626 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1304,6 +1304,8 @@ struct JSRuntime : private JS::shadow::Runtime, bool jitHardening; + bool jitSupportsFloatingPoint; + // Used to reset stack limit after a signaled interrupt (i.e. ionStackLimit_ = -1) // has been noticed by Ion/Baseline. void resetIonStackLimit() { diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 3ac2212c0c51..663f400035c3 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -2382,31 +2382,6 @@ class TypeConstraintFreezeStack : public TypeConstraint // TypeCompartment ///////////////////////////////////////////////////////////////////// -static inline bool -TypeInferenceSupported() -{ -#ifdef JS_METHODJIT - // JM+TI will generate FPU instructions with TI enabled. As a workaround, - // we disable TI to prevent this on platforms which do not have FPU - // support. - JSC::MacroAssembler masm; - if (!masm.supportsFloatingPoint()) - return false; -#endif - -#if WTF_ARM_ARCH_VERSION == 6 -#ifdef JS_ION - return js::ion::hasVFP(); -#else - // If building for ARMv6 targets, we can't be guaranteed an FPU, - // so we hardcode TI off for consistency (see bug 793740). - return false; -#endif -#endif - - return true; -} - TypeCompartment::TypeCompartment() { PodZero(this); @@ -2418,7 +2393,7 @@ TypeZone::init(JSContext *cx) { if (!cx || !cx->hasOption(JSOPTION_TYPE_INFERENCE) || - !TypeInferenceSupported()) + !cx->runtime->jitSupportsFloatingPoint) { return; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 013033e2f7f9..7c4e8286e8f2 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -5295,6 +5295,8 @@ main(int argc, char **argv, char **envp) || !op.addIntOption('\0', "baseline-uses-before-compile", "COUNT", "Wait for COUNT calls or iterations before baseline-compiling " "(default: 10)", -1) + || !op.addBoolOption('\0', "no-fpu", "Pretend CPU does not support floating-point operations " + "to test JIT codegen (no-op on platforms other than x86).") #ifdef JSGC_GENERATIONAL || !op.addBoolOption('\0', "ggc", "Enable Generational GC") #endif @@ -5329,6 +5331,11 @@ main(int argc, char **argv, char **envp) OOM_maxAllocations = op.getIntOption('A'); if (op.getBoolOption('O')) OOM_printAllocationCount = true; + +#if defined(JS_CPU_X86) + if (op.getBoolOption("no-fpu")) + JSC::MacroAssembler::SetFloatingPointDisabled(); +#endif #endif /* Use the same parameters as the browser in xpcjsruntime.cpp. */