mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Floating point register allocation, bug 609898.
This commit is contained in:
parent
0c537779e7
commit
fb68b676af
@ -254,6 +254,7 @@ private:
|
||||
OP2_SQRTSD_VsdWsd = 0x51,
|
||||
OP2_XORPD_VpdWpd = 0x57,
|
||||
OP2_MOVD_VdEd = 0x6E,
|
||||
OP2_PSRLDQ_Vd = 0x73,
|
||||
OP2_MOVD_EdVd = 0x7E,
|
||||
OP2_JCC_rel32 = 0x80,
|
||||
OP_SETCC = 0x90,
|
||||
@ -1862,6 +1863,27 @@ public:
|
||||
m_formatter.twoByteOp(OP2_MOVD_VdEd, (RegisterID)dst, src);
|
||||
}
|
||||
|
||||
/* :FIXME: borrowed from patch in bug 594247 */
|
||||
|
||||
void psrldq_rr(XMMRegisterID dest, int shift)
|
||||
{
|
||||
js::JaegerSpew(js::JSpew_Insns,
|
||||
IPFX "pslldq %s, %d\n", MAYBE_PAD,
|
||||
nameFPReg(dest), shift);
|
||||
m_formatter.prefix(PRE_SSE_66);
|
||||
m_formatter.twoByteOp(OP2_PSRLDQ_Vd, (RegisterID)3, (RegisterID)dest);
|
||||
m_formatter.immediate8(shift);
|
||||
}
|
||||
|
||||
void movd_rr(XMMRegisterID src, RegisterID dst)
|
||||
{
|
||||
js::JaegerSpew(js::JSpew_Insns,
|
||||
IPFX "movd %s, %s\n", MAYBE_PAD,
|
||||
nameFPReg(src), nameIReg(dst));
|
||||
m_formatter.prefix(PRE_SSE_66);
|
||||
m_formatter.twoByteOp(OP2_MOVD_EdVd, (RegisterID)src, dst);
|
||||
}
|
||||
|
||||
#if WTF_CPU_X86_64
|
||||
void movq_rr(XMMRegisterID src, RegisterID dst)
|
||||
{
|
||||
|
@ -745,6 +745,12 @@ Script::analyze(JSContext *cx)
|
||||
defineArray, defineCount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Treat the fallthrough of a branch instruction as a jump target. */
|
||||
if (type == JOF_JUMP || type == JOF_JUMPX)
|
||||
nextcode->jumpTarget = true;
|
||||
else
|
||||
nextcode->fallthrough = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,10 @@ struct Bytecode
|
||||
friend class Script;
|
||||
|
||||
/* Whether there are any incoming jumps to this instruction. */
|
||||
bool jumpTarget : 1;
|
||||
bool jumpTarget : 1;
|
||||
|
||||
/* Whether there is fallthrough to this instruction from a non-branching instruction. */
|
||||
bool fallthrough : 1;
|
||||
|
||||
/* Whether this instruction has been analyzed to get its output defines and stack. */
|
||||
bool analyzed : 1;
|
||||
|
@ -936,6 +936,8 @@ GetValueTypeFromTypeFlags(TypeFlags flags)
|
||||
return JSVAL_TYPE_BOOLEAN;
|
||||
case TYPE_FLAG_INT32:
|
||||
return JSVAL_TYPE_INT32;
|
||||
case (TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE):
|
||||
return JSVAL_TYPE_DOUBLE;
|
||||
case TYPE_FLAG_STRING:
|
||||
return JSVAL_TYPE_STRING;
|
||||
case TYPE_FLAG_OBJECT:
|
||||
@ -2119,6 +2121,8 @@ Script::analyzeTypes(JSContext *cx, Bytecode *code, TypeState &state)
|
||||
case JSOP_BITNOT:
|
||||
case JSOP_RSH:
|
||||
case JSOP_LSH:
|
||||
case JSOP_URSH:
|
||||
/* :TODO: Add heuristics for guessing URSH which can overflow. */
|
||||
code->setFixed(cx, 0, TYPE_INT32);
|
||||
break;
|
||||
case JSOP_FALSE:
|
||||
@ -2138,7 +2142,6 @@ Script::analyzeTypes(JSContext *cx, Bytecode *code, TypeState &state)
|
||||
code->setFixed(cx, 0, TYPE_BOOLEAN);
|
||||
break;
|
||||
case JSOP_DOUBLE:
|
||||
case JSOP_DIV:
|
||||
code->setFixed(cx, 0, TYPE_DOUBLE);
|
||||
break;
|
||||
case JSOP_STRING:
|
||||
@ -2600,7 +2603,8 @@ Script::analyzeTypes(JSContext *cx, Bytecode *code, TypeState &state)
|
||||
case JSOP_SUB:
|
||||
case JSOP_MUL:
|
||||
case JSOP_MOD:
|
||||
case JSOP_URSH:
|
||||
case JSOP_DIV:
|
||||
/* :TODO: Add heuristics for guessing when dividing two ints produces a double. */
|
||||
code->popped(0)->addArith(cx, pool, code, code->pushed(0));
|
||||
code->popped(1)->addArith(cx, pool, code, code->pushed(0));
|
||||
break;
|
||||
|
@ -3718,7 +3718,7 @@ END_CASE(JSOP_ADD)
|
||||
double d = d1 OP d2; \
|
||||
regs.sp--; \
|
||||
regs.sp[-1].setNumber(d); \
|
||||
TYPE_MONITOR_RESULT(cx, 0, regs.sp[-1], !regs.sp[-1].isInt32()); \
|
||||
TYPE_MONITOR_RESULT(cx, 0, regs.sp[-1], !regs.sp[-1].isInt32()); \
|
||||
JS_END_MACRO
|
||||
|
||||
BEGIN_CASE(JSOP_SUB)
|
||||
@ -3758,7 +3758,7 @@ BEGIN_CASE(JSOP_DIV)
|
||||
d1 /= d2;
|
||||
regs.sp[-1].setNumber(d1);
|
||||
}
|
||||
TYPE_MONITOR_RESULT(cx, 0, regs.sp[-1], false);
|
||||
TYPE_MONITOR_RESULT(cx, 0, regs.sp[-1], !regs.sp[-1].isInt32());
|
||||
}
|
||||
END_CASE(JSOP_DIV)
|
||||
|
||||
|
@ -191,12 +191,62 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
|
||||
m_assembler.pinsrd_rr(hi, fpReg);
|
||||
} else {
|
||||
m_assembler.movd_rr(lo, fpReg);
|
||||
m_assembler.movd_rr(hi, FPRegisters::Temp0);
|
||||
m_assembler.unpcklps_rr(FPRegisters::Temp0, fpReg);
|
||||
m_assembler.movd_rr(hi, FPRegisters::ConversionTemp);
|
||||
m_assembler.unpcklps_rr(FPRegisters::ConversionTemp, fpReg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Move a register pair which may indicate either an int32 or double into fpreg,
|
||||
* converting to double in the int32 case.
|
||||
*/
|
||||
void moveInt32OrDouble(RegisterID data, RegisterID type, Address address, FPRegisterID fpreg)
|
||||
{
|
||||
#ifdef JS_CPU_X86
|
||||
fastLoadDouble(data, type, fpreg);
|
||||
Jump notInteger = testInt32(Assembler::NotEqual, type);
|
||||
convertInt32ToDouble(data, fpreg);
|
||||
notInteger.linkTo(label(), this);
|
||||
#else
|
||||
Jump notInteger = testInt32(Assembler::NotEqual, type);
|
||||
convertInt32ToDouble(data, fpreg);
|
||||
Jump fallthrough = jump();
|
||||
notInteger.linkTo(label(), this);
|
||||
|
||||
/* Store the components, then read it back out as a double. */
|
||||
storeValueFromComponents(type, data, address);
|
||||
loadDouble(address, fpreg);
|
||||
|
||||
fallthrough.linkTo(label(), this);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Move a memory address which contains either an int32 or double into fpreg,
|
||||
* converting to double in the int32 case.
|
||||
*/
|
||||
void moveInt32OrDouble(Address address, FPRegisterID fpreg)
|
||||
{
|
||||
Jump notInteger = testInt32(Assembler::NotEqual, address);
|
||||
convertInt32ToDouble(payloadOf(address), fpreg);
|
||||
Jump fallthrough = jump();
|
||||
notInteger.linkTo(label(), this);
|
||||
loadDouble(address, fpreg);
|
||||
fallthrough.linkTo(label(), this);
|
||||
}
|
||||
|
||||
void negateDouble(FPRegisterID fpreg)
|
||||
{
|
||||
#if defined JS_CPU_X86 || defined JS_CPU_X64
|
||||
static const uint64 DoubleNegMask = 0x8000000000000000ULL;
|
||||
loadDouble(&DoubleNegMask, FPRegisters::ConversionTemp);
|
||||
xorDouble(FPRegisters::ConversionTemp, fpreg);
|
||||
#elif defined JS_CPU_ARM
|
||||
negDouble(fpreg, fpreg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepares for a stub call.
|
||||
*/
|
||||
|
@ -115,6 +115,8 @@ mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
|
||||
,addTraceHints(cx->traceJitEnabled)
|
||||
#endif
|
||||
#if defined JS_TYPE_INFERENCE
|
||||
,hasThisType(false)
|
||||
,thisType(JSVAL_TYPE_UNKNOWN)
|
||||
,argumentTypes(ContextAllocPolicy(cx))
|
||||
,localTypes(ContextAllocPolicy(cx))
|
||||
#endif
|
||||
@ -386,8 +388,11 @@ mjit::Compiler::generatePrologue()
|
||||
JSValueType type = knownLocalType(i);
|
||||
if (type != JSVAL_TYPE_UNKNOWN) {
|
||||
JS_ASSERT(!analysis->localHasUseBeforeDef(i));
|
||||
Address local(JSFrameReg, sizeof(JSStackFrame) + i * sizeof(Value));
|
||||
masm.storeTypeTag(ImmType(type), local);
|
||||
/* Doubles must will be written entirely when syncing. */
|
||||
if (type != JSVAL_TYPE_DOUBLE) {
|
||||
Address local(JSFrameReg, sizeof(JSStackFrame) + i * sizeof(Value));
|
||||
masm.storeTypeTag(ImmType(type), local);
|
||||
}
|
||||
frame.learnType(frame.getLocal(i), type, false);
|
||||
}
|
||||
}
|
||||
@ -853,14 +858,16 @@ mjit::Compiler::generateMethod()
|
||||
|
||||
frame.setInTryBlock(opinfo->inTryBlock);
|
||||
if (opinfo->jumpTarget || trap) {
|
||||
if (opinfo->fallthrough)
|
||||
fixDoubleTypes(Uses(0));
|
||||
frame.syncAndForgetEverything(opinfo->stackDepth);
|
||||
opinfo->safePoint = true;
|
||||
|
||||
if (!trap)
|
||||
restoreAnalysisTypes(opinfo->stackDepth);
|
||||
}
|
||||
jumpMap[uint32(PC - script->code)] = masm.label();
|
||||
|
||||
if (opinfo->jumpTarget)
|
||||
restoreAnalysisTypes(opinfo->stackDepth);
|
||||
|
||||
SPEW_OPCODE();
|
||||
JS_ASSERT(frame.stackDepth() == opinfo->stackDepth);
|
||||
|
||||
@ -922,6 +929,7 @@ mjit::Compiler::generateMethod()
|
||||
BEGIN_CASE(JSOP_GOTO)
|
||||
{
|
||||
/* :XXX: this isn't really necessary if we follow the branch. */
|
||||
fixDoubleTypes(Uses(0));
|
||||
frame.syncAndForgetEverything();
|
||||
Jump j = masm.jump();
|
||||
if (!jumpAndTrace(j, PC + GET_JUMP_OFFSET(PC)))
|
||||
@ -931,6 +939,7 @@ mjit::Compiler::generateMethod()
|
||||
|
||||
BEGIN_CASE(JSOP_IFEQ)
|
||||
BEGIN_CASE(JSOP_IFNE)
|
||||
fixDoubleTypes(Uses(1));
|
||||
if (!jsop_ifneq(op, PC + GET_JUMP_OFFSET(PC)))
|
||||
return Compile_Error;
|
||||
END_CASE(JSOP_IFNE)
|
||||
@ -938,7 +947,7 @@ mjit::Compiler::generateMethod()
|
||||
BEGIN_CASE(JSOP_ARGUMENTS)
|
||||
prepareStubCall(Uses(0));
|
||||
stubCall(stubs::Arguments);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
END_CASE(JSOP_ARGUMENTS)
|
||||
|
||||
BEGIN_CASE(JSOP_FORARG)
|
||||
@ -982,8 +991,10 @@ mjit::Compiler::generateMethod()
|
||||
|
||||
/* Get jump target, if any. */
|
||||
jsbytecode *target = NULL;
|
||||
if (fused != JSOP_NOP)
|
||||
if (fused != JSOP_NOP) {
|
||||
target = next + GET_JUMP_OFFSET(next);
|
||||
fixDoubleTypes(Uses(2));
|
||||
}
|
||||
|
||||
BoolStub stub = NULL;
|
||||
switch (op) {
|
||||
@ -1143,7 +1154,7 @@ mjit::Compiler::generateMethod()
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubCall(stubs::DelName);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
END_CASE(JSOP_DELNAME)
|
||||
|
||||
@ -1156,7 +1167,7 @@ mjit::Compiler::generateMethod()
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubCall(STRICT_VARIANT(stubs::DelProp));
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
END_CASE(JSOP_DELPROP)
|
||||
|
||||
@ -1164,7 +1175,7 @@ mjit::Compiler::generateMethod()
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(STRICT_VARIANT(stubs::DelElem));
|
||||
frame.popn(2);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
END_CASE(JSOP_DELELEM)
|
||||
|
||||
BEGIN_CASE(JSOP_TYPEOF)
|
||||
@ -1264,25 +1275,28 @@ mjit::Compiler::generateMethod()
|
||||
BEGIN_CASE(JSOP_GETTHISPROP)
|
||||
/* Push thisv onto stack. */
|
||||
jsop_this();
|
||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(PC))))
|
||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(PC)), knownPushedType(0)))
|
||||
return Compile_Error;
|
||||
END_CASE(JSOP_GETTHISPROP);
|
||||
|
||||
BEGIN_CASE(JSOP_GETARGPROP)
|
||||
/* Push arg onto stack. */
|
||||
jsop_getarg(GET_SLOTNO(PC));
|
||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[ARGNO_LEN]))))
|
||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[ARGNO_LEN])), knownPushedType(0)))
|
||||
return Compile_Error;
|
||||
END_CASE(JSOP_GETARGPROP)
|
||||
|
||||
BEGIN_CASE(JSOP_GETLOCALPROP)
|
||||
frame.pushLocal(GET_SLOTNO(PC));
|
||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[SLOTNO_LEN]))))
|
||||
{
|
||||
uint32 local = GET_SLOTNO(PC);
|
||||
frame.pushLocal(local, knownLocalType(local));
|
||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[SLOTNO_LEN])), knownPushedType(0)))
|
||||
return Compile_Error;
|
||||
}
|
||||
END_CASE(JSOP_GETLOCALPROP)
|
||||
|
||||
BEGIN_CASE(JSOP_GETPROP)
|
||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(PC))))
|
||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(PC)), knownPushedType(0)))
|
||||
return Compile_Error;
|
||||
END_CASE(JSOP_GETPROP)
|
||||
|
||||
@ -1305,8 +1319,8 @@ mjit::Compiler::generateMethod()
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(Imm32(fullAtomIndex(PC)), Registers::ArgReg1);
|
||||
stubCall(stubs::CallName);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
frame.pushSynced(knownPushedType(1));
|
||||
END_CASE(JSOP_CALLNAME)
|
||||
|
||||
BEGIN_CASE(JSOP_EVAL)
|
||||
@ -1372,11 +1386,13 @@ mjit::Compiler::generateMethod()
|
||||
|
||||
BEGIN_CASE(JSOP_OR)
|
||||
BEGIN_CASE(JSOP_AND)
|
||||
fixDoubleTypes(Uses(0));
|
||||
if (!jsop_andor(op, PC + GET_JUMP_OFFSET(PC)))
|
||||
return Compile_Error;
|
||||
END_CASE(JSOP_AND)
|
||||
|
||||
BEGIN_CASE(JSOP_TABLESWITCH)
|
||||
fixDoubleTypes(Uses(1));
|
||||
frame.syncAndForgetEverything();
|
||||
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||
|
||||
@ -1390,6 +1406,7 @@ mjit::Compiler::generateMethod()
|
||||
END_CASE(JSOP_TABLESWITCH)
|
||||
|
||||
BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
||||
fixDoubleTypes(Uses(1));
|
||||
frame.syncAndForgetEverything();
|
||||
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||
|
||||
@ -1416,7 +1433,7 @@ mjit::Compiler::generateMethod()
|
||||
masm.move(Imm32(PC[1]), Registers::ArgReg1);
|
||||
stubCall(stubs::Iter);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(JSVAL_TYPE_UNKNOWN);
|
||||
#else
|
||||
iter(PC[1]);
|
||||
#endif
|
||||
@ -1470,7 +1487,7 @@ mjit::Compiler::generateMethod()
|
||||
BEGIN_CASE(JSOP_GETLOCAL)
|
||||
{
|
||||
uint32 slot = GET_SLOTNO(PC);
|
||||
frame.pushLocal(slot);
|
||||
frame.pushLocal(slot, knownPushedType(0));
|
||||
}
|
||||
END_CASE(JSOP_GETLOCAL)
|
||||
|
||||
@ -1479,7 +1496,7 @@ mjit::Compiler::generateMethod()
|
||||
jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH];
|
||||
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
|
||||
JSValueType type = knownLocalType(GET_SLOTNO(PC));
|
||||
frame.storeLocal(GET_SLOTNO(PC), pop, type == JSVAL_TYPE_UNKNOWN);
|
||||
frame.storeLocal(GET_SLOTNO(PC), pop, type);
|
||||
if (pop) {
|
||||
frame.pop();
|
||||
PC += JSOP_SETLOCAL_LENGTH + JSOP_POP_LENGTH;
|
||||
@ -1653,7 +1670,7 @@ mjit::Compiler::generateMethod()
|
||||
|
||||
Address excn(reg, offsetof(JSContext, exception));
|
||||
frame.freeReg(reg);
|
||||
frame.push(excn);
|
||||
frame.push(excn, knownPushedType(0));
|
||||
}
|
||||
END_CASE(JSOP_EXCEPTION)
|
||||
|
||||
@ -1794,7 +1811,7 @@ mjit::Compiler::generateMethod()
|
||||
masm.loadPrivate(upvarAddress, reg);
|
||||
// push ((Value *) reg)[index]
|
||||
frame.freeReg(reg);
|
||||
frame.push(Address(reg, index * sizeof(Value)));
|
||||
frame.push(Address(reg, index * sizeof(Value)), knownPushedType(0));
|
||||
if (op == JSOP_CALLFCSLOT)
|
||||
frame.push(UndefinedValue());
|
||||
}
|
||||
@ -1804,13 +1821,13 @@ mjit::Compiler::generateMethod()
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(Imm32(GET_ARGNO(PC)), Registers::ArgReg1);
|
||||
stubCall(stubs::ArgSub);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
END_CASE(JSOP_ARGSUB)
|
||||
|
||||
BEGIN_CASE(JSOP_ARGCNT)
|
||||
prepareStubCall(Uses(0));
|
||||
stubCall(stubs::ArgCnt);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
END_CASE(JSOP_ARGCNT)
|
||||
|
||||
BEGIN_CASE(JSOP_DEFLOCALFUN)
|
||||
@ -1868,7 +1885,7 @@ mjit::Compiler::generateMethod()
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(Imm32(uva->vector[index].asInteger()), Registers::ArgReg1);
|
||||
stubCall(stubs::GetUpvar);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
if (op == JSOP_CALLUPVAR)
|
||||
frame.push(UndefinedValue());
|
||||
}
|
||||
@ -1902,7 +1919,7 @@ mjit::Compiler::generateMethod()
|
||||
END_CASE(JSOP_LEAVEBLOCK)
|
||||
|
||||
BEGIN_CASE(JSOP_CALLLOCAL)
|
||||
frame.pushLocal(GET_SLOTNO(PC));
|
||||
frame.pushLocal(GET_SLOTNO(PC), knownPushedType(0));
|
||||
frame.push(UndefinedValue());
|
||||
END_CASE(JSOP_CALLLOCAL)
|
||||
|
||||
@ -2114,7 +2131,7 @@ mjit::Compiler::jsop_getglobal(uint32 index)
|
||||
RegisterID reg = frame.allocReg();
|
||||
Address address = masm.objSlotRef(globalObj, reg, slot);
|
||||
frame.freeReg(reg);
|
||||
frame.push(address);
|
||||
frame.push(address, knownPushedType(0));
|
||||
}
|
||||
|
||||
void
|
||||
@ -2150,7 +2167,7 @@ mjit::Compiler::loadReturnValue(Assembler *masm, FrameEntry *fe)
|
||||
stubcc.masm.loadValueAsComponents(fe->getValue(), typeReg, dataReg);
|
||||
} else {
|
||||
Address rval(frame.addressOf(fe));
|
||||
if (fe->isTypeKnown()) {
|
||||
if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
stubcc.masm.loadPayload(rval, dataReg);
|
||||
stubcc.masm.move(ImmType(fe->getKnownType()), typeReg);
|
||||
} else {
|
||||
@ -2369,18 +2386,12 @@ mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
|
||||
|
||||
frame.popn(argc + 2);
|
||||
|
||||
JSValueType type = knownPushedType(0);
|
||||
if (type != JSVAL_TYPE_UNKNOWN) {
|
||||
frame.takeReg(JSReturnReg_Data);
|
||||
frame.pushTypedPayload(type, JSReturnReg_Data);
|
||||
} else {
|
||||
frame.takeReg(JSReturnReg_Type);
|
||||
frame.takeReg(JSReturnReg_Data);
|
||||
frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data);
|
||||
}
|
||||
frame.takeReg(JSReturnReg_Type);
|
||||
frame.takeReg(JSReturnReg_Data);
|
||||
frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data, knownPushedType(0));
|
||||
|
||||
stubcc.linkExitDirect(notCompiled, stubcc.masm.label());
|
||||
stubcc.rejoin(Changes(0));
|
||||
stubcc.rejoin(Changes(1));
|
||||
callPatches.append(callPatch);
|
||||
}
|
||||
|
||||
@ -2533,19 +2544,15 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||
frame.popn(argc + 2);
|
||||
|
||||
JSValueType type = knownPushedType(0);
|
||||
if (type != JSVAL_TYPE_UNKNOWN) {
|
||||
frame.takeReg(JSReturnReg_Data);
|
||||
frame.pushTypedPayload(type, JSReturnReg_Data);
|
||||
} else {
|
||||
frame.takeReg(JSReturnReg_Type);
|
||||
frame.takeReg(JSReturnReg_Data);
|
||||
frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data);
|
||||
}
|
||||
|
||||
frame.takeReg(JSReturnReg_Type);
|
||||
frame.takeReg(JSReturnReg_Data);
|
||||
frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data, type);
|
||||
|
||||
callIC.slowJoinPoint = stubcc.masm.label();
|
||||
rejoin1.linkTo(callIC.slowJoinPoint, &stubcc.masm);
|
||||
rejoin2.linkTo(callIC.slowJoinPoint, &stubcc.masm);
|
||||
stubcc.rejoin(Changes(0));
|
||||
stubcc.rejoin(Changes(1));
|
||||
|
||||
callICs.append(callIC);
|
||||
callPatches.append(callPatch);
|
||||
@ -2690,7 +2697,7 @@ mjit::Compiler::jsop_getprop_slow(JSAtom *atom, bool usePropCache)
|
||||
stubCall(stubs::GetPropNoCache);
|
||||
}
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(JSVAL_TYPE_UNKNOWN);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2700,8 +2707,8 @@ mjit::Compiler::jsop_callprop_slow(JSAtom *atom)
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubCall(stubs::CallProp);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
frame.pushSynced(knownPushedType(1));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2728,12 +2735,12 @@ mjit::Compiler::jsop_length()
|
||||
}
|
||||
|
||||
#if defined JS_POLYIC
|
||||
return jsop_getprop(cx->runtime->atomState.lengthAtom);
|
||||
return jsop_getprop(cx->runtime->atomState.lengthAtom, knownPushedType(0));
|
||||
#else
|
||||
prepareStubCall(Uses(1));
|
||||
stubCall(stubs::Length);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
@ -2754,7 +2761,7 @@ mjit::Compiler::passICAddress(BaseICInfo *ic)
|
||||
}
|
||||
|
||||
bool
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType, bool doTypeCheck, bool usePropCache)
|
||||
{
|
||||
FrameEntry *top = frame.peek(-1);
|
||||
|
||||
@ -2873,7 +2880,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
||||
/* GETPROP_INLINE_TYPE_GUARD's validity is asserted above. */
|
||||
|
||||
pic.objReg = objReg;
|
||||
frame.pushRegs(shapeReg, objReg);
|
||||
frame.pushRegs(shapeReg, objReg, knownType);
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
|
||||
@ -2952,8 +2959,8 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
||||
|
||||
/* Adjust the frame. None of this will generate code. */
|
||||
frame.pop();
|
||||
frame.pushRegs(shapeReg, objReg);
|
||||
frame.pushSynced();
|
||||
frame.pushRegs(shapeReg, objReg, knownPushedType(0));
|
||||
frame.pushSynced(knownPushedType(1));
|
||||
|
||||
/* Load dslots. */
|
||||
#if defined JS_NUNBOX32
|
||||
@ -3026,7 +3033,7 @@ mjit::Compiler::jsop_callprop_str(JSAtom *atom)
|
||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
|
||||
|
||||
/* Get the property. */
|
||||
if (!jsop_getprop(atom))
|
||||
if (!jsop_getprop(atom, knownPushedType(0)))
|
||||
return false;
|
||||
|
||||
/* Perform a swap. */
|
||||
@ -3034,12 +3041,6 @@ mjit::Compiler::jsop_callprop_str(JSAtom *atom)
|
||||
frame.shift(-3);
|
||||
frame.shift(-1);
|
||||
|
||||
/* 4) Test if the function can take a primitive. */
|
||||
#ifdef DEBUG
|
||||
FrameEntry *funFe = frame.peek(-2);
|
||||
#endif
|
||||
JS_ASSERT(!funFe->isTypeKnown());
|
||||
|
||||
/*
|
||||
* See bug 584579 - need to forget string type, since wrapping could
|
||||
* create an object. forgetType() alone is not valid because it cannot be
|
||||
@ -3132,7 +3133,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
|
||||
* is the resulting vp[1].
|
||||
*/
|
||||
frame.dup();
|
||||
frame.pushRegs(shapeReg, objReg);
|
||||
frame.pushRegs(shapeReg, objReg, knownPushedType(0));
|
||||
frame.shift(-2);
|
||||
|
||||
/*
|
||||
@ -3343,7 +3344,7 @@ mjit::Compiler::jsop_name(JSAtom *atom)
|
||||
}
|
||||
|
||||
pic.fastPathRejoin = masm.label();
|
||||
frame.pushRegs(pic.shapeReg, pic.objReg);
|
||||
frame.pushRegs(pic.shapeReg, pic.objReg, knownPushedType(0));
|
||||
|
||||
JS_ASSERT(masm.differenceBetween(pic.fastPathStart, dbgJumpOffset) == SCOPENAME_JUMP_OFFSET);
|
||||
|
||||
@ -3359,7 +3360,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
|
||||
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
if (fe->isNotType(JSVAL_TYPE_OBJECT)) {
|
||||
return jsop_getprop(atom);
|
||||
return jsop_getprop(atom, knownPushedType(0));
|
||||
}
|
||||
|
||||
if (!fe->isTypeKnown()) {
|
||||
@ -3386,7 +3387,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
|
||||
|
||||
pic.fastPathRejoin = masm.label();
|
||||
frame.pop();
|
||||
frame.pushRegs(pic.shapeReg, pic.objReg);
|
||||
frame.pushRegs(pic.shapeReg, pic.objReg, knownPushedType(0));
|
||||
|
||||
JS_ASSERT(masm.differenceBetween(pic.fastPathStart, dbgJumpOffset) == SCOPENAME_JUMP_OFFSET);
|
||||
|
||||
@ -3456,17 +3457,17 @@ mjit::Compiler::jsop_name(JSAtom *atom)
|
||||
{
|
||||
prepareStubCall(Uses(0));
|
||||
stubCall(stubs::Name);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
|
||||
bool
|
||||
mjit::Compiler::jsop_xname(JSAtom *atom)
|
||||
{
|
||||
return jsop_getprop(atom);
|
||||
return jsop_getprop(atom, knownPushedType(0));
|
||||
}
|
||||
|
||||
bool
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck, bool usePropCache)
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType, bool typecheck, bool usePropCache)
|
||||
{
|
||||
jsop_getprop_slow(atom, usePropCache);
|
||||
return true;
|
||||
@ -3515,15 +3516,7 @@ void
|
||||
mjit::Compiler::jsop_getarg(uint32 slot)
|
||||
{
|
||||
Address argument(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, slot));
|
||||
|
||||
JSValueType type = knownArgumentType(slot);
|
||||
if (type != JSVAL_TYPE_UNKNOWN) {
|
||||
RegisterID dataReg = frame.allocReg();
|
||||
masm.loadPayload(argument, dataReg);
|
||||
frame.pushTypedPayload(type, dataReg);
|
||||
} else {
|
||||
frame.push(argument);
|
||||
}
|
||||
frame.push(argument, knownArgumentType(slot));
|
||||
}
|
||||
|
||||
void
|
||||
@ -3540,19 +3533,25 @@ void
|
||||
mjit::Compiler::jsop_this()
|
||||
{
|
||||
Address thisvAddr(JSFrameReg, JSStackFrame::offsetOfThis(fun));
|
||||
frame.push(thisvAddr);
|
||||
|
||||
frame.push(thisvAddr, JSVAL_TYPE_UNKNOWN);
|
||||
|
||||
/*
|
||||
* In strict mode code, we don't wrap 'this'.
|
||||
* In direct-call eval code, we wrapped 'this' before entering the eval.
|
||||
* In global code, 'this' is always an object.
|
||||
*/
|
||||
if (fun && !script->strictModeCode) {
|
||||
JSValueType type = knownThisType();
|
||||
if (fun && !script->strictModeCode && type != JSVAL_TYPE_OBJECT) {
|
||||
Jump notObj = frame.testObject(Assembler::NotEqual, frame.peek(-1));
|
||||
stubcc.linkExit(notObj, Uses(1));
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::This);
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
if (type == JSVAL_TYPE_OBJECT)
|
||||
frame.learnType(frame.peek(-1), type, false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -3637,7 +3636,7 @@ mjit::Compiler::jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index)
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubCall(stub);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
#endif
|
||||
|
||||
PC += JSOP_GNAMEINC_LENGTH;
|
||||
@ -3727,7 +3726,7 @@ mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index)
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubCall(stub);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
#endif
|
||||
|
||||
PC += JSOP_NAMEINC_LENGTH;
|
||||
@ -3751,7 +3750,7 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index)
|
||||
frame.dup();
|
||||
// OBJ OBJ
|
||||
|
||||
if (!jsop_getprop(atom))
|
||||
if (!jsop_getprop(atom, JSVAL_TYPE_UNKNOWN))
|
||||
return false;
|
||||
// OBJ V
|
||||
|
||||
@ -3774,7 +3773,7 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index)
|
||||
frame.dup();
|
||||
// OBJ OBJ
|
||||
|
||||
if (!jsop_getprop(atom))
|
||||
if (!jsop_getprop(atom, JSVAL_TYPE_UNKNOWN))
|
||||
return false;
|
||||
// OBJ V
|
||||
|
||||
@ -3815,7 +3814,7 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index)
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubCall(stub);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
|
||||
PC += JSOP_PROPINC_LENGTH;
|
||||
@ -3836,7 +3835,7 @@ mjit::Compiler::iter(uintN flags)
|
||||
masm.move(Imm32(flags), Registers::ArgReg1);
|
||||
stubCall(stubs::Iter);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(JSVAL_TYPE_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4096,7 +4095,7 @@ mjit::Compiler::jsop_eleminc(JSOp op, VoidStub stub)
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(stub);
|
||||
frame.popn(2);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
|
||||
void
|
||||
@ -4104,7 +4103,7 @@ mjit::Compiler::jsop_getgname_slow(uint32 index)
|
||||
{
|
||||
prepareStubCall(Uses(0));
|
||||
stubCall(stubs::GetGlobalName);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
|
||||
void
|
||||
@ -4202,7 +4201,7 @@ mjit::Compiler::jsop_getgname(uint32 index)
|
||||
JS_ASSERT(mic.patchValueOffset == masm.differenceBetween(mic.load, inlineValueLoadLabel));
|
||||
# endif
|
||||
|
||||
frame.pushRegs(treg, dreg);
|
||||
frame.pushRegs(treg, dreg, knownPushedType(0));
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
mics.append(mic);
|
||||
@ -4220,7 +4219,7 @@ mjit::Compiler::jsop_setgname_slow(uint32 index)
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubCall(STRICT_VARIANT(stubs::SetGlobalName));
|
||||
frame.popn(2);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
|
||||
void
|
||||
@ -4274,6 +4273,9 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
||||
RegisterID dataReg = Registers::ReturnReg;
|
||||
JSValueType typeTag = JSVAL_TYPE_INT32;
|
||||
|
||||
if (!fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE))
|
||||
frame.forgetKnownDouble(fe);
|
||||
|
||||
mic.u.name.typeConst = fe->isTypeKnown();
|
||||
mic.u.name.dataConst = fe->isConstant();
|
||||
|
||||
@ -4335,7 +4337,7 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
||||
if (mic.u.name.typeConst)
|
||||
frame.pushTypedPayload(typeTag, dataReg);
|
||||
else
|
||||
frame.pushRegs(typeReg, dataReg);
|
||||
frame.pushRegs(typeReg, dataReg, knownPushedType(0));
|
||||
}
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
@ -4352,7 +4354,7 @@ mjit::Compiler::jsop_setelem_slow()
|
||||
prepareStubCall(Uses(3));
|
||||
stubCall(STRICT_VARIANT(stubs::SetElem));
|
||||
frame.popn(3);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(JSVAL_TYPE_UNKNOWN);
|
||||
}
|
||||
|
||||
void
|
||||
@ -4361,7 +4363,7 @@ mjit::Compiler::jsop_getelem_slow()
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(stubs::GetElem);
|
||||
frame.popn(2);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
|
||||
void
|
||||
@ -4411,7 +4413,7 @@ mjit::Compiler::jsop_instanceof()
|
||||
/* This is sadly necessary because the error case needs the object. */
|
||||
frame.dup();
|
||||
|
||||
if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false))
|
||||
if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, JSVAL_TYPE_UNKNOWN, false))
|
||||
return false;
|
||||
|
||||
/* Primitive prototypes are invalid. */
|
||||
@ -4471,7 +4473,7 @@ mjit::Compiler::emitEval(uint32 argc)
|
||||
masm.move(Imm32(argc), Registers::ArgReg1);
|
||||
stubCall(stubs::Eval);
|
||||
frame.popn(argc + 2);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4618,7 +4620,7 @@ mjit::Compiler::constructThis()
|
||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, calleeReg);
|
||||
|
||||
// Get callee.prototype.
|
||||
if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false, false))
|
||||
if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, JSVAL_TYPE_UNKNOWN, false, false))
|
||||
return false;
|
||||
|
||||
// Reach into the proto Value and grab a register for its data.
|
||||
@ -4626,10 +4628,13 @@ mjit::Compiler::constructThis()
|
||||
RegisterID protoReg = frame.ownRegForData(protoFe);
|
||||
|
||||
// Now, get the type. If it's not an object, set protoReg to NULL.
|
||||
Jump isNotObject = frame.testObject(Assembler::NotEqual, protoFe);
|
||||
stubcc.linkExitDirect(isNotObject, stubcc.masm.label());
|
||||
stubcc.masm.move(ImmPtr(NULL), protoReg);
|
||||
stubcc.crossJump(stubcc.masm.jump(), masm.label());
|
||||
JS_ASSERT_IF(protoFe->isTypeKnown(), protoFe->isType(JSVAL_TYPE_OBJECT));
|
||||
if (!protoFe->isType(JSVAL_TYPE_OBJECT)) {
|
||||
Jump isNotObject = frame.testObject(Assembler::NotEqual, protoFe);
|
||||
stubcc.linkExitDirect(isNotObject, stubcc.masm.label());
|
||||
stubcc.masm.move(ImmPtr(NULL), protoReg);
|
||||
stubcc.crossJump(stubcc.masm.jump(), masm.label());
|
||||
}
|
||||
|
||||
// Done with the protoFe.
|
||||
frame.pop();
|
||||
@ -4648,19 +4653,52 @@ mjit::Compiler::jsop_callelem_slow()
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(stubs::CallElem);
|
||||
frame.popn(2);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
frame.pushSynced(knownPushedType(1));
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::fixDoubleTypes(Uses uses)
|
||||
{
|
||||
#ifdef JS_TYPE_INFERENCE
|
||||
/*
|
||||
* For any locals or stack values which we know to be integers but are treated as
|
||||
* doubles by the type inference, convert to double. These will be assumed to be
|
||||
* doubles at control flow join points. Skip this for the top 'uses' values on the
|
||||
* stack, which will be popped before branching.
|
||||
*/
|
||||
for (uint32 i = 0; i < script->nfixed; i++) {
|
||||
JSValueType type = knownLocalType(i);
|
||||
if (type == JSVAL_TYPE_DOUBLE) {
|
||||
FrameEntry *fe = frame.getLocal(i);
|
||||
if (!fe->isType(JSVAL_TYPE_DOUBLE))
|
||||
frame.ensureDouble(fe);
|
||||
}
|
||||
}
|
||||
analyze::Bytecode &opinfo = analysis->getCode(PC);
|
||||
for (uint32 i = 0; i < opinfo.stackDepth - uses.nuses; i++) {
|
||||
types::TypeStack *stack = opinfo.inStack;
|
||||
types::TypeSet *types = analysis->getStackTypes(script->nfixed + i, stack);
|
||||
JSValueType type = types->getKnownTypeTag(cx, script, isConstructing);
|
||||
if (type == JSVAL_TYPE_DOUBLE) {
|
||||
FrameEntry *fe = frame.getLocal(script->nfixed + i);
|
||||
if (!fe->isType(JSVAL_TYPE_DOUBLE))
|
||||
frame.ensureDouble(fe);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::restoreAnalysisTypes(uint32 stackDepth)
|
||||
{
|
||||
#ifdef JS_TYPE_INFERENCE
|
||||
/* Restore known types of locals. */
|
||||
/* Restore known types of locals, for join points or after forgetting everything. */
|
||||
for (uint32 i = 0; i < script->nfixed; i++) {
|
||||
JSValueType type = knownLocalType(i);
|
||||
if (type != JSVAL_TYPE_UNKNOWN) {
|
||||
FrameEntry *fe = frame.getLocal(i);
|
||||
JS_ASSERT(!fe->isTypeKnown());
|
||||
frame.learnType(fe, type, false);
|
||||
}
|
||||
}
|
||||
@ -4670,12 +4708,26 @@ mjit::Compiler::restoreAnalysisTypes(uint32 stackDepth)
|
||||
JSValueType type = types->getKnownTypeTag(cx, script, isConstructing);
|
||||
if (type != JSVAL_TYPE_UNKNOWN) {
|
||||
FrameEntry *fe = frame.getLocal(script->nfixed + i);
|
||||
frame.learnType(fe, type, true);
|
||||
JS_ASSERT(!fe->isTypeKnown());
|
||||
frame.learnType(fe, type, type != JSVAL_TYPE_DOUBLE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JSValueType
|
||||
mjit::Compiler::knownThisType()
|
||||
{
|
||||
#ifdef JS_TYPE_INFERENCE
|
||||
if (hasThisType)
|
||||
return thisType;
|
||||
hasThisType = true;
|
||||
thisType = analysis->thisTypes.getKnownTypeTag(cx, script, isConstructing);
|
||||
return thisType;
|
||||
#endif
|
||||
return JSVAL_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
JSValueType
|
||||
mjit::Compiler::knownArgumentType(uint32 arg)
|
||||
{
|
||||
|
@ -291,6 +291,8 @@ class Compiler : public BaseCompiler
|
||||
bool addTraceHints;
|
||||
|
||||
#ifdef JS_TYPE_INFERENCE
|
||||
bool hasThisType;
|
||||
JSValueType thisType;
|
||||
js::Vector<JSValueType, 16> argumentTypes;
|
||||
js::Vector<JSValueType, 16> localTypes;
|
||||
#endif
|
||||
@ -320,7 +322,9 @@ class Compiler : public BaseCompiler
|
||||
CompileStatus finishThisUp(JITScript **jitp);
|
||||
|
||||
/* Analysis helpers. */
|
||||
void fixDoubleTypes(Uses uses);
|
||||
void restoreAnalysisTypes(uint32 stackDepth);
|
||||
JSValueType knownThisType();
|
||||
JSValueType knownArgumentType(uint32 arg);
|
||||
JSValueType knownLocalType(uint32 local);
|
||||
JSValueType knownPushedType(uint32 pushed);
|
||||
@ -340,7 +344,7 @@ class Compiler : public BaseCompiler
|
||||
void iterNext();
|
||||
bool iterMore();
|
||||
void iterEnd();
|
||||
MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg);
|
||||
MaybeJump loadDouble(FrameEntry *fe, FPRegisterID *fpReg, bool *allocated);
|
||||
#ifdef JS_POLYIC
|
||||
void passICAddress(BaseICInfo *ic);
|
||||
#endif
|
||||
@ -348,6 +352,16 @@ class Compiler : public BaseCompiler
|
||||
void passMICAddress(MICGenInfo &mic);
|
||||
#endif
|
||||
bool constructThis();
|
||||
void ensureDouble(FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Ensure fe is an integer, truncating from double if necessary, or jump to
|
||||
* the slow path per uses.
|
||||
*/
|
||||
void ensureInteger(FrameEntry *fe, Uses uses);
|
||||
|
||||
/* Convert fe from a double to integer (per ValueToECMAInt32) in place. */
|
||||
void truncateDoubleToInt32(FrameEntry *fe, Uses uses);
|
||||
|
||||
/* Opcode handlers. */
|
||||
bool jumpAndTrace(Jump j, jsbytecode *target, Jump *slow = NULL);
|
||||
@ -380,7 +394,7 @@ class Compiler : public BaseCompiler
|
||||
void jsop_getelem_slow();
|
||||
void jsop_callelem_slow();
|
||||
void jsop_unbrand();
|
||||
bool jsop_getprop(JSAtom *atom, bool typeCheck = true, bool usePropCache = true);
|
||||
bool jsop_getprop(JSAtom *atom, JSValueType type, bool typeCheck = true, bool usePropCache = true);
|
||||
bool jsop_length();
|
||||
bool jsop_setprop(JSAtom *atom, bool usePropCache = true);
|
||||
void jsop_setprop_slow(JSAtom *atom, bool usePropCache = true);
|
||||
|
@ -226,10 +226,7 @@ mjit::Compiler::jsop_binary(JSOp op, VoidStub stub)
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(stub);
|
||||
frame.popn(2);
|
||||
if (isStringResult)
|
||||
frame.pushSyncedType(JSVAL_TYPE_STRING);
|
||||
else
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : knownPushedType(0));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -270,28 +267,35 @@ EmitDoubleOp(JSOp op, FPRegisterID fpRight, FPRegisterID fpLeft, Assembler &masm
|
||||
}
|
||||
|
||||
mjit::MaybeJump
|
||||
mjit::Compiler::loadDouble(FrameEntry *fe, FPRegisterID fpReg)
|
||||
mjit::Compiler::loadDouble(FrameEntry *fe, FPRegisterID *fpReg, bool *allocated)
|
||||
{
|
||||
MaybeJump notNumber;
|
||||
|
||||
if (!fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
*fpReg = frame.tempFPRegForData(fe);
|
||||
*allocated = false;
|
||||
return notNumber;
|
||||
}
|
||||
|
||||
*fpReg = frame.allocFPReg();
|
||||
*allocated = true;
|
||||
|
||||
if (fe->isConstant()) {
|
||||
slowLoadConstantDouble(masm, fe, fpReg);
|
||||
slowLoadConstantDouble(masm, fe, *fpReg);
|
||||
} else if (!fe->isTypeKnown()) {
|
||||
frame.tempRegForType(fe);
|
||||
Jump j = frame.testDouble(Assembler::Equal, fe);
|
||||
notNumber = frame.testInt32(Assembler::NotEqual, fe);
|
||||
frame.convertInt32ToDouble(masm, fe, fpReg);
|
||||
frame.convertInt32ToDouble(masm, fe, *fpReg);
|
||||
Jump converted = masm.jump();
|
||||
j.linkTo(masm.label(), &masm);
|
||||
// CANDIDATE
|
||||
frame.loadDouble(fe, fpReg, masm);
|
||||
frame.loadDouble(fe, *fpReg, masm);
|
||||
converted.linkTo(masm.label(), &masm);
|
||||
} else if (fe->getKnownType() == JSVAL_TYPE_INT32) {
|
||||
frame.tempRegForData(fe);
|
||||
frame.convertInt32ToDouble(masm, fe, fpReg);
|
||||
} else {
|
||||
JS_ASSERT(fe->getKnownType() == JSVAL_TYPE_DOUBLE);
|
||||
frame.loadDouble(fe, fpReg, masm);
|
||||
JS_ASSERT(fe->isType(JSVAL_TYPE_INT32));
|
||||
frame.tempRegForData(fe);
|
||||
frame.convertInt32ToDouble(masm, fe, *fpReg);
|
||||
}
|
||||
|
||||
return notNumber;
|
||||
@ -304,18 +308,27 @@ mjit::Compiler::loadDouble(FrameEntry *fe, FPRegisterID fpReg)
|
||||
void
|
||||
mjit::Compiler::jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub)
|
||||
{
|
||||
FPRegisterID fpLeft = FPRegisters::First;
|
||||
FPRegisterID fpRight = FPRegisters::Second;
|
||||
FPRegisterID fpLeft, fpRight;
|
||||
bool allocateLeft, allocateRight;
|
||||
|
||||
MaybeJump lhsNotNumber = loadDouble(lhs, fpLeft);
|
||||
MaybeJump lhsNotNumber = loadDouble(lhs, &fpLeft, &allocateLeft);
|
||||
if (lhsNotNumber.isSet())
|
||||
stubcc.linkExit(lhsNotNumber.get(), Uses(2));
|
||||
|
||||
/* The left register holds the result, and needs to be mutable. */
|
||||
if (!allocateLeft) {
|
||||
FPRegisterID res = frame.allocFPReg();
|
||||
masm.moveDouble(fpLeft, res);
|
||||
fpLeft = res;
|
||||
allocateLeft = true;
|
||||
}
|
||||
|
||||
MaybeJump rhsNotNumber;
|
||||
if (frame.haveSameBacking(lhs, rhs)) {
|
||||
masm.moveDouble(fpLeft, fpRight);
|
||||
fpRight = fpLeft;
|
||||
allocateRight = false;
|
||||
} else {
|
||||
rhsNotNumber = loadDouble(rhs, fpRight);
|
||||
rhsNotNumber = loadDouble(rhs, &fpRight, &allocateRight);
|
||||
if (rhsNotNumber.isSet())
|
||||
stubcc.linkExit(rhsNotNumber.get(), Uses(2));
|
||||
}
|
||||
@ -323,13 +336,17 @@ mjit::Compiler::jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, Vo
|
||||
EmitDoubleOp(op, fpRight, fpLeft, masm);
|
||||
|
||||
MaybeJump done;
|
||||
|
||||
JSValueType type = knownPushedType(0);
|
||||
|
||||
/*
|
||||
* Try to convert result to integer. Skip this for 1/x or -1/x, as the
|
||||
* result is unlikely to fit in an int.
|
||||
* Try to convert result to integer, if the result has unknown or integer type.
|
||||
* Skip this for 1/x or -1/x, as the result is unlikely to fit in an int.
|
||||
*/
|
||||
if (op == JSOP_DIV && !(lhs->isConstant() && lhs->isType(JSVAL_TYPE_INT32) &&
|
||||
abs(lhs->getValue().toInt32()) == 1)) {
|
||||
if (op == JSOP_DIV &&
|
||||
(type == JSVAL_TYPE_INT32 ||
|
||||
(type == JSVAL_TYPE_UNKNOWN &&
|
||||
!(lhs->isConstant() && lhs->isType(JSVAL_TYPE_INT32) &&
|
||||
abs(lhs->getValue().toInt32()) == 1)))) {
|
||||
RegisterID reg = frame.allocReg();
|
||||
JumpList isDouble;
|
||||
masm.branchConvertDoubleToInt32(fpLeft, reg, isDouble, fpRight);
|
||||
@ -339,10 +356,21 @@ mjit::Compiler::jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, Vo
|
||||
|
||||
frame.freeReg(reg);
|
||||
done.setJump(masm.jump());
|
||||
|
||||
isDouble.linkTo(masm.label(), &masm);
|
||||
}
|
||||
|
||||
masm.storeDouble(fpLeft, frame.addressOf(lhs));
|
||||
if (type == JSVAL_TYPE_UNKNOWN) {
|
||||
masm.storeDouble(fpLeft, frame.addressOf(lhs));
|
||||
} else if (type == JSVAL_TYPE_INT32) {
|
||||
/*
|
||||
* Integer conversion failed, but the result is expected to be an integer.
|
||||
* Call a stub and try harder to convert to int32, or failing that trigger
|
||||
* recompilation of this script.
|
||||
*/
|
||||
JS_ASSERT(op == JSOP_DIV);
|
||||
stubcc.linkExit(masm.jump(), Uses(2));
|
||||
}
|
||||
|
||||
if (done.isSet())
|
||||
done.getJump().linkTo(masm.label(), &masm);
|
||||
@ -352,8 +380,21 @@ mjit::Compiler::jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, Vo
|
||||
stubcc.call(stub);
|
||||
}
|
||||
|
||||
if (allocateRight)
|
||||
frame.freeFPReg(fpRight);
|
||||
|
||||
frame.popn(2);
|
||||
frame.pushNumber(MaybeRegisterID());
|
||||
|
||||
if (type == JSVAL_TYPE_UNKNOWN) {
|
||||
frame.freeFPReg(fpLeft);
|
||||
frame.pushSynced(type);
|
||||
} else if (type == JSVAL_TYPE_DOUBLE) {
|
||||
frame.pushDouble(fpLeft);
|
||||
} else {
|
||||
JS_ASSERT(op == JSOP_DIV && type == JSVAL_TYPE_INT32);
|
||||
frame.freeFPReg(fpLeft);
|
||||
frame.pushSynced(type);
|
||||
}
|
||||
|
||||
if (lhsNotNumber.isSet() || rhsNotNumber.isSet())
|
||||
stubcc.rejoin(Changes(1));
|
||||
@ -368,11 +409,15 @@ mjit::Compiler::jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub)
|
||||
FrameEntry *lhs = frame.peek(-2);
|
||||
|
||||
/* Easiest case: known double. Don't bother conversion back yet? */
|
||||
if (fe->isTypeKnown() && fe->getKnownType() == JSVAL_TYPE_DOUBLE) {
|
||||
loadDouble(fe, FPRegisters::First);
|
||||
EmitDoubleOp(op, FPRegisters::First, FPRegisters::First, masm);
|
||||
if (fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
FPRegisterID fpreg = frame.allocFPReg();
|
||||
FPRegisterID lhs = frame.tempFPRegForData(fe);
|
||||
masm.moveDouble(lhs, fpreg);
|
||||
EmitDoubleOp(op, fpreg, fpreg, masm);
|
||||
frame.popn(2);
|
||||
frame.pushNumber(MaybeRegisterID());
|
||||
|
||||
JS_ASSERT(knownPushedType(0) == JSVAL_TYPE_DOUBLE);
|
||||
frame.pushDouble(fpreg);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -387,12 +432,12 @@ mjit::Compiler::jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub)
|
||||
stubcc.linkExitDirect(notInt, stubcc.masm.label());
|
||||
|
||||
notNumber = stubcc.masm.testDouble(Assembler::NotEqual, regs.lhsType.reg());
|
||||
frame.loadDouble(fe, FPRegisters::First, stubcc.masm);
|
||||
EmitDoubleOp(op, FPRegisters::First, FPRegisters::First, stubcc.masm);
|
||||
frame.loadDouble(fe, regs.lhsFP, stubcc.masm);
|
||||
EmitDoubleOp(op, regs.lhsFP, regs.lhsFP, stubcc.masm);
|
||||
|
||||
/* Force the double back to memory. */
|
||||
Address result = frame.addressOf(lhs);
|
||||
stubcc.masm.storeDouble(FPRegisters::First, result);
|
||||
stubcc.masm.storeDouble(regs.lhsFP, result);
|
||||
|
||||
/* Load the payload into the result reg so the rejoin is safe. */
|
||||
stubcc.masm.loadPayload(result, regs.result);
|
||||
@ -432,17 +477,17 @@ mjit::Compiler::jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub)
|
||||
{
|
||||
if (regs.lhsNeedsRemat) {
|
||||
Address address = masm.payloadOf(frame.addressForDataRemat(lhs));
|
||||
stubcc.masm.convertInt32ToDouble(address, FPRegisters::First);
|
||||
stubcc.masm.convertInt32ToDouble(address, regs.lhsFP);
|
||||
} else if (!lhs->isConstant()) {
|
||||
stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), FPRegisters::First);
|
||||
stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), regs.lhsFP);
|
||||
} else {
|
||||
slowLoadConstantDouble(stubcc.masm, lhs, FPRegisters::First);
|
||||
slowLoadConstantDouble(stubcc.masm, lhs, regs.lhsFP);
|
||||
}
|
||||
|
||||
EmitDoubleOp(op, FPRegisters::First, FPRegisters::First, stubcc.masm);
|
||||
EmitDoubleOp(op, regs.lhsFP, regs.lhsFP, stubcc.masm);
|
||||
|
||||
Address address = frame.addressOf(lhs);
|
||||
stubcc.masm.storeDouble(FPRegisters::First, address);
|
||||
stubcc.masm.storeDouble(regs.lhsFP, address);
|
||||
stubcc.masm.loadPayload(address, regs.result);
|
||||
|
||||
overflowDone = stubcc.masm.jump();
|
||||
@ -462,11 +507,13 @@ mjit::Compiler::jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub)
|
||||
frame.popn(2);
|
||||
|
||||
JSValueType type = knownPushedType(0);
|
||||
if (type != JSVAL_TYPE_UNKNOWN)
|
||||
if (type == JSVAL_TYPE_INT32)
|
||||
frame.pushTypedPayload(type, regs.result);
|
||||
else
|
||||
frame.pushNumber(regs.result, true);
|
||||
|
||||
frame.freeFPReg(regs.lhsFP);
|
||||
|
||||
/* Merge back OOL double paths. */
|
||||
if (doublePathDone.isSet())
|
||||
stubcc.linkRejoin(doublePathDone.get());
|
||||
@ -527,9 +574,6 @@ mjit::Compiler::jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, Void
|
||||
JS_ASSERT_IF(lhs->isTypeKnown(), lhs->getKnownType() == JSVAL_TYPE_INT32);
|
||||
JS_ASSERT_IF(rhs->isTypeKnown(), rhs->getKnownType() == JSVAL_TYPE_INT32);
|
||||
|
||||
FPRegisterID fpLeft = FPRegisters::First;
|
||||
FPRegisterID fpRight = FPRegisters::Second;
|
||||
|
||||
MaybeJump lhsNotDouble, rhsNotNumber, lhsUnknownDone;
|
||||
if (!lhs->isTypeKnown())
|
||||
emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
|
||||
@ -546,11 +590,11 @@ mjit::Compiler::jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, Void
|
||||
lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
|
||||
/* Perform the double operation. */
|
||||
EmitDoubleOp(op, fpRight, fpLeft, stubcc.masm);
|
||||
EmitDoubleOp(op, regs.rhsFP, regs.lhsFP, stubcc.masm);
|
||||
|
||||
/* Force the double back to memory. */
|
||||
Address result = frame.addressOf(lhs);
|
||||
stubcc.masm.storeDouble(fpLeft, result);
|
||||
stubcc.masm.storeDouble(regs.lhsFP, result);
|
||||
|
||||
/* Load the payload into the result reg so the rejoin is safe. */
|
||||
stubcc.masm.loadPayload(result, regs.result);
|
||||
@ -667,26 +711,26 @@ mjit::Compiler::jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, Void
|
||||
{
|
||||
if (regs.lhsNeedsRemat) {
|
||||
Address address = masm.payloadOf(frame.addressForDataRemat(lhs));
|
||||
stubcc.masm.convertInt32ToDouble(address, fpLeft);
|
||||
stubcc.masm.convertInt32ToDouble(address, regs.lhsFP);
|
||||
} else if (!lhs->isConstant()) {
|
||||
stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), fpLeft);
|
||||
stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), regs.lhsFP);
|
||||
} else {
|
||||
slowLoadConstantDouble(stubcc.masm, lhs, fpLeft);
|
||||
slowLoadConstantDouble(stubcc.masm, lhs, regs.lhsFP);
|
||||
}
|
||||
|
||||
if (regs.rhsNeedsRemat) {
|
||||
Address address = masm.payloadOf(frame.addressForDataRemat(rhs));
|
||||
stubcc.masm.convertInt32ToDouble(address, fpRight);
|
||||
stubcc.masm.convertInt32ToDouble(address, regs.rhsFP);
|
||||
} else if (!rhs->isConstant()) {
|
||||
stubcc.masm.convertInt32ToDouble(regs.rhsData.reg(), fpRight);
|
||||
stubcc.masm.convertInt32ToDouble(regs.rhsData.reg(), regs.rhsFP);
|
||||
} else {
|
||||
slowLoadConstantDouble(stubcc.masm, rhs, fpRight);
|
||||
slowLoadConstantDouble(stubcc.masm, rhs, regs.rhsFP);
|
||||
}
|
||||
|
||||
EmitDoubleOp(op, fpRight, fpLeft, stubcc.masm);
|
||||
EmitDoubleOp(op, regs.rhsFP, regs.lhsFP, stubcc.masm);
|
||||
|
||||
Address address = frame.addressOf(lhs);
|
||||
stubcc.masm.storeDouble(fpLeft, address);
|
||||
stubcc.masm.storeDouble(regs.lhsFP, address);
|
||||
stubcc.masm.loadPayload(address, regs.result);
|
||||
|
||||
overflowDone = stubcc.masm.jump();
|
||||
@ -714,11 +758,14 @@ mjit::Compiler::jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, Void
|
||||
frame.popn(2);
|
||||
|
||||
JSValueType type = knownPushedType(0);
|
||||
if (type != JSVAL_TYPE_UNKNOWN)
|
||||
if (type == JSVAL_TYPE_INT32)
|
||||
frame.pushTypedPayload(type, regs.result);
|
||||
else
|
||||
frame.pushNumber(regs.result, true);
|
||||
|
||||
frame.freeFPReg(regs.lhsFP);
|
||||
frame.freeFPReg(regs.rhsFP);
|
||||
|
||||
/* Merge back OOL double paths. */
|
||||
if (doublePathDone.isSet())
|
||||
stubcc.linkRejoin(doublePathDone.get());
|
||||
@ -729,8 +776,6 @@ mjit::Compiler::jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, Void
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
static const uint64 DoubleNegMask = 0x8000000000000000ULL;
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_neg()
|
||||
{
|
||||
@ -740,12 +785,23 @@ mjit::Compiler::jsop_neg()
|
||||
prepareStubCall(Uses(1));
|
||||
stubCall(stubs::Neg);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
return;
|
||||
}
|
||||
|
||||
JS_ASSERT(!fe->isConstant());
|
||||
|
||||
if (fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
FPRegisterID fpreg = frame.tempFPRegForData(fe);
|
||||
FPRegisterID res = frame.allocFPReg();
|
||||
masm.moveDouble(fpreg, res);
|
||||
masm.negateDouble(res);
|
||||
|
||||
frame.pop();
|
||||
frame.pushDouble(res);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load type information into register. */
|
||||
MaybeRegisterID feTypeReg;
|
||||
if (!fe->isTypeKnown() && !frame.shouldAvoidTypeRemat(fe)) {
|
||||
@ -764,17 +820,13 @@ mjit::Compiler::jsop_neg()
|
||||
{
|
||||
maybeJumpIfNotDouble(masm, jmpNotDbl, fe, feTypeReg);
|
||||
|
||||
FPRegisterID fpreg = frame.copyEntryIntoFPReg(fe, FPRegisters::First);
|
||||
|
||||
#if defined JS_CPU_X86 || defined JS_CPU_X64
|
||||
masm.loadDouble(&DoubleNegMask, FPRegisters::Second);
|
||||
masm.xorDouble(FPRegisters::Second, fpreg);
|
||||
#elif defined JS_CPU_ARM
|
||||
masm.negDouble(fpreg, fpreg);
|
||||
#endif
|
||||
FPRegisterID fpreg = frame.allocFPReg();
|
||||
frame.loadDouble(fe, fpreg, masm);
|
||||
masm.negateDouble(fpreg);
|
||||
|
||||
/* Overwrite pushed frame's memory (before push). */
|
||||
masm.storeDouble(fpreg, frame.addressOf(fe));
|
||||
frame.freeFPReg(fpreg);
|
||||
}
|
||||
|
||||
/* Try an integer path (out-of-line). */
|
||||
@ -808,7 +860,7 @@ mjit::Compiler::jsop_neg()
|
||||
stubcc.call(stubs::Neg);
|
||||
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
|
||||
/* Link jumps. */
|
||||
if (jmpNotDbl.isSet())
|
||||
@ -839,7 +891,7 @@ mjit::Compiler::jsop_mod()
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(stubs::Mod);
|
||||
frame.popn(2);
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -946,7 +998,7 @@ mjit::Compiler::jsop_mod()
|
||||
frame.popn(2);
|
||||
|
||||
JSValueType type = knownPushedType(0);
|
||||
if (type != JSVAL_TYPE_UNKNOWN)
|
||||
if (type == JSVAL_TYPE_INT32)
|
||||
frame.pushTypedPayload(type, X86Registers::edx);
|
||||
else
|
||||
frame.pushNumber(X86Registers::edx);
|
||||
@ -1172,9 +1224,6 @@ mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState:
|
||||
MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
|
||||
MaybeJump &lhsUnknownDone)
|
||||
{
|
||||
FPRegisterID fpLeft = FPRegisters::First;
|
||||
FPRegisterID fpRight = FPRegisters::Second;
|
||||
|
||||
/* 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());
|
||||
@ -1191,9 +1240,9 @@ mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState:
|
||||
|
||||
/* If RHS is constant, convert now. */
|
||||
if (rhs->isConstant())
|
||||
slowLoadConstantDouble(stubcc.masm, rhs, fpRight);
|
||||
slowLoadConstantDouble(stubcc.masm, rhs, regs.rhsFP);
|
||||
else
|
||||
stubcc.masm.convertInt32ToDouble(regs.rhsData.reg(), fpRight);
|
||||
stubcc.masm.convertInt32ToDouble(regs.rhsData.reg(), regs.rhsFP);
|
||||
|
||||
if (!rhs->isTypeKnown()) {
|
||||
/* Jump past double load, bind double type check. */
|
||||
@ -1202,14 +1251,14 @@ mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState:
|
||||
|
||||
/* Load the double. */
|
||||
frame.loadDouble(regs.rhsType.reg(), regs.rhsData.reg(),
|
||||
rhs, fpRight, stubcc.masm);
|
||||
rhs, regs.rhsFP, stubcc.masm);
|
||||
|
||||
converted.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
}
|
||||
|
||||
/* Load the LHS. */
|
||||
frame.loadDouble(regs.lhsType.reg(), regs.lhsData.reg(),
|
||||
lhs, fpLeft, stubcc.masm);
|
||||
lhs, regs.lhsFP, stubcc.masm);
|
||||
lhsUnknownDone = stubcc.masm.jump();
|
||||
}
|
||||
|
||||
@ -1220,9 +1269,6 @@ void
|
||||
mjit::Compiler::emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s,
|
||||
MaybeJump &rhsNotNumber2)
|
||||
{
|
||||
FPRegisterID fpLeft = FPRegisters::First;
|
||||
FPRegisterID fpRight = FPRegisters::Second;
|
||||
|
||||
/* 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());
|
||||
@ -1232,13 +1278,13 @@ mjit::Compiler::emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState
|
||||
|
||||
/* We know LHS is an integer. */
|
||||
if (lhs->isConstant())
|
||||
slowLoadConstantDouble(stubcc.masm, lhs, fpLeft);
|
||||
slowLoadConstantDouble(stubcc.masm, lhs, regs.lhsFP);
|
||||
else
|
||||
stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), fpLeft);
|
||||
stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), regs.lhsFP);
|
||||
|
||||
/* Load the RHS. */
|
||||
frame.loadDouble(regs.rhsType.reg(), regs.rhsData.reg(),
|
||||
rhs, fpRight, stubcc.masm);
|
||||
rhs, regs.rhsFP, stubcc.masm);
|
||||
}
|
||||
|
||||
static inline Assembler::DoubleCondition
|
||||
@ -1274,13 +1320,18 @@ mjit::Compiler::jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *targe
|
||||
FrameEntry *rhs = frame.peek(-1);
|
||||
FrameEntry *lhs = frame.peek(-2);
|
||||
|
||||
FPRegisterID fpLeft = FPRegisters::First;
|
||||
FPRegisterID fpRight = FPRegisters::Second;
|
||||
|
||||
JS_ASSERT_IF(!target, fused != JSOP_IFEQ);
|
||||
|
||||
MaybeJump lhsNotNumber = loadDouble(lhs, fpLeft);
|
||||
MaybeJump rhsNotNumber = loadDouble(rhs, fpRight);
|
||||
FPRegisterID fpLeft, fpRight;
|
||||
bool allocateLeft, allocateRight;
|
||||
|
||||
MaybeJump lhsNotNumber = loadDouble(lhs, &fpLeft, &allocateLeft);
|
||||
if (!allocateLeft)
|
||||
frame.pinFPReg(fpLeft);
|
||||
|
||||
MaybeJump rhsNotNumber = loadDouble(rhs, &fpRight, &allocateRight);
|
||||
if (!allocateLeft)
|
||||
frame.unpinFPReg(fpLeft);
|
||||
|
||||
Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused);
|
||||
|
||||
@ -1337,7 +1388,13 @@ mjit::Compiler::jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *targe
|
||||
frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
|
||||
if (allocateLeft)
|
||||
frame.freeFPReg(fpLeft);
|
||||
if (allocateRight)
|
||||
frame.freeFPReg(fpRight);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1366,9 +1423,6 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
|
||||
FrameState::BinaryAlloc regs;
|
||||
frame.allocForBinary(lhs, rhs, op, regs, !target);
|
||||
|
||||
FPRegisterID fpLeft = FPRegisters::First;
|
||||
FPRegisterID fpRight = FPRegisters::Second;
|
||||
|
||||
MaybeJump lhsNotDouble, rhsNotNumber, lhsUnknownDone;
|
||||
if (!lhs->isTypeKnown())
|
||||
emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
|
||||
@ -1434,7 +1488,7 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
|
||||
if (lhsUnknownDone.isSet())
|
||||
lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
frame.sync(stubcc.masm, Uses(frame.frameDepth()));
|
||||
doubleTest = stubcc.masm.branchDouble(dblCond, fpLeft, fpRight);
|
||||
doubleTest = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
|
||||
doubleFall = stubcc.masm.jump();
|
||||
|
||||
/* Link all incoming slow paths to here. */
|
||||
@ -1538,7 +1592,7 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
|
||||
if (lhsUnknownDone.isSet())
|
||||
lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
/* :FIXME: Use SET if we can? */
|
||||
Jump test = stubcc.masm.branchDouble(dblCond, fpLeft, fpRight);
|
||||
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);
|
||||
@ -1606,7 +1660,11 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
|
||||
if (hasDoublePath)
|
||||
stubcc.crossJump(doubleDone.get(), masm.label());
|
||||
stubcc.rejoin(Changes(1));
|
||||
|
||||
frame.freeFPReg(regs.lhsFP);
|
||||
frame.freeFPReg(regs.rhsFP);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -115,136 +115,45 @@ mjit::Compiler::jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs)
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs)
|
||||
mjit::Compiler::ensureInteger(FrameEntry *fe, Uses uses)
|
||||
{
|
||||
int32 shiftAmount = rhs->getValue().toInt32();
|
||||
if (fe->isConstant()) {
|
||||
if (!fe->isType(JSVAL_TYPE_INT32)) {
|
||||
JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
fe->convertConstantDoubleToInt32(cx);
|
||||
}
|
||||
} else if (fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
FPRegisterID fpreg = frame.tempFPRegForData(fe);
|
||||
|
||||
RegisterID lhsType = frame.tempRegForType(lhs);
|
||||
frame.pinReg(lhsType);
|
||||
RegisterID lhsData = frame.copyDataIntoReg(lhs);
|
||||
frame.unpinReg(lhsType);
|
||||
RegisterID data = frame.allocReg();
|
||||
Jump truncateGuard = masm.branchTruncateDoubleToInt32(fpreg, data);
|
||||
stubcc.linkExit(truncateGuard, uses);
|
||||
|
||||
Jump lhsIntGuard = masm.testInt32(Assembler::NotEqual, lhsType);
|
||||
stubcc.linkExitDirect(lhsIntGuard, stubcc.masm.label());
|
||||
frame.learnType(fe, JSVAL_TYPE_INT32, data);
|
||||
} else if (!fe->isType(JSVAL_TYPE_INT32)) {
|
||||
RegisterID typeReg = frame.tempRegForType(fe);
|
||||
frame.pinReg(typeReg);
|
||||
RegisterID dataReg = frame.tempRegForData(fe);
|
||||
frame.pinReg(dataReg);
|
||||
RegisterID scratchReg = frame.allocReg();
|
||||
frame.unpinReg(dataReg);
|
||||
frame.unpinReg(typeReg);
|
||||
|
||||
Jump lhsDoubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, lhsType);
|
||||
frame.loadDouble(lhs, FPRegisters::First, stubcc.masm);
|
||||
Jump lhsTruncateGuard = stubcc.masm.branchTruncateDoubleToInt32(FPRegisters::First, lhsData);
|
||||
stubcc.crossJump(stubcc.masm.jump(), masm.label());
|
||||
Jump intGuard = masm.testInt32(Assembler::Equal, typeReg);
|
||||
Jump doubleGuard = masm.testDouble(Assembler::NotEqual, typeReg);
|
||||
stubcc.linkExit(doubleGuard, uses);
|
||||
|
||||
lhsDoubleGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
lhsTruncateGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
FPRegisterID fpreg = frame.allocFPReg();
|
||||
frame.loadDouble(fe, fpreg, masm);
|
||||
Jump truncateGuard = masm.branchTruncateDoubleToInt32(fpreg, scratchReg);
|
||||
stubcc.linkExit(truncateGuard, uses);
|
||||
masm.move(scratchReg, dataReg);
|
||||
intGuard.linkTo(masm.label(), &masm);
|
||||
|
||||
frame.sync(stubcc.masm, Uses(2));
|
||||
stubcc.call(stubs::Rsh);
|
||||
|
||||
if (shiftAmount)
|
||||
masm.rshift32(Imm32(shiftAmount), lhsData);
|
||||
|
||||
frame.popn(2);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData);
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs)
|
||||
{
|
||||
RegisterID rhsData = rightRegForShift(rhs);
|
||||
RegisterID rhsType = frame.tempRegForType(rhs);
|
||||
frame.pinReg(rhsType);
|
||||
RegisterID result = frame.allocReg();
|
||||
frame.unpinReg(rhsType);
|
||||
|
||||
Jump rhsIntGuard = masm.testInt32(Assembler::NotEqual, rhsType);
|
||||
stubcc.linkExit(rhsIntGuard, Uses(2));
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::Rsh);
|
||||
masm.move(Imm32(lhs->getValue().toInt32()), result);
|
||||
masm.rshift32(rhsData, result);
|
||||
frame.freeReg(rhsData);
|
||||
|
||||
frame.popn(2);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, result);
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs)
|
||||
{
|
||||
RegisterID rhsData = rightRegForShift(rhs);
|
||||
RegisterID rhsType = frame.tempRegForType(rhs);
|
||||
frame.pinReg(rhsType);
|
||||
RegisterID lhsData = frame.copyDataIntoReg(lhs);
|
||||
frame.unpinReg(rhsType);
|
||||
|
||||
Jump rhsIntGuard = masm.testInt32(Assembler::NotEqual, rhsType);
|
||||
stubcc.linkExit(rhsIntGuard, Uses(2));
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::Rsh);
|
||||
|
||||
masm.rshift32(rhsData, lhsData);
|
||||
frame.freeReg(rhsData);
|
||||
frame.popn(2);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData);
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_rsh_unknown_any(FrameEntry *lhs, FrameEntry *rhs)
|
||||
{
|
||||
JS_ASSERT(!lhs->isTypeKnown());
|
||||
JS_ASSERT(!rhs->isNotType(JSVAL_TYPE_INT32));
|
||||
|
||||
/* Allocate registers. */
|
||||
RegisterID rhsData = rightRegForShift(rhs);
|
||||
|
||||
MaybeRegisterID rhsType;
|
||||
if (!rhs->isTypeKnown()) {
|
||||
rhsType.setReg(frame.tempRegForType(rhs));
|
||||
frame.pinReg(rhsType.reg());
|
||||
frame.freeFPReg(fpreg);
|
||||
frame.freeReg(scratchReg);
|
||||
frame.learnType(fe, JSVAL_TYPE_INT32);
|
||||
}
|
||||
|
||||
RegisterID lhsData = frame.copyDataIntoReg(lhs);
|
||||
MaybeRegisterID lhsType;
|
||||
if (rhsType.isSet() && frame.haveSameBacking(lhs, rhs))
|
||||
lhsType = rhsType;
|
||||
else
|
||||
lhsType = frame.tempRegForType(lhs);
|
||||
|
||||
/* Non-integer rhs jumps to stub. */
|
||||
MaybeJump rhsIntGuard;
|
||||
if (rhsType.isSet()) {
|
||||
rhsIntGuard.setJump(masm.testInt32(Assembler::NotEqual, rhsType.reg()));
|
||||
frame.unpinReg(rhsType.reg());
|
||||
}
|
||||
|
||||
/* Non-integer lhs jumps to double guard. */
|
||||
Jump lhsIntGuard = masm.testInt32(Assembler::NotEqual, lhsType.reg());
|
||||
stubcc.linkExitDirect(lhsIntGuard, stubcc.masm.label());
|
||||
|
||||
/* Attempt to convert lhs double to int32. */
|
||||
Jump lhsDoubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, lhsType.reg());
|
||||
frame.loadDouble(lhs, FPRegisters::First, stubcc.masm);
|
||||
Jump lhsTruncateGuard = stubcc.masm.branchTruncateDoubleToInt32(FPRegisters::First, lhsData);
|
||||
stubcc.crossJump(stubcc.masm.jump(), masm.label());
|
||||
|
||||
lhsDoubleGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
lhsTruncateGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
|
||||
if (rhsIntGuard.isSet())
|
||||
stubcc.linkExitDirect(rhsIntGuard.getJump(), stubcc.masm.label());
|
||||
frame.sync(stubcc.masm, Uses(2));
|
||||
stubcc.call(stubs::Rsh);
|
||||
|
||||
masm.rshift32(rhsData, lhsData);
|
||||
|
||||
frame.freeReg(rhsData);
|
||||
frame.popn(2);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData);
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
void
|
||||
@ -256,33 +165,31 @@ mjit::Compiler::jsop_rsh()
|
||||
if (tryBinaryConstantFold(cx, frame, JSOP_RSH, lhs, rhs))
|
||||
return;
|
||||
|
||||
if (lhs->isNotType(JSVAL_TYPE_INT32) || rhs->isNotType(JSVAL_TYPE_INT32)) {
|
||||
if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
|
||||
(rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE))) {
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(stubs::Rsh);
|
||||
frame.popn(2);
|
||||
frame.pushSyncedType(JSVAL_TYPE_INT32);
|
||||
frame.pushSynced(JSVAL_TYPE_INT32);
|
||||
return;
|
||||
}
|
||||
|
||||
ensureInteger(lhs, Uses(2));
|
||||
ensureInteger(rhs, Uses(2));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::Rsh);
|
||||
|
||||
JS_ASSERT(!(lhs->isConstant() && rhs->isConstant()));
|
||||
if (lhs->isConstant()) {
|
||||
if (rhs->isType(JSVAL_TYPE_INT32))
|
||||
jsop_rsh_const_int(lhs, rhs);
|
||||
else
|
||||
jsop_rsh_const_unknown(lhs, rhs);
|
||||
jsop_rsh_const_int(lhs, rhs);
|
||||
} else if (rhs->isConstant()) {
|
||||
if (lhs->isType(JSVAL_TYPE_INT32))
|
||||
jsop_rsh_int_const(lhs, rhs);
|
||||
else
|
||||
jsop_rsh_unknown_const(lhs, rhs);
|
||||
jsop_rsh_int_const(lhs, rhs);
|
||||
} else {
|
||||
if (lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32))
|
||||
jsop_rsh_int_int(lhs, rhs);
|
||||
else if (lhs->isType(JSVAL_TYPE_INT32))
|
||||
jsop_rsh_int_unknown(lhs, rhs);
|
||||
else
|
||||
jsop_rsh_unknown_any(lhs, rhs);
|
||||
jsop_rsh_int_int(lhs, rhs);
|
||||
}
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
void
|
||||
@ -295,7 +202,7 @@ mjit::Compiler::jsop_bitnot()
|
||||
prepareStubCall(Uses(1));
|
||||
stubCall(stubs::BitNot);
|
||||
frame.pop();
|
||||
frame.pushSyncedType(JSVAL_TYPE_INT32);
|
||||
frame.pushSynced(JSVAL_TYPE_INT32);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -357,60 +264,32 @@ mjit::Compiler::jsop_bitop(JSOp op)
|
||||
if (!lhs->isConstant() && rhs->isConstant() && lhsIntOrDouble &&
|
||||
rhs->isType(JSVAL_TYPE_INT32) && rhs->getValue().toInt32() == 0 &&
|
||||
(op == JSOP_BITOR || op == JSOP_LSH)) {
|
||||
ensureInteger(lhs, Uses(2));
|
||||
RegisterID reg = frame.copyDataIntoReg(lhs);
|
||||
if (lhs->isType(JSVAL_TYPE_INT32)) {
|
||||
frame.popn(2);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
||||
return;
|
||||
}
|
||||
MaybeJump isInt;
|
||||
if (!lhs->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
RegisterID typeReg = frame.tempRegForType(lhs);
|
||||
isInt = masm.testInt32(Assembler::Equal, typeReg);
|
||||
Jump notDouble = masm.testDouble(Assembler::NotEqual, typeReg);
|
||||
stubcc.linkExit(notDouble, Uses(2));
|
||||
}
|
||||
frame.loadDouble(lhs, FPRegisters::First, masm);
|
||||
|
||||
Jump truncateGuard = masm.branchTruncateDoubleToInt32(FPRegisters::First, reg);
|
||||
stubcc.linkExit(truncateGuard, Uses(2));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.call(stub);
|
||||
|
||||
if (isInt.isSet())
|
||||
isInt.get().linkTo(masm.label(), &masm);
|
||||
|
||||
frame.popn(2);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
return;
|
||||
}
|
||||
|
||||
/* We only want to handle integers here. */
|
||||
if (rhs->isNotType(JSVAL_TYPE_INT32) || lhs->isNotType(JSVAL_TYPE_INT32) ||
|
||||
if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
|
||||
(rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
|
||||
(op == JSOP_URSH && rhs->isConstant() && rhs->getValue().toInt32() % 32 == 0)) {
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(stub);
|
||||
frame.popn(2);
|
||||
if (op == JSOP_URSH)
|
||||
frame.pushSynced();
|
||||
else
|
||||
frame.pushSyncedType(JSVAL_TYPE_INT32);
|
||||
frame.pushSynced(op != JSOP_URSH ? JSVAL_TYPE_INT32 : knownPushedType(0));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test the types. */
|
||||
bool stubNeeded = false;
|
||||
if (!rhs->isTypeKnown()) {
|
||||
Jump rhsFail = frame.testInt32(Assembler::NotEqual, rhs);
|
||||
stubcc.linkExit(rhsFail, Uses(2));
|
||||
frame.learnType(rhs, JSVAL_TYPE_INT32);
|
||||
stubNeeded = true;
|
||||
}
|
||||
if (!lhs->isTypeKnown() && !frame.haveSameBacking(lhs, rhs)) {
|
||||
Jump lhsFail = frame.testInt32(Assembler::NotEqual, lhs);
|
||||
stubcc.linkExit(lhsFail, Uses(2));
|
||||
stubNeeded = true;
|
||||
}
|
||||
|
||||
ensureInteger(lhs, Uses(2));
|
||||
ensureInteger(rhs, Uses(2));
|
||||
|
||||
if (lhs->isConstant() && rhs->isConstant()) {
|
||||
int32 L = lhs->getValue().toInt32();
|
||||
@ -495,25 +374,22 @@ mjit::Compiler::jsop_bitop(JSOp op)
|
||||
RegisterID reg = frame.ownRegForData(lhs);
|
||||
int shift = rhs->getValue().toInt32() & 0x1F;
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.call(stub);
|
||||
|
||||
if (shift) {
|
||||
if (op == JSOP_LSH)
|
||||
masm.lshift32(Imm32(shift), reg);
|
||||
else
|
||||
masm.urshift32(Imm32(shift), reg);
|
||||
}
|
||||
if (stubNeeded) {
|
||||
stubcc.leave();
|
||||
stubcc.call(stub);
|
||||
}
|
||||
frame.popn(2);
|
||||
|
||||
/* x >>> 0 may result in a double, handled above. */
|
||||
JS_ASSERT_IF(op == JSOP_URSH, shift >= 1);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
||||
|
||||
if (stubNeeded)
|
||||
stubcc.rejoin(Changes(1));
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
return;
|
||||
}
|
||||
#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
|
||||
@ -548,7 +424,6 @@ mjit::Compiler::jsop_bitop(JSOp op)
|
||||
|
||||
Jump isNegative = masm.branch32(Assembler::LessThan, reg, Imm32(0));
|
||||
stubcc.linkExit(isNegative, Uses(2));
|
||||
stubNeeded = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -558,31 +433,29 @@ mjit::Compiler::jsop_bitop(JSOp op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (stubNeeded) {
|
||||
stubcc.leave();
|
||||
stubcc.call(stub);
|
||||
}
|
||||
stubcc.leave();
|
||||
stubcc.call(stub);
|
||||
|
||||
frame.pop();
|
||||
frame.pop();
|
||||
|
||||
JSValueType type = knownPushedType(0);
|
||||
|
||||
if (type != JSVAL_TYPE_UNKNOWN)
|
||||
if (type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE)
|
||||
frame.pushTypedPayload(type, reg);
|
||||
else if (op == JSOP_URSH)
|
||||
frame.pushNumber(reg, true);
|
||||
else
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
||||
|
||||
if (stubNeeded)
|
||||
stubcc.rejoin(Changes(1));
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_globalinc(JSOp op, uint32 index)
|
||||
{
|
||||
uint32 slot = script->getGlobalSlot(index);
|
||||
JSValueType type = knownPushedType(0);
|
||||
|
||||
bool popped = false;
|
||||
PC += JSOP_GLOBALINC_LENGTH;
|
||||
@ -599,15 +472,22 @@ mjit::Compiler::jsop_globalinc(JSOp op, uint32 index)
|
||||
Address addr = masm.objSlotRef(globalObj, reg, slot);
|
||||
uint32 depth = frame.stackDepth();
|
||||
|
||||
if (post && !popped) {
|
||||
frame.push(addr);
|
||||
if (type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_INT32) {
|
||||
data = frame.allocReg();
|
||||
stubcc.linkExit(masm.jump(), Uses(0));
|
||||
} else if (post && !popped) {
|
||||
frame.push(addr, type);
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
Jump notInt = frame.testInt32(Assembler::NotEqual, fe);
|
||||
stubcc.linkExit(notInt, Uses(0));
|
||||
if (type == JSVAL_TYPE_UNKNOWN) {
|
||||
Jump notInt = frame.testInt32(Assembler::NotEqual, fe);
|
||||
stubcc.linkExit(notInt, Uses(0));
|
||||
}
|
||||
data = frame.copyDataIntoReg(fe);
|
||||
} else {
|
||||
Jump notInt = masm.testInt32(Assembler::NotEqual, addr);
|
||||
stubcc.linkExit(notInt, Uses(0));
|
||||
if (type == JSVAL_TYPE_UNKNOWN) {
|
||||
Jump notInt = masm.testInt32(Assembler::NotEqual, addr);
|
||||
stubcc.linkExit(notInt, Uses(0));
|
||||
}
|
||||
data = frame.allocReg();
|
||||
masm.loadPayload(addr, data);
|
||||
}
|
||||
@ -933,7 +813,8 @@ mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target)
|
||||
|
||||
if (!fe->isTypeKnown() && !frame.shouldAvoidTypeRemat(fe))
|
||||
type.setReg(frame.copyTypeIntoReg(fe));
|
||||
data.setReg(frame.copyDataIntoReg(fe));
|
||||
if (!fe->isType(JSVAL_TYPE_DOUBLE))
|
||||
data.setReg(frame.copyDataIntoReg(fe));
|
||||
|
||||
frame.syncAndForgetEverything();
|
||||
|
||||
@ -963,7 +844,8 @@ mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target)
|
||||
* TODO: We don't need the second jump if
|
||||
* jumpInScript() can go from ool path to inline path.
|
||||
*/
|
||||
jmpNotExecScript.setJump(masm.branchTest32(ncond, data.reg(), data.reg()));
|
||||
if (!fe->isType(JSVAL_TYPE_DOUBLE))
|
||||
jmpNotExecScript.setJump(masm.branchTest32(ncond, data.reg(), data.reg()));
|
||||
Label lblExecScript = masm.label();
|
||||
Jump j = masm.jump();
|
||||
|
||||
@ -1061,7 +943,7 @@ mjit::Compiler::jsop_localinc(JSOp op, uint32 slot, bool popped)
|
||||
bool post = (op == JSOP_LOCALINC || op == JSOP_LOCALDEC);
|
||||
int32 amt = (op == JSOP_INCLOCAL || op == JSOP_LOCALINC) ? 1 : -1;
|
||||
|
||||
frame.pushLocal(slot);
|
||||
frame.pushLocal(slot, knownPushedType(0));
|
||||
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
|
||||
@ -1140,14 +1022,18 @@ mjit::Compiler::jsop_localinc(JSOp op, uint32 slot, bool popped)
|
||||
else
|
||||
stubcc.call(stubs::DecLocal);
|
||||
|
||||
JSValueType type = knownLocalType(slot);
|
||||
|
||||
frame.pop();
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
||||
frame.storeLocal(slot, popped, false);
|
||||
|
||||
if (type == JSVAL_TYPE_INT32)
|
||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
||||
else
|
||||
frame.pushNumber(reg, true);
|
||||
frame.storeLocal(slot, popped, type);
|
||||
|
||||
if (popped)
|
||||
frame.pop();
|
||||
else
|
||||
frame.forgetType(frame.peek(-1));
|
||||
|
||||
stubcc.rejoin(Changes(0));
|
||||
}
|
||||
@ -1534,7 +1420,7 @@ mjit::Compiler::jsop_getelem_dense(bool isPacked)
|
||||
RegisterID dataReg = frame.allocReg();
|
||||
|
||||
MaybeRegisterID typeReg;
|
||||
if (!isPacked || type == JSVAL_TYPE_UNKNOWN)
|
||||
if (!isPacked || type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_DOUBLE)
|
||||
typeReg = frame.allocReg();
|
||||
|
||||
frame.unpinReg(objReg);
|
||||
@ -1561,7 +1447,7 @@ mjit::Compiler::jsop_getelem_dense(bool isPacked)
|
||||
|
||||
if (!isPacked) {
|
||||
stubcc.linkExit(holeCheck, Uses(2));
|
||||
if (type != JSVAL_TYPE_UNKNOWN)
|
||||
if (type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE)
|
||||
frame.freeReg(typeReg.reg());
|
||||
}
|
||||
|
||||
@ -1570,10 +1456,10 @@ mjit::Compiler::jsop_getelem_dense(bool isPacked)
|
||||
|
||||
frame.popn(2);
|
||||
|
||||
if (type != JSVAL_TYPE_UNKNOWN)
|
||||
frame.pushTypedPayload(type, dataReg);
|
||||
if (type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_DOUBLE)
|
||||
frame.pushRegs(typeReg.reg(), dataReg, type);
|
||||
else
|
||||
frame.pushRegs(typeReg.reg(), dataReg);
|
||||
frame.pushTypedPayload(type, dataReg);
|
||||
|
||||
stubcc.rejoin(Changes(2));
|
||||
}
|
||||
@ -1714,9 +1600,9 @@ mjit::Compiler::jsop_getelem(bool isCall)
|
||||
ic.fastPathRejoin = masm.label();
|
||||
|
||||
frame.popn(2);
|
||||
frame.pushRegs(ic.typeReg, ic.objReg);
|
||||
frame.pushRegs(ic.typeReg, ic.objReg, knownPushedType(0));
|
||||
if (isCall)
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(1));
|
||||
|
||||
stubcc.rejoin(Changes(2));
|
||||
|
||||
@ -1887,7 +1773,7 @@ mjit::Compiler::jsop_stricteq(JSOp op)
|
||||
stubCall(stubs::StrictNe);
|
||||
|
||||
frame.popn(2);
|
||||
frame.pushSyncedType(JSVAL_TYPE_BOOLEAN);
|
||||
frame.pushSynced(JSVAL_TYPE_BOOLEAN);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1972,7 +1858,7 @@ mjit::Compiler::jsop_pos()
|
||||
prepareStubCall(Uses(1));
|
||||
stubCall(stubs::Pos);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
frame.pushSynced(knownPushedType(0));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
#define jsjaeger_valueinfo_h__
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsnum.h"
|
||||
#include "methodjit/MachineRegs.h"
|
||||
#include "methodjit/RematInfo.h"
|
||||
#include "assembler/assembler/MacroAssembler.h"
|
||||
@ -72,6 +73,10 @@ class FrameEntry
|
||||
return type.isConstant();
|
||||
}
|
||||
|
||||
/*
|
||||
* The known type should not be used in generated code if it is JSVAL_TYPE_DOUBLE.
|
||||
* In such cases either the value is constant, in memory or in a floating point register.
|
||||
*/
|
||||
JSValueType getKnownType() const {
|
||||
JS_ASSERT(isTypeKnown());
|
||||
return knownType;
|
||||
@ -79,6 +84,7 @@ class FrameEntry
|
||||
|
||||
#if defined JS_NUNBOX32
|
||||
JSValueTag getKnownTag() const {
|
||||
JS_ASSERT(v_.s.tag != JSVAL_TAG_CLEAR);
|
||||
return v_.s.tag;
|
||||
}
|
||||
#elif defined JS_PUNBOX64
|
||||
@ -114,14 +120,20 @@ class FrameEntry
|
||||
}
|
||||
#endif
|
||||
|
||||
bool isCachedNumber() const {
|
||||
return isNumber;
|
||||
}
|
||||
|
||||
bool hasSameBacking(const FrameEntry *other) const {
|
||||
return backing() == other->backing();
|
||||
}
|
||||
|
||||
/* For a constant double FrameEntry, truncate to an int32. */
|
||||
void convertConstantDoubleToInt32(JSContext *cx) {
|
||||
JS_ASSERT(isType(JSVAL_TYPE_DOUBLE) && isConstant());
|
||||
int32 value;
|
||||
ValueToECMAInt32(cx, getValue(), &value);
|
||||
|
||||
Value newValue = Int32Value(value);
|
||||
setConstant(Jsvalify(newValue));
|
||||
}
|
||||
|
||||
private:
|
||||
void setType(JSValueType type_) {
|
||||
type.setConstant();
|
||||
@ -132,7 +144,6 @@ class FrameEntry
|
||||
v_.asBits |= JSVAL_TYPE_TO_SHIFTED_TAG(type_);
|
||||
#endif
|
||||
knownType = type_;
|
||||
JS_ASSERT(!isNumber);
|
||||
}
|
||||
|
||||
void track(uint32 index) {
|
||||
@ -144,7 +155,6 @@ class FrameEntry
|
||||
void clear() {
|
||||
copied = false;
|
||||
copy = NULL;
|
||||
isNumber = false;
|
||||
}
|
||||
|
||||
uint32 trackerIndex() {
|
||||
@ -242,9 +252,8 @@ class FrameEntry
|
||||
uint32 index_;
|
||||
FrameEntry *copy;
|
||||
bool copied;
|
||||
bool isNumber;
|
||||
bool tracked;
|
||||
char padding[1];
|
||||
char padding[2];
|
||||
};
|
||||
|
||||
} /* namespace mjit */
|
||||
|
@ -126,6 +126,20 @@ FrameState::allocReg(FrameEntry *fe, RematInfo::RematType type)
|
||||
return reg;
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::FPRegisterID
|
||||
FrameState::allocFPReg()
|
||||
{
|
||||
FPRegisterID reg;
|
||||
if (!freeFPRegs.empty()) {
|
||||
reg = freeFPRegs.takeAnyReg();
|
||||
} else {
|
||||
reg = evictSomeFPReg();
|
||||
fpregstate[reg].forget();
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::convertInt32ToDouble(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg) const
|
||||
{
|
||||
@ -168,6 +182,14 @@ FrameState::freeReg(RegisterID reg)
|
||||
freeRegs.putReg(reg);
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::freeFPReg(FPRegisterID reg)
|
||||
{
|
||||
JS_ASSERT(!fpregstate[reg].usedBy());
|
||||
|
||||
freeFPRegs.putReg(reg);
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::forgetReg(RegisterID reg)
|
||||
{
|
||||
@ -183,6 +205,16 @@ FrameState::forgetReg(RegisterID reg)
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::forgetFPReg(FPRegisterID reg)
|
||||
{
|
||||
JS_ASSERT_IF(fpregstate[reg].fe(), !fpregstate[reg].fe()->isCopy());
|
||||
JS_ASSERT(!fpregstate[reg].isPinned());
|
||||
|
||||
fpregstate[reg].forget();
|
||||
freeFPRegs.putReg(reg);
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::syncAndForgetEverything(uint32 newStackDepth)
|
||||
{
|
||||
@ -209,20 +241,16 @@ FrameState::push(const Value &v)
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::pushSynced()
|
||||
{
|
||||
if (sp->isTracked())
|
||||
sp->resetSynced();
|
||||
sp++;
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::pushSyncedType(JSValueType type)
|
||||
FrameState::pushSynced(JSValueType type)
|
||||
{
|
||||
FrameEntry *fe = rawPush();
|
||||
|
||||
fe->resetSynced();
|
||||
fe->setType(type);
|
||||
if (type != JSVAL_TYPE_UNKNOWN) {
|
||||
fe->setType(type);
|
||||
if (type == JSVAL_TYPE_DOUBLE)
|
||||
ensureInMemoryDouble(fe, masm);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -239,8 +267,15 @@ FrameState::pushSynced(JSValueType type, RegisterID reg)
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::push(Address address)
|
||||
FrameState::push(Address address, JSValueType knownType)
|
||||
{
|
||||
if (knownType == JSVAL_TYPE_DOUBLE) {
|
||||
FPRegisterID fpreg = allocFPReg();
|
||||
masm.moveInt32OrDouble(address, fpreg);
|
||||
pushDouble(fpreg);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef JS_PUNBOX64
|
||||
// It's okay if either of these clobbers address.base, since we guarantee
|
||||
// eviction will not physically clobber. It's also safe, on x64, for
|
||||
@ -268,26 +303,37 @@ FrameState::push(Address address)
|
||||
masm.loadPayload(address, dataReg);
|
||||
#endif
|
||||
|
||||
pushRegs(typeReg, dataReg);
|
||||
pushRegs(typeReg, dataReg, knownType);
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::pushRegs(RegisterID type, RegisterID data)
|
||||
FrameState::pushRegs(RegisterID type, RegisterID data, JSValueType knownType)
|
||||
{
|
||||
JS_ASSERT(!freeRegs.hasReg(type) && !freeRegs.hasReg(data));
|
||||
|
||||
FrameEntry *fe = rawPush();
|
||||
|
||||
fe->resetUnsynced();
|
||||
fe->type.setRegister(type);
|
||||
fe->data.setRegister(data);
|
||||
regstate[type].associate(fe, RematInfo::TYPE);
|
||||
regstate[data].associate(fe, RematInfo::DATA);
|
||||
if (knownType == JSVAL_TYPE_UNKNOWN) {
|
||||
FrameEntry *fe = rawPush();
|
||||
fe->resetUnsynced();
|
||||
fe->type.setRegister(type);
|
||||
fe->data.setRegister(data);
|
||||
regstate[type].associate(fe, RematInfo::TYPE);
|
||||
regstate[data].associate(fe, RematInfo::DATA);
|
||||
} else if (knownType == JSVAL_TYPE_DOUBLE) {
|
||||
FPRegisterID fpreg = allocFPReg();
|
||||
masm.moveInt32OrDouble(data, type, addressOf(sp), fpreg);
|
||||
pushDouble(fpreg);
|
||||
freeReg(type);
|
||||
freeReg(data);
|
||||
} else {
|
||||
freeReg(type);
|
||||
pushTypedPayload(knownType, data);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::pushTypedPayload(JSValueType type, RegisterID payload)
|
||||
{
|
||||
JS_ASSERT(type != JSVAL_TYPE_DOUBLE);
|
||||
JS_ASSERT(!freeRegs.hasReg(payload));
|
||||
|
||||
FrameEntry *fe = rawPush();
|
||||
@ -299,15 +345,13 @@ FrameState::pushTypedPayload(JSValueType type, RegisterID payload)
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::pushNumber(MaybeRegisterID payload, bool asInt32)
|
||||
FrameState::pushNumber(RegisterID payload, bool asInt32)
|
||||
{
|
||||
JS_ASSERT_IF(payload.isSet(), !freeRegs.hasReg(payload.reg()));
|
||||
JS_ASSERT(!freeRegs.hasReg(payload));
|
||||
|
||||
FrameEntry *fe = rawPush();
|
||||
fe->clear();
|
||||
|
||||
JS_ASSERT(!fe->isNumber);
|
||||
|
||||
if (asInt32) {
|
||||
if (!fe->type.synced())
|
||||
masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
|
||||
@ -316,14 +360,9 @@ FrameState::pushNumber(MaybeRegisterID payload, bool asInt32)
|
||||
fe->type.setMemory();
|
||||
}
|
||||
|
||||
fe->isNumber = true;
|
||||
if (payload.isSet()) {
|
||||
fe->data.unsync();
|
||||
fe->data.setRegister(payload.reg());
|
||||
regstate[payload.reg()].associate(fe, RematInfo::DATA);
|
||||
} else {
|
||||
fe->data.setMemory();
|
||||
}
|
||||
fe->data.unsync();
|
||||
fe->data.setRegister(payload);
|
||||
regstate[payload].associate(fe, RematInfo::DATA);
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -331,12 +370,10 @@ FrameState::pushInt32(RegisterID payload)
|
||||
{
|
||||
FrameEntry *fe = rawPush();
|
||||
fe->clear();
|
||||
JS_ASSERT(!fe->isNumber);
|
||||
|
||||
masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
|
||||
fe->type.setMemory();
|
||||
|
||||
fe->isNumber = true;
|
||||
fe->data.unsync();
|
||||
fe->data.setRegister(payload);
|
||||
regstate[payload].associate(fe, RematInfo::DATA);
|
||||
@ -407,6 +444,7 @@ inline JSC::MacroAssembler::RegisterID
|
||||
FrameState::tempRegForData(FrameEntry *fe)
|
||||
{
|
||||
JS_ASSERT(!fe->data.isConstant());
|
||||
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
@ -420,10 +458,31 @@ FrameState::tempRegForData(FrameEntry *fe)
|
||||
return reg;
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::FPRegisterID
|
||||
FrameState::tempFPRegForData(FrameEntry *fe)
|
||||
{
|
||||
JS_ASSERT(!fe->data.isConstant());
|
||||
JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
|
||||
if (fe->data.inFPRegister())
|
||||
return fe->data.fpreg();
|
||||
|
||||
FPRegisterID reg = allocFPReg();
|
||||
masm.loadDouble(addressOf(fe), reg);
|
||||
|
||||
setFPRegister(fe, reg);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::RegisterID
|
||||
FrameState::tempRegInMaskForData(FrameEntry *fe, uint32 mask)
|
||||
{
|
||||
JS_ASSERT(!fe->data.isConstant());
|
||||
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
@ -485,6 +544,25 @@ FrameState::ensureFeSynced(const FrameEntry *fe, Assembler &masm) const
|
||||
if (fe->isCopy())
|
||||
backing = fe->copyOf();
|
||||
|
||||
if (backing->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
if (fe->data.synced()) {
|
||||
/* Entries representing known doubles can't be partially synced. */
|
||||
JS_ASSERT(fe->type.synced());
|
||||
return;
|
||||
}
|
||||
if (backing->isConstant()) {
|
||||
masm.storeValue(backing->getValue(), to);
|
||||
} else if (backing->data.inFPRegister()) {
|
||||
masm.storeDouble(backing->data.fpreg(), to);
|
||||
} else {
|
||||
/* Use a temporary so the entry can be synced without allocating a register. */
|
||||
JS_ASSERT(backing->data.inMemory() && backing != fe);
|
||||
masm.loadDouble(addressOf(backing), FPRegisters::ConversionTemp);
|
||||
masm.storeDouble(FPRegisters::ConversionTemp, to);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined JS_PUNBOX64
|
||||
/* If we can, sync the type and data in one go. */
|
||||
if (!fe->data.synced() && !fe->type.synced()) {
|
||||
@ -574,10 +652,25 @@ FrameState::ensureDataSynced(const FrameEntry *fe, Assembler &masm) const
|
||||
inline void
|
||||
FrameState::syncFe(FrameEntry *fe)
|
||||
{
|
||||
if (fe->type.synced() && fe->data.synced())
|
||||
return;
|
||||
|
||||
FrameEntry *backing = fe;
|
||||
if (fe->isCopy())
|
||||
backing = fe->copyOf();
|
||||
|
||||
if (backing->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
if (!backing->isConstant())
|
||||
tempFPRegForData(backing);
|
||||
ensureFeSynced(fe, masm);
|
||||
|
||||
if (!fe->type.synced())
|
||||
fe->type.sync();
|
||||
if (!fe->data.synced())
|
||||
fe->data.sync();
|
||||
return;
|
||||
}
|
||||
|
||||
bool needTypeReg = !fe->type.synced() && backing->type.inMemory();
|
||||
bool needDataReg = !fe->data.synced() && backing->data.inMemory();
|
||||
|
||||
@ -633,6 +726,8 @@ FrameState::syncFe(FrameEntry *fe)
|
||||
inline void
|
||||
FrameState::syncType(FrameEntry *fe)
|
||||
{
|
||||
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
FrameEntry *backing = fe;
|
||||
if (fe->isCopy())
|
||||
backing = fe->copyOf();
|
||||
@ -649,6 +744,8 @@ FrameState::syncType(FrameEntry *fe)
|
||||
inline void
|
||||
FrameState::syncData(FrameEntry *fe)
|
||||
{
|
||||
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
FrameEntry *backing = fe;
|
||||
if (fe->isCopy())
|
||||
backing = fe->copyOf();
|
||||
@ -690,16 +787,30 @@ FrameState::forgetType(FrameEntry *fe)
|
||||
inline void
|
||||
FrameState::learnType(FrameEntry *fe, JSValueType type, bool unsync)
|
||||
{
|
||||
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
if (fe->type.inRegister())
|
||||
forgetReg(fe->type.reg());
|
||||
#ifdef DEBUG
|
||||
fe->isNumber = false;
|
||||
#endif
|
||||
fe->setType(type);
|
||||
if (unsync)
|
||||
fe->type.unsync();
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::learnType(FrameEntry *fe, JSValueType type, RegisterID data)
|
||||
{
|
||||
forgetAllRegs(fe);
|
||||
fe->setCopyOf(NULL);
|
||||
|
||||
fe->type.setConstant();
|
||||
fe->knownType = type;
|
||||
|
||||
fe->data.setRegister(data);
|
||||
regstate[data].associate(fe, RematInfo::DATA);
|
||||
|
||||
fe->data.unsync();
|
||||
fe->type.unsync();
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::Address
|
||||
FrameState::addressOf(const FrameEntry *fe) const
|
||||
{
|
||||
@ -802,18 +913,6 @@ FrameState::getLocal(uint32 slot)
|
||||
return fe;
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::pinReg(RegisterID reg)
|
||||
{
|
||||
regstate[reg].pin();
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::unpinReg(RegisterID reg)
|
||||
{
|
||||
regstate[reg].unpin();
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::unpinKilledReg(RegisterID reg)
|
||||
{
|
||||
@ -828,6 +927,8 @@ FrameState::forgetAllRegs(FrameEntry *fe)
|
||||
forgetReg(fe->type.reg());
|
||||
if (fe->data.inRegister())
|
||||
forgetReg(fe->data.reg());
|
||||
if (fe->data.inFPRegister())
|
||||
forgetFPReg(fe->data.fpreg());
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -873,7 +974,7 @@ FrameState::dupAt(int32 n)
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::pushLocal(uint32 n)
|
||||
FrameState::pushLocal(uint32 n, JSValueType knownType)
|
||||
{
|
||||
if (!eval && !isClosedVar(n)) {
|
||||
pushCopyOf(indexOfFe(getLocal(n)));
|
||||
@ -890,7 +991,7 @@ FrameState::pushLocal(uint32 n)
|
||||
JS_ASSERT(fe->data.inMemory());
|
||||
}
|
||||
#endif
|
||||
push(Address(JSFrameReg, sizeof(JSStackFrame) + n * sizeof(Value)));
|
||||
push(Address(JSFrameReg, sizeof(JSStackFrame) + n * sizeof(Value)), knownType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -959,18 +1060,18 @@ FrameState::giveOwnRegs(FrameEntry *fe)
|
||||
} else {
|
||||
RegisterID type = copyTypeIntoReg(fe);
|
||||
pop();
|
||||
pushRegs(type, data);
|
||||
pushRegs(type, data, JSVAL_TYPE_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::loadDouble(RegisterID t, RegisterID d, FrameEntry *fe, FPRegisterID fpReg,
|
||||
FrameState::loadDouble(RegisterID t, RegisterID d, FrameEntry *fe, FPRegisterID fpreg,
|
||||
Assembler &masm) const
|
||||
{
|
||||
#ifdef JS_CPU_X86
|
||||
masm.fastLoadDouble(d, t, fpReg);
|
||||
masm.fastLoadDouble(d, t, fpreg);
|
||||
#else
|
||||
loadDouble(fe, fpReg, masm);
|
||||
loadDouble(fe, fpreg, masm);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -993,25 +1094,28 @@ FrameState::loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) cons
|
||||
FrameEntry *backing = fe->copyOf();
|
||||
if (tryFastDoubleLoad(fe, fpReg, masm))
|
||||
return;
|
||||
if (backing->isCachedNumber() || (backing->type.synced() && backing->data.synced())) {
|
||||
masm.loadDouble(addressOf(backing), fpReg);
|
||||
return;
|
||||
}
|
||||
fe = backing;
|
||||
}
|
||||
|
||||
if (tryFastDoubleLoad(fe, fpReg, masm))
|
||||
return;
|
||||
|
||||
if ((fe->type.synced() && fe->data.synced()) || fe->isCachedNumber()) {
|
||||
masm.loadDouble(addressOf(fe), fpReg);
|
||||
return;
|
||||
}
|
||||
|
||||
ensureFeSynced(fe, masm);
|
||||
masm.loadDouble(addressOf(fe), fpReg);
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::setFPRegister(FrameEntry *fe, FPRegisterID fpreg, bool reassociate)
|
||||
{
|
||||
fe->type.setConstant();
|
||||
fe->knownType = JSVAL_TYPE_DOUBLE;
|
||||
fe->data.setFPRegister(fpreg);
|
||||
if (reassociate)
|
||||
fpregstate[fpreg].reassociate(fe);
|
||||
else
|
||||
fpregstate[fpreg].associate(fe, RematInfo::DATA);
|
||||
}
|
||||
|
||||
inline bool
|
||||
FrameState::isClosedVar(uint32 slot)
|
||||
{
|
||||
|
@ -176,6 +176,41 @@ FrameState::evictSomeReg(uint32 mask)
|
||||
return fallback;
|
||||
}
|
||||
|
||||
JSC::MacroAssembler::FPRegisterID
|
||||
FrameState::evictSomeFPReg()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
bool fallbackSet = false;
|
||||
#endif
|
||||
FPRegisterID fallback = FPRegisterID(0);
|
||||
|
||||
for (uint32 i = 0; i < FPRegisters::TotalFPRegisters; i++) {
|
||||
FPRegisterID reg = FPRegisterID(i);
|
||||
|
||||
FrameEntry *fe = fpregstate[i].fe();
|
||||
if (!fe)
|
||||
continue;
|
||||
JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
#ifdef DEBUG
|
||||
fallbackSet = true;
|
||||
#endif
|
||||
fallback = reg;
|
||||
|
||||
if (fe->data.synced()) {
|
||||
fe->data.setMemory();
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
JS_ASSERT(fallbackSet);
|
||||
|
||||
FrameEntry *fe = fpregstate[fallback].fe();
|
||||
syncFe(fe);
|
||||
|
||||
fe->data.setMemory();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::syncAndForgetEverything()
|
||||
@ -192,6 +227,7 @@ FrameState::resetInternalState()
|
||||
|
||||
tracker.reset();
|
||||
freeRegs.reset();
|
||||
freeFPRegs.reset();
|
||||
}
|
||||
|
||||
void
|
||||
@ -200,6 +236,7 @@ FrameState::discardFrame()
|
||||
resetInternalState();
|
||||
|
||||
memset(regstate, 0, sizeof(regstate));
|
||||
memset(fpregstate, 0, sizeof(fpregstate));
|
||||
}
|
||||
|
||||
void
|
||||
@ -208,9 +245,10 @@ FrameState::forgetEverything()
|
||||
resetInternalState();
|
||||
|
||||
#ifdef DEBUG
|
||||
for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
|
||||
for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++)
|
||||
JS_ASSERT(!regstate[i].usedBy());
|
||||
}
|
||||
for (uint32 i = 0; i < FPRegisters::TotalFPRegisters; i++)
|
||||
JS_ASSERT(!fpregstate[i].usedBy());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -233,6 +271,18 @@ FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
|
||||
addressOf(fe).base != address.base ||
|
||||
addressOf(fe).offset != address.offset);
|
||||
|
||||
if (fe->data.inFPRegister()) {
|
||||
masm.storeDouble(fe->data.fpreg(), address);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
JS_ASSERT(fe->data.inMemory());
|
||||
masm.loadDouble(addressOf(fe), FPRegisters::ConversionTemp);
|
||||
masm.storeDouble(FPRegisters::ConversionTemp, address);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined JS_PUNBOX64
|
||||
if (fe->type.inMemory() && fe->data.inMemory()) {
|
||||
/* Future optimization: track that the Value is in a register. */
|
||||
@ -242,6 +292,8 @@ FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
|
||||
return;
|
||||
}
|
||||
|
||||
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
/*
|
||||
* If dreg is obtained via allocReg(), then calling
|
||||
* pinReg() trips an assertion. But in all other cases,
|
||||
@ -335,6 +387,12 @@ void FrameState::loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID da
|
||||
return;
|
||||
}
|
||||
|
||||
if (fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
FPRegisterID fpreg = tempFPRegForData(fe);
|
||||
masm.breakDouble(fpreg, typeReg, dataReg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
|
||||
@ -409,6 +467,7 @@ void
|
||||
FrameState::assertValidRegisterState() const
|
||||
{
|
||||
Registers checkedFreeRegs;
|
||||
FPRegisters checkedFreeFPRegs;
|
||||
|
||||
for (uint32 i = 0; i < tracker.nentries; i++) {
|
||||
FrameEntry *fe = tracker[i];
|
||||
@ -419,7 +478,8 @@ FrameState::assertValidRegisterState() const
|
||||
JS_ASSERT_IF(fe->isCopy(),
|
||||
fe->trackerIndex() > fe->copyOf()->trackerIndex());
|
||||
JS_ASSERT_IF(fe->isCopy(), fe > fe->copyOf());
|
||||
JS_ASSERT_IF(fe->isCopy(), !fe->type.inRegister() && !fe->data.inRegister());
|
||||
JS_ASSERT_IF(fe->isCopy(),
|
||||
!fe->type.inRegister() && !fe->data.inRegister() && !fe->data.inFPRegister());
|
||||
JS_ASSERT_IF(fe->isCopy(), fe->copyOf() < sp);
|
||||
JS_ASSERT_IF(fe->isCopy(), fe->copyOf()->isCopied());
|
||||
|
||||
@ -433,15 +493,28 @@ FrameState::assertValidRegisterState() const
|
||||
checkedFreeRegs.takeReg(fe->data.reg());
|
||||
JS_ASSERT(regstate[fe->data.reg()].fe() == fe);
|
||||
}
|
||||
if (fe->data.inFPRegister()) {
|
||||
JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
checkedFreeFPRegs.takeReg(fe->data.fpreg());
|
||||
JS_ASSERT(fpregstate[fe->data.fpreg()].fe() == fe);
|
||||
}
|
||||
}
|
||||
|
||||
JS_ASSERT(checkedFreeRegs == freeRegs);
|
||||
JS_ASSERT(checkedFreeFPRegs == freeFPRegs);
|
||||
|
||||
for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
|
||||
JS_ASSERT(!regstate[i].isPinned());
|
||||
JS_ASSERT_IF(regstate[i].fe(), !freeRegs.hasReg(RegisterID(i)));
|
||||
JS_ASSERT_IF(regstate[i].fe(), regstate[i].fe()->isTracked());
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < FPRegisters::TotalFPRegisters; i++) {
|
||||
JS_ASSERT(!fpregstate[i].isPinned());
|
||||
JS_ASSERT_IF(fpregstate[i].fe(), !freeFPRegs.hasReg(FPRegisterID(i)));
|
||||
JS_ASSERT_IF(fpregstate[i].fe(), fpregstate[i].fe()->isTracked());
|
||||
JS_ASSERT_IF(fpregstate[i].fe(), fpregstate[i].type() == RematInfo::DATA);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -498,6 +571,21 @@ FrameState::sync(Assembler &masm, Uses uses) const
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Floating point registers are all volatile, so they are always synced for calls. */
|
||||
for (unsigned i = 0; i < FPRegisters::TotalFPRegisters; i++) {
|
||||
if (freeFPRegs.hasReg(FPRegisterID(i)))
|
||||
continue;
|
||||
|
||||
FrameEntry *fe = fpregstate[i].fe();
|
||||
if (!fe)
|
||||
continue;
|
||||
|
||||
JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
JS_ASSERT(fpregstate[i].type() == RematInfo::DATA);
|
||||
|
||||
ensureFeSynced(fe, masm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep track of free registers using a bitmask. If we have to drop into
|
||||
* syncFancy(), then this mask will help avoid eviction.
|
||||
@ -511,6 +599,12 @@ FrameState::sync(Assembler &masm, Uses uses) const
|
||||
if (!fe->isTracked())
|
||||
continue;
|
||||
|
||||
if (fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
/* Copies of in-memory doubles can be synced without spilling. */
|
||||
ensureFeSynced(fe, masm);
|
||||
continue;
|
||||
}
|
||||
|
||||
FrameEntry *backing = fe;
|
||||
|
||||
if (!fe->isCopy()) {
|
||||
@ -669,11 +763,56 @@ FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore)
|
||||
|
||||
forgetReg(reg);
|
||||
}
|
||||
|
||||
|
||||
/* Floating point registers are all volatile, so they are always synced for calls. */
|
||||
for (unsigned i = 0; i < FPRegisters::TotalFPRegisters; i++) {
|
||||
if (freeFPRegs.hasReg(FPRegisterID(i)))
|
||||
continue;
|
||||
|
||||
FrameEntry *fe = fpregstate[i].fe();
|
||||
if (!fe || fe >= spStop)
|
||||
continue;
|
||||
|
||||
JS_ASSERT(fe && fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
JS_ASSERT(fpregstate[i].type() == RematInfo::DATA);
|
||||
|
||||
syncFe(fe);
|
||||
|
||||
JS_ASSERT(fe->data.synced() && fe->type.synced());
|
||||
fe->data.setMemory();
|
||||
forgetFPReg(FPRegisterID(i));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::merge(Assembler &masm, Changes changes) const
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
for (unsigned i = 0; i < changes.nchanges; i++) {
|
||||
FrameEntry *fe = sp - 1 - i;
|
||||
if (fe->isType(JSVAL_TYPE_DOUBLE))
|
||||
ensureInMemoryDouble(fe, masm);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < FPRegisters::TotalFPRegisters; i++) {
|
||||
if (freeFPRegs.hasReg(FPRegisterID(i)))
|
||||
continue;
|
||||
|
||||
FrameEntry *fe = fpregstate[i].fe();
|
||||
if (!fe)
|
||||
continue;
|
||||
|
||||
JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
JS_ASSERT(fpregstate[i].type() == RematInfo::DATA);
|
||||
|
||||
masm.loadDouble(addressOf(fe), FPRegisterID(i));
|
||||
}
|
||||
|
||||
Registers search(Registers::AvailRegs & ~freeRegs.freeMask);
|
||||
|
||||
while (!search.empty()) {
|
||||
@ -712,6 +851,7 @@ void
|
||||
FrameState::copyDataIntoReg(FrameEntry *fe, RegisterID hint)
|
||||
{
|
||||
JS_ASSERT(!fe->data.isConstant());
|
||||
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
@ -822,24 +962,6 @@ FrameState::copyInt32ConstantIntoReg(Assembler &masm, FrameEntry *fe)
|
||||
return reg;
|
||||
}
|
||||
|
||||
JSC::MacroAssembler::FPRegisterID
|
||||
FrameState::copyEntryIntoFPReg(FrameEntry *fe, FPRegisterID fpreg)
|
||||
{
|
||||
return copyEntryIntoFPReg(this->masm, fe, fpreg);
|
||||
}
|
||||
|
||||
JSC::MacroAssembler::FPRegisterID
|
||||
FrameState::copyEntryIntoFPReg(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg)
|
||||
{
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
|
||||
ensureFeSynced(fe, masm);
|
||||
masm.loadDouble(addressOf(fe), fpreg);
|
||||
|
||||
return fpreg;
|
||||
}
|
||||
|
||||
JSC::MacroAssembler::RegisterID
|
||||
FrameState::ownRegForType(FrameEntry *fe)
|
||||
{
|
||||
@ -887,6 +1009,7 @@ JSC::MacroAssembler::RegisterID
|
||||
FrameState::ownRegForData(FrameEntry *fe)
|
||||
{
|
||||
JS_ASSERT(!fe->data.isConstant());
|
||||
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
RegisterID reg;
|
||||
if (fe->isCopy()) {
|
||||
@ -942,6 +1065,77 @@ FrameState::discardFe(FrameEntry *fe)
|
||||
fe->data.setMemory();
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::pushDouble(FPRegisterID fpreg)
|
||||
{
|
||||
FrameEntry *fe = rawPush();
|
||||
fe->resetUnsynced();
|
||||
setFPRegister(fe, fpreg);
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::pushDouble(Address address)
|
||||
{
|
||||
FPRegisterID fpreg = allocFPReg();
|
||||
masm.loadDouble(address, fpreg);
|
||||
|
||||
FrameEntry *fe = rawPush();
|
||||
fe->resetUnsynced();
|
||||
setFPRegister(fe, fpreg);
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::ensureInMemoryDouble(FrameEntry *fe, Assembler &masm) const
|
||||
{
|
||||
Address address = addressOf(fe);
|
||||
Jump notInteger = masm.testInt32(Assembler::NotEqual, address);
|
||||
masm.convertInt32ToDouble(masm.payloadOf(address), FPRegisters::ConversionTemp);
|
||||
masm.storeDouble(FPRegisters::ConversionTemp, address);
|
||||
notInteger.linkTo(masm.label(), &masm);
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::ensureDouble(FrameEntry *fe)
|
||||
{
|
||||
if (fe->isConstant()) {
|
||||
JS_ASSERT(fe->getValue().isInt32());
|
||||
Value newValue = DoubleValue(double(fe->getValue().toInt32()));
|
||||
fe->setConstant(Jsvalify(newValue));
|
||||
return;
|
||||
}
|
||||
|
||||
if (fe->isCopy()) {
|
||||
/* If this is a copy of another slot, that slot should already have been converted to double. */
|
||||
JS_ASSERT(fe->copyOf()->isType(JSVAL_TYPE_DOUBLE));
|
||||
fe->type.setConstant();
|
||||
fe->knownType = JSVAL_TYPE_DOUBLE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fe->isType(JSVAL_TYPE_DOUBLE))
|
||||
return;
|
||||
|
||||
if (fe->isType(JSVAL_TYPE_INT32)) {
|
||||
RegisterID data = tempRegForData(fe);
|
||||
FPRegisterID fpreg = allocFPReg();
|
||||
masm.convertInt32ToDouble(data, fpreg);
|
||||
|
||||
forgetAllRegs(fe);
|
||||
setFPRegister(fe, fpreg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fe->data.inMemory()) {
|
||||
FPRegisterID fpreg = allocFPReg();
|
||||
masm.moveInt32OrDouble(addressOf(fe), fpreg);
|
||||
|
||||
setFPRegister(fe, fpreg);
|
||||
return;
|
||||
}
|
||||
|
||||
JS_NOT_REACHED("FIXME");
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::pushCopyOf(uint32 index)
|
||||
{
|
||||
@ -955,7 +1149,6 @@ FrameState::pushCopyOf(uint32 index)
|
||||
fe->setType(backing->getKnownType());
|
||||
else
|
||||
fe->type.invalidate();
|
||||
fe->isNumber = backing->isNumber;
|
||||
fe->data.invalidate();
|
||||
if (backing->isCopy()) {
|
||||
backing = backing->copyOf();
|
||||
@ -1139,11 +1332,11 @@ FrameState::uncopy(FrameEntry *original)
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::storeLocal(uint32 n, bool popGuaranteed, bool typeChange)
|
||||
FrameState::storeLocal(uint32 n, bool popGuaranteed, JSValueType type)
|
||||
{
|
||||
FrameEntry *local = getLocal(n);
|
||||
|
||||
storeTop(local, popGuaranteed, typeChange);
|
||||
storeTop(local, popGuaranteed, type);
|
||||
|
||||
bool closed = eval || isClosedVar(n);
|
||||
if (!closed && !inTryBlock)
|
||||
@ -1173,9 +1366,8 @@ FrameState::forgetEntry(FrameEntry *fe)
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange)
|
||||
FrameState::storeTop(FrameEntry *target, bool popGuaranteed, JSValueType type)
|
||||
{
|
||||
bool wasSynced = target->type.synced();
|
||||
/* Detect something like (x = x) which is a no-op. */
|
||||
FrameEntry *top = peek(-1);
|
||||
if (top->isCopy() && top->copyOf() == target) {
|
||||
@ -1192,8 +1384,12 @@ FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange)
|
||||
target->setCopyOf(NULL);
|
||||
target->setNotCopied();
|
||||
target->setConstant(Jsvalify(top->getValue()));
|
||||
if (!typeChange)
|
||||
|
||||
/* Types of local variables are always in sync if known. */
|
||||
if (indexOfFe(target) < localIndex(script->nfixed) &&
|
||||
type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE) {
|
||||
target->type.sync();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1227,7 +1423,6 @@ FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange)
|
||||
else
|
||||
target->type.invalidate();
|
||||
target->data.invalidate();
|
||||
target->isNumber = backing->isNumber;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1269,40 +1464,60 @@ FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange)
|
||||
if (backing->trackerIndex() < target->trackerIndex())
|
||||
swapInTracker(backing, target);
|
||||
|
||||
/*
|
||||
* Move the backing store down - we spill registers here, but we could be
|
||||
* smarter and re-use the type reg.
|
||||
*/
|
||||
RegisterID reg = tempRegForData(backing);
|
||||
target->data.setRegister(reg);
|
||||
regstate[reg].reassociate(target);
|
||||
if (backing->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
FPRegisterID fpreg = tempFPRegForData(backing);
|
||||
if (type == JSVAL_TYPE_UNKNOWN) {
|
||||
masm.storeDouble(fpreg, addressOf(target));
|
||||
target->resetSynced();
|
||||
|
||||
if (typeChange) {
|
||||
if (backing->isTypeKnown()) {
|
||||
target->setType(backing->getKnownType());
|
||||
/* We're about to invalidate the backing, so forget the FP register. */
|
||||
forgetFPReg(fpreg);
|
||||
} else {
|
||||
RegisterID reg = tempRegForType(backing);
|
||||
target->type.setRegister(reg);
|
||||
regstate[reg].reassociate(target);
|
||||
JS_ASSERT(type == JSVAL_TYPE_DOUBLE);
|
||||
target->resetUnsynced();
|
||||
setFPRegister(target, fpreg, true);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* :FIXME: Should eventually assert this, but can't yet as registers are still
|
||||
* used to hold things with known types in some places.
|
||||
* Move the backing store down - we spill registers here, but we could be
|
||||
* smarter and re-use the type reg.
|
||||
*/
|
||||
// JS_ASSERT(backing->isTypeKnown());
|
||||
if (!backing->isTypeKnown() && backing->type.inRegister())
|
||||
forgetReg(backing->type.reg());
|
||||
if (!wasSynced)
|
||||
masm.storeTypeTag(ImmType(backing->getKnownType()), addressOf(target));
|
||||
target->type.setMemory();
|
||||
RegisterID reg = tempRegForData(backing);
|
||||
target->data.setRegister(reg);
|
||||
regstate[reg].reassociate(target);
|
||||
|
||||
if (type == JSVAL_TYPE_UNKNOWN) {
|
||||
if (backing->isTypeKnown()) {
|
||||
target->setType(backing->getKnownType());
|
||||
} else {
|
||||
RegisterID reg = tempRegForType(backing);
|
||||
target->type.setRegister(reg);
|
||||
regstate[reg].reassociate(target);
|
||||
}
|
||||
} else if (type == JSVAL_TYPE_DOUBLE) {
|
||||
JS_ASSERT(backing->isType(JSVAL_TYPE_INT32));
|
||||
|
||||
FPRegisterID fpreg = allocFPReg();
|
||||
masm.convertInt32ToDouble(reg, fpreg);
|
||||
setFPRegister(target, fpreg);
|
||||
forgetReg(reg);
|
||||
} else {
|
||||
/*
|
||||
* The backing should normally already be the type we are storing. However,
|
||||
* we do not always keep track of the type in fused opcodes like GETTHISPROP.
|
||||
*/
|
||||
JS_ASSERT_IF(backing->isTypeKnown(), backing->isType(type));
|
||||
if (!backing->isTypeKnown())
|
||||
learnType(backing, type);
|
||||
target->type.setConstant();
|
||||
target->knownType = type;
|
||||
}
|
||||
}
|
||||
|
||||
if (!backing->isTypeKnown())
|
||||
backing->type.invalidate();
|
||||
backing->data.invalidate();
|
||||
backing->setCopyOf(target);
|
||||
backing->isNumber = target->isNumber;
|
||||
|
||||
JS_ASSERT(top->copyOf() == target);
|
||||
|
||||
@ -1337,12 +1552,37 @@ FrameState::shift(int32 n)
|
||||
pop();
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::forgetKnownDouble(FrameEntry *fe)
|
||||
{
|
||||
/*
|
||||
* Forget all information indicating fe is a double, so we can use GPRs for its
|
||||
* contents. We currently need to do this in order to use the entry in MICs/PICs
|
||||
* or to construct its ValueRemat. :FIXME: this needs to get fixed.
|
||||
*/
|
||||
JS_ASSERT(!fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE));
|
||||
|
||||
FPRegisterID fpreg = tempFPRegForData(fe);
|
||||
forgetAllRegs(fe);
|
||||
fe->resetUnsynced();
|
||||
RegisterID typeReg = allocReg(fe, RematInfo::TYPE);
|
||||
pinReg(typeReg);
|
||||
RegisterID dataReg = allocReg(fe, RematInfo::DATA);
|
||||
unpinReg(typeReg);
|
||||
masm.breakDouble(fpreg, typeReg, dataReg);
|
||||
fe->type.setRegister(typeReg);
|
||||
fe->data.setRegister(dataReg);
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::pinEntry(FrameEntry *fe, ValueRemat &vr)
|
||||
{
|
||||
if (fe->isConstant()) {
|
||||
vr = ValueRemat::FromConstant(fe->getValue());
|
||||
} else {
|
||||
if (fe->isType(JSVAL_TYPE_DOUBLE))
|
||||
forgetKnownDouble(fe);
|
||||
|
||||
// Pin the type register so it can't spill.
|
||||
MaybeRegisterID maybePinnedType = maybePinType(fe);
|
||||
|
||||
@ -1431,6 +1671,8 @@ FrameState::allocForSameBinary(FrameEntry *fe, JSOp op, BinaryAlloc &alloc)
|
||||
|
||||
if (alloc.lhsType.isSet())
|
||||
unpinReg(alloc.lhsType.reg());
|
||||
|
||||
alloc.lhsFP = alloc.rhsFP = allocFPReg();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1510,6 +1752,16 @@ FrameState::allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAllo
|
||||
pinReg(alloc.rhsType.reg());
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate floating point registers. These are temporaries with no pre-existing data;
|
||||
* floating point registers are only allocated for known doubles, and BinaryAlloc is not
|
||||
* used for such operations.
|
||||
*/
|
||||
JS_ASSERT(!backingLeft->isType(JSVAL_TYPE_DOUBLE));
|
||||
JS_ASSERT(!backingRight->isType(JSVAL_TYPE_DOUBLE));
|
||||
alloc.lhsFP = allocFPReg();
|
||||
alloc.rhsFP = allocFPReg();
|
||||
|
||||
bool commu;
|
||||
switch (op) {
|
||||
case JSOP_EQ:
|
||||
|
@ -242,19 +242,14 @@ class FrameState
|
||||
bool init(uint32 nargs);
|
||||
|
||||
/*
|
||||
* Pushes a synced slot.
|
||||
* Pushes a synced slot that may have a known type.
|
||||
*/
|
||||
inline void pushSynced();
|
||||
inline void pushSynced(JSValueType knownType);
|
||||
|
||||
/*
|
||||
* Pushes a slot that has a known, synced type and payload.
|
||||
*/
|
||||
inline void pushSyncedType(JSValueType type);
|
||||
|
||||
/*
|
||||
* Pushes a slot that has a known, synced type and payload.
|
||||
*/
|
||||
inline void pushSynced(JSValueType type, RegisterID reg);
|
||||
inline void pushSynced(JSValueType knownType, RegisterID reg);
|
||||
|
||||
/*
|
||||
* Pushes a constant value.
|
||||
@ -264,7 +259,7 @@ class FrameState
|
||||
/*
|
||||
* Loads a value from memory and pushes it.
|
||||
*/
|
||||
inline void push(Address address);
|
||||
inline void push(Address address, JSValueType knownType);
|
||||
|
||||
/*
|
||||
* Pushes a known type and allocated payload onto the operation stack.
|
||||
@ -272,9 +267,23 @@ class FrameState
|
||||
inline void pushTypedPayload(JSValueType type, RegisterID payload);
|
||||
|
||||
/*
|
||||
* Pushes a type register and data register pair.
|
||||
* Pushes a type register and data register pair, converting to the specified
|
||||
* known type if necessary.
|
||||
*/
|
||||
inline void pushRegs(RegisterID type, RegisterID data);
|
||||
inline void pushRegs(RegisterID type, RegisterID data, JSValueType knownType);
|
||||
|
||||
/* Push a value which is definitely a double. */
|
||||
void pushDouble(FPRegisterID fpreg);
|
||||
void pushDouble(Address address);
|
||||
|
||||
/* Ensure that fe is definitely a double. It must already be either int or double. */
|
||||
void ensureDouble(FrameEntry *fe);
|
||||
|
||||
/* Ensure that in-memory fe is definitely a double. */
|
||||
void ensureInMemoryDouble(FrameEntry *fe, Assembler &masm) const;
|
||||
|
||||
/* Forget that fe is definitely a double. */
|
||||
void forgetKnownDouble(FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Pushes a known type and allocated payload onto the operation stack.
|
||||
@ -298,7 +307,7 @@ class FrameState
|
||||
* was synced, then popping both and pushing a maybe-int32 does not need
|
||||
* to be synced.
|
||||
*/
|
||||
inline void pushNumber(MaybeRegisterID payload, bool asInt32 = false);
|
||||
inline void pushNumber(RegisterID payload, bool asInt32 = false);
|
||||
|
||||
/*
|
||||
* Pushes an int32 onto the operation stack. This is a specialized version
|
||||
@ -333,7 +342,7 @@ class FrameState
|
||||
/*
|
||||
* Pushes a copy of a local variable.
|
||||
*/
|
||||
void pushLocal(uint32 n);
|
||||
void pushLocal(uint32 n, JSValueType knownType);
|
||||
|
||||
inline FrameEntry *getLocal(uint32 slot);
|
||||
|
||||
@ -359,6 +368,7 @@ class FrameState
|
||||
* The compiler should NOT explicitly free it.
|
||||
*/
|
||||
inline RegisterID tempRegForData(FrameEntry *fe);
|
||||
inline FPRegisterID tempFPRegForData(FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Same as above, except register must match identically.
|
||||
@ -413,14 +423,6 @@ class FrameState
|
||||
void copyDataIntoReg(FrameEntry *fe, RegisterID exact);
|
||||
RegisterID copyDataIntoReg(Assembler &masm, FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Allocates a FPRegister for a FrameEntry, such that the compiler
|
||||
* can modify it in-place. The FrameState is not modified.
|
||||
*/
|
||||
FPRegisterID copyEntryIntoFPReg(FrameEntry *fe, FPRegisterID fpreg);
|
||||
FPRegisterID copyEntryIntoFPReg(Assembler &masm, FrameEntry *fe,
|
||||
FPRegisterID fpreg);
|
||||
|
||||
/*
|
||||
* Allocates a register for a FrameEntry's type, such that the compiler
|
||||
* can modify it in-place. The actual FE is not modified.
|
||||
@ -455,6 +457,8 @@ class FrameState
|
||||
MaybeRegisterID rhsData;
|
||||
MaybeRegisterID extraFree;
|
||||
RegisterID result; // mutable result reg
|
||||
FPRegisterID lhsFP; // mutable scratch floating point reg
|
||||
FPRegisterID rhsFP; // mutable scratch floating point reg
|
||||
bool resultHasRhs; // whether the result has the RHS instead of the LHS
|
||||
bool lhsNeedsRemat; // whether LHS needs memory remat
|
||||
bool rhsNeedsRemat; // whether RHS needs memory remat
|
||||
@ -513,6 +517,7 @@ class FrameState
|
||||
* is not spilled; the backing data becomes invalidated!
|
||||
*/
|
||||
inline void freeReg(RegisterID reg);
|
||||
inline void freeFPReg(FPRegisterID reg);
|
||||
|
||||
/*
|
||||
* Allocates a register. If none are free, one may be spilled from the
|
||||
@ -520,6 +525,7 @@ class FrameState
|
||||
* then this is considered a compiler bug and an assert will fire.
|
||||
*/
|
||||
inline RegisterID allocReg();
|
||||
inline FPRegisterID allocFPReg();
|
||||
|
||||
/*
|
||||
* Allocates a register, except using a mask.
|
||||
@ -549,10 +555,13 @@ class FrameState
|
||||
void loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
|
||||
|
||||
/*
|
||||
* Stores the top stack slot back to a slot.
|
||||
* Stores the top stack slot back to a local or slot. type indicates any known
|
||||
* type for the local/slot.
|
||||
*/
|
||||
void storeLocal(uint32 n, bool popGuaranteed = false, bool typeChange = true);
|
||||
void storeTop(FrameEntry *target, bool popGuaranteed = false, bool typeChange = true);
|
||||
void storeLocal(uint32 n, bool popGuaranteed = false,
|
||||
JSValueType type = JSVAL_TYPE_UNKNOWN);
|
||||
void storeTop(FrameEntry *target, bool popGuaranteed = false,
|
||||
JSValueType type = JSVAL_TYPE_UNKNOWN);
|
||||
|
||||
/*
|
||||
* Restores state from a slow path.
|
||||
@ -601,9 +610,10 @@ class FrameState
|
||||
void discardFrame();
|
||||
|
||||
/*
|
||||
* Mark an existing slot with a type.
|
||||
* Mark an existing slot with a type. unsync indicates whether type is already synced.
|
||||
*/
|
||||
inline void learnType(FrameEntry *fe, JSValueType type, bool unsync = true);
|
||||
inline void learnType(FrameEntry *fe, JSValueType type, RegisterID payload);
|
||||
|
||||
/*
|
||||
* Forget a type, syncing in the process.
|
||||
@ -669,12 +679,14 @@ class FrameState
|
||||
* no matter what. In addition, pinReg() can only be used on registers
|
||||
* which are associated with FrameEntries.
|
||||
*/
|
||||
inline void pinReg(RegisterID reg);
|
||||
inline void pinReg(RegisterID reg) { regstate[reg].pin(); }
|
||||
inline void pinFPReg(FPRegisterID reg) { fpregstate[reg].pin(); }
|
||||
|
||||
/*
|
||||
* Unpins a previously pinned register.
|
||||
*/
|
||||
inline void unpinReg(RegisterID reg);
|
||||
inline void unpinReg(RegisterID reg) { regstate[reg].unpin(); }
|
||||
inline void unpinFPReg(FPRegisterID reg) { fpregstate[reg].unpin(); }
|
||||
|
||||
/*
|
||||
* Same as unpinReg(), but does not restore the FrameEntry.
|
||||
@ -755,10 +767,13 @@ class FrameState
|
||||
private:
|
||||
inline RegisterID allocReg(FrameEntry *fe, RematInfo::RematType type);
|
||||
inline void forgetReg(RegisterID reg);
|
||||
inline void forgetFPReg(FPRegisterID reg);
|
||||
RegisterID evictSomeReg(uint32 mask);
|
||||
FPRegisterID evictSomeFPReg();
|
||||
void evictReg(RegisterID reg);
|
||||
inline FrameEntry *rawPush();
|
||||
inline void addToTracker(FrameEntry *fe);
|
||||
inline void setFPRegister(FrameEntry *fe, FPRegisterID fpreg, bool reassociate = false);
|
||||
|
||||
/* Guarantee sync, but do not set any sync flag. */
|
||||
inline void ensureFeSynced(const FrameEntry *fe, Assembler &masm) const;
|
||||
@ -826,6 +841,7 @@ class FrameState
|
||||
|
||||
/* All allocated registers. */
|
||||
Registers freeRegs;
|
||||
FPRegisters freeFPRegs;
|
||||
|
||||
/* Cache of FrameEntry objects. */
|
||||
FrameEntry *entries;
|
||||
@ -850,6 +866,7 @@ class FrameState
|
||||
* entry is active, you must check the allocated registers.
|
||||
*/
|
||||
RegisterState regstate[Assembler::TotalRegisters];
|
||||
RegisterState fpregstate[FPRegisters::TotalFPRegisters];
|
||||
|
||||
#if defined JS_NUNBOX32
|
||||
mutable ImmutableSync reifier;
|
||||
|
@ -215,7 +215,7 @@ ImmutableSync::syncCopy(FrameEntry *fe)
|
||||
|
||||
Address addr = frame.addressOf(fe);
|
||||
|
||||
if (fe->isTypeKnown() && !e.learnedType) {
|
||||
if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE) && !e.learnedType) {
|
||||
e.learnedType = true;
|
||||
e.type = fe->getKnownType();
|
||||
}
|
||||
@ -238,7 +238,7 @@ ImmutableSync::syncNormal(FrameEntry *fe)
|
||||
|
||||
Address addr = frame.addressOf(fe);
|
||||
|
||||
if (fe->isTypeKnown()) {
|
||||
if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE)) {
|
||||
e.learnedType = true;
|
||||
e.type = fe->getKnownType();
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ struct FPRegisters {
|
||||
typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
|
||||
|
||||
#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
|
||||
static const uint32 TotalFPRegisters = 8;
|
||||
static const uint32 TotalFPRegisters = 7;
|
||||
static const uint32 TempFPRegs =
|
||||
(1 << JSC::X86Registers::xmm0)
|
||||
| (1 << JSC::X86Registers::xmm1)
|
||||
@ -262,25 +262,16 @@ struct FPRegisters {
|
||||
| (1 << JSC::X86Registers::xmm3)
|
||||
| (1 << JSC::X86Registers::xmm4)
|
||||
| (1 << JSC::X86Registers::xmm5)
|
||||
| (1 << JSC::X86Registers::xmm6)
|
||||
| (1 << JSC::X86Registers::xmm7);
|
||||
/* FIXME: Temporary hack until FPRegister allocation exists. */
|
||||
static const FPRegisterID First = JSC::X86Registers::xmm0;
|
||||
static const FPRegisterID Second = JSC::X86Registers::xmm1;
|
||||
static const FPRegisterID Temp0 = JSC::X86Registers::xmm2;
|
||||
static const FPRegisterID Temp1 = JSC::X86Registers::xmm3;
|
||||
| (1 << JSC::X86Registers::xmm6);
|
||||
/* For shuffling FP values around, or loading GPRs into a FP reg. */
|
||||
static const FPRegisterID ConversionTemp = JSC::X86Registers::xmm7;
|
||||
#elif defined(JS_CPU_ARM)
|
||||
static const uint32 TotalFPRegisters = 4;
|
||||
static const uint32 TotalFPRegisters = 3;
|
||||
static const uint32 TempFPRegs =
|
||||
(1 << JSC::ARMRegisters::d0)
|
||||
| (1 << JSC::ARMRegisters::d1)
|
||||
| (1 << JSC::ARMRegisters::d2)
|
||||
| (1 << JSC::ARMRegisters::d3);
|
||||
/* FIXME: Temporary hack until FPRegister allocation exists. */
|
||||
static const FPRegisterID First = JSC::ARMRegisters::d0;
|
||||
static const FPRegisterID Second = JSC::ARMRegisters::d1;
|
||||
static const FPRegisterID Temp0 = JSC::ARMRegisters::d2;
|
||||
static const FPRegisterID Temp1 = JSC::ARMRegisters::d3;
|
||||
| (1 << JSC::ARMRegisters::d2);
|
||||
static const FPRegisterID ConversionTemp = JSC::ARMRegisters::d3;
|
||||
#else
|
||||
# error "Unsupported platform"
|
||||
#endif
|
||||
|
@ -59,7 +59,9 @@ struct ImmType : ImmTag
|
||||
{
|
||||
ImmType(JSValueType type)
|
||||
: ImmTag(JSVAL_TYPE_TO_TAG(type))
|
||||
{ }
|
||||
{
|
||||
JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
|
||||
}
|
||||
};
|
||||
|
||||
struct ImmPayload : JSC::MacroAssembler::Imm32
|
||||
@ -313,6 +315,21 @@ class NunboxAssembler : public JSC::MacroAssembler
|
||||
loadPayload(address, dataReg);
|
||||
return notHole;
|
||||
}
|
||||
|
||||
/* :FIXME: borrowed from patch in bug 594247 */
|
||||
void breakDouble(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) {
|
||||
#ifdef JS_CPU_X86
|
||||
// Move the low 32-bits of the 128-bit XMM register into dataReg.
|
||||
// Then, right shift the 128-bit XMM register by 4 bytes.
|
||||
// Finally, move the new low 32-bits of the 128-bit XMM register into typeReg.
|
||||
m_assembler.movd_rr(srcDest, dataReg);
|
||||
m_assembler.psrldq_rr(srcDest, 4);
|
||||
m_assembler.movd_rr(srcDest, typeReg);
|
||||
#else
|
||||
JS_STATIC_ASSERT(0);
|
||||
JS_NOT_REACHED("implement this - push double, pop pop is easiest");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
typedef NunboxAssembler ValueAssembler;
|
||||
|
@ -66,7 +66,9 @@ struct ImmType : ImmTag
|
||||
{
|
||||
ImmType(JSValueType type)
|
||||
: ImmTag(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type)))
|
||||
{ }
|
||||
{
|
||||
JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
|
||||
}
|
||||
};
|
||||
|
||||
struct ImmPayload : Imm64
|
||||
@ -326,6 +328,14 @@ class PunboxAssembler : public JSC::MacroAssembler
|
||||
}
|
||||
return notHole;
|
||||
}
|
||||
|
||||
/* :FIXME: borrowed from patch in bug 594247 */
|
||||
void breakDouble(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) {
|
||||
m_assembler.movq_rr(srcDest, typeReg);
|
||||
move(Registers::PayloadMaskReg, dataReg);
|
||||
andPtr(typeReg, dataReg);
|
||||
xorPtr(dataReg, typeReg);
|
||||
}
|
||||
};
|
||||
|
||||
typedef PunboxAssembler ValueAssembler;
|
||||
|
@ -200,6 +200,7 @@ struct ValueRemat {
|
||||
*/
|
||||
struct RematInfo {
|
||||
typedef JSC::MacroAssembler::RegisterID RegisterID;
|
||||
typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
|
||||
|
||||
enum SyncState {
|
||||
SYNCED,
|
||||
@ -221,9 +222,12 @@ struct RematInfo {
|
||||
/* Backing bits are known at compile time. */
|
||||
PhysLoc_Constant,
|
||||
|
||||
/* Backing bits are in a register. */
|
||||
/* Backing bits are in a general purpose register. */
|
||||
PhysLoc_Register,
|
||||
|
||||
/* Backing bits are part of a floating point register. */
|
||||
PhysLoc_FPRegister,
|
||||
|
||||
/* Backing bits are invalid/unknown. */
|
||||
PhysLoc_Invalid
|
||||
};
|
||||
@ -238,6 +242,16 @@ struct RematInfo {
|
||||
return reg_;
|
||||
}
|
||||
|
||||
void setFPRegister(FPRegisterID reg) {
|
||||
fpreg_ = reg;
|
||||
location_ = PhysLoc_FPRegister;
|
||||
}
|
||||
|
||||
FPRegisterID fpreg() const {
|
||||
JS_ASSERT(inFPRegister());
|
||||
return fpreg_;
|
||||
}
|
||||
|
||||
void setMemory() {
|
||||
location_ = PhysLoc_Memory;
|
||||
sync_ = SYNCED;
|
||||
@ -251,6 +265,7 @@ struct RematInfo {
|
||||
|
||||
bool isConstant() const { return location_ == PhysLoc_Constant; }
|
||||
bool inRegister() const { return location_ == PhysLoc_Register; }
|
||||
bool inFPRegister() const { return location_ == PhysLoc_FPRegister; }
|
||||
bool inMemory() const { return location_ == PhysLoc_Memory; }
|
||||
bool synced() const { return sync_ == SYNCED; }
|
||||
void sync() {
|
||||
@ -267,8 +282,16 @@ struct RematInfo {
|
||||
}
|
||||
|
||||
private:
|
||||
/* Set if location is PhysLoc_Register. */
|
||||
RegisterID reg_;
|
||||
union {
|
||||
/* Set if location is PhysLoc_Register. */
|
||||
RegisterID reg_;
|
||||
|
||||
/*
|
||||
* Set if location is PhysLoc_FPRegister. This must be the data for a FE,
|
||||
* and the known type is JSVAL_TYPE_DOUBLE.
|
||||
*/
|
||||
FPRegisterID fpreg_;
|
||||
};
|
||||
|
||||
/* Remat source. */
|
||||
PhysLoc location_;
|
||||
|
Loading…
Reference in New Issue
Block a user