зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1360254 - Baldr: remove JSContext::wasmActivationStack (r=bbouvier)
MozReview-Commit-ID: Ftzs7mTUzWN --HG-- extra : rebase_source : b4670defcde377465b9d51681bb51a60a942b214
This commit is contained in:
Родитель
90264dad88
Коммит
b9a4912ee2
|
@ -3092,13 +3092,6 @@ MacroAssembler::wasmAssertNonExitInvariants(Register activation)
|
||||||
|
|
||||||
//}}} check_macroassembler_style
|
//}}} check_macroassembler_style
|
||||||
|
|
||||||
void
|
|
||||||
MacroAssembler::loadWasmActivationFromTls(Register dest)
|
|
||||||
{
|
|
||||||
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, cx)), dest);
|
|
||||||
loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroAssembler::loadWasmTlsRegFromFrame(Register dest)
|
MacroAssembler::loadWasmTlsRegFromFrame(Register dest)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1539,7 +1539,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||||
|
|
||||||
void guardGroupHasUnanalyzedNewScript(Register group, Register scratch, Label* fail);
|
void guardGroupHasUnanalyzedNewScript(Register group, Register scratch, Label* fail);
|
||||||
|
|
||||||
void loadWasmActivationFromTls(Register dest);
|
|
||||||
void loadWasmTlsRegFromFrame(Register dest = WasmTlsReg);
|
void loadWasmTlsRegFromFrame(Register dest = WasmTlsReg);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -1558,7 +1558,7 @@ Simulator::handleWasmInterrupt()
|
||||||
void* pc = (void*)get_pc();
|
void* pc = (void*)get_pc();
|
||||||
uint8_t* fp = (uint8_t*)get_register(r11);
|
uint8_t* fp = (uint8_t*)get_register(r11);
|
||||||
|
|
||||||
WasmActivation* activation = JSContext::innermostWasmActivation();
|
WasmActivation* activation = wasm::MaybeActiveActivation(cx_);
|
||||||
const wasm::Code* code = activation->compartment()->wasm.lookupCode(pc);
|
const wasm::Code* code = activation->compartment()->wasm.lookupCode(pc);
|
||||||
if (!code || !code->segment().containsFunctionPC(pc))
|
if (!code || !code->segment().containsFunctionPC(pc))
|
||||||
return;
|
return;
|
||||||
|
@ -1580,7 +1580,7 @@ Simulator::handleWasmInterrupt()
|
||||||
bool
|
bool
|
||||||
Simulator::handleWasmFault(int32_t addr, unsigned numBytes)
|
Simulator::handleWasmFault(int32_t addr, unsigned numBytes)
|
||||||
{
|
{
|
||||||
WasmActivation* act = cx_->wasmActivationStack();
|
WasmActivation* act = wasm::MaybeActiveActivation(cx_);
|
||||||
if (!act)
|
if (!act)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1614,7 +1614,7 @@ Simulator::readQ(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See the comments below in readW.
|
// See the comments below in readW.
|
||||||
if (FixupFault() && wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
if (FixupFault() && wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
|
||||||
char* ptr = reinterpret_cast<char*>(addr);
|
char* ptr = reinterpret_cast<char*>(addr);
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
memcpy(&value, ptr, sizeof(value));
|
memcpy(&value, ptr, sizeof(value));
|
||||||
|
@ -1638,7 +1638,7 @@ Simulator::writeQ(int32_t addr, uint64_t value, SimInstruction* instr, Unaligned
|
||||||
}
|
}
|
||||||
|
|
||||||
// See the comments below in readW.
|
// See the comments below in readW.
|
||||||
if (FixupFault() && wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
if (FixupFault() && wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
|
||||||
char* ptr = reinterpret_cast<char*>(addr);
|
char* ptr = reinterpret_cast<char*>(addr);
|
||||||
memcpy(ptr, &value, sizeof(value));
|
memcpy(ptr, &value, sizeof(value));
|
||||||
return;
|
return;
|
||||||
|
@ -1663,7 +1663,7 @@ Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
|
||||||
// do the right thing. Making this simulator properly emulate the behavior
|
// do the right thing. Making this simulator properly emulate the behavior
|
||||||
// of raising a signal is complex, so as a special-case, when in wasm code,
|
// of raising a signal is complex, so as a special-case, when in wasm code,
|
||||||
// we just do the right thing.
|
// we just do the right thing.
|
||||||
if (FixupFault() && wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
if (FixupFault() && wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
|
||||||
char* ptr = reinterpret_cast<char*>(addr);
|
char* ptr = reinterpret_cast<char*>(addr);
|
||||||
int value;
|
int value;
|
||||||
memcpy(&value, ptr, sizeof(value));
|
memcpy(&value, ptr, sizeof(value));
|
||||||
|
@ -1687,7 +1687,7 @@ Simulator::writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolic
|
||||||
}
|
}
|
||||||
|
|
||||||
// See the comments above in readW.
|
// See the comments above in readW.
|
||||||
if (FixupFault() && wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
if (FixupFault() && wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
|
||||||
char* ptr = reinterpret_cast<char*>(addr);
|
char* ptr = reinterpret_cast<char*>(addr);
|
||||||
memcpy(ptr, &value, sizeof(value));
|
memcpy(ptr, &value, sizeof(value));
|
||||||
return;
|
return;
|
||||||
|
@ -1763,7 +1763,7 @@ Simulator::readHU(int32_t addr, SimInstruction* instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See comments above in readW.
|
// See comments above in readW.
|
||||||
if (FixupFault() && wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
if (FixupFault() && wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
|
||||||
char* ptr = reinterpret_cast<char*>(addr);
|
char* ptr = reinterpret_cast<char*>(addr);
|
||||||
uint16_t value;
|
uint16_t value;
|
||||||
memcpy(&value, ptr, sizeof(value));
|
memcpy(&value, ptr, sizeof(value));
|
||||||
|
@ -1787,7 +1787,7 @@ Simulator::readH(int32_t addr, SimInstruction* instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See comments above in readW.
|
// See comments above in readW.
|
||||||
if (FixupFault() && wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
if (FixupFault() && wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
|
||||||
char* ptr = reinterpret_cast<char*>(addr);
|
char* ptr = reinterpret_cast<char*>(addr);
|
||||||
int16_t value;
|
int16_t value;
|
||||||
memcpy(&value, ptr, sizeof(value));
|
memcpy(&value, ptr, sizeof(value));
|
||||||
|
@ -1812,7 +1812,7 @@ Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See the comments above in readW.
|
// See the comments above in readW.
|
||||||
if (FixupFault() && wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
if (FixupFault() && wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
|
||||||
char* ptr = reinterpret_cast<char*>(addr);
|
char* ptr = reinterpret_cast<char*>(addr);
|
||||||
memcpy(ptr, &value, sizeof(value));
|
memcpy(ptr, &value, sizeof(value));
|
||||||
return;
|
return;
|
||||||
|
@ -1835,7 +1835,7 @@ Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See the comments above in readW.
|
// See the comments above in readW.
|
||||||
if (FixupFault() && wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
if (FixupFault() && wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
|
||||||
char* ptr = reinterpret_cast<char*>(addr);
|
char* ptr = reinterpret_cast<char*>(addr);
|
||||||
memcpy(ptr, &value, sizeof(value));
|
memcpy(ptr, &value, sizeof(value));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -545,8 +545,8 @@ const char* RegisterToken::kWAliases[kNumberOfRegisters][kMaxAliasNumber] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Debugger::Debugger(Decoder* decoder, FILE* stream)
|
Debugger::Debugger(JSContext* cx, Decoder* decoder, FILE* stream)
|
||||||
: Simulator(decoder, stream),
|
: Simulator(cx, decoder, stream),
|
||||||
debug_parameters_(DBG_INACTIVE),
|
debug_parameters_(DBG_INACTIVE),
|
||||||
pending_request_(false),
|
pending_request_(false),
|
||||||
steps_(0),
|
steps_(0),
|
||||||
|
|
|
@ -54,7 +54,7 @@ class FormatToken;
|
||||||
|
|
||||||
class Debugger : public Simulator {
|
class Debugger : public Simulator {
|
||||||
public:
|
public:
|
||||||
explicit Debugger(Decoder* decoder, FILE* stream = stdout);
|
explicit Debugger(JSContext* cx, Decoder* decoder, FILE* stream = stdout);
|
||||||
~Debugger();
|
~Debugger();
|
||||||
|
|
||||||
virtual void Run();
|
virtual void Run();
|
||||||
|
|
|
@ -43,8 +43,9 @@ using mozilla::DebugOnly;
|
||||||
using js::jit::ABIFunctionType;
|
using js::jit::ABIFunctionType;
|
||||||
using js::jit::SimulatorProcess;
|
using js::jit::SimulatorProcess;
|
||||||
|
|
||||||
Simulator::Simulator(Decoder* decoder, FILE* stream)
|
Simulator::Simulator(JSContext* cx, Decoder* decoder, FILE* stream)
|
||||||
: stream_(nullptr)
|
: cx_(cx)
|
||||||
|
, stream_(nullptr)
|
||||||
, print_disasm_(nullptr)
|
, print_disasm_(nullptr)
|
||||||
, instrumentation_(nullptr)
|
, instrumentation_(nullptr)
|
||||||
, stack_(nullptr)
|
, stack_(nullptr)
|
||||||
|
@ -168,9 +169,9 @@ Simulator* Simulator::Create(JSContext* cx) {
|
||||||
// FIXME: Note that it can't be stored in the SimulatorRuntime due to lifetime conflicts.
|
// FIXME: Note that it can't be stored in the SimulatorRuntime due to lifetime conflicts.
|
||||||
Simulator *sim;
|
Simulator *sim;
|
||||||
if (getenv("USE_DEBUGGER") != nullptr)
|
if (getenv("USE_DEBUGGER") != nullptr)
|
||||||
sim = js_new<Debugger>(decoder, stdout);
|
sim = js_new<Debugger>(cx, decoder, stdout);
|
||||||
else
|
else
|
||||||
sim = js_new<Simulator>(decoder, stdout);
|
sim = js_new<Simulator>(cx, decoder, stdout);
|
||||||
|
|
||||||
// Check if Simulator:init ran out of memory.
|
// Check if Simulator:init ran out of memory.
|
||||||
if (sim && sim->oom()) {
|
if (sim && sim->oom()) {
|
||||||
|
@ -242,7 +243,7 @@ void Simulator::handle_wasm_interrupt() {
|
||||||
void* pc = (void*)get_pc();
|
void* pc = (void*)get_pc();
|
||||||
uint8_t* fp = (uint8_t*)xreg(30);
|
uint8_t* fp = (uint8_t*)xreg(30);
|
||||||
|
|
||||||
js::WasmActivation* activation = JSContext::innermostWasmActivation();
|
js::WasmActivation* activation = js::wasm::MaybeActiveActivation(cx_);
|
||||||
const js::wasm::Code* code = activation->compartment()->wasm.lookupCode(pc);
|
const js::wasm::Code* code = activation->compartment()->wasm.lookupCode(pc);
|
||||||
if (!code || !code->segment().containsFunctionPC(pc))
|
if (!code || !code->segment().containsFunctionPC(pc))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -697,7 +697,7 @@ class Redirection;
|
||||||
|
|
||||||
class Simulator : public DecoderVisitor {
|
class Simulator : public DecoderVisitor {
|
||||||
public:
|
public:
|
||||||
explicit Simulator(Decoder* decoder, FILE* stream = stdout);
|
explicit Simulator(JSContext* cx, Decoder* decoder, FILE* stream = stdout);
|
||||||
~Simulator();
|
~Simulator();
|
||||||
|
|
||||||
// Moz changes.
|
// Moz changes.
|
||||||
|
@ -2510,6 +2510,8 @@ class Simulator : public DecoderVisitor {
|
||||||
|
|
||||||
// Processor state ---------------------------------------
|
// Processor state ---------------------------------------
|
||||||
|
|
||||||
|
JSContext* const cx_;
|
||||||
|
|
||||||
// Simulated monitors for exclusive access instructions.
|
// Simulated monitors for exclusive access instructions.
|
||||||
SimExclusiveLocalMonitor local_monitor_;
|
SimExclusiveLocalMonitor local_monitor_;
|
||||||
SimExclusiveGlobalMonitor global_monitor_;
|
SimExclusiveGlobalMonitor global_monitor_;
|
||||||
|
|
|
@ -413,7 +413,6 @@ class MacroAssemblerNone : public Assembler
|
||||||
void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); }
|
void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); }
|
||||||
bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); }
|
bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); }
|
||||||
void loadWasmGlobalPtr(uint32_t, Register) { MOZ_CRASH(); }
|
void loadWasmGlobalPtr(uint32_t, Register) { MOZ_CRASH(); }
|
||||||
void loadWasmActivationFromTls(Register) { MOZ_CRASH(); }
|
|
||||||
void loadWasmPinnedRegsFromTls() { MOZ_CRASH(); }
|
void loadWasmPinnedRegsFromTls() { MOZ_CRASH(); }
|
||||||
|
|
||||||
void setPrinter(Sprinter*) { MOZ_CRASH(); }
|
void setPrinter(Sprinter*) { MOZ_CRASH(); }
|
||||||
|
|
|
@ -1133,7 +1133,6 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
|
||||||
jitActivation(nullptr),
|
jitActivation(nullptr),
|
||||||
activation_(nullptr),
|
activation_(nullptr),
|
||||||
profilingActivation_(nullptr),
|
profilingActivation_(nullptr),
|
||||||
wasmActivationStack_(nullptr),
|
|
||||||
nativeStackBase(GetNativeStackBase()),
|
nativeStackBase(GetNativeStackBase()),
|
||||||
entryMonitor(nullptr),
|
entryMonitor(nullptr),
|
||||||
noExecuteDebuggerTop(nullptr),
|
noExecuteDebuggerTop(nullptr),
|
||||||
|
|
|
@ -293,9 +293,6 @@ struct JSContext : public JS::RootingContext,
|
||||||
static size_t offsetOfActivation() {
|
static size_t offsetOfActivation() {
|
||||||
return offsetof(JSContext, activation_);
|
return offsetof(JSContext, activation_);
|
||||||
}
|
}
|
||||||
static size_t offsetOfWasmActivation() {
|
|
||||||
return offsetof(JSContext, wasmActivationStack_);
|
|
||||||
}
|
|
||||||
static size_t offsetOfProfilingActivation() {
|
static size_t offsetOfProfilingActivation() {
|
||||||
return offsetof(JSContext, profilingActivation_);
|
return offsetof(JSContext, profilingActivation_);
|
||||||
}
|
}
|
||||||
|
@ -369,16 +366,6 @@ struct JSContext : public JS::RootingContext,
|
||||||
js::Activation* volatile profilingActivation_;
|
js::Activation* volatile profilingActivation_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* See WasmActivation comment. */
|
|
||||||
js::WasmActivation* volatile wasmActivationStack_;
|
|
||||||
|
|
||||||
js::WasmActivation* wasmActivationStack() const {
|
|
||||||
return wasmActivationStack_;
|
|
||||||
}
|
|
||||||
static js::WasmActivation* innermostWasmActivation() {
|
|
||||||
return js::TlsContext.get()->wasmActivationStack_;
|
|
||||||
}
|
|
||||||
|
|
||||||
js::Activation* activation() const {
|
js::Activation* activation() const {
|
||||||
return activation_;
|
return activation_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1647,9 +1647,6 @@ WasmActivation::WasmActivation(JSContext* cx)
|
||||||
exitFP_(nullptr),
|
exitFP_(nullptr),
|
||||||
exitReason_(wasm::ExitReason::Fixed::None)
|
exitReason_(wasm::ExitReason::Fixed::None)
|
||||||
{
|
{
|
||||||
prevWasm_ = cx->wasmActivationStack_;
|
|
||||||
cx->wasmActivationStack_ = this;
|
|
||||||
|
|
||||||
// Now that the WasmActivation is fully initialized, make it visible to
|
// Now that the WasmActivation is fully initialized, make it visible to
|
||||||
// asynchronous profiling.
|
// asynchronous profiling.
|
||||||
registerProfiling();
|
registerProfiling();
|
||||||
|
@ -1663,9 +1660,6 @@ WasmActivation::~WasmActivation()
|
||||||
MOZ_ASSERT(!interrupted());
|
MOZ_ASSERT(!interrupted());
|
||||||
MOZ_ASSERT(exitFP_ == nullptr);
|
MOZ_ASSERT(exitFP_ == nullptr);
|
||||||
MOZ_ASSERT(exitReason_.isNone());
|
MOZ_ASSERT(exitReason_.isNone());
|
||||||
|
|
||||||
MOZ_ASSERT(cx_->wasmActivationStack_ == this);
|
|
||||||
cx_->wasmActivationStack_ = prevWasm_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1360,6 +1360,9 @@ class Activation
|
||||||
return hideScriptedCallerCount_ > 0;
|
return hideScriptedCallerCount_ > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t offsetOfPrev() {
|
||||||
|
return offsetof(Activation, prev_);
|
||||||
|
}
|
||||||
static size_t offsetOfPrevProfiling() {
|
static size_t offsetOfPrevProfiling() {
|
||||||
return offsetof(Activation, prevProfiling_);
|
return offsetof(Activation, prevProfiling_);
|
||||||
}
|
}
|
||||||
|
@ -1721,18 +1724,12 @@ class InterpreterFrameIterator
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A WasmActivation is part of two activation linked lists:
|
|
||||||
// - the normal Activation list used by FrameIter
|
|
||||||
// - a list of only WasmActivations that is signal-safe since it is accessed
|
|
||||||
// from the profiler at arbitrary points
|
|
||||||
//
|
|
||||||
// An eventual goal is to remove WasmActivation and to run asm code in a
|
// An eventual goal is to remove WasmActivation and to run asm code in a
|
||||||
// JitActivation interleaved with Ion/Baseline jit code. This would allow
|
// JitActivation interleaved with Ion/Baseline jit code. This would allow
|
||||||
// efficient calls back and forth but requires that we can walk the stack for
|
// efficient calls back and forth but requires that we can walk the stack for
|
||||||
// all kinds of jit code.
|
// all kinds of jit code.
|
||||||
class WasmActivation : public Activation
|
class WasmActivation : public Activation
|
||||||
{
|
{
|
||||||
WasmActivation* prevWasm_;
|
|
||||||
wasm::Frame* exitFP_;
|
wasm::Frame* exitFP_;
|
||||||
wasm::ExitReason exitReason_;
|
wasm::ExitReason exitReason_;
|
||||||
|
|
||||||
|
@ -1740,8 +1737,6 @@ class WasmActivation : public Activation
|
||||||
explicit WasmActivation(JSContext* cx);
|
explicit WasmActivation(JSContext* cx);
|
||||||
~WasmActivation();
|
~WasmActivation();
|
||||||
|
|
||||||
WasmActivation* prevWasm() const { return prevWasm_; }
|
|
||||||
|
|
||||||
bool isProfiling() const {
|
bool isProfiling() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,10 +61,22 @@ __aeabi_uidivmod(int, int);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// This utility function can only be called for builtins that are called
|
||||||
|
// directly from wasm code. Note that WasmCall pushes both an outer
|
||||||
|
// WasmActivation and an inner JitActivation that becomes active when calling
|
||||||
|
// JIT code.
|
||||||
|
static WasmActivation*
|
||||||
|
CallingActivation()
|
||||||
|
{
|
||||||
|
Activation* act = TlsContext.get()->activation();
|
||||||
|
MOZ_ASSERT(!act->asJit()->isActive(), "WasmCall pushes an inactive JitActivation");
|
||||||
|
return act->prev()->asWasm();
|
||||||
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
WasmHandleExecutionInterrupt()
|
WasmHandleExecutionInterrupt()
|
||||||
{
|
{
|
||||||
WasmActivation* activation = JSContext::innermostWasmActivation();
|
WasmActivation* activation = CallingActivation();
|
||||||
MOZ_ASSERT(activation->interrupted());
|
MOZ_ASSERT(activation->interrupted());
|
||||||
|
|
||||||
if (!CheckForInterrupt(activation->cx())) {
|
if (!CheckForInterrupt(activation->cx())) {
|
||||||
|
@ -86,7 +98,7 @@ WasmHandleExecutionInterrupt()
|
||||||
static bool
|
static bool
|
||||||
WasmHandleDebugTrap()
|
WasmHandleDebugTrap()
|
||||||
{
|
{
|
||||||
WasmActivation* activation = JSContext::innermostWasmActivation();
|
WasmActivation* activation = CallingActivation();
|
||||||
MOZ_ASSERT(activation);
|
MOZ_ASSERT(activation);
|
||||||
JSContext* cx = activation->cx();
|
JSContext* cx = activation->cx();
|
||||||
|
|
||||||
|
@ -154,10 +166,8 @@ WasmHandleDebugTrap()
|
||||||
static void*
|
static void*
|
||||||
WasmHandleThrow()
|
WasmHandleThrow()
|
||||||
{
|
{
|
||||||
JSContext* cx = TlsContext.get();
|
WasmActivation* activation = CallingActivation();
|
||||||
|
JSContext* cx = activation->cx();
|
||||||
WasmActivation* activation = cx->wasmActivationStack();
|
|
||||||
MOZ_ASSERT(activation);
|
|
||||||
|
|
||||||
// FrameIterator iterates down wasm frames in the activation starting at
|
// FrameIterator iterates down wasm frames in the activation starting at
|
||||||
// WasmActivation::exitFP. Pass Unwind::True to pop WasmActivation::exitFP
|
// WasmActivation::exitFP. Pass Unwind::True to pop WasmActivation::exitFP
|
||||||
|
@ -215,7 +225,7 @@ WasmHandleThrow()
|
||||||
static void
|
static void
|
||||||
WasmReportTrap(int32_t trapIndex)
|
WasmReportTrap(int32_t trapIndex)
|
||||||
{
|
{
|
||||||
JSContext* cx = JSContext::innermostWasmActivation()->cx();
|
JSContext* cx = TlsContext.get();
|
||||||
|
|
||||||
MOZ_ASSERT(trapIndex < int32_t(Trap::Limit) && trapIndex >= 0);
|
MOZ_ASSERT(trapIndex < int32_t(Trap::Limit) && trapIndex >= 0);
|
||||||
Trap trap = Trap(trapIndex);
|
Trap trap = Trap(trapIndex);
|
||||||
|
@ -259,21 +269,21 @@ WasmReportTrap(int32_t trapIndex)
|
||||||
static void
|
static void
|
||||||
WasmReportOutOfBounds()
|
WasmReportOutOfBounds()
|
||||||
{
|
{
|
||||||
JSContext* cx = JSContext::innermostWasmActivation()->cx();
|
JSContext* cx = TlsContext.get();
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_OUT_OF_BOUNDS);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_OUT_OF_BOUNDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
WasmReportUnalignedAccess()
|
WasmReportUnalignedAccess()
|
||||||
{
|
{
|
||||||
JSContext* cx = JSContext::innermostWasmActivation()->cx();
|
JSContext* cx = TlsContext.get();
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_UNALIGNED_ACCESS);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_UNALIGNED_ACCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t
|
static int32_t
|
||||||
CoerceInPlace_ToInt32(MutableHandleValue val)
|
CoerceInPlace_ToInt32(MutableHandleValue val)
|
||||||
{
|
{
|
||||||
JSContext* cx = JSContext::innermostWasmActivation()->cx();
|
JSContext* cx = TlsContext.get();
|
||||||
|
|
||||||
int32_t i32;
|
int32_t i32;
|
||||||
if (!ToInt32(cx, val, &i32))
|
if (!ToInt32(cx, val, &i32))
|
||||||
|
@ -286,7 +296,7 @@ CoerceInPlace_ToInt32(MutableHandleValue val)
|
||||||
static int32_t
|
static int32_t
|
||||||
CoerceInPlace_ToNumber(MutableHandleValue val)
|
CoerceInPlace_ToNumber(MutableHandleValue val)
|
||||||
{
|
{
|
||||||
JSContext* cx = JSContext::innermostWasmActivation()->cx();
|
JSContext* cx = TlsContext.get();
|
||||||
|
|
||||||
double dbl;
|
double dbl;
|
||||||
if (!ToNumber(cx, val, &dbl))
|
if (!ToNumber(cx, val, &dbl))
|
||||||
|
|
|
@ -300,6 +300,16 @@ PushRetAddr(MacroAssembler& masm, unsigned entry)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
LoadActivation(MacroAssembler& masm, Register dest)
|
||||||
|
{
|
||||||
|
// WasmCall pushes a WasmActivation and an inactive JitActivation. The
|
||||||
|
// JitActivation only becomes active when calling into JS from wasm.
|
||||||
|
masm.loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, cx)), dest);
|
||||||
|
masm.loadPtr(Address(dest, JSContext::offsetOfActivation()), dest);
|
||||||
|
masm.loadPtr(Address(dest, Activation::offsetOfPrev()), dest);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
|
GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
|
||||||
uint32_t* entry)
|
uint32_t* entry)
|
||||||
|
@ -326,15 +336,13 @@ GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reason.isNone()) {
|
if (!reason.isNone()) {
|
||||||
|
// Native callers expect the native ABI, which assume that nonvolatile
|
||||||
|
// registers are preserved.
|
||||||
Register scratch = ABINonArgReg0;
|
Register scratch = ABINonArgReg0;
|
||||||
|
|
||||||
// Native callers expect the native ABI, which assume that non-saved
|
|
||||||
// registers are preserved. Explicitly preserve the scratch register
|
|
||||||
// in that case.
|
|
||||||
if (reason.isNative() && !scratch.volatile_())
|
if (reason.isNative() && !scratch.volatile_())
|
||||||
masm.Push(scratch);
|
masm.Push(scratch);
|
||||||
|
|
||||||
masm.loadWasmActivationFromTls(scratch);
|
LoadActivation(masm, scratch);
|
||||||
masm.wasmAssertNonExitInvariants(scratch);
|
masm.wasmAssertNonExitInvariants(scratch);
|
||||||
Address exitReason(scratch, WasmActivation::offsetOfExitReason());
|
Address exitReason(scratch, WasmActivation::offsetOfExitReason());
|
||||||
masm.store32(Imm32(reason.raw()), exitReason);
|
masm.store32(Imm32(reason.raw()), exitReason);
|
||||||
|
@ -357,13 +365,12 @@ GenerateCallableEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason
|
||||||
masm.addToStackPtr(Imm32(framePushed));
|
masm.addToStackPtr(Imm32(framePushed));
|
||||||
|
|
||||||
if (!reason.isNone()) {
|
if (!reason.isNone()) {
|
||||||
Register scratch = ABINonArgReturnReg0;
|
|
||||||
|
|
||||||
// See comment in GenerateCallablePrologue.
|
// See comment in GenerateCallablePrologue.
|
||||||
|
Register scratch = ABINonArgReturnReg0;
|
||||||
if (reason.isNative() && !scratch.volatile_())
|
if (reason.isNative() && !scratch.volatile_())
|
||||||
masm.Push(scratch);
|
masm.Push(scratch);
|
||||||
|
|
||||||
masm.loadWasmActivationFromTls(scratch);
|
LoadActivation(masm, scratch);
|
||||||
Address exitFP(scratch, WasmActivation::offsetOfExitFP());
|
Address exitFP(scratch, WasmActivation::offsetOfExitFP());
|
||||||
masm.storePtr(ImmWord(0), exitFP);
|
masm.storePtr(ImmWord(0), exitFP);
|
||||||
Address exitReason(scratch, WasmActivation::offsetOfExitReason());
|
Address exitReason(scratch, WasmActivation::offsetOfExitReason());
|
||||||
|
@ -963,3 +970,33 @@ wasm::LookupFaultingInstance(WasmActivation* activation, void* pc, void* fp)
|
||||||
MOZ_RELEASE_ASSERT(&instance->code() == code);
|
MOZ_RELEASE_ASSERT(&instance->code() == code);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WasmActivation*
|
||||||
|
wasm::MaybeActiveActivation(JSContext* cx)
|
||||||
|
{
|
||||||
|
// WasmCall pushes both an outer WasmActivation and an inner JitActivation
|
||||||
|
// that only becomes active when calling JIT code.
|
||||||
|
Activation* act = cx->activation();
|
||||||
|
while (act && act->isJit() && !act->asJit()->isActive())
|
||||||
|
act = act->prev();
|
||||||
|
if (!act || !act->isWasm())
|
||||||
|
return nullptr;
|
||||||
|
return act->asWasm();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
wasm::InCompiledCode(void* pc)
|
||||||
|
{
|
||||||
|
JSContext* cx = TlsContext.get();
|
||||||
|
if (!cx)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MOZ_RELEASE_ASSERT(!cx->handlingSegFault);
|
||||||
|
|
||||||
|
if (cx->compartment()->wasm.lookupCode(pc))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const CodeRange* codeRange;
|
||||||
|
uint8_t* codeBase;
|
||||||
|
return LookupBuiltinThunk(pc, &codeRange, &codeBase);
|
||||||
|
}
|
||||||
|
|
|
@ -187,6 +187,16 @@ TraceActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc)
|
||||||
Instance*
|
Instance*
|
||||||
LookupFaultingInstance(WasmActivation* activation, void* pc, void* fp);
|
LookupFaultingInstance(WasmActivation* activation, void* pc, void* fp);
|
||||||
|
|
||||||
|
// If the innermost (active) Activation is a WasmActivation, return it.
|
||||||
|
|
||||||
|
WasmActivation*
|
||||||
|
MaybeActiveActivation(JSContext* cx);
|
||||||
|
|
||||||
|
// Return whether the given PC is in wasm code.
|
||||||
|
|
||||||
|
bool
|
||||||
|
InCompiledCode(void* pc);
|
||||||
|
|
||||||
} // namespace wasm
|
} // namespace wasm
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
|
@ -858,14 +858,14 @@ HandleFault(PEXCEPTION_POINTERS exception)
|
||||||
return false;
|
return false;
|
||||||
AutoSetHandlingSegFault handling(cx);
|
AutoSetHandlingSegFault handling(cx);
|
||||||
|
|
||||||
WasmActivation* activation = cx->wasmActivationStack();
|
|
||||||
if (!activation)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const Code* code = activation->compartment()->wasm.lookupCode(pc);
|
const Code* code = activation->compartment()->wasm.lookupCode(pc);
|
||||||
if (!code)
|
if (!code)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
WasmActivation* activation = MaybeActiveActivation(cx);
|
||||||
|
if (!activation)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!code->segment().containsFunctionPC(pc)) {
|
if (!code->segment().containsFunctionPC(pc)) {
|
||||||
// On Windows, it is possible for InterruptRunningJitCode to execute
|
// On Windows, it is possible for InterruptRunningJitCode to execute
|
||||||
// between a faulting heap access and the handling of the fault due
|
// between a faulting heap access and the handling of the fault due
|
||||||
|
@ -1012,7 +1012,7 @@ HandleMachException(JSContext* cx, const ExceptionRequest& request)
|
||||||
if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2)
|
if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
WasmActivation* activation = cx->wasmActivationStack();
|
WasmActivation* activation = MaybeActiveActivation(cx);
|
||||||
if (!activation)
|
if (!activation)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1224,7 +1224,7 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
|
||||||
return false;
|
return false;
|
||||||
AutoSetHandlingSegFault handling(cx);
|
AutoSetHandlingSegFault handling(cx);
|
||||||
|
|
||||||
WasmActivation* activation = cx->wasmActivationStack();
|
WasmActivation* activation = MaybeActiveActivation(cx);
|
||||||
if (!activation)
|
if (!activation)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1332,38 +1332,54 @@ RedirectJitCodeToInterruptCheck(JSContext* cx, CONTEXT* context)
|
||||||
if (cx != cx->runtime()->activeContext())
|
if (cx != cx->runtime()->activeContext())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// The faulting thread is suspended so we can access cx fields that can
|
||||||
|
// normally only be accessed by the cx's active thread.
|
||||||
|
AutoNoteSingleThreadedRegion anstr;
|
||||||
|
|
||||||
RedirectIonBackedgesToInterruptCheck(cx);
|
RedirectIonBackedgesToInterruptCheck(cx);
|
||||||
|
|
||||||
if (WasmActivation* activation = cx->wasmActivationStack()) {
|
|
||||||
#ifdef JS_SIMULATOR
|
#ifdef JS_SIMULATOR
|
||||||
(void)ContextToPC(context); // silence static 'unused' errors
|
uint8_t* pc = cx->simulator()->get_pc_as<uint8_t*>();
|
||||||
|
|
||||||
void* pc = cx->simulator()->get_pc_as<void*>();
|
|
||||||
|
|
||||||
const Code* code = activation->compartment()->wasm.lookupCode(pc);
|
|
||||||
if (code && code->segment().containsFunctionPC(pc))
|
|
||||||
cx->simulator()->trigger_wasm_interrupt();
|
|
||||||
#else
|
#else
|
||||||
uint8_t** ppc = ContextToPC(context);
|
uint8_t* pc = *ContextToPC(context);
|
||||||
uint8_t* pc = *ppc;
|
|
||||||
uint8_t* fp = ContextToFP(context);
|
|
||||||
|
|
||||||
// Only interrupt in function code so that the frame iterators have the
|
|
||||||
// invariant that resumePC always has a function CodeRange and we can't
|
|
||||||
// get into any weird interrupt-during-interrupt-stub cases. Note that
|
|
||||||
// the out-of-bounds/unaligned trap paths which call startInterrupt() go
|
|
||||||
// through function code, so test if already interrupted. All these
|
|
||||||
// paths are temporary though, so this case can be removed later.
|
|
||||||
const Code* code = activation->compartment()->wasm.lookupCode(pc);
|
|
||||||
if (code && code->segment().containsFunctionPC(pc) && fp && !activation->interrupted()) {
|
|
||||||
activation->startInterrupt(pc, fp);
|
|
||||||
*ppc = code->segment().interruptCode();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
// Only interrupt in function code so that the frame iterators have the
|
||||||
|
// invariant that resumePC always has a function CodeRange and we can't
|
||||||
|
// get into any weird interrupt-during-interrupt-stub cases.
|
||||||
|
if (!cx->compartment())
|
||||||
|
return false;
|
||||||
|
const Code* code = cx->compartment()->wasm.lookupCode(pc);
|
||||||
|
if (!code || !code->segment().containsFunctionPC(pc))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Only probe cx->activation() via MaybeActiveActivation after we know the
|
||||||
|
// pc is in wasm code. This way we don't depend on signal-safe update of
|
||||||
|
// cx->activation().
|
||||||
|
WasmActivation* activation = MaybeActiveActivation(cx);
|
||||||
|
MOZ_ASSERT(activation);
|
||||||
|
|
||||||
|
#ifdef JS_SIMULATOR
|
||||||
|
// The checks performed by the !JS_SIMULATOR path happen in
|
||||||
|
// Simulator::handleWasmInterrupt.
|
||||||
|
cx->simulator()->trigger_wasm_interrupt();
|
||||||
|
#else
|
||||||
|
// fp may be null when first entering wasm code from an entry stub.
|
||||||
|
uint8_t* fp = ContextToFP(context);
|
||||||
|
if (!fp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The out-of-bounds/unaligned trap paths which call startInterrupt() go
|
||||||
|
// through function code, so test if already interrupted. These paths are
|
||||||
|
// temporary though, so this case can be removed later.
|
||||||
|
if (activation->interrupted())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
activation->startInterrupt(pc, fp);
|
||||||
|
*ContextToPC(context) = code->segment().interruptCode();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(XP_WIN)
|
#if !defined(XP_WIN)
|
||||||
|
@ -1577,24 +1593,3 @@ js::InterruptRunningJitCode(JSContext* cx)
|
||||||
pthread_kill(thread, sInterruptSignal);
|
pthread_kill(thread, sInterruptSignal);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_COLD bool
|
|
||||||
js::wasm::IsPCInWasmCode(void* pc)
|
|
||||||
{
|
|
||||||
JSContext* cx = TlsContext.get();
|
|
||||||
if (!cx)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
MOZ_RELEASE_ASSERT(!cx->handlingSegFault);
|
|
||||||
|
|
||||||
WasmActivation* activation = cx->wasmActivationStack();
|
|
||||||
if (!activation)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (activation->compartment()->wasm.lookupCode(pc))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
const CodeRange* codeRange;
|
|
||||||
uint8_t* codeBase;
|
|
||||||
return LookupBuiltinThunk(pc, &codeRange, &codeBase);
|
|
||||||
}
|
|
||||||
|
|
|
@ -72,10 +72,6 @@ class MachExceptionHandler
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Test whether the given PC is within the innermost wasm activation. Return
|
|
||||||
// false if it is not, or it cannot be determined.
|
|
||||||
bool IsPCInWasmCode(void *pc);
|
|
||||||
|
|
||||||
} // namespace wasm
|
} // namespace wasm
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче