/* * spacewasm.h — C API for the SpaceWasm WebAssembly interpreter. * Generated by cbindgen */ #ifndef SPACEWASM_H #define SPACEWASM_H #include #include #include #if !defined(SPACEWASM_NORETURN) && defined(__has_c_attribute) # if __has_c_attribute(noreturn) # define SPACEWASM_NORETURN [[noreturn]] /* Standard C23 attribute */ # endif #endif #if !defined(SPACEWASM_NORETURN) # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) # define SPACEWASM_NORETURN _Noreturn /* Standard C11 keyword */ # elif defined(__GNUC__) || defined(__clang__) # define SPACEWASM_NORETURN __attribute__((noreturn)) /* GCC / Clang extension */ # elif defined(_MSC_VER) # define SPACEWASM_NORETURN __declspec(noreturn) /* MSVC extension */ # else # define SPACEWASM_NORETURN /* Fallback: do nothing on unsupported compilers */ # endif #endif #define CustomSection_MAX_NAME_LENGTH 32 /* Operation status returned by most `spacewasm_*` functions. [`spacewasm_status_t::SPACEWASM_OK`] (0) means success. */ enum spacewasm_status_t #if defined(__cplusplus) || __STDC_VERSION__ >= 202311L : int32_t #endif // defined(__cplusplus) || __STDC_VERSION__ >= 202311L { SPACEWASM_OK = 0, SPACEWASM_ERR_NULL_ARG = 1, SPACEWASM_ERR_BAD_ARG = 2, SPACEWASM_ERR_BAD_UTF8 = 3, SPACEWASM_ERR_NAME_TOO_LONG = 4, SPACEWASM_ERR_BAD_SIGNATURE = 5, SPACEWASM_ERR_CAPACITY = 6, SPACEWASM_ERR_NOT_FOUND = 7, SPACEWASM_ERR_WRONG_STATE = 8, SPACEWASM_ERR_GUEST_MEMORY_ALLOC_FAILED = 15, SPACEWASM_ERR_ALLOC_FAILED = 16, SPACEWASM_ERR_OUT_OF_MEMORY = 17, SPACEWASM_ERR_PAGE_TOO_SMALL = 18, SPACEWASM_ERR_HEAP_POISONED = 19, SPACEWASM_ERR_MEM_OUT_OF_BOUNDS = 32, SPACEWASM_ERR_PARAM_LEN_MISMATCH = 48, SPACEWASM_ERR_PARAM_TYPE_MISMATCH = 49, SPACEWASM_ERR_STACK_OVERFLOW = 50, SPACEWASM_ERR_EOF = 64, SPACEWASM_ERR_MALFORMED_INTEGER = 65, SPACEWASM_ERR_I33_IS_NEGATIVE = 66, SPACEWASM_ERR_MALFORMED_MAGIC = 67, SPACEWASM_ERR_MALFORMED_VERSION = 68, SPACEWASM_ERR_MALFORMED_UTF8 = 69, SPACEWASM_ERR_DUPLICATE_MODULE_NAME = 70, SPACEWASM_ERR_DUPLICATE_EXPORT_NAME = 71, SPACEWASM_ERR_MALFORMED_SECTION_ID = 72, SPACEWASM_ERR_MALFORMED_VALUE_TYPE = 73, SPACEWASM_ERR_MALFORMED_FUNCTION = 74, SPACEWASM_ERR_MALFORMED_LIMIT = 75, SPACEWASM_ERR_MALFORMED_ELEM_TYPE = 76, SPACEWASM_ERR_MALFORMED_SECTION_SIZE = 77, SPACEWASM_ERR_EXPECTED_CONST_OR_VAR = 78, SPACEWASM_ERR_MALFORMED_IMPORT_EXPORT_DESC = 79, SPACEWASM_ERR_MALFORMED_MEM_TYPE = 80, SPACEWASM_ERR_INVALID_PAGE_SIZE = 81, SPACEWASM_ERR_INVALID_SECTION_ORDERING = 82, SPACEWASM_ERR_DUPLICATE_SECTION = 83, SPACEWASM_ERR_INVALID_MAX_LIMIT = 84, SPACEWASM_ERR_EXPECTED_TERMINAL = 85, SPACEWASM_ERR_INVALID_OPCODE = 86, SPACEWASM_ERR_MALFORMED_CODE_SIZE = 87, SPACEWASM_ERR_INVALID_CODE_SECTION_FUNCTION_COUNT = 88, SPACEWASM_ERR_VEC_TOO_LONG = 89, SPACEWASM_ERR_IDX_TOO_LARGE = 90, SPACEWASM_ERR_MODULE_IDX_TOO_LARGE = 91, SPACEWASM_ERR_MEMORY_TOO_LARGE = 92, SPACEWASM_ERR_MEMORY_IMPORT_TOO_LARGE = 93, SPACEWASM_ERR_MEM_ALIGN_TOO_LARGE = 94, SPACEWASM_ERR_TABLE_TOO_LARGE = 95, SPACEWASM_ERR_CONTROL_FLOW_TOO_DEEP = 96, SPACEWASM_ERR_STACK_UNDERFLOW = 97, SPACEWASM_ERR_STACK_TOO_LARGE = 98, SPACEWASM_ERR_LABEL_STACK_JUMP_TOO_DEEP = 99, SPACEWASM_ERR_LABEL_JUMP_TOO_LARGE = 100, SPACEWASM_ERR_TYPE_MISMATCH = 101, SPACEWASM_ERR_BLOCK_RESULT_TYPE_MISMATCH = 102, SPACEWASM_ERR_FUNCTION_RESULT_TYPE_MISMATCH = 103, SPACEWASM_ERR_BR_TABLE_RESULT_TYPE_MISMATCH = 104, SPACEWASM_ERR_ILLEGAL_MEMORY_GROW = 112, SPACEWASM_ERR_INVALID_ELEMENT_OFFSET = 113, SPACEWASM_ERR_INVALID_ELEMENT_OUT_OF_BOUNDS = 114, SPACEWASM_ERR_INVALID_TABLE_INDEX = 115, SPACEWASM_ERR_TABLE_NOT_DEFINED = 116, SPACEWASM_ERR_INVALID_ELEMENT_COUNT = 117, SPACEWASM_ERR_INVALID_MEM_INDEX = 118, SPACEWASM_ERR_MEMORY_NOT_DEFINED = 119, SPACEWASM_ERR_INVALID_MEM_OFFSET_TYPE = 120, SPACEWASM_ERR_INVALID_MEM_OFFSET = 122, SPACEWASM_ERR_MULTIPLE_MEMORIES = 123, SPACEWASM_ERR_MULTIPLE_TABLES = 124, SPACEWASM_ERR_INVALID_LABEL_INDEX = 128, SPACEWASM_ERR_INVALID_ELSE_BLOCK = 129, SPACEWASM_ERR_INVALID_END_BLOCK = 130, SPACEWASM_ERR_INSTRUCTION_OUTSIDE_OF_FUNCTION = 131, SPACEWASM_ERR_LOCAL_IDX_OUT_OF_RANGE = 132, SPACEWASM_ERR_FUNCTION_IDX_OUT_OF_RANGE = 133, SPACEWASM_ERR_TYPE_IDX_OUT_OF_RANGE = 134, SPACEWASM_ERR_FUNCTION_TEXT_OUT_OF_RANGE = 135, SPACEWASM_ERR_GLOBAL_IDX_OUT_OF_RANGE = 136, SPACEWASM_ERR_FUNCTION_IMPORT_NOT_FOUND = 144, SPACEWASM_ERR_GLOBAL_IMPORT_NOT_FOUND = 145, SPACEWASM_ERR_MEMORY_IMPORT_NOT_FOUND = 146, SPACEWASM_ERR_TABLE_IMPORT_NOT_FOUND = 147, SPACEWASM_ERR_FUNCTION_IMPORT_OUT_OF_RANGE = 148, SPACEWASM_ERR_FUNCTION_IMPORT_TYPE_MISMATCH = 149, SPACEWASM_ERR_GLOBAL_NOT_MUTABLE = 150, SPACEWASM_ERR_GLOBAL_IMPORT_TYPE_MISMATCH = 151, SPACEWASM_ERR_MEMORY_IMPORT_TYPE_MISMATCH = 152, SPACEWASM_ERR_TABLE_IMPORT_TYPE_MISMATCH = 153, SPACEWASM_ERR_TABLE_IMPORT_INCOMPATIBLE_SIZE = 154, SPACEWASM_ERR_TABLE_REF_NOT_UNIQUE = 155, SPACEWASM_ERR_FUNCTION_PARAMETERS_TOO_LARGE = 160, SPACEWASM_ERR_FUNCTION_RETURNS_TOO_LARGE = 161, SPACEWASM_ERR_TOO_MANY_LOCALS = 162, SPACEWASM_ERR_INVALID_CONST_INSTRUCTION = 163, SPACEWASM_ERR_GLOBAL_TYPE_MISMATCH = 164, SPACEWASM_ERR_ALIGNMENT_LARGER_THAN_TYPE = 165, SPACEWASM_ERR_INVALID_START_FUNCTION_SIGNATURE = 166, SPACEWASM_ERR_INVALID_HOST_START_FUNCTION = 167, SPACEWASM_ERR_CONST_ALREADY_HAS_VALUE = 176, SPACEWASM_ERR_CONST_NO_VALUE = 177, SPACEWASM_ERR_CONST_INVALID_GLOBAL = 178, SPACEWASM_ERR_POSSIBLE_BACKPATCH_CYCLE = 192, SPACEWASM_ERR_PAGE_FAULT = 193, SPACEWASM_ERR_READER_ERROR = 194, }; #ifndef __cplusplus #if __STDC_VERSION__ >= 202311L typedef enum spacewasm_status_t spacewasm_status_t; #else typedef int32_t spacewasm_status_t; #endif // __STDC_VERSION__ >= 202311L #endif // __cplusplus /* Result of a C host function call. */ enum spacewasm_hostcall_result_t #if defined(__cplusplus) || __STDC_VERSION__ >= 202311L : int32_t #endif // defined(__cplusplus) || __STDC_VERSION__ >= 202311L { /* Continue, do not return a value */ SPACEWASM_CONTINUE_NONE = 0, /* Continue; populate `out_result` if the function has a result type. */ SPACEWASM_CONTINUE_SOME = 1, /* Trap the interpreter. */ SPACEWASM_TRAP = 2, /* Pause the interpreter (cooperative yield). `spacewasm_run` returns `SPACEWASM_RUN_PAUSE`, and keeps returning it without running anything, until the result is supplied with `spacewasm_resume` or `spacewasm_resume_value`. Until then the PC is the calling instruction. */ SPACEWASM_PAUSE = 3, }; #ifndef __cplusplus #if __STDC_VERSION__ >= 202311L typedef enum spacewasm_hostcall_result_t spacewasm_hostcall_result_t; #else typedef int32_t spacewasm_hostcall_result_t; #endif // __STDC_VERSION__ >= 202311L #endif // __cplusplus /* FFI-safe value type tag. Matches the ordering of [`spacewasm::ValType`]. */ enum spacewasm_valtype_t #if defined(__cplusplus) || __STDC_VERSION__ >= 202311L : uint8_t #endif // defined(__cplusplus) || __STDC_VERSION__ >= 202311L { SPACEWASM_I32 = 0, SPACEWASM_I64 = 1, SPACEWASM_F32 = 2, SPACEWASM_F64 = 3, }; #ifndef __cplusplus #if __STDC_VERSION__ >= 202311L typedef enum spacewasm_valtype_t spacewasm_valtype_t; #else typedef uint8_t spacewasm_valtype_t; #endif // __STDC_VERSION__ >= 202311L #endif // __cplusplus /* Outcome of a [`spacewasm_read_fn_t`] call, written by the callback. */ enum spacewasm_read_result_t #if defined(__cplusplus) || __STDC_VERSION__ >= 202311L : int32_t #endif // defined(__cplusplus) || __STDC_VERSION__ >= 202311L { /* A chunk of `*out_len` bytes was written to the buffer. `out_len == 0` also signals end-of-stream. */ SPACEWASM_READ_OK = 0, /* End of stream; no more bytes. */ SPACEWASM_READ_EOF = 1, /* An I/O error occurred; loading fails with `SPACEWASM_ERR_READER_ERROR`. */ SPACEWASM_READ_ERROR = 2, }; #ifndef __cplusplus #if __STDC_VERSION__ >= 202311L typedef enum spacewasm_read_result_t spacewasm_read_result_t; #else typedef int32_t spacewasm_read_result_t; #endif // __STDC_VERSION__ >= 202311L #endif // __cplusplus /* Outcome of a call to `spacewasm_run`. */ enum spacewasm_run_status_t #if defined(__cplusplus) || __STDC_VERSION__ >= 202311L : int32_t #endif // defined(__cplusplus) || __STDC_VERSION__ >= 202311L { SPACEWASM_RUN_FINISHED = 0, SPACEWASM_RUN_OUT_OF_FUEL = 1, SPACEWASM_RUN_PAUSE = 2, SPACEWASM_RUN_TRAP = 3, }; #ifndef __cplusplus #if __STDC_VERSION__ >= 202311L typedef enum spacewasm_run_status_t spacewasm_run_status_t; #else typedef int32_t spacewasm_run_status_t; #endif // __STDC_VERSION__ >= 202311L #endif // __cplusplus /* Reason accompanying a trap (`out_trap`). Mirrors [`spacewasm::TrapReason`], with an extra [`SPACEWASM_TRAP_NONE`] (`-1`) written when no trap occurred. */ enum spacewasm_trap_t #if defined(__cplusplus) || __STDC_VERSION__ >= 202311L : int32_t #endif // defined(__cplusplus) || __STDC_VERSION__ >= 202311L { /* No trap occurred (the run finished, paused, or ran out of fuel). */ SPACEWASM_TRAP_NONE = -1, /* Triggered by an `unreachable` instruction. */ SPACEWASM_TRAP_UNREACHABLE = 0, /* A host function noted an unrecoverable failure. */ SPACEWASM_TRAP_HOST = 1, /* Integer or floating-point division by zero. */ SPACEWASM_TRAP_DIVIDE_BY_ZERO = 2, /* An indirect call index was out of the table's range. */ SPACEWASM_TRAP_INVALID_TABLE_INDEX = 3, /* The function type in an indirect call did not match the pointer's type. */ SPACEWASM_TRAP_INVALID_TABLE_FUNCTION_TYPE = 4, /* An indirect call referenced an uninitialized table element. */ SPACEWASM_TRAP_UNINITIALIZED_TABLE_ELEMENT = 5, /* An imported global could not be read. */ SPACEWASM_TRAP_GLOBAL_GET_FAILED = 6, /* An imported global could not be set. */ SPACEWASM_TRAP_GLOBAL_SET_FAILED = 7, /* A memory allocation (e.g. `memory.grow`) ran out of memory. */ SPACEWASM_TRAP_OUT_OF_MEMORY = 8, /* `memory.grow` failed because a host function holds the memory. */ SPACEWASM_TRAP_MEMORY_REF_NOT_UNIQUE = 9, /* A memory operation was out of bounds. */ SPACEWASM_TRAP_MEMORY_OUT_OF_BOUNDS = 10, /* Ran out of stack space. */ SPACEWASM_TRAP_STACK_OVERFLOW = 11, /* The result of an operation was unrepresentable (e.g. converting Inf). */ SPACEWASM_TRAP_UNREPRESENTABLE_RESULT = 12, /* Signed division caused integer overflow. */ SPACEWASM_TRAP_INTEGER_OVERFLOW = 13, /* Attempted to convert NaN to an integer. */ SPACEWASM_TRAP_BAD_CONVERSION_TO_INTEGER = 14, /* The IR decoder reached an opcode or immediate it cannot interpret. */ SPACEWASM_TRAP_MALFORMED_IR = 15, }; #ifndef __cplusplus #if __STDC_VERSION__ >= 202311L typedef enum spacewasm_trap_t spacewasm_trap_t; #else typedef int32_t spacewasm_trap_t; #endif // __STDC_VERSION__ >= 202311L #endif // __cplusplus /* A struct holding the alloc, realloc, dealloc, userdata pointers to adapt the C API to the Rc API. This struct is reference counted and deallocated once all modules using this allocator are dropped. */ typedef struct spacewasm_allocator_t spacewasm_allocator_t; /* Handle holding the SpaceWasm engine and compiled IR code. This handle is used for holding and executing the SpaceWasm interpreter. */ typedef struct spacewasm_t spacewasm_t; typedef struct spacewasm_host_module_t spacewasm_host_module_t; /* Opaque handle passed to C host callbacks, wrapping a borrowed core [`Engine`]. Valid only for the duration of the call. */ typedef struct spacewasm_caller_t spacewasm_caller_t; /* Allocate `size` bytes aligned to `align`. Return NULL on failure. */ typedef uint8_t *(*spacewasm_alloc_fn_t)(void *userdata, size_t size, size_t align); /* Resize the `old_size`-byte allocation at `ptr` (alignment `align`) to `new_size` bytes, moving the contents if needed. Return NULL on failure. */ typedef uint8_t *(*spacewasm_realloc_fn_t)(void *userdata, uint8_t *ptr, size_t old_size, size_t new_size, size_t align); /* Free the `size`-byte allocation at `ptr` (alignment `align`). */ typedef void (*spacewasm_dealloc_fn_t)(void *userdata, uint8_t *ptr, size_t size, size_t align); typedef struct spacewasm_host_t { struct spacewasm_host_module_t *ptr; size_t capacity; size_t len; } spacewasm_host_t; /* FFI-safe union of the four WebAssembly 1.0 value payloads. */ typedef union spacewasm_value_payload_t { int32_t i32_; int64_t i64_; float f32_; double f64_; } spacewasm_value_payload_t; /* FFI-safe tagged value. `tag` selects the active `u` field. */ typedef struct spacewasm_value_t { spacewasm_valtype_t tag; union spacewasm_value_payload_t u; } spacewasm_value_t; /* Callback signature for a host function implemented in C. `caller` is an opaque handle for `spacewasm_mem_*`; write `out_result` iff returning a value. */ typedef spacewasm_hostcall_result_t (*spacewasm_host_fn_t)(struct spacewasm_caller_t *caller, void *userdata, const struct spacewasm_value_t *params, size_t n_params, struct spacewasm_value_t *out_result); /* C callback that supplies the next chunk of a Wasm module. The callback owns the buffer: it sets `*out_buf` to point at the next chunk and `*out_len` to its length (0 == EOF). The chunk must stay valid until the next call to the callback (or until loading completes). */ typedef spacewasm_read_result_t (*spacewasm_read_fn_t)(void *userdata, const uint8_t **out_buf, size_t *out_len); /* FFI-safe mirror of [`CompilerOptions`], controlling how guest modules loaded onto a store are compiled. Passed to [`spacewasm_new`]. */ typedef struct spacewasm_compiler_options_t { /* Allow compiling `memory.grow` instructions. When `false`, a module using `memory.grow` is rejected at load time. */ bool allow_memory_grow; /* Maximum number of iterations to resolve during a control-flow backpatch. Bounds compile time on pathological modules at the cost of rejecting some valid programs. Set to 0 for unlimited iterations. */ uint32_t max_backpatch_iterations; /* Maximum number of compiled code pages allowed across all modules loaded onto the store. */ size_t max_code_pages; } spacewasm_compiler_options_t; /* Allocate `size` bytes aligned to `align`. Return NULL on failure. Per page allocation. */ typedef uint8_t *(*spacewasm_global_alloc_fn_t)(void *userdata, size_t size, size_t align); /* Free the `size`-byte allocation at `ptr` (alignment `align`). Per page deallocation. */ typedef void (*spacewasm_global_dealloc_fn_t)(void *userdata, uint8_t *ptr, size_t size, size_t align); #ifdef __cplusplus extern "C" { #endif // __cplusplus /* Create a guest linear-memory allocator from three C callbacks, returning an opaque handle (or null if any callback is null or allocation fails). The handle is passed to [`spacewasm_load_module`] and must be released with [`spacewasm_allocator_destroy`]. `userdata` is passed to every callback. */ struct spacewasm_allocator_t *spacewasm_allocator_new(spacewasm_alloc_fn_t alloc, spacewasm_realloc_fn_t realloc, spacewasm_dealloc_fn_t dealloc, void *userdata); /* Destroy an allocator handle. No-op on null. Any loaded module keeps its own reference to the underlying allocator, so destroying the handle after loading is safe. # Safety `allocator` must be a live handle from [`spacewasm_allocator_new`], not already destroyed. */ void spacewasm_allocator_destroy(struct spacewasm_allocator_t *allocator); /* Create a new host module vector of `len` size # Safety `dest` must be null or a valid, live pointer to write the new host vector into. */ spacewasm_status_t spacewasm_host_new(size_t len, struct spacewasm_host_t *dest); /* Add a host module named `name` sized for `max_functions` functions and `max_globals` globals, writing its index to `out_idx` (if non-null). # Safety `host` must be live; all C strings valid and NUL-terminated. */ spacewasm_status_t spacewasm_add_host_module(struct spacewasm_host_t *host, const char *name, size_t max_functions, size_t max_globals, uint32_t *out_idx); /* Register a host function `name` in host module `module_idx`, with parameter and return signatures given by `params_sig`/`returns_sig` and implemented by callback `f` (passed `userdata` on each call). # Safety `host` must be live; all C strings valid and NUL-terminated. */ spacewasm_status_t spacewasm_add_host_function(struct spacewasm_host_t *host, uint32_t module_idx, const char *name, const char *params_sig, const char *returns_sig, spacewasm_host_fn_t f, void *userdata); /* Load a guest module named `name` onto an existing engine by streaming its bytes through the `read` callback. The callback owns the buffer backing each chunk (see [`spacewasm_read_fn_t`]). This does not run the module's start function; resolve it with [`spacewasm_module_start`] and invoke it with [`spacewasm_invoke`] for that. `allocator` supplies the guest linear memory (see [`spacewasm_allocator_new`]). Writes the new module's index to `out_module_idx` (if non-null). May be called repeatedly to load several modules onto the same engine, as long as every prior load succeeded. # Failure invalidates the engine Any status other than [`spacewasm_status_t::SPACEWASM_OK`] (including [`spacewasm_status_t::SPACEWASM_ERR_CAPACITY`]) leaves the engine unusable: segments may already have been written into imported memories and tables, and the page allocator is poisoned. The caller must destroy the engine with [`spacewasm_destroy`] and create a new one; [`spacewasm_reset`] does not recover from a failed load. # Safety `engine` and `allocator` must be live handles; `read` a valid callback; `out_module_idx` null or valid. */ spacewasm_status_t spacewasm_load_module(struct spacewasm_t *engine, const char *name, spacewasm_read_fn_t read, void *read_userdata, struct spacewasm_allocator_t *allocator, uint32_t *out_module_idx); /* Consume the host module vector `host` and finish it into an engine handle, written to `out_engine`. The engine is sized with a `stack_size`-word guest stack (each word is 4 bytes), room for `max_modules` guest modules (<= 256), and compiles guest modules according to `options` (code-page budget, `memory.grow` support, backpatch bound). No guest module is loaded yet; use [`spacewasm_load_module`] to load one or more. `host` may be null to create an engine with no host modules. # Ownership of `host` The host vector is consumed on every path *except* the two argument-validation failures that are rejected before `host` is read: * [`spacewasm_status_t::SPACEWASM_ERR_NULL_ARG`] — `out_engine` is null. * [`spacewasm_status_t::SPACEWASM_ERR_VEC_TOO_LONG`] — `max_modules` exceeds 256. On those two the caller still owns `host` and must [`spacewasm_host_destroy`] it. Every other outcome, success or failure, consumes it. Concretely: check for these two codes before deciding whether to destroy the vector. # Safety `host` must be null or a live handle from [`spacewasm_host_new`], not already consumed/destroyed; `out_engine` must be a valid pointer. */ spacewasm_status_t spacewasm_new(struct spacewasm_host_t *host, size_t stack_size, size_t max_modules, struct spacewasm_compiler_options_t options, struct spacewasm_t **out_engine); /* Destroy a host vector that was never consumed into an engine. No-op on null. # Safety `host` must be null or a live unconsumed handle from [`spacewasm_host_new`]. */ void spacewasm_host_destroy(struct spacewasm_host_t *host); /* Find a module with a given name in the engine. # Safety `engine` must be live; `name` valid; `out_index` valid. */ spacewasm_status_t spacewasm_find_module(struct spacewasm_t *engine, const char *name, uint32_t *out_index); /* Look up the exported function named `name` in module `module_idx` and write its index to `out_index`. # Safety `engine` must be live; `name` valid; `out_index` valid. */ spacewasm_status_t spacewasm_find_export_func(struct spacewasm_t *engine, uint32_t module_idx, const char *name, uint32_t *out_index); /* Look up the start function of module `module_idx` and write its location to `out_module_idx` and `out_func_index`. Start functions are never host functions (that is rejected at load time), so the result is always a directly-invokable Wasm function. The written indices can be passed straight to [`spacewasm_invoke`] followed by [`spacewasm_run`], exactly as you would an exported function. Note that `out_module_idx` may differ from `module_idx` when the start is an imported (cross-module) function. Returns [`spacewasm_status_t::SPACEWASM_OK`] and populates the outputs when the module declares a start function. Returns [`spacewasm_status_t::SPACEWASM_ERR_NOT_FOUND`] when `module_idx` is out of range or the module has no start function, in which case there is nothing to invoke. # Safety `engine` must be live; `out_module_idx` and `out_func_index` valid. */ spacewasm_status_t spacewasm_module_start(struct spacewasm_t *engine, uint32_t module_idx, uint32_t *out_module_idx, uint32_t *out_func_index); /* Check that function `func_index` of module `module_idx` has the signature described by `params_sig` and `returns_sig`. Signatures use the same alphabet as [`spacewasm_add_host_function`]: `i` (i32), `I` (i64), `f` (f32), `d` (f64). For example, a function `(i32, i32) -> i32` matches `params_sig = "ii"`, `returns_sig = "i"`. Returns [`spacewasm_status_t::SPACEWASM_OK`] when the signature matches. Returns [`spacewasm_status_t::SPACEWASM_ERR_PARAM_LEN_MISMATCH`] when the parameter or return count differs, and [`spacewasm_status_t::SPACEWASM_ERR_PARAM_TYPE_MISMATCH`] when a type at some position differs. Returns [`spacewasm_status_t::SPACEWASM_ERR_NOT_FOUND`] when `module_idx` or `func_index` is out of range. When a signature string contains a character other than `iIfd` it returns [`spacewasm_status_t::SPACEWASM_ERR_BAD_ARG`], and when it declares more than `MAX_HOST_FUNCTION_PARAMS` entries it returns [`spacewasm_status_t::SPACEWASM_ERR_FUNCTION_PARAMETERS_TOO_LARGE`]. # Safety `engine` must be live; all C strings valid and NUL-terminated. */ spacewasm_status_t spacewasm_check_func_signature(struct spacewasm_t *engine, uint32_t module_idx, uint32_t func_index, const char *params_sig, const char *returns_sig); /* Look up the global exported as `name` in module `module_idx` and write its index to `out_index`. The written index addresses the module's own globals and can be passed straight to [`spacewasm_get_global`] and [`spacewasm_set_global`]. Only globals defined by module `module_idx` itself are resolvable this way: if the export re-exports a global imported from another (guest or host) module, this returns [`spacewasm_status_t::SPACEWASM_ERR_NOT_FOUND`], exactly as [`spacewasm_find_export_func`] does for imported functions. Reach such a global through the module that defines it. Returns [`spacewasm_status_t::SPACEWASM_ERR_NOT_FOUND`] when `module_idx` is out of range or the module exports no matching, locally-defined global. # Safety `engine` must be live; `name` valid; `out_index` valid. */ spacewasm_status_t spacewasm_find_global(struct spacewasm_t *engine, uint32_t module_idx, const char *name, uint32_t *out_index); /* Read global `global_index` of module `module_idx` into `out`, tagged with the global's declared value type. `global_index` addresses the module's own globals, as returned by [`spacewasm_find_global`]. Returns [`spacewasm_status_t::SPACEWASM_ERR_NOT_FOUND`] when `module_idx` or `global_index` is out of range. # Safety `engine` must be live; `out` valid. */ spacewasm_status_t spacewasm_get_global(struct spacewasm_t *engine, uint32_t module_idx, uint32_t global_index, struct spacewasm_value_t *out); /* Write `value` into global `global_index` of module `module_idx`. `global_index` addresses the module's own globals, as returned by [`spacewasm_find_global`]. The tag of `value` must match the global's declared value type, and the global must be mutable. Returns [`spacewasm_status_t::SPACEWASM_ERR_NOT_FOUND`] when `module_idx` or `global_index` is out of range, [`spacewasm_status_t::SPACEWASM_ERR_GLOBAL_TYPE_MISMATCH`] when the value type does not match the global, and [`spacewasm_status_t::SPACEWASM_ERR_GLOBAL_NOT_MUTABLE`] when the global is declared `const`. # Safety `engine` must be a live handle. */ spacewasm_status_t spacewasm_set_global(struct spacewasm_t *engine, uint32_t module_idx, uint32_t global_index, struct spacewasm_value_t value); /* Set up a call to exported function `func_index` of module `module_idx` with the `n` arguments in `params`. Does not run the function; drive execution with [`spacewasm_run`]. # Safety `engine` must be live; `params` valid for `n` entries. */ spacewasm_status_t spacewasm_invoke(struct spacewasm_t *engine, uint32_t module_idx, uint32_t func_index, const struct spacewasm_value_t *params, size_t n); /* Run the pending invocation for up to `fuel` units of work, writing any trap to `out_trap`. Returns whether the call finished, trapped, paused, or ran out of fuel. A paused engine runs nothing and returns [`spacewasm_run_status_t::SPACEWASM_RUN_PAUSE`] again until the host call's result is supplied with [`spacewasm_resume`] or [`spacewasm_resume_value`]. # Safety `engine` must be live; `out_trap` null or valid. */ spacewasm_run_status_t spacewasm_run(struct spacewasm_t *engine, size_t fuel, spacewasm_trap_t *out_trap); /* Resume the interpreter from a paused state (no return value). Returns [`spacewasm_status_t::SPACEWASM_ERR_WRONG_STATE`] if the engine is not paused, and [`spacewasm_status_t::SPACEWASM_ERR_PARAM_TYPE_MISMATCH`] if the paused host function declared a result — use [`spacewasm_resume_value`] instead. On the latter the pause is preserved, so the call can be retried. # Safety `engine` must be live. */ spacewasm_status_t spacewasm_resume(struct spacewasm_t *engine); /* Resume the interpreter from a paused state. This function will also push a value to the interpreter stack as the return value of the host function that requested a pause. Returns [`spacewasm_status_t::SPACEWASM_ERR_BAD_ARG`] if `resume_value.tag` is not a valid [`spacewasm_valtype_t`], [`spacewasm_status_t::SPACEWASM_ERR_WRONG_STATE`] if the engine is not paused, and [`spacewasm_status_t::SPACEWASM_ERR_PARAM_TYPE_MISMATCH`] if the value's type does not match the paused host function's declared result. In the mismatch case the pause is preserved and no stack state changes, so the call can be retried with a correctly typed value. # Safety `engine` must be live. */ spacewasm_status_t spacewasm_resume_value(struct spacewasm_t *engine, struct spacewasm_value_t resume_value); /* Reset the engine back to an idle state, discarding any in-progress or completed call: the program counter, stack pointers, and pending result are cleared, and guest linear memory and the table are reset to their zero state. Loaded modules remain loaded. Use this to abandon a paused or out-of-fuel call, or to run a fresh invocation from a clean slate. # Safety `engine` must be a live handle. */ spacewasm_status_t spacewasm_reset(struct spacewasm_t *engine); /* Fetch the result of the last completed call, coerced to `expected`, into `out`. # Silent type coercion The core engine stores a completed call's result as an untagged [`RawValue`]. The function signature must be checked before invoking and the return value must be extracted (in this function) using the proper `expected` type. # Safety `engine` must be live; `out` valid. */ spacewasm_status_t spacewasm_get_result(struct spacewasm_t *engine, spacewasm_valtype_t expected, struct spacewasm_value_t *out); /* Write the engine's call stack, as it stands between [`spacewasm_run`] calls, to `out_pcs`, innermost first, and its depth to `out_len`. Each entry is an IR program counter: an address into the IR of every module loaded onto this engine. Mapping it back to Wasm requires an IR map built from the same modules, loaded in the same order, with the same compiler options. - Entry 0 is the instruction the engine is at: - out of fuel (or invoked and not yet run), the next instruction to execute; - paused, the `call` / `call_indirect` instruction that called the pausing host function, until [`spacewasm_resume`] moves past it; - trapped, the faulting instruction. The trap leaves the stack in place, so the backtrace remains until the next [`spacewasm_invoke`] or [`spacewasm_reset`]. - Each later entry is the PC of the `call` / `call_indirect` instruction in the next-outer function. It is the address of the call instruction itself, not a return address, so a symbol lookup must not subtract one. The last entry is in the function passed to [`spacewasm_invoke`]. A host function that wants its own call stack returns [`spacewasm_hostcall_result_t::SPACEWASM_PAUSE`]: entry 0 is then its `call`, and the embedder resumes once it has read the backtrace. Writes at most `capacity` entries. `*out_len` is always the full depth; if it is larger than `capacity`, the innermost `capacity` entries are written and [`spacewasm_status_t::SPACEWASM_ERR_CAPACITY`] is returned. Pass `capacity == 0` (with a null `out_pcs`) to query the depth only. Returns [`spacewasm_status_t::SPACEWASM_ERR_WRONG_STATE`] if there is no call stack: nothing has been invoked since the last reset, or the last call finished. Must not be called while [`spacewasm_run`] is executing. # Safety `engine` must be live; `out_pcs` valid for `capacity` entries (or null if `capacity` is 0); `out_len` valid. */ spacewasm_status_t spacewasm_backtrace(const struct spacewasm_t *engine, uint32_t *out_pcs, size_t capacity, size_t *out_len); /* Destroy an engine and free its resources. No-op on null. # Safety `engine` must be a live handle, not already destroyed. */ void spacewasm_destroy(struct spacewasm_t *engine); /* Read `len` bytes of guest linear memory starting at `addr` into `dst`. Intended for use from within a host function. # Safety `caller` must be a live caller handle; `dst` valid for `len`. */ spacewasm_status_t spacewasm_mem_read(struct spacewasm_caller_t *caller, uint32_t addr, uint8_t *dst, size_t len); /* Write `len` bytes from `src` to guest linear memory starting at `addr`. Intended for use from within a host function. # Safety `caller` must be a live caller handle; `src` valid for `len`. */ spacewasm_status_t spacewasm_mem_write(struct spacewasm_caller_t *caller, uint32_t addr, const uint8_t *src, size_t len); /* Report the size of guest linear memory in pages. Intended for use from within a host function. # Safety `caller` must be a live caller handle; `out_pages` must be a valid pointer. */ spacewasm_status_t spacewasm_mem_size(struct spacewasm_caller_t *caller, uint32_t *out_pages); /* Handle a spacewasm Rust panic. This function should not return # Arguments * `filename`: Filename where panic occurred (not null terminated) * `filename_len`: Length of filename (could be 0) * `line`: Line number where panic occured * `msg`: Panic message if it could be extracted (not null terminated) * `len`: Length of panic message (zero if empty) returns: ! */ SPACEWASM_NORETURN extern void spacewasm_panic(const uint8_t *filename, size_t filename_len, uint32_t line, const uint8_t *msg, size_t len); /* Install the process-wide heap allocator backing the interpreter. `alloc`/`dealloc` are called at *page* granularity. # Safety `alloc`/`dealloc` must remain valid for the lifetime of the process and honor the requested size/alignment. `userdata` must outlive all allocations. */ spacewasm_status_t spacewasm_set_global_allocator(spacewasm_global_alloc_fn_t alloc, spacewasm_global_dealloc_fn_t dealloc, void *userdata); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif /* SPACEWASM_H */