зеркало из https://github.com/mozilla/gecko-dev.git
Bug 907187 - Rewrite Baseline -> Ion OSR to not use the StackFrame layout. r=djvj
This commit is contained in:
Родитель
150ebd9bb0
Коммит
0d5ad78783
|
@ -810,22 +810,18 @@ EnsureCanEnterIon(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *frame
|
|||
// The following data is kept in a temporary heap-allocated buffer, stored in
|
||||
// IonRuntime (high memory addresses at top, low at bottom):
|
||||
//
|
||||
// +=================================+ -- <---- High Address
|
||||
// | | |
|
||||
// | ...Locals/Stack... | |
|
||||
// | | |
|
||||
// +---------------------------------+ |
|
||||
// | | |
|
||||
// | ...StackFrame... | |-- Fake StackFrame
|
||||
// | | |
|
||||
// +----> +---------------------------------+ |
|
||||
// +----->+=================================+ -- <---- High Address
|
||||
// | | | |
|
||||
// | | ...Args/This... | |
|
||||
// | | ...BaselineFrame... | |-- Copy of BaselineFrame + stack values
|
||||
// | | | |
|
||||
// | +---------------------------------+ |
|
||||
// | | | |
|
||||
// | | ...Locals/Stack... | |
|
||||
// | | | |
|
||||
// | +=================================+ --
|
||||
// | | Padding(Maybe Empty) |
|
||||
// | +=================================+ --
|
||||
// +------|-- stackFrame | |-- IonOsrTempData
|
||||
// +------|-- baselineFrame | |-- IonOsrTempData
|
||||
// | jitcode | |
|
||||
// +=================================+ -- <---- Low Address
|
||||
//
|
||||
|
@ -834,31 +830,27 @@ EnsureCanEnterIon(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *frame
|
|||
struct IonOsrTempData
|
||||
{
|
||||
void *jitcode;
|
||||
uint8_t *stackFrame;
|
||||
uint8_t *baselineFrame;
|
||||
};
|
||||
|
||||
static IonOsrTempData *
|
||||
PrepareOsrTempData(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *frame,
|
||||
HandleScript script, jsbytecode *pc, void *jitcode)
|
||||
{
|
||||
// Calculate the (numLocals + numStackVals), and the number of formal args.
|
||||
size_t numLocalsAndStackVals = frame->numValueSlots();
|
||||
size_t numFormalArgs = frame->isFunctionFrame() ? frame->numFormalArgs() : 0;
|
||||
|
||||
// Calculate the amount of space to allocate:
|
||||
// StackFrame space:
|
||||
// BaselineFrame space:
|
||||
// (sizeof(Value) * (numLocals + numStackVals))
|
||||
// + sizeof(StackFrame)
|
||||
// + (sizeof(Value) * (numFormalArgs + 1)) // +1 for ThisV
|
||||
// + sizeof(BaselineFrame)
|
||||
//
|
||||
// IonOsrTempData space:
|
||||
// sizeof(IonOsrTempData)
|
||||
|
||||
size_t stackFrameSpace = (sizeof(Value) * numLocalsAndStackVals) + sizeof(StackFrame)
|
||||
+ (sizeof(Value) * (numFormalArgs + 1));
|
||||
size_t frameSpace = sizeof(BaselineFrame) + sizeof(Value) * numLocalsAndStackVals;
|
||||
size_t ionOsrTempDataSpace = sizeof(IonOsrTempData);
|
||||
|
||||
size_t totalSpace = AlignBytes(stackFrameSpace, sizeof(Value)) +
|
||||
size_t totalSpace = AlignBytes(frameSpace, sizeof(Value)) +
|
||||
AlignBytes(ionOsrTempDataSpace, sizeof(Value));
|
||||
|
||||
IonOsrTempData *info = (IonOsrTempData *)cx->runtime()->getIonRuntime(cx)->allocateOsrTempData(totalSpace);
|
||||
|
@ -869,44 +861,15 @@ PrepareOsrTempData(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *fram
|
|||
|
||||
info->jitcode = jitcode;
|
||||
|
||||
uint8_t *stackFrameStart = (uint8_t *)info + AlignBytes(ionOsrTempDataSpace, sizeof(Value));
|
||||
info->stackFrame = stackFrameStart + (numFormalArgs * sizeof(Value)) + sizeof(Value);
|
||||
// Copy the BaselineFrame + local/stack Values to the buffer. Arguments and
|
||||
// |this| are not copied but left on the stack: the Baseline and Ion frame
|
||||
// share the same frame prefix and Ion won't clobber these values. Note
|
||||
// that info->baselineFrame will point to the *end* of the frame data, like
|
||||
// the frame pointer register in baseline frames.
|
||||
uint8_t *frameStart = (uint8_t *)info + AlignBytes(ionOsrTempDataSpace, sizeof(Value));
|
||||
info->baselineFrame = frameStart + frameSpace;
|
||||
|
||||
//
|
||||
// Initialize the fake StackFrame.
|
||||
//
|
||||
|
||||
// Copy formal args and thisv.
|
||||
memcpy(stackFrameStart, frame->argv() - 1, (numFormalArgs + 1) * sizeof(Value));
|
||||
|
||||
// Initialize ScopeChain, Exec, ArgsObj, and Flags fields in StackFrame struct.
|
||||
uint8_t *stackFrame = info->stackFrame;
|
||||
*((JSObject **) (stackFrame + StackFrame::offsetOfScopeChain())) = frame->scopeChain();
|
||||
if (frame->script()->needsArgsObj()) {
|
||||
JS_ASSERT(frame->hasArgsObj());
|
||||
*((JSObject **) (stackFrame + StackFrame::offsetOfArgumentsObject())) = &frame->argsObj();
|
||||
}
|
||||
if (frame->isFunctionFrame()) {
|
||||
// Store the function in exec field, and StackFrame::FUNCTION for flags.
|
||||
*((JSFunction **) (stackFrame + StackFrame::offsetOfExec())) = frame->fun();
|
||||
*((uint32_t *) (stackFrame + StackFrame::offsetOfFlags())) = StackFrame::FUNCTION;
|
||||
} else {
|
||||
*((JSScript **) (stackFrame + StackFrame::offsetOfExec())) = frame->script();
|
||||
*((uint32_t *) (stackFrame + StackFrame::offsetOfFlags())) = 0;
|
||||
}
|
||||
|
||||
// Set return value.
|
||||
if (frame->hasReturnValue()) {
|
||||
*((uint32_t *) (stackFrame + StackFrame::offsetOfFlags())) |= StackFrame::HAS_RVAL;
|
||||
*((Value *) (stackFrame + StackFrame::offsetOfReturnValue())) = *(frame->returnValue());
|
||||
}
|
||||
|
||||
// Do locals and stack values. Note that in the fake StackFrame, these go from
|
||||
// low to high addresses, while on the C stack, they go from high to low addresses.
|
||||
// So we can't use memcpy on this, but must copy the values in reverse order.
|
||||
Value *stackFrameLocalsStart = (Value *) (stackFrame + sizeof(StackFrame));
|
||||
for (size_t i = 0; i < numLocalsAndStackVals; i++)
|
||||
stackFrameLocalsStart[i] = *(frame->valueSlot(i));
|
||||
memcpy(frameStart, (uint8_t *)frame - numLocalsAndStackVals * sizeof(Value), frameSpace);
|
||||
|
||||
IonSpew(IonSpew_BaselineOSR, "Allocated IonOsrTempData at %p", (void *) info);
|
||||
IonSpew(IonSpew_BaselineOSR, "Jitcode is %p", info->jitcode);
|
||||
|
@ -1041,7 +1004,7 @@ ICUseCount_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
|
||||
// Jump into Ion.
|
||||
masm.loadPtr(Address(osrDataReg, offsetof(IonOsrTempData, jitcode)), scratchReg);
|
||||
masm.loadPtr(Address(osrDataReg, offsetof(IonOsrTempData, stackFrame)), OsrFrameReg);
|
||||
masm.loadPtr(Address(osrDataReg, offsetof(IonOsrTempData, baselineFrame)), OsrFrameReg);
|
||||
masm.jump(scratchReg);
|
||||
|
||||
// No jitcode available, do nothing.
|
||||
|
|
|
@ -1041,7 +1041,7 @@ CodeGenerator::visitOsrScopeChain(LOsrScopeChain *lir)
|
|||
const LAllocation *frame = lir->getOperand(0);
|
||||
const LDefinition *object = lir->getDef(0);
|
||||
|
||||
const ptrdiff_t frameOffset = StackFrame::offsetOfScopeChain();
|
||||
const ptrdiff_t frameOffset = BaselineFrame::reverseOffsetOfScopeChain();
|
||||
|
||||
masm.loadPtr(Address(ToRegister(frame), frameOffset), ToRegister(object));
|
||||
return true;
|
||||
|
@ -1053,7 +1053,7 @@ CodeGenerator::visitOsrArgumentsObject(LOsrArgumentsObject *lir)
|
|||
const LAllocation *frame = lir->getOperand(0);
|
||||
const LDefinition *object = lir->getDef(0);
|
||||
|
||||
const ptrdiff_t frameOffset = StackFrame::offsetOfArgumentsObject();
|
||||
const ptrdiff_t frameOffset = BaselineFrame::reverseOffsetOfArgsObj();
|
||||
|
||||
masm.loadPtr(Address(ToRegister(frame), frameOffset), ToRegister(object));
|
||||
return true;
|
||||
|
@ -1077,13 +1077,13 @@ CodeGenerator::visitOsrReturnValue(LOsrReturnValue *lir)
|
|||
const LAllocation *frame = lir->getOperand(0);
|
||||
const ValueOperand out = ToOutValue(lir);
|
||||
|
||||
Address flags = Address(ToRegister(frame), StackFrame::offsetOfFlags());
|
||||
Address retval = Address(ToRegister(frame), StackFrame::offsetOfReturnValue());
|
||||
Address flags = Address(ToRegister(frame), BaselineFrame::reverseOffsetOfFlags());
|
||||
Address retval = Address(ToRegister(frame), BaselineFrame::reverseOffsetOfReturnValue());
|
||||
|
||||
masm.moveValue(UndefinedValue(), out);
|
||||
|
||||
Label done;
|
||||
masm.branchTest32(Assembler::Zero, flags, Imm32(StackFrame::HAS_RVAL), &done);
|
||||
masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL), &done);
|
||||
masm.loadValue(retval, out);
|
||||
masm.bind(&done);
|
||||
|
||||
|
|
|
@ -5713,12 +5713,9 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
|||
|
||||
if (info().fun()) {
|
||||
// Initialize |this| parameter.
|
||||
uint32_t slot = info().thisSlot();
|
||||
ptrdiff_t offset = StackFrame::offsetOfThis(info().fun());
|
||||
|
||||
MOsrValue *thisv = MOsrValue::New(entry, offset);
|
||||
MParameter *thisv = MParameter::New(MParameter::THIS_SLOT, nullptr);
|
||||
osrBlock->add(thisv);
|
||||
osrBlock->initSlot(slot, thisv);
|
||||
osrBlock->initSlot(info().thisSlot(), thisv);
|
||||
|
||||
// Initialize arguments.
|
||||
for (uint32_t i = 0; i < info().nargs(); i++) {
|
||||
|
@ -5741,10 +5738,9 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
|||
osrBlock->add(osrv);
|
||||
osrBlock->initSlot(slot, osrv);
|
||||
} else {
|
||||
ptrdiff_t offset = StackFrame::offsetOfFormalArg(info().fun(), i);
|
||||
MOsrValue *osrv = MOsrValue::New(entry, offset);
|
||||
osrBlock->add(osrv);
|
||||
osrBlock->initSlot(slot, osrv);
|
||||
MParameter *arg = MParameter::New(i, nullptr);
|
||||
osrBlock->add(arg);
|
||||
osrBlock->initSlot(slot, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5752,7 +5748,7 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
|||
// Initialize locals.
|
||||
for (uint32_t i = 0; i < info().nlocals(); i++) {
|
||||
uint32_t slot = info().localSlot(i);
|
||||
ptrdiff_t offset = StackFrame::offsetOfFixed(i);
|
||||
ptrdiff_t offset = BaselineFrame::reverseOffsetOfLocal(i);
|
||||
|
||||
MOsrValue *osrv = MOsrValue::New(entry, offset);
|
||||
osrBlock->add(osrv);
|
||||
|
@ -5763,7 +5759,7 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
|||
uint32_t numStackSlots = preheader->stackDepth() - info().firstStackSlot();
|
||||
for (uint32_t i = 0; i < numStackSlots; i++) {
|
||||
uint32_t slot = info().stackSlot(i);
|
||||
ptrdiff_t offset = StackFrame::offsetOfFixed(info().nlocals() + i);
|
||||
ptrdiff_t offset = BaselineFrame::reverseOffsetOfLocal(info().nlocals() + i);
|
||||
|
||||
MOsrValue *osrv = MOsrValue::New(entry, offset);
|
||||
osrBlock->add(osrv);
|
||||
|
|
|
@ -867,82 +867,6 @@ MacroAssembler::checkInterruptFlagsPar(const Register &tempReg,
|
|||
branchTest32(Assembler::NonZero, tempReg, tempReg, fail);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::maybeRemoveOsrFrame(Register scratch)
|
||||
{
|
||||
// Before we link an exit frame, check for an OSR frame, which is
|
||||
// indicative of working inside an existing bailout. In this case, remove
|
||||
// the OSR frame, so we don't explode the stack with repeated bailouts.
|
||||
Label osrRemoved;
|
||||
loadPtr(Address(StackPointer, IonCommonFrameLayout::offsetOfDescriptor()), scratch);
|
||||
and32(Imm32(FRAMETYPE_MASK), scratch);
|
||||
branch32(Assembler::NotEqual, scratch, Imm32(IonFrame_Osr), &osrRemoved);
|
||||
addPtr(Imm32(sizeof(IonOsrFrameLayout)), StackPointer);
|
||||
bind(&osrRemoved);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::performOsr()
|
||||
{
|
||||
GeneralRegisterSet regs = GeneralRegisterSet::All();
|
||||
if (FramePointer != InvalidReg && sps_ && sps_->enabled())
|
||||
regs.take(FramePointer);
|
||||
|
||||
// This register must be fixed as it's used in the Osr prologue.
|
||||
regs.take(OsrFrameReg);
|
||||
|
||||
// Remove any existing OSR frame so we don't create one per bailout.
|
||||
maybeRemoveOsrFrame(regs.getAny());
|
||||
|
||||
const Register script = regs.takeAny();
|
||||
const Register calleeToken = regs.takeAny();
|
||||
|
||||
// Grab fp.exec
|
||||
loadPtr(Address(OsrFrameReg, StackFrame::offsetOfExec()), script);
|
||||
mov(script, calleeToken);
|
||||
|
||||
Label isFunction, performOsr;
|
||||
branchTest32(Assembler::NonZero,
|
||||
Address(OsrFrameReg, StackFrame::offsetOfFlags()),
|
||||
Imm32(StackFrame::FUNCTION),
|
||||
&isFunction);
|
||||
|
||||
{
|
||||
// Not a function - just tag the calleeToken now.
|
||||
orPtr(Imm32(CalleeToken_Script), calleeToken);
|
||||
jump(&performOsr);
|
||||
}
|
||||
|
||||
bind(&isFunction);
|
||||
{
|
||||
// Function - create the callee token, then get the script.
|
||||
|
||||
// Skip the or-ing of CalleeToken_Function into calleeToken since it is zero.
|
||||
JS_ASSERT(CalleeToken_Function == 0);
|
||||
|
||||
loadPtr(Address(script, JSFunction::offsetOfNativeOrScript()), script);
|
||||
}
|
||||
|
||||
bind(&performOsr);
|
||||
|
||||
const Register ionScript = regs.takeAny();
|
||||
const Register osrEntry = regs.takeAny();
|
||||
|
||||
loadPtr(Address(script, JSScript::offsetOfIonScript()), ionScript);
|
||||
load32(Address(ionScript, IonScript::offsetOfOsrEntryOffset()), osrEntry);
|
||||
|
||||
// Get ionScript->method->code, and scoot to the osrEntry.
|
||||
const Register code = ionScript;
|
||||
loadPtr(Address(ionScript, IonScript::offsetOfMethod()), code);
|
||||
loadPtr(Address(code, IonCode::offsetOfCode()), code);
|
||||
addPtr(osrEntry, code);
|
||||
|
||||
// To simplify stack handling, we create an intermediate OSR frame, that
|
||||
// looks like a JS frame with no argv.
|
||||
enterOsr(calleeToken, code);
|
||||
ret();
|
||||
}
|
||||
|
||||
static void
|
||||
ReportOverRecursed(JSContext *cx)
|
||||
{
|
||||
|
|
|
@ -864,13 +864,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
}
|
||||
|
||||
// Given a js::StackFrame in OsrFrameReg, performs inline on-stack
|
||||
// replacement. The stack frame must be at a valid OSR entry-point.
|
||||
void performOsr();
|
||||
|
||||
// Checks if an OSR frame is the previous frame, and if so, removes it.
|
||||
void maybeRemoveOsrFrame(Register scratch);
|
||||
|
||||
// Generates code used to complete a bailout.
|
||||
void generateBailoutTail(Register scratch, Register bailoutInfo);
|
||||
|
||||
|
|
|
@ -461,7 +461,9 @@ MBasicBlock::linkOsrValues(MStart *start)
|
|||
if (def->isOsrArgumentsObject())
|
||||
def->toOsrArgumentsObject()->setResumePoint(res);
|
||||
} else {
|
||||
JS_ASSERT(def->isOsrValue() || def->isGetArgumentsObjectArg() || def->isConstant());
|
||||
JS_ASSERT(def->isOsrValue() || def->isGetArgumentsObjectArg() || def->isConstant() ||
|
||||
def->isParameter());
|
||||
|
||||
// A constant Undefined can show up here for an argument slot when the function uses
|
||||
// a heavyweight argsobj, but the argument in question is stored on the scope chain.
|
||||
JS_ASSERT_IF(def->isConstant(), def->toConstant()->value() == UndefinedValue());
|
||||
|
@ -470,6 +472,8 @@ MBasicBlock::linkOsrValues(MStart *start)
|
|||
def->toOsrValue()->setResumePoint(res);
|
||||
else if (def->isGetArgumentsObjectArg())
|
||||
def->toGetArgumentsObjectArg()->setResumePoint(res);
|
||||
else if (def->isParameter())
|
||||
def->toParameter()->setResumePoint(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -928,46 +928,6 @@ class StackFrame
|
|||
flags_ &= ~SUSPENDED;
|
||||
}
|
||||
|
||||
public:
|
||||
static size_t offsetOfFlags() {
|
||||
return offsetof(StackFrame, flags_);
|
||||
}
|
||||
|
||||
static size_t offsetOfExec() {
|
||||
return offsetof(StackFrame, exec);
|
||||
}
|
||||
|
||||
static size_t offsetOfNumActual() {
|
||||
return offsetof(StackFrame, u.nactual);
|
||||
}
|
||||
|
||||
static size_t offsetOfScopeChain() {
|
||||
return offsetof(StackFrame, scopeChain_);
|
||||
}
|
||||
|
||||
static size_t offsetOfReturnValue() {
|
||||
return offsetof(StackFrame, rval_);
|
||||
}
|
||||
|
||||
static size_t offsetOfArgumentsObject() {
|
||||
return offsetof(StackFrame, argsObj_);
|
||||
}
|
||||
|
||||
static ptrdiff_t offsetOfThis(JSFunction *fun) {
|
||||
return fun == nullptr
|
||||
? -1 * ptrdiff_t(sizeof(Value))
|
||||
: -(fun->nargs + 1) * ptrdiff_t(sizeof(Value));
|
||||
}
|
||||
|
||||
static ptrdiff_t offsetOfFormalArg(JSFunction *fun, unsigned i) {
|
||||
JS_ASSERT(i < fun->nargs);
|
||||
return (-(int)fun->nargs + i) * sizeof(Value);
|
||||
}
|
||||
|
||||
static size_t offsetOfFixed(unsigned i) {
|
||||
return sizeof(StackFrame) + i * sizeof(Value);
|
||||
}
|
||||
|
||||
public:
|
||||
void mark(JSTracer *trc);
|
||||
void markValues(JSTracer *trc, Value *sp);
|
||||
|
|
Загрузка…
Ссылка в новой задаче