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_)) if (!newBlock(/* pred = */ nullptr, &curBlock_, fn_))
return false; return false;
curBlock_->add(MAsmJSCheckOverRecursed::New(alloc(), &m_.stackOverflowLabel()));
for (ABIArgTypeIter i = argTypes; !i.done(); i++) { for (ABIArgTypeIter i = argTypes; !i.done(); i++) {
MAsmJSParameter *ins = MAsmJSParameter::New(alloc(), *i, i.mirType()); MAsmJSParameter *ins = MAsmJSParameter::New(alloc(), *i, i.mirType());
curBlock_->add(ins); curBlock_->add(ins);
@ -5470,8 +5468,8 @@ GenerateCode(ModuleCompiler &m, ModuleCompiler::Func &func, MIRGenerator &mir, L
m.masm().bind(func.code()); m.masm().bind(func.code());
ScopedJSDeletePtr<CodeGenerator> codegen(jit::GenerateCode(&mir, &lir, &m.masm())); ScopedJSDeletePtr<CodeGenerator> codegen(js_new<CodeGenerator>(&mir, &lir, &m.masm()));
if (!codegen) if (!codegen || !codegen->generateAsmJS(&m.stackOverflowLabel()))
return m.fail(nullptr, "internal codegen failure (probably out of memory)"); return m.fail(nullptr, "internal codegen failure (probably out of memory)");
if (!m.collectAccesses(mir)) if (!m.collectAccesses(mir))
@ -6739,30 +6737,37 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
masm.align(CodeAlignment); masm.align(CodeAlignment);
masm.bind(&m.stackOverflowLabel()); masm.bind(&m.stackOverflowLabel());
#if defined(JS_CODEGEN_X86) // The overflow check always occurs before the initial function-specific
// Ensure that at least one slot is pushed for passing 'cx' below. // stack-size adjustment. See CodeGenerator::generateAsmJSPrologue.
masm.push(Imm32(0)); masm.setFramePushed(AlignmentMidPrologue - AlignmentAtPrologue);
#endif
// We know that StackPointer is word-aligned, but nothing past that. Thus, MIRTypeVector argTypes(m.cx());
// we must align StackPointer dynamically. Don't worry about restoring argTypes.infallibleAppend(MIRType_Pointer); // cx
// StackPointer since throwLabel will clobber StackPointer immediately.
masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer);
if (ShadowStackSpace)
masm.subPtr(Imm32(ShadowStackSpace), StackPointer);
// Prepare the arguments for the call to js_ReportOverRecursed. unsigned stackDec = StackDecrementForCall(masm, argTypes);
#if defined(JS_CODEGEN_X86) masm.reserveStack(stackDec);
LoadAsmJSActivationIntoRegister(masm, eax);
LoadJSContextFromActivation(masm, eax, eax); ABIArgMIRTypeIter i(argTypes);
masm.storePtr(eax, Address(StackPointer, 0));
#else Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
LoadAsmJSActivationIntoRegister(masm, IntArgReg0); LoadAsmJSActivationIntoRegister(masm, scratch);
LoadJSContextFromActivation(masm, IntArgReg0, IntArgReg0);
#endif // 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.call(AsmJSImm_ReportOverRecursed);
masm.jump(throwLabel);
// Don't worry about restoring the stack; throwLabel will pop everything.
masm.jump(throwLabel);
return !masm.oom(); 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 bool
CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed *lir) CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed *lir)
{ {
@ -6202,7 +6191,7 @@ CodeGenerator::visitRestPar(LRestPar *lir)
} }
bool bool
CodeGenerator::generateAsmJS() CodeGenerator::generateAsmJS(Label *stackOverflowLabel)
{ {
IonSpew(IonSpew_Codegen, "# Emitting asm.js code"); IonSpew(IonSpew_Codegen, "# Emitting asm.js code");
@ -6215,7 +6204,7 @@ CodeGenerator::generateAsmJS()
// parameters have been useFixed()ed to these ABI-specified positions. // parameters have been useFixed()ed to these ABI-specified positions.
// Thus, there is nothing special to do in the prologue except (possibly) // Thus, there is nothing special to do in the prologue except (possibly)
// bump the stack. // bump the stack.
if (!generatePrologue()) if (!generateAsmJSPrologue(stackOverflowLabel))
return false; return false;
if (!generateBody()) if (!generateBody())
return false; return false;
@ -8297,20 +8286,6 @@ CodeGenerator::visitAsmJSVoidReturn(LAsmJSVoidReturn *lir)
return true; 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 bool
CodeGenerator::emitAssertRangeI(const Range *r, Register input) CodeGenerator::emitAssertRangeI(const Range *r, Register input)
{ {

View File

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

View File

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

View File

@ -149,8 +149,8 @@ class CodeGenerator;
bool OptimizeMIR(MIRGenerator *mir); bool OptimizeMIR(MIRGenerator *mir);
LIRGraph *GenerateLIR(MIRGenerator *mir); LIRGraph *GenerateLIR(MIRGenerator *mir);
CodeGenerator *GenerateCode(MIRGenerator *mir, LIRGraph *lir, MacroAssembler *maybeMasm = nullptr); CodeGenerator *GenerateCode(MIRGenerator *mir, LIRGraph *lir);
CodeGenerator *CompileBackEnd(MIRGenerator *mir, MacroAssembler *maybeMasm = nullptr); CodeGenerator *CompileBackEnd(MIRGenerator *mir);
void AttachFinishedCompilations(JSContext *cx); void AttachFinishedCompilations(JSContext *cx);
void FinishOffThreadBuilder(IonBuilder *builder); 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> class LAssertRangeI : public LInstructionHelper<0, 1, 0>
{ {
public: public:

View File

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

View File

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

View File

@ -254,7 +254,6 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitAsmJSVoidReturn(MAsmJSVoidReturn *ins); bool visitAsmJSVoidReturn(MAsmJSVoidReturn *ins);
bool visitAsmJSPassStackArg(MAsmJSPassStackArg *ins); bool visitAsmJSPassStackArg(MAsmJSPassStackArg *ins);
bool visitAsmJSCall(MAsmJSCall *ins); bool visitAsmJSCall(MAsmJSCall *ins);
bool visitAsmJSCheckOverRecursed(MAsmJSCheckOverRecursed *ins);
bool visitSetDOMProperty(MSetDOMProperty *ins); bool visitSetDOMProperty(MSetDOMProperty *ins);
bool visitGetDOMProperty(MGetDOMProperty *ins); bool visitGetDOMProperty(MGetDOMProperty *ins);
bool visitGetDOMMember(MGetDOMMember *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 #undef INSTRUCTION_HEADER
// Implement opcode casts now that the compiler can see the inheritance. // Implement opcode casts now that the compiler can see the inheritance.

View File

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

View File

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

View File

@ -40,16 +40,34 @@ CodeGeneratorARM::CodeGeneratorARM(MIRGenerator *gen, LIRGraph *graph, MacroAsse
bool bool
CodeGeneratorARM::generatePrologue() CodeGeneratorARM::generatePrologue()
{ {
if (gen->compilingAsmJS()) { JS_ASSERT(!gen->compilingAsmJS());
masm.Push(lr);
// Note that this automatically sets MacroAssembler::framePushed(). // Note that this automatically sets MacroAssembler::framePushed().
masm.reserveStack(frameDepth_); masm.reserveStack(frameSize());
} else { masm.checkStackAlignment();
// Note that this automatically sets MacroAssembler::framePushed(). return true;
masm.reserveStack(frameSize()); }
masm.checkStackAlignment();
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; return true;
} }

View File

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

View File

@ -776,6 +776,17 @@ CodeGeneratorShared::visitOutOfLineTruncateSlow(OutOfLineTruncateSlow *ool)
return true; 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 void
CodeGeneratorShared::emitPreBarrier(Register base, const LAllocation *index, MIRType type) CodeGeneratorShared::emitPreBarrier(Register base, const LAllocation *index, MIRType type)
{ {

View File

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

View File

@ -39,12 +39,34 @@ CodeGeneratorX86Shared::CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph *grap
bool bool
CodeGeneratorX86Shared::generatePrologue() CodeGeneratorX86Shared::generatePrologue()
{ {
JS_ASSERT(!gen->compilingAsmJS());
// Note that this automatically sets MacroAssembler::framePushed(). // Note that this automatically sets MacroAssembler::framePushed().
masm.reserveStack(frameSize()); masm.reserveStack(frameSize());
return true; 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 bool
CodeGeneratorX86Shared::generateEpilogue() CodeGeneratorX86Shared::generateEpilogue()
{ {

View File

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