From fbed274902a6fe99f7f6bd6b1fffd97acf573a1b Mon Sep 17 00:00:00 2001 From: Tomohisa Takaoka Date: Sat, 31 Jan 2026 22:28:11 -0800 Subject: [PATCH] Toggle dev ABI layouts with DevBuild --- Directory.Build.props | 5 +- README.md | 12 +++++ src/TrapException.cs | 107 +++++++++++++++++++++++++++++++++++++++++- src/Value.cs | 59 +++++++++++++++++++++++ 4 files changed, 181 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 65eb7e5b..a0c461ff 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,4 +6,7 @@ $(WasmtimeVersion)$(WasmtimeDotnetVersion)-dev $(WasmtimeVersion)$(WasmtimeDotnetVersion) - \ No newline at end of file + + $(DefineConstants);WASMTIME_DEV + + diff --git a/README.md b/README.md index e0828d04..071fdc87 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,18 @@ $ dotnet build Wasmtime.sln This will download the latest development snapshot of Wasmtime for your platform. +By default, local builds set `DevBuild=true`, which uses the dev C API artifacts +(`wasmtime-dev-*`) and enables a `WASMTIME_DEV` build define to match the dev +ABI (value/trap layouts). To build against the stable Wasmtime release instead, +override the flag: + +``` +$ dotnet build Wasmtime.sln -p:DevBuild=false +``` + +If you switch between `DevBuild=true` and `DevBuild=false`, you may need to +delete `src/obj` to force the correct C API download. + ### Testing Use `dotnet` to run the unit tests: diff --git a/src/TrapException.cs b/src/TrapException.cs index a158dd0d..ede5f2ad 100644 --- a/src/TrapException.cs +++ b/src/TrapException.cs @@ -37,8 +37,112 @@ public enum TrapCode Unreachable = 9, /// The trap was the result of interrupting execution. Interrupt = 10, +#if WASMTIME_DEV + /// The trap was the result of running out of the configured fuel amount. + OutOfFuel = 11, + /// + /// The trap was the result of atomic wait operations on non-shared memory. + /// + AtomicWaitNonSharedMemory = 12, + /// + /// The trap was the result of a call to a null reference. + /// + NullReference = 13, + /// + /// The trap was the result of an attempt to access beyond the bounds of an array. + /// + ArrayOutOfBounds = 14, + /// + /// The trap was the result of an allocation that was too large to succeed. + /// + AllocationTooLarge = 15, + /// + /// The trap was the result of an attempt to cast a reference to a type that it is not an instance of. + /// + CastFailure = 16, + /// + /// The trap was the result of a component calling another component that would have violated the reentrance rules. + /// + CannotEnterComponent = 17, + /// + /// The trap was the result of an async-lifted export failing to return a valid async result. + /// + /// + /// An async-lifted export failed to produce a result by calling `task.return` before returning `STATUS_DONE` + /// and/or after all host tasks completed. + /// + NoAsyncResult = 18, + /// + /// The trap was the result of suspending to a tag for which there is no active handler. + /// + UnhandledTag = 19, + /// + /// The trap was the result of an attempt to resume a continuation twice. + /// + ContinuationAlreadyConsumed = 20, + /// + /// The trap was the result of a Pulley opcode executed at runtime when the opcode was disabled at compile time. + /// + DisabledOpCode = 21, + /// + /// The trap was the result of an async event loop deadlock. + /// + /// + /// The async event loop cannot make further progress given that all host tasks have completed + /// and any/all host-owned stream/future handles have been dropped. + /// + AsyncDeadlock = 22, + /// + /// The trap was the result of a component instance trying to call an import or intrinsic when not allowed. + /// + /// + /// When the component-model feature is enabled this trap represents a scenario where a component instance + /// tried to call an import or intrinsic when it wasn't allowed to, e.g. from a post-return function. + /// + CannotLeaveComponent = 23, + /// + /// The trap was the result of a synchronous task attempting to make a potentially blocking call prior to returning. + /// + CannotBlockSyncTask = 24, + /// + /// The trap was the result of a component trying to lift a char with an invalid bit pattern. + /// + InvalidChar = 25, + /// + /// Debug assertion generated for a fused adapter regarding the expected completion of a string encoding operation. + /// + DebugAssertStringEncodingFinished = 26, + /// + /// Debug assertion generated for a fused adapter regarding a string encoding operation. + /// + DebugAssertEqualCodeUnits = 27, + /// + /// Debug assertion generated for a fused adapter regarding the alignment of a pointer. + /// + DebugAssertPointerAligned = 28, + /// + /// Debug assertion generated for a fused adapter regarding the upper bits of a 64-bit value. + /// + DebugAssertUpperBitsUnset = 29, + /// + /// The trap was the result of a component trying to lift or lower a string past the end of its memory. + /// + StringOutOfBounds = 30, + /// + /// The trap was the result of a component trying to lift or lower a list past the end of its memory. + /// + ListOutOfBounds = 31, + /// + /// The trap was the result of a component using an invalid discriminant when lowering a variant value. + /// + InvalidDiscriminant = 32, + /// + /// The trap was the result of a component passing an unaligned pointer when lifting or lowering a value. + /// + UnalignedPointer = 33 +#else /// - /// The trap was the result of executing a function that was `canon lift`'d, then `canonlower`'d, then called. + /// The trap was the result of executing a function that was `canon lift`'d, then `canonlower`'d, then called. /// /// /// When the component model feature is enabled this trap represents a function that was `canon lift`'d, @@ -84,6 +188,7 @@ public enum TrapCode /// The trap was the result of a Pulley opcode executed at runtime when the opcode was disabled at compile time. /// DisabledOpCode = 20 +#endif } /// diff --git a/src/Value.cs b/src/Value.cs index eff55005..876b5f8a 100644 --- a/src/Value.cs +++ b/src/Value.cs @@ -212,9 +212,27 @@ private static class Native /// . /// /// +#if WASMTIME_DEV + [StructLayout(LayoutKind.Explicit, Size = 32)] + internal struct Value + { + static Value() + { + // Ensure the struct size matches the expected wasmtime_val_t size. + System.Diagnostics.Debug.Assert(Marshal.SizeOf(typeof(Value)) == 32, + $"Value struct size mismatch: expected 32, got {Marshal.SizeOf(typeof(Value))}"); + } +#else [StructLayout(LayoutKind.Sequential)] internal struct Value { + static Value() + { + // Ensure the struct size matches the expected wasmtime_val_t size. + System.Diagnostics.Debug.Assert(Marshal.SizeOf(typeof(Value)) == 24, + $"Value struct size mismatch: expected 24, got {Marshal.SizeOf(typeof(Value))}"); + } +#endif public void Release(Store store) { Native.wasmtime_val_unroot(store.Context.handle, this); @@ -490,9 +508,16 @@ public static class Native } public static readonly Native.Finalizer Finalizer = (p) => GCHandle.FromIntPtr(p).Free(); +#if WASMTIME_DEV + [FieldOffset(0)] + private ValueKind kind; + [FieldOffset(8)] + private ValueUnion of; +#else private ValueKind kind; private ValueUnion of; +#endif } [StructLayout(LayoutKind.Explicit)] @@ -523,9 +548,40 @@ internal unsafe struct ValueUnion public V128 v128; } +#if WASMTIME_DEV + [StructLayout(LayoutKind.Sequential)] + internal struct AnyRef + { + static AnyRef() => System.Diagnostics.Debug.Assert(Marshal.SizeOf(typeof(AnyRef)) == 24); + + public ulong store; + + private uint __private1; + + private uint __private2; + + private IntPtr __private3; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ExternRef + { + static ExternRef() => System.Diagnostics.Debug.Assert(Marshal.SizeOf(typeof(ExternRef)) == 24); + + public ulong store; + + private uint __private1; + + private uint __private2; + + private IntPtr __private3; + } +#else [StructLayout(LayoutKind.Sequential)] internal struct AnyRef { + static AnyRef() => System.Diagnostics.Debug.Assert(Marshal.SizeOf(typeof(AnyRef)) == 16); + public ulong store; private uint __private1; @@ -536,10 +592,13 @@ internal struct AnyRef [StructLayout(LayoutKind.Sequential)] internal struct ExternRef { + static ExternRef() => System.Diagnostics.Debug.Assert(Marshal.SizeOf(typeof(ExternRef)) == 16); + public ulong store; private uint __private1; private uint __private2; } +#endif }