From 5303d14f9431d6d8310721b8d2325e8131390ecf Mon Sep 17 00:00:00 2001 From: Austin Drenski Date: Tue, 13 Oct 2026 09:04:09 -0400 Subject: [PATCH 1/3] Add support for wasmtime_linker_clone --- src/Linker.cs | 10 +++++ tests/LinkerTests.cs | 89 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/Linker.cs b/src/Linker.cs index 2e36b29d..3157a6f5 100644 --- a/src/Linker.cs +++ b/src/Linker.cs @@ -27,6 +27,8 @@ public Linker(Engine engine) handle = new Handle(Native.wasmtime_linker_new(engine.NativeHandle)); } + private Linker(IntPtr handle) => this.handle = new Handle(handle); + /// /// Configures whether or not the linker allows later definitions to shadow previous definitions. /// @@ -38,6 +40,11 @@ public bool AllowShadowing } } + /// + /// Clones existing linker. + /// + public Linker Clone() => new Linker(Native.wasmtime_linker_clone(handle)); + private void Define(string module, string name, T item) where T : IExternal { @@ -511,6 +518,9 @@ internal static class Native [DllImport(Engine.LibraryName)] public static extern void wasmtime_linker_allow_shadowing(Handle linker, [MarshalAs(UnmanagedType.I1)] bool allow); + [DllImport(Engine.LibraryName)] + public static extern IntPtr wasmtime_linker_clone(Handle linker); + [DllImport(Engine.LibraryName)] public static unsafe extern IntPtr wasmtime_linker_define(Handle linker, IntPtr context, byte* module, nuint moduleLen, byte* name, nuint nameLen, in Extern item); diff --git a/tests/LinkerTests.cs b/tests/LinkerTests.cs index 6bab78ec..ab16d4b3 100644 --- a/tests/LinkerTests.cs +++ b/tests/LinkerTests.cs @@ -35,6 +35,95 @@ public void ItThrowsWithNullEngine() Assert.Throws(() => new Linker(null!)); } + [Fact] + public void CloneCarriesAllowShadowing() + { + Linker.AllowShadowing = true; + + using var clone = Linker.Clone(); + + clone.DefineFunction("", "hello", () => { }); + clone.DefineFunction("", "hello", () => { }); + } + + [Fact] + public void CloneCarriesDefinitions() + { + var called = 0; + Linker.DefineFunction("", "hello", () => { called++; }); + + using var clone = Linker.Clone(); + clone.GetFunction(Store, "", "hello")!.Invoke(); + + Assert.Equal(1, called); + } + + [Fact] + public void CloneCarriesWasi() + { + Linker.DefineWasi(); + + using var clone = Linker.Clone(); + + Assert.Throws(() => clone.DefineWasi()); + } + + [Fact] + public void CloneDisallowsShadowingByDefault() + { + using var clone = Linker.Clone(); + + clone.DefineFunction("", "hello", () => { }); + Assert.Throws(() => clone.DefineFunction("", "hello", () => { })); + } + + [Fact] + public void CloneDoesNotShareDefinitionsAddedToTheClone() + { + using var clone = Linker.Clone(); + clone.DefineFunction("", "hello", () => { }); + + Assert.NotNull(clone.GetFunction(Store, "", "hello")); + Assert.Null(Linker.GetFunction(Store, "", "hello")); + } + + [Fact] + public void CloneDoesNotShareDefinitionsAddedToTheOriginal() + { + using var clone = Linker.Clone(); + Linker.DefineFunction("", "hello", () => { }); + + Assert.NotNull(Linker.GetFunction(Store, "", "hello")); + Assert.Null(clone.GetFunction(Store, "", "hello")); + } + + [Fact] + public void CloneOutlivesTheOriginal() + { + var called = 0; + var linker = new Linker(Fixture.Engine); + linker.DefineFunction("", "hello", () => { called++; }); + + using var clone = linker.Clone(); + linker.Dispose(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + + clone.GetFunction(Store, "", "hello")!.Invoke(); + + Assert.Equal(1, called); + } + + [Fact] + public void CloneThrowsWhenDisposed() + { + var linker = new Linker(Fixture.Engine); + linker.Dispose(); + + Assert.Throws(() => linker.Clone()); + } + [Fact] public void DefineThrowsWithNullStore() { From 79ee7a06dcb079cc8b5ea2ee26ce5b4e2c3ea737 Mon Sep 17 00:00:00 2001 From: Martin Evans Date: Fri, 16 Oct 2026 03:11:07 +0100 Subject: [PATCH 2/3] Update src/Linker.cs --- src/Linker.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Linker.cs b/src/Linker.cs index 3157a6f5..b1c18658 100644 --- a/src/Linker.cs +++ b/src/Linker.cs @@ -27,7 +27,10 @@ public Linker(Engine engine) handle = new Handle(Native.wasmtime_linker_new(engine.NativeHandle)); } - private Linker(IntPtr handle) => this.handle = new Handle(handle); + private Linker(IntPtr handle) + { + this.handle = new Handle(handle); + } /// /// Configures whether or not the linker allows later definitions to shadow previous definitions. From 5e89cf4c3d151d861f50566800e29c10772c4f8b Mon Sep 17 00:00:00 2001 From: Martin Evans Date: Fri, 16 Oct 2026 03:11:14 +0100 Subject: [PATCH 3/3] Update src/Linker.cs --- src/Linker.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Linker.cs b/src/Linker.cs index b1c18658..98a01180 100644 --- a/src/Linker.cs +++ b/src/Linker.cs @@ -46,7 +46,10 @@ public bool AllowShadowing /// /// Clones existing linker. /// - public Linker Clone() => new Linker(Native.wasmtime_linker_clone(handle)); + public Linker Clone() + { + return new Linker(Native.wasmtime_linker_clone(handle)); + } private void Define(string module, string name, T item) where T : IExternal