diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index d419d42d5a7..eee6694ee7b 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -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 codegen(jit::GenerateCode(&mir, &lir, &m.masm())); - if (!codegen) + ScopedJSDeletePtr codegen(js_new(&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(); } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 95f28ab966f..068068b3bcc 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -2748,17 +2748,6 @@ class CheckOverRecursedFailure : public OutOfLineCodeBase } }; -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) { diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index f9aafceca1e..8baea176edb 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -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 ionScriptLabels_; #ifdef DEBUG bool branchIfInvalidated(Register temp, Label *invalidated); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 540831946b9..a163ff268c3 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1628,29 +1628,22 @@ GenerateLIR(MIRGenerator *mir) } CodeGenerator * -GenerateCode(MIRGenerator *mir, LIRGraph *lir, MacroAssembler *maybeMasm) +GenerateCode(MIRGenerator *mir, LIRGraph *lir) { - CodeGenerator *codegen = js_new(mir, lir, maybeMasm); + CodeGenerator *codegen = js_new(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 diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 16554eef328..865ca9fb065 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -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); diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h index 54b705f1299..c90aef94acd 100644 --- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -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: diff --git a/js/src/jit/LOpcodes.h b/js/src/jit/LOpcodes.h index 9e44dd99a96..a32d64f2662 100644 --- a/js/src/jit/LOpcodes.h +++ b/js/src/jit/LOpcodes.h @@ -292,7 +292,6 @@ _(AsmJSVoidReturn) \ _(AsmJSPassStackArg) \ _(AsmJSCall) \ - _(AsmJSCheckOverRecursed) \ _(InterruptCheckPar) \ _(RecompileCheck) \ _(AssertRangeI) \ diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 65230774111..d5f8227f003 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -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) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index e5f858387c6..1e9b6c2fccf 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -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); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index be76db15597..6658c886f71 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -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. diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index 3ec7f176e60..5e15e20dbf2 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -210,7 +210,6 @@ namespace jit { _(AsmJSVoidReturn) \ _(AsmJSPassStackArg) \ _(AsmJSCall) \ - _(AsmJSCheckOverRecursed) \ _(CheckOverRecursedPar) \ _(NewCallObjectPar) \ _(NewPar) \ diff --git a/js/src/jit/ParallelSafetyAnalysis.cpp b/js/src/jit/ParallelSafetyAnalysis.cpp index f05b8ebc9d5..dcd17402114 100644 --- a/js/src/jit/ParallelSafetyAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -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: diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 4e3ed384ebc..06f555c9433 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -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; } diff --git a/js/src/jit/arm/CodeGenerator-arm.h b/js/src/jit/arm/CodeGenerator-arm.h index df8c2802e5b..0882d9fc7db 100644 --- a/js/src/jit/arm/CodeGenerator-arm.h +++ b/js/src/jit/arm/CodeGenerator-arm.h @@ -71,6 +71,7 @@ class CodeGeneratorARM : public CodeGeneratorShared protected: bool generatePrologue(); + bool generateAsmJSPrologue(Label *stackOverflowLabel); bool generateEpilogue(); bool generateOutOfLineCode(); diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 48484c185c7..d3ed35bbcbb 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -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) { diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index d1a78e8762f..4fe73994339 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -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); diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index 675d6169163..b1958941775 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -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() { diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.h b/js/src/jit/shared/CodeGenerator-x86-shared.h index 3b5fcccf177..d9b40f8862e 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.h +++ b/js/src/jit/shared/CodeGenerator-x86-shared.h @@ -78,6 +78,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared protected: bool generatePrologue(); + bool generateAsmJSPrologue(Label *stackOverflowLabe); bool generateEpilogue(); bool generateOutOfLineCode();