зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1362357: wasm: Move exitReason to the wasm::Frame; r=luke
MozReview-Commit-ID: 9351D0DQVEf --HG-- extra : rebase_source : dc1d27e24fa0c12eba3f699f493f75b0193c4b9b extra : amend_source : 6ec242303ad225d8b50545eb4e68321b476394c4
This commit is contained in:
Родитель
fecbc27222
Коммит
676c55f50d
|
@ -1629,8 +1629,7 @@ jit::JitActivation::traceIonRecovery(JSTracer* trc)
|
|||
|
||||
WasmActivation::WasmActivation(JSContext* cx)
|
||||
: Activation(cx, Wasm),
|
||||
exitFP_(nullptr),
|
||||
exitReason_(wasm::ExitReason::Fixed::None)
|
||||
exitFP_(nullptr)
|
||||
{
|
||||
// Now that the WasmActivation is fully initialized, make it visible to
|
||||
// asynchronous profiling.
|
||||
|
@ -1644,14 +1643,12 @@ WasmActivation::~WasmActivation()
|
|||
|
||||
MOZ_ASSERT(!interrupted());
|
||||
MOZ_ASSERT(exitFP_ == nullptr);
|
||||
MOZ_ASSERT(exitReason_.isNone());
|
||||
}
|
||||
|
||||
void
|
||||
WasmActivation::unwindExitFP(wasm::Frame* exitFP)
|
||||
{
|
||||
exitFP_ = exitFP;
|
||||
exitReason_ = wasm::ExitReason::Fixed::None;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1741,7 +1741,6 @@ class InterpreterFrameIterator
|
|||
class WasmActivation : public Activation
|
||||
{
|
||||
wasm::Frame* exitFP_;
|
||||
wasm::ExitReason exitReason_;
|
||||
|
||||
public:
|
||||
explicit WasmActivation(JSContext* cx);
|
||||
|
@ -1755,12 +1754,8 @@ class WasmActivation : public Activation
|
|||
// WasmActivation.
|
||||
wasm::Frame* exitFP() const { return exitFP_; }
|
||||
|
||||
// Returns the reason why wasm code called out of wasm code.
|
||||
wasm::ExitReason exitReason() const { return exitReason_; }
|
||||
|
||||
// Written by JIT code:
|
||||
static unsigned offsetOfExitFP() { return offsetof(WasmActivation, exitFP_); }
|
||||
static unsigned offsetOfExitReason() { return offsetof(WasmActivation, exitReason_); }
|
||||
|
||||
// Interrupts are started from the interrupt signal handler (or the ARM
|
||||
// simulator) and cleared by WasmHandleExecutionInterrupt or WasmHandleThrow
|
||||
|
|
|
@ -251,42 +251,54 @@ FrameIterator::debugTrapCallsite() const
|
|||
#if defined(JS_CODEGEN_X64)
|
||||
static const unsigned PushedRetAddr = 0;
|
||||
static const unsigned PushedTLS = 2;
|
||||
static const unsigned PushedFP = 3;
|
||||
static const unsigned SetFP = 6;
|
||||
static const unsigned PoppedFP = 2;
|
||||
static const unsigned PushedExitReason = 4;
|
||||
static const unsigned PushedFP = 5;
|
||||
static const unsigned SetFP = 8;
|
||||
static const unsigned PoppedFP = 4;
|
||||
static const unsigned PoppedExitReason = 2;
|
||||
#elif defined(JS_CODEGEN_X86)
|
||||
static const unsigned PushedRetAddr = 0;
|
||||
static const unsigned PushedTLS = 1;
|
||||
static const unsigned PushedFP = 2;
|
||||
static const unsigned SetFP = 4;
|
||||
static const unsigned PoppedFP = 1;
|
||||
static const unsigned PushedExitReason = 3;
|
||||
static const unsigned PushedFP = 4;
|
||||
static const unsigned SetFP = 6;
|
||||
static const unsigned PoppedFP = 2;
|
||||
static const unsigned PoppedExitReason = 1;
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
static const unsigned BeforePushRetAddr = 0;
|
||||
static const unsigned PushedRetAddr = 4;
|
||||
static const unsigned PushedTLS = 8;
|
||||
static const unsigned PushedFP = 12;
|
||||
static const unsigned SetFP = 16;
|
||||
static const unsigned PoppedFP = 4;
|
||||
static const unsigned PushedExitReason = 16;
|
||||
static const unsigned PushedFP = 20;
|
||||
static const unsigned SetFP = 24;
|
||||
static const unsigned PoppedFP = 8;
|
||||
static const unsigned PoppedExitReason = 4;
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
static const unsigned BeforePushRetAddr = 0;
|
||||
static const unsigned PushedRetAddr = 0;
|
||||
static const unsigned PushedTLS = 0;
|
||||
static const unsigned PushedExitReason = 0;
|
||||
static const unsigned PushedFP = 0;
|
||||
static const unsigned SetFP = 0;
|
||||
static const unsigned PoppedFP = 0;
|
||||
static const unsigned PoppedExitReason = 0;
|
||||
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
static const unsigned BeforePushRetAddr = 0;
|
||||
static const unsigned PushedRetAddr = 4;
|
||||
static const unsigned PushedTLS = 8;
|
||||
static const unsigned PushedFP = 12;
|
||||
static const unsigned SetFP = 16;
|
||||
static const unsigned PoppedFP = 4;
|
||||
static const unsigned PushedExitReason = 12;
|
||||
static const unsigned PushedFP = 16;
|
||||
static const unsigned SetFP = 20;
|
||||
static const unsigned PoppedFP = 8;
|
||||
static const unsigned PoppedExitReason = 4;
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
static const unsigned PushedRetAddr = 0;
|
||||
static const unsigned PushedTLS = 0;
|
||||
static const unsigned PushedExitReason = 0;
|
||||
static const unsigned PushedFP = 0;
|
||||
static const unsigned SetFP = 0;
|
||||
static const unsigned PoppedFP = 0;
|
||||
static const unsigned PoppedExitReason = 0;
|
||||
#else
|
||||
# error "Unknown architecture!"
|
||||
#endif
|
||||
|
@ -327,7 +339,7 @@ GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason
|
|||
// randomly inserted between two instructions.
|
||||
{
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
AutoForbidPools afp(&masm, /* number of instructions in scope = */ 8);
|
||||
AutoForbidPools afp(&masm, /* number of instructions in scope = */ 7);
|
||||
#endif
|
||||
*entry = masm.currentOffset();
|
||||
|
||||
|
@ -335,6 +347,8 @@ GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason
|
|||
MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - *entry);
|
||||
masm.push(WasmTlsReg);
|
||||
MOZ_ASSERT_IF(!masm.oom(), PushedTLS == masm.currentOffset() - *entry);
|
||||
masm.push(Imm32(reason.encode()));
|
||||
MOZ_ASSERT_IF(!masm.oom(), PushedExitReason == masm.currentOffset() - *entry);
|
||||
masm.push(FramePointer);
|
||||
MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - *entry);
|
||||
masm.moveStackPtrTo(FramePointer);
|
||||
|
@ -342,21 +356,20 @@ GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason
|
|||
}
|
||||
|
||||
if (!reason.isNone()) {
|
||||
// Native callers expect the native ABI, which assume that nonvolatile
|
||||
// registers are preserved.
|
||||
Register scratch = ABINonArgReg0;
|
||||
if (reason.isNative() && !scratch.volatile_())
|
||||
masm.Push(scratch);
|
||||
Register act = ABINonArgReg0;
|
||||
|
||||
LoadActivation(masm, scratch);
|
||||
masm.wasmAssertNonExitInvariants(scratch);
|
||||
Address exitReason(scratch, WasmActivation::offsetOfExitReason());
|
||||
masm.store32(Imm32(reason.raw()), exitReason);
|
||||
Address exitFP(scratch, WasmActivation::offsetOfExitFP());
|
||||
masm.storePtr(FramePointer, exitFP);
|
||||
// Native callers expect the native ABI, which assume that non-saved
|
||||
// registers are preserved. Explicitly preserve the act register
|
||||
// in that case.
|
||||
if (reason.isNative() && !act.volatile_())
|
||||
masm.Push(act);
|
||||
|
||||
if (reason.isNative() && !scratch.volatile_())
|
||||
masm.Pop(scratch);
|
||||
LoadActivation(masm, act);
|
||||
masm.wasmAssertNonExitInvariants(act);
|
||||
masm.storePtr(FramePointer, Address(act, WasmActivation::offsetOfExitFP()));
|
||||
|
||||
if (reason.isNative() && !act.volatile_())
|
||||
masm.Pop(act);
|
||||
}
|
||||
|
||||
if (framePushed)
|
||||
|
@ -371,34 +384,35 @@ GenerateCallableEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason
|
|||
masm.addToStackPtr(Imm32(framePushed));
|
||||
|
||||
if (!reason.isNone()) {
|
||||
// See comment in GenerateCallablePrologue.
|
||||
Register scratch = ABINonArgReturnReg0;
|
||||
if (reason.isNative() && !scratch.volatile_())
|
||||
masm.Push(scratch);
|
||||
Register act = ABINonArgReturnReg0;
|
||||
|
||||
// See comment in GenerateCallablePrologue.
|
||||
if (reason.isNative() && !act.volatile_())
|
||||
masm.Push(act);
|
||||
|
||||
LoadActivation(masm, act);
|
||||
masm.storePtr(ImmWord(0), Address(act, WasmActivation::offsetOfExitFP()));
|
||||
|
||||
LoadActivation(masm, scratch);
|
||||
Address exitFP(scratch, WasmActivation::offsetOfExitFP());
|
||||
masm.storePtr(ImmWord(0), exitFP);
|
||||
Address exitReason(scratch, WasmActivation::offsetOfExitReason());
|
||||
#ifdef DEBUG
|
||||
// Check the passed exitReason is the same as the one on entry.
|
||||
masm.push(scratch);
|
||||
masm.loadPtr(exitReason, ABINonArgReturnReg0);
|
||||
// Do it here rather than in the pop sequence to not perturbate the
|
||||
// static stack structure in debug vs optimized mode.
|
||||
Register scratch = act;
|
||||
size_t exitReasonSlot = 1 + (reason.isNative() && !scratch.volatile_() ? 1 : 0);
|
||||
masm.load32(Address(masm.getStackPointer(), exitReasonSlot * sizeof(void*)), scratch);
|
||||
Label ok;
|
||||
masm.branch32(Assembler::Condition::Equal, ABINonArgReturnReg0, Imm32(reason.raw()), &ok);
|
||||
masm.branch32(Assembler::Condition::Equal, scratch, Imm32(reason.encode()), &ok);
|
||||
masm.breakpoint();
|
||||
masm.bind(&ok);
|
||||
masm.pop(scratch);
|
||||
#endif
|
||||
masm.store32(Imm32(ExitReason::None().raw()), exitReason);
|
||||
|
||||
if (reason.isNative() && !scratch.volatile_())
|
||||
masm.Pop(scratch);
|
||||
if (reason.isNative() && !act.volatile_())
|
||||
masm.Pop(act);
|
||||
}
|
||||
|
||||
// Forbid pools for the same reason as described in GenerateCallablePrologue.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
AutoForbidPools afp(&masm, /* number of instructions in scope = */ 3);
|
||||
AutoForbidPools afp(&masm, /* number of instructions in scope = */ 7);
|
||||
#endif
|
||||
|
||||
// There is an important ordering constraint here: fp must be repointed to
|
||||
|
@ -410,11 +424,18 @@ GenerateCallableEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason
|
|||
|
||||
masm.pop(FramePointer);
|
||||
DebugOnly<uint32_t> poppedFP = masm.currentOffset();
|
||||
|
||||
// Pop the exit reason to WasmTlsReg; it's going to be clobbered just
|
||||
// thereafter to store the real value of WasmTlsReg.
|
||||
masm.pop(WasmTlsReg);
|
||||
DebugOnly<uint32_t> poppedExitReason = masm.currentOffset();
|
||||
|
||||
masm.pop(WasmTlsReg);
|
||||
*ret = masm.currentOffset();
|
||||
masm.ret();
|
||||
|
||||
MOZ_ASSERT_IF(!masm.oom(), PoppedFP == *ret - poppedFP);
|
||||
MOZ_ASSERT_IF(!masm.oom(), PoppedExitReason == *ret - poppedExitReason);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -537,6 +558,10 @@ ProfilingFrameIterator::initFromExitFP()
|
|||
Frame* fp = activation_->exitFP();
|
||||
void* pc = fp->returnAddress;
|
||||
|
||||
// The iterator inserts a pretend innermost frame for ExitReasons.
|
||||
// This allows the variety of exit reasons to show up in the callstack.
|
||||
exitReason_ = ExitReason::Decode(fp->encodedExitReason);
|
||||
|
||||
stackAddress_ = fp;
|
||||
|
||||
code_ = activation_->compartment()->wasm.lookupCode(pc);
|
||||
|
@ -575,10 +600,6 @@ ProfilingFrameIterator::initFromExitFP()
|
|||
MOZ_CRASH("Unexpected CodeRange kind");
|
||||
}
|
||||
|
||||
// The iterator inserts a pretend innermost frame for non-None ExitReasons.
|
||||
// This allows the variety of exit reasons to show up in the callstack.
|
||||
exitReason_ = activation_->exitReason();
|
||||
|
||||
MOZ_ASSERT(!done());
|
||||
}
|
||||
|
||||
|
@ -667,12 +688,18 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
|
|||
callerPC_ = sp[0];
|
||||
callerFP_ = fp;
|
||||
AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
|
||||
} else if (offsetFromEntry == PushedTLS) {
|
||||
// The return address and caller's TLS have been pushed on the stack; fp
|
||||
// is still the caller's fp.
|
||||
} else if (offsetFromEntry >= PushedTLS && offsetFromEntry < PushedExitReason) {
|
||||
// The return address and caller's TLS have been pushed on the
|
||||
// stack; fp is still the caller's fp.
|
||||
callerPC_ = sp[1];
|
||||
callerFP_ = fp;
|
||||
AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
|
||||
} else if (offsetFromEntry == PushedExitReason) {
|
||||
// The return address, caller's TLS and exit reason have been
|
||||
// pushed on the stack; fp is still the caller's fp.
|
||||
callerPC_ = sp[2];
|
||||
callerFP_ = fp;
|
||||
AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
|
||||
} else if (offsetFromEntry == PushedFP) {
|
||||
// The full Frame has been pushed; fp is still the caller's fp.
|
||||
MOZ_ASSERT(fp == reinterpret_cast<Frame*>(sp)->callerFP);
|
||||
|
@ -680,9 +707,17 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
|
|||
callerFP_ = fp;
|
||||
AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
|
||||
} else if (offsetInCode == codeRange->ret() - PoppedFP) {
|
||||
// The callerFP field of the Frame has been popped into fp.
|
||||
// The callerFP field of the Frame has been popped into fp, but the
|
||||
// exit reason hasn't been popped yet.
|
||||
callerPC_ = sp[2];
|
||||
callerFP_ = fp;
|
||||
AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
|
||||
} else if (offsetInCode == codeRange->ret() - PoppedExitReason) {
|
||||
// The callerFP field of the Frame has been popped into fp, and the
|
||||
// exit reason has been popped.
|
||||
callerPC_ = sp[1];
|
||||
callerFP_ = fp;
|
||||
AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
|
||||
} else if (offsetInCode == codeRange->ret()) {
|
||||
// Both the TLS and callerFP fields have been popped and fp now
|
||||
// points to the caller's frame.
|
||||
|
|
|
@ -93,6 +93,8 @@ class ExitReason
|
|||
{
|
||||
uint32_t payload_;
|
||||
|
||||
ExitReason() {}
|
||||
|
||||
public:
|
||||
enum class Fixed : uint32_t
|
||||
{
|
||||
|
@ -117,13 +119,19 @@ class ExitReason
|
|||
MOZ_ASSERT(!isFixed());
|
||||
}
|
||||
|
||||
static ExitReason Decode(uint32_t payload) {
|
||||
ExitReason reason;
|
||||
reason.payload_ = payload;
|
||||
return reason;
|
||||
}
|
||||
|
||||
static ExitReason None() { return ExitReason(ExitReason::Fixed::None); }
|
||||
|
||||
bool isFixed() const { return (payload_ & 0x1) == 0; }
|
||||
bool isNone() const { return isFixed() && fixed() == Fixed::None; }
|
||||
bool isNative() const { return !isFixed() || fixed() == Fixed::BuiltinNative; }
|
||||
|
||||
uint32_t raw() const {
|
||||
uint32_t encode() const {
|
||||
return payload_;
|
||||
}
|
||||
Fixed fixed() const {
|
||||
|
|
|
@ -1627,6 +1627,10 @@ struct Frame
|
|||
// the first field of wasm::Frame (in a downward-growing stack).
|
||||
Frame* callerFP;
|
||||
|
||||
// The raw payload of an ExitReason describing why we've left wasm. It is
|
||||
// non null if and only if a call exited wasm code.
|
||||
uint32_t encodedExitReason;
|
||||
|
||||
// The saved value of WasmTlsReg on entry to the function. This is
|
||||
// effectively the callee's instance.
|
||||
TlsData* tls;
|
||||
|
@ -1680,13 +1684,6 @@ class DebugFrame
|
|||
void* flagsWord_;
|
||||
};
|
||||
|
||||
// Padding so that DebugFrame has Alignment.
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
protected: // suppress clang's -Wunused-private-field warning-as-error
|
||||
void* padding_;
|
||||
private:
|
||||
#endif
|
||||
|
||||
// The Frame goes at the end since the stack grows down.
|
||||
Frame frame_;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче