Bug 998490 - OdinMonkey: simplify stack-overflow exit stub (r=sunfish)

--HG--
extra : rebase_source : a9fdec79fcf136ef296173f08ae8908ee46019f9
This commit is contained in:
Luke Wagner 2014-04-16 15:57:00 -05:00
parent b7df0d287a
commit 0e10a5f610
18 changed files with 104 additions and 113 deletions

View File

@ -2029,8 +2029,6 @@ class FunctionCompiler
if (!newBlock(/* pred = */ nullptr, &curBlock_, fn_))
return false;
curBlock_->add(MAsmJSCheckOverRecursed::New(alloc(), &m_.stackOverflowLabel()));
for (ABIArgTypeIter i = argTypes; !i.done(); i++) {
MAsmJSParameter *ins = MAsmJSParameter::New(alloc(), *i, i.mirType());
curBlock_->add(ins);
@ -5470,8 +5468,8 @@ GenerateCode(ModuleCompiler &m, ModuleCompiler::Func &func, MIRGenerator &mir, L
m.masm().bind(func.code());
ScopedJSDeletePtr<CodeGenerator> codegen(jit::GenerateCode(&mir, &lir, &m.masm()));
if (!codegen)
ScopedJSDeletePtr<CodeGenerator> codegen(js_new<CodeGenerator>(&mir, &lir, &m.masm()));
if (!codegen || !codegen->generateAsmJS(&m.stackOverflowLabel()))
return m.fail(nullptr, "internal codegen failure (probably out of memory)");
if (!m.collectAccesses(mir))
@ -6739,30 +6737,37 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
masm.align(CodeAlignment);
masm.bind(&m.stackOverflowLabel());
#if defined(JS_CODEGEN_X86)
// Ensure that at least one slot is pushed for passing 'cx' below.
masm.push(Imm32(0));
#endif
// The overflow check always occurs before the initial function-specific
// stack-size adjustment. See CodeGenerator::generateAsmJSPrologue.
masm.setFramePushed(AlignmentMidPrologue - AlignmentAtPrologue);
// We know that StackPointer is word-aligned, but nothing past that. Thus,
// we must align StackPointer dynamically. Don't worry about restoring
// StackPointer since throwLabel will clobber StackPointer immediately.
masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer);
if (ShadowStackSpace)
masm.subPtr(Imm32(ShadowStackSpace), StackPointer);
MIRTypeVector argTypes(m.cx());
argTypes.infallibleAppend(MIRType_Pointer); // cx
// Prepare the arguments for the call to js_ReportOverRecursed.
#if defined(JS_CODEGEN_X86)
LoadAsmJSActivationIntoRegister(masm, eax);
LoadJSContextFromActivation(masm, eax, eax);
masm.storePtr(eax, Address(StackPointer, 0));
#else
LoadAsmJSActivationIntoRegister(masm, IntArgReg0);
LoadJSContextFromActivation(masm, IntArgReg0, IntArgReg0);
#endif
unsigned stackDec = StackDecrementForCall(masm, argTypes);
masm.reserveStack(stackDec);
ABIArgMIRTypeIter i(argTypes);
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
LoadAsmJSActivationIntoRegister(masm, scratch);
// argument 0: cx
if (i->kind() == ABIArg::GPR) {
LoadJSContextFromActivation(masm, scratch, i->gpr());
} else {
LoadJSContextFromActivation(masm, scratch, scratch);
masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
}
i++;
JS_ASSERT(i.done());
AssertStackAlignment(masm);
masm.call(AsmJSImm_ReportOverRecursed);
masm.jump(throwLabel);
// Don't worry about restoring the stack; throwLabel will pop everything.
masm.jump(throwLabel);
return !masm.oom();
}

View File

