Bug 858022 - Fix baseline compiler crashes on hardware without SSE2. r=dvander

This commit is contained in:
Jan de Mooij 2013-04-10 14:33:57 +02:00
parent 210f563736
commit 03dc58891f
14 changed files with 223 additions and 65 deletions

View File

@ -14,5 +14,9 @@
using namespace JSC; using namespace JSC;
MacroAssemblerX86Common::SSECheckState MacroAssemblerX86Common::s_sseCheckState = NotCheckedSSE; MacroAssemblerX86Common::SSECheckState MacroAssemblerX86Common::s_sseCheckState = NotCheckedSSE;
#ifdef DEBUG
bool MacroAssemblerX86Common::s_floatingPointDisabled = false;
#endif
#endif /* WTF_CPU_X86 || WTF_CPU_X86_64 */ #endif /* WTF_CPU_X86 || WTF_CPU_X86_64 */

View File

@ -1374,6 +1374,15 @@ private:
); );
#endif #endif
#endif #endif
#ifdef DEBUG
if (s_floatingPointDisabled) {
// Disable SSE2.
s_sseCheckState = HasSSE;
return;
}
#endif
static const int SSEFeatureBit = 1 << 25; static const int SSEFeatureBit = 1 << 25;
static const int SSE2FeatureBit = 1 << 26; static const int SSE2FeatureBit = 1 << 26;
static const int SSE3FeatureBit = 1 << 0; static const int SSE3FeatureBit = 1 << 0;
@ -1407,6 +1416,10 @@ private:
static bool isSSE2Present() static bool isSSE2Present()
{ {
#ifdef DEBUG
if (s_floatingPointDisabled)
return false;
#endif
return true; return true;
} }
@ -1489,6 +1502,15 @@ private:
return s_sseCheckState >= HasSSE4_2; return s_sseCheckState >= HasSSE4_2;
} }
#ifdef DEBUG
static bool s_floatingPointDisabled;
public:
static void SetFloatingPointDisabled() {
s_floatingPointDisabled = true;
}
#endif
}; };
} // namespace JSC } // namespace JSC

View File

