diff --git a/third_party/wasmer/Cargo.toml b/third_party/wasmer/Cargo.toml index 9f08f1646d4..bfe61724256 100644 --- a/third_party/wasmer/Cargo.toml +++ b/third_party/wasmer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "0.7.0" +version = "0.17.1" [lib] name = "wasmer" @@ -8,4 +8,4 @@ crate-type = ["staticlib"] path = "wasmer.rs" [dependencies] -wasmer-runtime-c-api = "0.7.0" +wasmer-runtime-c-api = "0.17.1" diff --git a/third_party/wasmer/LICENSE b/third_party/wasmer/LICENSE index 079740dd377..62bb543eb9e 100644 --- a/third_party/wasmer/LICENSE +++ b/third_party/wasmer/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Wasmer, Inc. and its affiliates. +Copyright (c) 2019-present Wasmer, Inc. and its affiliates. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/third_party/wasmer/README.md b/third_party/wasmer/README.md index 1e741cfd121..d1475b7fdea 100644 --- a/third_party/wasmer/README.md +++ b/third_party/wasmer/README.md @@ -1,31 +1,31 @@

- Wasmer logo + Wasmer logo

- - Build Status + + Build Status - License + License Join the Wasmer Community - Number of downloads from crates.io + Number of downloads from crates.io - - Read our API documentation + + Wasmer C API Documentation

