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:
Benjamin Bouvier 2016-05-03 16:29:49 +02:00
parent 4385ba4cf1
commit dbc6dd425e
6 changed files with 98 additions and 52 deletions

View File

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

View File

@ -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:

View File

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

View File

@ -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*);

View File

@ -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);
}

View File

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