@ -1662,6 +1662,9 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
return true; return true;
} }
if (!cx->runtime->jitSupportsFloatingPoint && (lhs.isNumber() || rhs.isNumber()))
return true;
if (lhs.isNumber() && rhs.isNumber()) { if (lhs.isNumber() && rhs.isNumber()) {
IonSpew(IonSpew_BaselineIC, " Generating %s(Number, Number) stub", js_CodeName[op]); 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; return true;
} }
if (arg.isDouble()) { if (arg.isDouble() && cx->runtime->jitSupportsFloatingPoint) {
IonSpew(IonSpew_BaselineIC, " Generating ToBool(Double) stub."); IonSpew(IonSpew_BaselineIC, " Generating ToBool(Double) stub.");
ICToBool_Double::Compiler compiler(cx); ICToBool_Double::Compiler compiler(cx);
ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script)); ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
@ -2456,6 +2459,9 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
JS_ASSERT(ret.isNumber()); JS_ASSERT(ret.isNumber());
if (lhs.isDouble() || rhs.isDouble() || ret.isDouble()) { if (lhs.isDouble() || rhs.isDouble() || ret.isDouble()) {
if (!cx->runtime->jitSupportsFloatingPoint)
return true;
switch (op) { switch (op) {
case JSOP_ADD: case JSOP_ADD:
case JSOP_SUB: case JSOP_SUB:
@ -2912,7 +2918,10 @@ DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback
return true; 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]); 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. // Unlink int32 stubs, the double stub handles both cases and TI specializes for both.
stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32); stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32);
@ -3255,6 +3264,15 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script,
return true; 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 static bool
TryAttachGetElemStub(JSContext *cx, HandleScript script, ICGetElem_Fallback *stub, TryAttachGetElemStub(JSContext *cx, HandleScript script, ICGetElem_Fallback *stub,
HandleValue lhs, HandleValue rhs, HandleValue res) 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() && if (obj->isTypedArray() && rhs.isInt32() && res.isNumber() &&
!TypedArrayGetElemStubExists(stub, obj)) !TypedArrayGetElemStubExists(stub, obj))
{ {
if (!cx->runtime->jitSupportsFloatingPoint && TypedArrayRequiresFloatingPoint(obj))
return true;
IonSpew(IonSpew_BaselineIC, " Generating GetElem(TypedArray[Int32]) stub"); IonSpew(IonSpew_BaselineIC, " Generating GetElem(TypedArray[Int32]) stub");
ICGetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(), TypedArray::type(obj)); ICGetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(), TypedArray::type(obj));
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script)); 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 (obj->isTypedArray() && index.isInt32() && rhs.isNumber()) {
if (!cx->runtime->jitSupportsFloatingPoint && TypedArrayRequiresFloatingPoint(obj))
return true;
uint32_t len = TypedArray::length(obj); uint32_t len = TypedArray::length(obj);
int32_t idx = index.toInt32(); int32_t idx = index.toInt32();
bool expectOutOfBounds = (idx < 0) || (static_cast<uint32_t>(idx) >= len); bool expectOutOfBounds = (idx < 0) || (static_cast<uint32_t>(idx) >= len);
@ -3980,9 +4004,14 @@ ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
masm.storeValue(R0, element); masm.storeValue(R0, element);
EmitReturnFromIC(masm); 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.bind(&convertDoubles);
if (cx->runtime->jitSupportsFloatingPoint)
masm.convertInt32ValueToDouble(valueAddr, R0.scratchReg(), &convertDoublesDone); masm.convertInt32ValueToDouble(valueAddr, R0.scratchReg(), &convertDoublesDone);
else
masm.breakpoint();
masm.jump(&convertDoublesDone); masm.jump(&convertDoublesDone);
// Failure case - fail but first unstow R0 and R1 // Failure case - fail but first unstow R0 and R1
@ -4143,9 +4172,14 @@ ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
masm.storeValue(R0, element); masm.storeValue(R0, element);
EmitReturnFromIC(masm); 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.bind(&convertDoubles);
if (cx->runtime->jitSupportsFloatingPoint)
masm.convertInt32ValueToDouble(valueAddr, R0.scratchReg(), &convertDoublesDone); masm.convertInt32ValueToDouble(valueAddr, R0.scratchReg(), &convertDoublesDone);
else
masm.breakpoint();
masm.jump(&convertDoublesDone); masm.jump(&convertDoublesDone);
// Failure case - fail but first unstow R0 and R1 // 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. // If the value is a double, clamp to uint8 and jump back.
// Else, jump to failure. // Else, jump to failure.
masm.bind(&notInt32); masm.bind(&notInt32);
if (cx->runtime->jitSupportsFloatingPoint) {
masm.branchTestDouble(Assembler::NotEqual, value, &failure); masm.branchTestDouble(Assembler::NotEqual, value, &failure);
masm.unboxDouble(value, FloatReg0); masm.unboxDouble(value, FloatReg0);
masm.clampDoubleToUint8(FloatReg0, secondScratch); masm.clampDoubleToUint8(FloatReg0, secondScratch);
masm.jump(&clamped); masm.jump(&clamped);
} else {
masm.jump(&failure);
}
} else { } else {
Label notInt32; Label notInt32;
masm.branchTestInt32(Assembler::NotEqual, value, &notInt32); masm.branchTestInt32(Assembler::NotEqual, value, &notInt32);
@ -4236,10 +4274,14 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
// Else, jump to failure. // Else, jump to failure.
Label failureRestoreRegs; Label failureRestoreRegs;
masm.bind(&notInt32); masm.bind(&notInt32);
if (cx->runtime->jitSupportsFloatingPoint) {
masm.branchTestDouble(Assembler::NotEqual, value, &failure); masm.branchTestDouble(Assembler::NotEqual, value, &failure);
masm.unboxDouble(value, FloatReg0); masm.unboxDouble(value, FloatReg0);
masm.branchTruncateDouble(FloatReg0, secondScratch, &failureRestoreRegs); masm.branchTruncateDouble(FloatReg0, secondScratch, &failureRestoreRegs);
masm.jump(&isInt32); masm.jump(&isInt32);
} else {
masm.jump(&failure);
}
// Writing to secondScratch may have clobbered R0 or R1, restore them // Writing to secondScratch may have clobbered R0 or R1, restore them
// first. // first.
@ -6511,6 +6553,18 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler &masm)
return true; 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 bool
ICTableSwitch::Compiler::generateStubCode(MacroAssembler &masm) ICTableSwitch::Compiler::generateStubCode(MacroAssembler &masm)
{ {
@ -6537,10 +6591,27 @@ ICTableSwitch::Compiler::generateStubCode(MacroAssembler &masm)
masm.bind(&notInt32); masm.bind(&notInt32);
masm.branchTestDouble(Assembler::NotEqual, R0, &outOfRange); masm.branchTestDouble(Assembler::NotEqual, R0, &outOfRange);
if (cx->runtime->jitSupportsFloatingPoint) {
masm.unboxDouble(R0, FloatReg0); masm.unboxDouble(R0, FloatReg0);
// N.B. -0 === 0, so convert -0 to a 0 int32. // N.B. -0 === 0, so convert -0 to a 0 int32.
masm.convertDoubleToInt32(FloatReg0, key, &outOfRange, /* negativeZeroCheck = */ false); 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.jump(&isInt32);
masm.bind(&outOfRange); masm.bind(&outOfRange);

View File

@ -249,7 +249,8 @@ struct BaselineScript
} }
}; };
inline bool IsBaselineEnabled(JSContext *cx) inline bool
IsBaselineEnabled(JSContext *cx)
{ {
return cx->hasOption(JSOPTION_BASELINE); return cx->hasOption(JSOPTION_BASELINE);
} }

