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:
Benjamin Bouvier 2017-05-05 12:09:48 +02:00
Родитель fecbc27222
Коммит 676c55f50d
5 изменённых файлов: 99 добавлений и 67 удалений

Просмотреть файл

@ -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_;