# Wasmer Runtime C API Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully -compatible with Emscripten, Rust and Go. [Learn +compatible with WASI, Emscripten, Rust and Go. [Learn more](https://github.com/wasmerio/wasmer). This crate exposes a C and a C++ API for the Wasmer runtime. @@ -36,6 +36,10 @@ The C and C++ header files can be found in the source tree of this crate, respectively [`wasmer.h`][wasmer_h] and [`wasmer.hh`][wasmer_hh]. They are automatically generated, and always up-to-date in this repository. +The runtime shared library (so, dll, dylib) can also be downloaded in Wasmer [release page](https://github.com/wasmerio/wasmer/releases). + +You can find the full C API documentation here: +https://wasmerio.github.io/wasmer/c/runtime-c-api/ Here is a simple example to use the C API: @@ -104,10 +108,14 @@ int main() # Testing +Tests are run using the release build of the library. If you make +changes or compile with non-default features, please ensure you +rebuild in release mode for the tests to see the changes. + The tests can be run via `cargo test`, such as: ```sh -$ cargo test -- --nocapture +$ cargo test --release -- --nocapture ``` To run tests manually, enter the `lib/runtime-c-api/tests` directory diff --git a/third_party/wasmer/wasmer.hh b/third_party/wasmer/wasmer.hh index cf7a1c7b321..647e637d03f 100644 --- a/third_party/wasmer/wasmer.hh +++ b/third_party/wasmer/wasmer.hh @@ -1,3 +1,36 @@ + +#if !defined(WASMER_H_MACROS) + +#define WASMER_H_MACROS + +// Define the `ARCH_X86_X64` constant. +#if defined(MSVC) && defined(_M_AMD64) +# define ARCH_X86_64 +#elif (defined(GCC) || defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__) +# define ARCH_X86_64 +#endif + +// Compatibility with non-Clang compilers. +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif + +// Compatibility with non-Clang compilers. +#if !defined(__has_declspec_attribute) +# define __has_declspec_attribute(x) 0 +#endif + +// Define the `DEPRECATED` macro. +#if defined(GCC) || defined(__GNUC__) || __has_attribute(deprecated) +# define DEPRECATED(message) __attribute__((deprecated(message))) +#elif defined(MSVC) || __has_declspec_attribute(deprecated) +# define DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#define WASMER_WASI_ENABLED +#endif // WASMER_H_MACROS + + #ifndef WASMER_H #define WASMER_H @@ -6,22 +39,52 @@ #include #include +#if defined(WASMER_WASI_ENABLED) +enum class Version : uint8_t { + /// Version cannot be detected or is unknown. + Unknown = 0, + /// Latest version. See `wasmer_wasi::WasiVersion::Latest` to + /// learn more. + Latest = 1, + /// `wasi_unstable`. + Snapshot0 = 2, + /// `wasi_snapshot_preview1`. + Snapshot1 = 3, +}; +#endif + +/// List of export/import kinds. enum class wasmer_import_export_kind : uint32_t { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + /// The export/import is a function. + WASM_FUNCTION = 0, + /// The export/import is a global. + WASM_GLOBAL = 1, + /// The export/import is a memory. + WASM_MEMORY = 2, + /// The export/import is a table. + WASM_TABLE = 3, }; +/// The `wasmer_result_t` enum is a type that represents either a +/// success, or a failure. enum class wasmer_result_t { + /// Represents a success. WASMER_OK = 1, + /// Represents a failure. WASMER_ERROR = 2, }; +/// Represents all possibles WebAssembly value types. +/// +/// See `wasmer_value_t` to get a complete example. enum class wasmer_value_tag : uint32_t { + /// Represents the `i32` WebAssembly type. WASM_I32, + /// Represents the `i64` WebAssembly type. WASM_I64, + /// Represents the `f32` WebAssembly type. WASM_F32, + /// Represents the `f64` WebAssembly type. WASM_F64, }; @@ -29,7 +92,12 @@ struct wasmer_module_t { }; -struct wasmer_export_descriptor_t { +/// Opaque pointer to a `wasmer_runtime::Instance` value in Rust. +/// +/// A `wasmer_runtime::Instance` represents a WebAssembly instance. It +/// is generally generated by the `wasmer_instantiate()` function, or by +/// the `wasmer_module_instantiate()` function for the most common paths. +struct wasmer_instance_t { }; @@ -38,14 +106,38 @@ struct wasmer_byte_array { uint32_t bytes_len; }; +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/// Type used to construct an import_object_t with Emscripten imports. +struct wasmer_emscripten_globals_t { + +}; +#endif + +struct wasmer_import_object_t { + +}; + +/// Opaque pointer to `NamedExportDescriptor`. +struct wasmer_export_descriptor_t { + +}; + +/// Opaque pointer to `NamedExportDescriptors`. struct wasmer_export_descriptors_t { }; +/// Opaque pointer to `wasmer_export_t`. struct wasmer_export_func_t { }; +/// Represents a WebAssembly value. +/// +/// This is a [Rust union][rust-union], which is equivalent to the C +/// union. See `wasmer_value_t` to get a complete example. +/// +/// [rust-union]: https://doc.rust-lang.org/reference/items/unions.html union wasmer_value { int32_t I32; int64_t I64; @@ -53,19 +145,53 @@ union wasmer_value { double F64; }; +/// Represents a WebAssembly type and value pair, +/// i.e. `wasmer_value_tag` and `wasmer_value`. Since the latter is an +/// union, it's the safe way to read or write a WebAssembly value in +/// C. +/// +/// Example: +/// +/// ```c +/// // Create a WebAssembly value. +/// wasmer_value_t wasm_value = { +/// .tag = WASM_I32, +/// .value.I32 = 42, +/// }; +/// +/// // Read a WebAssembly value. +/// if (wasm_value.tag == WASM_I32) { +/// int32_t x = wasm_value.value.I32; +/// // … +/// } +/// ``` struct wasmer_value_t { + /// The value type. wasmer_value_tag tag; + /// The value. wasmer_value value; }; +/// Opaque pointer to `NamedExport`. struct wasmer_export_t { }; +/// Opaque pointer to a `wasmer_runtime::Memory` value in Rust. +/// +/// A `wasmer_runtime::Memory` represents a WebAssembly memory. It is +/// possible to create one with `wasmer_memory_new()` and pass it as +/// imports of an instance, or to read it from exports of an instance +/// with `wasmer_export_to_memory()`. struct wasmer_memory_t { }; +/// Opaque pointer to the opaque structure `crate::NamedExports`, +/// which is a wrapper around a vector of the opaque structure +/// `crate::NamedExport`. +/// +/// Check the `wasmer_instance_exports()` function to learn more. struct wasmer_exports_t { }; @@ -91,14 +217,11 @@ struct wasmer_import_func_t { }; -struct wasmer_import_object_t { - -}; - struct wasmer_table_t { }; +/// Union of import/export value. union wasmer_import_export_value { const wasmer_import_func_t *func; const wasmer_table_t *table; @@ -113,21 +236,55 @@ struct wasmer_import_t { wasmer_import_export_value value; }; -struct wasmer_instance_t { +struct wasmer_import_object_iter_t { }; +/// Opaque pointer to a `wasmer_runtime::Ctx` value in Rust. +/// +/// An instance context is passed to any host function (aka imported +/// function) as the first argument. It is necessary to read the +/// instance data or the memory, respectively with the +/// `wasmer_instance_context_data_get()` function, and the +/// `wasmer_instance_context_memory()` function. +/// +/// It is also possible to get the instance context outside a host +/// function by using the `wasmer_instance_context_get()` +/// function. See also `wasmer_instance_context_data_set()` to set the +/// instance context data. +/// +/// Example: +/// +/// ```c +/// // A host function that prints data from the WebAssembly memory to +/// // the standard output. +/// void print(wasmer_instance_context_t *context, int32_t pointer, int32_t length) { +/// // Use `wasmer_instance_context` to get back the first instance memory. +/// const wasmer_memory_t *memory = wasmer_instance_context_memory(context, 0); +/// +/// // Continue… +/// } +/// ``` struct wasmer_instance_context_t { }; +/// The `wasmer_limit_option_t` struct represents an optional limit +/// for `wasmer_limits_t`. struct wasmer_limit_option_t { + /// Whether the limit is set. bool has_some; + /// The limit value. uint32_t some; }; +/// The `wasmer_limits_t` struct is a type that describes a memory +/// options. See the `wasmer_memory_t` struct or the +/// `wasmer_memory_new()` function to get more information. struct wasmer_limits_t { + /// The minimum number of allowed pages. uint32_t min; + /// The maximum number of allowed pages. wasmer_limit_option_t max; }; @@ -135,28 +292,95 @@ struct wasmer_serialized_module_t { }; +#if (!defined(_WIN32) && defined(ARCH_X86_64)) struct wasmer_trampoline_buffer_builder_t { }; +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) struct wasmer_trampoline_callable_t { }; +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) struct wasmer_trampoline_buffer_t { }; +#endif + +#if defined(WASMER_WASI_ENABLED) +/// Opens a directory that's visible to the WASI module as `alias` but +/// is backed by the host file at `host_file_path` +struct wasmer_wasi_map_dir_entry_t { + /// What the WASI module will see in its virtual root + wasmer_byte_array alias; + /// The backing file that the WASI module will interact with via the alias + wasmer_byte_array host_file_path; +}; +#endif extern "C" { /// Creates a new Module from the given wasm bytes. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_compile(wasmer_module_t **module, uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/// Convenience function for setting up arguments and calling the Emscripten +/// main function. +/// +/// WARNING: +/// +/// Do not call this function on untrusted code when operating without +/// additional sandboxing in place. +/// Emscripten has access to many host system calls and therefore may do very +/// bad things. +wasmer_result_t wasmer_emscripten_call_main(wasmer_instance_t *instance, + const wasmer_byte_array *args, + unsigned int args_len); +#endif + +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/// Destroy `wasmer_emscrpten_globals_t` created by +/// `wasmer_emscripten_get_emscripten_globals`. +void wasmer_emscripten_destroy_globals(wasmer_emscripten_globals_t *globals); +#endif + +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/// Create a `wasmer_import_object_t` with Emscripten imports, use +/// `wasmer_emscripten_get_emscripten_globals` to get a +/// `wasmer_emscripten_globals_t` from a `wasmer_module_t`. +/// +/// WARNING: +/// +/// This `import_object_t` contains thin-wrappers around host system calls. +/// Do not use this to execute untrusted code without additional sandboxing. +wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscripten_globals_t *globals); +#endif + +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/// Create a `wasmer_emscripten_globals_t` from a Wasm module. +wasmer_emscripten_globals_t *wasmer_emscripten_get_globals(const wasmer_module_t *module); +#endif + +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/// Execute global constructors (required if the module is compiled from C++) +/// and sets up the internal environment. +/// +/// This function sets the data pointer in the same way that +/// [`wasmer_instance_context_data_set`] does. +wasmer_result_t wasmer_emscripten_set_up(wasmer_instance_t *instance, + wasmer_emscripten_globals_t *globals); +#endif + /// Gets export descriptor kind wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_); @@ -164,6 +388,7 @@ wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor wasmer_byte_array wasmer_export_descriptor_name(wasmer_export_descriptor_t *export_descriptor); /// Gets export descriptors for the given module +/// /// The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it. void wasmer_export_descriptors(const wasmer_module_t *module, wasmer_export_descriptors_t **export_descriptors); @@ -180,17 +405,21 @@ int wasmer_export_descriptors_len(wasmer_export_descriptors_t *exports); /// Calls a `func` with the provided parameters. /// Results are set using the provided `results` pointer. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_export_func_call(const wasmer_export_func_t *func, const wasmer_value_t *params, - int params_len, + unsigned int params_len, wasmer_value_t *results, - int results_len); + unsigned int results_len); /// Sets the params buffer to the parameter types of the given wasmer_export_func_t +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func, @@ -198,13 +427,17 @@ wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func, uint32_t params_len); /// Sets the result parameter to the arity of the params of the wasmer_export_func_t +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_export_func_params_arity(const wasmer_export_func_t *func, uint32_t *result); /// Sets the returns buffer to the parameter types of the given wasmer_export_func_t +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func, @@ -212,7 +445,9 @@ wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func, uint32_t returns_len); /// Sets the result parameter to the arity of the returns of the wasmer_export_func_t +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_export_func_returns_arity(const wasmer_export_func_t *func, @@ -228,12 +463,30 @@ wasmer_byte_array wasmer_export_name(wasmer_export_t *export_); const wasmer_export_func_t *wasmer_export_to_func(const wasmer_export_t *export_); /// Gets a memory pointer from an export pointer. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_export_to_memory(const wasmer_export_t *export_, wasmer_memory_t **memory); -/// Frees the memory for the given exports +/// Frees the memory for the given exports. +/// +/// Check the `wasmer_instance_exports()` function to get a complete +/// example. +/// +/// If `exports` is a null pointer, this function does nothing. +/// +/// Example: +/// +/// ```c +/// // Get some exports. +/// wasmer_exports_t *exports = NULL; +/// wasmer_instance_exports(instance, &exports); +/// +/// // Destroy the exports. +/// wasmer_exports_destroy(exports); +/// ``` void wasmer_exports_destroy(wasmer_exports_t *exports); /// Gets wasmer_export by index @@ -268,6 +521,7 @@ wasmer_byte_array wasmer_import_descriptor_module_name(wasmer_import_descriptor_ wasmer_byte_array wasmer_import_descriptor_name(wasmer_import_descriptor_t *import_descriptor); /// Gets import descriptors for the given module +/// /// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it. void wasmer_import_descriptors(const wasmer_module_t *module, wasmer_import_descriptors_t **import_descriptors); @@ -285,8 +539,23 @@ unsigned int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports) /// Frees memory for the given Func void wasmer_import_func_destroy(wasmer_import_func_t *func); -/// Creates new func -/// The caller owns the object and should call `wasmer_import_func_destroy` to free it. +/// Creates new host function, aka imported function. `func` is a +/// function pointer, where the first argument is the famous `vm::Ctx` +/// (in Rust), or `wasmer_instance_context_t` (in C). All arguments +/// must be typed with compatible WebAssembly native types: +/// +/// | WebAssembly type | C/C++ type | +/// | ---------------- | ---------- | +/// | `i32` | `int32_t` | +/// | `i64` | `int64_t` | +/// | `f32` | `float` | +/// | `f64` | `double` | +/// +/// The function pointer must have a lifetime greater than the +/// WebAssembly instance lifetime. +/// +/// The caller owns the object and should call +/// `wasmer_import_func_destroy` to free it. wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data), const wasmer_value_tag *params, unsigned int params_len, @@ -294,7 +563,9 @@ wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data), unsigned int returns_len); /// Sets the params buffer to the parameter types of the given wasmer_import_func_t +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_import_func_params(const wasmer_import_func_t *func, @@ -302,13 +573,17 @@ wasmer_result_t wasmer_import_func_params(const wasmer_import_func_t *func, unsigned int params_len); /// Sets the result parameter to the arity of the params of the wasmer_import_func_t +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_import_func_params_arity(const wasmer_import_func_t *func, uint32_t *result); /// Sets the returns buffer to the parameter types of the given wasmer_import_func_t +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func, @@ -316,7 +591,9 @@ wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func, unsigned int returns_len); /// Sets the result parameter to the arity of the returns of the wasmer_import_func_t +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *func, @@ -327,18 +604,101 @@ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); /// Extends an existing import object with new imports wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object, - wasmer_import_t *imports, + const wasmer_import_t *imports, unsigned int imports_len); +/// Gets an entry from an ImportObject at the name and namespace. +/// Stores `name`, `namespace`, and `import_export_value` in `import`. +/// Thus these must remain valid for the lifetime of `import`. +/// +/// The caller owns all data involved. +/// `import_export_value` will be written to based on `tag`. +wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, + wasmer_byte_array namespace_, + wasmer_byte_array name, + wasmer_import_t *import, + wasmer_import_export_value *import_export_value, + uint32_t tag); + +/// Frees the memory allocated in `wasmer_import_object_iter_next` +/// +/// This function does not free the memory in `wasmer_import_object_t`; +/// it only frees memory allocated while querying a `wasmer_import_object_t`. +void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); + +/// Returns true if further calls to `wasmer_import_object_iter_next` will +/// not return any new data +bool wasmer_import_object_iter_at_end(wasmer_import_object_iter_t *import_object_iter); + +/// Frees the memory allocated by `wasmer_import_object_iterate_functions` +void wasmer_import_object_iter_destroy(wasmer_import_object_iter_t *import_object_iter); + +/// Writes the next value to `import`. `WASMER_ERROR` is returned if there +/// was an error or there's nothing left to return. +/// +/// To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. +/// To check if the iterator is done, use `wasmer_import_object_iter_at_end`. +wasmer_result_t wasmer_import_object_iter_next(wasmer_import_object_iter_t *import_object_iter, + wasmer_import_t *import); + +/// Create an iterator over the functions in the import object. +/// Get the next import with `wasmer_import_object_iter_next` +/// Free the iterator with `wasmer_import_object_iter_destroy` +wasmer_import_object_iter_t *wasmer_import_object_iterate_functions(const wasmer_import_object_t *import_object); + /// Creates a new empty import object. /// See also `wasmer_import_object_append` wasmer_import_object_t *wasmer_import_object_new(); -/// Calls an instances exported function by `name` with the provided parameters. -/// Results are set using the provided `results` pointer. -/// Returns `wasmer_result_t::WASMER_OK` upon success. -/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` -/// and `wasmer_last_error_message` to get an error message. +/// Calls an exported function of a WebAssembly instance by `name` +/// with the provided parameters. The exported function results are +/// stored on the provided `results` pointer. +/// +/// This function returns `wasmer_result_t::WASMER_OK` upon success, +/// `wasmer_result_t::WASMER_ERROR` otherwise. You can use +/// `wasmer_last_error_message()` to get the generated error message. +/// +/// Potential errors are the following: +/// +/// * `instance` is a null pointer, +/// * `name` is a null pointer, +/// * `params` is a null pointer. +/// +/// Example of calling an exported function that needs two parameters, and returns one value: +/// +/// ```c +/// // First argument. +/// wasmer_value_t argument_one = { +/// .tag = WASM_I32, +/// .value.I32 = 3, +/// }; +/// +/// // Second argument. +/// wasmer_value_t argument_two = { +/// .tag = WASM_I32, +/// .value.I32 = 4, +/// }; +/// +/// // First result. +/// wasmer_value_t result_one; +/// +/// // All arguments and results. +/// wasmer_value_t arguments[] = {argument_one, argument_two}; +/// wasmer_value_t results[] = {result_one}; +/// +/// wasmer_result_t call_result = wasmer_instance_call( +/// instance, // instance pointer +/// "sum", // the exported function name +/// arguments, // the arguments +/// 2, // the number of arguments +/// results, // the results +/// 1 // the number of results +/// ); +/// +/// if (call_result == WASMER_OK) { +/// printf("Result is: %d\n", results[0].value.I32); +/// } +/// ``` wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name, const wasmer_value_t *params, @@ -346,89 +706,362 @@ wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, wasmer_value_t *results, uint32_t results_len); -/// Gets the `data` field within the context. +/// Gets the data that can be hold by an instance. +/// +/// This function is complementary of +/// `wasmer_instance_context_data_set()`. Please read its +/// documentation. You can also read the documentation of +/// `wasmer_instance_context_t` to get other examples. +/// +/// This function returns nothing if `ctx` is a null pointer. void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx); -/// Sets the `data` field of the instance context. This context will be -/// passed to all imported function for instance. -void wasmer_instance_context_data_set(wasmer_instance_t *instance, void *data_ptr); +/// Sets the data that can be hold by an instance context. +/// +/// An instance context (represented by the opaque +/// `wasmer_instance_context_t` structure) can hold user-defined +/// data. This function sets the data. This function is complementary +/// of `wasmer_instance_context_data_get()`. +/// +/// This function does nothing if `instance` is a null pointer. +/// +/// Example: +/// +/// ```c +/// // Define your own data. +/// typedef struct { +/// // … +/// } my_data; +/// +/// // Allocate them and set them on the given instance. +/// my_data *data = malloc(sizeof(my_data)); +/// data->… = …; +/// wasmer_instance_context_data_set(instance, (void*) data); +/// +/// // You can read your data. +/// { +/// my_data *data = (my_data*) wasmer_instance_context_data_get(wasmer_instance_context_get(instance)); +/// // … +/// } +/// ``` +void wasmer_instance_context_data_set(wasmer_instance_t *instance, + void *data_ptr); -/// Extracts the instance's context and returns it. +/// Returns the instance context. Learn more by looking at the +/// `wasmer_instance_context_t` struct. +/// +/// This function returns `null` if `instance` is a null pointer. +/// +/// Example: +/// +/// ```c +/// const wasmer_instance_context_get *context = wasmer_instance_context_get(instance); +/// my_data *data = (my_data *) wasmer_instance_context_data_get(context); +/// // Do something with `my_data`. +/// ``` +/// +/// It is often useful with `wasmer_instance_context_data_set()`. const wasmer_instance_context_t *wasmer_instance_context_get(wasmer_instance_t *instance); -/// Gets the memory within the context at the index `memory_idx`. -/// The index is always 0 until multiple memories are supported. +/// Gets the `memory_idx`th memory of the instance. +/// +/// Note that the index is always `0` until multiple memories are supported. +/// +/// This function is mostly used inside host functions (aka imported +/// functions) to read the instance memory. +/// +/// Example of a _host function_ that reads and prints a string based on a pointer and a length: +/// +/// ```c +/// void print_string(const wasmer_instance_context_t *context, int32_t pointer, int32_t length) { +/// // Get the 0th memory. +/// const wasmer_memory_t *memory = wasmer_instance_context_memory(context, 0); +/// +/// // Get the memory data as a pointer. +/// uint8_t *memory_bytes = wasmer_memory_data(memory); +/// +/// // Print what we assumed to be a string! +/// printf("%.*s", length, memory_bytes + pointer); +/// } +/// ``` const wasmer_memory_t *wasmer_instance_context_memory(const wasmer_instance_context_t *ctx, uint32_t _memory_idx); -/// Frees memory for the given Instance +/// Frees memory for the given `wasmer_instance_t`. +/// +/// Check the `wasmer_instantiate()` function to get a complete +/// example. +/// +/// If `instance` is a null pointer, this function does nothing. +/// +/// Example: +/// +/// ```c +/// // Get an instance. +/// wasmer_instance_t *instance = NULL; +/// wasmer_instantiate(&instance, bytes, bytes_length, imports, 0); +/// +/// // Destroy the instance. +/// wasmer_instance_destroy(instance); +/// ``` void wasmer_instance_destroy(wasmer_instance_t *instance); -/// Gets Exports for the given instance -/// The caller owns the object and should call `wasmer_exports_destroy` to free it. +/// Gets all the exports of the given WebAssembly instance. +/// +/// This function stores a Rust vector of exports into `exports` as an +/// opaque pointer of kind `wasmer_exports_t`. +/// +/// As is, you can do anything with `exports` except using the +/// companion functions, like `wasmer_exports_len()`, +/// `wasmer_exports_get()` or `wasmer_export_kind()`. See the example below. +/// +/// **Warning**: The caller owns the object and should call +/// `wasmer_exports_destroy()` to free it. +/// +/// Example: +/// +/// ```c +/// // Get the exports. +/// wasmer_exports_t *exports = NULL; +/// wasmer_instance_exports(instance, &exports); +/// +/// // Get the number of exports. +/// int exports_length = wasmer_exports_len(exports); +/// printf("Number of exports: %d\n", exports_length); +/// +/// // Read the first export. +/// wasmer_export_t *export = wasmer_exports_get(exports, 0); +/// +/// // Get the kind of the export. +/// wasmer_import_export_kind export_kind = wasmer_export_kind(export); +/// +/// // Assert it is a function (why not). +/// assert(export_kind == WASM_FUNCTION); +/// +/// // Read the export name. +/// wasmer_byte_array name_bytes = wasmer_export_name(export); +/// +/// assert(name_bytes.bytes_len == sizeof("sum") - 1); +/// assert(memcmp(name_bytes.bytes, "sum", sizeof("sum") - 1) == 0); +/// +/// // Destroy the exports. +/// wasmer_exports_destroy(exports); +/// ``` void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exports); -/// Creates a new Instance from the given wasm bytes and imports. -/// Returns `wasmer_result_t::WASMER_OK` upon success. -/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` -/// and `wasmer_last_error_message` to get an error message. +/// Creates a new WebAssembly instance from the given bytes and imports. +/// +/// The result is stored in the first argument `instance` if +/// successful, i.e. when the function returns +/// `wasmer_result_t::WASMER_OK`. Otherwise +/// `wasmer_result_t::WASMER_ERROR` is returned, and +/// `wasmer_last_error_length()` with `wasmer_last_error_message()` must +/// be used to read the error message. +/// +/// The caller is responsible to free the instance with +/// `wasmer_instance_destroy()`. +/// +/// Example: +/// +/// ```c +/// // 1. Read a WebAssembly module from a file. +/// FILE *file = fopen("sum.wasm", "r"); +/// fseek(file, 0, SEEK_END); +/// long bytes_length = ftell(file); +/// uint8_t *bytes = malloc(bytes_length); +/// fseek(file, 0, SEEK_SET); +/// fread(bytes, 1, bytes_length, file); +/// fclose(file); +/// +/// // 2. Declare the imports (here, none). +/// wasmer_import_t imports[] = {}; +/// +/// // 3. Instantiate the WebAssembly module. +/// wasmer_instance_t *instance = NULL; +/// wasmer_result_t result = wasmer_instantiate(&instance, bytes, bytes_length, imports, 0); +/// +/// // 4. Check for errors. +/// if (result != WASMER_OK) { +/// int error_length = wasmer_last_error_length(); +/// char *error = malloc(error_length); +/// wasmer_last_error_message(error, error_length); +/// // Do something with `error`… +/// } +/// +/// // 5. Free the memory! +/// wasmer_instance_destroy(instance); +/// ``` wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, wasmer_import_t *imports, int imports_len); -/// Gets the length in bytes of the last error. +/// Gets the length in bytes of the last error if any. +/// /// This can be used to dynamically allocate a buffer with the correct number of /// bytes needed to store a message. -/// # Example -/// ```c -/// int error_len = wasmer_last_error_length(); -/// char *error_str = malloc(error_len); -/// ``` +/// +/// See `wasmer_last_error_message()` to get a full example. int wasmer_last_error_length(); -/// Stores the last error message into the provided buffer up to the given `length`. -/// The `length` parameter must be large enough to store the last error message. -/// Returns the length of the string in bytes. -/// Returns `-1` if an error occurs. -/// # Example +/// Gets the last error message if any into the provided buffer +/// `buffer` up to the given `length`. +/// +/// The `length` parameter must be large enough to store the last +/// error message. Ideally, the value should come from +/// `wasmer_last_error_length()`. +/// +/// The function returns the length of the string in bytes, `-1` if an +/// error occurs. Potential errors are: +/// +/// * The buffer is a null pointer, +/// * The buffer is too smal to hold the error message. +/// +/// Note: The error message always has a trailing null character. +/// +/// Example: +/// /// ```c -/// int error_len = wasmer_last_error_length(); -/// char *error_str = malloc(error_len); -/// wasmer_last_error_message(error_str, error_len); -/// printf("Error str: `%s`\n", error_str); +/// int error_length = wasmer_last_error_length(); +/// +/// if (error_length > 0) { +/// char *error_message = malloc(error_length); +/// wasmer_last_error_message(error_message, error_length); +/// printf("Error message: `%s`\n", error_message); +/// } else { +/// printf("No error message\n"); +/// } /// ``` int wasmer_last_error_message(char *buffer, int length); -/// Gets the start pointer to the bytes within a Memory -uint8_t *wasmer_memory_data(const wasmer_memory_t *mem); +/// Gets a pointer to the beginning of the contiguous memory data +/// bytes. +/// +/// The function returns `NULL` if `memory` is a null pointer. +/// +/// Note that when the memory grows, it can be reallocated, and thus +/// the returned pointer can be invalidated. +/// +/// Example: +/// +/// ```c +/// uint8_t *memory_data = wasmer_memory_data(memory); +/// char *str = (char*) malloc(sizeof(char) * 7); +/// +/// for (uint32_t nth = 0; nth < 7; ++nth) { +/// str[nth] = (char) memory_data[nth]; +/// } +/// ``` +uint8_t *wasmer_memory_data(const wasmer_memory_t *memory); -/// Gets the size in bytes of a Memory -uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); +/// Gets the size in bytes of the memory data. +/// +/// This function returns 0 if `memory` is a null pointer. +/// +/// Example: +/// +/// ```c +/// uint32_t memory_data_length = wasmer_memory_data_length(memory); +/// ``` +uint32_t wasmer_memory_data_length(const wasmer_memory_t *memory); -/// Frees memory for the given Memory +/// Frees memory for the given `wasmer_memory_t`. +/// +/// Check the `wasmer_memory_new()` function to get a complete +/// example. +/// +/// If `memory` is a null pointer, this function does nothing. +/// +/// Example: +/// +/// ```c +/// // Get a memory. +/// wasmer_memory_t *memory = NULL; +/// wasmer_result_t result = wasmer_memory_new(&memory, memory_descriptor); +/// +/// // Destroy the memory. +/// wasmer_memory_destroy(memory); +/// ``` void wasmer_memory_destroy(wasmer_memory_t *memory); -/// Grows a Memory by the given number of pages. -/// Returns `wasmer_result_t::WASMER_OK` upon success. -/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` -/// and `wasmer_last_error_message` to get an error message. +/// Grows a memory by the given number of pages (of 65Kb each). +/// +/// The functions return `wasmer_result_t::WASMER_OK` upon success, +/// `wasmer_result_t::WASMER_ERROR` otherwise. Use +/// `wasmer_last_error_length()` with `wasmer_last_error_message()` to +/// read the error message. +/// +/// Example: +/// +/// ```c +/// wasmer_result_t result = wasmer_memory_grow(memory, 10); +/// +/// if (result != WASMER_OK) { +/// // … +/// } +/// ``` wasmer_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); -/// Returns the current length in pages of the given memory +/// Reads the current length (in pages) of the given memory. +/// +/// The function returns zero if `memory` is a null pointer. +/// +/// Example: +/// +/// ```c +/// uint32_t memory_length = wasmer_memory_length(memory); +/// +/// printf("Memory pages length: %d\n", memory_length); +/// ``` uint32_t wasmer_memory_length(const wasmer_memory_t *memory); -/// Creates a new Memory for the given descriptor and initializes the given -/// pointer to pointer to a pointer to the new memory. -/// The caller owns the object and should call `wasmer_memory_destroy` to free it. -/// Returns `wasmer_result_t::WASMER_OK` upon success. -/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` -/// and `wasmer_last_error_message` to get an error message. +/// Creates a new empty WebAssembly memory for the given descriptor. +/// +/// The result is stored in the first argument `memory` if successful, +/// i.e. when the function returns +/// `wasmer_result_t::WASMER_OK`. Otherwise, +/// `wasmer_result_t::WASMER_ERROR` is returned, and +/// `wasmer_last_error_length()` with `wasmer_last_error_message()` +/// must be used to read the error message. +/// +/// The caller owns the memory and is responsible to free it with +/// `wasmer_memory_destroy()`. +/// +/// Example: +/// +/// ```c +/// // 1. The memory object. +/// wasmer_memory_t *memory = NULL; +/// +/// // 2. The memory descriptor. +/// wasmer_limits_t memory_descriptor = { +/// .min = 10, +/// .max = { +/// .has_some = true, +/// .some = 15, +/// }, +/// }; +/// +/// // 3. Initialize the memory. +/// wasmer_result_t result = wasmer_memory_new(&memory, memory_descriptor); +/// +/// if (result != WASMER_OK) { +/// int error_length = wasmer_last_error_length(); +/// char *error = malloc(error_length); +/// wasmer_last_error_message(error, error_length); +/// // Do something with `error`… +/// } +/// +/// // 4. Free the memory! +/// wasmer_memory_destroy(memory); +/// ``` wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); /// Deserialize the given serialized module. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module, @@ -438,15 +1071,18 @@ wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module, void wasmer_module_destroy(wasmer_module_t *module); /// Given: -/// A prepared `wasmer` import-object -/// A compiled wasmer module +/// * A prepared `wasmer` import-object +/// * A compiled wasmer module +/// /// Instantiates a wasmer instance wasmer_result_t wasmer_module_import_instantiate(wasmer_instance_t **instance, const wasmer_module_t *module, const wasmer_import_object_t *import_object); /// Creates a new Instance from the given module and imports. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_module_instantiate(const wasmer_module_t *module, @@ -455,8 +1091,11 @@ wasmer_result_t wasmer_module_instantiate(const wasmer_module_t *module, int imports_len); /// Serialize the given Module. +/// /// The caller owns the object and should call `wasmer_serialized_module_destroy` to free it. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_module_serialize(wasmer_serialized_module_t **serialized_module, @@ -469,8 +1108,11 @@ wasmer_byte_array wasmer_serialized_module_bytes(const wasmer_serialized_module_ void wasmer_serialized_module_destroy(wasmer_serialized_module_t *serialized_module); /// Transform a sequence of bytes into a serialized module. +/// /// The caller owns the object and should call `wasmer_serialized_module_destroy` to free it. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_serialized_module_from_bytes(wasmer_serialized_module_t **serialized_module, @@ -481,7 +1123,9 @@ wasmer_result_t wasmer_serialized_module_from_bytes(wasmer_serialized_module_t * void wasmer_table_destroy(wasmer_table_t *table); /// Grows a Table by the given number of elements. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); @@ -491,42 +1135,139 @@ uint32_t wasmer_table_length(wasmer_table_t *table); /// Creates a new Table for the given descriptor and initializes the given /// pointer to pointer to a pointer to the new Table. +/// /// The caller owns the object and should call `wasmer_table_destroy` to free it. +/// /// Returns `wasmer_result_t::WASMER_OK` upon success. +/// /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Adds a callinfo trampoline to the builder. +/// +/// Deprecated. In a future version `DynamicFunc::new` will be exposed to the C API and should be used instead of this function. uintptr_t wasmer_trampoline_buffer_builder_add_callinfo_trampoline(wasmer_trampoline_buffer_builder_t *builder, const wasmer_trampoline_callable_t *func, const void *ctx, uint32_t num_params); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Adds a context trampoline to the builder. uintptr_t wasmer_trampoline_buffer_builder_add_context_trampoline(wasmer_trampoline_buffer_builder_t *builder, const wasmer_trampoline_callable_t *func, const void *ctx); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Finalizes the trampoline builder into an executable buffer. wasmer_trampoline_buffer_t *wasmer_trampoline_buffer_builder_build(wasmer_trampoline_buffer_builder_t *builder); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Creates a new trampoline builder. wasmer_trampoline_buffer_builder_t *wasmer_trampoline_buffer_builder_new(); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Destroys the trampoline buffer if not null. void wasmer_trampoline_buffer_destroy(wasmer_trampoline_buffer_t *buffer); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Returns the callable pointer for the trampoline with index `idx`. const wasmer_trampoline_callable_t *wasmer_trampoline_buffer_get_trampoline(const wasmer_trampoline_buffer_t *buffer, uintptr_t idx); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Returns the context added by `add_context_trampoline`, from within the callee function. void *wasmer_trampoline_get_context(); +#endif -/// Returns true for valid wasm bytes and false for invalid bytes +/// Stop the execution of a host function, aka imported function. The +/// function must be used _only_ inside a host function. +/// +/// The pointer to `wasmer_instance_context_t` is received by the host +/// function as its first argument. Just passing it to `ctx` is fine. +/// +/// The error message must have a greater lifetime than the host +/// function itself since the error is read outside the host function +/// with `wasmer_last_error_message`. +/// +/// This function returns `wasmer_result_t::WASMER_ERROR` if `ctx` or +/// `error_message` are null. +/// +/// This function never returns otherwise. +wasmer_result_t wasmer_trap(const wasmer_instance_context_t *ctx, const char *error_message); + +/// Validates a sequence of bytes hoping it represents a valid WebAssembly module. +/// +/// The function returns true if the bytes are valid, false otherwise. +/// +/// Example: +/// +/// ```c +/// bool result = wasmer_validate(bytes, bytes_length); +/// +/// if (false == result) { +/// // Do something… +/// } +/// ``` bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +#if defined(WASMER_WASI_ENABLED) +/// Convenience function that creates a WASI import object with no arguments, +/// environment variables, preopened files, or mapped directories. +/// +/// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all +/// empty values. +wasmer_import_object_t *wasmer_wasi_generate_default_import_object(); +#endif + +#if defined(WASMER_WASI_ENABLED) +/// Creates a WASI import object. +/// +/// This function treats null pointers as empty collections. +/// For example, passing null for a string in `args`, will lead to a zero +/// length argument in that position. +wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args, + unsigned int args_len, + const wasmer_byte_array *envs, + unsigned int envs_len, + const wasmer_byte_array *preopened_files, + unsigned int preopened_files_len, + const wasmer_wasi_map_dir_entry_t *mapped_dirs, + unsigned int mapped_dirs_len); +#endif + +#if defined(WASMER_WASI_ENABLED) +/// Creates a WASI import object for a specific version. +/// +/// This function is similar to `wasmer_wasi_generate_import_object` +/// except that the first argument describes the WASI version. +/// +/// The version is expected to be of kind `Version`. +wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(unsigned char version, + const wasmer_byte_array *args, + unsigned int args_len, + const wasmer_byte_array *envs, + unsigned int envs_len, + const wasmer_byte_array *preopened_files, + unsigned int preopened_files_len, + const wasmer_wasi_map_dir_entry_t *mapped_dirs, + unsigned int mapped_dirs_len); +#endif + +#if defined(WASMER_WASI_ENABLED) +/// Find the version of WASI used by the module. +/// +/// In case of error, the returned version is `Version::Unknown`. +Version wasmer_wasi_get_version(const wasmer_module_t *module); +#endif + } // extern "C" #endif // WASMER_H