From b23ef57259fdfcecff2817cba1da9f2d9d139478 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 27 Oct 2023 21:30:13 +0100 Subject: [PATCH] Update wasmtime headers, use latest wasmtime C APIs --- lib/src/wasm.c | 23 +- lib/src/wasm/wasmtime/async.h | 369 +++++++++++++++++++++++++++++++ lib/src/wasm/wasmtime/config.h | 207 ++++++++++++++++- lib/src/wasm/wasmtime/error.h | 23 ++ lib/src/wasm/wasmtime/func.h | 12 +- lib/src/wasm/wasmtime/instance.h | 45 ++++ lib/src/wasm/wasmtime/linker.h | 20 ++ lib/src/wasm/wasmtime/memory.h | 2 +- lib/src/wasm/wasmtime/module.h | 15 ++ lib/src/wasm/wasmtime/store.h | 91 +++++--- lib/src/wasm/wasmtime/trap.h | 11 +- lib/src/wasm/wasmtime/val.h | 38 ++-- 12 files changed, 785 insertions(+), 71 deletions(-) create mode 100644 lib/src/wasm/wasmtime/async.h diff --git a/lib/src/wasm.c b/lib/src/wasm.c index b7e35d67..e763884d 100644 --- a/lib/src/wasm.c +++ b/lib/src/wasm.c @@ -1021,7 +1021,12 @@ void ts_wasm_store_stop(TSWasmStore *self) { self->current_instance = NULL; } -static void ts_wasm_store__call(TSWasmStore *self, int32_t function_index, wasmtime_val_raw_t *args_and_results) { +static void ts_wasm_store__call( + TSWasmStore *self, + int32_t function_index, + wasmtime_val_raw_t *args_and_results, + size_t args_and_results_len +) { wasmtime_context_t *context = wasmtime_store_context(self->store); wasmtime_val_t value; bool succeeded = wasmtime_table_get(context, &self->function_table, function_index, &value); @@ -1029,7 +1034,9 @@ static void ts_wasm_store__call(TSWasmStore *self, int32_t function_index, wasmt assert(value.kind == WASMTIME_FUNCREF); wasmtime_func_t func = value.of.funcref; - wasm_trap_t *trap = wasmtime_func_call_unchecked(context, &func, args_and_results); + wasm_trap_t *trap = NULL; + wasmtime_error_t *error = wasmtime_func_call_unchecked(context, &func, args_and_results, args_and_results_len, &trap); + assert(!error); if (trap) { wasm_message_t message; wasm_trap_message(trap, &message); @@ -1051,7 +1058,7 @@ static bool ts_wasm_store__call_lex_function(TSWasmStore *self, unsigned functio {.i32 = LEXER_ADDRESS}, {.i32 = state}, }; - ts_wasm_store__call(self, function_index, args); + ts_wasm_store__call(self, function_index, args, 2); bool result = args[0].i32; memcpy( @@ -1080,13 +1087,13 @@ bool ts_wasm_store_call_lex_keyword(TSWasmStore *self, TSStateId state) { uint32_t ts_wasm_store_call_scanner_create(TSWasmStore *self) { wasmtime_val_raw_t args[1] = {{.i32 = 0}}; - ts_wasm_store__call(self, self->current_instance->scanner_create_fn_index, args); + ts_wasm_store__call(self, self->current_instance->scanner_create_fn_index, args, 1); return args[0].i32; } void ts_wasm_store_call_scanner_destroy(TSWasmStore *self, uint32_t scanner_address) { wasmtime_val_raw_t args[1] = {{.i32 = scanner_address}}; - ts_wasm_store__call(self, self->current_instance->scanner_destroy_fn_index, args); + ts_wasm_store__call(self, self->current_instance->scanner_destroy_fn_index, args, 1); } bool ts_wasm_store_call_scanner_scan( @@ -1111,7 +1118,7 @@ bool ts_wasm_store_call_scanner_scan( {.i32 = LEXER_ADDRESS}, {.i32 = valid_tokens_address} }; - ts_wasm_store__call(self, self->current_instance->scanner_scan_fn_index, args); + ts_wasm_store__call(self, self->current_instance->scanner_scan_fn_index, args, 3); memcpy( &self->current_lexer->lookahead, @@ -1133,7 +1140,7 @@ uint32_t ts_wasm_store_call_scanner_serialize( {.i32 = scanner_address}, {.i32 = SERIALIZATION_BUFFER_ADDRESS}, }; - ts_wasm_store__call(self, self->current_instance->scanner_serialize_fn_index, args); + ts_wasm_store__call(self, self->current_instance->scanner_serialize_fn_index, args, 2); uint32_t length = args[0].i32; if (length > 0) { @@ -1168,7 +1175,7 @@ void ts_wasm_store_call_scanner_deserialize( {.i32 = SERIALIZATION_BUFFER_ADDRESS}, {.i32 = length}, }; - ts_wasm_store__call(self, self->current_instance->scanner_deserialize_fn_index, args); + ts_wasm_store__call(self, self->current_instance->scanner_deserialize_fn_index, args, 3); } bool ts_language_is_wasm(const TSLanguage *self) { diff --git a/lib/src/wasm/wasmtime/async.h b/lib/src/wasm/wasmtime/async.h new file mode 100644 index 00000000..1b490003 --- /dev/null +++ b/lib/src/wasm/wasmtime/async.h @@ -0,0 +1,369 @@ +/** + * \file wasmtime/async.h + * + * \brief Wasmtime async functionality + * + * Async functionality in Wasmtime is well documented here: + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.async_support + * + * All WebAssembly executes synchronously, but an async support enables the Wasm code + * be executed on a seperate stack, so it can be paused and resumed. There are three + * mechanisms for yielding control from wasm to the caller: fuel, epochs, and async host functions. + * + * When WebAssembly is executed, a #wasmtime_call_future_t is returned. This struct represents the + * state of the execution and each call to #wasmtime_call_future_poll will execute the WebAssembly + * code on a seperate stack until the function returns or yields control back to the caller. + * + * It's expected these futures are pulled in a loop until completed, at which point the future + * should be deleted. Functions that return a #wasmtime_call_future_t are special in that all + * parameters to that function should not be modified in any way and must be kept alive until + * the future is deleted. This includes concurrent calls for a single store - another function + * on a store should not be called while there is a #wasmtime_call_future_t alive. + * + * As for asynchronous host calls - the reverse contract is upheld. Wasmtime will keep all parameters + * to the function alive and unmodified until the #wasmtime_func_async_continuation_callback_t returns + * true. + * + */ + +#ifndef WASMTIME_ASYNC_H +#define WASMTIME_ASYNC_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Whether or not to enable support for asynchronous functions in Wasmtime. + * + * When enabled, the config can optionally define host functions with async. + * Instances created and functions called with this Config must be called through their asynchronous APIs, however. + * For example using wasmtime_func_call will panic when used with this config. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.async_support + */ +WASMTIME_CONFIG_PROP(void, async_support, bool) + +/** + * \brief Configures the size of the stacks used for asynchronous execution. + * + * This setting configures the size of the stacks that are allocated for asynchronous execution. + * + * The value cannot be less than max_wasm_stack. + * + * The amount of stack space guaranteed for host functions is async_stack_size - max_wasm_stack, so take care + * not to set these two values close to one another; doing so may cause host functions to overflow the stack + * and abort the process. + * + * By default this option is 2 MiB. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.async_stack_size + */ +WASMTIME_CONFIG_PROP(void, async_stack_size, uint64_t) + +/** + * \brief Configures a Store to yield execution of async WebAssembly code + * periodically. + * + * When a Store is configured to consume fuel with + * `wasmtime_config_consume_fuel` this method will configure what happens when + * fuel runs out. Specifically executing WebAssembly will be suspended and + * control will be yielded back to the caller. + * + * This is only suitable with use of a store associated with an async config + * because only then are futures used and yields are possible. + * + * \param context the context for the store to configure. + * \param interval the amount of fuel at which to yield. A value of 0 will + * disable yielding. + */ +WASM_API_EXTERN void +wasmtime_context_fuel_async_yield_interval(wasmtime_context_t *context, + uint64_t interval); + +/** + * \brief Configures epoch-deadline expiration to yield to the async caller and the update the deadline. + * + * This is only suitable with use of a store associated with an async config because + * only then are futures used and yields are possible. + * + * See the Rust documentation for more: + * https://docs.wasmtime.dev/api/wasmtime/struct.Store.html#method.epoch_deadline_async_yield_and_update + */ +WASM_API_EXTERN wasmtime_error_t* wasmtime_context_epoch_deadline_async_yield_and_update( + wasmtime_context_t *context, + uint64_t delta); + +/** + * The callback to determine a continuation's current state. + * + * Return true if the host call has completed, otherwise false will + * continue to yield WebAssembly execution. + */ +typedef bool (*wasmtime_func_async_continuation_callback_t)(void *env); + +/** + * A continuation for the current state of the host function's execution. + */ +typedef struct wasmtime_async_continuation_t { + /// Callback for if the async function has completed. + wasmtime_func_async_continuation_callback_t callback; + /// User-provided argument to pass to the callback. + void *env; + /// A finalizer for the user-provided *env + void (*finalizer)(void *); +} wasmtime_async_continuation_t; + +/** + * \brief Callback signature for #wasmtime_linker_define_async_func. + * + * This is a host function that returns a continuation to be called later. + * + * All the arguments to this function will be kept alive until the continuation + * returns that it has errored or has completed. + * + * \param env user-provided argument passed to #wasmtime_linker_define_async_func + * \param caller a temporary object that can only be used during this function + * call. Used to acquire #wasmtime_context_t or caller's state + * \param args the arguments provided to this function invocation + * \param nargs how many arguments are provided + * \param results where to write the results of this function + * \param nresults how many results must be produced + * \param trap_ret if assigned a not `NULL` value then the called function will + * trap with the returned error. Note that ownership of trap is transferred + * to wasmtime. + * \param continuation_ret the returned continuation that determines when the + * async function has completed executing. + * + * Only supported for async stores. + * + * See #wasmtime_func_callback_t for more information. + */ +typedef void (*wasmtime_func_async_callback_t)( + void *env, + wasmtime_caller_t *caller, + const wasmtime_val_t *args, + size_t nargs, + wasmtime_val_t *results, + size_t nresults, + wasm_trap_t** trap_ret, + wasmtime_async_continuation_t * continuation_ret); + +/** + * \brief The structure representing a asynchronously running function. + * + * This structure is always owned by the caller and must be deleted using #wasmtime_call_future_delete. + * + * Functions that return this type require that the parameters to the function are unmodified until + * this future is destroyed. + */ +typedef struct wasmtime_call_future wasmtime_call_future_t; + +/** + * \brief Executes WebAssembly in the function. + * + * Returns true if the function call has completed. After this function returns true, it should *not* be + * called again for a given future. + * + * This function returns false if execution has yielded either due to being out of fuel + * (see wasmtime_context_fuel_async_yield_interval), or the epoch has been incremented enough + * (see wasmtime_context_epoch_deadline_async_yield_and_update). The function may also return false if + * asynchronous host functions have been called, which then calling this function will call the + * continuation from the async host function. + * + * For more see the information at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#asynchronous-wasm + * + */ +WASM_API_EXTERN bool wasmtime_call_future_poll(wasmtime_call_future_t *future); + +/** + * /brief Frees the underlying memory for a future. + * + * All wasmtime_call_future_t are owned by the caller and should be deleted using this function. + */ +WASM_API_EXTERN void wasmtime_call_future_delete(wasmtime_call_future_t *future); + +/** + * \brief Invokes this function with the params given, returning the results asynchronously. + * + * This function is the same as wasmtime_func_call except that it is asynchronous. + * This is only compatible with stores associated with an asynchronous config. + * + * The result is a future that is owned by the caller and must be deleted via #wasmtime_call_future_delete. + * + * The `args` and `results` pointers may be `NULL` if the corresponding length is zero. + * The `trap_ret` and `error_ret` pointers may *not* be `NULL`. + * + * Does not take ownership of #wasmtime_val_t arguments or #wasmtime_val_t results, + * and all parameters to this function must be kept alive and not modified until the + * returned #wasmtime_call_future_t is deleted. This includes the context and store + * parameters. Only a single future can be alive for a given store at a single time + * (meaning only call this function after the previous call's future was deleted). + * + * See the header documentation for for more information. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Func.html#method.call_async + */ +WASM_API_EXTERN wasmtime_call_future_t* wasmtime_func_call_async( + wasmtime_context_t *context, + const wasmtime_func_t *func, + const wasmtime_val_t *args, + size_t nargs, + wasmtime_val_t *results, + size_t nresults, + wasm_trap_t** trap_ret, + wasmtime_error_t** error_ret); + +/** + * \brief Defines a new async function in this linker. + * + * This function behaves similar to #wasmtime_linker_define_func, except it supports async + * callbacks. + * + * The callback `cb` will be invoked on another stack (fiber for Windows). + */ +WASM_API_EXTERN wasmtime_error_t *wasmtime_linker_define_async_func( + wasmtime_linker_t *linker, + const char *module, + size_t module_len, + const char *name, + size_t name_len, + const wasm_functype_t *ty, + wasmtime_func_async_callback_t cb, + void *data, + void (*finalizer)(void *)); + +/** + * \brief Instantiates a #wasm_module_t with the items defined in this linker for an async store. + * + * This is the same as #wasmtime_linker_instantiate but used for async stores + * (which requires functions are called asynchronously). The returning #wasmtime_call_future_t + * must be polled using #wasmtime_call_future_poll, and is owned and must be deleted using #wasmtime_call_future_delete. + * + * The `trap_ret` and `error_ret` pointers may *not* be `NULL` and the returned memory is owned by the caller. + * + * All arguments to this function must outlive the returned future and be unmodified until the future is deleted. + */ +WASM_API_EXTERN wasmtime_call_future_t *wasmtime_linker_instantiate_async( + const wasmtime_linker_t *linker, + wasmtime_context_t *store, + const wasmtime_module_t *module, + wasmtime_instance_t *instance, + wasm_trap_t** trap_ret, + wasmtime_error_t** error_ret); + +/** + * \brief Instantiates instance within the given store. + * + * This will also run the function's startup function, if there is one. + * + * For more information on async instantiation see #wasmtime_linker_instantiate_async. + * + * \param instance_pre the pre-initialized instance + * \param store the store in which to create the instance + * \param instance where to store the returned instance + * \param trap_ret where to store the returned trap + * \param error_ret where to store the returned trap + * + * The `trap_ret` and `error_ret` pointers may *not* be `NULL` and the returned memory is owned by the caller. + * + * All arguments to this function must outlive the returned future and be unmodified until the future is deleted. + */ +WASM_API_EXTERN wasmtime_call_future_t *wasmtime_instance_pre_instantiate_async( + const wasmtime_instance_pre_t* instance_pre, + wasmtime_context_t *store, + wasmtime_instance_t *instance, + wasm_trap_t** trap_ret, + wasmtime_error_t** error_ret); + +/** + * A callback to get the top of the stack address and the length of the stack, + * excluding guard pages. + * + * For more information about the parameters see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.StackMemory.html + */ +typedef uint8_t *(*wasmtime_stack_memory_get_callback_t)( + void *env, + size_t *out_len); + +/** + * A Stack instance created from a #wasmtime_new_stack_memory_callback_t. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.StackMemory.html + */ +typedef struct { + /// User provided value to be passed to get_memory and grow_memory + void *env; + /// Callback to get the memory and size of this LinearMemory + wasmtime_stack_memory_get_callback_t get_stack_memory; + /// An optional finalizer for env + void (*finalizer)(void*); +} wasmtime_stack_memory_t; + +/** + * A callback to create a new StackMemory from the specified parameters. + * + * The result should be written to `stack_ret` and wasmtime will own the values written + * into that struct. + * + * This callback must be thread-safe. + * + * For more information about the parameters see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.StackCreator.html#tymethod.new_stack + */ +typedef wasmtime_error_t *(*wasmtime_new_stack_memory_callback_t)( + void *env, + size_t size, + wasmtime_stack_memory_t *stack_ret); + +/** + * A representation of custom stack creator. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.StackCreator.html + */ +typedef struct { + /// User provided value to be passed to new_stack + void* env; + /// The callback to create a new stack, must be thread safe + wasmtime_new_stack_memory_callback_t new_stack; + /// An optional finalizer for env. + void (*finalizer)(void*); +} wasmtime_stack_creator_t; + +/** + * Sets a custom stack creator. + * + * Custom memory creators are used when creating creating async instance stacks for + * the on-demand instance allocation strategy. + * + * The config does **not** take ownership of the #wasmtime_stack_creator_t passed in, but + * instead copies all the values in the struct. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.with_host_stack + */ +WASM_API_EXTERN void wasmtime_config_host_stack_creator_set( + wasm_config_t*, + wasmtime_stack_creator_t*); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WASMTIME_ASYNC_H + diff --git a/lib/src/wasm/wasmtime/config.h b/lib/src/wasm/wasmtime/config.h index 77c11936..b299d048 100644 --- a/lib/src/wasm/wasmtime/config.h +++ b/lib/src/wasm/wasmtime/config.h @@ -80,6 +80,10 @@ enum wasmtime_profiling_strategy_enum { // ProfilingStrategy /// /// Note that this isn't always enabled at build time. WASMTIME_PROFILING_STRATEGY_VTUNE, + /// Linux's simple "perfmap" support in `perf` is enabled and when Wasmtime is + /// run under `perf` necessary calls will be made to profile generated JIT + /// code. + WASMTIME_PROFILING_STRATEGY_PERFMAP, }; #define WASMTIME_CONFIG_PROP(ret, name, ty) \ @@ -161,6 +165,22 @@ WASMTIME_CONFIG_PROP(void, wasm_reference_types, bool) */ WASMTIME_CONFIG_PROP(void, wasm_simd, bool) +/** + * \brief Configures whether the WebAssembly relaxed SIMD proposal is + * enabled. + * + * This setting is `false` by default. + */ +WASMTIME_CONFIG_PROP(void, wasm_relaxed_simd, bool) + +/** + * \brief Configures whether the WebAssembly relaxed SIMD proposal is + * in deterministic mode. + * + * This setting is `false` by default. + */ +WASMTIME_CONFIG_PROP(void, wasm_relaxed_simd_deterministic, bool) + /** * \brief Configures whether the WebAssembly bulk memory proposal is * enabled. @@ -200,6 +220,14 @@ WASMTIME_CONFIG_PROP(void, wasm_memory64, bool) */ WASMTIME_CONFIG_PROP(void, strategy, wasmtime_strategy_t) +/** + * \brief Configure whether wasmtime should compile a module using multiple threads. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.parallel_compilation. + */ +WASMTIME_CONFIG_PROP(void, parallel_compilation, bool) + /** * \brief Configures whether Cranelift's debug verifier is enabled. * @@ -216,13 +244,13 @@ WASMTIME_CONFIG_PROP(void, cranelift_debug_verifier, bool) * When Cranelift is used as a code generation backend this will configure * it to replace NaNs with a single canonical value. This is useful for users * requiring entirely deterministic WebAssembly computation. - * + * * This is not required by the WebAssembly spec, so it is not enabled by default. - * + * * The default value for this is `false` */ WASMTIME_CONFIG_PROP(void, cranelift_nan_canonicalization, bool) - + /** * \brief Configures Cranelift's optimization level for JIT code. * @@ -237,6 +265,16 @@ WASMTIME_CONFIG_PROP(void, cranelift_opt_level, wasmtime_opt_level_t) */ WASMTIME_CONFIG_PROP(void, profiler, wasmtime_profiling_strategy_t) +/** + * \brief Configures the “static” style of memory to always be used. + * + * This setting is `false` by default. + * + * For more information see the Rust documentation at + * https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.static_memory_forced. + */ +WASMTIME_CONFIG_PROP(void, static_memory_forced, bool) + /** * \brief Configures the maximum size for memory to be considered "static" * @@ -261,6 +299,24 @@ WASMTIME_CONFIG_PROP(void, static_memory_guard_size, uint64_t) */ WASMTIME_CONFIG_PROP(void, dynamic_memory_guard_size, uint64_t) +/** + * \brief Configures the size, in bytes, of the extra virtual memory space reserved after a “dynamic” memory for growing into. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.dynamic_memory_reserved_for_growth + */ +WASMTIME_CONFIG_PROP(void, dynamic_memory_reserved_for_growth, uint64_t) + +/** + * \brief Configures whether to generate native unwind information (e.g. .eh_frame on Linux). + * + * This option defaults to true. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.native_unwind_info + */ +WASMTIME_CONFIG_PROP(void, native_unwind_info, bool) + /** * \brief Enables Wasmtime's cache and loads configuration from the specified * path. @@ -275,6 +331,151 @@ WASMTIME_CONFIG_PROP(void, dynamic_memory_guard_size, uint64_t) */ WASM_API_EXTERN wasmtime_error_t* wasmtime_config_cache_config_load(wasm_config_t*, const char*); +/** + * \brief Configures the target triple that this configuration will produce + * machine code for. + * + * This option defaults to the native host. Calling this method will + * additionally disable inference of the native features of the host (e.g. + * detection of SSE4.2 on x86_64 hosts). Native features can be reenabled with + * the `cranelift_flag_{set,enable}` properties. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.config + */ +WASMTIME_CONFIG_PROP(wasmtime_error_t*, target, const char*) + +/** + * \brief Enables a target-specific flag in Cranelift. + * + * This can be used, for example, to enable SSE4.2 on x86_64 hosts. Settings can + * be explored with `wasmtime settings` on the CLI. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.cranelift_flag_enable + */ +WASM_API_EXTERN void wasmtime_config_cranelift_flag_enable(wasm_config_t*, const char*); + +/** + * \brief Sets a target-specific flag in Cranelift to the specified value. + * + * This can be used, for example, to enable SSE4.2 on x86_64 hosts. Settings can + * be explored with `wasmtime settings` on the CLI. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.cranelift_flag_set + */ +WASM_API_EXTERN void wasmtime_config_cranelift_flag_set(wasm_config_t*, const char *key, const char *value); + + +/** + * Return the data from a LinearMemory instance. + * + * The size in bytes as well as the maximum number of bytes that can be allocated should be + * returned as well. + * + * For more information about see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html + */ +typedef uint8_t *(*wasmtime_memory_get_callback_t)( + void *env, + size_t *byte_size, + size_t *maximum_byte_size); + +/** + * Grow the memory to the `new_size` in bytes. + * + * For more information about the parameters see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html#tymethod.grow_to + */ +typedef wasmtime_error_t *(*wasmtime_memory_grow_callback_t)( + void *env, + size_t new_size); + +/** + * A LinearMemory instance created from a #wasmtime_new_memory_callback_t. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html + */ +typedef struct wasmtime_linear_memory { + /// User provided value to be passed to get_memory and grow_memory + void *env; + /// Callback to get the memory and size of this LinearMemory + wasmtime_memory_get_callback_t get_memory; + /// Callback to request growing the memory + wasmtime_memory_grow_callback_t grow_memory; + /// An optional finalizer for env + void (*finalizer)(void*); +} wasmtime_linear_memory_t; + +/** + * A callback to create a new LinearMemory from the specified parameters. + * + * The result should be written to `memory_ret` and wasmtime will own the values written + * into that struct. + * + * This callback must be thread-safe. + * + * For more information about the parameters see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.MemoryCreator.html#tymethod.new_memory + */ +typedef wasmtime_error_t *(*wasmtime_new_memory_callback_t)( + void *env, + const wasm_memorytype_t *ty, + size_t minimum, + size_t maximum, + size_t reserved_size_in_bytes, + size_t guard_size_in_bytes, + wasmtime_linear_memory_t *memory_ret); + +/** + * A representation of custom memory creator and methods for an instance of LinearMemory. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/trait.MemoryCreator.html + */ +typedef struct wasmtime_memory_creator { + /// User provided value to be passed to new_memory + void* env; + /// The callback to create new memory, must be thread safe + wasmtime_new_memory_callback_t new_memory; + /// An optional finalizer for env. + void (*finalizer)(void*); +} wasmtime_memory_creator_t; + +/** + * Sets a custom memory creator. + * + * Custom memory creators are used when creating host Memory objects or when creating instance + * linear memories for the on-demand instance allocation strategy. + * + * The config does **not** take ownership of the #wasmtime_memory_creator_t passed in, but + * instead copies all the values in the struct. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.with_host_memory + */ +WASM_API_EXTERN void wasmtime_config_host_memory_creator_set( + wasm_config_t*, + wasmtime_memory_creator_t*); + +/** + * \brief 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. + * + * This option defaults to true. + * + * For more information see the Rust documentation at + * https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.memory_init_cow + */ +WASMTIME_CONFIG_PROP(void, memory_init_cow, bool) + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/src/wasm/wasmtime/error.h b/lib/src/wasm/wasmtime/error.h index 2ffee72b..51775520 100644 --- a/lib/src/wasm/wasmtime/error.h +++ b/lib/src/wasm/wasmtime/error.h @@ -30,6 +30,11 @@ extern "C" { */ typedef struct wasmtime_error wasmtime_error_t; +/** + * \brief Creates a new error with the provided message. + */ +WASM_API_EXTERN wasmtime_error_t *wasmtime_error_new(const char*); + /** * \brief Deletes an error. */ @@ -48,6 +53,24 @@ WASM_API_EXTERN void wasmtime_error_message( wasm_name_t *message ); +/** + * \brief Attempts to extract a WASI-specific exit status from this error. + * + * Returns `true` if the error is a WASI "exit" trap and has a return status. + * If `true` is returned then the exit status is returned through the `status` + * pointer. If `false` is returned then this is not a wasi exit trap. + */ +WASM_API_EXTERN bool wasmtime_error_exit_status(const wasmtime_error_t*, int *status); + +/** + * \brief Attempts to extract a WebAssembly trace from this error. + * + * This is similar to #wasm_trap_trace except that it takes a #wasmtime_error_t + * as input. The `out` argument will be filled in with the wasm trace, if + * present. + */ +WASM_API_EXTERN void wasmtime_error_wasm_trace(const wasmtime_error_t*, wasm_frame_vec_t *out); + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/src/wasm/wasmtime/func.h b/lib/src/wasm/wasmtime/func.h index 2683eaab..c5b927fd 100644 --- a/lib/src/wasm/wasmtime/func.h +++ b/lib/src/wasm/wasmtime/func.h @@ -233,6 +233,8 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_func_call( * * * The `args_and_results` pointer has enough space to hold all the parameters * and all the results (but not at the same time). + * * The `args_and_results_len` contains the length of the `args_and_results` + * buffer. * * Parameters must all be configured as if they were the correct type. * * Values such as `externref` and `funcref` are valid within the store being * called. @@ -241,10 +243,12 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_func_call( * faster than that function, but the tradeoff is that embeddings must uphold * more invariants rather than relying on Wasmtime to check them for you. */ -WASM_API_EXTERN wasm_trap_t *wasmtime_func_call_unchecked( +WASM_API_EXTERN wasmtime_error_t *wasmtime_func_call_unchecked( wasmtime_context_t *store, const wasmtime_func_t *func, - wasmtime_val_raw_t *args_and_results + wasmtime_val_raw_t *args_and_results, + size_t args_and_results_len, + wasm_trap_t **trap ); /** @@ -292,14 +296,14 @@ WASM_API_EXTERN wasmtime_context_t* wasmtime_caller_context(wasmtime_caller_t* c */ WASM_API_EXTERN void wasmtime_func_from_raw( wasmtime_context_t* context, - size_t raw, + void *raw, wasmtime_func_t *ret); /** * \brief Converts a `func` which belongs to `context` into a `usize` * parameter that is suitable for insertion into a #wasmtime_val_raw_t. */ -WASM_API_EXTERN size_t wasmtime_func_to_raw( +WASM_API_EXTERN void *wasmtime_func_to_raw( wasmtime_context_t* context, const wasmtime_func_t *func); diff --git a/lib/src/wasm/wasmtime/instance.h b/lib/src/wasm/wasmtime/instance.h index 544661f9..72f398ec 100644 --- a/lib/src/wasm/wasmtime/instance.h +++ b/lib/src/wasm/wasmtime/instance.h @@ -121,6 +121,51 @@ WASM_API_EXTERN bool wasmtime_instance_export_nth( wasmtime_extern_t *item ); +/** + * \brief A #wasmtime_instance_t, pre-instantiation, that is ready to be instantiated. + * + * Must be deleted using #wasmtime_instance_pre_delete. + * + * For more information see the Rust documentation: + * https://docs.wasmtime.dev/api/wasmtime/struct.InstancePre.html + */ +typedef struct wasmtime_instance_pre wasmtime_instance_pre_t; + +/** + * \brief Delete a previously created wasmtime_instance_pre_t. + */ +WASM_API_EXTERN void +wasmtime_instance_pre_delete(wasmtime_instance_pre_t *instance); + +/** + * \brief Instantiates instance within the given store. + * + * This will also run the function's startup function, if there is one. + * + * For more information on instantiation see #wasmtime_instance_new. + * + * \param instance_pre the pre-initialized instance + * \param store the store in which to create the instance + * \param instance where to store the returned instance + * \param trap_ptr where to store the returned trap + * + * \return One of three things can happen as a result of this function. First + * the module could be successfully instantiated and returned through + * `instance`, meaning the return value and `trap` are both set to `NULL`. + * Second the start function may trap, meaning the return value and `instance` + * are set to `NULL` and `trap` describes the trap that happens. Finally + * instantiation may fail for another reason, in which case an error is returned + * and `trap` and `instance` are set to `NULL`. + * + * This function does not take ownership of any of its arguments, and all return + * values are owned by the caller. + */ +WASM_API_EXTERN wasmtime_error_t* wasmtime_instance_pre_instantiate( + const wasmtime_instance_pre_t* instance_pre, + wasmtime_store_t *store, + wasmtime_instance_t* instance, + wasm_trap_t **trap_ptr); + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/src/wasm/wasmtime/linker.h b/lib/src/wasm/wasmtime/linker.h index edd52442..750c18d8 100644 --- a/lib/src/wasm/wasmtime/linker.h +++ b/lib/src/wasm/wasmtime/linker.h @@ -59,6 +59,7 @@ WASM_API_EXTERN void wasmtime_linker_allow_shadowing(wasmtime_linker_t* linker, * \brief Defines a new item in this linker. * * \param linker the linker the name is being defined in. + * \param store the store that the `item` is owned by. * \param module the module name the item is defined under. * \param module_len the byte length of `module` * \param name the field name the item is defined under @@ -73,6 +74,7 @@ WASM_API_EXTERN void wasmtime_linker_allow_shadowing(wasmtime_linker_t* linker, */ WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_define( wasmtime_linker_t *linker, + wasmtime_context_t *store, const char *module, size_t module_len, const char *name, @@ -290,6 +292,24 @@ WASM_API_EXTERN bool wasmtime_linker_get( wasmtime_extern_t *item ); +/** + * \brief Preform all the checks for instantiating `module` with the linker, + * except that instantiation doesn't actually finish. + * + * \param linker the linker used to instantiate the provided module. + * \param module the module that is being instantiated. + * \param instance_pre the returned instance_pre, if successful. + * + * \return An error or `NULL` if successful. + * + * For more information see the Rust documentation at: + * https://docs.wasmtime.dev/api/wasmtime/struct.Linker.html#method.instantiate_pre + */ +WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_instantiate_pre( + const wasmtime_linker_t *linker, + const wasmtime_module_t *module, + wasmtime_instance_pre_t **instance_pre); + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/src/wasm/wasmtime/memory.h b/lib/src/wasm/wasmtime/memory.h index 6aecbaff..cda42c2b 100644 --- a/lib/src/wasm/wasmtime/memory.h +++ b/lib/src/wasm/wasmtime/memory.h @@ -66,7 +66,7 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_memory_new( ); /** - * \brief Returns the tyep of the memory specified + * \brief Returns the type of the memory specified */ WASM_API_EXTERN wasm_memorytype_t* wasmtime_memory_type( const wasmtime_context_t *store, diff --git a/lib/src/wasm/wasmtime/module.h b/lib/src/wasm/wasmtime/module.h index deb6bcec..222239e8 100644 --- a/lib/src/wasm/wasmtime/module.h +++ b/lib/src/wasm/wasmtime/module.h @@ -148,6 +148,21 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_module_deserialize_file( wasmtime_module_t **ret ); + +/** + * \brief Returns the range of bytes in memory where this module’s compilation image resides. + * + * The compilation image for a module contains executable code, data, debug information, etc. + * This is roughly the same as the wasmtime_module_serialize but not the exact same. + * + * For more details see: https://docs.wasmtime.dev/api/wasmtime/struct.Module.html#method.image_range + */ +WASM_API_EXTERN void wasmtime_module_image_range( + const wasmtime_module_t *module, + size_t *start, + size_t *end +); + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/src/wasm/wasmtime/store.h b/lib/src/wasm/wasmtime/store.h index 55c9f680..740d98a3 100644 --- a/lib/src/wasm/wasmtime/store.h +++ b/lib/src/wasm/wasmtime/store.h @@ -79,6 +79,44 @@ WASM_API_EXTERN wasmtime_store_t *wasmtime_store_new( */ WASM_API_EXTERN wasmtime_context_t *wasmtime_store_context(wasmtime_store_t *store); +/** + * \brief Provides limits for a store. Used by hosts to limit resource + * consumption of instances. Use negative value to keep the default value + * for the limit. + * + * \param store store where the limits should be set. + * \param memory_size the maximum number of bytes a linear memory can grow to. + * Growing a linear memory beyond this limit will fail. By default, + * linear memory will not be limited. + * \param table_elements the maximum number of elements in a table. + * Growing a table beyond this limit will fail. By default, table elements + * will not be limited. + * \param instances the maximum number of instances that can be created + * for a Store. Module instantiation will fail if this limit is exceeded. + * This value defaults to 10,000. + * \param tables the maximum number of tables that can be created for a Store. + * Module instantiation will fail if this limit is exceeded. This value + * defaults to 10,000. + * \param memories the maximum number of linear memories that can be created + * for a Store. Instantiation will fail with an error if this limit is exceeded. + * This value defaults to 10,000. + * + * Use any negative value for the parameters that should be kept on + * the default values. + * + * Note that the limits are only used to limit the creation/growth of + * resources in the future, this does not retroactively attempt to apply + * limits to the store. + */ +WASM_API_EXTERN void wasmtime_store_limiter( + wasmtime_store_t *store, + int64_t memory_size, + int64_t table_elements, + int64_t instances, + int64_t tables, + int64_t memories +); + /** * \brief Deletes a store. */ @@ -110,7 +148,7 @@ WASM_API_EXTERN void wasmtime_context_set_data(wasmtime_context_t* context, void WASM_API_EXTERN void wasmtime_context_gc(wasmtime_context_t* context); /** - * \brief Adds fuel to this context's store for wasm to consume while executing. + * \brief Set fuel to this context's store for wasm to consume while executing. * * For this method to work fuel consumption must be enabled via * #wasmtime_config_consume_fuel_set. By default a store starts with 0 fuel @@ -118,40 +156,24 @@ WASM_API_EXTERN void wasmtime_context_gc(wasmtime_context_t* context); * This function must be called for the store to have * some fuel to allow WebAssembly to execute. * - * Note that at this time when fuel is entirely consumed it will cause - * wasm to trap. More usages of fuel are planned for the future. + * Note that when fuel is entirely consumed it will cause wasm to trap. * * If fuel is not enabled within this store then an error is returned. If fuel * is successfully added then NULL is returned. */ -WASM_API_EXTERN wasmtime_error_t *wasmtime_context_add_fuel(wasmtime_context_t *store, uint64_t fuel); +WASM_API_EXTERN wasmtime_error_t *wasmtime_context_set_fuel(wasmtime_context_t *store, uint64_t fuel); /** - * \brief Returns the amount of fuel consumed by this context's store execution - * so far. + * \brief Returns the amount of fuel remaining in this context's store. * * If fuel consumption is not enabled via #wasmtime_config_consume_fuel_set - * then this function will return false. Otherwise true is returned and the - * fuel parameter is filled in with fuel consuemd so far. + * then this function will return an error. Otherwise `NULL` is returned and the + * fuel parameter is filled in with fuel consumed so far. * * Also note that fuel, if enabled, must be originally configured via - * #wasmtime_context_add_fuel. + * #wasmtime_context_set_fuel. */ -WASM_API_EXTERN bool wasmtime_context_fuel_consumed(const wasmtime_context_t *context, uint64_t *fuel); - -/** - * \brief Attempt to manually consume fuel from the store. - * - * If fuel consumption is not enabled via #wasmtime_config_consume_fuel_set then - * this function will return an error. Otherwise this will attempt to consume - * the specified amount of `fuel` from the store. If successful the remaining - * amount of fuel is stored into `remaining`. If `fuel` couldn't be consumed - * then an error is returned. - * - * Also note that fuel, if enabled, must be originally configured via - * #wasmtime_context_add_fuel. - */ -WASM_API_EXTERN wasmtime_error_t *wasmtime_context_consume_fuel(wasmtime_context_t *context, uint64_t fuel, uint64_t *remaining); +WASM_API_EXTERN wasmtime_error_t* wasmtime_context_get_fuel(const wasmtime_context_t *context, uint64_t *fuel); /** * \brief Configures WASI state within the specified store. @@ -168,15 +190,30 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_context_set_wasi(wasmtime_context_t * /** * \brief Configures the relative deadline at which point WebAssembly code will - * trap. + * trap or invoke the callback function. * * This function configures the store-local epoch deadline after which point - * WebAssembly code will trap. + * WebAssembly code will trap or invoke the callback function. * - * See also #wasmtime_config_epoch_interruption_set. + * See also #wasmtime_config_epoch_interruption_set and + * #wasmtime_store_epoch_deadline_callback. */ WASM_API_EXTERN void wasmtime_context_set_epoch_deadline(wasmtime_context_t *context, uint64_t ticks_beyond_current); +/** + * \brief Configures epoch deadline callback to C function. + * + * This function configures a store-local callback function that will be + * called when the running WebAssembly function has exceeded its epoch + * deadline. That function can return a #wasmtime_error_t to terminate + * the function, or set the delta argument and return NULL to update the + * epoch deadline and resume function execution. + * + * See also #wasmtime_config_epoch_interruption_set and + * #wasmtime_context_set_epoch_deadline. + */ +WASM_API_EXTERN void wasmtime_store_epoch_deadline_callback(wasmtime_store_t *store, wasmtime_error_t* (*func)(wasmtime_context_t*, void*, uint64_t*), void *data); + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/src/wasm/wasmtime/trap.h b/lib/src/wasm/wasmtime/trap.h index 909a4801..2d2e2040 100644 --- a/lib/src/wasm/wasmtime/trap.h +++ b/lib/src/wasm/wasmtime/trap.h @@ -46,6 +46,8 @@ enum wasmtime_trap_code_enum { WASMTIME_TRAP_CODE_UNREACHABLE_CODE_REACHED, /// Execution has potentially run too long and may be interrupted. WASMTIME_TRAP_CODE_INTERRUPT, + /// Execution has run out of the configured fuel amount. + WASMTIME_TRAP_CODE_OUT_OF_FUEL, }; /** @@ -69,15 +71,6 @@ WASM_API_EXTERN wasm_trap_t *wasmtime_trap_new(const char *msg, size_t msg_len); */ WASM_API_EXTERN bool wasmtime_trap_code(const wasm_trap_t*, wasmtime_trap_code_t *code); -/** - * \brief Attempts to extract a WASI-specific exit status from this trap. - * - * Returns `true` if the trap is a WASI "exit" trap and has a return status. If - * `true` is returned then the exit status is returned through the `status` - * pointer. If `false` is returned then this is not a wasi exit trap. - */ -WASM_API_EXTERN bool wasmtime_trap_exit_status(const wasm_trap_t*, int *status); - /** * \brief Returns a human-readable name for this frame's function. * diff --git a/lib/src/wasm/wasmtime/val.h b/lib/src/wasm/wasmtime/val.h index ae0a1961..4c408133 100644 --- a/lib/src/wasm/wasmtime/val.h +++ b/lib/src/wasm/wasmtime/val.h @@ -70,7 +70,7 @@ WASM_API_EXTERN void wasmtime_externref_delete(wasmtime_externref_t *ref); * Note that the returned #wasmtime_externref_t is an owned value that must be * deleted via #wasmtime_externref_delete by the caller if it is non-null. */ -WASM_API_EXTERN wasmtime_externref_t *wasmtime_externref_from_raw(wasmtime_context_t *context, size_t raw); +WASM_API_EXTERN wasmtime_externref_t *wasmtime_externref_from_raw(wasmtime_context_t *context, void *raw); /** * \brief Converts a #wasmtime_externref_t to a raw value suitable for storing @@ -82,7 +82,7 @@ WASM_API_EXTERN wasmtime_externref_t *wasmtime_externref_from_raw(wasmtime_conte * context of the store. Do not perform a GC between calling this function and * passing it to WebAssembly. */ -WASM_API_EXTERN size_t wasmtime_externref_to_raw( +WASM_API_EXTERN void *wasmtime_externref_to_raw( wasmtime_context_t *context, const wasmtime_externref_t *ref); @@ -119,38 +119,24 @@ typedef uint8_t wasmtime_v128[16]; */ typedef union wasmtime_valunion { /// Field used if #wasmtime_val_t::kind is #WASMTIME_I32 - /// - /// Note that this field is always stored in a little-endian format. int32_t i32; /// Field used if #wasmtime_val_t::kind is #WASMTIME_I64 - /// - /// Note that this field is always stored in a little-endian format. int64_t i64; /// Field used if #wasmtime_val_t::kind is #WASMTIME_F32 - /// - /// Note that this field is always stored in a little-endian format. float32_t f32; /// Field used if #wasmtime_val_t::kind is #WASMTIME_F64 - /// - /// Note that this field is always stored in a little-endian format. float64_t f64; /// Field used if #wasmtime_val_t::kind is #WASMTIME_FUNCREF /// /// If this value represents a `ref.null func` value then the `store_id` field /// is set to zero. - /// - /// Note that this field is always stored in a little-endian format. wasmtime_func_t funcref; /// Field used if #wasmtime_val_t::kind is #WASMTIME_EXTERNREF /// /// If this value represents a `ref.null extern` value then this pointer will /// be `NULL`. - /// - /// Note that this field is always stored in a little-endian format. wasmtime_externref_t *externref; /// Field used if #wasmtime_val_t::kind is #WASMTIME_V128 - /// - /// Note that this field is always stored in a little-endian format. wasmtime_v128 v128; } wasmtime_valunion_t; @@ -169,26 +155,40 @@ typedef union wasmtime_valunion { */ typedef union wasmtime_val_raw { /// Field for when this val is a WebAssembly `i32` value. + /// + /// Note that this field is always stored in a little-endian format. int32_t i32; /// Field for when this val is a WebAssembly `i64` value. + /// + /// Note that this field is always stored in a little-endian format. int64_t i64; /// Field for when this val is a WebAssembly `f32` value. + /// + /// Note that this field is always stored in a little-endian format. float32_t f32; /// Field for when this val is a WebAssembly `f64` value. + /// + /// Note that this field is always stored in a little-endian format. float64_t f64; /// Field for when this val is a WebAssembly `v128` value. + /// + /// Note that this field is always stored in a little-endian format. wasmtime_v128 v128; /// Field for when this val is a WebAssembly `funcref` value. /// /// If this is set to 0 then it's a null funcref, otherwise this must be /// passed to `wasmtime_func_from_raw` to determine the `wasmtime_func_t`. - size_t funcref; + /// + /// Note that this field is always stored in a little-endian format. + void *funcref; /// Field for when this val is a WebAssembly `externref` value. /// /// If this is set to 0 then it's a null externref, otherwise this must be /// passed to `wasmtime_externref_from_raw` to determine the /// `wasmtime_externref_t`. - size_t externref; + /// + /// Note that this field is always stored in a little-endian format. + void *externref; } wasmtime_val_raw_t; /** @@ -212,7 +212,7 @@ typedef struct wasmtime_val { } wasmtime_val_t; /** - * \brief Delets an owned #wasmtime_val_t. + * \brief Deletes an owned #wasmtime_val_t. * * Note that this only deletes the contents, not the memory that `val` points to * itself (which is owned by the caller).