diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index 42646df276..315d6cee8d 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -115,6 +115,8 @@ public: [&](auto value) { if constexpr (IsSame) result = value; + else if constexpr (!IsFloatingPoint && IsSame>) + result = value; }, [&](const FunctionAddress& address) { if constexpr (IsSame) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp index 6e789c8671..68312a5f3c 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp @@ -274,6 +274,51 @@ struct ConvertToRaw { } }; +template +MakeSigned Interpreter::checked_signed_truncate(V value) +{ + if (isnan(value) || isinf(value)) { // "undefined", let's just trap. + m_do_trap = true; + return 0; + } + + double truncated; + if constexpr (IsSame) + truncated = truncf(value); + else + truncated = trunc(value); + + using SignedT = MakeSigned; + if (NumericLimits::min() <= truncated && static_cast(NumericLimits::max()) >= truncated) + return static_cast(truncated); + + dbgln_if(WASM_TRACE_DEBUG, "Truncate out of range error"); + m_do_trap = true; + return true; +} + +template +MakeUnsigned Interpreter::checked_unsigned_truncate(V value) +{ + if (isnan(value) || isinf(value)) { // "undefined", let's just trap. + m_do_trap = true; + return 0; + } + double truncated; + if constexpr (IsSame) + truncated = truncf(value); + else + truncated = trunc(value); + + using UnsignedT = MakeUnsigned; + if (NumericLimits::min() <= truncated && static_cast(NumericLimits::max()) >= truncated) + return static_cast(truncated); + + dbgln_if(WASM_TRACE_DEBUG, "Truncate out of range error"); + m_do_trap = true; + return true; +} + Vector> Interpreter::pop_values(Configuration& configuration, size_t count) { Vector> results; @@ -753,20 +798,42 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip BINARY_PREFIX_NUMERIC_OPERATION(double, copysign, double); case Instructions::i32_wrap_i64.value(): UNARY_MAP(i64, i32, i32); - case Instructions::i32_trunc_sf32.value(): - case Instructions::i32_trunc_uf32.value(): - case Instructions::i32_trunc_sf64.value(): - case Instructions::i32_trunc_uf64.value(): - goto unimplemented; + case Instructions::i32_trunc_sf32.value(): { + auto fn = [this](auto& v) { return checked_signed_truncate(v); }; + UNARY_MAP(float, fn, i32); + } + case Instructions::i32_trunc_uf32.value(): { + auto fn = [this](auto& value) { return checked_unsigned_truncate(value); }; + UNARY_MAP(float, fn, i32); + } + case Instructions::i32_trunc_sf64.value(): { + auto fn = [this](auto& value) { return checked_signed_truncate(value); }; + UNARY_MAP(double, fn, i32); + } + case Instructions::i32_trunc_uf64.value(): { + auto fn = [this](auto& value) { return checked_unsigned_truncate(value); }; + UNARY_MAP(double, fn, i32); + } + case Instructions::i64_trunc_sf32.value(): { + auto fn = [this](auto& value) { return checked_signed_truncate(value); }; + UNARY_MAP(float, fn, i64); + } + case Instructions::i64_trunc_uf32.value(): { + auto fn = [this](auto& value) { return checked_unsigned_truncate(value); }; + UNARY_MAP(float, fn, i64); + } + case Instructions::i64_trunc_sf64.value(): { + auto fn = [this](auto& value) { return checked_signed_truncate(value); }; + UNARY_MAP(double, fn, i64); + } + case Instructions::i64_trunc_uf64.value(): { + auto fn = [this](auto& value) { return checked_unsigned_truncate(value); }; + UNARY_MAP(double, fn, i64); + } case Instructions::i64_extend_si32.value(): UNARY_MAP(i32, i64, i64); case Instructions::i64_extend_ui32.value(): UNARY_MAP(u32, i64, i64); - case Instructions::i64_trunc_sf32.value(): - case Instructions::i64_trunc_uf32.value(): - case Instructions::i64_trunc_sf64.value(): - case Instructions::i64_trunc_uf64.value(): - goto unimplemented; case Instructions::f32_convert_si32.value(): UNARY_MAP(i32, float, float); case Instructions::f32_convert_ui32.value(): diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h index e78f8f462d..0e06650bf5 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h @@ -20,6 +20,13 @@ private: ReadonlyBytes load_from_memory(Configuration&, const Instruction&, size_t); void store_to_memory(Configuration&, const Instruction&, ReadonlyBytes data); void call_address(Configuration&, FunctionAddress); + + template + MakeUnsigned checked_unsigned_truncate(V); + + template + MakeSigned checked_signed_truncate(V); + Vector> pop_values(Configuration& configuration, size_t count); bool trap_if_not(bool value) {