mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
Bug 1268910: Refactor WebAssembly trap handling; r=luke
MozReview-Commit-ID: 72PFgaGUBBC --HG-- extra : rebase_source : 3cac1acb2c3f669f9d6e4fa0e11947f26267d33c extra : histedit_source : 2c0e66eb7cfa366e785452a118163d49066ed1a1
This commit is contained in:
parent
4385ba4cf1
commit
dbc6dd425e
@ -858,6 +858,43 @@ GenerateErrorStub(MacroAssembler& masm, SymbolicAddress address)
|
||||
return offsets;
|
||||
}
|
||||
|
||||
// Generate a stub that calls into HandleTrap with the right trap reason.
|
||||
static Offsets
|
||||
GenerateTrapStub(MacroAssembler& masm, Trap reason)
|
||||
{
|
||||
masm.haltingAlign(CodeAlignment);
|
||||
|
||||
Offsets offsets;
|
||||
offsets.begin = masm.currentOffset();
|
||||
|
||||
// sp can be anything at this point, so ensure it is aligned when calling
|
||||
// into C++. We unconditionally jump to throw so don't worry about
|
||||
// restoring sp.
|
||||
masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1)));
|
||||
if (ShadowStackSpace)
|
||||
masm.subFromStackPtr(Imm32(ShadowStackSpace));
|
||||
|
||||
MIRTypeVector args;
|
||||
JS_ALWAYS_TRUE(args.append(MIRType::Int32));
|
||||
|
||||
ABIArgMIRTypeIter i(args);
|
||||
if (i->kind() == ABIArg::GPR) {
|
||||
masm.move32(Imm32(int32_t(reason)), i->gpr());
|
||||
} else {
|
||||
masm.store32(Imm32(int32_t(reason)),
|
||||
Address(masm.getStackPointer(), i->offsetFromArgBase()));
|
||||
}
|
||||
|
||||
i++;
|
||||
MOZ_ASSERT(i.done());
|
||||
|
||||
masm.call(SymbolicAddress::HandleTrap);
|
||||
masm.jump(JumpTarget::Throw);
|
||||
|
||||
offsets.end = masm.currentOffset();
|
||||
return offsets;
|
||||
}
|
||||
|
||||
// If an exception is thrown, simply pop all frames (since asm.js does not
|
||||
// contain try/catch). To do this:
|
||||
// 1. Restore 'sp' to it's value right after the PushRegsInMask in GenerateEntry.
|
||||
@ -897,20 +934,17 @@ wasm::GenerateJumpTarget(MacroAssembler& masm, JumpTarget target)
|
||||
switch (target) {
|
||||
case JumpTarget::StackOverflow:
|
||||
return GenerateStackOverflow(masm);
|
||||
case JumpTarget::ConversionError:
|
||||
return GenerateErrorStub(masm, SymbolicAddress::OnImpreciseConversion);
|
||||
case JumpTarget::OutOfBounds:
|
||||
return GenerateErrorStub(masm, SymbolicAddress::OnOutOfBounds);
|
||||
case JumpTarget::BadIndirectCall:
|
||||
return GenerateErrorStub(masm, SymbolicAddress::BadIndirectCall);
|
||||
case JumpTarget::UnreachableTrap:
|
||||
return GenerateErrorStub(masm, SymbolicAddress::UnreachableTrap);
|
||||
case JumpTarget::InvalidConversionToIntegerTrap:
|
||||
return GenerateErrorStub(masm, SymbolicAddress::InvalidConversionToIntegerTrap);
|
||||
case JumpTarget::IntegerOverflowTrap:
|
||||
return GenerateErrorStub(masm, SymbolicAddress::IntegerOverflowTrap);
|
||||
case JumpTarget::Throw:
|
||||
return GenerateThrow(masm);
|
||||
case JumpTarget::Unreachable:
|
||||
case JumpTarget::IntegerOverflow:
|
||||
case JumpTarget::InvalidConversionToInteger:
|
||||
case JumpTarget::ImpreciseSimdConversion:
|
||||
return GenerateTrapStub(masm, Trap(target));
|
||||
case JumpTarget::Limit:
|
||||
break;
|
||||
}
|
||||
|
@ -65,13 +65,6 @@ OnOutOfBounds()
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
}
|
||||
|
||||
static void
|
||||
OnImpreciseConversion()
|
||||
{
|
||||
JSContext* cx = JSRuntime::innermostWasmActivation()->cx();
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SIMD_FAILED_CONVERSION);
|
||||
}
|
||||
|
||||
static void
|
||||
BadIndirectCall()
|
||||
{
|
||||
@ -80,24 +73,32 @@ BadIndirectCall()
|
||||
}
|
||||
|
||||
static void
|
||||
UnreachableTrap()
|
||||
HandleTrap(int32_t trapIndex)
|
||||
{
|
||||
JSContext* cx = JSRuntime::innermostWasmActivation()->cx();
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_UNREACHABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
IntegerOverflowTrap()
|
||||
{
|
||||
JSContext* cx = JSRuntime::innermostWasmActivation()->cx();
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_INTEGER_OVERFLOW);
|
||||
}
|
||||
MOZ_ASSERT(trapIndex < int32_t(Trap::Limit) && trapIndex >= 0);
|
||||
Trap trap = Trap(trapIndex);
|
||||
|
||||
static void
|
||||
InvalidConversionToIntegerTrap()
|
||||
{
|
||||
JSContext* cx = JSRuntime::innermostWasmActivation()->cx();
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_INVALID_CONVERSION);
|
||||
unsigned errorNumber;
|
||||
switch (trap) {
|
||||
case Trap::Unreachable:
|
||||
errorNumber = JSMSG_WASM_UNREACHABLE;
|
||||
break;
|
||||
case Trap::IntegerOverflow:
|
||||
errorNumber = JSMSG_WASM_INTEGER_OVERFLOW;
|
||||
break;
|
||||
case Trap::InvalidConversionToInteger:
|
||||
errorNumber = JSMSG_WASM_INVALID_CONVERSION;
|
||||
break;
|
||||
case Trap::ImpreciseSimdConversion:
|
||||
errorNumber = JSMSG_SIMD_FAILED_CONVERSION;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected trap");
|
||||
}
|
||||
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, errorNumber);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
@ -246,18 +247,12 @@ wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx)
|
||||
return FuncCast(WasmReportOverRecursed, Args_General0);
|
||||
case SymbolicAddress::OnOutOfBounds:
|
||||
return FuncCast(OnOutOfBounds, Args_General0);
|
||||
case SymbolicAddress::OnImpreciseConversion:
|
||||
return FuncCast(OnImpreciseConversion, Args_General0);
|
||||
case SymbolicAddress::BadIndirectCall:
|
||||
return FuncCast(BadIndirectCall, Args_General0);
|
||||
case SymbolicAddress::UnreachableTrap:
|
||||
return FuncCast(UnreachableTrap, Args_General0);
|
||||
case SymbolicAddress::IntegerOverflowTrap:
|
||||
return FuncCast(IntegerOverflowTrap, Args_General0);
|
||||
case SymbolicAddress::InvalidConversionToIntegerTrap:
|
||||
return FuncCast(InvalidConversionToIntegerTrap, Args_General0);
|
||||
case SymbolicAddress::HandleExecutionInterrupt:
|
||||
return FuncCast(WasmHandleExecutionInterrupt, Args_General0);
|
||||
case SymbolicAddress::HandleTrap:
|
||||
return FuncCast(HandleTrap, Args_General1);
|
||||
case SymbolicAddress::InvokeImport_Void:
|
||||
return FuncCast(InvokeImport_Void, Args_General3);
|
||||
case SymbolicAddress::InvokeImport_I32:
|
||||
|
@ -628,12 +628,9 @@ enum class SymbolicAddress
|
||||
StackLimit,
|
||||
ReportOverRecursed,
|
||||
OnOutOfBounds,
|
||||
OnImpreciseConversion,
|
||||
BadIndirectCall,
|
||||
UnreachableTrap,
|
||||
IntegerOverflowTrap,
|
||||
InvalidConversionToIntegerTrap,
|
||||
HandleExecutionInterrupt,
|
||||
HandleTrap,
|
||||
InvokeImport_Void,
|
||||
InvokeImport_I32,
|
||||
InvokeImport_I64,
|
||||
@ -650,6 +647,24 @@ AddressOf(SymbolicAddress imm, ExclusiveContext* cx);
|
||||
// testing purposes mainly.
|
||||
MOZ_MUST_USE bool ReadI64Object(JSContext* cx, HandleValue v, int64_t* val);
|
||||
|
||||
// A wasm::Trap is a reason for why we reached a trap in executed code. Each
|
||||
// different trap is mapped to a different error message.
|
||||
|
||||
enum class Trap
|
||||
{
|
||||
// The Unreachable opcode has been executed.
|
||||
Unreachable,
|
||||
// An integer arithmetic operation led to an overflow.
|
||||
IntegerOverflow,
|
||||
// Trying to coerce NaN to an integer.
|
||||
InvalidConversionToInteger,
|
||||
// (asm.js only) SIMD float to int conversion failed because the input
|
||||
// wasn't in bounds.
|
||||
ImpreciseSimdConversion,
|
||||
|
||||
Limit
|
||||
};
|
||||
|
||||
// A wasm::JumpTarget represents one of a special set of stubs that can be
|
||||
// jumped to from any function. Because wasm modules can be larger than the
|
||||
// range of a plain jump, these potentially out-of-range jumps must be recorded
|
||||
@ -657,13 +672,15 @@ MOZ_MUST_USE bool ReadI64Object(JSContext* cx, HandleValue v, int64_t* val);
|
||||
|
||||
enum class JumpTarget
|
||||
{
|
||||
// Traps
|
||||
Unreachable = unsigned(Trap::Unreachable),
|
||||
IntegerOverflow = unsigned(Trap::IntegerOverflow),
|
||||
InvalidConversionToInteger = unsigned(Trap::InvalidConversionToInteger),
|
||||
ImpreciseSimdConversion = unsigned(Trap::ImpreciseSimdConversion),
|
||||
// Non-traps
|
||||
StackOverflow,
|
||||
OutOfBounds,
|
||||
ConversionError,
|
||||
BadIndirectCall,
|
||||
UnreachableTrap,
|
||||
IntegerOverflowTrap,
|
||||
InvalidConversionToIntegerTrap,
|
||||
Throw,
|
||||
Limit
|
||||
};
|
||||
|
@ -11203,7 +11203,7 @@ void
|
||||
CodeGenerator::visitAsmThrowUnreachable(LAsmThrowUnreachable* lir)
|
||||
{
|
||||
MOZ_ASSERT(gen->compilingAsmJS());
|
||||
masm.jump(wasm::JumpTarget::UnreachableTrap);
|
||||
masm.jump(wasm::JumpTarget::Unreachable);
|
||||
}
|
||||
|
||||
typedef bool (*RecompileFn)(JSContext*);
|
||||
|
@ -2965,8 +2965,8 @@ CodeGeneratorARM::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* oo
|
||||
|
||||
// Handle errors.
|
||||
masm.bind(&fail);
|
||||
masm.jump(wasm::JumpTarget::IntegerOverflowTrap);
|
||||
masm.jump(wasm::JumpTarget::IntegerOverflow);
|
||||
|
||||
masm.bind(&inputIsNaN);
|
||||
masm.jump(wasm::JumpTarget::InvalidConversionToIntegerTrap);
|
||||
masm.jump(wasm::JumpTarget::InvalidConversionToInteger);
|
||||
}
|
||||
|
@ -2498,7 +2498,7 @@ CodeGeneratorX86Shared::visitOutOfLineSimdFloatToIntCheck(OutOfLineSimdFloatToIn
|
||||
masm.jump(ool->rejoin());
|
||||
|
||||
if (gen->compilingAsmJS()) {
|
||||
masm.bindLater(&onConversionError, wasm::JumpTarget::ConversionError);
|
||||
masm.bindLater(&onConversionError, wasm::JumpTarget::ImpreciseSimdConversion);
|
||||
} else {
|
||||
masm.bind(&onConversionError);
|
||||
bailout(ool->ins()->snapshot());
|
||||
@ -2577,7 +2577,7 @@ CodeGeneratorX86Shared::visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins)
|
||||
masm.cmp32(temp, Imm32(0));
|
||||
|
||||
if (gen->compilingAsmJS())
|
||||
masm.j(Assembler::NotEqual, wasm::JumpTarget::ConversionError);
|
||||
masm.j(Assembler::NotEqual, wasm::JumpTarget::ImpreciseSimdConversion);
|
||||
else
|
||||
bailoutIf(Assembler::NotEqual, ins->snapshot());
|
||||
}
|
||||
@ -4071,10 +4071,10 @@ CodeGeneratorX86Shared::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateChe
|
||||
|
||||
// Handle errors.
|
||||
masm.bind(&fail);
|
||||
masm.jump(wasm::JumpTarget::IntegerOverflowTrap);
|
||||
masm.jump(wasm::JumpTarget::IntegerOverflow);
|
||||
|
||||
masm.bind(&inputIsNaN);
|
||||
masm.jump(wasm::JumpTarget::InvalidConversionToIntegerTrap);
|
||||
masm.jump(wasm::JumpTarget::InvalidConversionToInteger);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user