Support pre-SSE2 CPUs in JaegerMonkey (bug 696291, r=bhackett).

--HG--
extra : rebase_source : f1f6a1e60b05974533ff39292a0a278fc69fbb0f
This commit is contained in:
David Anderson 2012-01-13 13:33:56 -08:00
parent 8636172c79
commit 5365dca1bc
7 changed files with 134 additions and 76 deletions

View File

@ -1678,13 +1678,7 @@ 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
}

View File

@ -59,6 +59,9 @@
#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"
@ -1961,8 +1964,13 @@ 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 *

View File

@ -638,6 +638,7 @@ private:
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);

View File

@ -175,6 +175,21 @@ mjit::Compiler::maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry
}
}
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)
{
@ -205,16 +220,7 @@ mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::Typ
(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);
}
/*
@ -238,6 +244,9 @@ mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::Typ
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
@ -572,7 +581,7 @@ mjit::Compiler::jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op,
/* 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);
@ -790,7 +799,9 @@ 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();
@ -802,7 +813,8 @@ mjit::Compiler::jsop_neg()
/* 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);
@ -1309,6 +1321,11 @@ mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState:
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());
@ -1354,6 +1371,11 @@ mjit::Compiler::emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState
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());
@ -1571,7 +1593,7 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
/* 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. */
@ -1612,26 +1634,26 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
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())
@ -1701,22 +1723,22 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
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);
/* Emit the slow path - note full frame syncage. */
frame.sync(stubcc.masm, Uses(2));
stubcc.leave();
OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
}
/* 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);
/* Get an integer comparison condition. */
Assembler::Condition i32Cond = GetCompareCondition(cmpOp, fused);

View File

@ -101,28 +101,42 @@ mjit::Compiler::ensureInteger(FrameEntry *fe, Uses uses)
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);
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);
Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
Label syncPath = stubcc.syncExitAndJump(uses);
stubcc.linkExitDirect(intGuard, stubcc.masm.label());
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);
/* 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.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);
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);
}
}
}
@ -562,6 +576,8 @@ mjit::Compiler::jsop_relational(JSOp op, BoolStub stub,
} 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)) {

View File

@ -1530,10 +1530,12 @@ FrameState::merge(Assembler &masm, Changes changes) const
* 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;

View File

@ -2537,6 +2537,14 @@ GetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid i
: 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);
@ -2829,6 +2837,13 @@ SetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, int32_t key)
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);