View File

@ -198,6 +198,8 @@ IonRuntime::initialize(JSContext *cx)
if (!functionWrappers_ || !functionWrappers_->init()) if (!functionWrappers_ || !functionWrappers_->init())
return false; return false;
if (cx->runtime->jitSupportsFloatingPoint) {
// Initialize some Ion-only stubs that require floating-point support.
if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId())) if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId()))
return false; return false;
@ -215,6 +217,11 @@ IonRuntime::initialize(JSContext *cx)
if (!bailoutHandler_) if (!bailoutHandler_)
return false; return false;
invalidator_ = generateInvalidator(cx);
if (!invalidator_)
return false;
}
argumentsRectifier_ = generateArgumentsRectifier(cx, SequentialExecution, &argumentsRectifierReturnAddr_); argumentsRectifier_ = generateArgumentsRectifier(cx, SequentialExecution, &argumentsRectifierReturnAddr_);
if (!argumentsRectifier_) if (!argumentsRectifier_)
return false; return false;
@ -225,10 +232,6 @@ IonRuntime::initialize(JSContext *cx)
return false; return false;
#endif #endif
invalidator_ = generateInvalidator(cx);
if (!invalidator_)
return false;
enterJIT_ = generateEnterJIT(cx, EnterJitOptimized); enterJIT_ = generateEnterJIT(cx, EnterJitOptimized);
if (!enterJIT_) if (!enterJIT_)
return false; return false;

View File

