зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 1af8f0c895bc from PGO bustage
This commit is contained in:
Родитель
2e4ff06ce2
Коммит
9b97ea3fb7
|
@ -602,7 +602,7 @@ mjit::Compiler::generateMethod()
|
||||||
OpcodeStatus &opinfo = analysis[PC];
|
OpcodeStatus &opinfo = analysis[PC];
|
||||||
frame.setInTryBlock(opinfo.inTryBlock);
|
frame.setInTryBlock(opinfo.inTryBlock);
|
||||||
if (opinfo.nincoming || opinfo.trap) {
|
if (opinfo.nincoming || opinfo.trap) {
|
||||||
frame.syncAndForgetEverything(opinfo.stackDepth);
|
frame.forgetEverything(opinfo.stackDepth);
|
||||||
opinfo.safePoint = true;
|
opinfo.safePoint = true;
|
||||||
}
|
}
|
||||||
jumpMap[uint32(PC - script->code)] = masm.label();
|
jumpMap[uint32(PC - script->code)] = masm.label();
|
||||||
|
@ -683,7 +683,7 @@ mjit::Compiler::generateMethod()
|
||||||
BEGIN_CASE(JSOP_GOTO)
|
BEGIN_CASE(JSOP_GOTO)
|
||||||
{
|
{
|
||||||
/* :XXX: this isn't really necessary if we follow the branch. */
|
/* :XXX: this isn't really necessary if we follow the branch. */
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
Jump j = masm.jump();
|
Jump j = masm.jump();
|
||||||
jumpAndTrace(j, PC + GET_JUMP_OFFSET(PC));
|
jumpAndTrace(j, PC + GET_JUMP_OFFSET(PC));
|
||||||
}
|
}
|
||||||
|
@ -786,7 +786,7 @@ mjit::Compiler::generateMethod()
|
||||||
|
|
||||||
/* Branch is never taken, don't bother doing anything. */
|
/* Branch is never taken, don't bother doing anything. */
|
||||||
if (result) {
|
if (result) {
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
Jump j = masm.jump();
|
Jump j = masm.jump();
|
||||||
jumpAndTrace(j, target);
|
jumpAndTrace(j, target);
|
||||||
}
|
}
|
||||||
|
@ -1105,10 +1105,10 @@ mjit::Compiler::generateMethod()
|
||||||
END_CASE(JSOP_AND)
|
END_CASE(JSOP_AND)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_TABLESWITCH)
|
BEGIN_CASE(JSOP_TABLESWITCH)
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||||
|
|
||||||
/* prepareStubCall() is not needed due to syncAndForgetEverything() */
|
/* prepareStubCall() is not needed due to forgetEverything() */
|
||||||
stubCall(stubs::TableSwitch);
|
stubCall(stubs::TableSwitch);
|
||||||
frame.pop();
|
frame.pop();
|
||||||
|
|
||||||
|
@ -1118,10 +1118,10 @@ mjit::Compiler::generateMethod()
|
||||||
END_CASE(JSOP_TABLESWITCH)
|
END_CASE(JSOP_TABLESWITCH)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||||
|
|
||||||
/* prepareStubCall() is not needed due to syncAndForgetEverything() */
|
/* prepareStubCall() is not needed due to forgetEverything() */
|
||||||
stubCall(stubs::LookupSwitch);
|
stubCall(stubs::LookupSwitch);
|
||||||
frame.pop();
|
frame.pop();
|
||||||
|
|
||||||
|
@ -1213,22 +1213,11 @@ mjit::Compiler::generateMethod()
|
||||||
END_CASE(JSOP_GETLOCAL)
|
END_CASE(JSOP_GETLOCAL)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_SETLOCAL)
|
BEGIN_CASE(JSOP_SETLOCAL)
|
||||||
{
|
|
||||||
jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH];
|
|
||||||
bool pop = JSOp(*next) == JSOP_POP && !analysis[next].nincoming;
|
|
||||||
frame.storeLocal(GET_SLOTNO(PC), pop);
|
|
||||||
if (pop) {
|
|
||||||
frame.pop();
|
|
||||||
PC += JSOP_SETLOCAL_LENGTH + JSOP_POP_LENGTH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END_CASE(JSOP_SETLOCAL)
|
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_SETLOCALPOP)
|
BEGIN_CASE(JSOP_SETLOCALPOP)
|
||||||
frame.storeLocal(GET_SLOTNO(PC), true);
|
frame.storeLocal(GET_SLOTNO(PC));
|
||||||
frame.pop();
|
if (op == JSOP_SETLOCALPOP)
|
||||||
END_CASE(JSOP_SETLOCALPOP)
|
frame.pop();
|
||||||
|
END_CASE(JSOP_SETLOCAL)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_UINT16)
|
BEGIN_CASE(JSOP_UINT16)
|
||||||
frame.push(Value(Int32Value((int32_t) GET_UINT16(PC))));
|
frame.push(Value(Int32Value((int32_t) GET_UINT16(PC))));
|
||||||
|
@ -1372,7 +1361,7 @@ mjit::Compiler::generateMethod()
|
||||||
if (fun) {
|
if (fun) {
|
||||||
JSLocalKind localKind = fun->lookupLocal(cx, inner->atom, NULL);
|
JSLocalKind localKind = fun->lookupLocal(cx, inner->atom, NULL);
|
||||||
if (localKind != JSLOCAL_NONE)
|
if (localKind != JSLOCAL_NONE)
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareStubCall(Uses(0));
|
prepareStubCall(Uses(0));
|
||||||
|
@ -1439,7 +1428,6 @@ mjit::Compiler::generateMethod()
|
||||||
END_CASE(JSOP_LAMBDA)
|
END_CASE(JSOP_LAMBDA)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_TRY)
|
BEGIN_CASE(JSOP_TRY)
|
||||||
frame.syncAndForgetEverything();
|
|
||||||
END_CASE(JSOP_TRY)
|
END_CASE(JSOP_TRY)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_GETFCSLOT)
|
BEGIN_CASE(JSOP_GETFCSLOT)
|
||||||
|
@ -1564,7 +1552,7 @@ mjit::Compiler::generateMethod()
|
||||||
|
|
||||||
/* For now, don't bother doing anything for this opcode. */
|
/* For now, don't bother doing anything for this opcode. */
|
||||||
JSObject *obj = script->getObject(fullAtomIndex(PC));
|
JSObject *obj = script->getObject(fullAtomIndex(PC));
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
masm.move(ImmPtr(obj), Registers::ArgReg1);
|
masm.move(ImmPtr(obj), Registers::ArgReg1);
|
||||||
uint32 n = js_GetEnterBlockStackDefs(cx, script, PC);
|
uint32 n = js_GetEnterBlockStackDefs(cx, script, PC);
|
||||||
stubCall(stubs::EnterBlock);
|
stubCall(stubs::EnterBlock);
|
||||||
|
@ -1833,14 +1821,14 @@ mjit::Compiler::emitReturn()
|
||||||
/* There will always be a call object. */
|
/* There will always be a call object. */
|
||||||
prepareStubCall(Uses(0));
|
prepareStubCall(Uses(0));
|
||||||
stubCall(stubs::PutCallObject);
|
stubCall(stubs::PutCallObject);
|
||||||
frame.discardFrame();
|
frame.throwaway();
|
||||||
} else {
|
} else {
|
||||||
/* if (hasCallObj() || hasArgsObj()) stubs::PutActivationObjects() */
|
/* if (hasCallObj() || hasArgsObj()) stubs::PutActivationObjects() */
|
||||||
Jump putObjs = masm.branchTest32(Assembler::NonZero,
|
Jump putObjs = masm.branchTest32(Assembler::NonZero,
|
||||||
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
|
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
|
||||||
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
|
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
|
||||||
stubcc.linkExit(putObjs, Uses(frame.frameDepth()));
|
stubcc.linkExit(putObjs, Uses(frame.frameDepth()));
|
||||||
frame.discardFrame();
|
frame.throwaway();
|
||||||
|
|
||||||
stubcc.leave();
|
stubcc.leave();
|
||||||
stubcc.call(stubs::PutActivationObjects);
|
stubcc.call(stubs::PutActivationObjects);
|
||||||
|
@ -1926,8 +1914,6 @@ mjit::Compiler::interruptCheckHelper()
|
||||||
Jump noInterrupt = stubcc.masm.branchTest32(Assembler::Zero, flag);
|
Jump noInterrupt = stubcc.masm.branchTest32(Assembler::Zero, flag);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
frame.freeReg(reg);
|
|
||||||
|
|
||||||
frame.sync(stubcc.masm, Uses(0));
|
frame.sync(stubcc.masm, Uses(0));
|
||||||
stubcc.masm.move(ImmPtr(PC), Registers::ArgReg1);
|
stubcc.masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||||
stubcc.call(stubs::Interrupt);
|
stubcc.call(stubs::Interrupt);
|
||||||
|
@ -1937,6 +1923,8 @@ mjit::Compiler::interruptCheckHelper()
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
stubcc.linkRejoin(noInterrupt);
|
stubcc.linkRejoin(noInterrupt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
frame.freeReg(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2028,9 +2016,7 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||||
* registers we've preserved.
|
* registers we've preserved.
|
||||||
*/
|
*/
|
||||||
frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2));
|
frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2));
|
||||||
frame.unpinKilledReg(dataReg);
|
frame.resetRegState();
|
||||||
if (typeReg.isSet())
|
|
||||||
frame.unpinKilledReg(typeReg.reg());
|
|
||||||
|
|
||||||
Registers tempRegs;
|
Registers tempRegs;
|
||||||
|
|
||||||
|
@ -2294,7 +2280,7 @@ mjit::Compiler::emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused)
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(fused == JSOP_IFEQ || fused == JSOP_IFNE);
|
JS_ASSERT(fused == JSOP_IFEQ || fused == JSOP_IFNE);
|
||||||
|
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
Assembler::Condition cond = (fused == JSOP_IFEQ)
|
Assembler::Condition cond = (fused == JSOP_IFEQ)
|
||||||
? Assembler::Zero
|
? Assembler::Zero
|
||||||
: Assembler::NonZero;
|
: Assembler::NonZero;
|
||||||
|
@ -3694,7 +3680,7 @@ mjit::Compiler::iterMore()
|
||||||
|
|
||||||
/* Get props_cursor, test */
|
/* Get props_cursor, test */
|
||||||
RegisterID T2 = frame.allocReg();
|
RegisterID T2 = frame.allocReg();
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
masm.loadPtr(Address(T1, offsetof(NativeIterator, props_cursor)), T2);
|
masm.loadPtr(Address(T1, offsetof(NativeIterator, props_cursor)), T2);
|
||||||
masm.loadPtr(Address(T1, offsetof(NativeIterator, props_end)), T1);
|
masm.loadPtr(Address(T1, offsetof(NativeIterator, props_end)), T1);
|
||||||
Jump jFast = masm.branchPtr(Assembler::LessThan, T2, T1);
|
Jump jFast = masm.branchPtr(Assembler::LessThan, T2, T1);
|
||||||
|
@ -3931,7 +3917,8 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
||||||
mic.shape);
|
mic.shape);
|
||||||
masm.move(ImmPtr(obj), objReg);
|
masm.move(ImmPtr(obj), objReg);
|
||||||
} else {
|
} else {
|
||||||
objReg = frame.copyDataIntoReg(objFe);
|
objReg = frame.tempRegForData(objFe);
|
||||||
|
frame.pinReg(objReg);
|
||||||
RegisterID reg = frame.allocReg();
|
RegisterID reg = frame.allocReg();
|
||||||
|
|
||||||
masm.loadShape(objReg, reg);
|
masm.loadShape(objReg, reg);
|
||||||
|
@ -4025,7 +4012,8 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
||||||
JS_ASSERT(mic.patchValueOffset == masm.differenceBetween(mic.load, masm.label()));
|
JS_ASSERT(mic.patchValueOffset == masm.differenceBetween(mic.load, masm.label()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
frame.freeReg(objReg);
|
if (objFe->isConstant())
|
||||||
|
frame.freeReg(objReg);
|
||||||
frame.popn(2);
|
frame.popn(2);
|
||||||
if (mic.u.name.dataConst) {
|
if (mic.u.name.dataConst) {
|
||||||
frame.push(v);
|
frame.push(v);
|
||||||
|
|
|
@ -1000,7 +1000,7 @@ mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *tar
|
||||||
|
|
||||||
frame.pop();
|
frame.pop();
|
||||||
frame.pop();
|
frame.pop();
|
||||||
frame.discardFrame();
|
frame.throwaway();
|
||||||
|
|
||||||
/* Start of the slow path for equality stub call. */
|
/* Start of the slow path for equality stub call. */
|
||||||
Label stubCall = stubcc.masm.label();
|
Label stubCall = stubcc.masm.label();
|
||||||
|
@ -1286,7 +1286,7 @@ mjit::Compiler::jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *targe
|
||||||
stubcc.call(stub);
|
stubcc.call(stub);
|
||||||
|
|
||||||
frame.popn(2);
|
frame.popn(2);
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
|
|
||||||
Jump j = masm.branchDouble(dblCond, fpLeft, fpRight);
|
Jump j = masm.branchDouble(dblCond, fpLeft, fpRight);
|
||||||
|
|
||||||
|
@ -1453,12 +1453,7 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
|
||||||
frame.pinReg(reg.reg());
|
frame.pinReg(reg.reg());
|
||||||
|
|
||||||
frame.popn(2);
|
frame.popn(2);
|
||||||
|
frame.forgetEverything();
|
||||||
frame.syncAndKillEverything();
|
|
||||||
frame.unpinKilledReg(cmpReg);
|
|
||||||
if (reg.isSet())
|
|
||||||
frame.unpinKilledReg(reg.reg());
|
|
||||||
frame.syncAndForgetEverything();
|
|
||||||
|
|
||||||
/* Operands could have been reordered, so use cmpOp. */
|
/* Operands could have been reordered, so use cmpOp. */
|
||||||
Assembler::Condition i32Cond;
|
Assembler::Condition i32Cond;
|
||||||
|
|
|
@ -660,7 +660,7 @@ mjit::Compiler::jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp f
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
|
|
||||||
if ((op == JSOP_EQ && fused == JSOP_IFNE) ||
|
if ((op == JSOP_EQ && fused == JSOP_IFNE) ||
|
||||||
(op == JSOP_NE && fused == JSOP_IFEQ)) {
|
(op == JSOP_NE && fused == JSOP_IFEQ)) {
|
||||||
|
@ -907,7 +907,8 @@ mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target)
|
||||||
type.setReg(frame.copyTypeIntoReg(fe));
|
type.setReg(frame.copyTypeIntoReg(fe));
|
||||||
data.setReg(frame.copyDataIntoReg(fe));
|
data.setReg(frame.copyDataIntoReg(fe));
|
||||||
|
|
||||||
frame.syncAndForgetEverything();
|
/* :FIXME: Can something more lightweight be used? */
|
||||||
|
frame.forgetEverything();
|
||||||
|
|
||||||
Assembler::Condition cond = (op == JSOP_IFNE || op == JSOP_OR)
|
Assembler::Condition cond = (op == JSOP_IFNE || op == JSOP_OR)
|
||||||
? Assembler::NonZero
|
? Assembler::NonZero
|
||||||
|
@ -994,7 +995,7 @@ mjit::Compiler::jsop_ifneq(JSOp op, jsbytecode *target)
|
||||||
if (op == JSOP_IFEQ)
|
if (op == JSOP_IFEQ)
|
||||||
b = !b;
|
b = !b;
|
||||||
if (b) {
|
if (b) {
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
jumpAndTrace(masm.jump(), target);
|
jumpAndTrace(masm.jump(), target);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -1014,7 +1015,7 @@ mjit::Compiler::jsop_andor(JSOp op, jsbytecode *target)
|
||||||
/* Short-circuit. */
|
/* Short-circuit. */
|
||||||
if ((op == JSOP_OR && b == JS_TRUE) ||
|
if ((op == JSOP_OR && b == JS_TRUE) ||
|
||||||
(op == JSOP_AND && b == JS_FALSE)) {
|
(op == JSOP_AND && b == JS_FALSE)) {
|
||||||
frame.syncAndForgetEverything();
|
frame.forgetEverything();
|
||||||
jumpAndTrace(masm.jump(), target);
|
jumpAndTrace(masm.jump(), target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,6 @@ class FrameEntry
|
||||||
void track(uint32 index) {
|
void track(uint32 index) {
|
||||||
clear();
|
clear();
|
||||||
index_ = index;
|
index_ = index;
|
||||||
tracked = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
@ -211,14 +210,6 @@ class FrameEntry
|
||||||
copy = fe;
|
copy = fe;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isTracked() const {
|
|
||||||
return tracked;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void untrack() {
|
|
||||||
tracked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSValueType knownType;
|
JSValueType knownType;
|
||||||
jsval_layout v_;
|
jsval_layout v_;
|
||||||
|
@ -228,8 +219,7 @@ class FrameEntry
|
||||||
FrameEntry *copy;
|
FrameEntry *copy;
|
||||||
bool copied;
|
bool copied;
|
||||||
bool isNumber;
|
bool isNumber;
|
||||||
bool tracked;
|
char padding[2];
|
||||||
char padding[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace mjit */
|
} /* namespace mjit */
|
||||||
|
|
|
@ -43,13 +43,16 @@
|
||||||
namespace js {
|
namespace js {
|
||||||
namespace mjit {
|
namespace mjit {
|
||||||
|
|
||||||
inline void
|
inline FrameEntry *
|
||||||
FrameState::addToTracker(FrameEntry *fe)
|
FrameState::addToTracker(uint32 index)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!fe->isTracked());
|
JS_ASSERT(!base[index]);
|
||||||
|
FrameEntry *fe = &entries[index];
|
||||||
|
base[index] = fe;
|
||||||
fe->track(tracker.nentries);
|
fe->track(tracker.nentries);
|
||||||
tracker.add(fe);
|
tracker.add(fe);
|
||||||
JS_ASSERT(tracker.nentries <= script->nslots);
|
JS_ASSERT(tracker.nentries <= script->nslots);
|
||||||
|
return fe;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FrameEntry *
|
inline FrameEntry *
|
||||||
|
@ -57,9 +60,9 @@ FrameState::peek(int32 depth)
|
||||||
{
|
{
|
||||||
JS_ASSERT(depth < 0);
|
JS_ASSERT(depth < 0);
|
||||||
JS_ASSERT(sp + depth >= spBase);
|
JS_ASSERT(sp + depth >= spBase);
|
||||||
FrameEntry *fe = &sp[depth];
|
FrameEntry *fe = sp[depth];
|
||||||
if (!fe->isTracked()) {
|
if (!fe) {
|
||||||
addToTracker(fe);
|
fe = addToTracker(indexOf(depth));
|
||||||
fe->resetSynced();
|
fe->resetSynced();
|
||||||
}
|
}
|
||||||
return fe;
|
return fe;
|
||||||
|
@ -86,13 +89,11 @@ inline JSC::MacroAssembler::RegisterID
|
||||||
FrameState::allocReg()
|
FrameState::allocReg()
|
||||||
{
|
{
|
||||||
RegisterID reg;
|
RegisterID reg;
|
||||||
if (!freeRegs.empty()) {
|
if (!freeRegs.empty())
|
||||||
reg = freeRegs.takeAnyReg();
|
reg = freeRegs.takeAnyReg();
|
||||||
} else {
|
else
|
||||||
reg = evictSomeReg();
|
reg = evictSomeReg();
|
||||||
regstate[reg].forget();
|
regstate[reg].fe = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,13 +101,11 @@ inline JSC::MacroAssembler::RegisterID
|
||||||
FrameState::allocReg(uint32 mask)
|
FrameState::allocReg(uint32 mask)
|
||||||
{
|
{
|
||||||
RegisterID reg;
|
RegisterID reg;
|
||||||
if (freeRegs.hasRegInMask(mask)) {
|
if (freeRegs.hasRegInMask(mask))
|
||||||
reg = freeRegs.takeRegInMask(mask);
|
reg = freeRegs.takeRegInMask(mask);
|
||||||
} else {
|
else
|
||||||
reg = evictSomeReg(mask);
|
reg = evictSomeReg(mask);
|
||||||
regstate[reg].forget();
|
regstate[reg].fe = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,15 +113,11 @@ inline JSC::MacroAssembler::RegisterID
|
||||||
FrameState::allocReg(FrameEntry *fe, RematInfo::RematType type)
|
FrameState::allocReg(FrameEntry *fe, RematInfo::RematType type)
|
||||||
{
|
{
|
||||||
RegisterID reg;
|
RegisterID reg;
|
||||||
if (!freeRegs.empty()) {
|
if (!freeRegs.empty())
|
||||||
reg = freeRegs.takeAnyReg();
|
reg = freeRegs.takeAnyReg();
|
||||||
} else {
|
else
|
||||||
reg = evictSomeReg();
|
reg = evictSomeReg();
|
||||||
regstate[reg].forget();
|
regstate[reg] = RegisterState(fe, type);
|
||||||
}
|
|
||||||
|
|
||||||
regstate[reg].associate(fe, type);
|
|
||||||
|
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +162,8 @@ FrameState::pop()
|
||||||
{
|
{
|
||||||
JS_ASSERT(sp > spBase);
|
JS_ASSERT(sp > spBase);
|
||||||
|
|
||||||
FrameEntry *fe = --sp;
|
FrameEntry *fe = *--sp;
|
||||||
if (!fe->isTracked())
|
if (!fe)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
forgetAllRegs(fe);
|
forgetAllRegs(fe);
|
||||||
|
@ -177,8 +172,7 @@ FrameState::pop()
|
||||||
inline void
|
inline void
|
||||||
FrameState::freeReg(RegisterID reg)
|
FrameState::freeReg(RegisterID reg)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!regstate[reg].usedBy());
|
JS_ASSERT(regstate[reg].fe == NULL);
|
||||||
|
|
||||||
freeRegs.putReg(reg);
|
freeRegs.putReg(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,30 +183,28 @@ FrameState::forgetReg(RegisterID reg)
|
||||||
* Important: Do not touch the fe here. We can peephole optimize away
|
* Important: Do not touch the fe here. We can peephole optimize away
|
||||||
* loads and stores by re-using the contents of old FEs.
|
* loads and stores by re-using the contents of old FEs.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT_IF(regstate[reg].fe(), !regstate[reg].fe()->isCopy());
|
JS_ASSERT_IF(regstate[reg].fe, !regstate[reg].fe->isCopy());
|
||||||
|
freeRegs.putReg(reg);
|
||||||
if (!regstate[reg].isPinned()) {
|
|
||||||
regstate[reg].forget();
|
|
||||||
freeRegs.putReg(reg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FrameState::syncAndForgetEverything(uint32 newStackDepth)
|
FrameState::forgetEverything(uint32 newStackDepth)
|
||||||
{
|
{
|
||||||
syncAndForgetEverything();
|
forgetEverything();
|
||||||
sp = spBase + newStackDepth;
|
sp = spBase + newStackDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FrameEntry *
|
inline FrameEntry *
|
||||||
FrameState::rawPush()
|
FrameState::rawPush()
|
||||||
{
|
{
|
||||||
JS_ASSERT(unsigned(sp - entries) < nargs + script->nslots);
|
JS_ASSERT(unsigned(sp - base) < nargs + script->nslots);
|
||||||
|
|
||||||
if (!sp->isTracked())
|
sp++;
|
||||||
addToTracker(sp);
|
|
||||||
|
|
||||||
return sp++;
|
if (FrameEntry *fe = sp[-1])
|
||||||
|
return fe;
|
||||||
|
|
||||||
|
return addToTracker(&sp[-1] - base);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -225,9 +217,10 @@ FrameState::push(const Value &v)
|
||||||
inline void
|
inline void
|
||||||
FrameState::pushSynced()
|
FrameState::pushSynced()
|
||||||
{
|
{
|
||||||
if (sp->isTracked())
|
|
||||||
sp->resetSynced();
|
|
||||||
sp++;
|
sp++;
|
||||||
|
|
||||||
|
if (FrameEntry *fe = sp[-1])
|
||||||
|
fe->resetSynced();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -249,7 +242,7 @@ FrameState::pushSynced(JSValueType type, RegisterID reg)
|
||||||
fe->data.sync();
|
fe->data.sync();
|
||||||
fe->setType(type);
|
fe->setType(type);
|
||||||
fe->data.setRegister(reg);
|
fe->data.setRegister(reg);
|
||||||
regstate[reg].associate(fe, RematInfo::DATA);
|
regstate[reg] = RegisterState(fe, RematInfo::DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -288,8 +281,8 @@ FrameState::pushRegs(RegisterID type, RegisterID data)
|
||||||
fe->resetUnsynced();
|
fe->resetUnsynced();
|
||||||
fe->type.setRegister(type);
|
fe->type.setRegister(type);
|
||||||
fe->data.setRegister(data);
|
fe->data.setRegister(data);
|
||||||
regstate[type].associate(fe, RematInfo::TYPE);
|
regstate[type] = RegisterState(fe, RematInfo::TYPE);
|
||||||
regstate[data].associate(fe, RematInfo::DATA);
|
regstate[data] = RegisterState(fe, RematInfo::DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -302,7 +295,7 @@ FrameState::pushTypedPayload(JSValueType type, RegisterID payload)
|
||||||
fe->resetUnsynced();
|
fe->resetUnsynced();
|
||||||
fe->setType(type);
|
fe->setType(type);
|
||||||
fe->data.setRegister(payload);
|
fe->data.setRegister(payload);
|
||||||
regstate[payload].associate(fe, RematInfo::DATA);
|
regstate[payload] = RegisterState(fe, RematInfo::DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -327,7 +320,7 @@ FrameState::pushNumber(MaybeRegisterID payload, bool asInt32)
|
||||||
if (payload.isSet()) {
|
if (payload.isSet()) {
|
||||||
fe->data.unsync();
|
fe->data.unsync();
|
||||||
fe->data.setRegister(payload.reg());
|
fe->data.setRegister(payload.reg());
|
||||||
regstate[payload.reg()].associate(fe, RematInfo::DATA);
|
regstate[payload.reg()] = RegisterState(fe, RematInfo::DATA);
|
||||||
} else {
|
} else {
|
||||||
fe->data.setMemory();
|
fe->data.setMemory();
|
||||||
}
|
}
|
||||||
|
@ -346,7 +339,7 @@ FrameState::pushInt32(RegisterID payload)
|
||||||
fe->isNumber = true;
|
fe->isNumber = true;
|
||||||
fe->data.unsync();
|
fe->data.unsync();
|
||||||
fe->data.setRegister(payload);
|
fe->data.setRegister(payload);
|
||||||
regstate[payload].associate(fe, RematInfo::DATA);
|
regstate[payload] = RegisterState(fe, RematInfo::DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -369,13 +362,13 @@ FrameState::pushUntypedPayload(JSValueType type, RegisterID payload)
|
||||||
fe->setNotCopied();
|
fe->setNotCopied();
|
||||||
fe->setCopyOf(NULL);
|
fe->setCopyOf(NULL);
|
||||||
fe->data.setRegister(payload);
|
fe->data.setRegister(payload);
|
||||||
regstate[payload].associate(fe, RematInfo::DATA);
|
regstate[payload] = RegisterState(fe, RematInfo::DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline JSC::MacroAssembler::RegisterID
|
inline JSC::MacroAssembler::RegisterID
|
||||||
FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback)
|
FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!regstate[fallback].fe());
|
JS_ASSERT(regstate[fallback].fe == NULL);
|
||||||
if (fe->isCopy())
|
if (fe->isCopy())
|
||||||
fe = fe->copyOf();
|
fe = fe->copyOf();
|
||||||
|
|
||||||
|
@ -442,7 +435,7 @@ FrameState::tempRegInMaskForData(FrameEntry *fe, uint32 mask)
|
||||||
return old;
|
return old;
|
||||||
|
|
||||||
/* Keep the old register pinned. */
|
/* Keep the old register pinned. */
|
||||||
regstate[old].forget();
|
regstate[old].fe = NULL;
|
||||||
reg = allocReg(mask);
|
reg = allocReg(mask);
|
||||||
masm.move(old, reg);
|
masm.move(old, reg);
|
||||||
freeReg(old);
|
freeReg(old);
|
||||||
|
@ -450,7 +443,7 @@ FrameState::tempRegInMaskForData(FrameEntry *fe, uint32 mask)
|
||||||
reg = allocReg(mask);
|
reg = allocReg(mask);
|
||||||
masm.loadPayload(addressOf(fe), reg);
|
masm.loadPayload(addressOf(fe), reg);
|
||||||
}
|
}
|
||||||
regstate[reg].associate(fe, RematInfo::DATA);
|
regstate[reg] = RegisterState(fe, RematInfo::DATA);
|
||||||
fe->data.setRegister(reg);
|
fe->data.setRegister(reg);
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
@ -625,31 +618,28 @@ inline FrameEntry *
|
||||||
FrameState::getLocal(uint32 slot)
|
FrameState::getLocal(uint32 slot)
|
||||||
{
|
{
|
||||||
uint32 index = nargs + slot;
|
uint32 index = nargs + slot;
|
||||||
FrameEntry *fe = &entries[index];
|
if (FrameEntry *fe = base[index])
|
||||||
if (!fe->isTracked()) {
|
return fe;
|
||||||
addToTracker(fe);
|
FrameEntry *fe = addToTracker(index);
|
||||||
fe->resetSynced();
|
fe->resetSynced();
|
||||||
}
|
|
||||||
return fe;
|
return fe;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FrameState::pinReg(RegisterID reg)
|
FrameState::pinReg(RegisterID reg)
|
||||||
{
|
{
|
||||||
regstate[reg].pin();
|
JS_ASSERT(!freeRegs.hasReg(reg));
|
||||||
|
JS_ASSERT(regstate[reg].fe);
|
||||||
|
regstate[reg].save = regstate[reg].fe;
|
||||||
|
regstate[reg].fe = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FrameState::unpinReg(RegisterID reg)
|
FrameState::unpinReg(RegisterID reg)
|
||||||
{
|
{
|
||||||
regstate[reg].unpin();
|
JS_ASSERT(!freeRegs.hasReg(reg));
|
||||||
}
|
JS_ASSERT(!regstate[reg].fe);
|
||||||
|
regstate[reg].fe = regstate[reg].save;
|
||||||
inline void
|
|
||||||
FrameState::unpinKilledReg(RegisterID reg)
|
|
||||||
{
|
|
||||||
regstate[reg].unpinUnsafe();
|
|
||||||
freeRegs.putReg(reg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -661,6 +651,12 @@ FrameState::forgetAllRegs(FrameEntry *fe)
|
||||||
forgetReg(fe->data.reg());
|
forgetReg(fe->data.reg());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline FrameEntry *
|
||||||
|
FrameState::tosFe() const
|
||||||
|
{
|
||||||
|
return &entries[uint32(sp - base)];
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs)
|
FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs)
|
||||||
{
|
{
|
||||||
|
@ -715,8 +711,8 @@ FrameState::pushLocal(uint32 n)
|
||||||
* SETLOCAL equivocation of stack slots, and let expressions, just
|
* SETLOCAL equivocation of stack slots, and let expressions, just
|
||||||
* weakly assert on the fixed local vars.
|
* weakly assert on the fixed local vars.
|
||||||
*/
|
*/
|
||||||
FrameEntry *fe = &locals[n];
|
FrameEntry *fe = base[localIndex(n)];
|
||||||
if (fe->isTracked() && n < script->nfixed) {
|
if (fe && n < script->nfixed) {
|
||||||
JS_ASSERT(fe->type.inMemory());
|
JS_ASSERT(fe->type.inMemory());
|
||||||
JS_ASSERT(fe->data.inMemory());
|
JS_ASSERT(fe->data.inMemory());
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,17 +64,19 @@ FrameState::init(uint32 nargs)
|
||||||
|
|
||||||
uint32 nslots = script->nslots + nargs;
|
uint32 nslots = script->nslots + nargs;
|
||||||
if (!nslots) {
|
if (!nslots) {
|
||||||
sp = spBase = locals = args = NULL;
|
sp = spBase = locals = args = base = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
eval = script->usesEval || cx->compartment->debugMode;
|
uint32 nlocals = script->nslots;
|
||||||
|
if ((eval = script->usesEval || cx->compartment->debugMode))
|
||||||
|
nlocals = 0;
|
||||||
|
|
||||||
size_t totalBytes = sizeof(FrameEntry) * nslots + // entries[]
|
uint8 *cursor = (uint8 *)cx->malloc(sizeof(FrameEntry) * nslots + // entries[]
|
||||||
sizeof(FrameEntry *) * nslots + // tracker.entries
|
sizeof(FrameEntry *) * nslots + // base[]
|
||||||
(eval ? 0 : sizeof(uint32) * nslots); // closedVars[]
|
sizeof(FrameEntry *) * nslots + // tracker.entries[]
|
||||||
|
sizeof(uint32) * nlocals // escaping[]
|
||||||
uint8 *cursor = (uint8 *)cx->calloc(totalBytes);
|
);
|
||||||
if (!cursor)
|
if (!cursor)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -84,21 +86,22 @@ FrameState::init(uint32 nargs)
|
||||||
entries = (FrameEntry *)cursor;
|
entries = (FrameEntry *)cursor;
|
||||||
cursor += sizeof(FrameEntry) * nslots;
|
cursor += sizeof(FrameEntry) * nslots;
|
||||||
|
|
||||||
args = entries;
|
base = (FrameEntry **)cursor;
|
||||||
locals = args + nargs;
|
args = base;
|
||||||
|
locals = base + nargs;
|
||||||
spBase = locals + script->nfixed;
|
spBase = locals + script->nfixed;
|
||||||
sp = spBase;
|
sp = spBase;
|
||||||
|
memset(base, 0, sizeof(FrameEntry *) * nslots);
|
||||||
|
cursor += sizeof(FrameEntry *) * nslots;
|
||||||
|
|
||||||
tracker.entries = (FrameEntry **)cursor;
|
tracker.entries = (FrameEntry **)cursor;
|
||||||
cursor += sizeof(FrameEntry *) * nslots;
|
cursor += sizeof(FrameEntry *) * nslots;
|
||||||
|
|
||||||
if (!eval && nslots) {
|
if (nlocals) {
|
||||||
escaping = (uint32 *)cursor;
|
escaping = (uint32 *)cursor;
|
||||||
cursor += sizeof(uint32) * nslots;
|
memset(escaping, 0, sizeof(uint32) * nlocals);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(reinterpret_cast<uint8 *>(entries) + totalBytes == cursor);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,20 +110,19 @@ FrameState::takeReg(RegisterID reg)
|
||||||
{
|
{
|
||||||
if (freeRegs.hasReg(reg)) {
|
if (freeRegs.hasReg(reg)) {
|
||||||
freeRegs.takeReg(reg);
|
freeRegs.takeReg(reg);
|
||||||
JS_ASSERT(!regstate[reg].usedBy());
|
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(regstate[reg].fe());
|
JS_ASSERT(regstate[reg].fe);
|
||||||
evictReg(reg);
|
evictReg(reg);
|
||||||
regstate[reg].forget();
|
|
||||||
}
|
}
|
||||||
|
regstate[reg].fe = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FrameState::evictReg(RegisterID reg)
|
FrameState::evictReg(RegisterID reg)
|
||||||
{
|
{
|
||||||
FrameEntry *fe = regstate[reg].fe();
|
FrameEntry *fe = regstate[reg].fe;
|
||||||
|
|
||||||
if (regstate[reg].type() == RematInfo::TYPE) {
|
if (regstate[reg].type == RematInfo::TYPE) {
|
||||||
if (!fe->type.synced()) {
|
if (!fe->type.synced()) {
|
||||||
syncType(fe, addressOf(fe), masm);
|
syncType(fe, addressOf(fe), masm);
|
||||||
fe->type.sync();
|
fe->type.sync();
|
||||||
|
@ -151,7 +153,7 @@ FrameState::evictSomeReg(uint32 mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Register is not owned by the FrameState. */
|
/* Register is not owned by the FrameState. */
|
||||||
FrameEntry *fe = regstate[i].fe();
|
FrameEntry *fe = regstate[i].fe;
|
||||||
if (!fe)
|
if (!fe)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -161,11 +163,11 @@ FrameState::evictSomeReg(uint32 mask)
|
||||||
#endif
|
#endif
|
||||||
fallback = reg;
|
fallback = reg;
|
||||||
|
|
||||||
if (regstate[i].type() == RematInfo::TYPE && fe->type.synced()) {
|
if (regstate[i].type == RematInfo::TYPE && fe->type.synced()) {
|
||||||
fe->type.setMemory();
|
fe->type.setMemory();
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
if (regstate[i].type() == RematInfo::DATA && fe->data.synced()) {
|
if (regstate[i].type == RematInfo::DATA && fe->data.synced()) {
|
||||||
fe->data.setMemory();
|
fe->data.setMemory();
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
@ -179,42 +181,24 @@ FrameState::evictSomeReg(uint32 mask)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FrameState::syncAndForgetEverything()
|
FrameState::forgetEverything()
|
||||||
{
|
{
|
||||||
syncAndKill(Registers(Registers::AvailRegs), Uses(frameDepth()));
|
syncAndKill(Registers(Registers::AvailRegs), Uses(frameDepth()));
|
||||||
forgetEverything();
|
|
||||||
|
throwaway();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FrameState::resetInternalState()
|
FrameState::throwaway()
|
||||||
{
|
{
|
||||||
for (uint32 i = 0; i < tracker.nentries; i++)
|
for (uint32 i = 0; i < tracker.nentries; i++)
|
||||||
tracker[i]->untrack();
|
base[indexOfFe(tracker[i])] = NULL;
|
||||||
|
|
||||||
tracker.reset();
|
tracker.reset();
|
||||||
freeRegs.reset();
|
freeRegs.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
FrameState::discardFrame()
|
|
||||||
{
|
|
||||||
resetInternalState();
|
|
||||||
|
|
||||||
memset(regstate, 0, sizeof(regstate));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FrameState::forgetEverything()
|
|
||||||
{
|
|
||||||
resetInternalState();
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
|
|
||||||
JS_ASSERT(!regstate[i].usedBy());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
|
FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
|
||||||
{
|
{
|
||||||
|
@ -269,49 +253,46 @@ FrameState::assertValidRegisterState() const
|
||||||
{
|
{
|
||||||
Registers checkedFreeRegs;
|
Registers checkedFreeRegs;
|
||||||
|
|
||||||
|
FrameEntry *tos = tosFe();
|
||||||
for (uint32 i = 0; i < tracker.nentries; i++) {
|
for (uint32 i = 0; i < tracker.nentries; i++) {
|
||||||
FrameEntry *fe = tracker[i];
|
FrameEntry *fe = tracker[i];
|
||||||
if (fe >= sp)
|
if (fe >= tos)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
JS_ASSERT(i == fe->trackerIndex());
|
JS_ASSERT(i == fe->trackerIndex());
|
||||||
JS_ASSERT_IF(fe->isCopy(),
|
JS_ASSERT_IF(fe->isCopy(),
|
||||||
fe->trackerIndex() > fe->copyOf()->trackerIndex());
|
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());
|
||||||
JS_ASSERT_IF(fe->isCopy(), fe->copyOf() < sp);
|
JS_ASSERT_IF(fe->isCopy(), fe->copyOf() < tos);
|
||||||
JS_ASSERT_IF(fe->isCopy(), fe->copyOf()->isCopied());
|
JS_ASSERT_IF(fe->isCopy(), fe->copyOf()->isCopied());
|
||||||
|
|
||||||
if (fe->isCopy())
|
if (fe->isCopy())
|
||||||
continue;
|
continue;
|
||||||
if (fe->type.inRegister()) {
|
if (fe->type.inRegister()) {
|
||||||
checkedFreeRegs.takeReg(fe->type.reg());
|
checkedFreeRegs.takeReg(fe->type.reg());
|
||||||
JS_ASSERT(regstate[fe->type.reg()].fe() == fe);
|
JS_ASSERT(regstate[fe->type.reg()].fe == fe);
|
||||||
}
|
}
|
||||||
if (fe->data.inRegister()) {
|
if (fe->data.inRegister()) {
|
||||||
checkedFreeRegs.takeReg(fe->data.reg());
|
checkedFreeRegs.takeReg(fe->data.reg());
|
||||||
JS_ASSERT(regstate[fe->data.reg()].fe() == fe);
|
JS_ASSERT(regstate[fe->data.reg()].fe == fe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(checkedFreeRegs == freeRegs);
|
JS_ASSERT(checkedFreeRegs == freeRegs);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
FrameState::syncFancy(Assembler &masm, Registers avail, FrameEntry *resumeAt,
|
FrameState::syncFancy(Assembler &masm, Registers avail, uint32 resumeAt,
|
||||||
FrameEntry *bottom) const
|
FrameEntry *bottom) const
|
||||||
{
|
{
|
||||||
reifier.reset(&masm, avail, resumeAt, bottom);
|
/* :TODO: can be resumeAt? */
|
||||||
|
reifier.reset(&masm, avail, tracker.nentries, bottom);
|
||||||
|
|
||||||
for (FrameEntry *fe = resumeAt; fe >= bottom; fe--) {
|
FrameEntry *tos = tosFe();
|
||||||
if (!fe->isTracked())
|
for (uint32 i = resumeAt; i < tracker.nentries; i--) {
|
||||||
|
FrameEntry *fe = tracker[i];
|
||||||
|
if (fe >= tos)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
reifier.sync(fe);
|
reifier.sync(fe);
|
||||||
|
@ -321,29 +302,6 @@ FrameState::syncFancy(Assembler &masm, Registers avail, FrameEntry *resumeAt,
|
||||||
void
|
void
|
||||||
FrameState::sync(Assembler &masm, Uses uses) const
|
FrameState::sync(Assembler &masm, Uses uses) const
|
||||||
{
|
{
|
||||||
if (!entries)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Sync all registers up-front. */
|
|
||||||
for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
|
|
||||||
RegisterID reg = RegisterID(i);
|
|
||||||
FrameEntry *fe = regstate[reg].usedBy();
|
|
||||||
if (!fe)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
JS_ASSERT(fe->isTracked());
|
|
||||||
|
|
||||||
if (regstate[reg].type() == RematInfo::DATA) {
|
|
||||||
JS_ASSERT(fe->data.reg() == reg);
|
|
||||||
if (!fe->data.synced())
|
|
||||||
syncData(fe, addressOf(fe), masm);
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(fe->type.reg() == reg);
|
|
||||||
if (!fe->type.synced())
|
|
||||||
syncType(fe, addressOf(fe), masm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Keep track of free registers using a bitmask. If we have to drop into
|
* Keep track of free registers using a bitmask. If we have to drop into
|
||||||
* syncFancy(), then this mask will help avoid eviction.
|
* syncFancy(), then this mask will help avoid eviction.
|
||||||
|
@ -351,33 +309,35 @@ FrameState::sync(Assembler &masm, Uses uses) const
|
||||||
Registers avail(freeRegs);
|
Registers avail(freeRegs);
|
||||||
Registers temp(Registers::TempRegs);
|
Registers temp(Registers::TempRegs);
|
||||||
|
|
||||||
FrameEntry *bottom = sp - uses.nuses;
|
FrameEntry *tos = tosFe();
|
||||||
|
FrameEntry *bottom = tos - uses.nuses;
|
||||||
|
|
||||||
for (FrameEntry *fe = sp - 1; fe >= bottom; fe--) {
|
if (inTryBlock)
|
||||||
if (!fe->isTracked())
|
bottom = NULL;
|
||||||
|
|
||||||
|
for (uint32 i = tracker.nentries - 1; i < tracker.nentries; i--) {
|
||||||
|
FrameEntry *fe = tracker[i];
|
||||||
|
if (fe >= tos)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Address address = addressOf(fe);
|
Address address = addressOf(fe);
|
||||||
|
|
||||||
if (!fe->isCopy()) {
|
if (!fe->isCopy()) {
|
||||||
/*
|
/* Keep track of registers that can be clobbered. */
|
||||||
* If this |fe| has registers, track them as available. They've
|
if (fe->data.inRegister())
|
||||||
* already been synced. Otherwise, see if a constant needs to be
|
|
||||||
* synced.
|
|
||||||
*/
|
|
||||||
if (fe->data.inRegister()) {
|
|
||||||
avail.putReg(fe->data.reg());
|
avail.putReg(fe->data.reg());
|
||||||
} else if (!fe->data.synced()) {
|
if (fe->type.inRegister())
|
||||||
|
avail.putReg(fe->type.reg());
|
||||||
|
|
||||||
|
/* Sync. */
|
||||||
|
if (!fe->data.synced() && (fe->data.inRegister() || fe >= bottom)) {
|
||||||
syncData(fe, address, masm);
|
syncData(fe, address, masm);
|
||||||
if (fe->isConstant())
|
if (fe->isConstant())
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!fe->type.synced() && (fe->type.inRegister() || fe >= bottom))
|
||||||
if (fe->type.inRegister())
|
syncType(fe, addressOf(fe), masm);
|
||||||
avail.putReg(fe->type.reg());
|
} else if (fe >= bottom) {
|
||||||
else if (!fe->type.synced())
|
|
||||||
syncType(fe, address, masm);
|
|
||||||
} else {
|
|
||||||
FrameEntry *backing = fe->copyOf();
|
FrameEntry *backing = fe->copyOf();
|
||||||
JS_ASSERT(backing != fe);
|
JS_ASSERT(backing != fe);
|
||||||
JS_ASSERT(!backing->isConstant() && !fe->isConstant());
|
JS_ASSERT(!backing->isConstant() && !fe->isConstant());
|
||||||
|
@ -388,7 +348,7 @@ FrameState::sync(Assembler &masm, Uses uses) const
|
||||||
*/
|
*/
|
||||||
if ((!fe->type.synced() && !backing->type.inRegister()) ||
|
if ((!fe->type.synced() && !backing->type.inRegister()) ||
|
||||||
(!fe->data.synced() && !backing->data.inRegister())) {
|
(!fe->data.synced() && !backing->data.inRegister())) {
|
||||||
syncFancy(masm, avail, fe, bottom);
|
syncFancy(masm, avail, i, bottom);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,130 +371,93 @@ FrameState::sync(Assembler &masm, Uses uses) const
|
||||||
void
|
void
|
||||||
FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore)
|
FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore)
|
||||||
{
|
{
|
||||||
FrameEntry *spStop = sp - ignore.nuses;
|
/* Backwards, so we can allocate registers to backing slots better. */
|
||||||
|
FrameEntry *tos = tosFe();
|
||||||
|
FrameEntry *bottom = tos - uses.nuses;
|
||||||
|
|
||||||
/* Sync all kill-registers up-front. */
|
tos -= ignore.nuses;
|
||||||
Registers search(kill.freeMask & ~freeRegs.freeMask);
|
|
||||||
while (!search.empty()) {
|
|
||||||
RegisterID reg = search.takeAnyReg();
|
|
||||||
FrameEntry *fe = regstate[reg].usedBy();
|
|
||||||
if (!fe || fe >= spStop)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
JS_ASSERT(fe->isTracked());
|
if (inTryBlock)
|
||||||
|
bottom = NULL;
|
||||||
|
|
||||||
if (regstate[reg].type() == RematInfo::DATA) {
|
for (uint32 i = tracker.nentries - 1; i < tracker.nentries; i--) {
|
||||||
JS_ASSERT(fe->data.reg() == reg);
|
FrameEntry *fe = tracker[i];
|
||||||
if (!fe->data.synced()) {
|
if (fe >= tos)
|
||||||
syncData(fe, addressOf(fe), masm);
|
|
||||||
fe->data.sync();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(fe->type.reg() == reg);
|
|
||||||
if (!fe->type.synced()) {
|
|
||||||
syncType(fe, addressOf(fe), masm);
|
|
||||||
fe->type.sync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 maxvisits = tracker.nentries;
|
|
||||||
FrameEntry *bottom = sp - uses.nuses;
|
|
||||||
|
|
||||||
for (FrameEntry *fe = sp - 1; fe >= bottom && maxvisits; fe--) {
|
|
||||||
if (!fe->isTracked())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
maxvisits--;
|
|
||||||
|
|
||||||
if (fe >= spStop)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Address address = addressOf(fe);
|
Address address = addressOf(fe);
|
||||||
FrameEntry *backing = fe;
|
FrameEntry *backing = fe;
|
||||||
|
if (fe->isCopy()) {
|
||||||
if (fe->isCopy())
|
if (!inTryBlock && fe < bottom)
|
||||||
|
continue;
|
||||||
backing = fe->copyOf();
|
backing = fe->copyOf();
|
||||||
|
}
|
||||||
|
|
||||||
if (!fe->data.synced()) {
|
JS_ASSERT_IF(i == 0, !fe->isCopy());
|
||||||
|
|
||||||
|
bool killData = fe->data.inRegister() && kill.hasReg(fe->data.reg());
|
||||||
|
if (!fe->data.synced() && (killData || fe >= bottom)) {
|
||||||
if (backing != fe && backing->data.inMemory())
|
if (backing != fe && backing->data.inMemory())
|
||||||
tempRegForData(backing);
|
tempRegForData(backing);
|
||||||
syncData(backing, address, masm);
|
syncData(backing, address, masm);
|
||||||
fe->data.sync();
|
fe->data.sync();
|
||||||
if (fe->isConstant() && !fe->type.synced()) {
|
if (fe->isConstant() && !fe->type.synced())
|
||||||
fe->type.sync();
|
fe->type.sync();
|
||||||
} else if (fe->data.inRegister() && kill.hasReg(fe->data.reg())) {
|
|
||||||
forgetReg(fe->data.reg());
|
|
||||||
fe->data.setMemory();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!fe->type.synced()) {
|
if (killData) {
|
||||||
|
JS_ASSERT(backing == fe);
|
||||||
|
JS_ASSERT(fe->data.synced());
|
||||||
|
if (regstate[fe->data.reg()].fe)
|
||||||
|
forgetReg(fe->data.reg());
|
||||||
|
fe->data.setMemory();
|
||||||
|
}
|
||||||
|
bool killType = fe->type.inRegister() && kill.hasReg(fe->type.reg());
|
||||||
|
if (!fe->type.synced() && (killType || fe >= bottom)) {
|
||||||
if (backing != fe && backing->type.inMemory())
|
if (backing != fe && backing->type.inMemory())
|
||||||
tempRegForType(backing);
|
tempRegForType(backing);
|
||||||
syncType(backing, address, masm);
|
syncType(backing, address, masm);
|
||||||
fe->type.sync();
|
fe->type.sync();
|
||||||
if (fe->type.inRegister() && kill.hasReg(fe->type.reg())) {
|
|
||||||
forgetReg(fe->type.reg());
|
|
||||||
fe->type.setMemory();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if (killType) {
|
||||||
|
JS_ASSERT(backing == fe);
|
||||||
/*
|
|
||||||
* Anything still alive at this point is guaranteed to be synced. However,
|
|
||||||
* it is necessary to evict temporary registers.
|
|
||||||
*/
|
|
||||||
search = Registers(kill.freeMask & ~freeRegs.freeMask);
|
|
||||||
while (!search.empty()) {
|
|
||||||
RegisterID reg = search.takeAnyReg();
|
|
||||||
FrameEntry *fe = regstate[reg].usedBy();
|
|
||||||
if (!fe || fe >= spStop)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
JS_ASSERT(fe->isTracked());
|
|
||||||
|
|
||||||
if (regstate[reg].type() == RematInfo::DATA) {
|
|
||||||
JS_ASSERT(fe->data.reg() == reg);
|
|
||||||
JS_ASSERT(fe->data.synced());
|
|
||||||
fe->data.setMemory();
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(fe->type.reg() == reg);
|
|
||||||
JS_ASSERT(fe->type.synced());
|
JS_ASSERT(fe->type.synced());
|
||||||
|
if (regstate[fe->type.reg()].fe)
|
||||||
|
forgetReg(fe->type.reg());
|
||||||
fe->type.setMemory();
|
fe->type.setMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
forgetReg(reg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FrameState::resetRegState()
|
||||||
|
{
|
||||||
|
freeRegs = Registers();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FrameState::merge(Assembler &masm, Changes changes) const
|
FrameState::merge(Assembler &masm, Changes changes) const
|
||||||
{
|
{
|
||||||
Registers search(Registers::AvailRegs & ~freeRegs.freeMask);
|
FrameEntry *tos = tosFe();
|
||||||
|
Registers temp(Registers::TempRegs);
|
||||||
|
|
||||||
while (!search.empty()) {
|
for (uint32 i = 0; i < tracker.nentries; i++) {
|
||||||
RegisterID reg = search.peekReg();
|
FrameEntry *fe = tracker[i];
|
||||||
FrameEntry *fe = regstate[reg].usedBy();
|
if (fe >= tos)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!fe) {
|
/* Copies do not have registers. */
|
||||||
search.takeReg(reg);
|
if (fe->isCopy()) {
|
||||||
|
JS_ASSERT(!fe->data.inRegister());
|
||||||
|
JS_ASSERT(!fe->type.inRegister());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fe->data.inRegister() && fe->type.inRegister()) {
|
if (fe->data.inRegister() && fe->type.inRegister())
|
||||||
search.takeReg(fe->data.reg());
|
|
||||||
search.takeReg(fe->type.reg());
|
|
||||||
masm.loadValueAsComponents(addressOf(fe), fe->type.reg(), fe->data.reg());
|
masm.loadValueAsComponents(addressOf(fe), fe->type.reg(), fe->data.reg());
|
||||||
} else {
|
else if (fe->data.inRegister())
|
||||||
if (fe->data.inRegister()) {
|
masm.loadPayload(addressOf(fe), fe->data.reg());
|
||||||
search.takeReg(fe->data.reg());
|
else if (fe->type.inRegister())
|
||||||
masm.loadPayload(addressOf(fe), fe->data.reg());
|
masm.loadTypeTag(addressOf(fe), fe->type.reg());
|
||||||
}
|
|
||||||
if (fe->type.inRegister()) {
|
|
||||||
search.takeReg(fe->type.reg());
|
|
||||||
masm.loadTypeTag(addressOf(fe), fe->type.reg());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,9 +488,9 @@ FrameState::copyDataIntoReg(FrameEntry *fe, RegisterID hint)
|
||||||
reg = allocReg();
|
reg = allocReg();
|
||||||
masm.move(hint, reg);
|
masm.move(hint, reg);
|
||||||
fe->data.setRegister(reg);
|
fe->data.setRegister(reg);
|
||||||
regstate[reg].associate(regstate[hint].fe(), RematInfo::DATA);
|
regstate[reg] = regstate[hint];
|
||||||
}
|
}
|
||||||
regstate[hint].forget();
|
regstate[hint].fe = NULL;
|
||||||
} else {
|
} else {
|
||||||
pinReg(reg);
|
pinReg(reg);
|
||||||
takeReg(hint);
|
takeReg(hint);
|
||||||
|
@ -590,7 +513,7 @@ FrameState::copyDataIntoReg(Assembler &masm, FrameEntry *fe)
|
||||||
if (!fe->data.synced())
|
if (!fe->data.synced())
|
||||||
syncData(fe, addressOf(fe), masm);
|
syncData(fe, addressOf(fe), masm);
|
||||||
fe->data.setMemory();
|
fe->data.setMemory();
|
||||||
regstate[reg].forget();
|
regstate[reg].fe = NULL;
|
||||||
} else {
|
} else {
|
||||||
RegisterID newReg = allocReg();
|
RegisterID newReg = allocReg();
|
||||||
masm.move(reg, newReg);
|
masm.move(reg, newReg);
|
||||||
|
@ -623,7 +546,7 @@ FrameState::copyTypeIntoReg(FrameEntry *fe)
|
||||||
if (!fe->type.synced())
|
if (!fe->type.synced())
|
||||||
syncType(fe, addressOf(fe), masm);
|
syncType(fe, addressOf(fe), masm);
|
||||||
fe->type.setMemory();
|
fe->type.setMemory();
|
||||||
regstate[reg].forget();
|
regstate[reg].fe = NULL;
|
||||||
} else {
|
} else {
|
||||||
RegisterID newReg = allocReg();
|
RegisterID newReg = allocReg();
|
||||||
masm.move(reg, newReg);
|
masm.move(reg, newReg);
|
||||||
|
@ -710,7 +633,7 @@ FrameState::ownRegForType(FrameEntry *fe)
|
||||||
syncType(backing, addressOf(backing), masm);
|
syncType(backing, addressOf(backing), masm);
|
||||||
reg = backing->type.reg();
|
reg = backing->type.reg();
|
||||||
backing->type.setMemory();
|
backing->type.setMemory();
|
||||||
regstate[reg].forget();
|
moveOwnership(reg, NULL);
|
||||||
} else {
|
} else {
|
||||||
reg = allocReg();
|
reg = allocReg();
|
||||||
masm.move(backing->type.reg(), reg);
|
masm.move(backing->type.reg(), reg);
|
||||||
|
@ -720,11 +643,10 @@ FrameState::ownRegForType(FrameEntry *fe)
|
||||||
|
|
||||||
if (fe->type.inRegister()) {
|
if (fe->type.inRegister()) {
|
||||||
reg = fe->type.reg();
|
reg = fe->type.reg();
|
||||||
|
|
||||||
/* Remove ownership of this register. */
|
/* Remove ownership of this register. */
|
||||||
JS_ASSERT(regstate[reg].fe() == fe);
|
JS_ASSERT(regstate[reg].fe == fe);
|
||||||
JS_ASSERT(regstate[reg].type() == RematInfo::TYPE);
|
JS_ASSERT(regstate[reg].type == RematInfo::TYPE);
|
||||||
regstate[reg].forget();
|
regstate[reg].fe = NULL;
|
||||||
fe->type.invalidate();
|
fe->type.invalidate();
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(fe->type.inMemory());
|
JS_ASSERT(fe->type.inMemory());
|
||||||
|
@ -754,7 +676,7 @@ FrameState::ownRegForData(FrameEntry *fe)
|
||||||
syncData(backing, addressOf(backing), masm);
|
syncData(backing, addressOf(backing), masm);
|
||||||
reg = backing->data.reg();
|
reg = backing->data.reg();
|
||||||
backing->data.setMemory();
|
backing->data.setMemory();
|
||||||
regstate[reg].forget();
|
moveOwnership(reg, NULL);
|
||||||
} else {
|
} else {
|
||||||
reg = allocReg();
|
reg = allocReg();
|
||||||
masm.move(backing->data.reg(), reg);
|
masm.move(backing->data.reg(), reg);
|
||||||
|
@ -774,9 +696,9 @@ FrameState::ownRegForData(FrameEntry *fe)
|
||||||
if (fe->data.inRegister()) {
|
if (fe->data.inRegister()) {
|
||||||
reg = fe->data.reg();
|
reg = fe->data.reg();
|
||||||
/* Remove ownership of this register. */
|
/* Remove ownership of this register. */
|
||||||
JS_ASSERT(regstate[reg].fe() == fe);
|
JS_ASSERT(regstate[reg].fe == fe);
|
||||||
JS_ASSERT(regstate[reg].type() == RematInfo::DATA);
|
JS_ASSERT(regstate[reg].type == RematInfo::DATA);
|
||||||
regstate[reg].forget();
|
regstate[reg].fe = NULL;
|
||||||
fe->data.invalidate();
|
fe->data.invalidate();
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(fe->data.inMemory());
|
JS_ASSERT(fe->data.inMemory());
|
||||||
|
@ -817,14 +739,34 @@ FrameState::pushCopyOf(uint32 index)
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameEntry *
|
FrameEntry *
|
||||||
FrameState::walkTrackerForUncopy(FrameEntry *original)
|
FrameState::uncopy(FrameEntry *original)
|
||||||
{
|
{
|
||||||
|
JS_ASSERT(original->isCopied());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copies have two critical invariants:
|
||||||
|
* 1) The backing store precedes all copies in the tracker.
|
||||||
|
* 2) The backing store of a copy cannot be popped from the stack
|
||||||
|
* while the copy is still live.
|
||||||
|
*
|
||||||
|
* Maintaining this invariant iteratively is kind of hard, so we choose
|
||||||
|
* the "lowest" copy in the frame up-front.
|
||||||
|
*
|
||||||
|
* For example, if the stack is:
|
||||||
|
* [A, B, C, D]
|
||||||
|
* And the tracker has:
|
||||||
|
* [A, D, C, B]
|
||||||
|
*
|
||||||
|
* If B, C, and D are copies of A - we will walk the tracker to the end
|
||||||
|
* and select D, not B (see bug 583684).
|
||||||
|
*/
|
||||||
uint32 firstCopy = InvalidIndex;
|
uint32 firstCopy = InvalidIndex;
|
||||||
|
FrameEntry *tos = tosFe();
|
||||||
FrameEntry *bestFe = NULL;
|
FrameEntry *bestFe = NULL;
|
||||||
uint32 ncopies = 0;
|
uint32 ncopies = 0;
|
||||||
for (uint32 i = original->trackerIndex() + 1; i < tracker.nentries; i++) {
|
for (uint32 i = 0; i < tracker.nentries; i++) {
|
||||||
FrameEntry *fe = tracker[i];
|
FrameEntry *fe = tracker[i];
|
||||||
if (fe >= sp)
|
if (fe >= tos)
|
||||||
continue;
|
continue;
|
||||||
if (fe->isCopy() && fe->copyOf() == original) {
|
if (fe->isCopy() && fe->copyOf() == original) {
|
||||||
if (firstCopy == InvalidIndex) {
|
if (firstCopy == InvalidIndex) {
|
||||||
|
@ -840,12 +782,12 @@ FrameState::walkTrackerForUncopy(FrameEntry *original)
|
||||||
if (!ncopies) {
|
if (!ncopies) {
|
||||||
JS_ASSERT(firstCopy == InvalidIndex);
|
JS_ASSERT(firstCopy == InvalidIndex);
|
||||||
JS_ASSERT(!bestFe);
|
JS_ASSERT(!bestFe);
|
||||||
|
original->copied = false;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(firstCopy != InvalidIndex);
|
JS_ASSERT(firstCopy != InvalidIndex);
|
||||||
JS_ASSERT(bestFe);
|
JS_ASSERT(bestFe);
|
||||||
JS_ASSERT(bestFe > original);
|
|
||||||
|
|
||||||
/* Mark all extra copies as copies of the new backing index. */
|
/* Mark all extra copies as copies of the new backing index. */
|
||||||
bestFe->setCopyOf(NULL);
|
bestFe->setCopyOf(NULL);
|
||||||
|
@ -853,7 +795,7 @@ FrameState::walkTrackerForUncopy(FrameEntry *original)
|
||||||
bestFe->setCopied();
|
bestFe->setCopied();
|
||||||
for (uint32 i = firstCopy; i < tracker.nentries; i++) {
|
for (uint32 i = firstCopy; i < tracker.nentries; i++) {
|
||||||
FrameEntry *other = tracker[i];
|
FrameEntry *other = tracker[i];
|
||||||
if (other >= sp || other == bestFe)
|
if (other >= tos || other == bestFe)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* The original must be tracked before copies. */
|
/* The original must be tracked before copies. */
|
||||||
|
@ -878,80 +820,7 @@ FrameState::walkTrackerForUncopy(FrameEntry *original)
|
||||||
bestFe->setNotCopied();
|
bestFe->setNotCopied();
|
||||||
}
|
}
|
||||||
|
|
||||||
return bestFe;
|
FrameEntry *fe = bestFe;
|
||||||
}
|
|
||||||
|
|
||||||
FrameEntry *
|
|
||||||
FrameState::walkFrameForUncopy(FrameEntry *original)
|
|
||||||
{
|
|
||||||
FrameEntry *bestFe = NULL;
|
|
||||||
uint32 ncopies = 0;
|
|
||||||
|
|
||||||
/* It's only necessary to visit as many FEs are being tracked. */
|
|
||||||
uint32 maxvisits = tracker.nentries;
|
|
||||||
|
|
||||||
for (FrameEntry *fe = original + 1; fe < sp && maxvisits; fe++) {
|
|
||||||
if (!fe->isTracked())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
maxvisits--;
|
|
||||||
|
|
||||||
if (fe->isCopy() && fe->copyOf() == original) {
|
|
||||||
if (!bestFe) {
|
|
||||||
bestFe = fe;
|
|
||||||
bestFe->setCopyOf(NULL);
|
|
||||||
} else {
|
|
||||||
fe->setCopyOf(bestFe);
|
|
||||||
if (fe->trackerIndex() < bestFe->trackerIndex())
|
|
||||||
swapInTracker(bestFe, fe);
|
|
||||||
}
|
|
||||||
ncopies++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopies)
|
|
||||||
bestFe->setCopied();
|
|
||||||
|
|
||||||
return bestFe;
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameEntry *
|
|
||||||
FrameState::uncopy(FrameEntry *original)
|
|
||||||
{
|
|
||||||
JS_ASSERT(original->isCopied());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copies have three critical invariants:
|
|
||||||
* 1) The backing store precedes all copies in the tracker.
|
|
||||||
* 2) The backing store precedes all copies in the FrameState.
|
|
||||||
* 3) The backing store of a copy cannot be popped from the stack
|
|
||||||
* while the copy is still live.
|
|
||||||
*
|
|
||||||
* Maintaining this invariant iteratively is kind of hard, so we choose
|
|
||||||
* the "lowest" copy in the frame up-front.
|
|
||||||
*
|
|
||||||
* For example, if the stack is:
|
|
||||||
* [A, B, C, D]
|
|
||||||
* And the tracker has:
|
|
||||||
* [A, D, C, B]
|
|
||||||
*
|
|
||||||
* If B, C, and D are copies of A - we will walk the tracker to the end
|
|
||||||
* and select B, not D (see bug 583684).
|
|
||||||
*
|
|
||||||
* Note: |tracker.nentries <= (nslots + nargs)|. However, this walk is
|
|
||||||
* sub-optimal if |tracker.nentries - original->trackerIndex() > sp - original|.
|
|
||||||
* With large scripts this may be a problem worth investigating. Note that
|
|
||||||
* the tracker is walked twice, so we multiply by 2 for pessimism.
|
|
||||||
*/
|
|
||||||
FrameEntry *fe;
|
|
||||||
if ((tracker.nentries - original->trackerIndex()) * 2 > uint32(sp - original))
|
|
||||||
fe = walkFrameForUncopy(original);
|
|
||||||
else
|
|
||||||
fe = walkTrackerForUncopy(original);
|
|
||||||
if (!fe) {
|
|
||||||
original->setNotCopied();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Switch the new backing store to the old backing store. During
|
* Switch the new backing store to the old backing store. During
|
||||||
|
@ -968,7 +837,7 @@ FrameState::uncopy(FrameEntry *original)
|
||||||
tempRegForType(original);
|
tempRegForType(original);
|
||||||
fe->type.inherit(original->type);
|
fe->type.inherit(original->type);
|
||||||
if (fe->type.inRegister())
|
if (fe->type.inRegister())
|
||||||
regstate[fe->type.reg()].reassociate(fe);
|
moveOwnership(fe->type.reg(), fe);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(fe->isTypeKnown());
|
JS_ASSERT(fe->isTypeKnown());
|
||||||
JS_ASSERT(fe->getKnownType() == original->getKnownType());
|
JS_ASSERT(fe->getKnownType() == original->getKnownType());
|
||||||
|
@ -977,7 +846,7 @@ FrameState::uncopy(FrameEntry *original)
|
||||||
tempRegForData(original);
|
tempRegForData(original);
|
||||||
fe->data.inherit(original->data);
|
fe->data.inherit(original->data);
|
||||||
if (fe->data.inRegister())
|
if (fe->data.inRegister())
|
||||||
regstate[fe->data.reg()].reassociate(fe);
|
moveOwnership(fe->data.reg(), fe);
|
||||||
|
|
||||||
return fe;
|
return fe;
|
||||||
}
|
}
|
||||||
|
@ -985,86 +854,52 @@ FrameState::uncopy(FrameEntry *original)
|
||||||
void
|
void
|
||||||
FrameState::storeLocal(uint32 n, bool popGuaranteed, bool typeChange)
|
FrameState::storeLocal(uint32 n, bool popGuaranteed, bool typeChange)
|
||||||
{
|
{
|
||||||
FrameEntry *local = getLocal(n);
|
FrameEntry *localFe = getLocal(n);
|
||||||
|
bool cacheable = !eval && !escaping[n];
|
||||||
|
|
||||||
storeTop(local, popGuaranteed, typeChange);
|
if (!popGuaranteed && !cacheable) {
|
||||||
|
JS_ASSERT_IF(base[localIndex(n)] && (!eval || n < script->nfixed),
|
||||||
bool closed = eval || escaping[n];
|
entries[localIndex(n)].type.inMemory() &&
|
||||||
if (closed || inTryBlock) {
|
entries[localIndex(n)].data.inMemory());
|
||||||
/* Ensure that the local variable remains synced. */
|
Address local(JSFrameReg, sizeof(JSStackFrame) + n * sizeof(Value));
|
||||||
if (local->isCopy()) {
|
storeTo(peek(-1), local, false);
|
||||||
FrameEntry *backing = local->copyOf();
|
forgetAllRegs(getLocal(n));
|
||||||
if (!local->data.synced()) {
|
localFe->resetSynced();
|
||||||
if (backing->data.inMemory())
|
return;
|
||||||
tempRegForData(backing);
|
|
||||||
syncData(backing, addressOf(local), masm);
|
|
||||||
}
|
|
||||||
if (!local->type.synced()) {
|
|
||||||
if (backing->type.inMemory())
|
|
||||||
tempRegForType(backing);
|
|
||||||
syncType(backing, addressOf(local), masm);
|
|
||||||
}
|
|
||||||
} else if (local->isConstant()) {
|
|
||||||
if (!local->data.synced())
|
|
||||||
syncData(local, addressOf(local), masm);
|
|
||||||
} else {
|
|
||||||
if (!local->data.synced()) {
|
|
||||||
syncData(local, addressOf(local), masm);
|
|
||||||
local->data.sync();
|
|
||||||
}
|
|
||||||
if (!local->type.synced()) {
|
|
||||||
syncType(local, addressOf(local), masm);
|
|
||||||
local->type.sync();
|
|
||||||
}
|
|
||||||
if (closed)
|
|
||||||
forgetEntry(local);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (closed)
|
|
||||||
local->resetSynced();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
bool wasSynced = localFe->type.synced();
|
||||||
FrameState::forgetEntry(FrameEntry *fe)
|
|
||||||
{
|
|
||||||
if (fe->isCopied()) {
|
|
||||||
uncopy(fe);
|
|
||||||
if (!fe->isCopied())
|
|
||||||
forgetAllRegs(fe);
|
|
||||||
} else {
|
|
||||||
forgetAllRegs(fe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange)
|
|
||||||
{
|
|
||||||
bool wasSynced = target->type.synced();
|
|
||||||
/* Detect something like (x = x) which is a no-op. */
|
/* Detect something like (x = x) which is a no-op. */
|
||||||
FrameEntry *top = peek(-1);
|
FrameEntry *top = peek(-1);
|
||||||
if (top->isCopy() && top->copyOf() == target) {
|
if (top->isCopy() && top->copyOf() == localFe) {
|
||||||
JS_ASSERT(target->isCopied());
|
JS_ASSERT(localFe->isCopied());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Completely invalidate the local variable. */
|
/* Completely invalidate the local variable. */
|
||||||
forgetEntry(target);
|
if (localFe->isCopied()) {
|
||||||
target->resetUnsynced();
|
uncopy(localFe);
|
||||||
|
if (!localFe->isCopied())
|
||||||
|
forgetAllRegs(localFe);
|
||||||
|
} else {
|
||||||
|
forgetAllRegs(localFe);
|
||||||
|
}
|
||||||
|
|
||||||
|
localFe->resetUnsynced();
|
||||||
|
|
||||||
/* Constants are easy to propagate. */
|
/* Constants are easy to propagate. */
|
||||||
if (top->isConstant()) {
|
if (top->isConstant()) {
|
||||||
target->setCopyOf(NULL);
|
localFe->setCopyOf(NULL);
|
||||||
target->setNotCopied();
|
localFe->setNotCopied();
|
||||||
target->setConstant(Jsvalify(top->getValue()));
|
localFe->setConstant(Jsvalify(top->getValue()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When dealing with copies, there are three important invariants:
|
* When dealing with copies, there are two important invariants:
|
||||||
*
|
*
|
||||||
* 1) The backing store precedes all copies in the tracker.
|
* 1) The backing store precedes all copies in the tracker.
|
||||||
* 2) The backing store precedes all copies in the FrameState.
|
|
||||||
* 2) The backing store of a local is never a stack slot, UNLESS the local
|
* 2) The backing store of a local is never a stack slot, UNLESS the local
|
||||||
* variable itself is a stack slot (blocks) that precedes the stack
|
* variable itself is a stack slot (blocks) that precedes the stack
|
||||||
* slot.
|
* slot.
|
||||||
|
@ -1074,23 +909,24 @@ FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange)
|
||||||
* condition does not hold, force it to hold by swapping in-place.
|
* condition does not hold, force it to hold by swapping in-place.
|
||||||
*/
|
*/
|
||||||
FrameEntry *backing = top;
|
FrameEntry *backing = top;
|
||||||
bool copied = false;
|
|
||||||
if (top->isCopy()) {
|
if (top->isCopy()) {
|
||||||
backing = top->copyOf();
|
backing = top->copyOf();
|
||||||
JS_ASSERT(backing->trackerIndex() < top->trackerIndex());
|
JS_ASSERT(backing->trackerIndex() < top->trackerIndex());
|
||||||
|
|
||||||
if (backing < target) {
|
uint32 backingIndex = indexOfFe(backing);
|
||||||
|
uint32 tol = uint32(spBase - base);
|
||||||
|
if (backingIndex < tol || backingIndex < localIndex(n)) {
|
||||||
/* local.idx < backing.idx means local cannot be a copy yet */
|
/* local.idx < backing.idx means local cannot be a copy yet */
|
||||||
if (target->trackerIndex() < backing->trackerIndex())
|
if (localFe->trackerIndex() < backing->trackerIndex())
|
||||||
swapInTracker(backing, target);
|
swapInTracker(backing, localFe);
|
||||||
target->setNotCopied();
|
localFe->setNotCopied();
|
||||||
target->setCopyOf(backing);
|
localFe->setCopyOf(backing);
|
||||||
if (backing->isTypeKnown())
|
if (backing->isTypeKnown())
|
||||||
target->setType(backing->getKnownType());
|
localFe->setType(backing->getKnownType());
|
||||||
else
|
else
|
||||||
target->type.invalidate();
|
localFe->type.invalidate();
|
||||||
target->data.invalidate();
|
localFe->data.invalidate();
|
||||||
target->isNumber = backing->isNumber;
|
localFe->isNumber = backing->isNumber;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1112,14 +948,13 @@ FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange)
|
||||||
* but even so there's a quick workaround. We take all copies of the
|
* but even so there's a quick workaround. We take all copies of the
|
||||||
* backing fe, and redirect them to be copies of the destination.
|
* backing fe, and redirect them to be copies of the destination.
|
||||||
*/
|
*/
|
||||||
|
FrameEntry *tos = tosFe();
|
||||||
for (uint32 i = backing->trackerIndex() + 1; i < tracker.nentries; i++) {
|
for (uint32 i = backing->trackerIndex() + 1; i < tracker.nentries; i++) {
|
||||||
FrameEntry *fe = tracker[i];
|
FrameEntry *fe = tracker[i];
|
||||||
if (fe >= sp)
|
if (fe >= tos)
|
||||||
continue;
|
continue;
|
||||||
if (fe->isCopy() && fe->copyOf() == backing) {
|
if (fe->isCopy() && fe->copyOf() == backing)
|
||||||
fe->setCopyOf(target);
|
fe->setCopyOf(localFe);
|
||||||
copied = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
backing->setNotCopied();
|
backing->setNotCopied();
|
||||||
|
@ -1129,50 +964,50 @@ FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange)
|
||||||
* consistent ordering - all copies of |backing| are tracked after
|
* consistent ordering - all copies of |backing| are tracked after
|
||||||
* |backing|. Transitively, only one swap is needed.
|
* |backing|. Transitively, only one swap is needed.
|
||||||
*/
|
*/
|
||||||
if (backing->trackerIndex() < target->trackerIndex())
|
if (backing->trackerIndex() < localFe->trackerIndex())
|
||||||
swapInTracker(backing, target);
|
swapInTracker(backing, localFe);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Move the backing store down - we spill registers here, but we could be
|
* Move the backing store down - we spill registers here, but we could be
|
||||||
* smarter and re-use the type reg.
|
* smarter and re-use the type reg.
|
||||||
*/
|
*/
|
||||||
RegisterID reg = tempRegForData(backing);
|
RegisterID reg = tempRegForData(backing);
|
||||||
target->data.setRegister(reg);
|
localFe->data.setRegister(reg);
|
||||||
regstate[reg].reassociate(target);
|
moveOwnership(reg, localFe);
|
||||||
|
|
||||||
if (typeChange) {
|
if (typeChange) {
|
||||||
if (backing->isTypeKnown()) {
|
if (backing->isTypeKnown()) {
|
||||||
target->setType(backing->getKnownType());
|
localFe->setType(backing->getKnownType());
|
||||||
} else {
|
} else {
|
||||||
RegisterID reg = tempRegForType(backing);
|
RegisterID reg = tempRegForType(backing);
|
||||||
target->type.setRegister(reg);
|
localFe->type.setRegister(reg);
|
||||||
regstate[reg].reassociate(target);
|
moveOwnership(reg, localFe);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!wasSynced)
|
if (!wasSynced)
|
||||||
masm.storeTypeTag(ImmType(backing->getKnownType()), addressOf(target));
|
masm.storeTypeTag(ImmType(backing->getKnownType()), addressOf(localFe));
|
||||||
target->type.setMemory();
|
localFe->type.setMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!backing->isTypeKnown())
|
if (!backing->isTypeKnown())
|
||||||
backing->type.invalidate();
|
backing->type.invalidate();
|
||||||
backing->data.invalidate();
|
backing->data.invalidate();
|
||||||
backing->setCopyOf(target);
|
backing->setCopyOf(localFe);
|
||||||
backing->isNumber = target->isNumber;
|
backing->isNumber = localFe->isNumber;
|
||||||
|
localFe->setCopied();
|
||||||
|
|
||||||
JS_ASSERT(top->copyOf() == target);
|
if (!cacheable) {
|
||||||
|
/* TODO: x64 optimization */
|
||||||
|
if (!localFe->type.synced())
|
||||||
|
syncType(localFe, addressOf(localFe), masm);
|
||||||
|
if (!localFe->data.synced())
|
||||||
|
syncData(localFe, addressOf(localFe), masm);
|
||||||
|
forgetAllRegs(localFe);
|
||||||
|
localFe->type.setMemory();
|
||||||
|
localFe->data.setMemory();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
JS_ASSERT(top->copyOf() == localFe);
|
||||||
* Right now, |backing| is a copy of |target| (note the reversal), but
|
|
||||||
* |target| is not marked as copied. This is an optimization so uncopy()
|
|
||||||
* may avoid frame traversal.
|
|
||||||
*
|
|
||||||
* There are two cases where we must set the copy bit, however:
|
|
||||||
* - The fixup phase redirected more copies to |target|.
|
|
||||||
* - An immediate pop is not guaranteed.
|
|
||||||
*/
|
|
||||||
if (copied || !popGuaranteed)
|
|
||||||
target->setCopied();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1180,7 +1015,7 @@ FrameState::shimmy(uint32 n)
|
||||||
{
|
{
|
||||||
JS_ASSERT(sp - n >= spBase);
|
JS_ASSERT(sp - n >= spBase);
|
||||||
int32 depth = 0 - int32(n);
|
int32 depth = 0 - int32(n);
|
||||||
storeTop(&sp[depth - 1], true);
|
storeLocal(uint32(&sp[depth - 1] - locals), true);
|
||||||
popn(n);
|
popn(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,7 +1024,7 @@ FrameState::shift(int32 n)
|
||||||
{
|
{
|
||||||
JS_ASSERT(n < 0);
|
JS_ASSERT(n < 0);
|
||||||
JS_ASSERT(sp + n - 1 >= spBase);
|
JS_ASSERT(sp + n - 1 >= spBase);
|
||||||
storeTop(&sp[n - 1], true);
|
storeLocal(uint32(&sp[n - 1] - locals), true);
|
||||||
pop();
|
pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,103 +175,22 @@ class FrameState
|
||||||
uint32 nentries;
|
uint32 nentries;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Some RegisterState invariants.
|
|
||||||
*
|
|
||||||
* If |fe| is non-NULL, |save| is NULL.
|
|
||||||
* If |save| is non-NULL, |fe| is NULL.
|
|
||||||
* That is, both |fe| and |save| cannot be non-NULL.
|
|
||||||
*
|
|
||||||
* If either |fe| or |save| is non-NULL, the register is not in freeRegs.
|
|
||||||
* If both |fe| and |save| are NULL, the register is either in freeRegs,
|
|
||||||
* or owned by the compiler.
|
|
||||||
*/
|
|
||||||
struct RegisterState {
|
struct RegisterState {
|
||||||
RegisterState() : fe_(NULL), save_(NULL)
|
RegisterState()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
RegisterState(FrameEntry *fe, RematInfo::RematType type)
|
RegisterState(FrameEntry *fe, RematInfo::RematType type)
|
||||||
: fe_(fe), save_(NULL), type_(type)
|
: fe(fe), type(type)
|
||||||
{
|
{ }
|
||||||
JS_ASSERT(!save_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isPinned() const {
|
|
||||||
assertConsistency();
|
|
||||||
return !!save_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void assertConsistency() const {
|
|
||||||
JS_ASSERT_IF(fe_, !save_);
|
|
||||||
JS_ASSERT_IF(save_, !fe_);
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameEntry *fe() const {
|
|
||||||
assertConsistency();
|
|
||||||
return fe_;
|
|
||||||
}
|
|
||||||
|
|
||||||
RematInfo::RematType type() const {
|
|
||||||
assertConsistency();
|
|
||||||
return type_;
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameEntry *usedBy() const {
|
|
||||||
if (fe_)
|
|
||||||
return fe_;
|
|
||||||
return save_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void associate(FrameEntry *fe, RematInfo::RematType type) {
|
|
||||||
JS_ASSERT(!fe_);
|
|
||||||
JS_ASSERT(!save_);
|
|
||||||
|
|
||||||
fe_ = fe;
|
|
||||||
type_ = type;
|
|
||||||
JS_ASSERT(!save_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Change ownership. */
|
|
||||||
void reassociate(FrameEntry *fe) {
|
|
||||||
assertConsistency();
|
|
||||||
JS_ASSERT(fe);
|
|
||||||
|
|
||||||
fe_ = fe;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unassociate this register from the FE. */
|
|
||||||
void forget() {
|
|
||||||
JS_ASSERT(fe_);
|
|
||||||
fe_ = NULL;
|
|
||||||
JS_ASSERT(!save_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pin() {
|
|
||||||
assertConsistency();
|
|
||||||
save_ = fe_;
|
|
||||||
fe_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unpin() {
|
|
||||||
assertConsistency();
|
|
||||||
fe_ = save_;
|
|
||||||
save_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unpinUnsafe() {
|
|
||||||
assertConsistency();
|
|
||||||
save_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/* FrameEntry owning this register, or NULL if not owned by a frame. */
|
/* FrameEntry owning this register, or NULL if not owned by a frame. */
|
||||||
FrameEntry *fe_;
|
FrameEntry *fe;
|
||||||
|
|
||||||
/* Hack - simplifies register allocation for pairs. */
|
/* Hack - simplifies register allocation for pairs. */
|
||||||
FrameEntry *save_;
|
FrameEntry *save;
|
||||||
|
|
||||||
/* Part of the FrameEntry that owns the FE. */
|
/* Part of the FrameEntry that owns the FE. */
|
||||||
RematInfo::RematType type_;
|
RematInfo::RematType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -586,10 +505,9 @@ class FrameState
|
||||||
void storeTo(FrameEntry *fe, Address address, bool popHint);
|
void storeTo(FrameEntry *fe, Address address, bool popHint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stores the top stack slot back to a slot.
|
* Stores the top stack slot back to a local variable.
|
||||||
*/
|
*/
|
||||||
void storeLocal(uint32 n, bool popGuaranteed = false, bool typeChange = true);
|
void storeLocal(uint32 n, bool popGuaranteed = false, bool typeChange = true);
|
||||||
void storeTop(FrameEntry *target, bool popGuaranteed = false, bool typeChange = true);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restores state from a slow path.
|
* Restores state from a slow path.
|
||||||
|
@ -608,34 +526,28 @@ class FrameState
|
||||||
void syncAndKill(Registers kill, Uses uses, Uses ignored);
|
void syncAndKill(Registers kill, Uses uses, Uses ignored);
|
||||||
void syncAndKill(Registers kill, Uses uses) { syncAndKill(kill, uses, Uses(0)); }
|
void syncAndKill(Registers kill, Uses uses) { syncAndKill(kill, uses, Uses(0)); }
|
||||||
|
|
||||||
/* Syncs and kills everything. */
|
/*
|
||||||
void syncAndKillEverything() {
|
* Reset the register state.
|
||||||
syncAndKill(Registers(Registers::AvailRegs), Uses(frameDepth()));
|
*/
|
||||||
}
|
void resetRegState();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear all tracker entries, syncing all outstanding stores in the process.
|
* Clear all tracker entries, syncing all outstanding stores in the process.
|
||||||
* The stack depth is in case some merge points' edges did not immediately
|
* The stack depth is in case some merge points' edges did not immediately
|
||||||
* precede the current instruction.
|
* precede the current instruction.
|
||||||
*/
|
*/
|
||||||
inline void syncAndForgetEverything(uint32 newStackDepth);
|
inline void forgetEverything(uint32 newStackDepth);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same as above, except the stack depth is not changed. This is used for
|
* Same as above, except the stack depth is not changed. This is used for
|
||||||
* branching opcodes.
|
* branching opcodes.
|
||||||
*/
|
*/
|
||||||
void syncAndForgetEverything();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Throw away the entire frame state, without syncing anything.
|
|
||||||
* This can only be called after a syncAndKill() against all registers.
|
|
||||||
*/
|
|
||||||
void forgetEverything();
|
void forgetEverything();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Discard the entire framestate forcefully.
|
* Throw away the entire frame state, without syncing anything.
|
||||||
*/
|
*/
|
||||||
void discardFrame();
|
void throwaway();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark an existing slot with a type.
|
* Mark an existing slot with a type.
|
||||||
|
@ -691,9 +603,8 @@ class FrameState
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Marks a register such that it cannot be spilled by the register
|
* Marks a register such that it cannot be spilled by the register
|
||||||
* allocator. Any pinned registers must be unpinned at the end of the op,
|
* allocator. Any pinned registers must be unpinned at the end of the op.
|
||||||
* no matter what. In addition, pinReg() can only be used on registers
|
* Note: This function should only be used on registers tied to FEs.
|
||||||
* which are associated with FrameEntries.
|
|
||||||
*/
|
*/
|
||||||
inline void pinReg(RegisterID reg);
|
inline void pinReg(RegisterID reg);
|
||||||
|
|
||||||
|
@ -702,11 +613,6 @@ class FrameState
|
||||||
*/
|
*/
|
||||||
inline void unpinReg(RegisterID reg);
|
inline void unpinReg(RegisterID reg);
|
||||||
|
|
||||||
/*
|
|
||||||
* Same as unpinReg(), but does not restore the FrameEntry.
|
|
||||||
*/
|
|
||||||
inline void unpinKilledReg(RegisterID reg);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dups the top item on the stack.
|
* Dups the top item on the stack.
|
||||||
*/
|
*/
|
||||||
|
@ -733,6 +639,7 @@ class FrameState
|
||||||
*/
|
*/
|
||||||
uint32 stackDepth() const { return sp - spBase; }
|
uint32 stackDepth() const { return sp - spBase; }
|
||||||
uint32 frameDepth() const { return stackDepth() + script->nfixed; }
|
uint32 frameDepth() const { return stackDepth() + script->nfixed; }
|
||||||
|
inline FrameEntry *tosFe() const;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void assertValidRegisterState() const;
|
void assertValidRegisterState() const;
|
||||||
|
@ -780,7 +687,7 @@ class FrameState
|
||||||
RegisterID evictSomeReg(uint32 mask);
|
RegisterID evictSomeReg(uint32 mask);
|
||||||
void evictReg(RegisterID reg);
|
void evictReg(RegisterID reg);
|
||||||
inline FrameEntry *rawPush();
|
inline FrameEntry *rawPush();
|
||||||
inline void addToTracker(FrameEntry *fe);
|
inline FrameEntry *addToTracker(uint32 index);
|
||||||
inline void syncType(const FrameEntry *fe, Address to, Assembler &masm) const;
|
inline void syncType(const FrameEntry *fe, Address to, Assembler &masm) const;
|
||||||
inline void syncData(const FrameEntry *fe, Address to, Assembler &masm) const;
|
inline void syncData(const FrameEntry *fe, Address to, Assembler &masm) const;
|
||||||
inline FrameEntry *getLocal(uint32 slot);
|
inline FrameEntry *getLocal(uint32 slot);
|
||||||
|
@ -788,10 +695,9 @@ class FrameState
|
||||||
inline void swapInTracker(FrameEntry *lhs, FrameEntry *rhs);
|
inline void swapInTracker(FrameEntry *lhs, FrameEntry *rhs);
|
||||||
inline uint32 localIndex(uint32 n);
|
inline uint32 localIndex(uint32 n);
|
||||||
void pushCopyOf(uint32 index);
|
void pushCopyOf(uint32 index);
|
||||||
void syncFancy(Assembler &masm, Registers avail, FrameEntry *resumeAt,
|
void syncFancy(Assembler &masm, Registers avail, uint32 resumeAt,
|
||||||
FrameEntry *bottom) const;
|
FrameEntry *bottom) const;
|
||||||
inline bool tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const;
|
inline bool tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const;
|
||||||
void resetInternalState();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Uncopies" the backing store of a FrameEntry that has been copied. The
|
* "Uncopies" the backing store of a FrameEntry that has been copied. The
|
||||||
|
@ -802,29 +708,25 @@ class FrameState
|
||||||
* Later addition: uncopy() returns the first copy found.
|
* Later addition: uncopy() returns the first copy found.
|
||||||
*/
|
*/
|
||||||
FrameEntry *uncopy(FrameEntry *original);
|
FrameEntry *uncopy(FrameEntry *original);
|
||||||
FrameEntry *walkTrackerForUncopy(FrameEntry *original);
|
|
||||||
FrameEntry *walkFrameForUncopy(FrameEntry *original);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* All registers in the FE are forgotten. If it is copied, it is uncopied
|
|
||||||
* beforehand.
|
|
||||||
*/
|
|
||||||
void forgetEntry(FrameEntry *fe);
|
|
||||||
|
|
||||||
FrameEntry *entryFor(uint32 index) const {
|
FrameEntry *entryFor(uint32 index) const {
|
||||||
JS_ASSERT(entries[index].isTracked());
|
JS_ASSERT(base[index]);
|
||||||
return &entries[index];
|
return &entries[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void moveOwnership(RegisterID reg, FrameEntry *newFe) {
|
||||||
|
regstate[reg].fe = newFe;
|
||||||
|
}
|
||||||
|
|
||||||
RegisterID evictSomeReg() {
|
RegisterID evictSomeReg() {
|
||||||
return evictSomeReg(Registers::AvailRegs);
|
return evictSomeReg(Registers::AvailRegs);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 indexOf(int32 depth) {
|
uint32 indexOf(int32 depth) {
|
||||||
return uint32((sp + depth) - entries);
|
return uint32((sp + depth) - base);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 indexOfFe(FrameEntry *fe) const {
|
uint32 indexOfFe(FrameEntry *fe) {
|
||||||
return uint32(fe - entries);
|
return uint32(fe - entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,17 +742,20 @@ class FrameState
|
||||||
/* Cache of FrameEntry objects. */
|
/* Cache of FrameEntry objects. */
|
||||||
FrameEntry *entries;
|
FrameEntry *entries;
|
||||||
|
|
||||||
|
/* Base pointer of the FrameEntry vector. */
|
||||||
|
FrameEntry **base;
|
||||||
|
|
||||||
/* Base pointer for arguments. */
|
/* Base pointer for arguments. */
|
||||||
FrameEntry *args;
|
FrameEntry **args;
|
||||||
|
|
||||||
/* Base pointer for local variables. */
|
/* Base pointer for local variables. */
|
||||||
FrameEntry *locals;
|
FrameEntry **locals;
|
||||||
|
|
||||||
/* Base pointer for the stack. */
|
/* Base pointer for the stack. */
|
||||||
FrameEntry *spBase;
|
FrameEntry **spBase;
|
||||||
|
|
||||||
/* Dynamic stack pointer. */
|
/* Dynamic stack pointer. */
|
||||||
FrameEntry *sp;
|
FrameEntry **sp;
|
||||||
|
|
||||||
/* Vector of tracked slot indexes. */
|
/* Vector of tracked slot indexes. */
|
||||||
Tracker tracker;
|
Tracker tracker;
|
||||||
|
|
|
@ -45,7 +45,7 @@ using namespace js;
|
||||||
using namespace js::mjit;
|
using namespace js::mjit;
|
||||||
|
|
||||||
ImmutableSync::ImmutableSync(JSContext *cx, const FrameState &frame)
|
ImmutableSync::ImmutableSync(JSContext *cx, const FrameState &frame)
|
||||||
: cx(cx), entries(NULL), frame(frame), generation(0)
|
: cx(cx), entries(NULL), frame(frame)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,18 +57,19 @@ ImmutableSync::~ImmutableSync()
|
||||||
bool
|
bool
|
||||||
ImmutableSync::init(uint32 nentries)
|
ImmutableSync::init(uint32 nentries)
|
||||||
{
|
{
|
||||||
entries = (SyncEntry *)cx->calloc(sizeof(SyncEntry) * nentries);
|
entries = (SyncEntry *)cx->malloc(sizeof(SyncEntry) * nentries);
|
||||||
return !!entries;
|
return !!entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ImmutableSync::reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom)
|
ImmutableSync::reset(Assembler *masm, Registers avail, uint32 n,
|
||||||
|
FrameEntry *bottom)
|
||||||
{
|
{
|
||||||
this->avail = avail;
|
this->avail = avail;
|
||||||
|
this->nentries = n;
|
||||||
this->masm = masm;
|
this->masm = masm;
|
||||||
this->top = top;
|
|
||||||
this->bottom = bottom;
|
this->bottom = bottom;
|
||||||
this->generation++;
|
memset(entries, 0, sizeof(SyncEntry) * nentries);
|
||||||
memset(regs, 0, sizeof(regs));
|
memset(regs, 0, sizeof(regs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +92,17 @@ ImmutableSync::allocReg()
|
||||||
|
|
||||||
if (!regs[i]) {
|
if (!regs[i]) {
|
||||||
/* If the frame does not own this register, take it! */
|
/* If the frame does not own this register, take it! */
|
||||||
FrameEntry *fe = frame.regstate[i].fe();
|
FrameEntry *fe = frame.regstate[i].fe;
|
||||||
if (!fe)
|
if (!fe)
|
||||||
return reg;
|
return reg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Reifier does not own this register, but the frame does.
|
||||||
|
* This must mean that we've not yet processed this entry, and
|
||||||
|
* that it's data has not been clobbered.
|
||||||
|
*/
|
||||||
|
JS_ASSERT(fe->trackerIndex() < nentries);
|
||||||
|
|
||||||
evictFromFrame = i;
|
evictFromFrame = i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -107,14 +115,18 @@ ImmutableSync::allocReg()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evictFromFrame != FrameState::InvalidIndex) {
|
if (evictFromFrame != FrameState::InvalidIndex) {
|
||||||
FrameEntry *fe = frame.regstate[evictFromFrame].fe();
|
FrameEntry *fe = frame.regstate[evictFromFrame].fe;
|
||||||
SyncEntry &e = entryFor(fe);
|
SyncEntry &e = entryFor(fe);
|
||||||
if (frame.regstate[evictFromFrame].type() == RematInfo::TYPE) {
|
if (frame.regstate[evictFromFrame].type == RematInfo::TYPE) {
|
||||||
JS_ASSERT(!e.typeClobbered);
|
JS_ASSERT(!e.typeClobbered);
|
||||||
|
e.typeSynced = true;
|
||||||
e.typeClobbered = true;
|
e.typeClobbered = true;
|
||||||
|
masm->storeTypeTag(fe->type.reg(), frame.addressOf(fe));
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!e.dataClobbered);
|
JS_ASSERT(!e.dataClobbered);
|
||||||
|
e.dataSynced = true;
|
||||||
e.dataClobbered = true;
|
e.dataClobbered = true;
|
||||||
|
masm->storePayload(fe->data.reg(), frame.addressOf(fe));
|
||||||
}
|
}
|
||||||
return RegisterID(evictFromFrame);
|
return RegisterID(evictFromFrame);
|
||||||
}
|
}
|
||||||
|
@ -138,38 +150,39 @@ ImmutableSync::allocReg()
|
||||||
inline ImmutableSync::SyncEntry &
|
inline ImmutableSync::SyncEntry &
|
||||||
ImmutableSync::entryFor(FrameEntry *fe)
|
ImmutableSync::entryFor(FrameEntry *fe)
|
||||||
{
|
{
|
||||||
JS_ASSERT(fe <= top);
|
JS_ASSERT(fe->trackerIndex() < nentries);
|
||||||
SyncEntry &e = entries[frame.indexOfFe(fe)];
|
return entries[fe->trackerIndex()];
|
||||||
if (e.generation != generation)
|
|
||||||
e.reset(generation);
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ImmutableSync::sync(FrameEntry *fe)
|
ImmutableSync::sync(FrameEntry *fe)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
JS_ASSERT(nentries);
|
||||||
top = fe;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (fe->isCopy())
|
if (fe->isCopy())
|
||||||
syncCopy(fe);
|
syncCopy(fe);
|
||||||
else
|
else
|
||||||
syncNormal(fe);
|
syncNormal(fe);
|
||||||
|
nentries--;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ImmutableSync::shouldSyncType(FrameEntry *fe, SyncEntry &e)
|
ImmutableSync::shouldSyncType(FrameEntry *fe, SyncEntry &e)
|
||||||
{
|
{
|
||||||
/* Registers are synced up-front. */
|
if (fe->type.inRegister() && !e.typeClobbered)
|
||||||
return !fe->type.synced() && !fe->type.inRegister();
|
return true;
|
||||||
|
if (e.hasTypeReg)
|
||||||
|
return true;
|
||||||
|
return frame.inTryBlock || fe >= bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ImmutableSync::shouldSyncData(FrameEntry *fe, SyncEntry &e)
|
ImmutableSync::shouldSyncData(FrameEntry *fe, SyncEntry &e)
|
||||||
{
|
{
|
||||||
/* Registers are synced up-front. */
|
if (fe->data.inRegister() && !e.dataClobbered)
|
||||||
return !fe->data.synced() && !fe->data.inRegister();
|
return true;
|
||||||
|
if (e.hasDataReg)
|
||||||
|
return true;
|
||||||
|
return frame.inTryBlock || fe >= bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSC::MacroAssembler::RegisterID
|
JSC::MacroAssembler::RegisterID
|
||||||
|
@ -203,7 +216,8 @@ ImmutableSync::ensureDataReg(FrameEntry *fe, SyncEntry &e)
|
||||||
void
|
void
|
||||||
ImmutableSync::syncCopy(FrameEntry *fe)
|
ImmutableSync::syncCopy(FrameEntry *fe)
|
||||||
{
|
{
|
||||||
JS_ASSERT(fe >= bottom);
|
if (!frame.inTryBlock && fe < bottom)
|
||||||
|
return;
|
||||||
|
|
||||||
FrameEntry *backing = fe->copyOf();
|
FrameEntry *backing = fe->copyOf();
|
||||||
SyncEntry &e = entryFor(backing);
|
SyncEntry &e = entryFor(backing);
|
||||||
|
@ -240,7 +254,7 @@ ImmutableSync::syncNormal(FrameEntry *fe)
|
||||||
e.type = fe->getKnownType();
|
e.type = fe->getKnownType();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldSyncData(fe, e)) {
|
if (!fe->data.synced() && !e.dataSynced && shouldSyncData(fe, e)) {
|
||||||
if (fe->isConstant()) {
|
if (fe->isConstant()) {
|
||||||
masm->storeValue(fe->getValue(), addr);
|
masm->storeValue(fe->getValue(), addr);
|
||||||
return;
|
return;
|
||||||
|
@ -248,7 +262,7 @@ ImmutableSync::syncNormal(FrameEntry *fe)
|
||||||
masm->storePayload(ensureDataReg(fe, e), addr);
|
masm->storePayload(ensureDataReg(fe, e), addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldSyncType(fe, e)) {
|
if (!fe->type.synced() && !e.typeSynced && shouldSyncType(fe, e)) {
|
||||||
if (e.learnedType)
|
if (e.learnedType)
|
||||||
masm->storeTypeTag(ImmType(e.type), addr);
|
masm->storeTypeTag(ImmType(e.type), addr);
|
||||||
else
|
else
|
||||||
|
@ -258,14 +272,14 @@ ImmutableSync::syncNormal(FrameEntry *fe)
|
||||||
if (e.hasDataReg) {
|
if (e.hasDataReg) {
|
||||||
avail.putReg(e.dataReg);
|
avail.putReg(e.dataReg);
|
||||||
regs[e.dataReg] = NULL;
|
regs[e.dataReg] = NULL;
|
||||||
} else if (!e.dataClobbered && fe->data.inRegister() && frame.regstate[fe->data.reg()].fe()) {
|
} else if (!e.dataClobbered && fe->data.inRegister() && frame.regstate[fe->data.reg()].fe) {
|
||||||
avail.putReg(fe->data.reg());
|
avail.putReg(fe->data.reg());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.hasTypeReg) {
|
if (e.hasTypeReg) {
|
||||||
avail.putReg(e.typeReg);
|
avail.putReg(e.typeReg);
|
||||||
regs[e.typeReg] = NULL;
|
regs[e.typeReg] = NULL;
|
||||||
} else if (!e.typeClobbered && fe->type.inRegister() && frame.regstate[fe->type.reg()].fe()) {
|
} else if (!e.typeClobbered && fe->type.inRegister() && frame.regstate[fe->type.reg()].fe) {
|
||||||
avail.putReg(fe->type.reg());
|
avail.putReg(fe->type.reg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,24 +70,16 @@ class ImmutableSync
|
||||||
*
|
*
|
||||||
* They are separated for readability.
|
* They are separated for readability.
|
||||||
*/
|
*/
|
||||||
uint32 generation;
|
bool dataSynced;
|
||||||
|
bool typeSynced;
|
||||||
bool dataClobbered;
|
bool dataClobbered;
|
||||||
bool typeClobbered;
|
bool typeClobbered;
|
||||||
|
RegisterID dataReg;
|
||||||
|
RegisterID typeReg;
|
||||||
bool hasDataReg;
|
bool hasDataReg;
|
||||||
bool hasTypeReg;
|
bool hasTypeReg;
|
||||||
bool learnedType;
|
bool learnedType;
|
||||||
RegisterID dataReg;
|
|
||||||
RegisterID typeReg;
|
|
||||||
JSValueType type;
|
JSValueType type;
|
||||||
|
|
||||||
void reset(uint32 gen) {
|
|
||||||
dataClobbered = false;
|
|
||||||
typeClobbered = false;
|
|
||||||
hasDataReg = false;
|
|
||||||
hasTypeReg = false;
|
|
||||||
learnedType = false;
|
|
||||||
generation = gen;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -95,7 +87,8 @@ class ImmutableSync
|
||||||
~ImmutableSync();
|
~ImmutableSync();
|
||||||
bool init(uint32 nentries);
|
bool init(uint32 nentries);
|
||||||
|
|
||||||
void reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom);
|
void reset(Assembler *masm, Registers avail, uint32 n,
|
||||||
|
FrameEntry *bottom);
|
||||||
void sync(FrameEntry *fe);
|
void sync(FrameEntry *fe);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -118,9 +111,7 @@ class ImmutableSync
|
||||||
Registers avail;
|
Registers avail;
|
||||||
Assembler *masm;
|
Assembler *masm;
|
||||||
SyncEntry *regs[Assembler::TotalRegisters];
|
SyncEntry *regs[Assembler::TotalRegisters];
|
||||||
FrameEntry *top;
|
|
||||||
FrameEntry *bottom;
|
FrameEntry *bottom;
|
||||||
uint32 generation;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace mjit */
|
} /* namespace mjit */
|
||||||
|
|
|
@ -190,16 +190,11 @@ struct Registers {
|
||||||
return !(freeMask & mask);
|
return !(freeMask & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterID peekReg() {
|
RegisterID takeAnyReg() {
|
||||||
JS_ASSERT(!empty());
|
JS_ASSERT(!empty());
|
||||||
int ireg;
|
int ireg;
|
||||||
JS_FLOOR_LOG2(ireg, freeMask);
|
JS_FLOOR_LOG2(ireg, freeMask);
|
||||||
RegisterID reg = (RegisterID)ireg;
|
RegisterID reg = (RegisterID)ireg;
|
||||||
return reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegisterID takeAnyReg() {
|
|
||||||
RegisterID reg = peekReg();
|
|
||||||
takeReg(reg);
|
takeReg(reg);
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче