Backed out changeset f56ef640d6c0 (bug 1428453) for failing web platform tests on /_mozilla/wasm/select.wast.js r=backout on a CLOSED TREE

This commit is contained in:
Dorel Luca 2018-01-11 02:17:12 +02:00
Родитель 2de79f83da
Коммит 4eaec4d64b
31 изменённых файлов: 164 добавлений и 643 удалений

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

@ -194,7 +194,7 @@ for (let type of ['f32', 'f64']) {
(func (export "") (call $foo)) (func (export "") (call $foo))
)`, )`,
WebAssembly.RuntimeError, WebAssembly.RuntimeError,
["", ">", "1,>", "0,1,>", "1,>", "", ">", ""]); ["", ">", "1,>", "0,1,>", "interstitial,0,1,>", "trap handling,0,1,>", "", ">", ""]);
testError( testError(
`(module `(module

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

@ -12350,7 +12350,7 @@ CodeGenerator::visitWasmTrap(LWasmTrap* lir)
MOZ_ASSERT(gen->compilingWasm()); MOZ_ASSERT(gen->compilingWasm());
const MWasmTrap* mir = lir->mir(); const MWasmTrap* mir = lir->mir();
masm.wasmTrap(mir->trap(), mir->bytecodeOffset()); masm.jump(oldTrap(mir, mir->trap()));
} }
void void

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

@ -2930,12 +2930,6 @@ MacroAssembler::maybeBranchTestType(MIRType type, MDefinition* maybeDef, Registe
} }
} }
void
MacroAssembler::wasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset)
{
append(trap, wasm::TrapSite(illegalInstruction().offset(), bytecodeOffset));
}
void void
MacroAssembler::wasmCallImport(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee) MacroAssembler::wasmCallImport(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee)
{ {

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

@ -1399,9 +1399,6 @@ class MacroAssembler : public MacroAssemblerSpecific
// ======================================================================== // ========================================================================
// wasm support // wasm support
CodeOffset illegalInstruction() PER_SHARED_ARCH;
void wasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset);
// Emit a bounds check against the wasm heap limit, jumping to 'label' if 'cond' holds. // Emit a bounds check against the wasm heap limit, jumping to 'label' if 'cond' holds.
// Required when WASM_HUGE_MEMORY is not defined. // Required when WASM_HUGE_MEMORY is not defined.
template <class L> template <class L>

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

@ -3005,14 +3005,6 @@ Assembler::as_bkpt()
hit++; hit++;
} }
BufferOffset
Assembler::as_illegal_trap()
{
// Encoding of the permanently-undefined 'udf' instruction, with the imm16
// set to 0.
return writeInst(0xe7f000f0);
}
void void
Assembler::flushBuffer() Assembler::flushBuffer()
{ {

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

@ -1733,7 +1733,6 @@ class Assembler : public AssemblerShared
static void Bind(uint8_t* rawCode, CodeOffset label, CodeOffset target); static void Bind(uint8_t* rawCode, CodeOffset label, CodeOffset target);
void as_bkpt(); void as_bkpt();
BufferOffset as_illegal_trap();
public: public:
static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);

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

@ -4911,12 +4911,6 @@ template void
MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType, MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType,
const BaseIndex& dest, MIRType slotType); const BaseIndex& dest, MIRType slotType);
CodeOffset
MacroAssembler::illegalInstruction()
{
return CodeOffset(as_illegal_trap().getOffset());
}
void void
MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry) MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry)
{ {

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

@ -260,11 +260,6 @@ class SimInstruction {
return typeValue() == 7 && bit(24) == 1 && svcValue() >= kStopCode; return typeValue() == 7 && bit(24) == 1 && svcValue() >= kStopCode;
} }
// Test for a udf instruction, which falls under type 3.
inline bool isUDF() const {
return (instructionBits() & 0xfff000f0) == 0xe7f000f0;
}
// Special accessors that test for existence of a value. // Special accessors that test for existence of a value.
inline bool hasS() const { return sValue() == 1; } inline bool hasS() const { return sValue() == 1; }
inline bool hasB() const { return bValue() == 1; } inline bool hasB() const { return bValue() == 1; }
@ -1588,16 +1583,6 @@ Simulator::handleWasmInterrupt()
set_pc(int32_t(cs->interruptCode())); set_pc(int32_t(cs->interruptCode()));
} }
static inline JitActivation*
GetJitActivation(JSContext* cx)
{
if (!wasm::CodeExists)
return nullptr;
if (!cx->activation() || !cx->activation()->isJit())
return nullptr;
return cx->activation()->asJit();
}
// WebAssembly memories contain an extra region of guard pages (see // WebAssembly memories contain an extra region of guard pages (see
// WasmArrayRawBuffer comment). The guard pages catch out-of-bounds accesses // WasmArrayRawBuffer comment). The guard pages catch out-of-bounds accesses
// using a signal handler that redirects PC to a stub that safely reports an // using a signal handler that redirects PC to a stub that safely reports an
@ -1605,11 +1590,13 @@ GetJitActivation(JSContext* cx)
// and cannot be redirected. Therefore, we must avoid hitting the handler by // and cannot be redirected. Therefore, we must avoid hitting the handler by
// redirecting in the simulator before the real handler would have been hit. // redirecting in the simulator before the real handler would have been hit.
bool bool
Simulator::handleWasmSegFault(int32_t addr, unsigned numBytes) Simulator::handleWasmFault(int32_t addr, unsigned numBytes)
{ {
JitActivation* act = GetJitActivation(cx_); if (!wasm::CodeExists)
if (!act)
return false; return false;
if (!cx_->activation() || !cx_->activation()->isJit())
return false;
JitActivation* act = cx_->activation()->asJit();
void* pc = reinterpret_cast<void*>(get_pc()); void* pc = reinterpret_cast<void*>(get_pc());
uint8_t* fp = reinterpret_cast<uint8_t*>(get_register(r11)); uint8_t* fp = reinterpret_cast<uint8_t*>(get_register(r11));
@ -1636,34 +1623,10 @@ Simulator::handleWasmSegFault(int32_t addr, unsigned numBytes)
return true; return true;
} }
bool
Simulator::handleWasmIllFault()
{
JitActivation* act = GetJitActivation(cx_);
if (!act)
return false;
void* pc = reinterpret_cast<void*>(get_pc());
uint8_t* fp = reinterpret_cast<uint8_t*>(get_register(r11));
const wasm::CodeSegment* segment = wasm::LookupCodeSegment(pc);
if (!segment)
return false;
wasm::Trap trap;
wasm::BytecodeOffset bytecode;
if (!segment->code().lookupTrap(pc, &trap, &bytecode))
return false;
act->startWasmTrap(trap, bytecode.offset, pc, fp);
set_pc(int32_t(segment->trapCode()));
return true;
}
uint64_t uint64_t
Simulator::readQ(int32_t addr, SimInstruction* instr, UnalignedPolicy f) Simulator::readQ(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
{ {
if (handleWasmSegFault(addr, 8)) if (handleWasmFault(addr, 8))
return UINT64_MAX; return UINT64_MAX;
if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) { if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
@ -1686,7 +1649,7 @@ Simulator::readQ(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
void void
Simulator::writeQ(int32_t addr, uint64_t value, SimInstruction* instr, UnalignedPolicy f) Simulator::writeQ(int32_t addr, uint64_t value, SimInstruction* instr, UnalignedPolicy f)
{ {
if (handleWasmSegFault(addr, 8)) if (handleWasmFault(addr, 8))
return; return;
if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) { if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
@ -1709,7 +1672,7 @@ Simulator::writeQ(int32_t addr, uint64_t value, SimInstruction* instr, Unaligned
int int
Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f) Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
{ {
if (handleWasmSegFault(addr, 4)) if (handleWasmFault(addr, 4))
return -1; return -1;
if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) { if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
@ -1735,7 +1698,7 @@ Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
void void
Simulator::writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolicy f) Simulator::writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolicy f)
{ {
if (handleWasmSegFault(addr, 4)) if (handleWasmFault(addr, 4))
return; return;
if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) { if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
@ -1780,7 +1743,7 @@ Simulator::readExW(int32_t addr, SimInstruction* instr)
if (addr & 3) if (addr & 3)
MOZ_CRASH("Unaligned exclusive read"); MOZ_CRASH("Unaligned exclusive read");
if (handleWasmSegFault(addr, 4)) if (handleWasmFault(addr, 4))
return -1; return -1;
SharedMem<int32_t*> ptr = SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr)); SharedMem<int32_t*> ptr = SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
@ -1795,7 +1758,7 @@ Simulator::writeExW(int32_t addr, int value, SimInstruction* instr)
if (addr & 3) if (addr & 3)
MOZ_CRASH("Unaligned exclusive write"); MOZ_CRASH("Unaligned exclusive write");
if (handleWasmSegFault(addr, 4)) if (handleWasmFault(addr, 4))
return -1; return -1;
SharedMem<int32_t*> ptr = SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr)); SharedMem<int32_t*> ptr = SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
@ -1810,7 +1773,7 @@ Simulator::writeExW(int32_t addr, int value, SimInstruction* instr)
uint16_t uint16_t
Simulator::readHU(int32_t addr, SimInstruction* instr) Simulator::readHU(int32_t addr, SimInstruction* instr)
{ {
if (handleWasmSegFault(addr, 2)) if (handleWasmFault(addr, 2))
return UINT16_MAX; return UINT16_MAX;
// The regexp engine emits unaligned loads, so we don't check for them here // The regexp engine emits unaligned loads, so we don't check for them here
@ -1836,7 +1799,7 @@ Simulator::readHU(int32_t addr, SimInstruction* instr)
int16_t int16_t
Simulator::readH(int32_t addr, SimInstruction* instr) Simulator::readH(int32_t addr, SimInstruction* instr)
{ {
if (handleWasmSegFault(addr, 2)) if (handleWasmFault(addr, 2))
return -1; return -1;
if ((addr & 1) == 0 || !HasAlignmentFault()) { if ((addr & 1) == 0 || !HasAlignmentFault()) {
@ -1860,7 +1823,7 @@ Simulator::readH(int32_t addr, SimInstruction* instr)
void void
Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr) Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr)
{ {
if (handleWasmSegFault(addr, 2)) if (handleWasmFault(addr, 2))
return; return;
if ((addr & 1) == 0 || !HasAlignmentFault()) { if ((addr & 1) == 0 || !HasAlignmentFault()) {
@ -1883,7 +1846,7 @@ Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr)
void void
Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr) Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr)
{ {
if (handleWasmSegFault(addr, 2)) if (handleWasmFault(addr, 2))
return; return;
if ((addr & 1) == 0 || !HasAlignmentFault()) { if ((addr & 1) == 0 || !HasAlignmentFault()) {
@ -1909,7 +1872,7 @@ Simulator::readExHU(int32_t addr, SimInstruction* instr)
if (addr & 1) if (addr & 1)
MOZ_CRASH("Unaligned exclusive read"); MOZ_CRASH("Unaligned exclusive read");
if (handleWasmSegFault(addr, 2)) if (handleWasmFault(addr, 2))
return UINT16_MAX; return UINT16_MAX;
SharedMem<uint16_t*> ptr = SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr)); SharedMem<uint16_t*> ptr = SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr));
@ -1924,7 +1887,7 @@ Simulator::writeExH(int32_t addr, uint16_t value, SimInstruction* instr)
if (addr & 1) if (addr & 1)
MOZ_CRASH("Unaligned exclusive write"); MOZ_CRASH("Unaligned exclusive write");
if (handleWasmSegFault(addr, 2)) if (handleWasmFault(addr, 2))
return -1; return -1;
SharedMem<uint16_t*> ptr = SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr)); SharedMem<uint16_t*> ptr = SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr));
@ -1939,7 +1902,7 @@ Simulator::writeExH(int32_t addr, uint16_t value, SimInstruction* instr)
uint8_t uint8_t
Simulator::readBU(int32_t addr) Simulator::readBU(int32_t addr)
{ {
if (handleWasmSegFault(addr, 1)) if (handleWasmFault(addr, 1))
return UINT8_MAX; return UINT8_MAX;
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
@ -1949,7 +1912,7 @@ Simulator::readBU(int32_t addr)
uint8_t uint8_t
Simulator::readExBU(int32_t addr) Simulator::readExBU(int32_t addr)
{ {
if (handleWasmSegFault(addr, 1)) if (handleWasmFault(addr, 1))
return UINT8_MAX; return UINT8_MAX;
SharedMem<uint8_t*> ptr = SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr)); SharedMem<uint8_t*> ptr = SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr));
@ -1961,7 +1924,7 @@ Simulator::readExBU(int32_t addr)
int32_t int32_t
Simulator::writeExB(int32_t addr, uint8_t value) Simulator::writeExB(int32_t addr, uint8_t value)
{ {
if (handleWasmSegFault(addr, 1)) if (handleWasmFault(addr, 1))
return -1; return -1;
SharedMem<uint8_t*> ptr = SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr)); SharedMem<uint8_t*> ptr = SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr));
@ -1976,7 +1939,7 @@ Simulator::writeExB(int32_t addr, uint8_t value)
int8_t int8_t
Simulator::readB(int32_t addr) Simulator::readB(int32_t addr)
{ {
if (handleWasmSegFault(addr, 1)) if (handleWasmFault(addr, 1))
return -1; return -1;
int8_t* ptr = reinterpret_cast<int8_t*>(addr); int8_t* ptr = reinterpret_cast<int8_t*>(addr);
@ -1986,7 +1949,7 @@ Simulator::readB(int32_t addr)
void void
Simulator::writeB(int32_t addr, uint8_t value) Simulator::writeB(int32_t addr, uint8_t value)
{ {
if (handleWasmSegFault(addr, 1)) if (handleWasmFault(addr, 1))
return; return;
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
@ -1996,7 +1959,7 @@ Simulator::writeB(int32_t addr, uint8_t value)
void void
Simulator::writeB(int32_t addr, int8_t value) Simulator::writeB(int32_t addr, int8_t value)
{ {
if (handleWasmSegFault(addr, 1)) if (handleWasmFault(addr, 1))
return; return;
int8_t* ptr = reinterpret_cast<int8_t*>(addr); int8_t* ptr = reinterpret_cast<int8_t*>(addr);
@ -2006,7 +1969,7 @@ Simulator::writeB(int32_t addr, int8_t value)
int32_t* int32_t*
Simulator::readDW(int32_t addr) Simulator::readDW(int32_t addr)
{ {
if (handleWasmSegFault(addr, 8)) if (handleWasmFault(addr, 8))
return nullptr; return nullptr;
if ((addr & 3) == 0) { if ((addr & 3) == 0) {
@ -2021,7 +1984,7 @@ Simulator::readDW(int32_t addr)
void void
Simulator::writeDW(int32_t addr, int32_t value1, int32_t value2) Simulator::writeDW(int32_t addr, int32_t value1, int32_t value2)
{ {
if (handleWasmSegFault(addr, 8)) if (handleWasmFault(addr, 8))
return; return;
if ((addr & 3) == 0) { if ((addr & 3) == 0) {
@ -2041,7 +2004,7 @@ Simulator::readExDW(int32_t addr, int32_t* hibits)
if (addr & 3) if (addr & 3)
MOZ_CRASH("Unaligned exclusive read"); MOZ_CRASH("Unaligned exclusive read");
if (handleWasmSegFault(addr, 8)) if (handleWasmFault(addr, 8))
return -1; return -1;
SharedMem<uint64_t*> ptr = SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr)); SharedMem<uint64_t*> ptr = SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr));
@ -2062,7 +2025,7 @@ Simulator::writeExDW(int32_t addr, int32_t value1, int32_t value2)
if (addr & 3) if (addr & 3)
MOZ_CRASH("Unaligned exclusive write"); MOZ_CRASH("Unaligned exclusive write");
if (handleWasmSegFault(addr, 8)) if (handleWasmFault(addr, 8))
return -1; return -1;
SharedMem<uint64_t*> ptr = SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr)); SharedMem<uint64_t*> ptr = SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr));
@ -3588,12 +3551,6 @@ rotateBytes(uint32_t val, int32_t rotate)
void void
Simulator::decodeType3(SimInstruction* instr) Simulator::decodeType3(SimInstruction* instr)
{ {
if (MOZ_UNLIKELY(instr->isUDF())) {
if (handleWasmIllFault())
return;
MOZ_CRASH("illegal instruction encountered");
}
int rd = instr->rdValue(); int rd = instr->rdValue();
int rn = instr->rnValue(); int rn = instr->rnValue();
int32_t rn_val = get_register(rn); int32_t rn_val = get_register(rn);

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

@ -296,8 +296,7 @@ class Simulator
void startWasmInterrupt(JitActivation* act); void startWasmInterrupt(JitActivation* act);
// Handle any wasm faults, returning true if the fault was handled. // Handle any wasm faults, returning true if the fault was handled.
bool handleWasmSegFault(int32_t addr, unsigned numBytes); bool handleWasmFault(int32_t addr, unsigned numBytes);
bool handleWasmIllFault();
// Read and write memory. // Read and write memory.
inline uint8_t readBU(int32_t addr); inline uint8_t readBU(int32_t addr);

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

@ -852,12 +852,6 @@ MacroAssembler::comment(const char* msg)
// ======================================================================== // ========================================================================
// wasm support // wasm support
CodeOffset
MacroAssembler::illegalInstruction()
{
MOZ_CRASH("NYI");
}
void void
MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry) MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry)
{ {

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

@ -1863,14 +1863,6 @@ MacroAssembler::comment(const char* msg)
Assembler::comment(msg); Assembler::comment(msg);
} }
// ===============================================================
// WebAssembly
CodeOffset
MacroAssembler::illegalInstruction()
{
MOZ_CRASH("NYI");
}
void void
MacroAssembler::wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry) MacroAssembler::wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry)

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

@ -871,7 +871,6 @@ class AssemblerShared
{ {
wasm::CallSiteVector callSites_; wasm::CallSiteVector callSites_;
wasm::CallSiteTargetVector callSiteTargets_; wasm::CallSiteTargetVector callSiteTargets_;
wasm::TrapSiteVectorArray trapSites_;
wasm::OldTrapSiteVector oldTrapSites_; wasm::OldTrapSiteVector oldTrapSites_;
wasm::OldTrapFarJumpVector oldTrapFarJumps_; wasm::OldTrapFarJumpVector oldTrapFarJumps_;
wasm::CallFarJumpVector callFarJumps_; wasm::CallFarJumpVector callFarJumps_;
@ -931,9 +930,6 @@ class AssemblerShared
enoughMemory_ &= callSites_.emplaceBack(desc, retAddr.offset()); enoughMemory_ &= callSites_.emplaceBack(desc, retAddr.offset());
enoughMemory_ &= callSiteTargets_.emplaceBack(mozilla::Forward<Args>(args)...); enoughMemory_ &= callSiteTargets_.emplaceBack(mozilla::Forward<Args>(args)...);
} }
void append(wasm::Trap trap, wasm::TrapSite site) {
enoughMemory_ &= trapSites_[trap].append(site);
}
void append(wasm::OldTrapSite trapSite) { void append(wasm::OldTrapSite trapSite) {
enoughMemory_ &= oldTrapSites_.append(trapSite); enoughMemory_ &= oldTrapSites_.append(trapSite);
} }
@ -970,7 +966,6 @@ class AssemblerShared
wasm::CallSiteVector& callSites() { return callSites_; } wasm::CallSiteVector& callSites() { return callSites_; }
wasm::CallSiteTargetVector& callSiteTargets() { return callSiteTargets_; } wasm::CallSiteTargetVector& callSiteTargets() { return callSiteTargets_; }
wasm::TrapSiteVectorArray& trapSites() { return trapSites_; }
wasm::OldTrapSiteVector& oldTrapSites() { return oldTrapSites_; } wasm::OldTrapSiteVector& oldTrapSites() { return oldTrapSites_; }
wasm::OldTrapFarJumpVector& oldTrapFarJumps() { return oldTrapFarJumps_; } wasm::OldTrapFarJumpVector& oldTrapFarJumps() { return oldTrapFarJumps_; }
wasm::CallFarJumpVector& callFarJumps() { return callFarJumps_; } wasm::CallFarJumpVector& callFarJumps() { return callFarJumps_; }

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

@ -1101,11 +1101,6 @@ class AssemblerX86Shared : public AssemblerShared
void breakpoint() { void breakpoint() {
masm.int3(); masm.int3();
} }
CodeOffset ud2() {
CodeOffset off(masm.currentOffset());
masm.ud2();
return off;
}
static bool HasSSE2() { return CPUInfo::IsSSE2Present(); } static bool HasSSE2() { return CPUInfo::IsSSE2Present(); }
static bool HasSSE3() { return CPUInfo::IsSSE3Present(); } static bool HasSSE3() { return CPUInfo::IsSSE3Present(); }

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

@ -668,14 +668,7 @@ MacroAssembler::pushFakeReturnAddress(Register scratch)
return retAddr; return retAddr;
} }
// =============================================================== // wasm specific methods, used in both the wasm baseline compiler and ion.
// WebAssembly
CodeOffset
MacroAssembler::illegalInstruction()
{
return ud2();
}
// RAII class that generates the jumps to traps when it's destructed, to // RAII class that generates the jumps to traps when it's destructed, to
// prevent some code duplication in the outOfLineWasmTruncateXtoY methods. // prevent some code duplication in the outOfLineWasmTruncateXtoY methods.

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

@ -20,6 +20,9 @@
#include "vm/ErrorReporting.h" #include "vm/ErrorReporting.h"
#include "vm/MallocProvider.h" #include "vm/MallocProvider.h"
#include "vm/Runtime.h" #include "vm/Runtime.h"
#ifdef XP_DARWIN
# include "wasm/WasmSignalHandlers.h"
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)

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

@ -11,7 +11,6 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/DoublyLinkedList.h" #include "mozilla/DoublyLinkedList.h"
#include "mozilla/LinkedList.h" #include "mozilla/LinkedList.h"
#include "mozilla/MaybeOneOf.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h" #include "mozilla/PodOperations.h"
#include "mozilla/Scoped.h" #include "mozilla/Scoped.h"
@ -50,7 +49,6 @@
#include "vm/Stack.h" #include "vm/Stack.h"
#include "vm/Stopwatch.h" #include "vm/Stopwatch.h"
#include "vm/Symbol.h" #include "vm/Symbol.h"
#include "wasm/WasmSignalHandlers.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
@ -1051,17 +1049,34 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
public: public:
js::RuntimeCaches& caches() { return caches_.ref(); } js::RuntimeCaches& caches() { return caches_.ref(); }
// When wasm traps or is interrupted, the signal handler records some data private:
// for unwinding purposes. Wasm code can't interrupt or trap reentrantly. // When wasm is interrupted, the pc at which we should return if the
js::ActiveThreadData< // interrupt hasn't stopped execution of the current running code. Since
mozilla::MaybeOneOf<js::wasm::TrapData, js::wasm::InterruptData> // this is used only by the interrupt handler and the latter is not
> wasmUnwindData; // reentrant, this value can't be clobbered so there is at most one
// resume PC at a time.
js::ActiveThreadData<void*> wasmResumePC_;
js::wasm::TrapData& wasmTrapData() { // To ensure a consistent state of fp/pc, the unwound pc might be
return wasmUnwindData.ref().ref<js::wasm::TrapData>(); // different from the resumePC, especially at call boundaries.
js::ActiveThreadData<void*> wasmUnwindPC_;
public:
void startWasmInterrupt(void* resumePC, void* unwindPC) {
MOZ_ASSERT(resumePC && unwindPC);
wasmResumePC_ = resumePC;
wasmUnwindPC_ = unwindPC;
} }
js::wasm::InterruptData& wasmInterruptData() { void finishWasmInterrupt() {
return wasmUnwindData.ref().ref<js::wasm::InterruptData>(); MOZ_ASSERT(wasmResumePC_ && wasmUnwindPC_);
wasmResumePC_ = nullptr;
wasmUnwindPC_ = nullptr;
}
void* wasmResumePC() const {
return wasmResumePC_;
}
void* wasmUnwindPC() const {
return wasmUnwindPC_;
} }
public: public:

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

@ -1552,7 +1552,6 @@ jit::JitActivation::~JitActivation()
MOZ_ASSERT(!bailoutData_); MOZ_ASSERT(!bailoutData_);
MOZ_ASSERT(!isWasmInterrupted()); MOZ_ASSERT(!isWasmInterrupted());
MOZ_ASSERT(!isWasmTrapping());
clearRematerializedFrames(); clearRematerializedFrames();
js_delete(rematerializedFrames_); js_delete(rematerializedFrames_);
@ -1726,8 +1725,9 @@ jit::JitActivation::startWasmInterrupt(const JS::ProfilingFrameIterator::Registe
MOZ_ASSERT(state.fp); MOZ_ASSERT(state.fp);
// Execution can only be interrupted in function code. Afterwards, control // Execution can only be interrupted in function code. Afterwards, control
// flow does not reenter function code and thus there can be no // flow does not reenter function code and thus there should be no
// interrupt-during-interrupt. // interrupt-during-interrupt.
MOZ_ASSERT(!isWasmInterrupted());
bool ignoredUnwound; bool ignoredUnwound;
wasm::UnwindState unwindState; wasm::UnwindState unwindState;
@ -1736,7 +1736,7 @@ jit::JitActivation::startWasmInterrupt(const JS::ProfilingFrameIterator::Registe
void* pc = unwindState.pc; void* pc = unwindState.pc;
MOZ_ASSERT(wasm::LookupCode(pc)->lookupRange(pc)->isFunction()); MOZ_ASSERT(wasm::LookupCode(pc)->lookupRange(pc)->isFunction());
cx_->runtime()->wasmUnwindData.ref().construct<wasm::InterruptData>(pc, state.pc); cx_->runtime()->startWasmInterrupt(state.pc, pc);
setWasmExitFP(unwindState.fp); setWasmExitFP(unwindState.fp);
MOZ_ASSERT(compartment() == unwindState.fp->tls->instance->compartment()); MOZ_ASSERT(compartment() == unwindState.fp->tls->instance->compartment());
@ -1746,17 +1746,18 @@ jit::JitActivation::startWasmInterrupt(const JS::ProfilingFrameIterator::Registe
void void
jit::JitActivation::finishWasmInterrupt() jit::JitActivation::finishWasmInterrupt()
{ {
MOZ_ASSERT(hasWasmExitFP());
MOZ_ASSERT(isWasmInterrupted()); MOZ_ASSERT(isWasmInterrupted());
cx_->runtime()->wasmUnwindData.ref().destroy(); cx_->runtime()->finishWasmInterrupt();
packedExitFP_ = nullptr; packedExitFP_ = nullptr;
} }
bool bool
jit::JitActivation::isWasmInterrupted() const jit::JitActivation::isWasmInterrupted() const
{ {
JSRuntime* rt = cx_->runtime(); void* pc = cx_->runtime()->wasmUnwindPC();
if (!rt->wasmUnwindData.ref().constructed<wasm::InterruptData>()) if (!pc)
return false; return false;
Activation* act = cx_->activation(); Activation* act = cx_->activation();
@ -1767,76 +1768,24 @@ jit::JitActivation::isWasmInterrupted() const
return false; return false;
DebugOnly<const wasm::Frame*> fp = wasmExitFP(); DebugOnly<const wasm::Frame*> fp = wasmExitFP();
DebugOnly<void*> unwindPC = rt->wasmInterruptData().unwindPC; MOZ_ASSERT(fp && fp->instance()->code().containsCodePC(pc));
MOZ_ASSERT(fp->instance()->code().containsCodePC(unwindPC));
return true; return true;
} }
void* void*
jit::JitActivation::wasmInterruptUnwindPC() const jit::JitActivation::wasmUnwindPC() const
{ {
MOZ_ASSERT(hasWasmExitFP());
MOZ_ASSERT(isWasmInterrupted()); MOZ_ASSERT(isWasmInterrupted());
return cx_->runtime()->wasmInterruptData().unwindPC; return cx_->runtime()->wasmUnwindPC();
} }
void* void*
jit::JitActivation::wasmInterruptResumePC() const jit::JitActivation::wasmResumePC() const
{ {
MOZ_ASSERT(hasWasmExitFP());
MOZ_ASSERT(isWasmInterrupted()); MOZ_ASSERT(isWasmInterrupted());
return cx_->runtime()->wasmInterruptData().resumePC; return cx_->runtime()->wasmResumePC();
}
void
jit::JitActivation::startWasmTrap(wasm::Trap trap, uint32_t bytecodeOffset, void* pc, void* fp)
{
MOZ_ASSERT(pc);
MOZ_ASSERT(fp);
cx_->runtime()->wasmUnwindData.ref().construct<wasm::TrapData>(pc, trap, bytecodeOffset);
setWasmExitFP((wasm::Frame*)fp);
}
void
jit::JitActivation::finishWasmTrap()
{
MOZ_ASSERT(isWasmTrapping());
cx_->runtime()->wasmUnwindData.ref().destroy();
packedExitFP_ = nullptr;
}
bool
jit::JitActivation::isWasmTrapping() const
{
JSRuntime* rt = cx_->runtime();
if (!rt->wasmUnwindData.ref().constructed<wasm::TrapData>())
return false;
Activation* act = cx_->activation();
while (act && !act->hasWasmExitFP())
act = act->prev();
if (act != this)
return false;
DebugOnly<const wasm::Frame*> fp = wasmExitFP();
DebugOnly<void*> unwindPC = rt->wasmTrapData().pc;
MOZ_ASSERT(fp->instance()->code().containsCodePC(unwindPC));
return true;
}
void*
jit::JitActivation::wasmTrapPC() const
{
MOZ_ASSERT(isWasmTrapping());
return cx_->runtime()->wasmTrapData().pc;
}
uint32_t
jit::JitActivation::wasmTrapBytecodeOffset() const
{
MOZ_ASSERT(isWasmTrapping());
return cx_->runtime()->wasmTrapData().bytecodeOffset;
} }
InterpreterFrameIterator& InterpreterFrameIterator&

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

@ -1666,18 +1666,11 @@ class JitActivation : public Activation
// Interrupts are started from the interrupt signal handler (or the ARM // Interrupts are started from the interrupt signal handler (or the ARM
// simulator) and cleared by WasmHandleExecutionInterrupt or WasmHandleThrow // simulator) and cleared by WasmHandleExecutionInterrupt or WasmHandleThrow
// when the interrupt is handled. // when the interrupt is handled.
void startWasmInterrupt(const JS::ProfilingFrameIterator::RegisterState& state); void startWasmInterrupt(const JS::ProfilingFrameIterator::RegisterState& state);
void finishWasmInterrupt(); void finishWasmInterrupt();
bool isWasmInterrupted() const; bool isWasmInterrupted() const;
void* wasmInterruptUnwindPC() const; void* wasmUnwindPC() const;
void* wasmInterruptResumePC() const; void* wasmResumePC() const;
void startWasmTrap(wasm::Trap trap, uint32_t bytecodeOffset, void* pc, void* fp);
void finishWasmTrap();
bool isWasmTrapping() const;
void* wasmTrapPC() const;
uint32_t wasmTrapBytecodeOffset() const;
}; };
// A filtering of the ActivationIterator to only stop at JitActivations. // A filtering of the ActivationIterator to only stop at JitActivations.

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

@ -3807,6 +3807,15 @@ class BaseCompiler final : public BaseCompilerInterface
#endif #endif
} }
void unreachableTrap()
{
masm.jump(oldTrap(Trap::Unreachable));
#ifdef DEBUG
masm.breakpoint();
#endif
}
MOZ_MUST_USE bool MOZ_MUST_USE bool
supportsRoundInstruction(RoundingMode mode) supportsRoundInstruction(RoundingMode mode)
{ {
@ -4896,10 +4905,6 @@ class BaseCompiler final : public BaseCompilerInterface
return iter_.bytecodeOffset(); return iter_.bytecodeOffset();
} }
void trap(Trap t) const {
masm.wasmTrap(t, bytecodeOffset());
}
OldTrapDesc oldTrap(Trap t) const { OldTrapDesc oldTrap(Trap t) const {
// Use masm.framePushed() because the value needed by the trap machinery // Use masm.framePushed() because the value needed by the trap machinery
// is the size of the frame overall, not the height of the stack area of // is the size of the frame overall, not the height of the stack area of
@ -8528,7 +8533,7 @@ BaseCompiler::emitBody()
case uint16_t(Op::Unreachable): case uint16_t(Op::Unreachable):
CHECK(iter_.readUnreachable()); CHECK(iter_.readUnreachable());
if (!deadCode_) { if (!deadCode_) {
trap(Trap::Unreachable); unreachableTrap();
deadCode_ = true; deadCode_ = true;
} }
NEXT(); NEXT();

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

@ -87,7 +87,7 @@ WasmHandleExecutionInterrupt()
// If CheckForInterrupt succeeded, then execution can proceed and the // If CheckForInterrupt succeeded, then execution can proceed and the
// interrupt is over. // interrupt is over.
void* resumePC = activation->wasmInterruptResumePC(); void* resumePC = activation->wasmResumePC();
activation->finishWasmInterrupt(); activation->finishWasmInterrupt();
return resumePC; return resumePC;
} }
@ -225,7 +225,6 @@ wasm::HandleThrow(JSContext* cx, WasmFrameIter& iter)
} }
MOZ_ASSERT(!cx->activation()->asJit()->isWasmInterrupted(), "unwinding clears the interrupt"); MOZ_ASSERT(!cx->activation()->asJit()->isWasmInterrupted(), "unwinding clears the interrupt");
MOZ_ASSERT(!cx->activation()->asJit()->isWasmTrapping(), "unwinding clears the trapping state");
return iter.unwoundAddressOfReturnAddress(); return iter.unwoundAddressOfReturnAddress();
} }
@ -289,13 +288,6 @@ WasmOldReportTrap(int32_t trapIndex)
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber); JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber);
} }
static void
WasmReportTrap()
{
Trap trap = TlsContext.get()->runtime()->wasmTrapData().trap;
WasmOldReportTrap(int32_t(trap));
}
static void static void
WasmReportOutOfBounds() WasmReportOutOfBounds()
{ {
@ -452,9 +444,6 @@ AddressOf(SymbolicAddress imm, ABIFunctionType* abiType)
case SymbolicAddress::HandleThrow: case SymbolicAddress::HandleThrow:
*abiType = Args_General0; *abiType = Args_General0;
return FuncCast(WasmHandleThrow, *abiType); return FuncCast(WasmHandleThrow, *abiType);
case SymbolicAddress::ReportTrap:
*abiType = Args_General0;
return FuncCast(WasmReportTrap, *abiType);
case SymbolicAddress::OldReportTrap: case SymbolicAddress::OldReportTrap:
*abiType = Args_General1; *abiType = Args_General1;
return FuncCast(WasmOldReportTrap, *abiType); return FuncCast(WasmOldReportTrap, *abiType);
@ -611,7 +600,6 @@ wasm::NeedsBuiltinThunk(SymbolicAddress sym)
case SymbolicAddress::HandleExecutionInterrupt: // GenerateInterruptExit case SymbolicAddress::HandleExecutionInterrupt: // GenerateInterruptExit
case SymbolicAddress::HandleDebugTrap: // GenerateDebugTrapStub case SymbolicAddress::HandleDebugTrap: // GenerateDebugTrapStub
case SymbolicAddress::HandleThrow: // GenerateThrowStub case SymbolicAddress::HandleThrow: // GenerateThrowStub
case SymbolicAddress::ReportTrap: // GenerateTrapExit
case SymbolicAddress::OldReportTrap: // GenerateOldTrapExit case SymbolicAddress::OldReportTrap: // GenerateOldTrapExit
case SymbolicAddress::ReportOutOfBounds: // GenerateOutOfBoundsExit case SymbolicAddress::ReportOutOfBounds: // GenerateOutOfBoundsExit
case SymbolicAddress::ReportUnalignedAccess: // GeneratesUnalignedExit case SymbolicAddress::ReportUnalignedAccess: // GeneratesUnalignedExit
@ -908,7 +896,6 @@ wasm::EnsureBuiltinThunksInitialized()
MOZ_ASSERT(masm.callSites().empty()); MOZ_ASSERT(masm.callSites().empty());
MOZ_ASSERT(masm.callSiteTargets().empty()); MOZ_ASSERT(masm.callSiteTargets().empty());
MOZ_ASSERT(masm.callFarJumps().empty()); MOZ_ASSERT(masm.callFarJumps().empty());
MOZ_ASSERT(masm.trapSites().empty());
MOZ_ASSERT(masm.oldTrapSites().empty()); MOZ_ASSERT(masm.oldTrapSites().empty());
MOZ_ASSERT(masm.oldTrapFarJumps().empty()); MOZ_ASSERT(masm.oldTrapFarJumps().empty());
MOZ_ASSERT(masm.callFarJumps().empty()); MOZ_ASSERT(masm.callFarJumps().empty());

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

@ -242,6 +242,9 @@ CodeSegment::create(Tier tier,
const Metadata& metadata) const Metadata& metadata)
{ {
// These should always exist and should never be first in the code segment. // These should always exist and should never be first in the code segment.
MOZ_ASSERT(linkData.interruptOffset != 0);
MOZ_ASSERT(linkData.outOfBoundsOffset != 0);
MOZ_ASSERT(linkData.unalignedAccessOffset != 0);
auto cs = js::MakeUnique<CodeSegment>(); auto cs = js::MakeUnique<CodeSegment>();
if (!cs) if (!cs)
@ -265,7 +268,6 @@ CodeSegment::initialize(Tier tier,
MOZ_ASSERT(linkData.interruptOffset); MOZ_ASSERT(linkData.interruptOffset);
MOZ_ASSERT(linkData.outOfBoundsOffset); MOZ_ASSERT(linkData.outOfBoundsOffset);
MOZ_ASSERT(linkData.unalignedAccessOffset); MOZ_ASSERT(linkData.unalignedAccessOffset);
MOZ_ASSERT(linkData.trapOffset);
tier_ = tier; tier_ = tier;
bytes_ = Move(codeBytes); bytes_ = Move(codeBytes);
@ -273,7 +275,6 @@ CodeSegment::initialize(Tier tier,
interruptCode_ = bytes_.get() + linkData.interruptOffset; interruptCode_ = bytes_.get() + linkData.interruptOffset;
outOfBoundsCode_ = bytes_.get() + linkData.outOfBoundsOffset; outOfBoundsCode_ = bytes_.get() + linkData.outOfBoundsOffset;
unalignedAccessCode_ = bytes_.get() + linkData.unalignedAccessOffset; unalignedAccessCode_ = bytes_.get() + linkData.unalignedAccessOffset;
trapCode_ = bytes_.get() + linkData.trapOffset;
if (!StaticallyLink(*this, linkData)) if (!StaticallyLink(*this, linkData))
return false; return false;
@ -458,7 +459,6 @@ MetadataTier::serializedSize() const
return SerializedPodVectorSize(memoryAccesses) + return SerializedPodVectorSize(memoryAccesses) +
SerializedPodVectorSize(codeRanges) + SerializedPodVectorSize(codeRanges) +
SerializedPodVectorSize(callSites) + SerializedPodVectorSize(callSites) +
trapSites.serializedSize() +
SerializedVectorSize(funcImports) + SerializedVectorSize(funcImports) +
SerializedVectorSize(funcExports); SerializedVectorSize(funcExports);
} }
@ -469,7 +469,6 @@ MetadataTier::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
return memoryAccesses.sizeOfExcludingThis(mallocSizeOf) + return memoryAccesses.sizeOfExcludingThis(mallocSizeOf) +
codeRanges.sizeOfExcludingThis(mallocSizeOf) + codeRanges.sizeOfExcludingThis(mallocSizeOf) +
callSites.sizeOfExcludingThis(mallocSizeOf) + callSites.sizeOfExcludingThis(mallocSizeOf) +
trapSites.sizeOfExcludingThis(mallocSizeOf) +
SizeOfVectorExcludingThis(funcImports, mallocSizeOf) + SizeOfVectorExcludingThis(funcImports, mallocSizeOf) +
SizeOfVectorExcludingThis(funcExports, mallocSizeOf); SizeOfVectorExcludingThis(funcExports, mallocSizeOf);
} }
@ -481,7 +480,6 @@ MetadataTier::serialize(uint8_t* cursor) const
cursor = SerializePodVector(cursor, memoryAccesses); cursor = SerializePodVector(cursor, memoryAccesses);
cursor = SerializePodVector(cursor, codeRanges); cursor = SerializePodVector(cursor, codeRanges);
cursor = SerializePodVector(cursor, callSites); cursor = SerializePodVector(cursor, callSites);
cursor = trapSites.serialize(cursor);
cursor = SerializeVector(cursor, funcImports); cursor = SerializeVector(cursor, funcImports);
cursor = SerializeVector(cursor, funcExports); cursor = SerializeVector(cursor, funcExports);
return cursor; return cursor;
@ -493,7 +491,6 @@ MetadataTier::deserialize(const uint8_t* cursor)
(cursor = DeserializePodVector(cursor, &memoryAccesses)) && (cursor = DeserializePodVector(cursor, &memoryAccesses)) &&
(cursor = DeserializePodVector(cursor, &codeRanges)) && (cursor = DeserializePodVector(cursor, &codeRanges)) &&
(cursor = DeserializePodVector(cursor, &callSites)) && (cursor = DeserializePodVector(cursor, &callSites)) &&
(cursor = trapSites.deserialize(cursor)) &&
(cursor = DeserializeVector(cursor, &funcImports)) && (cursor = DeserializeVector(cursor, &funcImports)) &&
(cursor = DeserializeVector(cursor, &funcExports)); (cursor = DeserializeVector(cursor, &funcExports));
debugTrapFarJumpOffsets.clear(); debugTrapFarJumpOffsets.clear();
@ -753,7 +750,7 @@ Code::segment(Tier tier) const
bool bool
Code::containsCodePC(const void* pc) const Code::containsCodePC(const void* pc) const
{ {
for (Tier t : tiers()) { for (auto t : tiers()) {
const CodeSegment& cs = segment(t); const CodeSegment& cs = segment(t);
if (cs.containsCodePC(pc)) if (cs.containsCodePC(pc))
return true; return true;
@ -773,7 +770,7 @@ struct CallSiteRetAddrOffset
const CallSite* const CallSite*
Code::lookupCallSite(void* returnAddress) const Code::lookupCallSite(void* returnAddress) const
{ {
for (Tier t : tiers()) { for (auto t : tiers()) {
uint32_t target = ((uint8_t*)returnAddress) - segment(t).base(); uint32_t target = ((uint8_t*)returnAddress) - segment(t).base();
size_t lowerBound = 0; size_t lowerBound = 0;
size_t upperBound = metadata(t).callSites.length(); size_t upperBound = metadata(t).callSites.length();
@ -790,7 +787,7 @@ Code::lookupCallSite(void* returnAddress) const
const CodeRange* const CodeRange*
Code::lookupRange(void* pc) const Code::lookupRange(void* pc) const
{ {
for (Tier t : tiers()) { for (auto t : tiers()) {
CodeRange::OffsetInCode target((uint8_t*)pc - segment(t).base()); CodeRange::OffsetInCode target((uint8_t*)pc - segment(t).base());
const CodeRange* result = LookupInSorted(metadata(t).codeRanges, target); const CodeRange* result = LookupInSorted(metadata(t).codeRanges, target);
if (result) if (result)
@ -812,7 +809,7 @@ struct MemoryAccessOffset
const MemoryAccess* const MemoryAccess*
Code::lookupMemoryAccess(void* pc) const Code::lookupMemoryAccess(void* pc) const
{ {
for (Tier t : tiers()) { for (auto t : tiers()) {
const MemoryAccessVector& memoryAccesses = metadata(t).memoryAccesses; const MemoryAccessVector& memoryAccesses = metadata(t).memoryAccesses;
uint32_t target = ((uint8_t*)pc) - segment(t).base(); uint32_t target = ((uint8_t*)pc) - segment(t).base();
@ -830,40 +827,6 @@ Code::lookupMemoryAccess(void* pc) const
return nullptr; return nullptr;
} }
struct TrapSitePCOffset
{
const TrapSiteVector& trapSites;
explicit TrapSitePCOffset(const TrapSiteVector& trapSites) : trapSites(trapSites) {}
uint32_t operator[](size_t index) const {
return trapSites[index].pcOffset;
}
};
bool
Code::lookupTrap(void* pc, Trap* trapOut, BytecodeOffset* bytecode) const
{
for (Tier t : tiers()) {
const TrapSiteVectorArray& trapSitesArray = metadata(t).trapSites;
for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
const TrapSiteVector& trapSites = trapSitesArray[trap];
uint32_t target = ((uint8_t*)pc) - segment(t).base();
size_t lowerBound = 0;
size_t upperBound = trapSites.length();
size_t match;
if (BinarySearch(TrapSitePCOffset(trapSites), lowerBound, upperBound, target, &match)) {
MOZ_ASSERT(segment(t).containsCodePC(pc));
*trapOut = trap;
*bytecode = trapSites[match].bytecode;
return true;
}
}
}
return false;
}
// When enabled, generate profiling labels for every name in funcNames_ that is // When enabled, generate profiling labels for every name in funcNames_ that is
// the name of some Function CodeRange. This involves malloc() so do it now // the name of some Function CodeRange. This involves malloc() so do it now
// since, once we start sampling, we'll be in a signal-handing context where we // since, once we start sampling, we'll be in a signal-handing context where we

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

@ -81,7 +81,6 @@ class CodeSegment
uint8_t* interruptCode_; uint8_t* interruptCode_;
uint8_t* outOfBoundsCode_; uint8_t* outOfBoundsCode_;
uint8_t* unalignedAccessCode_; uint8_t* unalignedAccessCode_;
uint8_t* trapCode_;
bool registered_; bool registered_;
@ -109,7 +108,6 @@ class CodeSegment
interruptCode_(nullptr), interruptCode_(nullptr),
outOfBoundsCode_(nullptr), outOfBoundsCode_(nullptr),
unalignedAccessCode_(nullptr), unalignedAccessCode_(nullptr),
trapCode_(nullptr),
registered_(false) registered_(false)
{} {}
@ -141,7 +139,6 @@ class CodeSegment
uint8_t* interruptCode() const { return interruptCode_; } uint8_t* interruptCode() const { return interruptCode_; }
uint8_t* outOfBoundsCode() const { return outOfBoundsCode_; } uint8_t* outOfBoundsCode() const { return outOfBoundsCode_; }
uint8_t* unalignedAccessCode() const { return unalignedAccessCode_; } uint8_t* unalignedAccessCode() const { return unalignedAccessCode_; }
uint8_t* trapCode() const { return trapCode_; }
bool containsCodePC(const void* pc) const { bool containsCodePC(const void* pc) const {
return pc >= base() && pc < (base() + length_); return pc >= base() && pc < (base() + length_);
@ -354,7 +351,6 @@ struct MetadataTier
MemoryAccessVector memoryAccesses; MemoryAccessVector memoryAccesses;
CodeRangeVector codeRanges; CodeRangeVector codeRanges;
CallSiteVector callSites; CallSiteVector callSites;
TrapSiteVectorArray trapSites;
FuncImportVector funcImports; FuncImportVector funcImports;
FuncExportVector funcExports; FuncExportVector funcExports;
@ -492,7 +488,6 @@ class Code : public ShareableBase<Code>
const CodeRange* lookupRange(void* pc) const; const CodeRange* lookupRange(void* pc) const;
const MemoryAccess* lookupMemoryAccess(void* pc) const; const MemoryAccess* lookupMemoryAccess(void* pc) const;
bool containsCodePC(const void* pc) const; bool containsCodePC(const void* pc) const;
bool lookupTrap(void* pc, Trap* trap, BytecodeOffset* bytecode) const;
// To save memory, profilingLabels_ are generated lazily when profiling mode // To save memory, profilingLabels_ are generated lazily when profiling mode
// is enabled. // is enabled.

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

@ -42,23 +42,6 @@ WasmFrameIter::WasmFrameIter(JitActivation* activation, wasm::Frame* fp)
{ {
MOZ_ASSERT(fp_); MOZ_ASSERT(fp_);
// When the stack is captured during a trap (viz., to create the .stack
// for an Error object), use the pc/bytecode information captured by the
// signal handler in the runtime.
if (activation->isWasmTrapping()) {
code_ = &fp_->tls->instance->code();
MOZ_ASSERT(code_ == LookupCode(activation->wasmTrapPC()));
codeRange_ = code_->lookupRange(activation->wasmTrapPC());
MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
lineOrBytecode_ = activation->wasmTrapBytecodeOffset();
MOZ_ASSERT(!done());
return;
}
// When asynchronously interrupted, exitFP is set to the interrupted frame // When asynchronously interrupted, exitFP is set to the interrupted frame
// itself and so we do not want to skip it. Instead, we can recover the // itself and so we do not want to skip it. Instead, we can recover the
// Code and CodeRange from the JitActivation, which are set when control // Code and CodeRange from the JitActivation, which are set when control
@ -69,9 +52,9 @@ WasmFrameIter::WasmFrameIter(JitActivation* activation, wasm::Frame* fp)
if (activation->isWasmInterrupted()) { if (activation->isWasmInterrupted()) {
code_ = &fp_->tls->instance->code(); code_ = &fp_->tls->instance->code();
MOZ_ASSERT(code_ == LookupCode(activation->wasmInterruptUnwindPC())); MOZ_ASSERT(code_ == LookupCode(activation->wasmUnwindPC()));
codeRange_ = code_->lookupRange(activation->wasmInterruptUnwindPC()); codeRange_ = code_->lookupRange(activation->wasmUnwindPC());
MOZ_ASSERT(codeRange_->kind() == CodeRange::Function); MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
lineOrBytecode_ = codeRange_->funcLineOrBytecode(); lineOrBytecode_ = codeRange_->funcLineOrBytecode();
@ -115,8 +98,6 @@ WasmFrameIter::operator++()
if (unwind_ == Unwind::True) { if (unwind_ == Unwind::True) {
if (activation_->isWasmInterrupted()) if (activation_->isWasmInterrupted())
activation_->finishWasmInterrupt(); activation_->finishWasmInterrupt();
else if (activation_->isWasmTrapping())
activation_->finishWasmTrap();
activation_->setWasmExitFP(fp_); activation_->setWasmExitFP(fp_);
} }
@ -643,7 +624,6 @@ ProfilingFrameIterator::initFromExitFP(const Frame* fp)
case CodeRange::ImportJitExit: case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit: case CodeRange::ImportInterpExit:
case CodeRange::BuiltinThunk: case CodeRange::BuiltinThunk:
case CodeRange::TrapExit:
case CodeRange::OldTrapExit: case CodeRange::OldTrapExit:
case CodeRange::DebugTrap: case CodeRange::DebugTrap:
case CodeRange::OutOfBoundsExit: case CodeRange::OutOfBoundsExit:
@ -814,7 +794,6 @@ js::wasm::StartUnwinding(const RegisterState& registers, UnwindState* unwindStat
break; break;
} }
break; break;
case CodeRange::TrapExit:
case CodeRange::OutOfBoundsExit: case CodeRange::OutOfBoundsExit:
case CodeRange::UnalignedExit: case CodeRange::UnalignedExit:
// These code stubs execute after the prologue/epilogue have completed // These code stubs execute after the prologue/epilogue have completed
@ -923,7 +902,6 @@ ProfilingFrameIterator::operator++()
case CodeRange::ImportJitExit: case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit: case CodeRange::ImportInterpExit:
case CodeRange::BuiltinThunk: case CodeRange::BuiltinThunk:
case CodeRange::TrapExit:
case CodeRange::OldTrapExit: case CodeRange::OldTrapExit:
case CodeRange::DebugTrap: case CodeRange::DebugTrap:
case CodeRange::OutOfBoundsExit: case CodeRange::OutOfBoundsExit:
@ -952,7 +930,6 @@ ThunkedNativeToDescription(SymbolicAddress func)
case SymbolicAddress::HandleExecutionInterrupt: case SymbolicAddress::HandleExecutionInterrupt:
case SymbolicAddress::HandleDebugTrap: case SymbolicAddress::HandleDebugTrap:
case SymbolicAddress::HandleThrow: case SymbolicAddress::HandleThrow:
case SymbolicAddress::ReportTrap:
case SymbolicAddress::OldReportTrap: case SymbolicAddress::OldReportTrap:
case SymbolicAddress::ReportOutOfBounds: case SymbolicAddress::ReportOutOfBounds:
case SymbolicAddress::ReportUnalignedAccess: case SymbolicAddress::ReportUnalignedAccess:
@ -1083,7 +1060,6 @@ ProfilingFrameIterator::label() const
case CodeRange::ImportJitExit: return importJitDescription; case CodeRange::ImportJitExit: return importJitDescription;
case CodeRange::BuiltinThunk: return builtinNativeDescription; case CodeRange::BuiltinThunk: return builtinNativeDescription;
case CodeRange::ImportInterpExit: return importInterpDescription; case CodeRange::ImportInterpExit: return importInterpDescription;
case CodeRange::TrapExit: return trapDescription;
case CodeRange::OldTrapExit: return trapDescription; case CodeRange::OldTrapExit: return trapDescription;
case CodeRange::DebugTrap: return debugTrapDescription; case CodeRange::DebugTrap: return debugTrapDescription;
case CodeRange::OutOfBoundsExit: return "out-of-bounds stub (in wasm)"; case CodeRange::OutOfBoundsExit: return "out-of-bounds stub (in wasm)";

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

@ -47,7 +47,6 @@ CompiledCode::swap(MacroAssembler& masm)
callSites.swap(masm.callSites()); callSites.swap(masm.callSites());
callSiteTargets.swap(masm.callSiteTargets()); callSiteTargets.swap(masm.callSiteTargets());
trapSites.swap(masm.trapSites());
oldTrapSites.swap(masm.oldTrapSites()); oldTrapSites.swap(masm.oldTrapSites());
callFarJumps.swap(masm.callFarJumps()); callFarJumps.swap(masm.callFarJumps());
oldTrapFarJumps.swap(masm.oldTrapFarJumps()); oldTrapFarJumps.swap(masm.oldTrapFarJumps());
@ -381,7 +380,7 @@ InRange(uint32_t caller, uint32_t callee)
} }
typedef HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy> OffsetMap; typedef HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy> OffsetMap;
typedef EnumeratedArray<Trap, Trap::Limit, Maybe<uint32_t>> TrapMaybeOffsetArray; typedef EnumeratedArray<Trap, Trap::Limit, Maybe<uint32_t>> TrapOffsetArray;
bool bool
ModuleGenerator::linkCallSites() ModuleGenerator::linkCallSites()
@ -400,7 +399,7 @@ ModuleGenerator::linkCallSites()
if (!existingCallFarJumps.init()) if (!existingCallFarJumps.init())
return false; return false;
TrapMaybeOffsetArray existingTrapFarJumps; TrapOffsetArray existingTrapFarJumps;
for (; lastPatchedCallSite_ < metadataTier_->callSites.length(); lastPatchedCallSite_++) { for (; lastPatchedCallSite_ < metadataTier_->callSites.length(); lastPatchedCallSite_++) {
const CallSite& callSite = metadataTier_->callSites[lastPatchedCallSite_]; const CallSite& callSite = metadataTier_->callSites[lastPatchedCallSite_];
@ -524,10 +523,6 @@ ModuleGenerator::noteCodeRange(uint32_t codeRangeIndex, const CodeRange& codeRan
MOZ_ASSERT(!linkDataTier_->interruptOffset); MOZ_ASSERT(!linkDataTier_->interruptOffset);
linkDataTier_->interruptOffset = codeRange.begin(); linkDataTier_->interruptOffset = codeRange.begin();
break; break;
case CodeRange::TrapExit:
MOZ_ASSERT(!linkDataTier_->trapOffset);
linkDataTier_->trapOffset = codeRange.begin();
break;
case CodeRange::Throw: case CodeRange::Throw:
// Jumped to by other stubs, so nothing to do. // Jumped to by other stubs, so nothing to do.
break; break;
@ -585,12 +580,6 @@ ModuleGenerator::linkCompiledCode(const CompiledCode& code)
if (!callSiteTargets_.appendAll(code.callSiteTargets)) if (!callSiteTargets_.appendAll(code.callSiteTargets))
return false; return false;
for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
auto trapSiteOp = [=](uint32_t, TrapSite* ts) { ts->offsetBy(offsetInModule); };
if (!AppendForEach(&metadataTier_->trapSites[trap], code.trapSites[trap], trapSiteOp))
return false;
}
MOZ_ASSERT(code.oldTrapSites.empty()); MOZ_ASSERT(code.oldTrapSites.empty());
auto trapFarJumpOp = [=](uint32_t, OldTrapFarJump* tfj) { tfj->offsetBy(offsetInModule); }; auto trapFarJumpOp = [=](uint32_t, OldTrapFarJump* tfj) { tfj->offsetBy(offsetInModule); };
@ -809,7 +798,6 @@ ModuleGenerator::finishCode()
MOZ_ASSERT(masm_.callSites().empty()); MOZ_ASSERT(masm_.callSites().empty());
MOZ_ASSERT(masm_.callSiteTargets().empty()); MOZ_ASSERT(masm_.callSiteTargets().empty());
MOZ_ASSERT(masm_.trapSites().empty());
MOZ_ASSERT(masm_.oldTrapSites().empty()); MOZ_ASSERT(masm_.oldTrapSites().empty());
MOZ_ASSERT(masm_.oldTrapFarJumps().empty()); MOZ_ASSERT(masm_.oldTrapFarJumps().empty());
MOZ_ASSERT(masm_.callFarJumps().empty()); MOZ_ASSERT(masm_.callFarJumps().empty());
@ -824,32 +812,19 @@ ModuleGenerator::finishCode()
bool bool
ModuleGenerator::finishMetadata(const ShareableBytes& bytecode) ModuleGenerator::finishMetadata(const ShareableBytes& bytecode)
{ {
// Assert all sorted metadata is sorted.
#ifdef DEBUG #ifdef DEBUG
uint32_t last = 0; // Assert CodeRanges are sorted.
uint32_t lastEnd = 0;
for (const CodeRange& codeRange : metadataTier_->codeRanges) { for (const CodeRange& codeRange : metadataTier_->codeRanges) {
MOZ_ASSERT(codeRange.begin() >= last); MOZ_ASSERT(codeRange.begin() >= lastEnd);
last = codeRange.end(); lastEnd = codeRange.end();
} }
last = 0; // Assert debugTrapFarJumpOffsets are sorted.
for (const CallSite& callSite : metadataTier_->callSites) { uint32_t lastOffset = 0;
MOZ_ASSERT(callSite.returnAddressOffset() >= last);
last = callSite.returnAddressOffset();
}
for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
last = 0;
for (const TrapSite& trapSite : metadataTier_->trapSites[trap]) {
MOZ_ASSERT(trapSite.pcOffset >= last);
last = trapSite.pcOffset;
}
}
last = 0;
for (uint32_t debugTrapFarJumpOffset : metadataTier_->debugTrapFarJumpOffsets) { for (uint32_t debugTrapFarJumpOffset : metadataTier_->debugTrapFarJumpOffsets) {
MOZ_ASSERT(debugTrapFarJumpOffset >= last); MOZ_ASSERT(debugTrapFarJumpOffset >= lastOffset);
last = debugTrapFarJumpOffset; lastOffset = debugTrapFarJumpOffset;
} }
#endif #endif
@ -874,7 +849,7 @@ ModuleGenerator::finishMetadata(const ShareableBytes& bytecode)
metadataTier_->memoryAccesses.podResizeToFit(); metadataTier_->memoryAccesses.podResizeToFit();
metadataTier_->codeRanges.podResizeToFit(); metadataTier_->codeRanges.podResizeToFit();
metadataTier_->trapSites.podResizeToFit(); metadataTier_->callSites.podResizeToFit();
metadataTier_->debugTrapFarJumpOffsets.podResizeToFit(); metadataTier_->debugTrapFarJumpOffsets.podResizeToFit();
metadataTier_->debugFuncToCodeRange.podResizeToFit(); metadataTier_->debugFuncToCodeRange.podResizeToFit();

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

@ -64,7 +64,6 @@ struct CompiledCode
CodeRangeVector codeRanges; CodeRangeVector codeRanges;
CallSiteVector callSites; CallSiteVector callSites;
CallSiteTargetVector callSiteTargets; CallSiteTargetVector callSiteTargets;
TrapSiteVectorArray trapSites;
OldTrapSiteVector oldTrapSites; OldTrapSiteVector oldTrapSites;
OldTrapFarJumpVector oldTrapFarJumps; OldTrapFarJumpVector oldTrapFarJumps;
CallFarJumpVector callFarJumps; CallFarJumpVector callFarJumps;
@ -79,7 +78,6 @@ struct CompiledCode
codeRanges.clear(); codeRanges.clear();
callSites.clear(); callSites.clear();
callSiteTargets.clear(); callSiteTargets.clear();
trapSites.clear();
oldTrapSites.clear(); oldTrapSites.clear();
oldTrapFarJumps.clear(); oldTrapFarJumps.clear();
callFarJumps.clear(); callFarJumps.clear();
@ -94,7 +92,6 @@ struct CompiledCode
codeRanges.empty() && codeRanges.empty() &&
callSites.empty() && callSites.empty() &&
callSiteTargets.empty() && callSiteTargets.empty() &&
trapSites.empty() &&
oldTrapSites.empty() && oldTrapSites.empty() &&
oldTrapFarJumps.empty() && oldTrapFarJumps.empty() &&
callFarJumps.empty() && callFarJumps.empty() &&

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

@ -45,7 +45,6 @@ struct LinkDataTierCacheablePod
uint32_t interruptOffset; uint32_t interruptOffset;
uint32_t outOfBoundsOffset; uint32_t outOfBoundsOffset;
uint32_t unalignedAccessOffset; uint32_t unalignedAccessOffset;
uint32_t trapOffset;
LinkDataTierCacheablePod() { mozilla::PodZero(this); } LinkDataTierCacheablePod() { mozilla::PodZero(this); }
}; };

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

@ -975,15 +975,15 @@ HandleFault(PEXCEPTION_POINTERS exception)
EXCEPTION_RECORD* record = exception->ExceptionRecord; EXCEPTION_RECORD* record = exception->ExceptionRecord;
CONTEXT* context = exception->ContextRecord; CONTEXT* context = exception->ContextRecord;
if (record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION && if (record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
record->ExceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION)
{
return false; return false;
}
uint8_t** ppc = ContextToPC(context); uint8_t** ppc = ContextToPC(context);
uint8_t* pc = *ppc; uint8_t* pc = *ppc;
if (record->NumberParameters < 2)
return false;
const CodeSegment* codeSegment = LookupCodeSegment(pc); const CodeSegment* codeSegment = LookupCodeSegment(pc);
if (!codeSegment) if (!codeSegment)
return false; return false;
@ -994,7 +994,7 @@ HandleFault(PEXCEPTION_POINTERS exception)
const Instance* instance = LookupFaultingInstance(*codeSegment, pc, ContextToFP(context)); const Instance* instance = LookupFaultingInstance(*codeSegment, pc, ContextToFP(context));
if (!instance) { if (!instance) {
// On Windows, it is possible for InterruptRunningJitCode to execute // On Windows, it is possible for InterruptRunningJitCode to execute
// between a faulting instruction and the handling of the fault due // between a faulting heap access and the handling of the fault due
// to InterruptRunningJitCode's use of SuspendThread. When this happens, // to InterruptRunningJitCode's use of SuspendThread. When this happens,
// after ResumeThread, the exception handler is called with pc equal to // after ResumeThread, the exception handler is called with pc equal to
// CodeSegment.interrupt, which is logically wrong. The Right Thing would // CodeSegment.interrupt, which is logically wrong. The Right Thing would
@ -1004,36 +1004,9 @@ HandleFault(PEXCEPTION_POINTERS exception)
// retrigger after the interrupt jumps back to resumePC). // retrigger after the interrupt jumps back to resumePC).
return activation->isWasmInterrupted() && return activation->isWasmInterrupted() &&
pc == codeSegment->interruptCode() && pc == codeSegment->interruptCode() &&
codeSegment->containsCodePC(activation->wasmInterruptResumePC()); codeSegment->containsCodePC(activation->wasmResumePC());
} }
// In the same race-with-interrupt situation above, it's *also* possible
// that the reported 'pc' is the pre-interrupt pc, not post-interrupt
// codeSegment->interruptCode (this may be windows-version-specific). In
// this case, lookupTrap()/lookupMemoryAccess() will all succeed causing the
// pc to be redirected *again* (to a trap stub), leading to the interrupt
// stub never being called. Since the goal of the async interrupt is to break
// out iloops and trapping does just that, this is fine, we just clear the
// "interrupted" state.
if (activation->isWasmInterrupted()) {
MOZ_ASSERT(activation->wasmInterruptResumePC() == pc);
activation->finishWasmInterrupt();
}
if (record->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
Trap trap;
BytecodeOffset bytecode;
if (!codeSegment->code().lookupTrap(pc, &trap, &bytecode))
return false;
activation->startWasmTrap(trap, bytecode.offset, pc, ContextToFP(context));
*ppc = codeSegment->trapCode();
return true;
}
if (record->NumberParameters < 2)
return false;
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(record->ExceptionInformation[1]); uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(record->ExceptionInformation[1]);
// This check isn't necessary, but, since we can, check anyway to make // This check isn't necessary, but, since we can, check anyway to make
@ -1043,6 +1016,18 @@ HandleFault(PEXCEPTION_POINTERS exception)
MOZ_ASSERT(activation->compartment() == instance->compartment()); MOZ_ASSERT(activation->compartment() == instance->compartment());
// Similar to the non-atomic situation above, on Windows, an OOB fault at a
// PC can trigger *after* an async interrupt observed that PC and attempted
// to redirect to the async stub. In this unique case, isWasmInterrupted() is
// already true when the OOB handler is called. Since the point of the async
// interrupt is to get out of an iloop and the OOB trap will do just that,
// we can simply clear the interrupt. (The update to CONTEXT.pc made by
// HandleMemoryAccess will clobber the interrupt's previous update.)
if (activation->isWasmInterrupted()) {
MOZ_ASSERT(activation->wasmResumePC() == pc);
activation->finishWasmInterrupt();
}
HandleMemoryAccess(context, pc, faultingAddress, codeSegment, *instance, activation, ppc); HandleMemoryAccess(context, pc, faultingAddress, codeSegment, *instance, activation, ppc);
return true; return true;
} }
@ -1128,11 +1113,8 @@ HandleMachException(JSContext* cx, const ExceptionRequest& request)
uint8_t** ppc = ContextToPC(&context); uint8_t** ppc = ContextToPC(&context);
uint8_t* pc = *ppc; uint8_t* pc = *ppc;
if (request.body.exception != EXC_BAD_ACCESS && if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2)
request.body.exception != EXC_BAD_INSTRUCTION)
{
return false; return false;
}
// The faulting thread is suspended so we can access cx fields that can // The faulting thread is suspended so we can access cx fields that can
// normally only be accessed by the cx's active thread. // normally only be accessed by the cx's active thread.
@ -1146,31 +1128,17 @@ HandleMachException(JSContext* cx, const ExceptionRequest& request)
if (!instance) if (!instance)
return false; return false;
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(request.body.code[1]);
// This check isn't necessary, but, since we can, check anyway to make
// sure we aren't covering up a real bug.
if (!IsHeapAccessAddress(*instance, faultingAddress))
return false;
JitActivation* activation = cx->activation()->asJit(); JitActivation* activation = cx->activation()->asJit();
MOZ_ASSERT(activation->compartment() == instance->compartment()); MOZ_ASSERT(activation->compartment() == instance->compartment());
if (request.body.exception == EXC_BAD_INSTRUCTION) { HandleMemoryAccess(&context, pc, faultingAddress, codeSegment, *instance, activation, ppc);
Trap trap;
BytecodeOffset bytecode;
if (!codeSegment->code().lookupTrap(pc, &trap, &bytecode))
return false;
activation->startWasmTrap(trap, bytecode.offset, pc, ContextToFP(&context));
*ppc = codeSegment->trapCode();
} else {
MOZ_ASSERT(request.body.exception == EXC_BAD_ACCESS);
if (request.body.codeCnt != 2)
return false;
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(request.body.code[1]);
// This check isn't necessary, but, since we can, check anyway to make
// sure we aren't covering up a real bug.
if (!IsHeapAccessAddress(*instance, faultingAddress))
return false;
HandleMemoryAccess(&context, pc, faultingAddress, codeSegment, *instance, activation, ppc);
}
// Update the thread state with the new pc and register values. // Update the thread state with the new pc and register values.
kret = thread_set_state(cxThread, float_state, (thread_state_t)&context.float_, float_state_count); kret = thread_set_state(cxThread, float_state, (thread_state_t)&context.float_, float_state_count);
@ -1343,7 +1311,7 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
return false; return false;
AutoSignalHandler ash; AutoSignalHandler ash;
MOZ_RELEASE_ASSERT(signum == SIGSEGV || signum == SIGBUS || signum == SIGILL); MOZ_RELEASE_ASSERT(signum == SIGSEGV || signum == SIGBUS);
CONTEXT* context = (CONTEXT*)ctx; CONTEXT* context = (CONTEXT*)ctx;
uint8_t** ppc = ContextToPC(context); uint8_t** ppc = ContextToPC(context);
@ -1357,20 +1325,6 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
if (!instance) if (!instance)
return false; return false;
JitActivation* activation = TlsContext.get()->activation()->asJit();
MOZ_ASSERT(activation->compartment() == instance->compartment());
if (signum == SIGILL) {
Trap trap;
BytecodeOffset bytecode;
if (!segment->code().lookupTrap(pc, &trap, &bytecode))
return false;
activation->startWasmTrap(trap, bytecode.offset, pc, ContextToFP(context));
*ppc = segment->trapCode();
return true;
}
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(info->si_addr); uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(info->si_addr);
// Although it's not strictly necessary, to make sure we're not covering up // Although it's not strictly necessary, to make sure we're not covering up
@ -1392,6 +1346,9 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
return false; return false;
} }
JitActivation* activation = TlsContext.get()->activation()->asJit();
MOZ_ASSERT(activation->compartment() == instance->compartment());
#ifdef JS_CODEGEN_ARM #ifdef JS_CODEGEN_ARM
if (signum == SIGBUS) { if (signum == SIGBUS) {
// TODO: We may see a bus error for something that is an unaligned access that // TODO: We may see a bus error for something that is an unaligned access that
@ -1410,7 +1367,6 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
static struct sigaction sPrevSEGVHandler; static struct sigaction sPrevSEGVHandler;
static struct sigaction sPrevSIGBUSHandler; static struct sigaction sPrevSIGBUSHandler;
static struct sigaction sPrevSIGILLHandler;
static void static void
WasmFaultHandler(int signum, siginfo_t* info, void* context) WasmFaultHandler(int signum, siginfo_t* info, void* context)
@ -1418,13 +1374,9 @@ WasmFaultHandler(int signum, siginfo_t* info, void* context)
if (HandleFault(signum, info, context)) if (HandleFault(signum, info, context))
return; return;
struct sigaction* previousSignal = nullptr; struct sigaction* previousSignal = signum == SIGSEGV
switch (signum) { ? &sPrevSEGVHandler
case SIGSEGV: previousSignal = &sPrevSEGVHandler; break; : &sPrevSIGBUSHandler;
case SIGBUS: previousSignal = &sPrevSIGBUSHandler; break;
case SIGILL: previousSignal = &sPrevSIGILLHandler; break;
}
MOZ_ASSERT(previousSignal);
// This signal is not for any asm.js code we expect, so we need to forward // This signal is not for any asm.js code we expect, so we need to forward
// the signal to the next handler. If there is no next handler (SIG_IGN or // the signal to the next handler. If there is no next handler (SIG_IGN or
@ -1665,15 +1617,6 @@ ProcessHasSignalHandlers()
if (sigaction(SIGBUS, &busHandler, &sPrevSIGBUSHandler)) if (sigaction(SIGBUS, &busHandler, &sPrevSIGBUSHandler))
MOZ_CRASH("unable to install sigbus handler"); MOZ_CRASH("unable to install sigbus handler");
# endif # endif
// Install a SIGILL handler to handle the ud2 instructions that are emitted
// to implement wasm traps.
struct sigaction illegalHandler;
illegalHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
illegalHandler.sa_sigaction = WasmFaultHandler;
sigemptyset(&illegalHandler.sa_mask);
if (sigaction(SIGILL, &illegalHandler, &sPrevSIGILLHandler))
MOZ_CRASH("unable to install segv handler");
# endif # endif
sHaveSignalHandlers = true; sHaveSignalHandlers = true;

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

@ -25,7 +25,6 @@
# include <mach/mach.h> # include <mach/mach.h>
#endif #endif
#include "threading/Thread.h" #include "threading/Thread.h"
#include "wasm/WasmTypes.h"
struct JSContext; struct JSContext;
struct JSRuntime; struct JSRuntime;
@ -80,35 +79,6 @@ class MachExceptionHandler
}; };
#endif #endif
// Typed wrappers encapsulating the data saved by the signal handler on async
// interrupt or trap. On interrupt, the PC at which to resume is saved. On trap,
// the bytecode offset to be reported in callstacks is saved.
struct InterruptData
{
// The pc to use for unwinding purposes which is kept consistent with fp at
// call boundaries.
void* unwindPC;
// The pc at which we should return if the interrupt doesn't stop execution.
void* resumePC;
InterruptData(void* unwindPC, void* resumePC)
: unwindPC(unwindPC), resumePC(resumePC)
{}
};
struct TrapData
{
void* pc;
Trap trap;
uint32_t bytecodeOffset;
TrapData(void* pc, Trap trap, uint32_t bytecodeOffset)
: pc(pc), trap(trap), bytecodeOffset(bytecodeOffset)
{}
};
} // namespace wasm } // namespace wasm
} // namespace js } // namespace js

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

@ -1001,29 +1001,6 @@ wasm::GenerateBuiltinThunk(MacroAssembler& masm, ABIFunctionType abiType, ExitRe
return FinishOffsets(masm, offsets); return FinishOffsets(masm, offsets);
} }
// Generate a stub which calls WasmReportTrap() and can be executed by having
// the signal handler redirect PC from any trapping instruction.
static bool
GenerateTrapExit(MacroAssembler& masm, Label* throwLabel, Offsets* offsets)
{
masm.haltingAlign(CodeAlignment);
offsets->begin = masm.currentOffset();
// We know that StackPointer is word-aligned, but not necessarily
// stack-aligned, so we need to align it dynamically.
masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1)));
if (ShadowStackSpace)
masm.subFromStackPtr(Imm32(ShadowStackSpace));
masm.assertStackAlignment(ABIStackAlignment);
masm.call(SymbolicAddress::ReportTrap);
masm.jump(throwLabel);
return FinishOffsets(masm, offsets);
}
// Generate a stub that calls into WasmOldReportTrap with the right trap reason. // Generate a stub that calls into WasmOldReportTrap with the right trap reason.
// This stub is called with ABIStackAlignment by a trap out-of-line path. An // This stub is called with ABIStackAlignment by a trap out-of-line path. An
// exit prologue/epilogue is used so that stack unwinding picks up the // exit prologue/epilogue is used so that stack unwinding picks up the
@ -1391,30 +1368,11 @@ wasm::GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& import
} }
for (Trap trap : MakeEnumeratedRange(Trap::Limit)) { for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
switch (trap) { CallableOffsets offsets;
case Trap::Unreachable: if (!GenerateOldTrapExit(masm, trap, &throwLabel, &offsets))
break; return false;
// The TODO list of "old" traps to convert to new traps: if (!code->codeRanges.emplaceBack(trap, offsets))
case Trap::IntegerOverflow: return false;
case Trap::InvalidConversionToInteger:
case Trap::IntegerDivideByZero:
case Trap::OutOfBounds:
case Trap::UnalignedAccess:
case Trap::IndirectCallToNull:
case Trap::IndirectCallBadSig:
case Trap::ImpreciseSimdConversion:
case Trap::StackOverflow:
case Trap::ThrowReported: {
CallableOffsets offsets;
if (!GenerateOldTrapExit(masm, trap, &throwLabel, &offsets))
return false;
if (!code->codeRanges.emplaceBack(trap, offsets))
return false;
break;
}
case Trap::Limit:
MOZ_CRASH("impossible");
}
} }
Offsets offsets; Offsets offsets;
@ -1429,11 +1387,6 @@ wasm::GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& import
if (!code->codeRanges.emplaceBack(CodeRange::UnalignedExit, offsets)) if (!code->codeRanges.emplaceBack(CodeRange::UnalignedExit, offsets))
return false; return false;
if (!GenerateTrapExit(masm, &throwLabel, &offsets))
return false;
if (!code->codeRanges.emplaceBack(CodeRange::TrapExit, offsets))
return false;
if (!GenerateInterruptExit(masm, &throwLabel, &offsets)) if (!GenerateInterruptExit(masm, &throwLabel, &offsets))
return false; return false;
if (!code->codeRanges.emplaceBack(CodeRange::Interrupt, offsets)) if (!code->codeRanges.emplaceBack(CodeRange::Interrupt, offsets))

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

@ -30,7 +30,6 @@ using namespace js::jit;
using namespace js::wasm; using namespace js::wasm;
using mozilla::IsPowerOfTwo; using mozilla::IsPowerOfTwo;
using mozilla::MakeEnumeratedRange;
// A sanity check. We have only tested WASM_HUGE_MEMORY on x64, and only tested // A sanity check. We have only tested WASM_HUGE_MEMORY on x64, and only tested
// x64 with WASM_HUGE_MEMORY. // x64 with WASM_HUGE_MEMORY.
@ -691,75 +690,6 @@ DebugFrame::leave(JSContext* cx)
} }
} }
bool
TrapSiteVectorArray::empty() const
{
for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
if (!(*this)[trap].empty())
return false;
}
return true;
}
void
TrapSiteVectorArray::clear()
{
for (Trap trap : MakeEnumeratedRange(Trap::Limit))
(*this)[trap].clear();
}
void
TrapSiteVectorArray::swap(TrapSiteVectorArray& rhs)
{
for (Trap trap : MakeEnumeratedRange(Trap::Limit))
(*this)[trap].swap(rhs[trap]);
}
void
TrapSiteVectorArray::podResizeToFit()
{
for (Trap trap : MakeEnumeratedRange(Trap::Limit))
(*this)[trap].podResizeToFit();
}
size_t
TrapSiteVectorArray::serializedSize() const
{
size_t ret = 0;
for (Trap trap : MakeEnumeratedRange(Trap::Limit))
ret += SerializedPodVectorSize((*this)[trap]);
return ret;
}
uint8_t*
TrapSiteVectorArray::serialize(uint8_t* cursor) const
{
for (Trap trap : MakeEnumeratedRange(Trap::Limit))
cursor = SerializePodVector(cursor, (*this)[trap]);
return cursor;
}
const uint8_t*
TrapSiteVectorArray::deserialize(const uint8_t* cursor)
{
for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
cursor = DeserializePodVector(cursor, &(*this)[trap]);
if (!cursor)
return nullptr;
}
return cursor;
}
size_t
TrapSiteVectorArray::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
{
size_t ret = 0;
for (Trap trap : MakeEnumeratedRange(Trap::Limit))
ret += (*this)[trap].sizeOfExcludingThis(mallocSizeOf);
return ret;
}
CodeRange::CodeRange(Kind kind, Offsets offsets) CodeRange::CodeRange(Kind kind, Offsets offsets)
: begin_(offsets.begin), : begin_(offsets.begin),
ret_(0), ret_(0),
@ -773,7 +703,6 @@ CodeRange::CodeRange(Kind kind, Offsets offsets)
case FarJumpIsland: case FarJumpIsland:
case OutOfBoundsExit: case OutOfBoundsExit:
case UnalignedExit: case UnalignedExit:
case TrapExit:
case Throw: case Throw:
case Interrupt: case Interrupt:
break; break;

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

@ -935,52 +935,6 @@ enum class Trap
Limit Limit
}; };
// A wrapper around the bytecode offset of a wasm instruction within a whole
// module, used for trap offsets or call offsets. These offsets should refer to
// the first byte of the instruction that triggered the trap / did the call and
// should ultimately derive from OpIter::bytecodeOffset.
struct BytecodeOffset
{
static const uint32_t INVALID = -1;
uint32_t offset;
BytecodeOffset() : offset(INVALID) {}
explicit BytecodeOffset(uint32_t offset) : offset(offset) {}
bool isValid() const { return offset != INVALID; }
};
// A TrapSite (in the TrapSiteVector for a given Trap code) represents a wasm
// instruction at a given bytecode offset that can fault at the given pc offset.
// When such a fault occurs, a signal/exception handler looks up the TrapSite to
// confirm the fault is intended/safe and redirects pc to the trap stub.
struct TrapSite
{
uint32_t pcOffset;
BytecodeOffset bytecode;
TrapSite() : pcOffset(-1), bytecode() {}
TrapSite(uint32_t pcOffset, BytecodeOffset bytecode) : pcOffset(pcOffset), bytecode(bytecode) {}
void offsetBy(uint32_t offset) {
pcOffset += offset;
}
};
WASM_DECLARE_POD_VECTOR(TrapSite, TrapSiteVector)
struct TrapSiteVectorArray : EnumeratedArray<Trap, Trap::Limit, TrapSiteVector>
{
bool empty() const;
void clear();
void swap(TrapSiteVectorArray& rhs);
void podResizeToFit();
WASM_DECLARE_SERIALIZABLE(TrapSiteVectorArray)
};
// The (,Callable,Func)Offsets classes are used to record the offsets of // The (,Callable,Func)Offsets classes are used to record the offsets of
// different key points in a CodeRange during compilation. // different key points in a CodeRange during compilation.
@ -1057,7 +1011,6 @@ class CodeRange
ImportJitExit, // fast-path calling from wasm into JIT code ImportJitExit, // fast-path calling from wasm into JIT code
ImportInterpExit, // slow-path calling from wasm into C++ interp ImportInterpExit, // slow-path calling from wasm into C++ interp
BuiltinThunk, // fast-path calling from wasm into a C++ native BuiltinThunk, // fast-path calling from wasm into a C++ native
TrapExit, // calls C++ to report and jumps to throw stub
OldTrapExit, // calls C++ to report and jumps to throw stub OldTrapExit, // calls C++ to report and jumps to throw stub
DebugTrap, // calls C++ to handle debug event DebugTrap, // calls C++ to handle debug event
FarJumpIsland, // inserted to connect otherwise out-of-range insns FarJumpIsland, // inserted to connect otherwise out-of-range insns
@ -1134,7 +1087,7 @@ class CodeRange
return kind() == ImportJitExit; return kind() == ImportJitExit;
} }
bool isTrapExit() const { bool isTrapExit() const {
return kind() == OldTrapExit || kind() == TrapExit; return kind() == OldTrapExit;
} }
bool isDebugTrap() const { bool isDebugTrap() const {
return kind() == DebugTrap; return kind() == DebugTrap;
@ -1148,7 +1101,7 @@ class CodeRange
// the return instruction to calculate the frame pointer. // the return instruction to calculate the frame pointer.
bool hasReturn() const { bool hasReturn() const {
return isFunction() || isImportExit() || kind() == OldTrapExit || isDebugTrap(); return isFunction() || isImportExit() || isTrapExit() || isDebugTrap();
} }
uint32_t ret() const { uint32_t ret() const {
MOZ_ASSERT(hasReturn()); MOZ_ASSERT(hasReturn());
@ -1226,6 +1179,22 @@ WASM_DECLARE_POD_VECTOR(CodeRange, CodeRangeVector)
extern const CodeRange* extern const CodeRange*
LookupInSorted(const CodeRangeVector& codeRanges, CodeRange::OffsetInCode target); LookupInSorted(const CodeRangeVector& codeRanges, CodeRange::OffsetInCode target);
// A wrapper around the bytecode offset of a wasm instruction within a whole
// module, used for trap offsets or call offsets. These offsets should refer to
// the first byte of the instruction that triggered the trap / did the call and
// should ultimately derive from OpIter::bytecodeOffset.
struct BytecodeOffset
{
static const uint32_t INVALID = -1;
uint32_t offset;
BytecodeOffset() : offset(INVALID) {}
explicit BytecodeOffset(uint32_t offset) : offset(offset) {}
bool isValid() const { return offset != INVALID; }
};
// While the frame-pointer chain allows the stack to be unwound without // While the frame-pointer chain allows the stack to be unwound without
// metadata, Error.stack still needs to know the line/column of every call in // metadata, Error.stack still needs to know the line/column of every call in
// the chain. A CallSiteDesc describes a single callsite to which CallSite adds // the chain. A CallSiteDesc describes a single callsite to which CallSite adds
@ -1364,7 +1333,6 @@ enum class SymbolicAddress
HandleExecutionInterrupt, HandleExecutionInterrupt,
HandleDebugTrap, HandleDebugTrap,
HandleThrow, HandleThrow,
ReportTrap,
OldReportTrap, OldReportTrap,
ReportOutOfBounds, ReportOutOfBounds,
ReportUnalignedAccess, ReportUnalignedAccess,