@ -2748,17 +2748,6 @@ class CheckOverRecursedFailure : public OutOfLineCodeBase<CodeGenerator>
}
};
bool
CodeGenerator::omitOverRecursedCheck() const
{
// If the current function makes no calls (which means it isn't recursive)
// and it uses only a small amount of stack space, it doesn't need a
// stack overflow check. Note that the actual number here is somewhat
// arbitrary, and codegen actually uses small bounded amounts of
// additional stack space in some cases too.
return frameSize() < 64 && !gen->performsCall();
}
bool
CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed *lir)
{
@ -6202,7 +6191,7 @@ CodeGenerator::visitRestPar(LRestPar *lir)
}
bool
CodeGenerator::generateAsmJS()
CodeGenerator::generateAsmJS(Label *stackOverflowLabel)
{
IonSpew(IonSpew_Codegen, "# Emitting asm.js code");
@ -6215,7 +6204,7 @@ CodeGenerator::generateAsmJS()
// parameters have been useFixed()ed to these ABI-specified positions.
// Thus, there is nothing special to do in the prologue except (possibly)
// bump the stack.
if (!generatePrologue())
if (!generateAsmJSPrologue(stackOverflowLabel))
return false;
if (!generateBody())
return false;
@ -8297,20 +8286,6 @@ CodeGenerator::visitAsmJSVoidReturn(LAsmJSVoidReturn *lir)
return true;
}
bool
CodeGenerator::visitAsmJSCheckOverRecursed(LAsmJSCheckOverRecursed *lir)
{
// If we don't push anything on the stack, skip the check.
if (omitOverRecursedCheck())
return true;
masm.branchPtr(Assembler::AboveOrEqual,
AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
StackPointer,
lir->mir()->onError());
return true;
}
bool
CodeGenerator::emitAssertRangeI(const Range *r, Register input)
{

View File

@ -53,7 +53,7 @@ class CodeGenerator : public CodeGeneratorSpecific
public:
bool generate();
bool generateAsmJS();
bool generateAsmJS(Label *stackOverflowLabel);
bool link(JSContext *cx, types::CompilerConstraintList *constraints);
bool visitLabel(LLabel *lir);
@ -294,7 +294,6 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCheckOverRecursed(LCheckOverRecursed *lir);
bool visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool);
bool visitAsmJSCheckOverRecursed(LAsmJSCheckOverRecursed *lir);
bool visitCheckOverRecursedPar(LCheckOverRecursedPar *lir);
bool visitCheckOverRecursedFailurePar(CheckOverRecursedFailurePar *ool);
@ -447,8 +446,6 @@ class CodeGenerator : public CodeGeneratorSpecific
bool emitAssertRangeI(const Range *r, Register input);
bool emitAssertRangeD(const Range *r, FloatRegister input, FloatRegister temp);
bool omitOverRecursedCheck() const;
Vector<CodeOffsetLabel, 0, IonAllocPolicy> ionScriptLabels_;
#ifdef DEBUG
bool branchIfInvalidated(Register temp, Label *invalidated);

View File

@ -1628,29 +1628,22 @@ GenerateLIR(MIRGenerator *mir)
}
CodeGenerator *
GenerateCode(MIRGenerator *mir, LIRGraph *lir, MacroAssembler *maybeMasm)
GenerateCode(MIRGenerator *mir, LIRGraph *lir)
{
CodeGenerator *codegen = js_new<CodeGenerator>(mir, lir, maybeMasm);
CodeGenerator *codegen = js_new<CodeGenerator>(mir, lir);
if (!codegen)
return nullptr;
if (mir->compilingAsmJS()) {
if (!codegen->generateAsmJS()) {
js_delete(codegen);
return nullptr;
}
} else {
if (!codegen->generate()) {
js_delete(codegen);
return nullptr;
}
if (!codegen->generate()) {
js_delete(codegen);
return nullptr;
}
return codegen;
}
CodeGenerator *
CompileBackEnd(MIRGenerator *mir, MacroAssembler *maybeMasm)
CompileBackEnd(MIRGenerator *mir)
{
if (!OptimizeMIR(mir))
return nullptr;
@ -1659,7 +1652,7 @@ CompileBackEnd(MIRGenerator *mir, MacroAssembler *maybeMasm)
if (!lir)
return nullptr;
return GenerateCode(mir, lir, maybeMasm);
return GenerateCode(mir, lir);
}
void

View File

@ -149,8 +149,8 @@ class CodeGenerator;
bool OptimizeMIR(MIRGenerator *mir);
LIRGraph *GenerateLIR(MIRGenerator *mir);
CodeGenerator *GenerateCode(MIRGenerator *mir, LIRGraph *lir, MacroAssembler *maybeMasm = nullptr);
CodeGenerator *CompileBackEnd(MIRGenerator *mir, MacroAssembler *maybeMasm = nullptr);
CodeGenerator *GenerateCode(MIRGenerator *mir, LIRGraph *lir);
CodeGenerator *CompileBackEnd(MIRGenerator *mir);
void AttachFinishedCompilations(JSContext *cx);
void FinishOffThreadBuilder(IonBuilder *builder);

View File

@ -5995,16 +5995,6 @@ class LAsmJSCall MOZ_FINAL : public LInstruction
}
};
class LAsmJSCheckOverRecursed : public LInstructionHelper<0, 0, 0>
{
public:
LIR_HEADER(AsmJSCheckOverRecursed)
MAsmJSCheckOverRecursed *mir() const {
return mir_->toAsmJSCheckOverRecursed();
}
};
class LAssertRangeI : public LInstructionHelper<0, 1, 0>
{
public:

View File

@ -292,7 +292,6 @@
_(AsmJSVoidReturn) \
_(AsmJSPassStackArg) \
_(AsmJSCall) \
_(AsmJSCheckOverRecursed) \
_(InterruptCheckPar) \
_(RecompileCheck) \
_(AssertRangeI) \

View File

@ -3502,12 +3502,6 @@ LIRGenerator::visitAsmJSCall(MAsmJSCall *ins)
return defineReturn(lir, ins);
}
bool
LIRGenerator::visitAsmJSCheckOverRecursed(MAsmJSCheckOverRecursed *ins)
{
return add(new(alloc()) LAsmJSCheckOverRecursed(), ins);
}
bool
LIRGenerator::visitSetDOMProperty(MSetDOMProperty *ins)
{

View File

@ -254,7 +254,6 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitAsmJSVoidReturn(MAsmJSVoidReturn *ins);
bool visitAsmJSPassStackArg(MAsmJSPassStackArg *ins);
bool visitAsmJSCall(MAsmJSCall *ins);
bool visitAsmJSCheckOverRecursed(MAsmJSCheckOverRecursed *ins);
bool visitSetDOMProperty(MSetDOMProperty *ins);
bool visitGetDOMProperty(MGetDOMProperty *ins);
bool visitGetDOMMember(MGetDOMMember *ins);

View File

@ -10040,20 +10040,6 @@ class MAsmJSCall MOZ_FINAL : public MInstruction
}
};
// The asm.js version doesn't use the bail mechanism: instead it throws and
// exception by jumping to the given label.
class MAsmJSCheckOverRecursed : public MNullaryInstruction
{
Label *onError_;
MAsmJSCheckOverRecursed(Label *onError) : onError_(onError) {}
public:
INSTRUCTION_HEADER(AsmJSCheckOverRecursed);
static MAsmJSCheckOverRecursed *New(TempAllocator &alloc, Label *onError) {
return new(alloc) MAsmJSCheckOverRecursed(onError);
}
Label *onError() const { return onError_; }
};
#undef INSTRUCTION_HEADER
// Implement opcode casts now that the compiler can see the inheritance.

View File

