Bug 907187 - Rewrite Baseline -> Ion OSR to not use the StackFrame layout. r=djvj

This commit is contained in:
Jan de Mooij 2013-10-24 16:33:26 +02:00
Родитель 150ebd9bb0
Коммит 0d5ad78783
7 изменённых файлов: 38 добавлений и 198 удалений

Просмотреть файл

@ -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);