// Generate a stub that is called immediately after the prologue when there is a // stack overflow. This stub calls a C++ function to report the error and then // jumps to the throw stub to pop the activation. static bool GenerateStackOverflowStub(ModuleGenerator& mg, Label* throwLabel) { MacroAssembler& masm = mg.masm(); masm.haltingAlign(CodeAlignment); Offsets offsets; offsets.begin = masm.currentOffset(); masm.bind(masm.asmStackOverflowLabel()); // If we reach here via the non-profiling prologue, WasmActivation::fp has // not been updated. To enable stack unwinding from C++, store to it now. If // we reached here via the profiling prologue, we'll just store the same // value again. Do not update AsmJSFrame::callerFP as it is not necessary in // the non-profiling case (there is no return path from this point) and, in // the profiling case, it is already correct. Register activation = ABIArgGenerator::NonArgReturnReg0; masm.loadWasmActivation(activation); masm.storePtr(masm.getStackPointer(), Address(activation, WasmActivation::offsetOfFP())); // Prepare the stack for calling C++. if (uint32_t d = StackDecrementForCall(ABIStackAlignment, sizeof(AsmJSFrame), ShadowStackSpace)) masm.subFromStackPtr(Imm32(d)); // No need to restore the stack; the throw stub pops everything. masm.assertStackAlignment(ABIStackAlignment); masm.call(SymbolicAddress::ReportOverRecursed); masm.jump(throwLabel); if (masm.oom()) return false; offsets.end = masm.currentOffset(); return mg.defineInlineStub(offsets); }
// Generate a stub that is jumped to from an out-of-bounds heap access when // there are throwing semantics. This stub calls a C++ function to report an // error and then jumps to the throw stub to pop the activation. static bool GenerateConversionErrorStub(ModuleGenerator& mg, Label* throwLabel) { MacroAssembler& masm = mg.masm(); masm.haltingAlign(CodeAlignment); Offsets offsets; offsets.begin = masm.currentOffset(); masm.bind(masm.asmOnConversionErrorLabel()); // sp can be anything at this point, so ensure it is aligned when calling // into C++. We unconditionally jump to throw so don't worry about restoring sp. masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1))); // OnImpreciseConversion always throws. masm.assertStackAlignment(ABIStackAlignment); masm.call(SymbolicAddress::OnImpreciseConversion); masm.jump(throwLabel); if (masm.oom()) return false; offsets.end = masm.currentOffset(); return mg.defineInlineStub(offsets); }
// If an exception is thrown, simply pop all frames (since asm.js does not // contain try/catch). To do this: // 1. Restore 'sp' to it's value right after the PushRegsInMask in GenerateEntry. // 2. PopRegsInMask to restore the caller's non-volatile registers. // 3. Return (to CallAsmJS). static bool GenerateThrowStub(ModuleGenerator& mg, Label* throwLabel) { MacroAssembler& masm = mg.masm(); masm.haltingAlign(CodeAlignment); Offsets offsets; offsets.begin = masm.currentOffset(); masm.bind(throwLabel); // We are about to pop all frames in this WasmActivation. Set fp to null to // maintain the invariant that fp is either null or pointing to a valid // frame. Register scratch = ABIArgGenerator::NonArgReturnReg0; masm.loadWasmActivation(scratch); masm.storePtr(ImmWord(0), Address(scratch, WasmActivation::offsetOfFP())); masm.setFramePushed(FramePushedForEntrySP); masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP())); masm.Pop(scratch); masm.PopRegsInMask(NonVolatileRegs); MOZ_ASSERT(masm.framePushed() == 0); masm.mov(ImmWord(0), ReturnReg); masm.ret(); if (masm.oom()) return false; offsets.end = masm.currentOffset(); return mg.defineInlineStub(offsets); }