From aaa150937890309e834bd1e35de22061609eb366 Mon Sep 17 00:00:00 2001 From: Michael Thyregod <2386496+michaelthyregod@users.noreply.github.com> Date: Mon, 9 Nov 2026 05:07:10 +0100 Subject: [PATCH 1/2] Pass host import arguments with their WebAssembly types The switch expression in ConvertArguments had int, long, float and double arms, so C# gave it the common type double: every argument reached the import callback as a boxed double, and i64 values above 2^53 lost precision. Box each arm as object instead, so i32, i64, f32 and f64 arrive as int, long, float and double. --- CHANGELOG.md | 4 ++ .../WasmtimeRuntimeTests.cs | 47 +++++++++++++++++++ src/AngleSharp.Wasm/WasmtimeWasmRuntime.cs | 8 ++-- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffd4982..9bfce72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.1.1 + +- Fixed host import arguments arriving as `double` instead of their WebAssembly types @michaelthyregod + # 1.1.0 Released on Friday, August 21 2026. diff --git a/src/AngleSharp.Wasm.Tests/WasmtimeRuntimeTests.cs b/src/AngleSharp.Wasm.Tests/WasmtimeRuntimeTests.cs index c9e77b0..f071e98 100644 --- a/src/AngleSharp.Wasm.Tests/WasmtimeRuntimeTests.cs +++ b/src/AngleSharp.Wasm.Tests/WasmtimeRuntimeTests.cs @@ -1,6 +1,8 @@ namespace AngleSharp.Wasm.Tests; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using NUnit.Framework; @@ -43,6 +45,21 @@ public sealed class WasmtimeRuntimeTests 0x0A, 0x09, 0x01, 0x07, 0x00, 0x10, 0x00, 0x41, 0x01, 0x6A, 0x0B, }; + // (module + // (import "host" "echo" (func $echo (param i32 i64 f32 f64))) + // (func (export "run") (param i32 i64 f32 f64) + // local.get 0 local.get 1 local.get 2 local.get 3 call $echo)) + private static readonly byte[] HostImportArgumentsModule = + { + 0x00, 0x61, 0x73, 0x6D, + 0x01, 0x00, 0x00, 0x00, + 0x01, 0x08, 0x01, 0x60, 0x04, 0x7F, 0x7E, 0x7D, 0x7C, 0x00, + 0x02, 0x0D, 0x01, 0x04, 0x68, 0x6F, 0x73, 0x74, 0x04, 0x65, 0x63, 0x68, 0x6F, 0x00, 0x00, + 0x03, 0x02, 0x01, 0x00, + 0x07, 0x07, 0x01, 0x03, 0x72, 0x75, 0x6E, 0x00, 0x01, + 0x0A, 0x0E, 0x01, 0x0C, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x10, 0x00, 0x0B, + }; + [Test] public async Task CanCompileInstantiateAndInvokeExport() { @@ -97,4 +114,34 @@ public async Task CanInstantiateWithHostImport() Assert.That(Convert.ToInt32(result), Is.EqualTo(42)); } + + [Test] + public async Task HostImportReceivesArgumentsWithTheirWasmTypes() + { + using var runtime = new WasmtimeWasmRuntime(); + using var module = await runtime.CompileAsync(HostImportArgumentsModule).ConfigureAwait(false); + var types = new[] { WasmValueType.Int32, WasmValueType.Int64, WasmValueType.Float32, WasmValueType.Float64 }; + IReadOnlyList? received = null; + + var imports = new[] + { + new WasmImportFunction( + "host", + "echo", + types, + Array.Empty(), + arguments => + { + received = arguments; + return null; + }), + }; + + using var instance = await runtime.InstantiateAsync(module, imports).ConfigureAwait(false); + await instance.InvokeAsync("run", new object?[] { 7, 9007199254740993L, 1.5f, 2.25 }).ConfigureAwait(false); + + Assert.That(received, Is.EqualTo(new object?[] { 7, 9007199254740993L, 1.5f, 2.25 })); + Assert.That(received!.Select(argument => argument?.GetType()), + Is.EqualTo(new[] { typeof(int), typeof(long), typeof(float), typeof(double) })); + } } diff --git a/src/AngleSharp.Wasm/WasmtimeWasmRuntime.cs b/src/AngleSharp.Wasm/WasmtimeWasmRuntime.cs index 51dd0da..82f3edf 100644 --- a/src/AngleSharp.Wasm/WasmtimeWasmRuntime.cs +++ b/src/AngleSharp.Wasm/WasmtimeWasmRuntime.cs @@ -126,10 +126,10 @@ private static void BindImport(Linker linker, WasmImportFunction import) { converted[i] = types[i] switch { - WasmValueType.Int32 => arguments[i].AsInt32(), - WasmValueType.Int64 => arguments[i].AsInt64(), - WasmValueType.Float32 => arguments[i].AsSingle(), - WasmValueType.Float64 => arguments[i].AsDouble(), + WasmValueType.Int32 => (object)arguments[i].AsInt32(), + WasmValueType.Int64 => (object)arguments[i].AsInt64(), + WasmValueType.Float32 => (object)arguments[i].AsSingle(), + WasmValueType.Float64 => (object)arguments[i].AsDouble(), _ => throw new NotSupportedException($"Unsupported argument type '{types[i]}'."), }; } From 5b123e8831fe0191ec65b01b3f1a7f0cc2bef514 Mon Sep 17 00:00:00 2001 From: Michael Thyregod <2386496+michaelthyregod@users.noreply.github.com> Date: Mon, 9 Nov 2026 05:21:17 +0100 Subject: [PATCH 2/2] Add the PR number to the CHANGELOG line --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bfce72..5fe044d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # 1.1.1 -- Fixed host import arguments arriving as `double` instead of their WebAssembly types @michaelthyregod +- Fixed host import arguments arriving as `double` instead of their WebAssembly types (#18) @michaelthyregod # 1.1.0