@ -278,9 +278,11 @@ class AssemblerX86Shared
} }
void movsd(const FloatRegister &src, const FloatRegister &dest) { void movsd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.movsd_rr(src.code(), dest.code()); masm.movsd_rr(src.code(), dest.code());
} }
void movsd(const Operand &src, const FloatRegister &dest) { void movsd(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::FPREG: case Operand::FPREG:
masm.movsd_rr(src.fpu(), dest.code()); masm.movsd_rr(src.fpu(), dest.code());
@ -296,6 +298,7 @@ class AssemblerX86Shared
} }
} }
void movsd(const FloatRegister &src, const Operand &dest) { void movsd(const FloatRegister &src, const Operand &dest) {
JS_ASSERT(HasSSE2());
switch (dest.kind()) { switch (dest.kind()) {
case Operand::FPREG: case Operand::FPREG:
masm.movsd_rr(src.code(), dest.fpu()); masm.movsd_rr(src.code(), dest.fpu());
@ -311,6 +314,7 @@ class AssemblerX86Shared
} }
} }
void movss(const Operand &src, const FloatRegister &dest) { void movss(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::REG_DISP: case Operand::REG_DISP:
masm.movss_mr(src.disp(), src.base(), dest.code()); masm.movss_mr(src.disp(), src.base(), dest.code());
@ -323,6 +327,7 @@ class AssemblerX86Shared
} }
} }
void movss(const FloatRegister &src, const Operand &dest) { void movss(const FloatRegister &src, const Operand &dest) {
JS_ASSERT(HasSSE2());
switch (dest.kind()) { switch (dest.kind()) {
case Operand::REG_DISP: case Operand::REG_DISP:
masm.movss_rm(src.code(), dest.disp(), dest.base()); masm.movss_rm(src.code(), dest.disp(), dest.base());
@ -335,6 +340,7 @@ class AssemblerX86Shared
} }
} }
void movdqa(const Operand &src, const FloatRegister &dest) { void movdqa(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::REG_DISP: case Operand::REG_DISP:
masm.movdqa_mr(src.disp(), src.base(), dest.code()); masm.movdqa_mr(src.disp(), src.base(), dest.code());
@ -347,6 +353,7 @@ class AssemblerX86Shared
} }
} }
void movdqa(const FloatRegister &src, const Operand &dest) { void movdqa(const FloatRegister &src, const Operand &dest) {
JS_ASSERT(HasSSE2());
switch (dest.kind()) { switch (dest.kind()) {
case Operand::REG_DISP: case Operand::REG_DISP:
masm.movdqa_rm(src.code(), dest.disp(), dest.base()); masm.movdqa_rm(src.code(), dest.disp(), dest.base());
@ -359,9 +366,11 @@ class AssemblerX86Shared
} }
} }
void cvtss2sd(const FloatRegister &src, const FloatRegister &dest) { void cvtss2sd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.cvtss2sd_rr(src.code(), dest.code()); masm.cvtss2sd_rr(src.code(), dest.code());
} }
void cvtsd2ss(const FloatRegister &src, const FloatRegister &dest) { void cvtsd2ss(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.cvtsd2ss_rr(src.code(), dest.code()); masm.cvtsd2ss_rr(src.code(), dest.code());
} }
void movzbl(const Operand &src, const Register &dest) { void movzbl(const Operand &src, const Register &dest) {
@ -655,6 +664,9 @@ class AssemblerX86Shared
masm.int3(); masm.int3();
} }
static bool HasSSE2() {
return JSC::MacroAssembler::getSSEState() >= JSC::MacroAssembler::HasSSE2;
}
static bool HasSSE41() { static bool HasSSE41() {
return JSC::MacroAssembler::getSSEState() >= JSC::MacroAssembler::HasSSE4_1; return JSC::MacroAssembler::getSSEState() >= JSC::MacroAssembler::HasSSE4_1;
} }
@ -1052,12 +1064,15 @@ class AssemblerX86Shared
} }
void unpcklps(const FloatRegister &src, const FloatRegister &dest) { void unpcklps(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.unpcklps_rr(src.code(), dest.code()); masm.unpcklps_rr(src.code(), dest.code());
} }
void pinsrd(const Register &src, const FloatRegister &dest) { void pinsrd(const Register &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.pinsrd_rr(src.code(), dest.code()); masm.pinsrd_rr(src.code(), dest.code());
} }
void pinsrd(const Operand &src, const FloatRegister &dest) { void pinsrd(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::REG: case Operand::REG:
masm.pinsrd_rr(src.reg(), dest.code()); masm.pinsrd_rr(src.reg(), dest.code());
@ -1070,16 +1085,20 @@ class AssemblerX86Shared
} }
} }
void psrldq(Imm32 shift, const FloatRegister &dest) { void psrldq(Imm32 shift, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.psrldq_rr(dest.code(), shift.value); masm.psrldq_rr(dest.code(), shift.value);
} }
void psllq(Imm32 shift, const FloatRegister &dest) { void psllq(Imm32 shift, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.psllq_rr(dest.code(), shift.value); masm.psllq_rr(dest.code(), shift.value);
} }
void psrlq(Imm32 shift, const FloatRegister &dest) { void psrlq(Imm32 shift, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.psrlq_rr(dest.code(), shift.value); masm.psrlq_rr(dest.code(), shift.value);
} }
void cvtsi2sd(const Operand &src, const FloatRegister &dest) { void cvtsi2sd(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::REG: case Operand::REG:
masm.cvtsi2sd_rr(src.reg(), dest.code()); masm.cvtsi2sd_rr(src.reg(), dest.code());
@ -1095,12 +1114,15 @@ class AssemblerX86Shared
} }
} }
void cvttsd2si(const FloatRegister &src, const Register &dest) { void cvttsd2si(const FloatRegister &src, const Register &dest) {
JS_ASSERT(HasSSE2());
masm.cvttsd2si_rr(src.code(), dest.code()); masm.cvttsd2si_rr(src.code(), dest.code());
} }
void cvtsi2sd(const Register &src, const FloatRegister &dest) { void cvtsi2sd(const Register &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.cvtsi2sd_rr(src.code(), dest.code()); masm.cvtsi2sd_rr(src.code(), dest.code());
} }
void movmskpd(const FloatRegister &src, const Register &dest) { void movmskpd(const FloatRegister &src, const Register &dest) {
JS_ASSERT(HasSSE2());
masm.movmskpd_rr(src.code(), dest.code()); masm.movmskpd_rr(src.code(), dest.code());
} }
void ptest(const FloatRegister &lhs, const FloatRegister &rhs) { void ptest(const FloatRegister &lhs, const FloatRegister &rhs) {
@ -1108,21 +1130,27 @@ class AssemblerX86Shared
masm.ptest_rr(rhs.code(), lhs.code()); masm.ptest_rr(rhs.code(), lhs.code());
} }
void ucomisd(const FloatRegister &lhs, const FloatRegister &rhs) { void ucomisd(const FloatRegister &lhs, const FloatRegister &rhs) {
JS_ASSERT(HasSSE2());
masm.ucomisd_rr(rhs.code(), lhs.code()); masm.ucomisd_rr(rhs.code(), lhs.code());
} }
void pcmpeqw(const FloatRegister &lhs, const FloatRegister &rhs) { void pcmpeqw(const FloatRegister &lhs, const FloatRegister &rhs) {
JS_ASSERT(HasSSE2());
masm.pcmpeqw_rr(rhs.code(), lhs.code()); masm.pcmpeqw_rr(rhs.code(), lhs.code());
} }
void movd(const Register &src, const FloatRegister &dest) { void movd(const Register &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.movd_rr(src.code(), dest.code()); masm.movd_rr(src.code(), dest.code());
} }
void movd(const FloatRegister &src, const Register &dest) { void movd(const FloatRegister &src, const Register &dest) {
JS_ASSERT(HasSSE2());
masm.movd_rr(src.code(), dest.code()); masm.movd_rr(src.code(), dest.code());
} }
void addsd(const FloatRegister &src, const FloatRegister &dest) { void addsd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.addsd_rr(src.code(), dest.code()); masm.addsd_rr(src.code(), dest.code());
} }
void addsd(const Operand &src, const FloatRegister &dest) { void addsd(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::FPREG: case Operand::FPREG:
masm.addsd_rr(src.fpu(), dest.code()); masm.addsd_rr(src.fpu(), dest.code());
@ -1140,9 +1168,11 @@ class AssemblerX86Shared
} }
} }
void subsd(const FloatRegister &src, const FloatRegister &dest) { void subsd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.subsd_rr(src.code(), dest.code()); masm.subsd_rr(src.code(), dest.code());
} }
void subsd(const Operand &src, const FloatRegister &dest) { void subsd(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::FPREG: case Operand::FPREG:
masm.subsd_rr(src.fpu(), dest.code()); masm.subsd_rr(src.fpu(), dest.code());
@ -1155,9 +1185,11 @@ class AssemblerX86Shared
} }
} }
void mulsd(const FloatRegister &src, const FloatRegister &dest) { void mulsd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.mulsd_rr(src.code(), dest.code()); masm.mulsd_rr(src.code(), dest.code());
} }
void mulsd(const Operand &src, const FloatRegister &dest) { void mulsd(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::FPREG: case Operand::FPREG:
masm.mulsd_rr(src.fpu(), dest.code()); masm.mulsd_rr(src.fpu(), dest.code());
@ -1170,9 +1202,11 @@ class AssemblerX86Shared
} }
} }
void divsd(const FloatRegister &src, const FloatRegister &dest) { void divsd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.divsd_rr(src.code(), dest.code()); masm.divsd_rr(src.code(), dest.code());
} }
void divsd(const Operand &src, const FloatRegister &dest) { void divsd(const Operand &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::FPREG: case Operand::FPREG:
masm.divsd_rr(src.fpu(), dest.code()); masm.divsd_rr(src.fpu(), dest.code());
@ -1185,20 +1219,25 @@ class AssemblerX86Shared
} }
} }
void xorpd(const FloatRegister &src, const FloatRegister &dest) { void xorpd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.xorpd_rr(src.code(), dest.code()); masm.xorpd_rr(src.code(), dest.code());
} }
void orpd(const FloatRegister &src, const FloatRegister &dest) { void orpd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.orpd_rr(src.code(), dest.code()); masm.orpd_rr(src.code(), dest.code());
} }
void andpd(const FloatRegister &src, const FloatRegister &dest) { void andpd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.andpd_rr(src.code(), dest.code()); masm.andpd_rr(src.code(), dest.code());
} }
void sqrtsd(const FloatRegister &src, const FloatRegister &dest) { void sqrtsd(const FloatRegister &src, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.sqrtsd_rr(src.code(), dest.code()); masm.sqrtsd_rr(src.code(), dest.code());
} }
void roundsd(const FloatRegister &src, const FloatRegister &dest, void roundsd(const FloatRegister &src, const FloatRegister &dest,
JSC::X86Assembler::RoundingMode mode) JSC::X86Assembler::RoundingMode mode)
{ {
JS_ASSERT(HasSSE41());
masm.roundsd_rr(src.code(), dest.code(), mode); masm.roundsd_rr(src.code(), dest.code(), mode);
} }
void fstp(const Operand &src) { void fstp(const Operand &src) {

View File

@ -432,6 +432,7 @@ class Assembler : public AssemblerX86Shared
} }
void movsd(const double *dp, const FloatRegister &dest) { void movsd(const double *dp, const FloatRegister &dest) {
JS_ASSERT(HasSSE2());
masm.movsd_mr((const void *)dp, dest.code()); masm.movsd_mr((const void *)dp, dest.code());
} }
@ -448,6 +449,7 @@ class Assembler : public AssemblerX86Shared
return masm.currentOffset(); return masm.currentOffset();
} }
CodeOffsetLabel movsdWithPatch(void *addr, FloatRegister dest) { CodeOffsetLabel movsdWithPatch(void *addr, FloatRegister dest) {
JS_ASSERT(HasSSE2());
masm.movsd_mr(addr, dest.code()); masm.movsd_mr(addr, dest.code());
return masm.currentOffset(); return masm.currentOffset();
} }
@ -458,6 +460,7 @@ class Assembler : public AssemblerX86Shared
return masm.currentOffset(); return masm.currentOffset();
} }
CodeOffsetLabel movsdWithPatch(FloatRegister dest, void *addr) { CodeOffsetLabel movsdWithPatch(FloatRegister dest, void *addr) {
JS_ASSERT(HasSSE2());
masm.movsd_rm(dest.code(), addr); masm.movsd_rm(dest.code(), addr);
return masm.currentOffset(); return masm.currentOffset();
} }
@ -484,10 +487,12 @@ class Assembler : public AssemblerX86Shared
return masm.currentOffset(); return masm.currentOffset();
} }
CodeOffsetLabel movssWithPatch(Address src, FloatRegister dest) { CodeOffsetLabel movssWithPatch(Address src, FloatRegister dest) {
JS_ASSERT(HasSSE2());
masm.movss_mr_disp32(src.offset, src.base.code(), dest.code()); masm.movss_mr_disp32(src.offset, src.base.code(), dest.code());
return masm.currentOffset(); return masm.currentOffset();
} }
CodeOffsetLabel movsdWithPatch(Address src, FloatRegister dest) { CodeOffsetLabel movsdWithPatch(Address src, FloatRegister dest) {
JS_ASSERT(HasSSE2());
masm.movsd_mr_disp32(src.offset, src.base.code(), dest.code()); masm.movsd_mr_disp32(src.offset, src.base.code(), dest.code());
return masm.currentOffset(); return masm.currentOffset();
} }
@ -506,10 +511,12 @@ class Assembler : public AssemblerX86Shared
return masm.currentOffset(); return masm.currentOffset();
} }
CodeOffsetLabel movssWithPatch(FloatRegister src, Address dest) { CodeOffsetLabel movssWithPatch(FloatRegister src, Address dest) {
JS_ASSERT(HasSSE2());
masm.movss_rm_disp32(src.code(), dest.offset, dest.base.code()); masm.movss_rm_disp32(src.code(), dest.offset, dest.base.code());
return masm.currentOffset(); return masm.currentOffset();
} }
CodeOffsetLabel movsdWithPatch(FloatRegister src, Address dest) { CodeOffsetLabel movsdWithPatch(FloatRegister src, Address dest) {
JS_ASSERT(HasSSE2());
masm.movsd_rm_disp32(src.code(), dest.offset, dest.base.code()); masm.movsd_rm_disp32(src.code(), dest.offset, dest.base.code());
return masm.currentOffset(); return masm.currentOffset();
} }

