зеркало из https://github.com/mozilla/gecko-dev.git
Allocate registers for formal arguments, callee, and this (bug 592976, r=luke).
This commit is contained in:
Родитель
b4ec0dde6d
Коммит
4d9c823214
|
@ -254,10 +254,10 @@ OPDEF(JSOP_DEFSHARP, 93, "defsharp", NULL, 5, 0, 0, 0, JOF_UINT16
|
||||||
OPDEF(JSOP_USESHARP, 94, "usesharp", NULL, 5, 0, 1, 0, JOF_UINT16PAIR|JOF_SHARPSLOT)
|
OPDEF(JSOP_USESHARP, 94, "usesharp", NULL, 5, 0, 1, 0, JOF_UINT16PAIR|JOF_SHARPSLOT)
|
||||||
|
|
||||||
/* Fast inc/dec ops for args and locals. */
|
/* Fast inc/dec ops for args and locals. */
|
||||||
OPDEF(JSOP_INCARG, 95, "incarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_TMPSLOT2)
|
OPDEF(JSOP_INCARG, 95, "incarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_TMPSLOT3)
|
||||||
OPDEF(JSOP_DECARG, 96, "decarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_TMPSLOT2)
|
OPDEF(JSOP_DECARG, 96, "decarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_TMPSLOT3)
|
||||||
OPDEF(JSOP_ARGINC, 97, "arginc", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT2)
|
OPDEF(JSOP_ARGINC, 97, "arginc", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3)
|
||||||
OPDEF(JSOP_ARGDEC, 98, "argdec", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT2)
|
OPDEF(JSOP_ARGDEC, 98, "argdec", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3)
|
||||||
|
|
||||||
OPDEF(JSOP_INCLOCAL, 99, "inclocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC|JOF_TMPSLOT3)
|
OPDEF(JSOP_INCLOCAL, 99, "inclocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC|JOF_TMPSLOT3)
|
||||||
OPDEF(JSOP_DECLOCAL, 100,"declocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_TMPSLOT3)
|
OPDEF(JSOP_DECLOCAL, 100,"declocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_TMPSLOT3)
|
||||||
|
|
|
@ -93,7 +93,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
|
||||||
: NULL),
|
: NULL),
|
||||||
isConstructing(fp->isConstructing()),
|
isConstructing(fp->isConstructing()),
|
||||||
analysis(NULL), jumpMap(NULL), savedTraps(NULL),
|
analysis(NULL), jumpMap(NULL), savedTraps(NULL),
|
||||||
frame(cx, script, masm),
|
frame(cx, script, fun, masm),
|
||||||
branchPatches(CompilerAllocPolicy(cx, *thisFromCtor())),
|
branchPatches(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||||
#if defined JS_MONOIC
|
#if defined JS_MONOIC
|
||||||
mics(CompilerAllocPolicy(cx, *thisFromCtor())),
|
mics(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||||
|
@ -174,8 +174,7 @@ mjit::Compiler::performCompilation(JITScript **jitp)
|
||||||
|
|
||||||
this->analysis = &analysis;
|
this->analysis = &analysis;
|
||||||
|
|
||||||
uint32 nargs = fun ? fun->nargs : 0;
|
if (!frame.init())
|
||||||
if (!frame.init(nargs) || !stubcc.init(nargs))
|
|
||||||
return Compile_Abort;
|
return Compile_Abort;
|
||||||
|
|
||||||
jumpMap = (Label *)cx->malloc(sizeof(Label) * script->length);
|
jumpMap = (Label *)cx->malloc(sizeof(Label) * script->length);
|
||||||
|
@ -200,6 +199,8 @@ mjit::Compiler::performCompilation(JITScript **jitp)
|
||||||
|
|
||||||
for (uint32 i = 0; i < script->nClosedVars; i++)
|
for (uint32 i = 0; i < script->nClosedVars; i++)
|
||||||
frame.setClosedVar(script->getClosedVar(i));
|
frame.setClosedVar(script->getClosedVar(i));
|
||||||
|
for (uint32 i = 0; i < script->nClosedArgs; i++)
|
||||||
|
frame.setClosedArg(script->getClosedArg(i));
|
||||||
|
|
||||||
CHECK_STATUS(generatePrologue());
|
CHECK_STATUS(generatePrologue());
|
||||||
CHECK_STATUS(generateMethod());
|
CHECK_STATUS(generateMethod());
|
||||||
|
@ -941,7 +942,7 @@ mjit::Compiler::generateMethod()
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_FORARG)
|
BEGIN_CASE(JSOP_FORARG)
|
||||||
iterNext();
|
iterNext();
|
||||||
jsop_setarg(GET_SLOTNO(PC), true);
|
frame.storeArg(GET_SLOTNO(PC), true);
|
||||||
frame.pop();
|
frame.pop();
|
||||||
END_CASE(JSOP_FORARG)
|
END_CASE(JSOP_FORARG)
|
||||||
|
|
||||||
|
@ -1268,7 +1269,7 @@ mjit::Compiler::generateMethod()
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_GETARGPROP)
|
BEGIN_CASE(JSOP_GETARGPROP)
|
||||||
/* Push arg onto stack. */
|
/* Push arg onto stack. */
|
||||||
jsop_getarg(GET_SLOTNO(PC));
|
frame.pushArg(GET_SLOTNO(PC));
|
||||||
if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[ARGNO_LEN]))))
|
if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[ARGNO_LEN]))))
|
||||||
return Compile_Error;
|
return Compile_Error;
|
||||||
END_CASE(JSOP_GETARGPROP)
|
END_CASE(JSOP_GETARGPROP)
|
||||||
|
@ -1452,7 +1453,7 @@ mjit::Compiler::generateMethod()
|
||||||
BEGIN_CASE(JSOP_GETARG)
|
BEGIN_CASE(JSOP_GETARG)
|
||||||
BEGIN_CASE(JSOP_CALLARG)
|
BEGIN_CASE(JSOP_CALLARG)
|
||||||
{
|
{
|
||||||
jsop_getarg(GET_SLOTNO(PC));
|
frame.pushArg(GET_SLOTNO(PC));
|
||||||
if (op == JSOP_CALLARG)
|
if (op == JSOP_CALLARG)
|
||||||
frame.push(UndefinedValue());
|
frame.push(UndefinedValue());
|
||||||
}
|
}
|
||||||
|
@ -1463,7 +1464,16 @@ mjit::Compiler::generateMethod()
|
||||||
END_CASE(JSOP_BINDGNAME)
|
END_CASE(JSOP_BINDGNAME)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_SETARG)
|
BEGIN_CASE(JSOP_SETARG)
|
||||||
jsop_setarg(GET_SLOTNO(PC), JSOp(PC[JSOP_SETARG_LENGTH]) == JSOP_POP);
|
{
|
||||||
|
jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH];
|
||||||
|
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
|
||||||
|
frame.storeArg(GET_SLOTNO(PC), pop);
|
||||||
|
if (pop) {
|
||||||
|
frame.pop();
|
||||||
|
PC += JSOP_SETARG_LENGTH + JSOP_POP_LENGTH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
END_CASE(JSOP_SETARG)
|
END_CASE(JSOP_SETARG)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_GETLOCAL)
|
BEGIN_CASE(JSOP_GETLOCAL)
|
||||||
|
@ -1722,7 +1732,7 @@ mjit::Compiler::generateMethod()
|
||||||
{
|
{
|
||||||
uint32 slot = GET_SLOTNO(PC);
|
uint32 slot = GET_SLOTNO(PC);
|
||||||
JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN]));
|
JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN]));
|
||||||
prepareStubCall(Uses(frame.frameDepth()));
|
prepareStubCall(Uses(frame.frameSlots()));
|
||||||
masm.move(ImmPtr(fun), Registers::ArgReg1);
|
masm.move(ImmPtr(fun), Registers::ArgReg1);
|
||||||
INLINE_STUBCALL(stubs::DefLocalFun_FC);
|
INLINE_STUBCALL(stubs::DefLocalFun_FC);
|
||||||
frame.takeReg(Registers::ReturnReg);
|
frame.takeReg(Registers::ReturnReg);
|
||||||
|
@ -1750,7 +1760,7 @@ mjit::Compiler::generateMethod()
|
||||||
} else if (fun->joinable()) {
|
} else if (fun->joinable()) {
|
||||||
if (next == JSOP_CALL) {
|
if (next == JSOP_CALL) {
|
||||||
stub = stubs::LambdaJoinableForCall;
|
stub = stubs::LambdaJoinableForCall;
|
||||||
uses = frame.frameDepth();
|
uses = frame.frameSlots();
|
||||||
} else if (next == JSOP_NULL) {
|
} else if (next == JSOP_NULL) {
|
||||||
stub = stubs::LambdaJoinableForNull;
|
stub = stubs::LambdaJoinableForNull;
|
||||||
}
|
}
|
||||||
|
@ -1781,9 +1791,12 @@ mjit::Compiler::generateMethod()
|
||||||
BEGIN_CASE(JSOP_CALLFCSLOT)
|
BEGIN_CASE(JSOP_CALLFCSLOT)
|
||||||
{
|
{
|
||||||
uintN index = GET_UINT16(PC);
|
uintN index = GET_UINT16(PC);
|
||||||
// JSObject *obj = &fp->argv[-2].toObject();
|
|
||||||
RegisterID reg = frame.allocReg();
|
// Load the callee's payload into a register.
|
||||||
masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), reg);
|
frame.pushCallee();
|
||||||
|
RegisterID reg = frame.copyDataIntoReg(frame.peek(-1));
|
||||||
|
frame.pop();
|
||||||
|
|
||||||
// obj->getFlatClosureUpvars()
|
// obj->getFlatClosureUpvars()
|
||||||
masm.loadPtr(Address(reg, offsetof(JSObject, slots)), reg);
|
masm.loadPtr(Address(reg, offsetof(JSObject, slots)), reg);
|
||||||
Address upvarAddress(reg, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
|
Address upvarAddress(reg, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
|
||||||
|
@ -1929,7 +1942,7 @@ mjit::Compiler::generateMethod()
|
||||||
BEGIN_CASE(JSOP_LAMBDA_FC)
|
BEGIN_CASE(JSOP_LAMBDA_FC)
|
||||||
{
|
{
|
||||||
JSFunction *fun = script->getFunction(fullAtomIndex(PC));
|
JSFunction *fun = script->getFunction(fullAtomIndex(PC));
|
||||||
prepareStubCall(Uses(frame.frameDepth()));
|
prepareStubCall(Uses(frame.frameSlots()));
|
||||||
masm.move(ImmPtr(fun), Registers::ArgReg1);
|
masm.move(ImmPtr(fun), Registers::ArgReg1);
|
||||||
INLINE_STUBCALL(stubs::FlatLambda);
|
INLINE_STUBCALL(stubs::FlatLambda);
|
||||||
frame.takeReg(Registers::ReturnReg);
|
frame.takeReg(Registers::ReturnReg);
|
||||||
|
@ -2176,11 +2189,15 @@ mjit::Compiler::fixPrimitiveReturn(Assembler *masm, FrameEntry *fe)
|
||||||
{
|
{
|
||||||
JS_ASSERT(isConstructing);
|
JS_ASSERT(isConstructing);
|
||||||
|
|
||||||
|
bool ool = (masm != &this->masm);
|
||||||
Address thisv(JSFrameReg, JSStackFrame::offsetOfThis(fun));
|
Address thisv(JSFrameReg, JSStackFrame::offsetOfThis(fun));
|
||||||
|
|
||||||
// Easy cases - no return value, or known primitive, so just return thisv.
|
// Easy cases - no return value, or known primitive, so just return thisv.
|
||||||
if (!fe || (fe->isTypeKnown() && fe->getKnownType() != JSVAL_TYPE_OBJECT)) {
|
if (!fe || (fe->isTypeKnown() && fe->getKnownType() != JSVAL_TYPE_OBJECT)) {
|
||||||
masm->loadValueAsComponents(thisv, JSReturnReg_Type, JSReturnReg_Data);
|
if (ool)
|
||||||
|
masm->loadValueAsComponents(thisv, JSReturnReg_Type, JSReturnReg_Data);
|
||||||
|
else
|
||||||
|
frame.loadThisForReturn(JSReturnReg_Type, JSReturnReg_Data, Registers::ReturnReg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2242,7 +2259,7 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
|
||||||
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.frameSlots()));
|
||||||
|
|
||||||
stubcc.leave();
|
stubcc.leave();
|
||||||
OOL_STUBCALL(stubs::PutActivationObjects);
|
OOL_STUBCALL(stubs::PutActivationObjects);
|
||||||
|
@ -2424,8 +2441,8 @@ mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedA
|
||||||
|
|
||||||
stubcc.masm.move(Imm32(callImmArgc), Registers::ArgReg1);
|
stubcc.masm.move(Imm32(callImmArgc), Registers::ArgReg1);
|
||||||
JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n");
|
JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n");
|
||||||
OOL_STUBCALL_SLOTS(JS_FUNC_TO_DATA_PTR(void *, stubs::UncachedCall),
|
OOL_STUBCALL_LOCAL_SLOTS(JS_FUNC_TO_DATA_PTR(void *, stubs::UncachedCall),
|
||||||
frame.frameDepth() + frameDepthAdjust);
|
frame.localSlots() + frameDepthAdjust);
|
||||||
JaegerSpew(JSpew_Insns, " ---- END SLOW CALL CODE ---- \n");
|
JaegerSpew(JSpew_Insns, " ---- END SLOW CALL CODE ---- \n");
|
||||||
|
|
||||||
RegisterID r0 = Registers::ReturnReg;
|
RegisterID r0 = Registers::ReturnReg;
|
||||||
|
@ -2576,7 +2593,7 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
|
||||||
* length of the array passed to apply.
|
* length of the array passed to apply.
|
||||||
*/
|
*/
|
||||||
if (*PC == JSOP_FUNCALL)
|
if (*PC == JSOP_FUNCALL)
|
||||||
callIC.frameSize.initStatic(frame.frameDepth(), speculatedArgc - 1);
|
callIC.frameSize.initStatic(frame.localSlots(), speculatedArgc - 1);
|
||||||
else
|
else
|
||||||
callIC.frameSize.initDynamic();
|
callIC.frameSize.initDynamic();
|
||||||
} else {
|
} else {
|
||||||
|
@ -2586,7 +2603,7 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
|
||||||
icCalleeType = origCalleeType;
|
icCalleeType = origCalleeType;
|
||||||
icCalleeData = origCalleeData;
|
icCalleeData = origCalleeData;
|
||||||
icRvalAddr = frame.addressOf(origCallee);
|
icRvalAddr = frame.addressOf(origCallee);
|
||||||
callIC.frameSize.initStatic(frame.frameDepth(), speculatedArgc);
|
callIC.frameSize.initStatic(frame.localSlots(), speculatedArgc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2660,9 +2677,9 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
|
||||||
callIC.addrLabel1 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
callIC.addrLabel1 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
||||||
void *icFunPtr = JS_FUNC_TO_DATA_PTR(void *, callingNew ? ic::New : ic::Call);
|
void *icFunPtr = JS_FUNC_TO_DATA_PTR(void *, callingNew ? ic::New : ic::Call);
|
||||||
if (callIC.frameSize.isStatic())
|
if (callIC.frameSize.isStatic())
|
||||||
callIC.oolCall = OOL_STUBCALL_SLOTS(icFunPtr, frame.frameDepth());
|
callIC.oolCall = OOL_STUBCALL_LOCAL_SLOTS(icFunPtr, frame.localSlots());
|
||||||
else
|
else
|
||||||
callIC.oolCall = OOL_STUBCALL_SLOTS(icFunPtr, -1);
|
callIC.oolCall = OOL_STUBCALL_LOCAL_SLOTS(icFunPtr, -1);
|
||||||
|
|
||||||
callIC.funObjReg = icCalleeData;
|
callIC.funObjReg = icCalleeData;
|
||||||
callIC.funPtrReg = funPtrReg;
|
callIC.funPtrReg = funPtrReg;
|
||||||
|
@ -3114,7 +3131,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
||||||
* Store the type and object back. Don't bother keeping them in registers,
|
* Store the type and object back. Don't bother keeping them in registers,
|
||||||
* since a sync will be needed for the upcoming call.
|
* since a sync will be needed for the upcoming call.
|
||||||
*/
|
*/
|
||||||
uint32 thisvSlot = frame.frameDepth();
|
uint32 thisvSlot = frame.localSlots();
|
||||||
Address thisv = Address(JSFrameReg, sizeof(JSStackFrame) + thisvSlot * sizeof(Value));
|
Address thisv = Address(JSFrameReg, sizeof(JSStackFrame) + thisvSlot * sizeof(Value));
|
||||||
#if defined JS_NUNBOX32
|
#if defined JS_NUNBOX32
|
||||||
masm.storeValueFromComponents(pic.typeReg, pic.objReg, thisv);
|
masm.storeValueFromComponents(pic.typeReg, pic.objReg, thisv);
|
||||||
|
@ -3702,38 +3719,32 @@ mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
|
||||||
mjit::Compiler::jsop_getarg(uint32 slot)
|
|
||||||
{
|
|
||||||
frame.push(Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, slot)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
mjit::Compiler::jsop_setarg(uint32 slot, bool popped)
|
|
||||||
{
|
|
||||||
FrameEntry *top = frame.peek(-1);
|
|
||||||
RegisterID reg = frame.allocReg();
|
|
||||||
Address address = Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, slot));
|
|
||||||
frame.storeTo(top, address, popped);
|
|
||||||
frame.freeReg(reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
mjit::Compiler::jsop_this()
|
mjit::Compiler::jsop_this()
|
||||||
{
|
{
|
||||||
Address thisvAddr(JSFrameReg, JSStackFrame::offsetOfThis(fun));
|
frame.pushThis();
|
||||||
frame.push(thisvAddr);
|
|
||||||
/*
|
/*
|
||||||
* In strict mode code, we don't wrap 'this'.
|
* In strict mode code, we don't wrap 'this'.
|
||||||
* In direct-call eval code, we wrapped 'this' before entering the eval.
|
* In direct-call eval code, we wrapped 'this' before entering the eval.
|
||||||
* In global code, 'this' is always an object.
|
* In global code, 'this' is always an object.
|
||||||
*/
|
*/
|
||||||
if (fun && !script->strictModeCode) {
|
if (fun && !script->strictModeCode) {
|
||||||
Jump notObj = frame.testObject(Assembler::NotEqual, frame.peek(-1));
|
FrameEntry *thisFe = frame.peek(-1);
|
||||||
stubcc.linkExit(notObj, Uses(1));
|
if (!thisFe->isTypeKnown()) {
|
||||||
stubcc.leave();
|
Jump notObj = frame.testObject(Assembler::NotEqual, thisFe);
|
||||||
OOL_STUBCALL(stubs::This);
|
stubcc.linkExit(notObj, Uses(1));
|
||||||
stubcc.rejoin(Changes(1));
|
stubcc.leave();
|
||||||
|
OOL_STUBCALL(stubs::This);
|
||||||
|
stubcc.rejoin(Changes(1));
|
||||||
|
|
||||||
|
// Now we know that |this| is an object.
|
||||||
|
frame.pop();
|
||||||
|
frame.learnThisIsObject();
|
||||||
|
frame.pushThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_ASSERT(thisFe->isType(JSVAL_TYPE_OBJECT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4758,7 +4769,7 @@ mjit::Compiler::enterBlock(JSObject *obj)
|
||||||
if (analysis->getCode(PC).exceptionEntry)
|
if (analysis->getCode(PC).exceptionEntry)
|
||||||
restoreFrameRegs(masm);
|
restoreFrameRegs(masm);
|
||||||
|
|
||||||
uint32 oldFrameDepth = frame.frameDepth();
|
uint32 oldFrameDepth = frame.localSlots();
|
||||||
|
|
||||||
/* For now, don't bother doing anything for this opcode. */
|
/* For now, don't bother doing anything for this opcode. */
|
||||||
frame.syncAndForgetEverything();
|
frame.syncAndForgetEverything();
|
||||||
|
@ -4806,10 +4817,7 @@ mjit::Compiler::constructThis()
|
||||||
JS_ASSERT(isConstructing);
|
JS_ASSERT(isConstructing);
|
||||||
|
|
||||||
// Load the callee.
|
// Load the callee.
|
||||||
Address callee(JSFrameReg, JSStackFrame::offsetOfCallee(fun));
|
frame.pushCallee();
|
||||||
RegisterID calleeReg = frame.allocReg();
|
|
||||||
masm.loadPayload(callee, calleeReg);
|
|
||||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, calleeReg);
|
|
||||||
|
|
||||||
// Get callee.prototype.
|
// Get callee.prototype.
|
||||||
if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false, false))
|
if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false, false))
|
||||||
|
|
|
@ -485,7 +485,7 @@ class Compiler : public BaseCompiler
|
||||||
stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), __LINE__) \
|
stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), __LINE__) \
|
||||||
|
|
||||||
// Same as OOL_STUBCALL, but specifies a slot depth.
|
// Same as OOL_STUBCALL, but specifies a slot depth.
|
||||||
#define OOL_STUBCALL_SLOTS(stub, slots) \
|
#define OOL_STUBCALL_LOCAL_SLOTS(stub, slots) \
|
||||||
stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), (slots), __LINE__) \
|
stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), (slots), __LINE__) \
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
|
@ -991,7 +991,7 @@ mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *tar
|
||||||
* Sync everything except the top two entries.
|
* Sync everything except the top two entries.
|
||||||
* We will handle the lhs/rhs in the stub call path.
|
* We will handle the lhs/rhs in the stub call path.
|
||||||
*/
|
*/
|
||||||
frame.syncAndKill(Registers(Registers::AvailRegs), Uses(frame.frameDepth()), Uses(2));
|
frame.syncAndKill(Registers(Registers::AvailRegs), Uses(frame.frameSlots()), Uses(2));
|
||||||
|
|
||||||
RegisterID tempReg = frame.allocReg();
|
RegisterID tempReg = frame.allocReg();
|
||||||
|
|
||||||
|
@ -1026,13 +1026,14 @@ mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *tar
|
||||||
if (useIC) {
|
if (useIC) {
|
||||||
/* Adjust for the two values just pushed. */
|
/* Adjust for the two values just pushed. */
|
||||||
ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
||||||
ic.stubCall = OOL_STUBCALL_SLOTS(ic::Equality, frame.stackDepth() + script->nfixed + 2);
|
ic.stubCall = OOL_STUBCALL_LOCAL_SLOTS(ic::Equality,
|
||||||
|
frame.stackDepth() + script->nfixed + 2);
|
||||||
needStub = false;
|
needStub = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (needStub)
|
if (needStub)
|
||||||
OOL_STUBCALL_SLOTS(stub, frame.stackDepth() + script->nfixed + 2);
|
OOL_STUBCALL_LOCAL_SLOTS(stub, frame.stackDepth() + script->nfixed + 2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The stub call has no need to rejoin, since state is synced.
|
* The stub call has no need to rejoin, since state is synced.
|
||||||
|
@ -1418,7 +1419,7 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
|
||||||
if (hasDoublePath) {
|
if (hasDoublePath) {
|
||||||
if (lhsUnknownDone.isSet())
|
if (lhsUnknownDone.isSet())
|
||||||
lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
|
lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||||
frame.sync(stubcc.masm, Uses(frame.frameDepth()));
|
frame.sync(stubcc.masm, Uses(frame.frameSlots()));
|
||||||
doubleTest = stubcc.masm.branchDouble(dblCond, fpLeft, fpRight);
|
doubleTest = stubcc.masm.branchDouble(dblCond, fpLeft, fpRight);
|
||||||
doubleFall = stubcc.masm.jump();
|
doubleFall = stubcc.masm.jump();
|
||||||
|
|
||||||
|
@ -1436,7 +1437,7 @@ mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target,
|
||||||
* that frame.sync() must be used directly, to avoid syncExit()'s
|
* that frame.sync() must be used directly, to avoid syncExit()'s
|
||||||
* jumping logic.
|
* jumping logic.
|
||||||
*/
|
*/
|
||||||
frame.sync(stubcc.masm, Uses(frame.frameDepth()));
|
frame.sync(stubcc.masm, Uses(frame.frameSlots()));
|
||||||
stubcc.leave();
|
stubcc.leave();
|
||||||
OOL_STUBCALL(stub);
|
OOL_STUBCALL(stub);
|
||||||
}
|
}
|
||||||
|
|
|
@ -972,7 +972,7 @@ mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target)
|
||||||
if (!fe->isTypeKnown() ||
|
if (!fe->isTypeKnown() ||
|
||||||
!(fe->isType(JSVAL_TYPE_BOOLEAN) || fe->isType(JSVAL_TYPE_INT32))) {
|
!(fe->isType(JSVAL_TYPE_BOOLEAN) || fe->isType(JSVAL_TYPE_INT32))) {
|
||||||
stubcc.masm.infallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::ValueToBoolean),
|
stubcc.masm.infallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::ValueToBoolean),
|
||||||
frame.frameDepth());
|
frame.localSlots());
|
||||||
|
|
||||||
jmpCvtExecScript.setJump(stubcc.masm.branchTest32(cond, Registers::ReturnReg,
|
jmpCvtExecScript.setJump(stubcc.masm.branchTest32(cond, Registers::ReturnReg,
|
||||||
Registers::ReturnReg));
|
Registers::ReturnReg));
|
||||||
|
@ -1144,45 +1144,59 @@ mjit::Compiler::jsop_localinc(JSOp op, uint32 slot, bool popped)
|
||||||
void
|
void
|
||||||
mjit::Compiler::jsop_arginc(JSOp op, uint32 slot, bool popped)
|
mjit::Compiler::jsop_arginc(JSOp op, uint32 slot, bool popped)
|
||||||
{
|
{
|
||||||
int amt = (js_CodeSpec[op].format & JOF_INC) ? 1 : -1;
|
if (popped || (op == JSOP_INCARG || op == JSOP_DECARG)) {
|
||||||
bool post = !!(js_CodeSpec[op].format & JOF_POST);
|
int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? -1 : 1;
|
||||||
uint32 depth = frame.stackDepth();
|
|
||||||
|
|
||||||
jsop_getarg(slot);
|
// Before:
|
||||||
if (post && !popped)
|
// After: V
|
||||||
|
frame.pushArg(slot);
|
||||||
|
|
||||||
|
// Before: V
|
||||||
|
// After: V 1
|
||||||
|
frame.push(Int32Value(amt));
|
||||||
|
|
||||||
|
// Note, SUB will perform integer conversion for us.
|
||||||
|
// Before: V 1
|
||||||
|
// After: N+1
|
||||||
|
jsop_binary(JSOP_SUB, stubs::Sub);
|
||||||
|
|
||||||
|
// Before: N+1
|
||||||
|
// After: N+1
|
||||||
|
frame.storeArg(slot, popped);
|
||||||
|
|
||||||
|
if (popped)
|
||||||
|
frame.pop();
|
||||||
|
} else {
|
||||||
|
int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? 1 : -1;
|
||||||
|
|
||||||
|
// Before:
|
||||||
|
// After: V
|
||||||
|
frame.pushArg(slot);
|
||||||
|
|
||||||
|
// Before: V
|
||||||
|
// After: N
|
||||||
|
jsop_pos();
|
||||||
|
|
||||||
|
// Before: N
|
||||||
|
// After: N N
|
||||||
frame.dup();
|
frame.dup();
|
||||||
|
|
||||||
FrameEntry *fe = frame.peek(-1);
|
// Before: N N
|
||||||
Jump notInt = frame.testInt32(Assembler::NotEqual, fe);
|
// After: N N 1
|
||||||
stubcc.linkExit(notInt, Uses(0));
|
frame.push(Int32Value(amt));
|
||||||
|
|
||||||
RegisterID reg = frame.ownRegForData(fe);
|
// Before: N N 1
|
||||||
frame.pop();
|
// After: N N+1
|
||||||
|
jsop_binary(JSOP_ADD, stubs::Add);
|
||||||
|
|
||||||
Jump ovf;
|
// Before: N N+1
|
||||||
if (amt > 0)
|
// After: N N+1
|
||||||
ovf = masm.branchAdd32(Assembler::Overflow, Imm32(1), reg);
|
frame.storeArg(slot, true);
|
||||||
else
|
|
||||||
ovf = masm.branchSub32(Assembler::Overflow, Imm32(1), reg);
|
|
||||||
stubcc.linkExit(ovf, Uses(0));
|
|
||||||
|
|
||||||
stubcc.leave();
|
// Before: N N+1
|
||||||
stubcc.masm.addPtr(Imm32(JSStackFrame::offsetOfFormalArg(fun, slot)),
|
// After: N
|
||||||
JSFrameReg, Registers::ArgReg1);
|
|
||||||
stubcc.vpInc(op, depth);
|
|
||||||
|
|
||||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
|
||||||
fe = frame.peek(-1);
|
|
||||||
|
|
||||||
Address address = Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, slot));
|
|
||||||
frame.storeTo(fe, address, popped);
|
|
||||||
|
|
||||||
if (post || popped)
|
|
||||||
frame.pop();
|
frame.pop();
|
||||||
else
|
}
|
||||||
frame.forgetType(fe);
|
|
||||||
|
|
||||||
stubcc.rejoin(Changes((post || popped) ? 0 : 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
|
|
|
@ -49,7 +49,7 @@ FrameState::addToTracker(FrameEntry *fe)
|
||||||
JS_ASSERT(!fe->isTracked());
|
JS_ASSERT(!fe->isTracked());
|
||||||
fe->track(tracker.nentries);
|
fe->track(tracker.nentries);
|
||||||
tracker.add(fe);
|
tracker.add(fe);
|
||||||
JS_ASSERT(tracker.nentries <= script->nslots);
|
JS_ASSERT(tracker.nentries <= feLimit());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FrameEntry *
|
inline FrameEntry *
|
||||||
|
@ -193,7 +193,7 @@ FrameState::syncAndForgetEverything(uint32 newStackDepth)
|
||||||
inline FrameEntry *
|
inline FrameEntry *
|
||||||
FrameState::rawPush()
|
FrameState::rawPush()
|
||||||
{
|
{
|
||||||
JS_ASSERT(unsigned(sp - entries) < nargs + script->nslots);
|
JS_ASSERT(unsigned(sp - entries) < feLimit());
|
||||||
|
|
||||||
if (!sp->isTracked())
|
if (!sp->isTracked())
|
||||||
addToTracker(sp);
|
addToTracker(sp);
|
||||||
|
@ -701,10 +701,17 @@ FrameState::learnType(FrameEntry *fe, JSValueType type)
|
||||||
inline JSC::MacroAssembler::Address
|
inline JSC::MacroAssembler::Address
|
||||||
FrameState::addressOf(const FrameEntry *fe) const
|
FrameState::addressOf(const FrameEntry *fe) const
|
||||||
{
|
{
|
||||||
uint32 index = (fe - entries);
|
int32 frameOffset = 0;
|
||||||
JS_ASSERT(index >= nargs);
|
if (fe >= locals)
|
||||||
index -= nargs;
|
frameOffset = JSStackFrame::offsetOfFixed(uint32(fe - locals));
|
||||||
return Address(JSFrameReg, sizeof(JSStackFrame) + sizeof(Value) * index);
|
else if (fe >= args)
|
||||||
|
frameOffset = JSStackFrame::offsetOfFormalArg(fun, uint32(fe - args));
|
||||||
|
else if (fe == this_)
|
||||||
|
frameOffset = JSStackFrame::offsetOfThis(fun);
|
||||||
|
else if (fe == callee_)
|
||||||
|
frameOffset = JSStackFrame::offsetOfCallee(fun);
|
||||||
|
JS_ASSERT(frameOffset);
|
||||||
|
return Address(JSFrameReg, frameOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline JSC::MacroAssembler::Address
|
inline JSC::MacroAssembler::Address
|
||||||
|
@ -789,9 +796,8 @@ FrameState::testString(Assembler::Condition cond, FrameEntry *fe)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FrameEntry *
|
inline FrameEntry *
|
||||||
FrameState::getLocal(uint32 slot)
|
FrameState::getOrTrack(uint32 index)
|
||||||
{
|
{
|
||||||
uint32 index = nargs + slot;
|
|
||||||
FrameEntry *fe = &entries[index];
|
FrameEntry *fe = &entries[index];
|
||||||
if (!fe->isTracked()) {
|
if (!fe->isTracked()) {
|
||||||
addToTracker(fe);
|
addToTracker(fe);
|
||||||
|
@ -800,6 +806,39 @@ FrameState::getLocal(uint32 slot)
|
||||||
return fe;
|
return fe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline FrameEntry *
|
||||||
|
FrameState::getLocal(uint32 slot)
|
||||||
|
{
|
||||||
|
JS_ASSERT(slot < script->nslots);
|
||||||
|
return getOrTrack(uint32(&locals[slot] - entries));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FrameEntry *
|
||||||
|
FrameState::getArg(uint32 slot)
|
||||||
|
{
|
||||||
|
JS_ASSERT(slot < nargs);
|
||||||
|
return getOrTrack(uint32(&args[slot] - entries));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FrameEntry *
|
||||||
|
FrameState::getThis()
|
||||||
|
{
|
||||||
|
return getOrTrack(uint32(this_ - entries));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FrameEntry *
|
||||||
|
FrameState::getCallee()
|
||||||
|
{
|
||||||
|
// Callee can only be used in function code, and it's always an object.
|
||||||
|
JS_ASSERT(fun);
|
||||||
|
if (!callee_->isTracked()) {
|
||||||
|
addToTracker(callee_);
|
||||||
|
callee_->resetSynced();
|
||||||
|
callee_->setType(JSVAL_TYPE_OBJECT);
|
||||||
|
}
|
||||||
|
return callee_;
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FrameState::pinReg(RegisterID reg)
|
FrameState::pinReg(RegisterID reg)
|
||||||
{
|
{
|
||||||
|
@ -841,12 +880,6 @@ FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs)
|
||||||
rhs->index_ = li;
|
rhs->index_ = li;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32
|
|
||||||
FrameState::localIndex(uint32 n)
|
|
||||||
{
|
|
||||||
return nargs + n;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FrameState::dup()
|
FrameState::dup()
|
||||||
{
|
{
|
||||||
|
@ -873,8 +906,9 @@ FrameState::dupAt(int32 n)
|
||||||
inline void
|
inline void
|
||||||
FrameState::pushLocal(uint32 n)
|
FrameState::pushLocal(uint32 n)
|
||||||
{
|
{
|
||||||
if (!eval && !isClosedVar(n)) {
|
FrameEntry *fe = getLocal(n);
|
||||||
pushCopyOf(indexOfFe(getLocal(n)));
|
if (!isClosedVar(n)) {
|
||||||
|
pushCopyOf(indexOfFe(fe));
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/*
|
/*
|
||||||
|
@ -888,10 +922,51 @@ FrameState::pushLocal(uint32 n)
|
||||||
JS_ASSERT(fe->data.inMemory());
|
JS_ASSERT(fe->data.inMemory());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
push(Address(JSFrameReg, sizeof(JSStackFrame) + n * sizeof(Value)));
|
push(addressOf(fe));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
FrameState::pushArg(uint32 n)
|
||||||
|
{
|
||||||
|
FrameEntry *fe = getArg(n);
|
||||||
|
if (!isClosedArg(n)) {
|
||||||
|
pushCopyOf(indexOfFe(fe));
|
||||||
|
} else {
|
||||||
|
#ifdef DEBUG
|
||||||
|
FrameEntry *fe = &args[n];
|
||||||
|
if (fe->isTracked()) {
|
||||||
|
JS_ASSERT(fe->type.inMemory());
|
||||||
|
JS_ASSERT(fe->data.inMemory());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
push(addressOf(fe));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
FrameState::pushCallee()
|
||||||
|
{
|
||||||
|
FrameEntry *fe = getCallee();
|
||||||
|
pushCopyOf(indexOfFe(fe));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
FrameState::pushThis()
|
||||||
|
{
|
||||||
|
FrameEntry *fe = getThis();
|
||||||
|
pushCopyOf(indexOfFe(fe));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FrameState::learnThisIsObject()
|
||||||
|
{
|
||||||
|
// This is safe, albeit hacky. This is only called from the compiler,
|
||||||
|
// and only on the first use of |this| inside a basic block. Thus,
|
||||||
|
// there are no copies of |this| anywhere.
|
||||||
|
learnType(this_, JSVAL_TYPE_OBJECT);
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FrameState::leaveBlock(uint32 n)
|
FrameState::leaveBlock(uint32 n)
|
||||||
{
|
{
|
||||||
|
@ -927,6 +1002,13 @@ FrameState::setClosedVar(uint32 slot)
|
||||||
closedVars[slot] = true;
|
closedVars[slot] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
FrameState::setClosedArg(uint32 slot)
|
||||||
|
{
|
||||||
|
if (!eval && !usesArguments)
|
||||||
|
closedArgs[slot] = true;
|
||||||
|
}
|
||||||
|
|
||||||
inline StateRemat
|
inline StateRemat
|
||||||
FrameState::dataRematInfo(const FrameEntry *fe) const
|
FrameState::dataRematInfo(const FrameEntry *fe) const
|
||||||
{
|
{
|
||||||
|
@ -1013,7 +1095,13 @@ FrameState::loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) cons
|
||||||
inline bool
|
inline bool
|
||||||
FrameState::isClosedVar(uint32 slot)
|
FrameState::isClosedVar(uint32 slot)
|
||||||
{
|
{
|
||||||
return closedVars[slot];
|
return eval || closedVars[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
FrameState::isClosedArg(uint32 slot)
|
||||||
|
{
|
||||||
|
return eval || usesArguments || closedArgs[slot];
|
||||||
}
|
}
|
||||||
|
|
||||||
class PinRegAcrossSyncAndKill
|
class PinRegAcrossSyncAndKill
|
||||||
|
|
|
@ -46,11 +46,16 @@ using namespace js::mjit;
|
||||||
/* Because of Value alignment */
|
/* Because of Value alignment */
|
||||||
JS_STATIC_ASSERT(sizeof(FrameEntry) % 8 == 0);
|
JS_STATIC_ASSERT(sizeof(FrameEntry) % 8 == 0);
|
||||||
|
|
||||||
FrameState::FrameState(JSContext *cx, JSScript *script, Assembler &masm)
|
FrameState::FrameState(JSContext *cx, JSScript *script, JSFunction *fun, Assembler &masm)
|
||||||
: cx(cx), script(script), masm(masm), entries(NULL),
|
: cx(cx), script(script), fun(fun),
|
||||||
|
nargs(fun ? fun->nargs : 0),
|
||||||
|
masm(masm), entries(NULL),
|
||||||
#if defined JS_NUNBOX32
|
#if defined JS_NUNBOX32
|
||||||
reifier(cx, *thisFromCtor()),
|
reifier(cx, *thisFromCtor()),
|
||||||
#endif
|
#endif
|
||||||
|
closedVars(NULL),
|
||||||
|
closedArgs(NULL),
|
||||||
|
usesArguments(script->usesArguments),
|
||||||
inTryBlock(false)
|
inTryBlock(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -61,45 +66,57 @@ FrameState::~FrameState()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FrameState::init(uint32 nargs)
|
FrameState::init()
|
||||||
{
|
{
|
||||||
this->nargs = nargs;
|
// nslots + nargs + 2 (callee, this)
|
||||||
|
uint32 nentries = feLimit();
|
||||||
uint32 nslots = script->nslots + nargs;
|
if (!nentries) {
|
||||||
if (!nslots) {
|
|
||||||
sp = spBase = locals = args = NULL;
|
sp = spBase = locals = args = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
eval = script->usesEval || cx->compartment->debugMode;
|
eval = script->usesEval || cx->compartment->debugMode;
|
||||||
|
|
||||||
size_t totalBytes = sizeof(FrameEntry) * nslots + // entries[]
|
size_t totalBytes = sizeof(FrameEntry) * nentries + // entries[], w/ callee+this
|
||||||
sizeof(FrameEntry *) * nslots + // tracker.entries
|
sizeof(FrameEntry *) * nentries + // tracker.entries
|
||||||
(eval ? 0 : sizeof(JSPackedBool) * nslots); // closedVars[]
|
(eval
|
||||||
|
? 0
|
||||||
|
: sizeof(JSPackedBool) * script->nslots) + // closedVars[]
|
||||||
|
(eval || usesArguments
|
||||||
|
? 0
|
||||||
|
: sizeof(JSPackedBool) * nargs); // closedArgs[]
|
||||||
|
|
||||||
uint8 *cursor = (uint8 *)cx->calloc(totalBytes);
|
uint8 *cursor = (uint8 *)cx->calloc(totalBytes);
|
||||||
if (!cursor)
|
if (!cursor)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#if defined JS_NUNBOX32
|
#if defined JS_NUNBOX32
|
||||||
if (!reifier.init(nslots))
|
if (!reifier.init(nentries))
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
entries = (FrameEntry *)cursor;
|
entries = (FrameEntry *)cursor;
|
||||||
cursor += sizeof(FrameEntry) * nslots;
|
cursor += sizeof(FrameEntry) * nentries;
|
||||||
|
|
||||||
args = entries;
|
callee_ = entries;
|
||||||
|
this_ = entries + 1;
|
||||||
|
args = entries + 2;
|
||||||
locals = args + nargs;
|
locals = args + nargs;
|
||||||
spBase = locals + script->nfixed;
|
spBase = locals + script->nfixed;
|
||||||
sp = spBase;
|
sp = spBase;
|
||||||
|
|
||||||
tracker.entries = (FrameEntry **)cursor;
|
tracker.entries = (FrameEntry **)cursor;
|
||||||
cursor += sizeof(FrameEntry *) * nslots;
|
cursor += sizeof(FrameEntry *) * nentries;
|
||||||
|
|
||||||
if (!eval && nslots) {
|
if (!eval) {
|
||||||
closedVars = (JSPackedBool *)cursor;
|
if (script->nslots) {
|
||||||
cursor += sizeof(JSPackedBool) * nslots;
|
closedVars = (JSPackedBool *)cursor;
|
||||||
|
cursor += sizeof(JSPackedBool) * script->nslots;
|
||||||
|
}
|
||||||
|
if (!usesArguments && nargs) {
|
||||||
|
closedArgs = (JSPackedBool *)cursor;
|
||||||
|
cursor += sizeof(JSPackedBool) * nargs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(reinterpret_cast<uint8 *>(entries) + totalBytes == cursor);
|
JS_ASSERT(reinterpret_cast<uint8 *>(entries) + totalBytes == cursor);
|
||||||
|
@ -180,7 +197,7 @@ FrameState::evictSomeReg(uint32 mask)
|
||||||
void
|
void
|
||||||
FrameState::syncAndForgetEverything()
|
FrameState::syncAndForgetEverything()
|
||||||
{
|
{
|
||||||
syncAndKill(Registers(Registers::AvailRegs), Uses(frameDepth()));
|
syncAndKill(Registers(Registers::AvailRegs), Uses(frameSlots()));
|
||||||
forgetEverything();
|
forgetEverything();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,6 +343,12 @@ FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FrameState::loadThisForReturn(RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
|
||||||
|
{
|
||||||
|
return loadForReturn(getThis(), typeReg, dataReg, tempReg);
|
||||||
|
}
|
||||||
|
|
||||||
void FrameState::loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
|
void FrameState::loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
|
||||||
{
|
{
|
||||||
JS_ASSERT(dataReg != typeReg && dataReg != tempReg && typeReg != tempReg);
|
JS_ASSERT(dataReg != typeReg && dataReg != tempReg && typeReg != tempReg);
|
||||||
|
@ -1138,26 +1161,41 @@ FrameState::uncopy(FrameEntry *original)
|
||||||
return fe;
|
return fe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FrameState::finishStore(FrameEntry *fe, bool closed)
|
||||||
|
{
|
||||||
|
// Make sure the backing store entry is synced to memory, then if it's
|
||||||
|
// closed, forget it entirely (removing all copies) and reset it to a
|
||||||
|
// synced, in-memory state.
|
||||||
|
syncFe(fe);
|
||||||
|
if (closed) {
|
||||||
|
if (!fe->isCopy())
|
||||||
|
forgetEntry(fe);
|
||||||
|
fe->resetSynced();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FrameState::storeLocal(uint32 n, bool popGuaranteed, bool typeChange)
|
FrameState::storeLocal(uint32 n, bool popGuaranteed, bool typeChange)
|
||||||
{
|
{
|
||||||
FrameEntry *local = getLocal(n);
|
FrameEntry *local = getLocal(n);
|
||||||
|
|
||||||
storeTop(local, popGuaranteed, typeChange);
|
storeTop(local, popGuaranteed, typeChange);
|
||||||
|
|
||||||
bool closed = eval || isClosedVar(n);
|
bool closed = isClosedVar(n);
|
||||||
if (!closed && !inTryBlock)
|
if (!closed && !inTryBlock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Ensure that the local variable remains synced. */
|
finishStore(local, closed);
|
||||||
syncFe(local);
|
}
|
||||||
|
|
||||||
if (closed) {
|
void
|
||||||
/* If the FE can have registers, free them before resetting. */
|
FrameState::storeArg(uint32 n, bool popGuaranteed)
|
||||||
if (!local->isCopy())
|
{
|
||||||
forgetEntry(local);
|
// Note that args are always immediately synced, because they can be
|
||||||
local->resetSynced();
|
// aliased (but not written to) via f.arguments.
|
||||||
}
|
FrameEntry *arg = getArg(n);
|
||||||
|
storeTop(arg, popGuaranteed, true);
|
||||||
|
finishStore(arg, isClosedArg(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -238,9 +238,9 @@ class FrameState
|
||||||
|
|
||||||
FrameState *thisFromCtor() { return this; }
|
FrameState *thisFromCtor() { return this; }
|
||||||
public:
|
public:
|
||||||
FrameState(JSContext *cx, JSScript *script, Assembler &masm);
|
FrameState(JSContext *cx, JSScript *script, JSFunction *fun, Assembler &masm);
|
||||||
~FrameState();
|
~FrameState();
|
||||||
bool init(uint32 nargs);
|
bool init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pushes a synced slot.
|
* Pushes a synced slot.
|
||||||
|
@ -331,10 +331,13 @@ class FrameState
|
||||||
inline void enterBlock(uint32 n);
|
inline void enterBlock(uint32 n);
|
||||||
inline void leaveBlock(uint32 n);
|
inline void leaveBlock(uint32 n);
|
||||||
|
|
||||||
/*
|
// Pushes a copy of a slot (formal argument, local variable, or stack slot)
|
||||||
* Pushes a copy of a local variable.
|
// onto the operation stack.
|
||||||
*/
|
|
||||||
void pushLocal(uint32 n);
|
void pushLocal(uint32 n);
|
||||||
|
void pushArg(uint32 n);
|
||||||
|
void pushCallee();
|
||||||
|
void pushThis();
|
||||||
|
inline void learnThisIsObject();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocates a temporary register for a FrameEntry's type. The register
|
* Allocates a temporary register for a FrameEntry's type. The register
|
||||||
|
@ -546,12 +549,15 @@ class FrameState
|
||||||
* used as a temporary.
|
* used as a temporary.
|
||||||
*/
|
*/
|
||||||
void loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
|
void loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
|
||||||
|
void loadThisForReturn(RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stores the top stack slot back to a slot.
|
* Stores the top stack slot back to a slot.
|
||||||
*/
|
*/
|
||||||
void storeLocal(uint32 n, bool popGuaranteed = false, bool typeChange = true);
|
void storeLocal(uint32 n, bool popGuaranteed = false, bool typeChange = true);
|
||||||
|
void storeArg(uint32 n, bool popGuaranteed = false);
|
||||||
void storeTop(FrameEntry *target, bool popGuaranteed = false, bool typeChange = true);
|
void storeTop(FrameEntry *target, bool popGuaranteed = false, bool typeChange = true);
|
||||||
|
void finishStore(FrameEntry *fe, bool closed);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restores state from a slow path.
|
* Restores state from a slow path.
|
||||||
|
@ -572,7 +578,7 @@ class FrameState
|
||||||
|
|
||||||
/* Syncs and kills everything. */
|
/* Syncs and kills everything. */
|
||||||
void syncAndKillEverything() {
|
void syncAndKillEverything() {
|
||||||
syncAndKill(Registers(Registers::AvailRegs), Uses(frameDepth()));
|
syncAndKill(Registers(Registers::AvailRegs), Uses(frameSlots()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -706,17 +712,32 @@ class FrameState
|
||||||
*/
|
*/
|
||||||
inline void giveOwnRegs(FrameEntry *fe);
|
inline void giveOwnRegs(FrameEntry *fe);
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the current stack depth of the frame.
|
|
||||||
*/
|
|
||||||
uint32 stackDepth() const { return sp - spBase; }
|
uint32 stackDepth() const { return sp - spBase; }
|
||||||
uint32 frameDepth() const { return stackDepth() + script->nfixed; }
|
|
||||||
|
// Returns the number of entries in the frame, that is:
|
||||||
|
// 2 for callee, this +
|
||||||
|
// nargs +
|
||||||
|
// nfixed +
|
||||||
|
// currently pushed stack slots
|
||||||
|
uint32 frameSlots() const { return uint32(sp - entries); }
|
||||||
|
|
||||||
|
// Returns the number of local variables and active stack slots.
|
||||||
|
uint32 localSlots() const { return uint32(sp - locals); }
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void assertValidRegisterState() const;
|
void assertValidRegisterState() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Return an address, relative to the JSStackFrame, that represents where
|
||||||
|
// this FrameEntry is stored in memory. Note that this is its canonical
|
||||||
|
// address, not its backing store. There is no guarantee that the memory
|
||||||
|
// is coherent.
|
||||||
Address addressOf(const FrameEntry *fe) const;
|
Address addressOf(const FrameEntry *fe) const;
|
||||||
|
|
||||||
|
// Returns an address, relative to the JSStackFrame, that represents where
|
||||||
|
// this FrameEntry is backed in memory. This is not necessarily its
|
||||||
|
// canonical address, but the address for which the payload has been synced
|
||||||
|
// to memory. The caller guarantees that the payload has been synced.
|
||||||
Address addressForDataRemat(const FrameEntry *fe) const;
|
Address addressForDataRemat(const FrameEntry *fe) const;
|
||||||
|
|
||||||
inline StateRemat dataRematInfo(const FrameEntry *fe) const;
|
inline StateRemat dataRematInfo(const FrameEntry *fe) const;
|
||||||
|
@ -742,10 +763,9 @@ class FrameState
|
||||||
*/
|
*/
|
||||||
void shift(int32 n);
|
void shift(int32 n);
|
||||||
|
|
||||||
/*
|
// Notifies the frame that a local variable or argument slot is closed over.
|
||||||
* Notifies the frame of a slot that can escape.
|
|
||||||
*/
|
|
||||||
inline void setClosedVar(uint32 slot);
|
inline void setClosedVar(uint32 slot);
|
||||||
|
inline void setClosedArg(uint32 slot);
|
||||||
|
|
||||||
inline void setInTryBlock(bool inTryBlock) {
|
inline void setInTryBlock(bool inTryBlock) {
|
||||||
this->inTryBlock = inTryBlock;
|
this->inTryBlock = inTryBlock;
|
||||||
|
@ -769,10 +789,13 @@ class FrameState
|
||||||
inline void syncType(FrameEntry *fe);
|
inline void syncType(FrameEntry *fe);
|
||||||
inline void syncData(FrameEntry *fe);
|
inline void syncData(FrameEntry *fe);
|
||||||
|
|
||||||
|
inline FrameEntry *getOrTrack(uint32 index);
|
||||||
inline FrameEntry *getLocal(uint32 slot);
|
inline FrameEntry *getLocal(uint32 slot);
|
||||||
|
inline FrameEntry *getArg(uint32 slot);
|
||||||
|
inline FrameEntry *getCallee();
|
||||||
|
inline FrameEntry *getThis();
|
||||||
inline void forgetAllRegs(FrameEntry *fe);
|
inline void forgetAllRegs(FrameEntry *fe);
|
||||||
inline void swapInTracker(FrameEntry *lhs, FrameEntry *rhs);
|
inline void swapInTracker(FrameEntry *lhs, FrameEntry *rhs);
|
||||||
inline uint32 localIndex(uint32 n);
|
|
||||||
void pushCopyOf(uint32 index);
|
void pushCopyOf(uint32 index);
|
||||||
#if defined JS_NUNBOX32
|
#if defined JS_NUNBOX32
|
||||||
void syncFancy(Assembler &masm, Registers avail, FrameEntry *resumeAt,
|
void syncFancy(Assembler &masm, Registers avail, FrameEntry *resumeAt,
|
||||||
|
@ -804,23 +827,24 @@ class FrameState
|
||||||
return &entries[index];
|
return &entries[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterID evictSomeReg() {
|
RegisterID evictSomeReg() { return evictSomeReg(Registers::AvailRegs); }
|
||||||
return evictSomeReg(Registers::AvailRegs);
|
uint32 indexOf(int32 depth) const {
|
||||||
}
|
JS_ASSERT(uint32((sp + depth) - entries) < feLimit());
|
||||||
|
|
||||||
uint32 indexOf(int32 depth) {
|
|
||||||
return uint32((sp + depth) - entries);
|
return uint32((sp + depth) - entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 indexOfFe(FrameEntry *fe) const {
|
uint32 indexOfFe(FrameEntry *fe) const {
|
||||||
|
JS_ASSERT(uint32(fe - entries) < feLimit());
|
||||||
return uint32(fe - entries);
|
return uint32(fe - entries);
|
||||||
}
|
}
|
||||||
|
uint32 feLimit() const { return script->nslots + nargs + 2; }
|
||||||
|
|
||||||
inline bool isClosedVar(uint32 slot);
|
inline bool isClosedVar(uint32 slot);
|
||||||
|
inline bool isClosedArg(uint32 slot);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSContext *cx;
|
JSContext *cx;
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
|
JSFunction *fun;
|
||||||
uint32 nargs;
|
uint32 nargs;
|
||||||
Assembler &masm;
|
Assembler &masm;
|
||||||
|
|
||||||
|
@ -830,6 +854,9 @@ class FrameState
|
||||||
/* Cache of FrameEntry objects. */
|
/* Cache of FrameEntry objects. */
|
||||||
FrameEntry *entries;
|
FrameEntry *entries;
|
||||||
|
|
||||||
|
FrameEntry *callee_;
|
||||||
|
FrameEntry *this_;
|
||||||
|
|
||||||
/* Base pointer for arguments. */
|
/* Base pointer for arguments. */
|
||||||
FrameEntry *args;
|
FrameEntry *args;
|
||||||
|
|
||||||
|
@ -856,7 +883,9 @@ class FrameState
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JSPackedBool *closedVars;
|
JSPackedBool *closedVars;
|
||||||
|
JSPackedBool *closedArgs;
|
||||||
bool eval;
|
bool eval;
|
||||||
|
bool usesArguments;
|
||||||
bool inTryBlock;
|
bool inTryBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ class InlineFrameAssembler {
|
||||||
|
|
||||||
DataLabelPtr ncodePatch;
|
DataLabelPtr ncodePatch;
|
||||||
if (frameSize.isStatic()) {
|
if (frameSize.isStatic()) {
|
||||||
uint32 frameDepth = frameSize.staticFrameDepth();
|
uint32 frameDepth = frameSize.staticLocalSlots();
|
||||||
AdjustedFrame newfp(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
|
AdjustedFrame newfp(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
|
||||||
|
|
||||||
Address flagsAddr = newfp.addrOf(JSStackFrame::offsetOfFlags());
|
Address flagsAddr = newfp.addrOf(JSStackFrame::offsetOfFlags());
|
||||||
|
|
|
@ -528,7 +528,7 @@ class CallCompiler : public BaseCompiler
|
||||||
void *compilePtr = JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction);
|
void *compilePtr = JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction);
|
||||||
if (ic.frameSize.isStatic()) {
|
if (ic.frameSize.isStatic()) {
|
||||||
masm.move(Imm32(ic.frameSize.staticArgc()), Registers::ArgReg1);
|
masm.move(Imm32(ic.frameSize.staticArgc()), Registers::ArgReg1);
|
||||||
masm.fallibleVMCall(compilePtr, script->code, ic.frameSize.staticFrameDepth());
|
masm.fallibleVMCall(compilePtr, script->code, ic.frameSize.staticLocalSlots());
|
||||||
} else {
|
} else {
|
||||||
masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), Registers::ArgReg1);
|
masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), Registers::ArgReg1);
|
||||||
masm.fallibleVMCall(compilePtr, script->code, -1);
|
masm.fallibleVMCall(compilePtr, script->code, -1);
|
||||||
|
@ -642,7 +642,7 @@ class CallCompiler : public BaseCompiler
|
||||||
*/
|
*/
|
||||||
Value *vp;
|
Value *vp;
|
||||||
if (ic.frameSize.isStatic()) {
|
if (ic.frameSize.isStatic()) {
|
||||||
JS_ASSERT(f.regs.sp - f.regs.fp->slots() == (int)ic.frameSize.staticFrameDepth());
|
JS_ASSERT(f.regs.sp - f.regs.fp->slots() == (int)ic.frameSize.staticLocalSlots());
|
||||||
vp = f.regs.sp - (2 + ic.frameSize.staticArgc());
|
vp = f.regs.sp - (2 + ic.frameSize.staticArgc());
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(*f.regs.pc == JSOP_FUNAPPLY && GET_ARGC(f.regs.pc) == 2);
|
JS_ASSERT(*f.regs.pc == JSOP_FUNAPPLY && GET_ARGC(f.regs.pc) == 2);
|
||||||
|
|
|
@ -73,7 +73,7 @@ class FrameSize
|
||||||
return frameDepth_ == 0;
|
return frameDepth_ == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 staticFrameDepth() const {
|
uint32 staticLocalSlots() const {
|
||||||
JS_ASSERT(isStatic());
|
JS_ASSERT(isStatic());
|
||||||
return frameDepth_;
|
return frameDepth_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,10 @@ struct StateRemat {
|
||||||
bool isConstant() const { return offset_ == CONSTANT; }
|
bool isConstant() const { return offset_ == CONSTANT; }
|
||||||
bool inRegister() const { return offset_ >= 0 &&
|
bool inRegister() const { return offset_ >= 0 &&
|
||||||
offset_ <= int32(JSC::MacroAssembler::TotalRegisters); }
|
offset_ <= int32(JSC::MacroAssembler::TotalRegisters); }
|
||||||
bool inMemory() const { return offset_ >= int32(sizeof(JSStackFrame)); }
|
bool inMemory() const {
|
||||||
|
return offset_ >= int32(sizeof(JSStackFrame)) ||
|
||||||
|
offset_ < 0;
|
||||||
|
}
|
||||||
|
|
||||||
int32 toInt32() const { return offset_; }
|
int32 toInt32() const { return offset_; }
|
||||||
Address address() const {
|
Address address() const {
|
||||||
|
|
|
@ -64,12 +64,6 @@ StubCompiler::StubCompiler(JSContext *cx, mjit::Compiler &cc, FrameState &frame,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
StubCompiler::init(uint32 nargs)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
StubCompiler::linkExitDirect(Jump j, Label L)
|
StubCompiler::linkExitDirect(Jump j, Label L)
|
||||||
{
|
{
|
||||||
|
@ -136,7 +130,7 @@ StubCompiler::linkExit(Jump j, Uses uses)
|
||||||
void
|
void
|
||||||
StubCompiler::linkExitForBranch(Jump j)
|
StubCompiler::linkExitForBranch(Jump j)
|
||||||
{
|
{
|
||||||
Label l = syncExit(Uses(frame.frameDepth()));
|
Label l = syncExit(Uses(frame.frameSlots()));
|
||||||
linkExitDirect(j, l);
|
linkExitDirect(j, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,8 +96,6 @@ class StubCompiler
|
||||||
public:
|
public:
|
||||||
StubCompiler(JSContext *cx, mjit::Compiler &cc, FrameState &frame, JSScript *script);
|
StubCompiler(JSContext *cx, mjit::Compiler &cc, FrameState &frame, JSScript *script);
|
||||||
|
|
||||||
bool init(uint32 nargs);
|
|
||||||
|
|
||||||
size_t size() {
|
size_t size() {
|
||||||
return masm.size();
|
return masm.size();
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче