diff --git a/src/Config.cs b/src/Config.cs index 76adc3a..273bb14 100644 --- a/src/Config.cs +++ b/src/Config.cs @@ -1,6 +1,6 @@ +using Microsoft.Win32.SafeHandles; using System; using System.Runtime.InteropServices; -using Microsoft.Win32.SafeHandles; namespace Wasmtime { @@ -107,6 +107,39 @@ public Config WithFuelConsumption(bool enable) return this; } + /// + /// Sets whether or not to the WebAssembly tail call proposal is enabled. + /// + /// True to enable tails calls or false to disable. + /// Returns the current config. + public Config WithTailCalls(bool enable) + { + Native.wasmtime_config_wasm_tail_call_set(handle, enable); + return this; + } + + /// + /// Sets whether the WebAssembly typed function reference types proposal is enabled. + /// + /// True to enable function references or false to disable. + /// Returns the current config. + public Config WithFunctionReferences(bool enable) + { + Native.wasmtime_config_wasm_function_references_set(handle, enable); + return this; + } + + /// + /// Sets whether the WebAssembly GC proposal is enabled. + /// + /// True to enable GC or false to disable. + /// Returns the current config. + public Config WithGc(bool enable) + { + Native.wasmtime_config_wasm_gc_set(handle, enable); + return this; + } + /// /// Sets the maximum WebAssembly stack size. /// @@ -213,6 +246,41 @@ public Config WithMemory64(bool enable) return this; } + /// + /// Sets whether the WebAssembly wide-arithmetic proposal is enabled. + /// + /// True to enable WebAssembly wide arithmetic support or false to disable. + /// Returns the current config. + public Config WithWideArithmetic(bool enable) + { + Native.wasmtime_config_wasm_wide_arithmetic_set(handle, enable); + return this; + } + + /// + /// Sets whether the WebAssembly stack switching proposal is enabled. + /// + /// True to enable WebAssembly stack switching support or false to disable. + /// Returns the current config. + private Config WithStackSwitching(bool enable) + { + // todo: unlikely to be compatible with wasmtime-dotnet on Windows due to threads + + Native.wasmtime_config_wasm_stack_switching_set(handle, enable); + return this; + } + + /// + /// Sets whether wasmtime should compile a module using multiple threads. + /// + /// True to enable parallel compilation or false to disable. + /// Returns the current config. + public Config WithParallelCompilation(bool enable) + { + Native.wasmtime_config_parallel_compilation_set(handle, enable); + return this; + } + /// /// Sets the compiler strategy to use. /// @@ -240,6 +308,17 @@ public Config WithCraneliftDebugVerifier(bool enable) return this; } + /// + /// Configures whether memory_reservation is the maximal size of linear memory. + /// + /// True to allow memory base pointer to move or false to disable + /// Returns the current config. + public Config WithMemoryMayMove(bool enable) + { + Native.wasmtime_config_memory_may_move_set(handle, enable); + return this; + } + /// /// Configures whether Cranelift should perform a NaN-canonicalization pass. /// @@ -292,9 +371,9 @@ public Config WithProfilingStrategy(ProfilingStrategy strategy) } /// - /// Sets the maximum size of static WebAssembly linear memories. + /// Configures the size, in bytes, of initial memory reservation size for linear memories. If if not set, this is the maximum size of memory. /// - /// The maximum size of static WebAssembly linear memories, in bytes. + /// The initial size of static WebAssembly linear memories, in bytes. /// Returns the current config. public Config WithStaticMemoryMaximumSize(ulong size) { @@ -302,6 +381,33 @@ public Config WithStaticMemoryMaximumSize(ulong size) return this; } + /// + /// Configures the size, in bytes, of the extra virtual memory space reserved for memories to grow into after being relocated. + /// + /// The extra reserved bytes of virtual memory reserved for future growth. + /// Returns the current config. + public Config WithMemoryReservationForGrowth(ulong size) + { + Native.wasmtime_config_memory_reservation_for_growth_set(handle, size); + return this; + } + + /// + /// Configures whether copy-on-write memory-mapped data is used to initialize a linear memory. + /// Initializing linear memory via a copy-on-write mapping can drastically improve instantiation costs of a + /// WebAssembly module because copying memory is deferred.Additionally if a page of memory is only ever read + /// from WebAssembly and never written too then the same underlying page of data will be reused between + /// all instantiations of a module meaning that if a module is instantiated many times this can lower the + /// overall memory required needed to run that module. + /// + /// True to enable copy on write for memory initialisation or false to disable. + /// Returns the current config. + public Config WithMemoryInitCopyOnWrite(bool enabled) + { + Native.wasmtime_config_memory_init_cow_set(handle, enabled); + return this; + } + /// /// Sets the size of the guard region used at the end of a linear memory’s address space reservation /// @@ -346,6 +452,45 @@ public Config WithMacosMachPorts(bool enable) return this; } + /// + /// Configures whether to generate native unwind information (e.g. .eh_frame on Linux). + /// + /// For more information see the Rust documentation at https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.native_unwind_info + /// + /// True to enable unwind info or false to disable. + /// Returns the current config. + public Config WithUnwindInfo(bool enable) + { + Native.wasmtime_config_native_unwind_info_set(handle, enable); + return this; + } + + /// + /// Sets the Wasmtime allocation strategy to use the pooling allocator. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.allocation_strategy + /// + /// The pooling strategy config + /// + public Config WithPoolingAllocationStrategy(PoolingAllocationConfig strategy) + { + PoolingAllocationConfig.Native.wasmtime_pooling_allocation_strategy_set(NativeHandle, strategy.NativeHandle); + return this; + } + + /// + /// Configures whether the WebAssembly component-model proposal will be enabled for compilation. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.wasm_component_model + /// + /// True to enable component model or false to disable. + /// + public Config WithComponentModel(bool enabled) + { + Native.wasmtime_config_wasm_component_model_set(NativeHandle, enabled); + return this; + } + /// public void Dispose() { @@ -397,6 +542,15 @@ private static class Native [DllImport(Engine.LibraryName)] public static extern void wasmtime_config_consume_fuel_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_wasm_tail_call_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_wasm_function_references_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_wasm_gc_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + [DllImport(Engine.LibraryName)] public static extern void wasmtime_config_max_wasm_stack_set(Handle config, nuint size); @@ -426,6 +580,15 @@ private static class Native [DllImport(Engine.LibraryName)] public static extern void wasmtime_config_wasm_memory64_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_wasm_wide_arithmetic_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_wasm_stack_switching_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_parallel_compilation_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); [DllImport(Engine.LibraryName)] public static extern void wasmtime_config_strategy_set(Handle config, byte strategy); @@ -435,6 +598,18 @@ private static class Native [DllImport(Engine.LibraryName)] public static extern void wasmtime_config_cranelift_nan_canonicalization_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_memory_may_move_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_native_unwind_info_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_memory_init_cow_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_memory_reservation_for_growth_set(Handle config, ulong bytes); [DllImport(Engine.LibraryName)] public static extern void wasmtime_config_cranelift_opt_level_set(Handle config, byte level); @@ -453,6 +628,11 @@ private static class Native [DllImport(Engine.LibraryName)] public static extern void wasmtime_config_macos_use_mach_ports(Handle config, [MarshalAs(UnmanagedType.I1)] bool enable); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_config_wasm_component_model_set(Handle config, [MarshalAs(UnmanagedType.I1)] bool value); + + // todo: void wasmtime_config_host_memory_creator_set(wasm_config_t *, wasmtime_memory_creator_t *) } private readonly Handle handle; diff --git a/src/PoolingAllocationConfig.cs b/src/PoolingAllocationConfig.cs new file mode 100644 index 0000000..305494b --- /dev/null +++ b/src/PoolingAllocationConfig.cs @@ -0,0 +1,393 @@ +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; + +namespace Wasmtime; + +/// +/// A type containing configuration options for the pooling allocator. For more information +/// see the Rust documentation at https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html +/// +public class PoolingAllocationConfig + : IDisposable +{ + private readonly Handle handle; + + /// + /// Creates a new configuration. + /// + public PoolingAllocationConfig() + { + handle = new Handle(Native.wasmtime_pooling_allocation_config_new()); + } + + /// + public void Dispose() + { + handle.Dispose(); + } + + internal Handle NativeHandle + { + get + { + if (handle.IsInvalid || handle.IsClosed) + { + throw new ObjectDisposedException(typeof(Config).FullName); + } + + return handle; + } + } + + /// + /// Configures the maximum number of “unused warm slots” to retain in the pooling allocator. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_unused_warm_slots + /// + /// + /// + public PoolingAllocationConfig WithMaxUnusedWarmSlots(uint count) + { + Native.wasmtime_pooling_allocation_config_max_unused_warm_slots_set(NativeHandle, count); + return this; + } + + /// + /// The target number of decommits to do per batch. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.decommit_batch_size + /// + /// + /// + public PoolingAllocationConfig WithDecommitBatchSize(nuint count) + { + Native.wasmtime_pooling_allocation_config_decommit_batch_size_set(NativeHandle, count); + return this; + } + + /// + /// How much memory, in bytes, to keep resident for async stacks allocated with the pooling allocator. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.async_stack_keep_resident + /// + /// + /// + private PoolingAllocationConfig WithAsyncStackKeepResidentBytes(nuint bytes) + { + // todo: Wasmtime-dotnet does not support async! Expose this if support is added. + + Native.wasmtime_pooling_allocation_config_async_stack_keep_resident_set(NativeHandle, bytes); + return this; + } + + /// + /// How much memory, in bytes, to keep resident for each linear memory after deallocation. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.linear_memory_keep_resident + /// + /// + /// + public PoolingAllocationConfig WithLinearMemoryKeepResidentBytes(nuint bytes) + { + Native.wasmtime_pooling_allocation_config_linear_memory_keep_resident_set(NativeHandle, bytes); + return this; + } + + /// + /// How much memory, in bytes, to keep resident for each table after deallocation. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.table_keep_resident + /// + /// + /// + public PoolingAllocationConfig WithTableKeepResidentBytes(nuint bytes) + { + Native.wasmtime_pooling_allocation_config_table_keep_resident_set(NativeHandle, bytes); + return this; + } + + /// + /// The maximum number of concurrent component instances supported (default is 1000). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.total_component_instances + /// + /// + /// + public PoolingAllocationConfig WithTotalComponentInstances(uint count) + { + Native.wasmtime_pooling_allocation_config_total_component_instances_set(NativeHandle, count); + return this; + } + + /// + /// The maximum size, in bytes, allocated for a component instance’s VMComponentContext metadata. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_component_instance_size + /// + /// + /// + public PoolingAllocationConfig WithMaxComponentInstanceSize(nuint bytes) + { + Native.wasmtime_pooling_allocation_config_max_component_instance_size_set(NativeHandle, bytes); + return this; + } + + /// + /// The maximum size, in bytes, allocated for a core instance’s VMContext metadata. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_core_instance_size + /// + /// + /// + public PoolingAllocationConfig WithMaxCoreInstanceSize(nuint bytes) + { + Native.wasmtime_pooling_allocation_config_max_core_instance_size_set(NativeHandle, bytes); + return this; + } + + /// + /// The maximum number of core instances a single component may contain (default is unlimited). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_core_instances_per_component + /// + /// + /// + public PoolingAllocationConfig WithMaxCoreInstancesPerComponent(uint count) + { + Native.wasmtime_pooling_allocation_config_max_core_instances_per_component_set(NativeHandle, count); + return this; + } + + /// + /// The maximum number of Wasm linear memories that a single component may transitively contain (default is unlimited). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_memories_per_component + /// + /// + /// + public PoolingAllocationConfig WithMaxMemoriesPerComponent(uint count) + { + Native.wasmtime_pooling_allocation_config_max_memories_per_component_set(NativeHandle, count); + return this; + } + + /// + /// The maximum number of tables that a single component may transitively contain (default is unlimited). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_tables_per_component + /// + /// + /// + public PoolingAllocationConfig WithMaxTablesPerComponent(uint count) + { + Native.wasmtime_pooling_allocation_config_max_tables_per_component_set(NativeHandle, count); + return this; + } + + /// + /// The maximum number of concurrent Wasm linear memories supported (default is 1000). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.total_memories + /// + /// + /// + public PoolingAllocationConfig WithMaxMemories(uint count) + { + Native.wasmtime_pooling_allocation_config_total_memories_set(NativeHandle, count); + return this; + } + + /// + /// The maximum number of execution stacks allowed for asynchronous execution, when enabled (default is 1000). + /// For more information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.total_stacks + /// + /// + /// + private PoolingAllocationConfig WithMaxStacks(uint count) + { + // todo: Wasmtime-dotnet does not support async! Expose this if support is added. + + Native.wasmtime_pooling_allocation_config_total_stacks_set(NativeHandle, count); + return this; + } + + /// + /// The maximum number of concurrent tables supported (default is 1000). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.total_tables + /// + /// + /// + public PoolingAllocationConfig WithMaxTables(uint count) + { + Native.wasmtime_pooling_allocation_config_total_tables_set(NativeHandle, count); + return this; + } + + /// + /// The maximum number of concurrent core instances supported (default is 1000). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.total_core_instances + /// + /// + /// + public PoolingAllocationConfig WithMaxCoreInstances(uint count) + { + Native.wasmtime_pooling_allocation_config_total_core_instances_set(NativeHandle, count); + return this; + } + + /// + /// The maximum number of defined tables for a core module (default is 1). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_tables_per_module + /// + /// + /// + public PoolingAllocationConfig WithMaxTablesPerModule(uint count) + { + Native.wasmtime_pooling_allocation_config_max_tables_per_module_set(NativeHandle, count); + return this; + } + + /// + /// The maximum table elements for any table defined in a module (default is 20000). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.table_elements + /// + /// + /// + public PoolingAllocationConfig WithMaxTableElements(nuint count) + { + Native.wasmtime_pooling_allocation_config_table_elements_set(NativeHandle, count); + return this; + } + + /// + /// The maximum number of defined linear memories for a module (default is 1). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_memories_per_module + /// + /// + /// + public PoolingAllocationConfig WithMaxMemoriesPerModule(uint count) + { + Native.wasmtime_pooling_allocation_config_max_memories_per_module_set(NativeHandle, count); + return this; + } + + /// + /// The maximum byte size that any WebAssembly linear memory may grow to. For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.max_memory_size + /// + /// + /// + public PoolingAllocationConfig WithMaxMemorySize(nuint bytes) + { + Native.wasmtime_pooling_allocation_config_max_memory_size_set(NativeHandle, bytes); + return this; + } + + /// + /// The maximum number of concurrent GC heaps supported (default is 1000). For more + /// information see the Rust documentation at + /// https://docs.wasmtime.dev/api/wasmtime/struct.PoolingAllocationConfig.html#method.total_gc_heaps + /// + /// + /// + public PoolingAllocationConfig WithMaxGcHeaps(uint count) + { + Native.wasmtime_pooling_allocation_config_total_gc_heaps_set(NativeHandle, count); + return this; + } + + internal class Handle : SafeHandleZeroOrMinusOneIsInvalid + { + public Handle(IntPtr handle) + : base(true) + { + SetHandle(handle); + } + + protected override bool ReleaseHandle() + { + Native.wasmtime_pooling_allocation_config_delete(handle); + return true; + } + } + + internal static class Native + { + [DllImport(Engine.LibraryName)] + public static extern IntPtr wasmtime_pooling_allocation_config_new(); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_delete(IntPtr intPtr); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_unused_warm_slots_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_decommit_batch_size_set(Handle handle, nuint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_async_stack_keep_resident_set(Handle handle, nuint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_linear_memory_keep_resident_set(Handle handle, nuint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_table_keep_resident_set(Handle handle, nuint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_total_component_instances_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_component_instance_size_set(Handle handle, nuint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_core_instances_per_component_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_memories_per_component_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_tables_per_component_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_total_memories_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_total_tables_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_total_stacks_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_total_core_instances_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_core_instance_size_set(Handle handle, nuint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_tables_per_module_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_table_elements_set(Handle handle, nuint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_memories_per_module_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_max_memory_size_set(Handle handle, nuint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_config_total_gc_heaps_set(Handle handle, uint value); + + [DllImport(Engine.LibraryName)] + public static extern void wasmtime_pooling_allocation_strategy_set(Config.Handle configHandle, Handle handle); + } +} \ No newline at end of file diff --git a/tests/ConfigTests.cs b/tests/ConfigTests.cs index 028fa10..5e1d20c 100644 --- a/tests/ConfigTests.cs +++ b/tests/ConfigTests.cs @@ -94,6 +94,16 @@ public void ItSetsDebugInfo() using var engine = new Engine(config); } + [Fact] + public void ItSetsWideArithmetic() + { + var config = new Config(); + + config.WithWideArithmetic(true); + + using var engine = new Engine(config); + } + [Fact] public void ItSetsThreads() { @@ -178,5 +188,21 @@ public void ItCannotBeAccessedOnceDisposed() Assert.Throws(() => config.WithCacheConfig(null)); Assert.Throws(() => config.WithEpochInterruption(true)); } + + [Fact] + public void ItSetsPoolingStrategy() + { + using var strategy = new PoolingAllocationConfig() + .WithDecommitBatchSize(4) + .WithLinearMemoryKeepResidentBytes(8) + .WithMaxGcHeaps(15) + .WithMaxMemorySize(16) + .WithMaxUnusedWarmSlots(23) + .WithTableKeepResidentBytes(42); + + using var config = new Config(); + config.WithPoolingAllocationStrategy(strategy); + using var engine = new Engine(config); + } } }