View File

@ -665,8 +665,14 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type)
{ {
MacroAssembler masm; MacroAssembler masm;
RegisterSet save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask), RegisterSet save;
if (cx->runtime->jitSupportsFloatingPoint) {
save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
FloatRegisterSet(FloatRegisters::VolatileMask)); FloatRegisterSet(FloatRegisters::VolatileMask));
} else {
save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
FloatRegisterSet());
}
masm.PushRegsInMask(save); masm.PushRegsInMask(save);
JS_ASSERT(PreBarrierReg == edx); JS_ASSERT(PreBarrierReg == edx);

View File

@ -147,7 +147,7 @@ def main(argv):
['--no-baseline'], ['--no-baseline'],
['--no-baseline', '--ion-eager'], ['--no-baseline', '--ion-eager'],
['--baseline-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 # 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-jm', '--no-ti'],
['--no-baseline', '--no-ion', '--no-ti'], ['--no-baseline', '--no-ion', '--no-ti'],

View File

@ -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(100), 100);
assertEq(rec(1000), 1000); assertEq(rec(1000), 1000);
assertThrowsInstanceOf(function() rec(100000000000), InternalError); assertThrowsInstanceOf(function() rec(100000000000), InternalError);
assertEq(rec(10000), 10000); assertEq(rec(2000), 2000);

View File

@ -686,6 +686,24 @@ JS_FRIEND_API(bool) JS::isGCEnabled() { return true; }
static const JSSecurityCallbacks NullSecurityCallbacks = { }; 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) PerThreadData::PerThreadData(JSRuntime *runtime)
: PerThreadDataFriendFields(), : PerThreadDataFriendFields(),
runtime_(runtime), runtime_(runtime),
@ -893,6 +911,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
noGCOrAllocationCheck(0), noGCOrAllocationCheck(0),
#endif #endif
jitHardening(false), jitHardening(false),
jitSupportsFloatingPoint(false),
ionPcScriptCache(NULL), ionPcScriptCache(NULL),
threadPool(this), threadPool(this),
ctypesActivityCallback(NULL), ctypesActivityCallback(NULL),
@ -990,6 +1009,8 @@ JSRuntime::init(uint32_t maxbytes)
return false; return false;
nativeStackBase = GetNativeStackBase(); nativeStackBase = GetNativeStackBase();
jitSupportsFloatingPoint = JitSupportsFloatingPoint();
return true; return true;
} }

View File

@ -1304,6 +1304,8 @@ struct JSRuntime : private JS::shadow::Runtime,
bool jitHardening; bool jitHardening;
bool jitSupportsFloatingPoint;
// Used to reset stack limit after a signaled interrupt (i.e. ionStackLimit_ = -1) // Used to reset stack limit after a signaled interrupt (i.e. ionStackLimit_ = -1)
// has been noticed by Ion/Baseline. // has been noticed by Ion/Baseline.
void resetIonStackLimit() { void resetIonStackLimit() {

View File

@ -2382,31 +2382,6 @@ class TypeConstraintFreezeStack : public TypeConstraint
// TypeCompartment // 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() TypeCompartment::TypeCompartment()
{ {
PodZero(this); PodZero(this);
@ -2418,7 +2393,7 @@ TypeZone::init(JSContext *cx)
{ {
if (!cx || if (!cx ||
!cx->hasOption(JSOPTION_TYPE_INFERENCE) || !cx->hasOption(JSOPTION_TYPE_INFERENCE) ||
!TypeInferenceSupported()) !cx->runtime->jitSupportsFloatingPoint)
{ {
return; return;
} }

View File

@ -5295,6 +5295,8 @@ main(int argc, char **argv, char **envp)
|| !op.addIntOption('\0', "baseline-uses-before-compile", "COUNT", || !op.addIntOption('\0', "baseline-uses-before-compile", "COUNT",
"Wait for COUNT calls or iterations before baseline-compiling " "Wait for COUNT calls or iterations before baseline-compiling "
"(default: 10)", -1) "(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 #ifdef JSGC_GENERATIONAL
|| !op.addBoolOption('\0', "ggc", "Enable Generational GC") || !op.addBoolOption('\0', "ggc", "Enable Generational GC")
#endif #endif
@ -5329,6 +5331,11 @@ main(int argc, char **argv, char **envp)
OOM_maxAllocations = op.getIntOption('A'); OOM_maxAllocations = op.getIntOption('A');
if (op.getBoolOption('O')) if (op.getBoolOption('O'))
OOM_printAllocationCount = true; OOM_printAllocationCount = true;
#if defined(JS_CPU_X86)
if (op.getBoolOption("no-fpu"))
JSC::MacroAssembler::SetFloatingPointDisabled();
#endif
#endif #endif
/* Use the same parameters as the browser in xpcjsruntime.cpp. */ /* Use the same parameters as the browser in xpcjsruntime.cpp. */