@ -210,7 +210,6 @@ namespace jit {
_(AsmJSVoidReturn) \
_(AsmJSPassStackArg) \
_(AsmJSCall) \
_(AsmJSCheckOverRecursed) \
_(CheckOverRecursedPar) \
_(NewCallObjectPar) \
_(NewPar) \

View File

@ -321,7 +321,6 @@ class ParallelSafetyVisitor : public MInstructionVisitor
UNSAFE_OP(AsmJSPassStackArg)
UNSAFE_OP(AsmJSParameter)
UNSAFE_OP(AsmJSCall)
UNSAFE_OP(AsmJSCheckOverRecursed)
DROP_OP(RecompileCheck)
// It looks like this could easily be made safe:

View File

@ -40,16 +40,34 @@ CodeGeneratorARM::CodeGeneratorARM(MIRGenerator *gen, LIRGraph *graph, MacroAsse
bool
CodeGeneratorARM::generatePrologue()
{
if (gen->compilingAsmJS()) {
masm.Push(lr);
// Note that this automatically sets MacroAssembler::framePushed().
masm.reserveStack(frameDepth_);
} else {
// Note that this automatically sets MacroAssembler::framePushed().
masm.reserveStack(frameSize());
masm.checkStackAlignment();
JS_ASSERT(!gen->compilingAsmJS());
// Note that this automatically sets MacroAssembler::framePushed().
masm.reserveStack(frameSize());
masm.checkStackAlignment();
return true;
}
bool
CodeGeneratorARM::generateAsmJSPrologue(Label *stackOverflowLabel)
{
JS_ASSERT(gen->compilingAsmJS());
masm.Push(lr);
// The asm.js over-recursed handler wants to be able to assume that SP
// points to the return address, so perform the check after pushing lr but
// before pushing frameDepth.
if (!omitOverRecursedCheck()) {
masm.branchPtr(Assembler::AboveOrEqual,
AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
StackPointer,
stackOverflowLabel);
}
// Note that this automatically sets MacroAssembler::framePushed().
masm.reserveStack(frameDepth_);
masm.checkStackAlignment();
return true;
}

View File

@ -71,6 +71,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
protected:
bool generatePrologue();
bool generateAsmJSPrologue(Label *stackOverflowLabel);
bool generateEpilogue();
bool generateOutOfLineCode();

View File

@ -776,6 +776,17 @@ CodeGeneratorShared::visitOutOfLineTruncateSlow(OutOfLineTruncateSlow *ool)
return true;
}
bool
CodeGeneratorShared::omitOverRecursedCheck() const
{
// If the current function makes no calls (which means it isn't recursive)
// and it uses only a small amount of stack space, it doesn't need a
// stack overflow check. Note that the actual number here is somewhat
// arbitrary, and codegen actually uses small bounded amounts of
// additional stack space in some cases too.
return frameSize() < 64 && !gen->performsCall();
}
void
CodeGeneratorShared::emitPreBarrier(Register base, const LAllocation *index, MIRType type)
{

View File

@ -435,6 +435,8 @@ class CodeGeneratorShared : public LInstructionVisitor
bool visitOutOfLineTruncateSlow(OutOfLineTruncateSlow *ool);
bool omitOverRecursedCheck() const;
public:
bool callTraceLIR(uint32_t blockIndex, LInstruction *lir, const char *bailoutName = nullptr);

View File

@ -39,12 +39,34 @@ CodeGeneratorX86Shared::CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph *grap
bool
CodeGeneratorX86Shared::generatePrologue()
{
JS_ASSERT(!gen->compilingAsmJS());
// Note that this automatically sets MacroAssembler::framePushed().
masm.reserveStack(frameSize());
return true;
}
bool
CodeGeneratorX86Shared::generateAsmJSPrologue(Label *stackOverflowLabel)
{
JS_ASSERT(gen->compilingAsmJS());
// The asm.js over-recursed handler wants to be able to assume that SP
// points to the return address, so perform the check before pushing
// frameDepth.
if (!omitOverRecursedCheck()) {
masm.branchPtr(Assembler::AboveOrEqual,
AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
StackPointer,
stackOverflowLabel);
}
// Note that this automatically sets MacroAssembler::framePushed().
masm.reserveStack(frameSize());
return true;
}
bool
CodeGeneratorX86Shared::generateEpilogue()
{

View File

@ -78,6 +78,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
protected:
bool generatePrologue();
bool generateAsmJSPrologue(Label *stackOverflowLabe);
bool generateEpilogue();
bool generateOutOfLineCode();