diff --git a/js/src/asmjs/WasmStubs.cpp b/js/src/asmjs/WasmStubs.cpp index 3f23cafe0d1e..40ac409bdd70 100644 --- a/js/src/asmjs/WasmStubs.cpp +++ b/js/src/asmjs/WasmStubs.cpp @@ -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; } diff --git a/js/src/asmjs/WasmTypes.cpp b/js/src/asmjs/WasmTypes.cpp index c293212141db..a44df94b34fe 100644 --- a/js/src/asmjs/WasmTypes.cpp +++ b/js/src/asmjs/WasmTypes.cpp @@ -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: diff --git a/js/src/asmjs/WasmTypes.h b/js/src/asmjs/WasmTypes.h index eb9b11a9b35c..93505a74fa1a 100644 --- a/js/src/asmjs/WasmTypes.h +++ b/js/src/asmjs/WasmTypes.h @@ -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 }; diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index d459d5b33cbb..6d81e7fb7f09 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -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*); diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 50a00a0dab8d..06a52b4b2f89 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -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); } diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index c1b36d0222e6..2d69536873f4 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -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