From a569a6c32aa9a4fbea951e9d72e935eb5c829d32 Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Thu, 4 Jul 2024 08:40:36 -0700 Subject: [PATCH 1/9] LibWasm: Validate potentially empty `else` branch in `if` instruction (cherry picked from commit fce8ed15630a4969be7c9761b9b7d3cef0530cc6) --- Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp index faa9ae9873e2d8..325bd0dda5c858 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -1939,6 +1939,13 @@ VALIDATE_INSTRUCTION(structured_end) auto& last_frame = m_frames.last(); + // If this is true, then the `if` had no else. In that case, validate that the + // empty else block produces the correct type. + if (last_frame.kind == FrameKind::If) { + bool is_constant = false; + TRY(validate(Instruction(Instructions::structured_else), stack, is_constant)); + } + auto& results = last_frame.type.results(); for (size_t i = 1; i <= results.size(); ++i) TRY(stack.take(results[results.size() - i])); From a24c3ea21ac19897a5d4ae500441a6e44fdffd98 Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Wed, 3 Jul 2024 14:08:49 -0700 Subject: [PATCH 2/9] LibWasm: Preserve sign bit across JS boundary in `test-wasm` A `Uint8Array` can now be passed in the Wasm testjs files to be transmuted into a Wasm value. (cherry picked from commit 6493acf2f46f6e4522a0f1f01e12d0e48347562e) --- Meta/generate-libwasm-spec-test.py | 18 +++++++++++------- Tests/LibWasm/test-wasm.cpp | 12 +++++++++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Meta/generate-libwasm-spec-test.py b/Meta/generate-libwasm-spec-test.py index 7063449582dd6e..08d83c76ca4d33 100644 --- a/Meta/generate-libwasm-spec-test.py +++ b/Meta/generate-libwasm-spec-test.py @@ -200,7 +200,7 @@ def make_description(input_path: Path, name: str, out_path: Path) -> WastDescrip return parse(description) -def gen_value(value: WasmValue) -> str: +def gen_value(value: WasmValue, as_arg=False) -> str: def unsigned_to_signed(uint: int, bits: int) -> int: max_value = 2**bits if uint >= 2 ** (bits - 1): @@ -221,7 +221,13 @@ def int_to_float64_bitcast(uint: int) -> float: f = struct.unpack("d", b)[0] return f - def float_to_str(f: float) -> str: + def float_to_str(f: float, preserve_nan_sign=False) -> str: + if math.isnan(f) and preserve_nan_sign: + f_bytes = struct.pack("d", f) + # -NaN does not preserve the sign bit in JavaScript land, so if + # we want to preserve NaN "sign", we pass in raw bytes + return f"new Uint8Array({list(f_bytes)})" + if math.isnan(f) and math.copysign(1.0, f) < 0: return "-NaN" elif math.isnan(f): @@ -234,8 +240,6 @@ def float_to_str(f: float) -> str: if value.value.startswith("nan"): return "NaN" - elif value.value.startswith("-nan"): - return "-NaN" elif value.value == "inf": return "Infinity" elif value.value == "-inf": @@ -247,9 +251,9 @@ def float_to_str(f: float) -> str: case "i64": return str(unsigned_to_signed(int(value.value), 64)) + "n" case "f32": - return float_to_str(int_to_float_bitcast(int(value.value))) + return float_to_str(int_to_float_bitcast(int(value.value)), as_arg) case "f64": - return float_to_str(int_to_float64_bitcast(int(value.value))) + return float_to_str(int_to_float64_bitcast(int(value.value)), as_arg) case "externref" | "funcref" | "v128": return value.value case _: @@ -257,7 +261,7 @@ def float_to_str(f: float) -> str: def gen_args(args: list[WasmValue]) -> str: - return ",".join(gen_value(arg) for arg in args) + return ",".join(gen_value(arg, True) for arg in args) def gen_module_command(command: ModuleCommand, ctx: Context): diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index 78c795b36c58c3..35459a91606f68 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -256,7 +256,17 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) for (auto& param : type->parameters()) { auto argument = vm.argument(index++); double double_value = 0; - if (!argument.is_bigint()) + if (argument.is_object()) { + auto object = MUST(argument.to_object(vm)); + // Uint8Array allows for raw bytes to be passed into Wasm. This is + // particularly useful for preserving the sign bit of a NaN + if (!is(*object)) + return vm.throw_completion("Expected a Uint8Array object"sv); + auto& array = static_cast(*object); + if (array.array_length().length() != 8) + return vm.throw_completion("Expected a Uint8Array of size 8"sv); + memcpy(&double_value, array.data().data(), sizeof(double)); + } else if (!argument.is_bigint()) double_value = TRY(argument.to_double(vm)); switch (param.kind()) { case Wasm::ValueType::Kind::I32: From cce7e8363365c9ae5ce293fab55e28b2a6570acb Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Wed, 3 Jul 2024 18:33:55 -0700 Subject: [PATCH 3/9] LibWasm: Fix some floating-point conversion issues NaN bit patterns are now (hopefully) preserved. `static_cast` does not preserve the bit pattern of a given NaN, so ideally we'd use some other sort of cast and avoid `static_cast` altogether, but that's a large change for this commit. For now, this fixes the issues found in spec tests. (cherry picked from commit c882498d4450c4c2e46d77a8ab36afc4eb412c00) --- .../LibWasm/AbstractMachine/BytecodeInterpreter.cpp | 4 ++-- Userland/Libraries/LibWasm/AbstractMachine/Operators.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 73e82047986938..7a0247ce5572d1 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -519,10 +519,10 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi configuration.stack().push(Value(ValueType { ValueType::I64 }, instruction.arguments().get())); return; case Instructions::f32_const.value(): - configuration.stack().push(Value(ValueType { ValueType::F32 }, static_cast(instruction.arguments().get()))); + configuration.stack().push(Value(Value::AnyValueType(instruction.arguments().get()))); return; case Instructions::f64_const.value(): - configuration.stack().push(Value(ValueType { ValueType::F64 }, instruction.arguments().get())); + configuration.stack().push(Value(Value::AnyValueType(instruction.arguments().get()))); return; case Instructions::block.value(): { size_t arity = 0; diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Operators.h b/Userland/Libraries/LibWasm/AbstractMachine/Operators.h index 0ae68a2bf7e6c2..d19eabeb6c6cad 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Operators.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/Operators.h @@ -654,8 +654,8 @@ struct Convert { template ResultT operator()(Lhs lhs) const { - auto signed_interpretation = bit_cast>(lhs); - return static_cast(signed_interpretation); + auto interpretation = bit_cast(lhs); + return static_cast(interpretation); } static StringView name() { return "convert"sv; } @@ -690,7 +690,7 @@ struct Demote { return nanf(""); // FIXME: Ensure canonical NaN remains canonical if (isinf(lhs)) - return __builtin_huge_valf(); + return copysignf(__builtin_huge_valf(), lhs); return static_cast(lhs); } From 06b129cc7c82fe9e564833a6a03ef111688af626 Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Sat, 6 Jul 2024 08:01:26 -0700 Subject: [PATCH 4/9] LibWasm: Fix lossy NaN bit pattern conversions in spec-test gen (cherry picked from commit c103001f167d39fd68c4f04649332f76b7dd0b2e) --- Meta/generate-libwasm-spec-test.py | 12 ++++++++---- Tests/LibWasm/test-wasm.cpp | 20 +++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Meta/generate-libwasm-spec-test.py b/Meta/generate-libwasm-spec-test.py index 08d83c76ca4d33..a064b9077da40d 100644 --- a/Meta/generate-libwasm-spec-test.py +++ b/Meta/generate-libwasm-spec-test.py @@ -221,9 +221,11 @@ def int_to_float64_bitcast(uint: int) -> float: f = struct.unpack("d", b)[0] return f - def float_to_str(f: float, preserve_nan_sign=False) -> str: + def float_to_str(bits: int, *, double=False, preserve_nan_sign=False) -> str: + f = int_to_float64_bitcast(bits) if double else int_to_float_bitcast(bits) + if math.isnan(f) and preserve_nan_sign: - f_bytes = struct.pack("d", f) + f_bytes = bits.to_bytes(8 if double else 4, byteorder="little") # -NaN does not preserve the sign bit in JavaScript land, so if # we want to preserve NaN "sign", we pass in raw bytes return f"new Uint8Array({list(f_bytes)})" @@ -251,9 +253,11 @@ def float_to_str(f: float, preserve_nan_sign=False) -> str: case "i64": return str(unsigned_to_signed(int(value.value), 64)) + "n" case "f32": - return float_to_str(int_to_float_bitcast(int(value.value)), as_arg) + return float_to_str( + int(value.value), double=False, preserve_nan_sign=as_arg + ) case "f64": - return float_to_str(int_to_float64_bitcast(int(value.value)), as_arg) + return float_to_str(int(value.value), double=True, preserve_nan_sign=as_arg) case "externref" | "funcref" | "v128": return value.value case _: diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index 35459a91606f68..bca3bce9bc9f68 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -259,13 +259,13 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) if (argument.is_object()) { auto object = MUST(argument.to_object(vm)); // Uint8Array allows for raw bytes to be passed into Wasm. This is - // particularly useful for preserving the sign bit of a NaN + // particularly useful for NaN bit patterns if (!is(*object)) return vm.throw_completion("Expected a Uint8Array object"sv); auto& array = static_cast(*object); - if (array.array_length().length() != 8) - return vm.throw_completion("Expected a Uint8Array of size 8"sv); - memcpy(&double_value, array.data().data(), sizeof(double)); + if (array.array_length().length() > 8) + return vm.throw_completion("Expected a Uint8Array of size <= 8"sv); + memcpy(&double_value, array.data().data(), array.array_length().length()); } else if (!argument.is_bigint()) double_value = TRY(argument.to_double(vm)); switch (param.kind()) { @@ -281,7 +281,17 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) } break; case Wasm::ValueType::Kind::F32: - arguments.append(Wasm::Value(static_cast(double_value))); + // double_value should contain up to 8 bytes of information, + // if we were passed a Uint8Array. If the expected arg is a + // float, we were probably passed a Uint8Array of size 4. So + // we copy those bytes into a float value. + if (argument.is_object()) { + float float_value = 0; + memcpy(&float_value, &double_value, sizeof(float)); + arguments.append(Wasm::Value(float_value)); + } else { + arguments.append(Wasm::Value(static_cast(double_value))); + } break; case Wasm::ValueType::Kind::F64: arguments.append(Wasm::Value(static_cast(double_value))); From 5c3ca3ee4516b9b586a9b8dce6b42824c9d6227f Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Sat, 6 Jul 2024 13:54:56 -0700 Subject: [PATCH 5/9] LibWasm: Fix comparisons between 0.0 and -0.0 According to the spec, -0.0 < 0.0. (cherry picked from commit 31c7e98a4a46c2d0ef93c5fca47d64d05b96449f) --- .../LibWasm/AbstractMachine/Operators.h | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Operators.h b/Userland/Libraries/LibWasm/AbstractMachine/Operators.h index d19eabeb6c6cad..972e54f72a2a12 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Operators.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/Operators.h @@ -331,14 +331,12 @@ struct Minimum { auto operator()(Lhs lhs, Rhs rhs) const { if constexpr (IsFloatingPoint || IsFloatingPoint) { - if (isnan(lhs)) - return lhs; - if (isnan(rhs)) - return rhs; - if (isinf(lhs)) - return lhs > 0 ? rhs : lhs; - if (isinf(rhs)) - return rhs > 0 ? lhs : rhs; + if (isnan(lhs) || isnan(rhs)) { + return isnan(lhs) ? lhs : rhs; + } + if (lhs == 0 && rhs == 0) { + return signbit(lhs) ? lhs : rhs; + } } return min(lhs, rhs); } @@ -351,14 +349,12 @@ struct Maximum { auto operator()(Lhs lhs, Rhs rhs) const { if constexpr (IsFloatingPoint || IsFloatingPoint) { - if (isnan(lhs)) - return lhs; - if (isnan(rhs)) - return rhs; - if (isinf(lhs)) - return lhs > 0 ? lhs : rhs; - if (isinf(rhs)) - return rhs > 0 ? rhs : lhs; + if (isnan(lhs) || isnan(rhs)) { + return isnan(lhs) ? lhs : rhs; + } + if (lhs == 0 && rhs == 0) { + return signbit(lhs) ? rhs : lhs; + } } return max(lhs, rhs); } From adc92b7723c1db163de1b6df81938807c41087c7 Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Sun, 7 Jul 2024 19:01:28 -0700 Subject: [PATCH 6/9] LibWasm: Remove `Wasm::ValueType::Kind::Null*` variants As far as I know, they're not in the spec and don't serve any purposes in the internals of LibWasm. (cherry picked from commit 5382fbb6171555264e29872029330e1373b39671) --- Tests/LibWasm/test-wasm.cpp | 6 ------ .../LibWasm/AbstractMachine/AbstractMachine.h | 10 +--------- Userland/Libraries/LibWasm/Types.h | 8 +------- Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp | 9 ++------- 4 files changed, 4 insertions(+), 29 deletions(-) diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index bca3bce9bc9f68..01695053b8cede 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -328,12 +328,6 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) } arguments.append(Wasm::Value(Wasm::Reference { Wasm::Reference::Extern { static_cast(double_value) } })); break; - case Wasm::ValueType::Kind::NullFunctionReference: - arguments.append(Wasm::Value(Wasm::Reference { Wasm::Reference::Null { Wasm::ValueType(Wasm::ValueType::Kind::FunctionReference) } })); - break; - case Wasm::ValueType::Kind::NullExternReference: - arguments.append(Wasm::Value(Wasm::Reference { Wasm::Reference::Null { Wasm::ValueType(Wasm::ValueType::Kind::ExternReference) } })); - break; } } diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index e88172e5e11e00..63e7f5bffface2 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -108,14 +108,6 @@ class Value { case ValueType::Kind::F64: m_value = bit_cast(raw_value); break; - case ValueType::Kind::NullFunctionReference: - VERIFY(raw_value == 0); - m_value = Reference { Reference::Null { ValueType(ValueType::Kind::FunctionReference) } }; - break; - case ValueType::Kind::NullExternReference: - VERIFY(raw_value == 0); - m_value = Reference { Reference::Null { ValueType(ValueType::Kind::ExternReference) } }; - break; case ValueType::Kind::V128: m_value = u128(0ull, bit_cast(raw_value)); break; @@ -184,7 +176,7 @@ class Value { return type.ref().visit( [](Reference::Func const&) { return ValueType::Kind::FunctionReference; }, [](Reference::Null const& null_type) { - return null_type.type.kind() == ValueType::ExternReference ? ValueType::Kind::NullExternReference : ValueType::Kind::NullFunctionReference; + return null_type.type.kind(); }, [](Reference::Extern const&) { return ValueType::Kind::ExternReference; }); })); diff --git a/Userland/Libraries/LibWasm/Types.h b/Userland/Libraries/LibWasm/Types.h index f9e08d02b0e6b5..a7540cf4547404 100644 --- a/Userland/Libraries/LibWasm/Types.h +++ b/Userland/Libraries/LibWasm/Types.h @@ -165,8 +165,6 @@ class ValueType { V128, FunctionReference, ExternReference, - NullFunctionReference, - NullExternReference, }; explicit ValueType(Kind kind) @@ -176,7 +174,7 @@ class ValueType { bool operator==(ValueType const&) const = default; - auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference || m_kind == NullExternReference || m_kind == NullFunctionReference; } + auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference; } auto is_vector() const { return m_kind == V128; } auto is_numeric() const { return !is_reference() && !is_vector(); } auto kind() const { return m_kind; } @@ -200,10 +198,6 @@ class ValueType { return "funcref"; case ExternReference: return "externref"; - case NullFunctionReference: - return "ref.null externref"; - case NullExternReference: - return "ref.null funcref"; } VERIFY_NOT_REACHED(); } diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index fab14755b5fa69..eb69cdb00fadd6 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -412,10 +412,9 @@ JS::ThrowCompletionOr to_webassembly_value(JS::VM& vm, JS::Value va auto number = TRY(value.to_double(vm)); return Wasm::Value { static_cast(number) }; } - case Wasm::ValueType::FunctionReference: - case Wasm::ValueType::NullFunctionReference: { + case Wasm::ValueType::FunctionReference: { if (value.is_null()) - return Wasm::Value { Wasm::ValueType(Wasm::ValueType::NullExternReference), 0ull }; + return Wasm::Value { Wasm::ValueType(Wasm::ValueType::FunctionReference), 0ull }; if (value.is_function()) { auto& function = value.as_function(); @@ -429,7 +428,6 @@ JS::ThrowCompletionOr to_webassembly_value(JS::VM& vm, JS::Value va return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "Exported function"); } case Wasm::ValueType::ExternReference: - case Wasm::ValueType::NullExternReference: TODO(); case Wasm::ValueType::V128: return vm.throw_completion("Cannot convert a vector value to a javascript value"sv); @@ -453,11 +451,8 @@ JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value) case Wasm::ValueType::FunctionReference: // FIXME: What's the name of a function reference that isn't exported? return create_native_function(vm, wasm_value.to().value().address, "FIXME_IHaveNoIdeaWhatThisShouldBeCalled"); - case Wasm::ValueType::NullFunctionReference: - return JS::js_null(); case Wasm::ValueType::V128: case Wasm::ValueType::ExternReference: - case Wasm::ValueType::NullExternReference: TODO(); } VERIFY_NOT_REACHED(); From 521aceac5d5b9d3f6cc568658991d05338dbba8a Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:04:10 -0700 Subject: [PATCH 7/9] AK: Add `remaining` method to `ConstrainedStream` Simply returns how many bytes can be read from the stream. (cherry picked from commit aee2f25929157a4e6c7f391584c4839a40beadc8) --- AK/ConstrainedStream.h | 1 + 1 file changed, 1 insertion(+) diff --git a/AK/ConstrainedStream.h b/AK/ConstrainedStream.h index 087c32594ff652..7ef92b263828ad 100644 --- a/AK/ConstrainedStream.h +++ b/AK/ConstrainedStream.h @@ -22,6 +22,7 @@ class ConstrainedStream : public Stream { virtual bool is_eof() const override; virtual bool is_open() const override; virtual void close() override; + u64 remaining() const { return m_limit; } private: MaybeOwned m_stream; From 2023f0c556c12c073d81fde1fba9c990979022cc Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:04:48 -0700 Subject: [PATCH 8/9] LibWasm: Error when parsed section lengths are invalidated (cherry picked from commit afd8d90f3237e0cffaabb05becbff16f8c8fdd25) --- Userland/Libraries/LibWasm/Parser/Parser.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibWasm/Parser/Parser.cpp b/Userland/Libraries/LibWasm/Parser/Parser.cpp index 464e689d9b7ae4..e0bb54d5cd4a3c 100644 --- a/Userland/Libraries/LibWasm/Parser/Parser.cpp +++ b/Userland/Libraries/LibWasm/Parser/Parser.cpp @@ -1413,10 +1413,8 @@ ParseResult Module::parse(Stream& stream) return with_eof_check(stream, ParseError::InvalidModuleVersion); Vector sections; - for (;;) { + while (!stream.is_eof()) { auto section_id_or_error = stream.read_value(); - if (stream.is_eof()) - break; if (section_id_or_error.is_error()) return with_eof_check(stream, ParseError::ExpectedIndex); @@ -1472,7 +1470,7 @@ ParseResult Module::parse(Stream& stream) default: return with_eof_check(stream, ParseError::InvalidIndex); } - if (!section_stream.is_eof()) + if (section_stream.remaining() != 0) return ParseError::SectionSizeMismatch; } From 9210fa3c6848a9f336f2b1e2ca50bf45ed2e0795 Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Mon, 8 Jul 2024 18:09:00 -0700 Subject: [PATCH 9/9] LibWasm: Give names to functions exported to JS via `ref.func` https://webassembly.github.io/spec/js-api/index.html#name-of-the-webassembly-function (cherry picked from commit e8fd8982f82e91f97b24523f3ee60eef774990dd) --- Tests/LibWasm/test-wasm.cpp | 3 ++- .../LibWasm/AbstractMachine/AbstractMachine.h | 5 ++++- Userland/Libraries/LibWasm/WASI/Wasi.cpp | 3 ++- .../LibWeb/WebAssembly/WebAssembly.cpp | 20 +++++++++++++++---- Userland/Utilities/wasm.cpp | 3 ++- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index 01695053b8cede..0756f4d7626eba 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -142,7 +142,8 @@ class WebAssemblyModule final : public JS::Object { // Noop, this just needs to exist. return Wasm::Result { Vector {} }; }, - type }); + type, + "__TEST" }); } static HashMap s_spec_test_namespace; diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index 63e7f5bffface2..ed702a9d585f53 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -348,18 +348,21 @@ class WasmFunction { class HostFunction { public: - explicit HostFunction(AK::Function&)> function, FunctionType const& type) + explicit HostFunction(AK::Function&)> function, FunctionType const& type, ByteString name) : m_function(move(function)) , m_type(type) + , m_name(move(name)) { } auto& function() { return m_function; } auto& type() const { return m_type; } + auto& name() const { return m_name; } private: AK::Function&)> m_function; FunctionType m_type; + ByteString m_name; }; using FunctionInstance = Variant; diff --git a/Userland/Libraries/LibWasm/WASI/Wasi.cpp b/Userland/Libraries/LibWasm/WASI/Wasi.cpp index cb3d7baec1cfca..91e097eaf38522 100644 --- a/Userland/Libraries/LibWasm/WASI/Wasi.cpp +++ b/Userland/Libraries/LibWasm/WASI/Wasi.cpp @@ -971,7 +971,8 @@ struct InvocationOf { FunctionType { move(arguments_types), { ValueType(ValueType::I32) }, - }); + }, + function_name); } }; diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index eb69cdb00fadd6..df468a886fd915 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -219,7 +219,8 @@ JS::ThrowCompletionOr> instantiate_module(JS return Wasm::Result { move(wasm_values) }; }, - type + type, + ByteString::formatted("func{}", resolved_imports.size()), }; auto address = cache.abstract_machine().store().allocate(move(host_function)); dbgln("Resolved to {}", address->value()); @@ -448,9 +449,20 @@ JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value) return JS::Value(wasm_value.to().value()); case Wasm::ValueType::F32: return JS::Value(static_cast(wasm_value.to().value())); - case Wasm::ValueType::FunctionReference: - // FIXME: What's the name of a function reference that isn't exported? - return create_native_function(vm, wasm_value.to().value().address, "FIXME_IHaveNoIdeaWhatThisShouldBeCalled"); + case Wasm::ValueType::FunctionReference: { + auto address = wasm_value.to().value().address; + auto& cache = get_cache(realm); + auto* function = cache.abstract_machine().store().get(address); + auto name = function->visit( + [&](Wasm::WasmFunction& wasm_function) { + auto index = *wasm_function.module().functions().find_first_index(address); + return ByteString::formatted("func{}", index); + }, + [](Wasm::HostFunction& host_function) { + return host_function.name(); + }); + return create_native_function(vm, address, name); + } case Wasm::ValueType::V128: case Wasm::ValueType::ExternReference: TODO(); diff --git a/Userland/Utilities/wasm.cpp b/Userland/Utilities/wasm.cpp index 9417b721cc156b..5925a5084b8250 100644 --- a/Userland/Utilities/wasm.cpp +++ b/Userland/Utilities/wasm.cpp @@ -695,7 +695,8 @@ ErrorOr serenity_main(Main::Arguments arguments) result.append(Wasm::Value { result_type, 0ull }); return Wasm::Result { move(result) }; }, - type)); + type, + entry.name)); exports.set(entry, *address); }