From dc0cf7d4a48ff2b05bc6de7efb4b17b8bd55197d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 25 Jan 2021 14:42:46 +0100 Subject: [PATCH 01/25] feat(c-api) Implement `wasi_get_unordered_imports`. --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 120 ++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index cd288db4e30..9a50b61d840 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -9,6 +9,7 @@ use super::{ instance::wasm_instance_t, module::wasm_module_t, store::wasm_store_t, + types::wasm_name_t, }; // required due to really weird Rust resolution rules for macros // https://github.com/rust-lang/rust/issues/57966 @@ -341,7 +342,124 @@ pub unsafe extern "C" fn wasi_get_wasi_version(module: &wasm_module_t) -> wasi_v .unwrap_or(wasi_version_t::INVALID_VERSION) } -/// Takes ownership of `wasi_env_t`. +/// Non-standard type wrapping `wasm_extern_t` with the addition of +/// two `wasm_name_t` respectively for the module name and the name of +/// the extern (very likely to be an import). This non-standard type +/// is used by the non-standard `wasi_get_unordered_imports` function. +#[allow(non_camel_case_types)] +#[derive(Clone)] +pub struct wasm_named_extern_t { + module: Box, + name: Box, + r#extern: Box, +} + +wasm_declare_boxed_vec!(named_extern); + +/// Non-standard function to get the module name of a +/// `wasm_named_extern_t`. +#[no_mangle] +pub extern "C" fn wasm_named_extern_module(named_extern: &wasm_named_extern_t) -> &wasm_name_t { + named_extern.module.as_ref() +} + +/// Non-standard function to get the name of a `wasm_named_extern_t`. +#[no_mangle] +pub extern "C" fn wasm_named_extern_name(named_extern: &wasm_named_extern_t) -> &wasm_name_t { + named_extern.name.as_ref() +} + +/// Non-standard function to get the wrapped extern of a +/// `wasm_named_extern_t`. +#[no_mangle] +pub extern "C" fn wasm_named_extern_extern(named_extern: &wasm_named_extern_t) -> &wasm_extern_t { + named_extern.r#extern.as_ref() +} + +/// Non-standard function to get the imports needed for the WASI +/// implementation with no particular order. Each import has its +/// associated module name and name, so that it can be re-order later +/// based on the `wasm_module_t` requirements. +/// +/// This function takes ownership of `wasm_env_t`. +#[no_mangle] +pub unsafe extern "C" fn wasi_get_unordered_imports( + store: &wasm_store_t, + module: &wasm_module_t, + wasi_env: &wasi_env_t, + imports: &mut wasm_named_extern_vec_t, +) -> bool { + wasi_get_unordered_imports_inner(store, module, wasi_env, imports).is_some() +} + +unsafe fn wasi_get_unordered_imports_inner( + store: &wasm_store_t, + module: &wasm_module_t, + wasi_env: &wasi_env_t, + imports: &mut wasm_named_extern_vec_t, +) -> Option<()> { + let store = &store.inner; + + let version = c_try!( + get_wasi_version(&module.inner, false).ok_or_else(|| CApiError { + msg: "could not detect a WASI version on the given module".to_string(), + }) + ); + + let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); + + *imports = import_object + .into_iter() + .map(|((module, name), export)| { + let module = { + let mut module: Box = module.into_boxed_str(); + let module_ptr = module.as_mut_ptr(); + let module_len = module.bytes().len(); + let module_inner = wasm_name_t { + size: module_len, + data: module_ptr, + }; + + Box::leak(module); + + Box::new(module_inner) + }; + let name = { + let mut name: Box = name.into_boxed_str(); + let name_ptr = name.as_mut_ptr(); + let name_len = name.bytes().len(); + let name_inner = wasm_name_t { + size: name_len, + data: name_ptr, + }; + + Box::leak(name); + + Box::new(name_inner) + }; + + let extern_inner = Extern::from_vm_export(store, export); + let r#extern = Box::new(wasm_extern_t { + instance: None, + inner: extern_inner, + }); + + Box::new(wasm_named_extern_t { + module, + name, + r#extern, + }) + }) + .collect::>() + .into(); + + Some(()) +} + +/// Non-standard function to get the imports needed for the WASI +/// implementation ordered as expected by the `wasm_module_t`. +/// +/// This function takes ownership of `wasm_env_t`. #[no_mangle] pub unsafe extern "C" fn wasi_get_imports( store: &wasm_store_t, From 00bf74c488be34c0f44869e22bfba08c336af939 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 25 Jan 2021 14:43:20 +0100 Subject: [PATCH 02/25] chore(c-api) Reorder field for the sake of consistency. --- lib/c-api/src/wasm_c_api/types/import.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/c-api/src/wasm_c_api/types/import.rs b/lib/c-api/src/wasm_c_api/types/import.rs index a1f94f800a3..4b253e074fe 100644 --- a/lib/c-api/src/wasm_c_api/types/import.rs +++ b/lib/c-api/src/wasm_c_api/types/import.rs @@ -79,8 +79,8 @@ impl From<&ImportType> for wasm_importtype_t { let extern_type = Box::new(other.ty().into()); wasm_importtype_t { - name, module, + name, extern_type, } } From 0ad4d319d64b60f1914561e3e1bd4c4999e8574b Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 25 Jan 2021 14:43:42 +0100 Subject: [PATCH 03/25] chore(c-api) Update headers. --- lib/c-api/wasmer.h | 48 +++++++++++++++++++++++++++++++++++++++++ lib/c-api/wasmer.hh | 38 ++++++++++++++++++++++++++++++++ lib/c-api/wasmer_wasm.h | 23 ++++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/lib/c-api/wasmer.h b/lib/c-api/wasmer.h index 43bb8e87e9f..b97902c3cef 100644 --- a/lib/c-api/wasmer.h +++ b/lib/c-api/wasmer.h @@ -166,6 +166,16 @@ enum wasmer_value_tag typedef uint32_t wasmer_value_tag; #endif // __cplusplus +#if defined(WASMER_WASI_ENABLED) +/** + * Non-standard type wrapping `wasm_extern_t` with the addition of + * two `wasm_name_t` respectively for the module name and the name of + * the extern (very likely to be an import). This non-standard type + * is used by the non-standard `wasi_get_unordered_imports` function. + */ +typedef struct wasm_named_extern_t wasm_named_extern_t; +#endif + typedef struct { } wasmer_module_t; @@ -431,6 +441,44 @@ typedef struct { extern "C" { #endif // __cplusplus +#if defined(WASMER_WASI_ENABLED) +/** + * Non-standard function to get the imports needed for the WASI + * implementation with no particular order. Each import has its + * associated module name and name, so that it can be re-order later + * based on the `wasm_module_t` requirements. + * + * This function takes ownership of `wasm_env_t`. + */ +bool wasi_get_unordered_imports(const wasm_store_t *store, + const wasm_module_t *module, + const wasi_env_t *wasi_env, + wasm_named_extern_vec_t *imports); +#endif + +#if defined(WASMER_WASI_ENABLED) +/** + * Non-standard function to get the wrapped extern of a + * `wasm_named_extern_t`. + */ +const wasm_extern_t *wasm_named_extern_extern(const wasm_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +/** + * Non-standard function to get the module name of a + * `wasm_named_extern_t`. + */ +const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +/** + * Non-standard function to get the name of a `wasm_named_extern_t`. + */ +const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); +#endif + /** * Creates a new Module from the given wasm bytes. * diff --git a/lib/c-api/wasmer.hh b/lib/c-api/wasmer.hh index 33a27385db9..a8e6a907f91 100644 --- a/lib/c-api/wasmer.hh +++ b/lib/c-api/wasmer.hh @@ -112,6 +112,14 @@ enum class wasmer_value_tag : uint32_t { WASM_F64, }; +#if defined(WASMER_WASI_ENABLED) +/// Non-standard type wrapping `wasm_extern_t` with the addition of +/// two `wasm_name_t` respectively for the module name and the name of +/// the extern (very likely to be an import). This non-standard type +/// is used by the non-standard `wasi_get_unordered_imports` function. +struct wasm_named_extern_t; +#endif + struct wasmer_module_t { }; @@ -329,6 +337,36 @@ struct wasmer_wasi_map_dir_entry_t { extern "C" { +#if defined(WASMER_WASI_ENABLED) +/// Non-standard function to get the imports needed for the WASI +/// implementation with no particular order. Each import has its +/// associated module name and name, so that it can be re-order later +/// based on the `wasm_module_t` requirements. +/// +/// This function takes ownership of `wasm_env_t`. +bool wasi_get_unordered_imports(const wasm_store_t *store, + const wasm_module_t *module, + const wasi_env_t *wasi_env, + wasm_named_extern_vec_t *imports); +#endif + +#if defined(WASMER_WASI_ENABLED) +/// Non-standard function to get the wrapped extern of a +/// `wasm_named_extern_t`. +const wasm_extern_t *wasm_named_extern_extern(const wasm_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +/// Non-standard function to get the module name of a +/// `wasm_named_extern_t`. +const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +/// Non-standard function to get the name of a `wasm_named_extern_t`. +const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); +#endif + /// Creates a new Module from the given wasm bytes. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index a53fddbae39..1bbffe372d0 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -134,6 +134,10 @@ typedef struct wasi_config_t wasi_config_t; typedef struct wasi_env_t wasi_env_t; #endif +#if defined(WASMER_WASI_ENABLED) +typedef struct wasm_named_extern_t wasm_named_extern_t; +#endif + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -217,6 +221,13 @@ bool wasi_get_imports(const wasm_store_t *store, wasm_func_t *wasi_get_start_function(wasm_instance_t *instance); #endif +#if defined(WASMER_WASI_ENABLED) +bool wasi_get_unordered_imports(const wasm_store_t *store, + const wasm_module_t *module, + const wasi_env_t *wasi_env, + wasm_named_extern_vec_t *imports); +#endif + #if defined(WASMER_WASI_ENABLED) wasi_version_t wasi_get_wasi_version(const wasm_module_t *module); #endif @@ -231,6 +242,18 @@ void wasm_module_name(const wasm_module_t *module, wasm_name_t *out); bool wasm_module_set_name(wasm_module_t *module, const wasm_name_t *name); +#if defined(WASMER_WASI_ENABLED) +const wasm_extern_t *wasm_named_extern_extern(const wasm_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); +#endif + +#if defined(WASMER_WASI_ENABLED) +const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); +#endif + int wasmer_last_error_length(void); int wasmer_last_error_message(char *buffer, int length); From ffd07bcfd7cff71d51cfed859bc0cb159bdec160 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 25 Jan 2021 15:49:31 +0100 Subject: [PATCH 04/25] feat(c-api) Expand macros of the crate when generating C bindings. --- lib/c-api/build.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/c-api/build.rs b/lib/c-api/build.rs index 8212c3bfb37..a13df440517 100644 --- a/lib/c-api/build.rs +++ b/lib/c-api/build.rs @@ -61,6 +61,10 @@ macro_rules! map_feature_as_c_define { } fn main() { + if ::std::env::var("_CBINDGEN_IS_RUNNING").is_ok() { + return; + } + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap(); @@ -285,6 +289,12 @@ fn new_builder(language: Language, crate_dir: &str, include_guard: &str, header: .with_include_guard(include_guard) .with_header(header) .with_documentation(false) + .with_parse_expand(&[env::var("CARGO_PKG_NAME").unwrap()]) + .with_parse_expand_features(if env::var("CARGO_FEATURE_SYSTEM_LIBFFI").is_ok() { + &["system-libffi"] + } else { + &[] + }) .with_define("target_family", "windows", "_WIN32") .with_define("target_arch", "x86_64", "ARCH_X86_64") .with_define("feature", "jit", JIT_FEATURE_AS_C_DEFINE) From 8b29156d2de238493c232f42b83082acd1ec9b7c Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 25 Jan 2021 15:58:16 +0100 Subject: [PATCH 05/25] fixup --- lib/c-api/build.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/c-api/build.rs b/lib/c-api/build.rs index a13df440517..1e4630fcf4e 100644 --- a/lib/c-api/build.rs +++ b/lib/c-api/build.rs @@ -61,7 +61,7 @@ macro_rules! map_feature_as_c_define { } fn main() { - if ::std::env::var("_CBINDGEN_IS_RUNNING").is_ok() { + if env::var("_CBINDGEN_IS_RUNNING").is_ok() { return; } @@ -278,7 +278,7 @@ fn add_wasmer_version(pre_header: &mut String) { /// Create a fresh new `Builder`, already pre-configured. fn new_builder(language: Language, crate_dir: &str, include_guard: &str, header: &str) -> Builder { - Builder::new() + let builder = Builder::new() .with_config(cbindgen::Config { sort_by: cbindgen::SortKey::Name, cpp_compat: true, @@ -290,17 +290,17 @@ fn new_builder(language: Language, crate_dir: &str, include_guard: &str, header: .with_header(header) .with_documentation(false) .with_parse_expand(&[env::var("CARGO_PKG_NAME").unwrap()]) - .with_parse_expand_features(if env::var("CARGO_FEATURE_SYSTEM_LIBFFI").is_ok() { - &["system-libffi"] - } else { - &[] - }) .with_define("target_family", "windows", "_WIN32") .with_define("target_arch", "x86_64", "ARCH_X86_64") .with_define("feature", "jit", JIT_FEATURE_AS_C_DEFINE) .with_define("feature", "compiler", COMPILER_FEATURE_AS_C_DEFINE) .with_define("feature", "wasi", WASI_FEATURE_AS_C_DEFINE) - .with_define("feature", "emscripten", EMSCRIPTEN_FEATURE_AS_C_DEFINE) + .with_define("feature", "emscripten", EMSCRIPTEN_FEATURE_AS_C_DEFINE); + + #[cfg(feature = "system-libffi")] + let builder = builder.with_parse_expand_features(&["system-libffi"]); + + builder } /// Exclude types and functions from the `deprecated` API. From 5de7d71e848430017c88ec0aa43398a563f42080 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 25 Jan 2021 15:59:48 +0100 Subject: [PATCH 06/25] chore(c-api) Update headers. --- lib/c-api/wasmer_wasm.h | 86 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index 1bbffe372d0..53e1009eb39 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -154,6 +154,20 @@ void wasi_config_capture_stderr(wasi_config_t *config); void wasi_config_capture_stdout(wasi_config_t *config); #endif +/** + *Represents a vector of `wasm_named_extern_t`. + * + *Read the documentation of [`wasm_named_extern_t`] to see more concrete examples. + */ +typedef struct { + uintptr_t size; + wasm_named_extern_t **data; +} wasm_named_extern_vec_t; + +#if defined(WASMER_WASI_ENABLED) +void wasi_config_arg(wasi_config_t *config, const char *arg); +#endif + #if defined(WASMER_WASI_ENABLED) void wasi_config_env(wasi_config_t *config, const char *key, const char *value); #endif @@ -254,6 +268,78 @@ const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_ext const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); #endif +<<<<<<< HEAD +======= +#if defined(WASMER_WASI_ENABLED) +/** + *Performs a deep copy of a vector of [`wasm_named_extern_t`]. + */ +void wasm_named_extern_vec_copy(wasm_named_extern_vec_t *out_ptr, + const wasm_named_extern_vec_t *in_ptr); +#endif + +#if defined(WASMER_WASI_ENABLED) +/** + *Deletes a vector of [`wasm_named_extern_t`]. + * + *# Example + * + *See the [`wasm_named_extern_vec_t`] type to get an example. + */ +void wasm_named_extern_vec_delete(wasm_named_extern_vec_t *ptr); +#endif + +#if defined(WASMER_WASI_ENABLED) +/** + *Creates a new vector of [`wasm_named_extern_t`]. + */ +void wasm_named_extern_vec_new(wasm_named_extern_vec_t *out, + uintptr_t length, + wasm_named_extern_t *const *init); +#endif + +#if defined(WASMER_WASI_ENABLED) +/** + *Creates an empty vector of [`wasm_named_extern_t`]. + * + *# Example + * + *```rust # use inline_c::assert_c; # fn main() { # (assert_c! { # #include "tests/wasmer_wasm.h" # int main() { // Creates an empty vector of `wasm_named_extern_t`. wasm_named_extern_vec_t vector; wasm_named_extern_vec_new_empty(&vector); + * + * // Check that it is empty. assert(vector.size == 0); + * + * // Free it. wasm_named_extern_vec_delete(&vector); } # }) # .success(); # } ``` + */ +void wasm_named_extern_vec_new_empty(wasm_named_extern_vec_t *out); +#endif + +#if defined(WASMER_WASI_ENABLED) +/** + *Creates a new uninitialized vector of [`wasm_named_extern_t`]. + * + *# Example + * + *```rust # use inline_c::assert_c; # fn main() { # (assert_c! { # #include "tests/wasmer_wasm.h" # int main() { // Creates an empty vector of `wasm_named_extern_t`. wasm_named_extern_vec_t vector; wasm_named_extern_vec_new_uninitialized(&vector, 3); + * + * // Check that it contains 3 items. assert(vector.size == 3); + * + * // Free it. wasm_named_extern_vec_delete(&vector); } # }) # .success(); # } ``` + */ +void wasm_named_extern_vec_new_uninitialized(wasm_named_extern_vec_t *out, + uintptr_t length); +#endif + +/** + * Gets the length in bytes of the last error if any, zero otherwise. + * + * This can be used to dynamically allocate a buffer with the correct number of + * bytes needed to store a message. + * + * # Example + * + * See this module's documentation to get a complete example. + */ +>>>>>>> 75989d7f0 (chore(c-api) Update headers.) int wasmer_last_error_length(void); int wasmer_last_error_message(char *buffer, int length); From 5abac74618c8a04734a143f6f1a45d77a12af460 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 26 Jan 2021 10:51:05 +0100 Subject: [PATCH 07/25] feat(c-api) Rename `wasm_named_extern_extern` to `wasm_named_extern_unwrap`. --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 9a50b61d840..7a83ecc150d 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -372,7 +372,7 @@ pub extern "C" fn wasm_named_extern_name(named_extern: &wasm_named_extern_t) -> /// Non-standard function to get the wrapped extern of a /// `wasm_named_extern_t`. #[no_mangle] -pub extern "C" fn wasm_named_extern_extern(named_extern: &wasm_named_extern_t) -> &wasm_extern_t { +pub extern "C" fn wasm_named_extern_unwrap(named_extern: &wasm_named_extern_t) -> &wasm_extern_t { named_extern.r#extern.as_ref() } From 79b5d5c032bcc139cff203181bf40d26ca9aa5cb Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 26 Jan 2021 10:51:45 +0100 Subject: [PATCH 08/25] chore(c-api) Exclude more functions from Wasm C API for the Wasmer C API. --- lib/c-api/build.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/c-api/build.rs b/lib/c-api/build.rs index 1e4630fcf4e..a5731e44aa1 100644 --- a/lib/c-api/build.rs +++ b/lib/c-api/build.rs @@ -468,14 +468,23 @@ fn exclude_items_from_wasm_c_api(builder: Builder) -> Builder { .exclude_item("wasi_env_set_memory") .exclude_item("wasi_env_t") .exclude_item("wasi_get_imports") - .exclude_item("wasi_get_imports_inner") .exclude_item("wasi_get_start_function") + .exclude_item("wasi_get_unordered_imports") .exclude_item("wasi_get_wasi_version") .exclude_item("wasi_version_t") .exclude_item("wasm_config_set_compiler") .exclude_item("wasm_config_set_engine") .exclude_item("wasm_module_name") .exclude_item("wasm_module_set_name") + .exclude_item("wasm_named_extern_module") + .exclude_item("wasm_named_extern_name") + .exclude_item("wasm_named_extern_t") + .exclude_item("wasm_named_extern_unwrap") + .exclude_item("wasm_named_extern_vec_copy") + .exclude_item("wasm_named_extern_vec_delete") + .exclude_item("wasm_named_extern_vec_new") + .exclude_item("wasm_named_extern_vec_new_empty") + .exclude_item("wasm_named_extern_vec_new_uninitialized") .exclude_item("wasmer_compiler_t") .exclude_item("wasmer_engine_t") .exclude_item("wat2wasm") From 18761cad7dfb4d5d839d5ae2f189644f87337bb7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 26 Jan 2021 10:57:42 +0100 Subject: [PATCH 09/25] feat(c-api) Implement `wasm_extern_copy`. This patch also moves `wasm_extern_delete` into the correct Rust module. --- lib/c-api/src/wasm_c_api/externals/mod.rs | 78 +++++++++++++++++++++++ lib/c-api/src/wasm_c_api/wasi/mod.rs | 6 -- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index 05fc8043543..ab7088ab70a 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -20,6 +20,84 @@ pub struct wasm_extern_t { wasm_declare_boxed_vec!(extern); +/// Copy a `wasm_extern_t`. +/// +/// # Example +/// +/// ```rust +/// # use inline_c::assert_c; +/// # fn main() { +/// # (assert_c! { +/// # #include "tests/wasmer_wasm.h" +/// # +/// int main() { +/// // Create the engine and the store. +/// wasm_engine_t* engine = wasm_engine_new(); +/// wasm_store_t* store = wasm_store_new(engine); +/// +/// // Create a WebAssembly module from a WAT definition. +/// wasm_byte_vec_t wat; +/// wasmer_byte_vec_new_from_string( +/// &wat, +/// "(module\n" +/// " (func (export \"function\")))" +/// ); +/// wasm_byte_vec_t wasm; +/// wat2wasm(&wat, &wasm); +/// +/// // Create the module. +/// wasm_module_t* module = wasm_module_new(store, &wasm); +/// +/// // Instantiate the module. +/// wasm_extern_vec_t imports = WASM_EMPTY_VEC; +/// wasm_trap_t* traps = NULL; +/// +/// wasm_instance_t* instance = wasm_instance_new(store, module, &imports, &traps); +/// assert(instance); +/// +/// // Read the exports. +/// wasm_extern_vec_t exports; +/// wasm_instance_exports(instance, &exports); +/// +/// // We have 1 of them. +/// assert(exports.size == 1); +/// +/// // It is a function. +/// wasm_extern_t* function = exports.data[0]; +/// assert(wasm_extern_kind(function) == WASM_EXTERN_FUNC); +/// +/// // Let's copy the function. +/// wasm_extern_t* function_copy = wasm_extern_copy(function); +/// assert(wasm_extern_kind(function_copy) == WASM_EXTERN_FUNC); +/// +/// // Free everything. +/// wasm_extern_delete(function_copy); +/// wasm_instance_delete(instance); +/// wasm_module_delete(module); +/// wasm_byte_vec_delete(&wasm); +/// wasm_byte_vec_delete(&wat); +/// wasm_store_delete(store); +/// wasm_engine_delete(engine); +/// +/// return 0; +/// } +/// # }) +/// # .success(); +/// # } +/// ``` +#[no_mangle] +pub unsafe extern "C" fn wasm_extern_copy(r#extern: &wasm_extern_t) -> Box { + Box::new(r#extern.clone()) +} + +/// Delete an extern. +/// +/// # Example +/// +/// See `wasm_extern_copy`. +#[no_mangle] +pub unsafe extern "C" fn wasm_extern_delete(_extern: Option>) {} + #[no_mangle] pub unsafe extern "C" fn wasm_func_as_extern( func: Option<&wasm_func_t>, diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 7a83ecc150d..c844c3b19f3 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -524,12 +524,6 @@ pub unsafe extern "C" fn wasi_get_start_function( })) } -/// Delete a `wasm_extern_t` allocated by the API. -/// -/// cbindgen:ignore -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_delete(_item: Option>) {} - #[cfg(test)] mod tests { use inline_c::assert_c; From 1042dad5ebbbac994ea9a5311cdfbb103647a659 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 26 Jan 2021 10:59:05 +0100 Subject: [PATCH 10/25] chore(c-api) Update headers. --- lib/c-api/wasmer_wasm.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index 53e1009eb39..83ad74f3f1c 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -257,19 +257,28 @@ void wasm_module_name(const wasm_module_t *module, wasm_name_t *out); bool wasm_module_set_name(wasm_module_t *module, const wasm_name_t *name); #if defined(WASMER_WASI_ENABLED) -const wasm_extern_t *wasm_named_extern_extern(const wasm_named_extern_t *named_extern); +/** + * Non-standard function to get the module name of a + * `wasm_named_extern_t`. + */ +const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); #endif #if defined(WASMER_WASI_ENABLED) -const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); +/** + * Non-standard function to get the name of a `wasm_named_extern_t`. + */ +const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); #endif #if defined(WASMER_WASI_ENABLED) -const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); +/** + * Non-standard function to get the wrapped extern of a + * `wasm_named_extern_t`. + */ +const wasm_extern_t *wasm_named_extern_unwrap(const wasm_named_extern_t *named_extern); #endif -<<<<<<< HEAD -======= #if defined(WASMER_WASI_ENABLED) /** *Performs a deep copy of a vector of [`wasm_named_extern_t`]. @@ -339,7 +348,6 @@ void wasm_named_extern_vec_new_uninitialized(wasm_named_extern_vec_t *out, * * See this module's documentation to get a complete example. */ ->>>>>>> 75989d7f0 (chore(c-api) Update headers.) int wasmer_last_error_length(void); int wasmer_last_error_message(char *buffer, int length); From 5fc3e9fbca7131695440b0d88676c8878271e77e Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 26 Jan 2021 11:00:36 +0100 Subject: [PATCH 11/25] chore(c-api) Update headers. --- lib/c-api/wasmer.h | 153 +++++--------------------------------------- lib/c-api/wasmer.hh | 123 +++++------------------------------ 2 files changed, 32 insertions(+), 244 deletions(-) diff --git a/lib/c-api/wasmer.h b/lib/c-api/wasmer.h index b97902c3cef..7c77122932f 100644 --- a/lib/c-api/wasmer.h +++ b/lib/c-api/wasmer.h @@ -166,56 +166,22 @@ enum wasmer_value_tag typedef uint32_t wasmer_value_tag; #endif // __cplusplus -#if defined(WASMER_WASI_ENABLED) -/** - * Non-standard type wrapping `wasm_extern_t` with the addition of - * two `wasm_name_t` respectively for the module name and the name of - * the extern (very likely to be an import). This non-standard type - * is used by the non-standard `wasi_get_unordered_imports` function. - */ -typedef struct wasm_named_extern_t wasm_named_extern_t; -#endif - typedef struct { } wasmer_module_t; /** - * Opaque pointer to an Instance type plus metadata. - * - * This type 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. + * Opaque pointer to `NamedExportDescriptor`. */ typedef struct { -} wasmer_instance_t; +} wasmer_export_descriptor_t; typedef struct { const uint8_t *bytes; uint32_t bytes_len; } wasmer_byte_array; -#if defined(WASMER_EMSCRIPTEN_ENABLED) -/** - * Type used to construct an import_object_t with Emscripten imports. - */ -typedef struct { - -} wasmer_emscripten_globals_t; -#endif - -typedef struct { - -} wasmer_import_object_t; - -/** - * Opaque pointer to `NamedExportDescriptor`. - */ -typedef struct { - -} wasmer_export_descriptor_t; - /** * Opaque pointer to `NamedExportDescriptors`. */ @@ -331,6 +297,10 @@ typedef struct { typedef struct { +} wasmer_import_object_t; + +typedef struct { + } wasmer_table_t; /** @@ -354,6 +324,17 @@ typedef struct { } wasmer_import_object_iter_t; +/** + * Opaque pointer to an Instance type plus metadata. + * + * This type 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. + */ +typedef struct { + +} wasmer_instance_t; + /** * Opaque pointer to a `wasmer_vm::Ctx` value in Rust. * @@ -437,48 +418,6 @@ typedef struct { } wasmer_wasi_map_dir_entry_t; #endif -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#if defined(WASMER_WASI_ENABLED) -/** - * Non-standard function to get the imports needed for the WASI - * implementation with no particular order. Each import has its - * associated module name and name, so that it can be re-order later - * based on the `wasm_module_t` requirements. - * - * This function takes ownership of `wasm_env_t`. - */ -bool wasi_get_unordered_imports(const wasm_store_t *store, - const wasm_module_t *module, - const wasi_env_t *wasi_env, - wasm_named_extern_vec_t *imports); -#endif - -#if defined(WASMER_WASI_ENABLED) -/** - * Non-standard function to get the wrapped extern of a - * `wasm_named_extern_t`. - */ -const wasm_extern_t *wasm_named_extern_extern(const wasm_named_extern_t *named_extern); -#endif - -#if defined(WASMER_WASI_ENABLED) -/** - * Non-standard function to get the module name of a - * `wasm_named_extern_t`. - */ -const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); -#endif - -#if defined(WASMER_WASI_ENABLED) -/** - * Non-standard function to get the name of a `wasm_named_extern_t`. - */ -const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); -#endif - /** * Creates a new Module from the given wasm bytes. * @@ -491,64 +430,6 @@ 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 */ diff --git a/lib/c-api/wasmer.hh b/lib/c-api/wasmer.hh index a8e6a907f91..d2e5985c91e 100644 --- a/lib/c-api/wasmer.hh +++ b/lib/c-api/wasmer.hh @@ -112,24 +112,12 @@ enum class wasmer_value_tag : uint32_t { WASM_F64, }; -#if defined(WASMER_WASI_ENABLED) -/// Non-standard type wrapping `wasm_extern_t` with the addition of -/// two `wasm_name_t` respectively for the module name and the name of -/// the extern (very likely to be an import). This non-standard type -/// is used by the non-standard `wasi_get_unordered_imports` function. -struct wasm_named_extern_t; -#endif - struct wasmer_module_t { }; -/// Opaque pointer to an Instance type plus metadata. -/// -/// This type 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 { +/// Opaque pointer to `NamedExportDescriptor`. +struct wasmer_export_descriptor_t { }; @@ -138,22 +126,6 @@ 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 { @@ -249,6 +221,10 @@ struct wasmer_import_func_t { }; +struct wasmer_import_object_t { + +}; + struct wasmer_table_t { }; @@ -272,6 +248,15 @@ struct wasmer_import_object_iter_t { }; +/// Opaque pointer to an Instance type plus metadata. +/// +/// This type 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 { + +}; + /// Opaque pointer to a `wasmer_vm::Ctx` value in Rust. /// /// An instance context is passed to any host function (aka imported @@ -337,36 +322,6 @@ struct wasmer_wasi_map_dir_entry_t { extern "C" { -#if defined(WASMER_WASI_ENABLED) -/// Non-standard function to get the imports needed for the WASI -/// implementation with no particular order. Each import has its -/// associated module name and name, so that it can be re-order later -/// based on the `wasm_module_t` requirements. -/// -/// This function takes ownership of `wasm_env_t`. -bool wasi_get_unordered_imports(const wasm_store_t *store, - const wasm_module_t *module, - const wasi_env_t *wasi_env, - wasm_named_extern_vec_t *imports); -#endif - -#if defined(WASMER_WASI_ENABLED) -/// Non-standard function to get the wrapped extern of a -/// `wasm_named_extern_t`. -const wasm_extern_t *wasm_named_extern_extern(const wasm_named_extern_t *named_extern); -#endif - -#if defined(WASMER_WASI_ENABLED) -/// Non-standard function to get the module name of a -/// `wasm_named_extern_t`. -const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); -#endif - -#if defined(WASMER_WASI_ENABLED) -/// Non-standard function to get the name of a `wasm_named_extern_t`. -const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); -#endif - /// Creates a new Module from the given wasm bytes. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. @@ -377,54 +332,6 @@ 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_); From 83c69a562380b990f0ac8132e3792640ed85d464 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 28 Jan 2021 14:01:47 +0100 Subject: [PATCH 12/25] feat(c-api) Implement `From` for `wasm_name_t`. --- lib/c-api/src/wasm_c_api/types/export.rs | 19 +++-------- lib/c-api/src/wasm_c_api/types/import.rs | 32 +++--------------- lib/c-api/src/wasm_c_api/types/mod.rs | 13 ++++++++ lib/c-api/src/wasm_c_api/wasi/mod.rs | 42 +++++------------------- 4 files changed, 30 insertions(+), 76 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/types/export.rs b/lib/c-api/src/wasm_c_api/types/export.rs index 1654de8193e..9c70d04736b 100644 --- a/lib/c-api/src/wasm_c_api/types/export.rs +++ b/lib/c-api/src/wasm_c_api/types/export.rs @@ -42,21 +42,12 @@ impl From for wasm_exporttype_t { impl From<&ExportType> for wasm_exporttype_t { fn from(other: &ExportType) -> Self { - let name = { - let mut heap_str: Box = other.name().to_string().into_boxed_str(); - let char_ptr = heap_str.as_mut_ptr(); - let str_len = heap_str.bytes().len(); - let name_inner = wasm_name_t { - size: str_len, - data: char_ptr, - }; - Box::leak(heap_str); - - Box::new(name_inner) - }; - + let name = other.name().to_string().into(); let extern_type = Box::new(other.ty().into()); - wasm_exporttype_t { name, extern_type } + wasm_exporttype_t { + name: Box::new(name), + extern_type, + } } } diff --git a/lib/c-api/src/wasm_c_api/types/import.rs b/lib/c-api/src/wasm_c_api/types/import.rs index 4b253e074fe..a8b215836ea 100644 --- a/lib/c-api/src/wasm_c_api/types/import.rs +++ b/lib/c-api/src/wasm_c_api/types/import.rs @@ -50,37 +50,13 @@ impl From for wasm_importtype_t { impl From<&ImportType> for wasm_importtype_t { fn from(other: &ImportType) -> Self { - let module = { - let mut heap_str: Box = other.module().to_string().into_boxed_str(); - let char_ptr = heap_str.as_mut_ptr(); - let str_len = heap_str.bytes().len(); - let module_inner = wasm_name_t { - size: str_len, - data: char_ptr, - }; - Box::leak(heap_str); - - Box::new(module_inner) - }; - - let name = { - let mut heap_str: Box = other.name().to_string().into_boxed_str(); - let char_ptr = heap_str.as_mut_ptr(); - let str_len = heap_str.bytes().len(); - let name_inner = wasm_name_t { - size: str_len, - data: char_ptr, - }; - Box::leak(heap_str); - - Box::new(name_inner) - }; - + let module = other.module().to_string().into(); + let name = other.name().to_string().into(); let extern_type = Box::new(other.ty().into()); wasm_importtype_t { - module, - name, + module: Box::new(module), + name: Box::new(name), extern_type, } } diff --git a/lib/c-api/src/wasm_c_api/types/mod.rs b/lib/c-api/src/wasm_c_api/types/mod.rs index c518bce80a5..5f692b7c87e 100644 --- a/lib/c-api/src/wasm_c_api/types/mod.rs +++ b/lib/c-api/src/wasm_c_api/types/mod.rs @@ -28,6 +28,19 @@ wasm_declare_vec!(byte); #[allow(non_camel_case_types)] pub type wasm_name_t = wasm_byte_vec_t; +impl From for wasm_name_t { + fn from(string: String) -> Self { + let mut boxed_str: Box = string.into_boxed_str(); + let data = boxed_str.as_mut_ptr(); + let size = boxed_str.bytes().len(); + let wasm_byte = Self { data, size }; + + Box::leak(boxed_str); + + wasm_byte + } +} + // opaque type over `ExternRef`? #[allow(non_camel_case_types)] pub struct wasm_ref_t; diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index c844c3b19f3..8e286ca2d18 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -411,43 +411,17 @@ unsafe fn wasi_get_unordered_imports_inner( *imports = import_object .into_iter() .map(|((module, name), export)| { - let module = { - let mut module: Box = module.into_boxed_str(); - let module_ptr = module.as_mut_ptr(); - let module_len = module.bytes().len(); - let module_inner = wasm_name_t { - size: module_len, - data: module_ptr, - }; - - Box::leak(module); - - Box::new(module_inner) - }; - let name = { - let mut name: Box = name.into_boxed_str(); - let name_ptr = name.as_mut_ptr(); - let name_len = name.bytes().len(); - let name_inner = wasm_name_t { - size: name_len, - data: name_ptr, - }; - - Box::leak(name); - - Box::new(name_inner) - }; - + let module = module.into(); + let name = name.into(); let extern_inner = Extern::from_vm_export(store, export); - let r#extern = Box::new(wasm_extern_t { - instance: None, - inner: extern_inner, - }); Box::new(wasm_named_extern_t { - module, - name, - r#extern, + module: Box::new(module), + name: Box::new(name), + r#extern: Box::new(wasm_extern_t { + instance: None, + inner: extern_inner, + }), }) }) .collect::>() From e379fd79fb9f0ccbc890d26c13122a2ae79321c7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 28 Jan 2021 14:07:54 +0100 Subject: [PATCH 13/25] chore(c-api) Merge `_CBINDGEN_IS_RUNNING` with `DOCS_RS`. --- lib/c-api/build.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/c-api/build.rs b/lib/c-api/build.rs index a5731e44aa1..81730af83df 100644 --- a/lib/c-api/build.rs +++ b/lib/c-api/build.rs @@ -61,27 +61,21 @@ macro_rules! map_feature_as_c_define { } fn main() { - if env::var("_CBINDGEN_IS_RUNNING").is_ok() { + if !running_self() { return; } let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap(); - if building_c_api_headers() { - build_wasm_c_api_headers(&crate_dir, &out_dir); - build_wasmer_c_api_headers(&crate_dir, &out_dir); - } - + build_wasm_c_api_headers(&crate_dir, &out_dir); + build_wasmer_c_api_headers(&crate_dir, &out_dir); build_inline_c_env_vars(); } -/// Check whether we should build the C API headers. -/// -/// For the moment, it's always enabled, unless if the `DOCS_RS` -/// environment variable is present. -fn building_c_api_headers() -> bool { - env::var("DOCS_RS").is_err() +/// Check whether we should build the C API headers or set `inline-c` up. +fn running_self() -> bool { + env::var("DOCS_RS").is_err() && env::var("_CBINDGEN_IS_RUNNING").is_err() } /// Build the header files for the `wasm_c_api` API. From 37aee2d7ad32e22b437cc0f3f92d8a6321ce9303 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 28 Jan 2021 14:11:08 +0100 Subject: [PATCH 14/25] chore(c-api) Simplify code. --- lib/c-api/src/wasm_c_api/types/export.rs | 7 ++----- lib/c-api/src/wasm_c_api/types/import.rs | 8 ++++---- lib/c-api/src/wasm_c_api/types/mod.rs | 4 ++-- lib/c-api/src/wasm_c_api/wasi/mod.rs | 8 ++++---- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/types/export.rs b/lib/c-api/src/wasm_c_api/types/export.rs index 9c70d04736b..205566d5eee 100644 --- a/lib/c-api/src/wasm_c_api/types/export.rs +++ b/lib/c-api/src/wasm_c_api/types/export.rs @@ -42,12 +42,9 @@ impl From for wasm_exporttype_t { impl From<&ExportType> for wasm_exporttype_t { fn from(other: &ExportType) -> Self { - let name = other.name().to_string().into(); + let name = Box::new(other.name().to_string().into()); let extern_type = Box::new(other.ty().into()); - wasm_exporttype_t { - name: Box::new(name), - extern_type, - } + wasm_exporttype_t { name, extern_type } } } diff --git a/lib/c-api/src/wasm_c_api/types/import.rs b/lib/c-api/src/wasm_c_api/types/import.rs index a8b215836ea..13a56c46d17 100644 --- a/lib/c-api/src/wasm_c_api/types/import.rs +++ b/lib/c-api/src/wasm_c_api/types/import.rs @@ -50,13 +50,13 @@ impl From for wasm_importtype_t { impl From<&ImportType> for wasm_importtype_t { fn from(other: &ImportType) -> Self { - let module = other.module().to_string().into(); - let name = other.name().to_string().into(); + let module = Box::new(other.module().to_string().into()); + let name = Box::new(other.name().to_string().into()); let extern_type = Box::new(other.ty().into()); wasm_importtype_t { - module: Box::new(module), - name: Box::new(name), + module, + name, extern_type, } } diff --git a/lib/c-api/src/wasm_c_api/types/mod.rs b/lib/c-api/src/wasm_c_api/types/mod.rs index 5f692b7c87e..c022ba17ef1 100644 --- a/lib/c-api/src/wasm_c_api/types/mod.rs +++ b/lib/c-api/src/wasm_c_api/types/mod.rs @@ -33,11 +33,11 @@ impl From for wasm_name_t { let mut boxed_str: Box = string.into_boxed_str(); let data = boxed_str.as_mut_ptr(); let size = boxed_str.bytes().len(); - let wasm_byte = Self { data, size }; + let wasm_name = Self { data, size }; Box::leak(boxed_str); - wasm_byte + wasm_name } } diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 8e286ca2d18..a7d4ed1b832 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -411,13 +411,13 @@ unsafe fn wasi_get_unordered_imports_inner( *imports = import_object .into_iter() .map(|((module, name), export)| { - let module = module.into(); - let name = name.into(); + let module = Box::new(module.into()); + let name = Box::new(name.into()); let extern_inner = Extern::from_vm_export(store, export); Box::new(wasm_named_extern_t { - module: Box::new(module), - name: Box::new(name), + module, + name, r#extern: Box::new(wasm_extern_t { instance: None, inner: extern_inner, From b640a8ca62e309edb0ef8d94c71c9e5c7f10cf42 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 28 Jan 2021 14:14:34 +0100 Subject: [PATCH 15/25] doc(changelog) Add #2053. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26083c934ba..f9de445eaff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ## **[Unreleased]** ### Added +- [#2053](https://github.com/wasmerio/wasmer/pull/2053) Implement the non-standard `wasi_get_unordered_imports` function in the C API. - [#2059](https://github.com/wasmerio/wasmer/pull/2059) Ability to capture `stdout` and `stderr` with WASI in the C API. - [#2040](https://github.com/wasmerio/wasmer/pull/2040) Add `InstanceHandle::vmoffsets` to expose the offsets of the `vmctx` region. - [#2026](https://github.com/wasmerio/wasmer/pull/2010) Expose trap code of a `RuntimeError`, if it's a `Trap`. From 0861b739746e247d8c492473dad013221615f4c9 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 1 Feb 2021 12:04:10 +0100 Subject: [PATCH 16/25] Fix rebase. --- lib/c-api/wasmer.h | 4 ++ lib/c-api/wasmer_wasm.h | 84 +++++------------------------------------ 2 files changed, 14 insertions(+), 74 deletions(-) diff --git a/lib/c-api/wasmer.h b/lib/c-api/wasmer.h index 7c77122932f..f5b0dcb4fd4 100644 --- a/lib/c-api/wasmer.h +++ b/lib/c-api/wasmer.h @@ -418,6 +418,10 @@ typedef struct { } wasmer_wasi_map_dir_entry_t; #endif +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + /** * Creates a new Module from the given wasm bytes. * diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index 83ad74f3f1c..b4a6dd4a19a 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -138,6 +138,13 @@ typedef struct wasi_env_t wasi_env_t; typedef struct wasm_named_extern_t wasm_named_extern_t; #endif +#if defined(WASMER_WASI_ENABLED) +typedef struct { + uintptr_t size; + wasm_named_extern_t **data; +} wasm_named_extern_vec_t; +#endif + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -154,20 +161,6 @@ void wasi_config_capture_stderr(wasi_config_t *config); void wasi_config_capture_stdout(wasi_config_t *config); #endif -/** - *Represents a vector of `wasm_named_extern_t`. - * - *Read the documentation of [`wasm_named_extern_t`] to see more concrete examples. - */ -typedef struct { - uintptr_t size; - wasm_named_extern_t **data; -} wasm_named_extern_vec_t; - -#if defined(WASMER_WASI_ENABLED) -void wasi_config_arg(wasi_config_t *config, const char *arg); -#endif - #if defined(WASMER_WASI_ENABLED) void wasi_config_env(wasi_config_t *config, const char *key, const char *value); #endif @@ -257,97 +250,40 @@ void wasm_module_name(const wasm_module_t *module, wasm_name_t *out); bool wasm_module_set_name(wasm_module_t *module, const wasm_name_t *name); #if defined(WASMER_WASI_ENABLED) -/** - * Non-standard function to get the module name of a - * `wasm_named_extern_t`. - */ const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); #endif #if defined(WASMER_WASI_ENABLED) -/** - * Non-standard function to get the name of a `wasm_named_extern_t`. - */ const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern); #endif #if defined(WASMER_WASI_ENABLED) -/** - * Non-standard function to get the wrapped extern of a - * `wasm_named_extern_t`. - */ const wasm_extern_t *wasm_named_extern_unwrap(const wasm_named_extern_t *named_extern); #endif #if defined(WASMER_WASI_ENABLED) -/** - *Performs a deep copy of a vector of [`wasm_named_extern_t`]. - */ void wasm_named_extern_vec_copy(wasm_named_extern_vec_t *out_ptr, const wasm_named_extern_vec_t *in_ptr); #endif #if defined(WASMER_WASI_ENABLED) -/** - *Deletes a vector of [`wasm_named_extern_t`]. - * - *# Example - * - *See the [`wasm_named_extern_vec_t`] type to get an example. - */ void wasm_named_extern_vec_delete(wasm_named_extern_vec_t *ptr); #endif #if defined(WASMER_WASI_ENABLED) -/** - *Creates a new vector of [`wasm_named_extern_t`]. - */ void wasm_named_extern_vec_new(wasm_named_extern_vec_t *out, uintptr_t length, wasm_named_extern_t *const *init); #endif #if defined(WASMER_WASI_ENABLED) -/** - *Creates an empty vector of [`wasm_named_extern_t`]. - * - *# Example - * - *```rust # use inline_c::assert_c; # fn main() { # (assert_c! { # #include "tests/wasmer_wasm.h" # int main() { // Creates an empty vector of `wasm_named_extern_t`. wasm_named_extern_vec_t vector; wasm_named_extern_vec_new_empty(&vector); - * - * // Check that it is empty. assert(vector.size == 0); - * - * // Free it. wasm_named_extern_vec_delete(&vector); } # }) # .success(); # } ``` - */ void wasm_named_extern_vec_new_empty(wasm_named_extern_vec_t *out); #endif #if defined(WASMER_WASI_ENABLED) -/** - *Creates a new uninitialized vector of [`wasm_named_extern_t`]. - * - *# Example - * - *```rust # use inline_c::assert_c; # fn main() { # (assert_c! { # #include "tests/wasmer_wasm.h" # int main() { // Creates an empty vector of `wasm_named_extern_t`. wasm_named_extern_vec_t vector; wasm_named_extern_vec_new_uninitialized(&vector, 3); - * - * // Check that it contains 3 items. assert(vector.size == 3); - * - * // Free it. wasm_named_extern_vec_delete(&vector); } # }) # .success(); # } ``` - */ -void wasm_named_extern_vec_new_uninitialized(wasm_named_extern_vec_t *out, - uintptr_t length); -#endif - -/** - * Gets the length in bytes of the last error if any, zero otherwise. - * - * This can be used to dynamically allocate a buffer with the correct number of - * bytes needed to store a message. - * - * # Example - * - * See this module's documentation to get a complete example. - */ +void wasm_named_extern_vec_new_uninitialized(wasm_named_extern_vec_t *out, uintptr_t length); +#endif + int wasmer_last_error_length(void); int wasmer_last_error_message(char *buffer, int length); From bbbbe53602b4453e624376e0bd036a9d39b62760 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 1 Feb 2021 13:38:51 +0100 Subject: [PATCH 17/25] test(c-api) Move a doctest into a test. --- lib/c-api/src/wasm_c_api/externals/mod.rs | 116 +++++++++++----------- 1 file changed, 57 insertions(+), 59 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index ab7088ab70a..8870417bb0b 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -25,65 +25,6 @@ wasm_declare_boxed_vec!(extern); /// # Example /// /// ```rust -/// # use inline_c::assert_c; -/// # fn main() { -/// # (assert_c! { -/// # #include "tests/wasmer_wasm.h" -/// # -/// int main() { -/// // Create the engine and the store. -/// wasm_engine_t* engine = wasm_engine_new(); -/// wasm_store_t* store = wasm_store_new(engine); -/// -/// // Create a WebAssembly module from a WAT definition. -/// wasm_byte_vec_t wat; -/// wasmer_byte_vec_new_from_string( -/// &wat, -/// "(module\n" -/// " (func (export \"function\")))" -/// ); -/// wasm_byte_vec_t wasm; -/// wat2wasm(&wat, &wasm); -/// -/// // Create the module. -/// wasm_module_t* module = wasm_module_new(store, &wasm); -/// -/// // Instantiate the module. -/// wasm_extern_vec_t imports = WASM_EMPTY_VEC; -/// wasm_trap_t* traps = NULL; -/// -/// wasm_instance_t* instance = wasm_instance_new(store, module, &imports, &traps); -/// assert(instance); -/// -/// // Read the exports. -/// wasm_extern_vec_t exports; -/// wasm_instance_exports(instance, &exports); -/// -/// // We have 1 of them. -/// assert(exports.size == 1); -/// -/// // It is a function. -/// wasm_extern_t* function = exports.data[0]; -/// assert(wasm_extern_kind(function) == WASM_EXTERN_FUNC); -/// -/// // Let's copy the function. -/// wasm_extern_t* function_copy = wasm_extern_copy(function); -/// assert(wasm_extern_kind(function_copy) == WASM_EXTERN_FUNC); -/// -/// // Free everything. -/// wasm_extern_delete(function_copy); -/// wasm_instance_delete(instance); -/// wasm_module_delete(module); -/// wasm_byte_vec_delete(&wasm); -/// wasm_byte_vec_delete(&wat); -/// wasm_store_delete(store); -/// wasm_engine_delete(engine); -/// -/// return 0; -/// } -/// # }) -/// # .success(); -/// # } /// ``` #[no_mangle] pub unsafe extern "C" fn wasm_extern_copy(r#extern: &wasm_extern_t) -> Box { @@ -203,3 +144,60 @@ pub unsafe extern "C" fn wasm_extern_as_table( None } } + +#[cfg(test)] +mod tests { + use inline_c::assert_c; + + #[test] + fn test_extern_copy() { + (assert_c! { + #include "tests/wasmer_wasm.h" + + int main() { + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + wasm_byte_vec_t wat; + wasmer_byte_vec_new_from_string( + &wat, + "(module\n" + " (func (export \"function\")))" + ); + wasm_byte_vec_t wasm; + wat2wasm(&wat, &wasm); + + wasm_module_t* module = wasm_module_new(store, &wasm); + assert(module); + + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + wasm_trap_t* traps = NULL; + + wasm_instance_t* instance = wasm_instance_new(store, module, &imports, &traps); + assert(instance); + + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + + assert(exports.size == 1); + + wasm_extern_t* function = exports.data[0]; + assert(wasm_extern_kind(function) == WASM_EXTERN_FUNC); + + wasm_extern_t* function_copy = wasm_extern_copy(function); + assert(wasm_extern_kind(function_copy) == WASM_EXTERN_FUNC); + + wasm_extern_delete(function_copy); + wasm_instance_delete(instance); + wasm_module_delete(module); + wasm_byte_vec_delete(&wasm); + wasm_byte_vec_delete(&wat); + wasm_store_delete(store); + wasm_engine_delete(engine); + + return 0; + } + }) + .success(); + } +} From b1dc0416dd4fd554345aa70a9adf2abe42f778c8 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 1 Feb 2021 13:42:06 +0100 Subject: [PATCH 18/25] chore(c-api) Make type explicit for the sake of simplicity. --- lib/c-api/src/wasm_c_api/types/export.rs | 4 ++-- lib/c-api/src/wasm_c_api/types/import.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/types/export.rs b/lib/c-api/src/wasm_c_api/types/export.rs index 205566d5eee..6a78805cb77 100644 --- a/lib/c-api/src/wasm_c_api/types/export.rs +++ b/lib/c-api/src/wasm_c_api/types/export.rs @@ -42,8 +42,8 @@ impl From for wasm_exporttype_t { impl From<&ExportType> for wasm_exporttype_t { fn from(other: &ExportType) -> Self { - let name = Box::new(other.name().to_string().into()); - let extern_type = Box::new(other.ty().into()); + let name: Box = Box::new(other.name().to_string().into()); + let extern_type: Box = Box::new(other.ty().into()); wasm_exporttype_t { name, extern_type } } diff --git a/lib/c-api/src/wasm_c_api/types/import.rs b/lib/c-api/src/wasm_c_api/types/import.rs index 13a56c46d17..9d060584dd3 100644 --- a/lib/c-api/src/wasm_c_api/types/import.rs +++ b/lib/c-api/src/wasm_c_api/types/import.rs @@ -50,9 +50,9 @@ impl From for wasm_importtype_t { impl From<&ImportType> for wasm_importtype_t { fn from(other: &ImportType) -> Self { - let module = Box::new(other.module().to_string().into()); - let name = Box::new(other.name().to_string().into()); - let extern_type = Box::new(other.ty().into()); + let module: Box = Box::new(other.module().to_string().into()); + let name: Box = Box::new(other.name().to_string().into()); + let extern_type: Box = Box::new(other.ty().into()); wasm_importtype_t { module, From 9e63ba9a256ac141c73c4e1156bcec878dfdbe6d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 1 Feb 2021 14:55:45 +0100 Subject: [PATCH 19/25] fix(c-api) Fix memory leak and owernship in WASI. In `wasi_get_imports` and `wasi_get_unordered_imports`, we said the ownership of `wasi_env_t` was taken by the function, but it wasn't the case. This patch changes the type from `&wasi_env_t` to `Box` to take ownership of it. The rest of the patch updates the documentation, and improves null protections with `Option`. --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 68 +++++++++++++++++++--------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index a7d4ed1b832..31f1120ca3a 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -171,7 +171,9 @@ pub struct wasi_env_t { inner: WasiEnv, } -/// Takes ownership over the `wasi_config_t`. +/// Create a new WASI environment. +/// +/// It take ownership over the `wasi_config_t`. #[no_mangle] pub extern "C" fn wasi_env_new(mut config: Box) -> Option> { if !config.inherit_stdout { @@ -195,6 +197,7 @@ pub extern "C" fn wasi_env_new(mut config: Box) -> Option>) {} @@ -346,6 +349,8 @@ pub unsafe extern "C" fn wasi_get_wasi_version(module: &wasm_module_t) -> wasi_v /// two `wasm_name_t` respectively for the module name and the name of /// the extern (very likely to be an import). This non-standard type /// is used by the non-standard `wasi_get_unordered_imports` function. +/// +/// The `module`, `name` and `extern` fields are all owned by this type. #[allow(non_camel_case_types)] #[derive(Clone)] pub struct wasm_named_extern_t { @@ -358,22 +363,34 @@ wasm_declare_boxed_vec!(named_extern); /// Non-standard function to get the module name of a /// `wasm_named_extern_t`. +/// +/// The returned value isn't owned by the caller. #[no_mangle] -pub extern "C" fn wasm_named_extern_module(named_extern: &wasm_named_extern_t) -> &wasm_name_t { - named_extern.module.as_ref() +pub extern "C" fn wasm_named_extern_module( + named_extern: Option<&wasm_named_extern_t>, +) -> Option<&wasm_name_t> { + Some(named_extern?.module.as_ref()) } /// Non-standard function to get the name of a `wasm_named_extern_t`. +/// +/// The returned value isn't owned by the caller. #[no_mangle] -pub extern "C" fn wasm_named_extern_name(named_extern: &wasm_named_extern_t) -> &wasm_name_t { - named_extern.name.as_ref() +pub extern "C" fn wasm_named_extern_name( + named_extern: Option<&wasm_named_extern_t>, +) -> Option<&wasm_name_t> { + Some(named_extern?.name.as_ref()) } /// Non-standard function to get the wrapped extern of a /// `wasm_named_extern_t`. +/// +/// The returned value isn't owned by the caller. #[no_mangle] -pub extern "C" fn wasm_named_extern_unwrap(named_extern: &wasm_named_extern_t) -> &wasm_extern_t { - named_extern.r#extern.as_ref() +pub extern "C" fn wasm_named_extern_unwrap( + named_extern: Option<&wasm_named_extern_t>, +) -> Option<&wasm_extern_t> { + Some(named_extern?.r#extern.as_ref()) } /// Non-standard function to get the imports needed for the WASI @@ -384,20 +401,24 @@ pub extern "C" fn wasm_named_extern_unwrap(named_extern: &wasm_named_extern_t) - /// This function takes ownership of `wasm_env_t`. #[no_mangle] pub unsafe extern "C" fn wasi_get_unordered_imports( - store: &wasm_store_t, - module: &wasm_module_t, - wasi_env: &wasi_env_t, + store: Option<&wasm_store_t>, + module: Option<&wasm_module_t>, + wasi_env: Option>, imports: &mut wasm_named_extern_vec_t, ) -> bool { wasi_get_unordered_imports_inner(store, module, wasi_env, imports).is_some() } unsafe fn wasi_get_unordered_imports_inner( - store: &wasm_store_t, - module: &wasm_module_t, - wasi_env: &wasi_env_t, + store: Option<&wasm_store_t>, + module: Option<&wasm_module_t>, + wasi_env: Option>, imports: &mut wasm_named_extern_vec_t, ) -> Option<()> { + let store = store?; + let module = module?; + let wasi_env = wasi_env?; + let store = &store.inner; let version = c_try!( @@ -436,9 +457,9 @@ unsafe fn wasi_get_unordered_imports_inner( /// This function takes ownership of `wasm_env_t`. #[no_mangle] pub unsafe extern "C" fn wasi_get_imports( - store: &wasm_store_t, - module: &wasm_module_t, - wasi_env: &wasi_env_t, + store: Option<&wasm_store_t>, + module: Option<&wasm_module_t>, + wasi_env: Option>, imports: &mut wasm_extern_vec_t, ) -> bool { wasi_get_imports_inner(store, module, wasi_env, imports).is_some() @@ -446,11 +467,15 @@ pub unsafe extern "C" fn wasi_get_imports( /// Takes ownership of `wasi_env_t`. unsafe fn wasi_get_imports_inner( - store: &wasm_store_t, - module: &wasm_module_t, - wasi_env: &wasi_env_t, + store: Option<&wasm_store_t>, + module: Option<&wasm_module_t>, + wasi_env: Option>, imports: &mut wasm_extern_vec_t, ) -> Option<()> { + let store = store?; + let module = module?; + let wasi_env = wasi_env?; + let store = &store.inner; let version = c_try!( @@ -491,9 +516,10 @@ unsafe fn wasi_get_imports_inner( pub unsafe extern "C" fn wasi_get_start_function( instance: &mut wasm_instance_t, ) -> Option> { - let f = c_try!(instance.inner.exports.get_function("_start")); + let start = c_try!(instance.inner.exports.get_function("_start")); + Some(Box::new(wasm_func_t { - inner: f.clone(), + inner: start.clone(), instance: Some(instance.inner.clone()), })) } From 8ab82cf589b562f116701c9195ed38908b81390e Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 1 Feb 2021 14:58:42 +0100 Subject: [PATCH 20/25] doc(c-api) Fix documentation. --- lib/c-api/src/wasm_c_api/externals/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index 8870417bb0b..952d644a710 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -21,11 +21,6 @@ pub struct wasm_extern_t { wasm_declare_boxed_vec!(extern); /// Copy a `wasm_extern_t`. -/// -/// # Example -/// -/// ```rust -/// ``` #[no_mangle] pub unsafe extern "C" fn wasm_extern_copy(r#extern: &wasm_extern_t) -> Box { Box::new(r#extern.clone()) From d48bc1e67e72f1b16e4257e3dc60003605e0f45b Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 1 Feb 2021 14:58:54 +0100 Subject: [PATCH 21/25] chore(c-api) Update headers. --- lib/c-api/wasmer_wasm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index b4a6dd4a19a..ba819b8e930 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -220,7 +220,7 @@ void wasi_env_set_memory(wasi_env_t *_env, #if defined(WASMER_WASI_ENABLED) bool wasi_get_imports(const wasm_store_t *store, const wasm_module_t *module, - const wasi_env_t *wasi_env, + wasi_env_t *wasi_env, wasm_extern_vec_t *imports); #endif @@ -231,7 +231,7 @@ wasm_func_t *wasi_get_start_function(wasm_instance_t *instance); #if defined(WASMER_WASI_ENABLED) bool wasi_get_unordered_imports(const wasm_store_t *store, const wasm_module_t *module, - const wasi_env_t *wasi_env, + wasi_env_t *wasi_env, wasm_named_extern_vec_t *imports); #endif From 9a835a4fdca1f09803055e203ddbd8ed76e8d197 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 1 Feb 2021 15:00:13 +0100 Subject: [PATCH 22/25] doc(c-api) Remove incorrect link. --- lib/c-api/src/wasm_c_api/externals/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index 952d644a710..23dff955ef1 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -27,10 +27,6 @@ pub unsafe extern "C" fn wasm_extern_copy(r#extern: &wasm_extern_t) -> Box>) {} From 98bff43f351e56353f9be76269c3403c02e51479 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 1 Feb 2021 15:49:53 +0100 Subject: [PATCH 23/25] chore(c-api) Remove useless `unsafe` keywords. --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 31f1120ca3a..deadbd043e5 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -409,7 +409,7 @@ pub unsafe extern "C" fn wasi_get_unordered_imports( wasi_get_unordered_imports_inner(store, module, wasi_env, imports).is_some() } -unsafe fn wasi_get_unordered_imports_inner( +fn wasi_get_unordered_imports_inner( store: Option<&wasm_store_t>, module: Option<&wasm_module_t>, wasi_env: Option>, @@ -466,7 +466,7 @@ pub unsafe extern "C" fn wasi_get_imports( } /// Takes ownership of `wasi_env_t`. -unsafe fn wasi_get_imports_inner( +fn wasi_get_imports_inner( store: Option<&wasm_store_t>, module: Option<&wasm_module_t>, wasi_env: Option>, From 995a2d4779982d6192cac5aa84314eadefff25ee Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 2 Feb 2021 12:05:47 +0100 Subject: [PATCH 24/25] feat(c-api) No longer expand with `cbindgen`: drop dependency to Rust nightly. So. Let's explain a dirty hack. `cbindgen` reads the code and collects symbols. What symbols do we need? None of the one declared in `wasm.h`, but for non-standard API, we need to collect all of them. The problem is that `wasm_named_extern_t` is the only non-standard type where extra symbols are generated by a macro (`wasm_declare_boxed_vec!`). If we want those macro-generated symbols to be collected by `cbindgen`, we need to _expand_ the crate (i.e. running something like `rustc -- -Zunstable-options --pretty=expanded`). Expanding code is unstable and available only on nightly compiler. We _don't want_ to use a nightly compiler only for that. So how can we help `cbindgen` to _see_ those symbols? First solution: We write the C code directly in a file, which is then included in the generated header file with the `cbindgen` API. Problem, it's super easy to get it outdated, and it makes the build process more complex. Second solution: We write those symbols in a custom module, that is just here for `cbindgen`, never used by our Rust code (otherwise it's duplicated code), with no particular implementation. And that's why we have the following `cbindgen_hack` module. But this module must not be compiled by `rustc`. How to force `rustc` to ignore a module? With conditional compilation. Because `cbindgen` does not support conditional compilation, it will always _ignore_ the `#[cfg]` attribute, and will always read the content of the module. Sorry. --- lib/c-api/build.rs | 1 - lib/c-api/src/wasm_c_api/macros.rs | 2 +- lib/c-api/src/wasm_c_api/wasi/mod.rs | 82 ++++++++++++++++++++++ lib/c-api/wasmer.h | 101 ++++++++++++++++++++++----- lib/c-api/wasmer.hh | 85 ++++++++++++++++++---- 5 files changed, 237 insertions(+), 34 deletions(-) diff --git a/lib/c-api/build.rs b/lib/c-api/build.rs index 81730af83df..764cf99d0d3 100644 --- a/lib/c-api/build.rs +++ b/lib/c-api/build.rs @@ -283,7 +283,6 @@ fn new_builder(language: Language, crate_dir: &str, include_guard: &str, header: .with_include_guard(include_guard) .with_header(header) .with_documentation(false) - .with_parse_expand(&[env::var("CARGO_PKG_NAME").unwrap()]) .with_define("target_family", "windows", "_WIN32") .with_define("target_arch", "x86_64", "ARCH_X86_64") .with_define("feature", "jit", JIT_FEATURE_AS_C_DEFINE) diff --git a/lib/c-api/src/wasm_c_api/macros.rs b/lib/c-api/src/wasm_c_api/macros.rs index c1e8955e036..c1306637658 100644 --- a/lib/c-api/src/wasm_c_api/macros.rs +++ b/lib/c-api/src/wasm_c_api/macros.rs @@ -403,7 +403,7 @@ int main() { #[no_mangle] pub unsafe extern "C" fn []( out_ptr: &mut [], - in_ptr: & []) + in_ptr: & []) { *out_ptr = in_ptr.clone(); } diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index deadbd043e5..8d9fd0f71ab 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -361,6 +361,88 @@ pub struct wasm_named_extern_t { wasm_declare_boxed_vec!(named_extern); +/// So. Let's explain a dirty hack. `cbindgen` reads the code and +/// collects symbols. What symbols do we need? None of the one +/// declared in `wasm.h`, but for non-standard API, we need to collect +/// all of them. The problem is that `wasm_named_extern_t` is the only +/// non-standard type where extra symbols are generated by a macro +/// (`wasm_declare_boxed_vec!`). If we want those macro-generated +/// symbols to be collected by `cbindgen`, we need to _expand_ the +/// crate (i.e. running something like `rustc -- -Zunstable-options +/// --pretty=expanded`). Expanding code is unstable and available only +/// on nightly compiler. We _don't want_ to use a nightly compiler +/// only for that. So how can we help `cbindgen` to _see_ those +/// symbols? +/// +/// First solution: We write the C code directly in a file, which is +/// then included in the generated header file with the `cbindgen` +/// API. Problem, it's super easy to get it outdated, and it makes the +/// build process more complex. +/// +/// Second solution: We write those symbols in a custom module, that +/// is just here for `cbindgen`, never used by our Rust code +/// (otherwise it's duplicated code), with no particular +/// implementation. +/// +/// And that's why we have the following `cbindgen_hack` +/// module. +/// +/// But this module must not be compiled by `rustc`. How to force +/// `rustc` to ignore a module? With conditional compilation. Because +/// `cbindgen` does not support conditional compilation, it will +/// always _ignore_ the `#[cfg]` attribute, and will always read the +/// content of the module. +/// +/// Sorry. +#[doc(hidden)] +#[cfg(__cbindgen_hack__ = "yes")] +mod __cbindgen_hack__ { + use super::*; + + #[repr(C)] + pub struct wasm_named_extern_vec_t { + pub size: usize, + pub data: *mut *mut wasm_named_extern_t, + } + + #[no_mangle] + pub unsafe extern "C" fn wasm_named_extern_vec_new( + out: *mut wasm_named_extern_vec_t, + length: usize, + init: *const *mut wasm_named_extern_t, + ) { + unimplemented!() + } + + #[no_mangle] + pub unsafe extern "C" fn wasm_named_extern_vec_new_uninitialized( + out: *mut wasm_named_extern_vec_t, + length: usize, + ) { + unimplemented!() + } + + #[no_mangle] + pub unsafe extern "C" fn wasm_named_extern_vec_copy( + out_ptr: &mut wasm_named_extern_vec_t, + in_ptr: &wasm_named_extern_vec_t, + ) { + unimplemented!() + } + + #[no_mangle] + pub unsafe extern "C" fn wasm_named_extern_vec_delete( + ptr: Option<&mut wasm_named_extern_vec_t>, + ) { + unimplemented!() + } + + #[no_mangle] + pub unsafe extern "C" fn wasm_named_extern_vec_new_empty(out: *mut wasm_named_extern_vec_t) { + unimplemented!() + } +} + /// Non-standard function to get the module name of a /// `wasm_named_extern_t`. /// diff --git a/lib/c-api/wasmer.h b/lib/c-api/wasmer.h index f5b0dcb4fd4..43bb8e87e9f 100644 --- a/lib/c-api/wasmer.h +++ b/lib/c-api/wasmer.h @@ -171,17 +171,41 @@ typedef struct { } wasmer_module_t; /** - * Opaque pointer to `NamedExportDescriptor`. + * Opaque pointer to an Instance type plus metadata. + * + * This type 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. */ typedef struct { -} wasmer_export_descriptor_t; +} wasmer_instance_t; typedef struct { const uint8_t *bytes; uint32_t bytes_len; } wasmer_byte_array; +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/** + * Type used to construct an import_object_t with Emscripten imports. + */ +typedef struct { + +} wasmer_emscripten_globals_t; +#endif + +typedef struct { + +} wasmer_import_object_t; + +/** + * Opaque pointer to `NamedExportDescriptor`. + */ +typedef struct { + +} wasmer_export_descriptor_t; + /** * Opaque pointer to `NamedExportDescriptors`. */ @@ -297,10 +321,6 @@ typedef struct { typedef struct { -} wasmer_import_object_t; - -typedef struct { - } wasmer_table_t; /** @@ -324,17 +344,6 @@ typedef struct { } wasmer_import_object_iter_t; -/** - * Opaque pointer to an Instance type plus metadata. - * - * This type 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. - */ -typedef struct { - -} wasmer_instance_t; - /** * Opaque pointer to a `wasmer_vm::Ctx` value in Rust. * @@ -434,6 +443,64 @@ 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 */ diff --git a/lib/c-api/wasmer.hh b/lib/c-api/wasmer.hh index d2e5985c91e..33a27385db9 100644 --- a/lib/c-api/wasmer.hh +++ b/lib/c-api/wasmer.hh @@ -116,8 +116,12 @@ struct wasmer_module_t { }; -/// Opaque pointer to `NamedExportDescriptor`. -struct wasmer_export_descriptor_t { +/// Opaque pointer to an Instance type plus metadata. +/// +/// This type 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 { }; @@ -126,6 +130,22 @@ 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 { @@ -221,10 +241,6 @@ struct wasmer_import_func_t { }; -struct wasmer_import_object_t { - -}; - struct wasmer_table_t { }; @@ -248,15 +264,6 @@ struct wasmer_import_object_iter_t { }; -/// Opaque pointer to an Instance type plus metadata. -/// -/// This type 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 { - -}; - /// Opaque pointer to a `wasmer_vm::Ctx` value in Rust. /// /// An instance context is passed to any host function (aka imported @@ -332,6 +339,54 @@ 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_); From 698a26c7fef47aadfe23a3bad8049ee06d6cc081 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 2 Feb 2021 13:42:29 +0100 Subject: [PATCH 25/25] fix(c-api) Restore a bug with `wasi_get_imports`. We said that `wasi_get_imports` was taking ownership of `wasi_env_t`. It wasn't. In 9e63ba9a256ac141c73c4e1156bcec878dfdbe6d, we have fixed this. But it creates another bug when `wasi_env_t` is used _after_ for example when calling `wasi_env_read_stdout`. So this patch reverts the bug fix. And we will discuss about how to fix that later. --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 13 ++++--------- lib/c-api/wasmer_wasm.h | 4 ++-- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index b3f8cda72d2..7ac5bae3ba3 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -479,13 +479,11 @@ pub extern "C" fn wasm_named_extern_unwrap( /// implementation with no particular order. Each import has its /// associated module name and name, so that it can be re-order later /// based on the `wasm_module_t` requirements. -/// -/// This function takes ownership of `wasm_env_t`. #[no_mangle] pub unsafe extern "C" fn wasi_get_unordered_imports( store: Option<&wasm_store_t>, module: Option<&wasm_module_t>, - wasi_env: Option>, + wasi_env: Option<&wasi_env_t>, imports: &mut wasm_named_extern_vec_t, ) -> bool { wasi_get_unordered_imports_inner(store, module, wasi_env, imports).is_some() @@ -494,7 +492,7 @@ pub unsafe extern "C" fn wasi_get_unordered_imports( fn wasi_get_unordered_imports_inner( store: Option<&wasm_store_t>, module: Option<&wasm_module_t>, - wasi_env: Option>, + wasi_env: Option<&wasi_env_t>, imports: &mut wasm_named_extern_vec_t, ) -> Option<()> { let store = store?; @@ -535,23 +533,20 @@ fn wasi_get_unordered_imports_inner( /// Non-standard function to get the imports needed for the WASI /// implementation ordered as expected by the `wasm_module_t`. -/// -/// This function takes ownership of `wasm_env_t`. #[no_mangle] pub unsafe extern "C" fn wasi_get_imports( store: Option<&wasm_store_t>, module: Option<&wasm_module_t>, - wasi_env: Option>, + wasi_env: Option<&wasi_env_t>, imports: &mut wasm_extern_vec_t, ) -> bool { wasi_get_imports_inner(store, module, wasi_env, imports).is_some() } -/// Takes ownership of `wasi_env_t`. fn wasi_get_imports_inner( store: Option<&wasm_store_t>, module: Option<&wasm_module_t>, - wasi_env: Option>, + wasi_env: Option<&wasi_env_t>, imports: &mut wasm_extern_vec_t, ) -> Option<()> { let store = store?; diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index 0b4ed32bf8f..4f991a7c2b7 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -226,7 +226,7 @@ void wasi_env_set_memory(wasi_env_t *_env, #if defined(WASMER_WASI_ENABLED) bool wasi_get_imports(const wasm_store_t *store, const wasm_module_t *module, - wasi_env_t *wasi_env, + const wasi_env_t *wasi_env, wasm_extern_vec_t *imports); #endif @@ -237,7 +237,7 @@ wasm_func_t *wasi_get_start_function(wasm_instance_t *instance); #if defined(WASMER_WASI_ENABLED) bool wasi_get_unordered_imports(const wasm_store_t *store, const wasm_module_t *module, - wasi_env_t *wasi_env, + const wasi_env_t *wasi_env, wasm_named_extern_vec_t *imports); #endif