From 6ef09359b0716257a7c485d3c66aad685c513afb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 27 Mar 2020 09:50:32 -0500 Subject: [PATCH] Refactor and fill out wasmtime's C API (#1415) * Refactor and improve safety of C API This commit is intended to be a relatively large refactoring of the C API which is targeted at improving the safety of our C API definitions. Not all of the APIs have been updated yet but this is intended to be the start. The goal here is to make as many functions safe as we can, expressing inputs/outputs as native Rust types rather than raw pointers wherever possible. For example instead of `*const wasm_foo_t` we'd take `&wasm_foo_t`. Instead of returning `*mut wasm_foo_t` we'd return `Box`. No ABI/API changes are intended from this commit, it's supposed to only change how we define all these functions internally. This commit also additionally implements a few more API bindings for exposed vector types by unifying everything into one macro. Finally, this commit moves many internal caches in the C API to the `OnceCell` type which provides a safe interface for one-time initialization. * Split apart monolithic C API `lib.rs` This commit splits the monolithic `src/lib.rs` in the C API crate into lots of smaller files. The goal here is to make this a bit more readable and digestable. Each module now contains only API bindings for a particular type, roughly organized around the grouping in the wasm.h header file already. A few more extensions were added, such as filling out `*_as_*` conversions with both const and non-const versions. Additionally many APIs were made safer in the same style as the previous commit, generally preferring Rust types rather than raw pointer types. Overall no functional change is intended here, it should be mostly just code movement and minor refactorings! * Make a few wasi C bindings safer Use safe Rust types where we can and touch up a few APIs here and there. * Implement `wasm_*type_as_externtype*` APIs This commit restructures `wasm_externtype_t` to be similar to `wasm_extern_t` so type conversion between the `*_extern_*` variants to the concrete variants are all simple casts. (checked in the case of general to concrete, of course). * Consistently imlpement host info functions in the API This commit adds a small macro crate which is then used to consistently define the various host-info-related functions in the C API. The goal here is to try to mirror what the `wasm.h` header provides to provide a full implementation of the header. --- Cargo.lock | 16 + crates/api/src/lib.rs | 2 +- crates/api/src/ref.rs | 36 +- crates/api/src/types.rs | 24 + crates/c-api/Cargo.toml | 2 + crates/c-api/include/wasmtime.h | 24 +- crates/c-api/macros/Cargo.toml | 13 + crates/c-api/macros/src/lib.rs | 112 ++ crates/c-api/src/config.rs | 119 ++ crates/c-api/src/engine.rs | 25 + crates/c-api/src/ext.rs | 20 +- crates/c-api/src/extern.rs | 90 ++ crates/c-api/src/func.rs | 243 ++++ crates/c-api/src/global.rs | 68 ++ crates/c-api/src/instance.rs | 111 ++ crates/c-api/src/lib.rs | 1882 +----------------------------- crates/c-api/src/linker.rs | 86 ++ crates/c-api/src/memory.rs | 76 ++ crates/c-api/src/module.rs | 71 ++ crates/c-api/src/ref.rs | 64 + crates/c-api/src/store.rs | 18 + crates/c-api/src/table.rs | 120 ++ crates/c-api/src/trap.rs | 80 ++ crates/c-api/src/types.rs | 36 + crates/c-api/src/types/export.rs | 47 + crates/c-api/src/types/extern.rs | 112 ++ crates/c-api/src/types/func.rs | 105 ++ crates/c-api/src/types/global.rs | 98 ++ crates/c-api/src/types/import.rs | 58 + crates/c-api/src/types/memory.rs | 79 ++ crates/c-api/src/types/table.rs | 91 ++ crates/c-api/src/types/val.rs | 53 + crates/c-api/src/val.rs | 99 ++ crates/c-api/src/vec.rs | 221 ++++ crates/c-api/src/wasi.rs | 145 ++- crates/c-api/src/wat2wasm.rs | 31 + 36 files changed, 2503 insertions(+), 1974 deletions(-) create mode 100644 crates/c-api/macros/Cargo.toml create mode 100644 crates/c-api/macros/src/lib.rs create mode 100644 crates/c-api/src/config.rs create mode 100644 crates/c-api/src/engine.rs create mode 100644 crates/c-api/src/extern.rs create mode 100644 crates/c-api/src/func.rs create mode 100644 crates/c-api/src/global.rs create mode 100644 crates/c-api/src/instance.rs create mode 100644 crates/c-api/src/linker.rs create mode 100644 crates/c-api/src/memory.rs create mode 100644 crates/c-api/src/module.rs create mode 100644 crates/c-api/src/ref.rs create mode 100644 crates/c-api/src/store.rs create mode 100644 crates/c-api/src/table.rs create mode 100644 crates/c-api/src/trap.rs create mode 100644 crates/c-api/src/types.rs create mode 100644 crates/c-api/src/types/export.rs create mode 100644 crates/c-api/src/types/extern.rs create mode 100644 crates/c-api/src/types/func.rs create mode 100644 crates/c-api/src/types/global.rs create mode 100644 crates/c-api/src/types/import.rs create mode 100644 crates/c-api/src/types/memory.rs create mode 100644 crates/c-api/src/types/table.rs create mode 100644 crates/c-api/src/types/val.rs create mode 100644 crates/c-api/src/val.rs create mode 100644 crates/c-api/src/vec.rs create mode 100644 crates/c-api/src/wat2wasm.rs diff --git a/Cargo.lock b/Cargo.lock index 48b93f46f5..3034e4a107 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1308,6 +1308,12 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "once_cell" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" + [[package]] name = "opaque-debug" version = "0.2.3" @@ -2295,12 +2301,22 @@ name = "wasmtime-c-api" version = "0.14.0" dependencies = [ "anyhow", + "once_cell", "wasi-common", "wasmtime", + "wasmtime-c-api-macros", "wasmtime-wasi", "wat", ] +[[package]] +name = "wasmtime-c-api-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "wasmtime-cli" version = "0.14.0" diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index b4ff2207f6..0342833269 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -29,7 +29,7 @@ pub use crate::func::*; pub use crate::instance::Instance; pub use crate::linker::*; pub use crate::module::Module; -pub use crate::r#ref::{AnyRef, HostInfo, HostRef}; +pub use crate::r#ref::{AnyRef, HostRef}; pub use crate::runtime::*; pub use crate::trap::Trap; pub use crate::types::*; diff --git a/crates/api/src/ref.rs b/crates/api/src/ref.rs index f5dbd2ee42..2083c183d0 100644 --- a/crates/api/src/ref.rs +++ b/crates/api/src/ref.rs @@ -5,14 +5,10 @@ use std::cell::{self, RefCell}; use std::fmt; use std::rc::{Rc, Weak}; -pub trait HostInfo { - fn finalize(&mut self) {} -} - trait InternalRefBase: Any { fn as_any(&self) -> &dyn Any; - fn host_info(&self) -> Option>>; - fn set_host_info(&self, info: Option>); + fn host_info(&self) -> Option>>; + fn set_host_info(&self, info: Option>); fn ptr_eq(&self, other: &dyn InternalRefBase) -> bool; } @@ -34,15 +30,7 @@ impl InternalRef { struct AnyAndHostInfo { any: Box, - host_info: Option>, -} - -impl Drop for AnyAndHostInfo { - fn drop(&mut self) { - if let Some(info) = &mut self.host_info { - info.finalize(); - } - } + host_info: Option>, } #[derive(Clone)] @@ -100,7 +88,7 @@ impl AnyRef { /// Returns a mutable reference to the host information if available. /// # Panics /// Panics if `AnyRef` is already borrowed or `AnyRef` is `Null`. - pub fn host_info(&self) -> Option>> { + pub fn host_info(&self) -> Option>> { match self { AnyRef::Null => panic!("null"), AnyRef::Ref(r) => r.0.host_info(), @@ -117,7 +105,7 @@ impl AnyRef { /// Sets the host information for an `AnyRef`. /// # Panics /// Panics if `AnyRef` is already borrowed or `AnyRef` is `Null`. - pub fn set_host_info(&self, info: Option>) { + pub fn set_host_info(&self, info: Option>) { match self { AnyRef::Null => panic!("null"), AnyRef::Ref(r) => r.0.set_host_info(info), @@ -140,18 +128,10 @@ impl fmt::Debug for AnyRef { struct ContentBox { content: T, - host_info: Option>, + host_info: Option>, anyref_data: Weak, } -impl Drop for ContentBox { - fn drop(&mut self) { - if let Some(info) = &mut self.host_info { - info.finalize(); - } - } -} - /// Represents a piece of data located in the host environment. pub struct HostRef(Rc>>); @@ -215,7 +195,7 @@ impl InternalRefBase for HostRef { self } - fn host_info(&self) -> Option>> { + fn host_info(&self) -> Option>> { let info = cell::RefMut::map(self.0.borrow_mut(), |b| &mut b.host_info); if info.is_none() { return None; @@ -223,7 +203,7 @@ impl InternalRefBase for HostRef { Some(cell::RefMut::map(info, |info| info.as_mut().unwrap())) } - fn set_host_info(&self, info: Option>) { + fn set_host_info(&self, info: Option>) { self.0.borrow_mut().host_info = info; } } diff --git a/crates/api/src/types.rs b/crates/api/src/types.rs index a1a8d09699..7d39c8047f 100644 --- a/crates/api/src/types.rs +++ b/crates/api/src/types.rs @@ -159,6 +159,30 @@ impl ExternType { } } +impl From for ExternType { + fn from(ty: FuncType) -> ExternType { + ExternType::Func(ty) + } +} + +impl From for ExternType { + fn from(ty: GlobalType) -> ExternType { + ExternType::Global(ty) + } +} + +impl From for ExternType { + fn from(ty: MemoryType) -> ExternType { + ExternType::Memory(ty) + } +} + +impl From for ExternType { + fn from(ty: TableType) -> ExternType { + ExternType::Table(ty) + } +} + // Function Types fn from_wasmtime_abiparam(param: &ir::AbiParam) -> Option { assert_eq!(param.purpose, ir::ArgumentPurpose::Normal); diff --git a/crates/c-api/Cargo.toml b/crates/c-api/Cargo.toml index 4913f985e4..248935db69 100644 --- a/crates/c-api/Cargo.toml +++ b/crates/c-api/Cargo.toml @@ -18,9 +18,11 @@ doctest = false [dependencies] anyhow = "1.0" +once_cell = "1.3" wasmtime = { path = "../api", default-features = false } wasi-common = { path = "../wasi-common" } wasmtime-wasi = { path = "../wasi" } +wasmtime-c-api-macros = { path = "macros" } wat = "1.0" [features] diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index 1600b686fc..3e04349981 100644 --- a/crates/c-api/include/wasmtime.h +++ b/crates/c-api/include/wasmtime.h @@ -32,19 +32,19 @@ enum wasmtime_profiling_strategy_t { // ProfilingStrategy WASMTIME_PROFILING_STRATEGY_JITDUMP, }; -#define WASMTIME_CONFIG_PROP(name, ty) \ - WASM_API_EXTERN void wasmtime_config_##name##_set(wasm_config_t*, ty); +#define WASMTIME_CONFIG_PROP(ret, name, ty) \ + WASM_API_EXTERN ret wasmtime_config_##name##_set(wasm_config_t*, ty); -WASMTIME_CONFIG_PROP(debug_info, bool) -WASMTIME_CONFIG_PROP(wasm_threads, bool) -WASMTIME_CONFIG_PROP(wasm_reference_types, bool) -WASMTIME_CONFIG_PROP(wasm_simd, bool) -WASMTIME_CONFIG_PROP(wasm_bulk_memory, bool) -WASMTIME_CONFIG_PROP(wasm_multi_value, bool) -WASMTIME_CONFIG_PROP(strategy, wasmtime_strategy_t) -WASMTIME_CONFIG_PROP(cranelift_debug_verifier, bool) -WASMTIME_CONFIG_PROP(cranelift_opt_level, wasmtime_opt_level_t) -WASMTIME_CONFIG_PROP(profiler, wasmtime_profiling_strategy_t) +WASMTIME_CONFIG_PROP(void, debug_info, bool) +WASMTIME_CONFIG_PROP(void, wasm_threads, bool) +WASMTIME_CONFIG_PROP(void, wasm_reference_types, bool) +WASMTIME_CONFIG_PROP(void, wasm_simd, bool) +WASMTIME_CONFIG_PROP(void, wasm_bulk_memory, bool) +WASMTIME_CONFIG_PROP(void, wasm_multi_value, bool) +WASMTIME_CONFIG_PROP(bool, strategy, wasmtime_strategy_t) +WASMTIME_CONFIG_PROP(void, cranelift_debug_verifier, bool) +WASMTIME_CONFIG_PROP(void, cranelift_opt_level, wasmtime_opt_level_t) +WASMTIME_CONFIG_PROP(bool, profiler, wasmtime_profiling_strategy_t) /////////////////////////////////////////////////////////////////////////////// diff --git a/crates/c-api/macros/Cargo.toml b/crates/c-api/macros/Cargo.toml new file mode 100644 index 0000000000..a5f44694b0 --- /dev/null +++ b/crates/c-api/macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "wasmtime-c-api-macros" +version = "0.1.0" +authors = ["The Wasmtime Project Developers"] +edition = "2018" +publish = false + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0" +proc-macro2 = "1.0" diff --git a/crates/c-api/macros/src/lib.rs b/crates/c-api/macros/src/lib.rs new file mode 100644 index 0000000000..91ec702531 --- /dev/null +++ b/crates/c-api/macros/src/lib.rs @@ -0,0 +1,112 @@ +//! A set of convenience macros for our wasmtime-c-api crate. +//! +//! These are intended to mirror the macros in the `wasm.h` header file and +//! largely facilitate the `declare_ref` macro. + +extern crate proc_macro; + +use proc_macro2::{Ident, TokenStream, TokenTree}; +use quote::quote; + +fn extract_ident(input: proc_macro::TokenStream) -> Ident { + let input = TokenStream::from(input); + let i = match input.into_iter().next().unwrap() { + TokenTree::Ident(i) => i, + _ => panic!("expected an ident"), + }; + let name = i.to_string(); + assert!(name.ends_with("_t")); + return i; +} + +#[proc_macro] +pub fn declare_own(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ty = extract_ident(input); + let name = ty.to_string(); + let delete = quote::format_ident!("{}_delete", &name[..name.len() - 2]); + + (quote! { + #[no_mangle] + pub extern fn #delete(_: Box<#ty>) {} + }) + .into() +} + +#[proc_macro] +pub fn declare_ty(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ty = extract_ident(input); + let name = ty.to_string(); + let copy = quote::format_ident!("{}_copy", &name[..name.len() - 2]); + + (quote! { + wasmtime_c_api_macros::declare_own!(#ty); + + #[no_mangle] + pub extern fn #copy(src: &#ty) -> Box<#ty> { + Box::new(src.clone()) + } + }) + .into() +} + +#[proc_macro] +pub fn declare_ref(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ty = extract_ident(input); + let name = ty.to_string(); + let prefix = &name[..name.len() - 2]; + let copy = quote::format_ident!("{}_copy", prefix); + let same = quote::format_ident!("{}_same", prefix); + let get_host_info = quote::format_ident!("{}_get_host_info", prefix); + let set_host_info = quote::format_ident!("{}_set_host_info", prefix); + let set_host_info_final = quote::format_ident!("{}_set_host_info_with_finalizer", prefix); + let as_ref = quote::format_ident!("{}_as_ref", prefix); + let as_ref_const = quote::format_ident!("{}_as_ref_const", prefix); + + (quote! { + wasmtime_c_api_macros::declare_own!(#ty); + + #[no_mangle] + pub extern fn #copy(src: &#ty) -> Box<#ty> { + Box::new(src.clone()) + } + + #[no_mangle] + pub extern fn #same(a: &#ty, b: &#ty) -> bool { + a.anyref().ptr_eq(&b.anyref()) + } + + #[no_mangle] + pub extern fn #get_host_info(a: &#ty) -> *mut std::os::raw::c_void { + crate::r#ref::get_host_info(&a.anyref()) + } + + #[no_mangle] + pub extern fn #set_host_info(a: &#ty, info: *mut std::os::raw::c_void) { + crate::r#ref::set_host_info(&a.anyref(), info, None) + } + + #[no_mangle] + pub extern fn #set_host_info_final( + a: &#ty, + info: *mut std::os::raw::c_void, + finalizer: Option, + ) { + crate::r#ref::set_host_info(&a.anyref(), info, finalizer) + } + + #[no_mangle] + pub extern fn #as_ref(a: &#ty) -> Box { + let r = a.anyref(); + Box::new(crate::wasm_ref_t { r }) + } + + #[no_mangle] + pub extern fn #as_ref_const(a: &#ty) -> Box { + #as_ref(a) + } + + // TODO: implement `wasm_ref_as_#name#` + // TODO: implement `wasm_ref_as_#name#_const` + }) + .into() +} diff --git a/crates/c-api/src/config.rs b/crates/c-api/src/config.rs new file mode 100644 index 0000000000..7e4cebcf88 --- /dev/null +++ b/crates/c-api/src/config.rs @@ -0,0 +1,119 @@ +use wasmtime::{Config, OptLevel, ProfilingStrategy, Strategy}; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_config_t { + pub(crate) config: Config, +} + +wasmtime_c_api_macros::declare_own!(wasm_config_t); + +#[repr(u8)] +#[derive(Clone)] +pub enum wasmtime_strategy_t { + WASMTIME_STRATEGY_AUTO, + WASMTIME_STRATEGY_CRANELIFT, + WASMTIME_STRATEGY_LIGHTBEAM, +} + +#[repr(u8)] +#[derive(Clone)] +pub enum wasmtime_opt_level_t { + WASMTIME_OPT_LEVEL_NONE, + WASMTIME_OPT_LEVEL_SPEED, + WASMTIME_OPT_LEVEL_SPEED_AND_SIZE, +} + +#[repr(u8)] +#[derive(Clone)] +pub enum wasmtime_profiling_strategy_t { + WASMTIME_PROFILING_STRATEGY_NONE, + WASMTIME_PROFILING_STRATEGY_JITDUMP, +} + +#[no_mangle] +pub extern "C" fn wasm_config_new() -> Box { + Box::new(wasm_config_t { + config: Config::default(), + }) +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_debug_info_set(c: &mut wasm_config_t, enable: bool) { + c.config.debug_info(enable); +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_wasm_threads_set(c: &mut wasm_config_t, enable: bool) { + c.config.wasm_threads(enable); +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_wasm_reference_types_set(c: &mut wasm_config_t, enable: bool) { + c.config.wasm_reference_types(enable); +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_wasm_simd_set(c: &mut wasm_config_t, enable: bool) { + c.config.wasm_simd(enable); +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_wasm_bulk_memory_set(c: &mut wasm_config_t, enable: bool) { + c.config.wasm_bulk_memory(enable); +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_wasm_multi_value_set(c: &mut wasm_config_t, enable: bool) { + c.config.wasm_multi_value(enable); +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_strategy_set( + c: &mut wasm_config_t, + strategy: wasmtime_strategy_t, +) -> bool { + use wasmtime_strategy_t::*; + c.config + .strategy(match strategy { + WASMTIME_STRATEGY_AUTO => Strategy::Auto, + WASMTIME_STRATEGY_CRANELIFT => Strategy::Cranelift, + WASMTIME_STRATEGY_LIGHTBEAM => Strategy::Lightbeam, + }) + .is_ok() +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_cranelift_debug_verifier_set( + c: &mut wasm_config_t, + enable: bool, +) { + c.config.cranelift_debug_verifier(enable); +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_cranelift_opt_level_set( + c: &mut wasm_config_t, + opt_level: wasmtime_opt_level_t, +) { + use wasmtime_opt_level_t::*; + c.config.cranelift_opt_level(match opt_level { + WASMTIME_OPT_LEVEL_NONE => OptLevel::None, + WASMTIME_OPT_LEVEL_SPEED => OptLevel::Speed, + WASMTIME_OPT_LEVEL_SPEED_AND_SIZE => OptLevel::SpeedAndSize, + }); +} + +#[no_mangle] +pub extern "C" fn wasmtime_config_profiler_set( + c: &mut wasm_config_t, + strategy: wasmtime_profiling_strategy_t, +) -> bool { + use wasmtime_profiling_strategy_t::*; + c.config + .profiler(match strategy { + WASMTIME_PROFILING_STRATEGY_NONE => ProfilingStrategy::None, + WASMTIME_PROFILING_STRATEGY_JITDUMP => ProfilingStrategy::JitDump, + }) + .is_ok() +} diff --git a/crates/c-api/src/engine.rs b/crates/c-api/src/engine.rs new file mode 100644 index 0000000000..38f0e985db --- /dev/null +++ b/crates/c-api/src/engine.rs @@ -0,0 +1,25 @@ +use crate::wasm_config_t; +use wasmtime::{Engine, HostRef}; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_engine_t { + pub(crate) engine: HostRef, +} + +wasmtime_c_api_macros::declare_own!(wasm_engine_t); + +#[no_mangle] +pub extern "C" fn wasm_engine_new() -> Box { + Box::new(wasm_engine_t { + engine: HostRef::new(Engine::default()), + }) +} + +#[no_mangle] +pub extern "C" fn wasm_engine_new_with_config(c: Box) -> Box { + let config = c.config; + Box::new(wasm_engine_t { + engine: HostRef::new(Engine::new(&config)), + }) +} diff --git a/crates/c-api/src/ext.rs b/crates/c-api/src/ext.rs index dbccc6bc42..9b5a84c3ff 100644 --- a/crates/c-api/src/ext.rs +++ b/crates/c-api/src/ext.rs @@ -108,28 +108,28 @@ pub unsafe extern "C" fn wasmtime_config_profiler_set( } #[no_mangle] -pub unsafe extern "C" fn wasmtime_wat2wasm( - wat: *const wasm_byte_vec_t, - ret: *mut wasm_byte_vec_t, - error: *mut wasm_byte_vec_t, +pub extern "C" fn wasmtime_wat2wasm( + wat: &wasm_byte_vec_t, + ret: &mut wasm_byte_vec_t, + error: Option<&mut wasm_byte_vec_t>, ) -> bool { - let wat = match str::from_utf8((*wat).as_slice()) { + let wat = match str::from_utf8(wat.as_slice()) { Ok(s) => s, Err(_) => { - if !error.is_null() { - (*error).set_from_slice(b"input was not valid utf-8"); + if let Some(error) = error { + error.set_buffer(b"input was not valid utf-8".to_vec()); } return false; } }; match wat::parse_str(wat) { Ok(bytes) => { - (*ret).set_from_slice(&bytes); + ret.set_buffer(bytes.into()); true } Err(e) => { - if !error.is_null() { - (*error).set_from_slice(e.to_string().as_bytes()); + if let Some(error) = error { + error.set_buffer(e.to_string().into_bytes()); } false } diff --git a/crates/c-api/src/extern.rs b/crates/c-api/src/extern.rs new file mode 100644 index 0000000000..e5d6fc6152 --- /dev/null +++ b/crates/c-api/src/extern.rs @@ -0,0 +1,90 @@ +use crate::wasm_externkind_t; +use crate::{wasm_externtype_t, wasm_func_t, wasm_global_t, wasm_memory_t, wasm_table_t}; +use wasmtime::{ExternType, Func, Global, HostRef, Memory, Table}; + +#[derive(Clone)] +pub struct wasm_extern_t { + pub(crate) which: ExternHost, +} + +wasmtime_c_api_macros::declare_ref!(wasm_extern_t); + +#[derive(Clone)] +pub(crate) enum ExternHost { + Func(HostRef), + Global(HostRef), + Memory(HostRef), + Table(HostRef), +} + +impl wasm_extern_t { + fn anyref(&self) -> wasmtime::AnyRef { + match &self.which { + ExternHost::Func(f) => f.anyref(), + ExternHost::Global(f) => f.anyref(), + ExternHost::Memory(f) => f.anyref(), + ExternHost::Table(f) => f.anyref(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t { + match e.which { + ExternHost::Func(_) => crate::WASM_EXTERN_FUNC, + ExternHost::Global(_) => crate::WASM_EXTERN_GLOBAL, + ExternHost::Table(_) => crate::WASM_EXTERN_TABLE, + ExternHost::Memory(_) => crate::WASM_EXTERN_MEMORY, + } +} + +#[no_mangle] +pub extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box { + let ty = match &e.which { + ExternHost::Func(f) => ExternType::Func(f.borrow().ty().clone()), + ExternHost::Global(f) => ExternType::Global(f.borrow().ty().clone()), + ExternHost::Table(f) => ExternType::Table(f.borrow().ty().clone()), + ExternHost::Memory(f) => ExternType::Memory(f.borrow().ty().clone()), + }; + Box::new(wasm_externtype_t::new(ty)) +} + +#[no_mangle] +pub extern "C" fn wasm_extern_as_func(e: &wasm_extern_t) -> Option<&wasm_func_t> { + wasm_func_t::try_from(e) +} + +#[no_mangle] +pub extern "C" fn wasm_extern_as_func_const(e: &wasm_extern_t) -> Option<&wasm_func_t> { + wasm_extern_as_func(e) +} + +#[no_mangle] +pub extern "C" fn wasm_extern_as_global(e: &wasm_extern_t) -> Option<&wasm_global_t> { + wasm_global_t::try_from(e) +} + +#[no_mangle] +pub extern "C" fn wasm_extern_as_global_const(e: &wasm_extern_t) -> Option<&wasm_global_t> { + wasm_extern_as_global(e) +} + +#[no_mangle] +pub extern "C" fn wasm_extern_as_table(e: &wasm_extern_t) -> Option<&wasm_table_t> { + wasm_table_t::try_from(e) +} + +#[no_mangle] +pub extern "C" fn wasm_extern_as_table_const(e: &wasm_extern_t) -> Option<&wasm_table_t> { + wasm_extern_as_table(e) +} + +#[no_mangle] +pub extern "C" fn wasm_extern_as_memory(e: &wasm_extern_t) -> Option<&wasm_memory_t> { + wasm_memory_t::try_from(e) +} + +#[no_mangle] +pub extern "C" fn wasm_extern_as_memory_const(e: &wasm_extern_t) -> Option<&wasm_memory_t> { + wasm_extern_as_memory(e) +} diff --git a/crates/c-api/src/func.rs b/crates/c-api/src/func.rs new file mode 100644 index 0000000000..18582e243a --- /dev/null +++ b/crates/c-api/src/func.rs @@ -0,0 +1,243 @@ +use crate::{wasm_extern_t, wasm_functype_t, wasm_store_t, wasm_val_t}; +use crate::{wasm_name_t, wasm_trap_t, ExternHost}; +use std::ffi::c_void; +use std::panic::{self, AssertUnwindSafe}; +use std::ptr; +use std::str; +use wasmtime::{Caller, Extern, Func, HostRef, Trap}; + +#[derive(Clone)] +#[repr(transparent)] +pub struct wasm_func_t { + ext: wasm_extern_t, +} + +wasmtime_c_api_macros::declare_ref!(wasm_func_t); + +#[repr(C)] +pub struct wasmtime_caller_t<'a> { + caller: Caller<'a>, +} + +pub type wasm_func_callback_t = + extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> Option>; + +pub type wasm_func_callback_with_env_t = extern "C" fn( + env: *mut std::ffi::c_void, + args: *const wasm_val_t, + results: *mut wasm_val_t, +) -> Option>; + +pub type wasmtime_func_callback_t = extern "C" fn( + caller: *const wasmtime_caller_t, + args: *const wasm_val_t, + results: *mut wasm_val_t, +) -> Option>; + +pub type wasmtime_func_callback_with_env_t = extern "C" fn( + caller: *const wasmtime_caller_t, + env: *mut std::ffi::c_void, + args: *const wasm_val_t, + results: *mut wasm_val_t, +) -> Option>; + +struct Finalizer { + env: *mut c_void, + finalizer: Option, +} + +impl Drop for Finalizer { + fn drop(&mut self) { + if let Some(f) = self.finalizer { + f(self.env); + } + } +} + +impl wasm_func_t { + pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_func_t> { + match &e.which { + ExternHost::Func(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } + + fn func(&self) -> &HostRef { + match &self.ext.which { + ExternHost::Func(f) => f, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } + + fn anyref(&self) -> wasmtime::AnyRef { + self.func().anyref() + } +} + +fn create_function( + store: &wasm_store_t, + ty: &wasm_functype_t, + func: impl Fn(Caller<'_>, *const wasm_val_t, *mut wasm_val_t) -> Option> + 'static, +) -> Box { + let store = &store.store.borrow(); + let ty = ty.ty().ty.clone(); + let func = Func::new(store, ty, move |caller, params, results| { + let params = params + .iter() + .map(|p| wasm_val_t::from_val(p)) + .collect::>(); + let mut out_results = vec![wasm_val_t::default(); results.len()]; + let out = func(caller, params.as_ptr(), out_results.as_mut_ptr()); + if let Some(trap) = out { + return Err(trap.trap.borrow().clone()); + } + for i in 0..results.len() { + results[i] = out_results[i].val(); + } + Ok(()) + }); + Box::new(wasm_func_t { + ext: wasm_extern_t { + which: ExternHost::Func(HostRef::new(func)), + }, + }) +} + +#[no_mangle] +pub extern "C" fn wasm_func_new( + store: &wasm_store_t, + ty: &wasm_functype_t, + callback: wasm_func_callback_t, +) -> Box { + create_function(store, ty, move |_caller, params, results| { + callback(params, results) + }) +} + +#[no_mangle] +pub unsafe extern "C" fn wasmtime_func_new( + store: &wasm_store_t, + ty: &wasm_functype_t, + callback: wasmtime_func_callback_t, +) -> Box { + create_function(store, ty, move |caller, params, results| { + callback(&wasmtime_caller_t { caller }, params, results) + }) +} + +#[no_mangle] +pub extern "C" fn wasm_func_new_with_env( + store: &wasm_store_t, + ty: &wasm_functype_t, + callback: wasm_func_callback_with_env_t, + env: *mut c_void, + finalizer: Option, +) -> Box { + let finalizer = Finalizer { env, finalizer }; + create_function(store, ty, move |_caller, params, results| { + callback(finalizer.env, params, results) + }) +} + +#[no_mangle] +pub extern "C" fn wasmtime_func_new_with_env( + store: &wasm_store_t, + ty: &wasm_functype_t, + callback: wasmtime_func_callback_with_env_t, + env: *mut c_void, + finalizer: Option, +) -> Box { + let finalizer = Finalizer { env, finalizer }; + create_function(store, ty, move |caller, params, results| { + callback( + &wasmtime_caller_t { caller }, + finalizer.env, + params, + results, + ) + }) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_func_call( + func: &wasm_func_t, + args: *const wasm_val_t, + results: *mut wasm_val_t, +) -> *mut wasm_trap_t { + let func = func.func().borrow(); + let mut params = Vec::with_capacity(func.param_arity()); + for i in 0..func.param_arity() { + let val = &(*args.add(i)); + params.push(val.val()); + } + + // We're calling arbitrary code here most of the time, and we in general + // want to try to insulate callers against bugs in wasmtime/wasi/etc if we + // can. As a result we catch panics here and transform them to traps to + // allow the caller to have any insulation possible against Rust panics. + let result = panic::catch_unwind(AssertUnwindSafe(|| func.call(¶ms))); + match result { + Ok(Ok(out)) => { + for i in 0..func.result_arity() { + let val = &mut (*results.add(i)); + *val = wasm_val_t::from_val(&out[i]); + } + ptr::null_mut() + } + Ok(Err(trap)) => { + let trap = Box::new(wasm_trap_t { + trap: HostRef::new(trap), + }); + Box::into_raw(trap) + } + Err(panic) => { + let trap = if let Some(msg) = panic.downcast_ref::() { + Trap::new(msg) + } else if let Some(msg) = panic.downcast_ref::<&'static str>() { + Trap::new(*msg) + } else { + Trap::new("rust panic happened") + }; + let trap = Box::new(wasm_trap_t { + trap: HostRef::new(trap), + }); + Box::into_raw(trap) + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_func_type(f: &wasm_func_t) -> Box { + Box::new(wasm_functype_t::new(f.func().borrow().ty().clone())) +} + +#[no_mangle] +pub extern "C" fn wasm_func_param_arity(f: &wasm_func_t) -> usize { + f.func().borrow().param_arity() +} + +#[no_mangle] +pub extern "C" fn wasm_func_result_arity(f: &wasm_func_t) -> usize { + f.func().borrow().result_arity() +} + +#[no_mangle] +pub extern "C" fn wasm_func_as_extern(f: &mut wasm_func_t) -> &mut wasm_extern_t { + &mut (*f).ext +} + +#[no_mangle] +pub unsafe extern "C" fn wasmtime_caller_export_get( + caller: &wasmtime_caller_t, + name: &wasm_name_t, +) -> Option> { + let name = str::from_utf8(name.as_slice()).ok()?; + let export = caller.caller.get_export(name)?; + let which = match export { + Extern::Func(f) => ExternHost::Func(HostRef::new(f.clone())), + Extern::Global(g) => ExternHost::Global(HostRef::new(g.clone())), + Extern::Memory(m) => ExternHost::Memory(HostRef::new(m.clone())), + Extern::Table(t) => ExternHost::Table(HostRef::new(t.clone())), + }; + Some(Box::new(wasm_extern_t { which })) +} diff --git a/crates/c-api/src/global.rs b/crates/c-api/src/global.rs new file mode 100644 index 0000000000..9525ec028b --- /dev/null +++ b/crates/c-api/src/global.rs @@ -0,0 +1,68 @@ +use crate::{wasm_extern_t, wasm_globaltype_t, wasm_store_t, wasm_val_t, ExternHost}; +use wasmtime::{Global, HostRef}; + +#[derive(Clone)] +#[repr(transparent)] +pub struct wasm_global_t { + ext: wasm_extern_t, +} + +wasmtime_c_api_macros::declare_ref!(wasm_global_t); + +impl wasm_global_t { + pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_global_t> { + match &e.which { + ExternHost::Global(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } + + fn global(&self) -> &HostRef { + match &self.ext.which { + ExternHost::Global(g) => g, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } + + fn anyref(&self) -> wasmtime::AnyRef { + self.global().anyref() + } +} + +#[no_mangle] +pub extern "C" fn wasm_global_new( + store: &wasm_store_t, + gt: &wasm_globaltype_t, + val: &wasm_val_t, +) -> Option> { + let global = + HostRef::new(Global::new(&store.store.borrow(), gt.ty().ty.clone(), val.val()).ok()?); + Some(Box::new(wasm_global_t { + ext: wasm_extern_t { + which: ExternHost::Global(global), + }, + })) +} + +#[no_mangle] +pub extern "C" fn wasm_global_as_extern(g: &wasm_global_t) -> &wasm_extern_t { + &g.ext +} + +#[no_mangle] +pub extern "C" fn wasm_global_type(g: &wasm_global_t) -> Box { + let globaltype = g.global().borrow().ty().clone(); + Box::new(wasm_globaltype_t::new(globaltype)) +} + +#[no_mangle] +pub extern "C" fn wasm_global_get(g: &wasm_global_t, out: &mut wasm_val_t) { + out.set(g.global().borrow().get()); +} + +#[no_mangle] +pub extern "C" fn wasm_global_set(g: &wasm_global_t, val: &wasm_val_t) { + let result = g.global().borrow().set(val.val()); + // FIXME(WebAssembly/wasm-c-api#131) should communicate the error here + drop(result); +} diff --git a/crates/c-api/src/instance.rs b/crates/c-api/src/instance.rs new file mode 100644 index 0000000000..ab80fb469e --- /dev/null +++ b/crates/c-api/src/instance.rs @@ -0,0 +1,111 @@ +use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t}; +use crate::{wasm_store_t, ExternHost}; +use anyhow::Result; +use std::cell::RefCell; +use std::ptr; +use wasmtime::{Extern, HostRef, Instance, Store, Trap}; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_instance_t { + pub(crate) instance: HostRef, + exports_cache: RefCell>>, +} + +wasmtime_c_api_macros::declare_ref!(wasm_instance_t); + +impl wasm_instance_t { + fn new(instance: Instance) -> wasm_instance_t { + wasm_instance_t { + instance: HostRef::new(instance), + exports_cache: RefCell::new(None), + } + } + + fn anyref(&self) -> wasmtime::AnyRef { + self.instance.anyref() + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_instance_new( + store: &wasm_store_t, + module: &wasm_module_t, + imports: *const Box, + result: Option<&mut *mut wasm_trap_t>, +) -> Option> { + let mut externs: Vec = Vec::with_capacity((*module).imports.len()); + for i in 0..(*module).imports.len() { + let import = &*imports.add(i); + externs.push(match &import.which { + ExternHost::Func(e) => Extern::Func(e.borrow().clone()), + ExternHost::Table(e) => Extern::Table(e.borrow().clone()), + ExternHost::Global(e) => Extern::Global(e.borrow().clone()), + ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()), + }); + } + let store = &(*store).store.borrow(); + let module = &(*module).module.borrow(); + if !Store::same(&store, module.store()) { + if let Some(result) = result { + let trap = Trap::new("wasm_store_t must match store in wasm_module_t"); + let trap = Box::new(wasm_trap_t { + trap: HostRef::new(trap), + }); + *result = Box::into_raw(trap); + } + return None; + } + handle_instantiate(Instance::new(module, &externs), result) +} + +pub fn handle_instantiate( + instance: Result, + result: Option<&mut *mut wasm_trap_t>, +) -> Option> { + match instance { + Ok(instance) => { + if let Some(result) = result { + *result = ptr::null_mut(); + } + Some(Box::new(wasm_instance_t::new(instance))) + } + Err(trap) => { + if let Some(result) = result { + let trap = match trap.downcast::() { + Ok(trap) => trap, + Err(e) => Trap::new(format!("{:?}", e)), + }; + let trap = Box::new(wasm_trap_t { + trap: HostRef::new(trap), + }); + *result = Box::into_raw(trap); + } + None + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wasm_extern_vec_t) { + let mut cache = instance.exports_cache.borrow_mut(); + let exports = cache.get_or_insert_with(|| { + let instance = &instance.instance.borrow(); + instance + .exports() + .iter() + .map(|e| match e { + Extern::Func(f) => ExternHost::Func(HostRef::new(f.clone())), + Extern::Global(f) => ExternHost::Global(HostRef::new(f.clone())), + Extern::Memory(f) => ExternHost::Memory(HostRef::new(f.clone())), + Extern::Table(f) => ExternHost::Table(HostRef::new(f.clone())), + }) + .collect() + }); + let mut buffer = Vec::with_capacity(exports.len()); + for e in exports { + let ext = Box::new(wasm_extern_t { which: e.clone() }); + buffer.push(Some(ext)); + } + out.set_buffer(buffer); +} diff --git a/crates/c-api/src/lib.rs b/crates/c-api/src/lib.rs index 47be831c4b..cc842cfef9 100644 --- a/crates/c-api/src/lib.rs +++ b/crates/c-api/src/lib.rs @@ -5,1869 +5,65 @@ // TODO complete the C API -use anyhow::Result; -use std::cell::RefCell; -use std::panic::{self, AssertUnwindSafe}; -use std::{mem, ptr, slice}; -use wasmtime::{ - AnyRef, Config, Engine, ExportType, Extern, ExternType, Func, FuncType, Global, GlobalType, - HostInfo, HostRef, ImportType, Instance, Limits, Memory, MemoryType, Module, Store, Table, - TableType, Trap, Val, ValType, -}; - -mod ext; +mod config; +mod engine; +mod r#extern; +mod func; +mod global; +mod instance; +mod linker; +mod memory; +mod module; +mod r#ref; +mod store; +mod table; +mod trap; +mod types; +mod val; +mod vec; mod wasi; +mod wat2wasm; -pub use crate::ext::*; +pub use crate::config::*; +pub use crate::engine::*; +pub use crate::func::*; +pub use crate::global::*; +pub use crate::instance::*; +pub use crate::linker::*; +pub use crate::memory::*; +pub use crate::module::*; +pub use crate::r#extern::*; +pub use crate::r#ref::*; +pub use crate::store::*; +pub use crate::table::*; +pub use crate::trap::*; +pub use crate::types::*; +pub use crate::val::*; +pub use crate::vec::*; pub use crate::wasi::*; +pub use crate::wat2wasm::*; -macro_rules! declare_vec { - ($name:ident, $elem_ty:path) => { - #[repr(C)] - #[derive(Clone)] - pub struct $name { - pub size: usize, - pub data: *mut $elem_ty, - } - - impl $name { - #[allow(dead_code)] - fn set_from_slice(&mut self, source: &[$elem_ty]) { - let mut buffer = Vec::with_capacity(source.len()); - buffer.extend_from_slice(source); - assert_eq!(buffer.len(), buffer.capacity()); - self.size = buffer.len(); - self.data = buffer.as_mut_ptr(); - mem::forget(buffer); - } - - #[allow(dead_code)] - fn set_buffer(&mut self, mut buffer: Vec<$elem_ty>) { - assert_eq!(buffer.len(), buffer.capacity()); - self.size = buffer.len(); - self.data = buffer.as_mut_ptr(); - mem::forget(buffer); - } - - #[allow(dead_code)] - fn set_uninitialized(&mut self, size: usize) { - let mut buffer = vec![Default::default(); size]; - self.size = size; - self.data = buffer.as_mut_ptr(); - mem::forget(buffer); - } - - #[allow(dead_code)] - fn uninitialize(&mut self) { - let _ = unsafe { Vec::from_raw_parts(self.data, self.size, self.size) }; - } - - #[allow(dead_code)] - fn as_slice(&self) -> &[$elem_ty] { - unsafe { slice::from_raw_parts(self.data, self.size) } - } - } - - impl From> for $name { - fn from(mut vec: Vec<$elem_ty>) -> Self { - assert_eq!(vec.len(), vec.capacity()); - let result = $name { - size: vec.len(), - data: vec.as_mut_ptr(), - }; - mem::forget(vec); - result - } - } - - impl Drop for $name { - fn drop(&mut self) { - self.uninitialize(); - } - } - }; - - ($name:ident, *mut $elem_ty:path) => { - #[repr(C)] - #[derive(Clone)] - pub struct $name { - pub size: usize, - pub data: *mut *mut $elem_ty, - } - - impl $name { - #[allow(dead_code)] - fn set_from_slice(&mut self, source: &[*mut $elem_ty]) { - let mut buffer = Vec::with_capacity(source.len()); - buffer.extend_from_slice(source); - assert_eq!(buffer.len(), buffer.capacity()); - self.size = buffer.len(); - self.data = buffer.as_mut_ptr(); - mem::forget(buffer); - } - - #[allow(dead_code)] - fn set_buffer(&mut self, mut buffer: Vec<*mut $elem_ty>) { - assert_eq!(buffer.len(), buffer.capacity()); - self.size = buffer.len(); - self.data = buffer.as_mut_ptr(); - mem::forget(buffer); - } - - #[allow(dead_code)] - fn set_uninitialized(&mut self, size: usize) { - let mut buffer = vec![ptr::null_mut(); size]; - self.size = size; - self.data = buffer.as_mut_ptr(); - mem::forget(buffer); - } - - #[allow(dead_code)] - fn uninitialize(&mut self) { - for element in unsafe { Vec::from_raw_parts(self.data, self.size, self.size) } { - let _ = unsafe { Box::from_raw(element) }; - } - } - - #[allow(dead_code)] - fn as_slice(&self) -> &[*mut $elem_ty] { - unsafe { slice::from_raw_parts(self.data, self.size) } - } - } - - impl From> for $name { - fn from(mut vec: Vec<*mut $elem_ty>) -> Self { - assert_eq!(vec.len(), vec.capacity()); - let result = $name { - size: vec.len(), - data: vec.as_mut_ptr(), - }; - mem::forget(vec); - result - } - } - - impl Drop for $name { - fn drop(&mut self) { - self.uninitialize(); - } - } - }; -} - -pub type float32_t = f32; -pub type float64_t = f64; -pub type wasm_byte_t = u8; - -declare_vec!(wasm_byte_vec_t, wasm_byte_t); - -pub type wasm_name_t = wasm_byte_vec_t; -#[repr(C)] -#[derive(Clone)] -pub struct wasm_config_t { - pub(crate) config: Config, -} -#[repr(C)] -#[derive(Clone)] -pub struct wasm_engine_t { - engine: HostRef, -} -#[repr(C)] -#[derive(Clone)] -pub struct wasm_store_t { - store: HostRef, -} -#[doc = ""] -pub type wasm_mutability_t = u8; -#[repr(C)] -#[derive(Clone)] -pub struct wasm_limits_t { - pub min: u32, - pub max: u32, -} -#[repr(C)] -#[derive(Clone)] -pub struct wasm_valtype_t { - ty: ValType, -} - -declare_vec!(wasm_valtype_vec_t, *mut wasm_valtype_t); - -pub type wasm_valkind_t = u8; -#[repr(C)] -#[derive(Clone)] -pub struct wasm_functype_t { - functype: FuncType, - params_cache: Option, - returns_cache: Option, -} - -declare_vec!(wasm_functype_vec_t, *mut wasm_functype_t); - -#[repr(C)] -#[derive(Clone)] -pub struct wasm_globaltype_t { - globaltype: GlobalType, - content_cache: Option, -} - -declare_vec!(wasm_globaltype_vec_t, *mut wasm_globaltype_t); - -#[repr(C)] -#[derive(Clone)] -pub struct wasm_tabletype_t { - tabletype: TableType, - element_cache: Option, - limits_cache: Option, -} - -declare_vec!(wasm_tabletype_vec_t, *mut wasm_tabletype_t); - -#[repr(C)] -#[derive(Clone)] -pub struct wasm_memorytype_t { - memorytype: MemoryType, - limits_cache: Option, -} - -declare_vec!(wasm_memorytype_vec_t, *mut wasm_memorytype_t); - -#[repr(C)] -#[derive(Clone)] -pub struct wasm_externtype_t { - ty: ExternType, - cache: wasm_externtype_t_type_cache, -} - -#[derive(Clone)] -enum wasm_externtype_t_type_cache { - Empty, - Func(wasm_functype_t), - Global(wasm_globaltype_t), - Memory(wasm_memorytype_t), - Table(wasm_tabletype_t), -} - -declare_vec!(wasm_externtype_vec_t, *mut wasm_externtype_t); - -pub type wasm_externkind_t = u8; - -const WASM_EXTERN_FUNC: wasm_externkind_t = 0; -const WASM_EXTERN_GLOBAL: wasm_externkind_t = 1; -const WASM_EXTERN_TABLE: wasm_externkind_t = 2; -const WASM_EXTERN_MEMORY: wasm_externkind_t = 3; - -#[repr(C)] -#[derive(Clone)] -pub struct wasm_importtype_t { - ty: ImportType, - module_cache: Option, - name_cache: Option, - type_cache: Option, -} - -declare_vec!(wasm_importtype_vec_t, *mut wasm_importtype_t); - -#[repr(C)] -#[derive(Clone)] -pub struct wasm_exporttype_t { - ty: ExportType, - name_cache: Option, - type_cache: Option, -} - -declare_vec!(wasm_exporttype_vec_t, *mut wasm_exporttype_t); - -#[doc = ""] -#[repr(C)] -#[derive(Clone)] -pub struct wasm_ref_t { - r: AnyRef, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct wasm_val_t { - pub kind: wasm_valkind_t, - pub of: wasm_val_t__bindgen_ty_1, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub union wasm_val_t__bindgen_ty_1 { - pub i32: i32, - pub i64: i64, - pub u32: u32, - pub u64: u64, - pub f32: float32_t, - pub f64: float64_t, - pub ref_: *mut wasm_ref_t, - _bindgen_union_align: u64, -} - -impl Default for wasm_val_t { - fn default() -> Self { - wasm_val_t { - kind: 0, - of: wasm_val_t__bindgen_ty_1 { i32: 0 }, - } - } -} - -declare_vec!(wasm_val_vec_t, wasm_val_t); - -#[repr(C)] -#[derive(Clone)] -pub struct wasm_frame_t { - _unused: [u8; 0], -} - -declare_vec!(wasm_frame_vec_t, *mut wasm_frame_t); - -#[repr(C)] -#[derive(Clone)] -pub struct wasm_instance_t { - instance: HostRef, - exports_cache: RefCell>>, -} -pub type wasm_message_t = wasm_name_t; -#[repr(C)] -#[derive(Clone)] -pub struct wasm_trap_t { - trap: HostRef, -} #[repr(C)] #[derive(Clone)] pub struct wasm_foreign_t { _unused: [u8; 0], } -#[repr(C)] -#[derive(Clone)] -pub struct wasm_module_t { - module: HostRef, - imports: Vec, - exports: Vec, -} + #[repr(C)] #[derive(Clone)] pub struct wasm_shared_module_t { _unused: [u8; 0], } -#[derive(Clone)] -#[repr(transparent)] -pub struct wasm_func_t { - ext: wasm_extern_t, -} - -impl wasm_func_t { - fn func(&self) -> &HostRef { - match &self.ext.which { - ExternHost::Func(f) => f, - _ => unsafe { std::hint::unreachable_unchecked() }, - } - } -} - -pub type wasm_func_callback_t = - unsafe extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> *mut wasm_trap_t; - -pub type wasm_func_callback_with_env_t = unsafe extern "C" fn( - env: *mut std::ffi::c_void, - args: *const wasm_val_t, - results: *mut wasm_val_t, -) -> *mut wasm_trap_t; - -#[derive(Clone)] -#[repr(transparent)] -pub struct wasm_global_t { - ext: wasm_extern_t, -} - -impl wasm_global_t { - fn global(&self) -> &HostRef { - match &self.ext.which { - ExternHost::Global(g) => g, - _ => unsafe { std::hint::unreachable_unchecked() }, - } - } -} - -#[derive(Clone)] -#[repr(transparent)] -pub struct wasm_table_t { - ext: wasm_extern_t, -} - -impl wasm_table_t { - fn table(&self) -> &HostRef
{ - match &self.ext.which { - ExternHost::Table(t) => t, - _ => unsafe { std::hint::unreachable_unchecked() }, - } - } -} - -pub type wasm_table_size_t = u32; - -#[derive(Clone)] -#[repr(transparent)] -pub struct wasm_memory_t { - ext: wasm_extern_t, -} - -impl wasm_memory_t { - fn memory(&self) -> &HostRef { - match &self.ext.which { - ExternHost::Memory(m) => m, - _ => unsafe { std::hint::unreachable_unchecked() }, - } - } -} - -pub type wasm_memory_pages_t = u32; - -#[derive(Clone)] -pub struct wasm_extern_t { - which: ExternHost, -} - -#[derive(Clone)] -enum ExternHost { - Func(HostRef), - Global(HostRef), - Memory(HostRef), - Table(HostRef
), -} - -declare_vec!(wasm_extern_vec_t, *mut wasm_extern_t); - -#[no_mangle] -pub unsafe extern "C" fn wasm_byte_vec_delete(v: *mut wasm_byte_vec_t) { - (*v).uninitialize(); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_byte_vec_new_uninitialized(out: *mut wasm_byte_vec_t, size: usize) { - (*out).set_uninitialized(size); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_engine_delete(engine: *mut wasm_engine_t) { - let _ = Box::from_raw(engine); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_config_delete(config: *mut wasm_config_t) { - let _ = Box::from_raw(config); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_config_new() -> *mut wasm_config_t { - let config = Box::new(wasm_config_t { - config: Config::default(), - }); - Box::into_raw(config) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_engine_new() -> *mut wasm_engine_t { - let engine = Box::new(wasm_engine_t { - engine: HostRef::new(Engine::default()), - }); - Box::into_raw(engine) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_engine_new_with_config(c: *mut wasm_config_t) -> *mut wasm_engine_t { - let config = Box::from_raw(c).config; - let engine = Box::new(wasm_engine_t { - engine: HostRef::new(Engine::new(&config)), - }); - Box::into_raw(engine) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_delete(e: *mut wasm_extern_t) { - let _ = Box::from_raw(e); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_as_func(e: *mut wasm_extern_t) -> *mut wasm_func_t { - match &(*e).which { - ExternHost::Func(_) => e.cast(), - _ => ptr::null_mut(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_vec_delete(v: *mut wasm_extern_vec_t) { - (*v).uninitialize(); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_as_extern(f: *mut wasm_func_t) -> *mut wasm_extern_t { - &mut (*f).ext -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_call( - func: *const wasm_func_t, - args: *const wasm_val_t, - results: *mut wasm_val_t, -) -> *mut wasm_trap_t { - let func = (*func).func().borrow(); - let mut params = Vec::with_capacity(func.param_arity()); - for i in 0..func.param_arity() { - let val = &(*args.add(i)); - params.push(val.val()); - } - - // We're calling arbitrary code here most of the time, and we in general - // want to try to insulate callers against bugs in wasmtime/wasi/etc if we - // can. As a result we catch panics here and transform them to traps to - // allow the caller to have any insulation possible against Rust panics. - let result = panic::catch_unwind(AssertUnwindSafe(|| func.call(¶ms))); - match result { - Ok(Ok(out)) => { - for i in 0..func.result_arity() { - let val = &mut (*results.add(i)); - *val = wasm_val_t::from_val(&out[i]); - } - ptr::null_mut() - } - Ok(Err(trap)) => { - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(trap), - }); - Box::into_raw(trap) - } - Err(panic) => { - let trap = if let Some(msg) = panic.downcast_ref::() { - Trap::new(msg) - } else if let Some(msg) = panic.downcast_ref::<&'static str>() { - Trap::new(*msg) - } else { - Trap::new("rust panic happened") - }; - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(trap), - }); - Box::into_raw(trap) - } - } -} - -impl wasm_val_t { - fn default() -> wasm_val_t { - wasm_val_t { - kind: 0, - of: wasm_val_t__bindgen_ty_1 { i32: 0 }, - } - } - - fn set(&mut self, val: Val) { - match val { - Val::I32(i) => { - self.kind = from_valtype(&ValType::I32); - self.of = wasm_val_t__bindgen_ty_1 { i32: i }; - } - Val::I64(i) => { - self.kind = from_valtype(&ValType::I64); - self.of = wasm_val_t__bindgen_ty_1 { i64: i }; - } - Val::F32(f) => { - self.kind = from_valtype(&ValType::F32); - self.of = wasm_val_t__bindgen_ty_1 { u32: f }; - } - Val::F64(f) => { - self.kind = from_valtype(&ValType::F64); - self.of = wasm_val_t__bindgen_ty_1 { u64: f }; - } - _ => unimplemented!("wasm_val_t::from_val {:?}", val), - } - } - - fn from_val(val: &Val) -> wasm_val_t { - match val { - Val::I32(i) => wasm_val_t { - kind: from_valtype(&ValType::I32), - of: wasm_val_t__bindgen_ty_1 { i32: *i }, - }, - Val::I64(i) => wasm_val_t { - kind: from_valtype(&ValType::I64), - of: wasm_val_t__bindgen_ty_1 { i64: *i }, - }, - Val::F32(f) => wasm_val_t { - kind: from_valtype(&ValType::F32), - of: wasm_val_t__bindgen_ty_1 { u32: *f }, - }, - Val::F64(f) => wasm_val_t { - kind: from_valtype(&ValType::F64), - of: wasm_val_t__bindgen_ty_1 { u64: *f }, - }, - _ => unimplemented!("wasm_val_t::from_val {:?}", val), - } - } - - fn val(&self) -> Val { - match into_valtype(self.kind) { - ValType::I32 => Val::from(unsafe { self.of.i32 }), - ValType::I64 => Val::from(unsafe { self.of.i64 }), - ValType::F32 => Val::from(unsafe { self.of.f32 }), - ValType::F64 => Val::from(unsafe { self.of.f64 }), - _ => unimplemented!("wasm_val_t::val {:?}", self.kind), - } - } -} - -enum Callback { - Wasm(wasm_func_callback_t), - Wasmtime(crate::ext::wasmtime_func_callback_t), -} - -enum CallbackWithEnv { - Wasm(wasm_func_callback_with_env_t), - Wasmtime(crate::ext::wasmtime_func_callback_with_env_t), -} - -unsafe fn create_function( - store: *mut wasm_store_t, - ty: *const wasm_functype_t, - callback: Callback, -) -> *mut wasm_func_t { - let store = &(*store).store.borrow(); - let ty = (*ty).functype.clone(); - let func = Func::new(store, ty, move |caller, params, results| { - let params = params - .iter() - .map(|p| wasm_val_t::from_val(p)) - .collect::>(); - let mut out_results = vec![wasm_val_t::default(); results.len()]; - let out = match callback { - Callback::Wasm(callback) => callback(params.as_ptr(), out_results.as_mut_ptr()), - Callback::Wasmtime(callback) => { - let caller = crate::ext::wasmtime_caller_t { inner: caller }; - callback(&caller, params.as_ptr(), out_results.as_mut_ptr()) - } - }; - if !out.is_null() { - let trap: Box = Box::from_raw(out); - return Err(trap.trap.borrow().clone()); - } - for i in 0..results.len() { - results[i] = out_results[i].val(); - } - Ok(()) - }); - let func = Box::new(wasm_func_t { - ext: wasm_extern_t { - which: ExternHost::Func(HostRef::new(func)), - }, - }); - Box::into_raw(func) -} - -unsafe fn create_function_with_env( - store: *mut wasm_store_t, - ty: *const wasm_functype_t, - callback: CallbackWithEnv, - env: *mut std::ffi::c_void, - finalizer: Option, -) -> *mut wasm_func_t { - let store = &(*store).store.borrow(); - let ty = (*ty).functype.clone(); - - // Create a small object which will run the finalizer when it's dropped, and - // then we move this `run_finalizer` object into the closure below (via the - // `drop(&run_finalizer)` statement so it's all dropped when the closure is - // dropped. - struct RunOnDrop(F); - impl Drop for RunOnDrop { - fn drop(&mut self) { - (self.0)(); - } - } - let run_finalizer = RunOnDrop(move || { - if let Some(finalizer) = finalizer { - finalizer(env); - } - }); - let func = Func::new(store, ty, move |caller, params, results| { - drop(&run_finalizer); - let params = params - .iter() - .map(|p| wasm_val_t::from_val(p)) - .collect::>(); - let mut out_results = vec![wasm_val_t::default(); results.len()]; - let out = match callback { - CallbackWithEnv::Wasm(callback) => { - callback(env, params.as_ptr(), out_results.as_mut_ptr()) - } - CallbackWithEnv::Wasmtime(callback) => { - let caller = crate::ext::wasmtime_caller_t { inner: caller }; - callback(&caller, env, params.as_ptr(), out_results.as_mut_ptr()) - } - }; - if !out.is_null() { - let trap: Box = Box::from_raw(out); - return Err(trap.trap.borrow().clone()); - } - for i in 0..results.len() { - results[i] = out_results[i].val(); - } - Ok(()) - }); - - let func = Box::new(wasm_func_t { - ext: wasm_extern_t { - which: ExternHost::Func(HostRef::new(func)), - }, - }); - Box::into_raw(func) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_new( - store: *mut wasm_store_t, - ty: *const wasm_functype_t, - callback: wasm_func_callback_t, -) -> *mut wasm_func_t { - create_function(store, ty, Callback::Wasm(callback)) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_delete(f: *mut wasm_func_t) { - let _ = Box::from_raw(f); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_new( - params: *mut wasm_valtype_vec_t, - results: *mut wasm_valtype_vec_t, -) -> *mut wasm_functype_t { - let params = Vec::from_raw_parts((*params).data, (*params).size, (*params).size) - .into_iter() - .map(|vt| (*vt).ty.clone()) - .collect::>(); - let results = Vec::from_raw_parts((*results).data, (*results).size, (*results).size) - .into_iter() - .map(|vt| (*vt).ty.clone()) - .collect::>(); - let functype = FuncType::new(params.into_boxed_slice(), results.into_boxed_slice()); - let functype = Box::new(wasm_functype_t { - functype, - params_cache: None, // TODO get from args? - returns_cache: None, // TODO get from args? - }); - Box::into_raw(functype) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_delete(ft: *mut wasm_functype_t) { - let _ = Box::from_raw(ft); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_instance_delete(instance: *mut wasm_instance_t) { - let _ = Box::from_raw(instance); -} - -impl wasm_instance_t { - fn new(instance: Instance) -> wasm_instance_t { - wasm_instance_t { - instance: HostRef::new(instance), - exports_cache: RefCell::new(None), - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_instance_new( - store: *mut wasm_store_t, - module: *const wasm_module_t, - imports: *const *const wasm_extern_t, - result: *mut *mut wasm_trap_t, -) -> *mut wasm_instance_t { - let mut externs: Vec = Vec::with_capacity((*module).imports.len()); - for i in 0..(*module).imports.len() { - let import = *imports.add(i); - externs.push(match &(*import).which { - ExternHost::Func(e) => Extern::Func(e.borrow().clone()), - ExternHost::Table(e) => Extern::Table(e.borrow().clone()), - ExternHost::Global(e) => Extern::Global(e.borrow().clone()), - ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()), - }); - } - let store = &(*store).store.borrow(); - let module = &(*module).module.borrow(); - // FIXME(WebAssembly/wasm-c-api#126) what else can we do with the `store` - // argument? - if !Store::same(&store, module.store()) { - if !result.is_null() { - let trap = Trap::new("wasm_store_t must match store in wasm_module_t"); - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(trap), - }); - (*result) = Box::into_raw(trap); - } - return ptr::null_mut(); - } - handle_instantiate(Instance::new(module, &externs), result) -} - -unsafe fn handle_instantiate( - instance: Result, - result: *mut *mut wasm_trap_t, -) -> *mut wasm_instance_t { - match instance { - Ok(instance) => { - let instance = Box::new(wasm_instance_t::new(instance)); - if !result.is_null() { - (*result) = ptr::null_mut(); - } - Box::into_raw(instance) - } - Err(trap) => { - if !result.is_null() { - let trap = match trap.downcast::() { - Ok(trap) => trap, - Err(e) => Trap::new(format!("{:?}", e)), - }; - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(trap), - }); - (*result) = Box::into_raw(trap); - } - ptr::null_mut() - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_instance_exports( - instance: *const wasm_instance_t, - out: *mut wasm_extern_vec_t, -) { - let mut cache = (*instance).exports_cache.borrow_mut(); - let exports = cache.get_or_insert_with(|| { - let instance = &(*instance).instance.borrow(); - instance - .exports() - .iter() - .map(|e| match e { - Extern::Func(f) => ExternHost::Func(HostRef::new(f.clone())), - Extern::Global(f) => ExternHost::Global(HostRef::new(f.clone())), - Extern::Memory(f) => ExternHost::Memory(HostRef::new(f.clone())), - Extern::Table(f) => ExternHost::Table(HostRef::new(f.clone())), - }) - .collect() - }); - let mut buffer = Vec::with_capacity(exports.len()); - for e in exports { - let ext = Box::new(wasm_extern_t { which: e.clone() }); - buffer.push(Box::into_raw(ext)); - } - (*out).set_buffer(buffer); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_module_delete(module: *mut wasm_module_t) { - let _ = Box::from_raw(module); -} - -impl wasm_name_t { - fn from_name(name: &str) -> wasm_name_t { - name.to_string().into_bytes().into() - } -} - -/// Note that this function does not perform validation on the wasm -/// binary. To perform validation, use `wasm_module_validate`. -#[no_mangle] -pub unsafe extern "C" fn wasm_module_new( - store: *mut wasm_store_t, - binary: *const wasm_byte_vec_t, -) -> *mut wasm_module_t { - let binary = (*binary).as_slice(); - let store = &(*store).store.borrow(); - let module = match Module::from_binary(store, binary) { - Ok(module) => module, - Err(_) => return ptr::null_mut(), - }; - let imports = module - .imports() - .iter() - .map(|i| wasm_importtype_t { - ty: i.clone(), - module_cache: None, - name_cache: None, - type_cache: None, - }) - .collect::>(); - let exports = module - .exports() - .iter() - .map(|e| wasm_exporttype_t { - ty: e.clone(), - name_cache: None, - type_cache: None, - }) - .collect::>(); - let module = Box::new(wasm_module_t { - module: HostRef::new(module), - imports, - exports, - }); - Box::into_raw(module) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_module_validate( - store: *mut wasm_store_t, - binary: *const wasm_byte_vec_t, -) -> bool { - let binary = (*binary).as_slice(); - let store = &(*store).store.borrow(); - Module::validate(store, binary).is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_store_delete(store: *mut wasm_store_t) { - let _ = Box::from_raw(store); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_store_new(engine: *mut wasm_engine_t) -> *mut wasm_store_t { - let engine = &(*engine).engine; - let store = Box::new(wasm_store_t { - store: HostRef::new(Store::new(&engine.borrow())), - }); - Box::into_raw(store) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_vec_new_empty(out: *mut wasm_valtype_vec_t) { - (*out).set_uninitialized(0); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_vec_new( - out: *mut wasm_valtype_vec_t, - size: usize, - data: *const *mut wasm_valtype_t, -) { - let slice = slice::from_raw_parts(data, size); - (*out).set_from_slice(slice); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_vec_new_uninitialized( - out: *mut wasm_valtype_vec_t, - size: usize, -) { - (*out).set_uninitialized(size); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_new_with_env( - store: *mut wasm_store_t, - ty: *const wasm_functype_t, - callback: wasm_func_callback_with_env_t, - env: *mut std::ffi::c_void, - finalizer: Option, -) -> *mut wasm_func_t { - create_function_with_env(store, ty, CallbackWithEnv::Wasm(callback), env, finalizer) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_val_copy(out: *mut wasm_val_t, source: *const wasm_val_t) { - *out = match into_valtype((*source).kind) { - ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => *source, - _ => unimplemented!("wasm_val_copy arg"), - }; -} - -fn into_valtype(kind: wasm_valkind_t) -> ValType { - match kind { - 0 => ValType::I32, - 1 => ValType::I64, - 2 => ValType::F32, - 3 => ValType::F64, - 128 => ValType::AnyRef, - 129 => ValType::FuncRef, - _ => panic!("unexpected kind: {}", kind), - } -} - -fn from_valtype(ty: &ValType) -> wasm_valkind_t { - match ty { - ValType::I32 => 0, - ValType::I64 => 1, - ValType::F32 => 2, - ValType::F64 => 3, - ValType::AnyRef => 128, - ValType::FuncRef => 129, - _ => panic!("wasm_valkind_t has no known conversion for {:?}", ty), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> *mut wasm_valtype_t { - let ty = Box::new(wasm_valtype_t { - ty: into_valtype(kind), - }); - Box::into_raw(ty) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_delete(vt: *mut wasm_valtype_t) { - drop(Box::from_raw(vt)); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_byte_vec_new( - out: *mut wasm_byte_vec_t, - size: usize, - data: *const wasm_byte_t, -) { - let slice = slice::from_raw_parts(data, size); - (*out).set_from_slice(slice); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_frame_delete(_arg1: *mut wasm_frame_t) { - unimplemented!("wasm_frame_delete") -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_frame_func_index(_arg1: *const wasm_frame_t) -> u32 { - unimplemented!("wasm_frame_func_index") -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_frame_func_offset(_arg1: *const wasm_frame_t) -> usize { - unimplemented!("wasm_frame_func_offset") -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t) -> *mut wasm_instance_t { - unimplemented!("wasm_frame_instance") -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_frame_module_offset(_arg1: *const wasm_frame_t) -> usize { - unimplemented!("wasm_frame_module_offset") -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_frame_vec_delete(frames: *mut wasm_frame_vec_t) { - (*frames).uninitialize(); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_trap_delete(trap: *mut wasm_trap_t) { - let _ = Box::from_raw(trap); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_trap_new( - _store: *mut wasm_store_t, - message: *const wasm_message_t, -) -> *mut wasm_trap_t { - let message = (*message).as_slice(); - if message[message.len() - 1] != 0 { - panic!("wasm_trap_new message stringz expected"); - } - let message = String::from_utf8_lossy(&message[..message.len() - 1]); - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(Trap::new(message)), - }); - Box::into_raw(trap) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_trap_message(trap: *const wasm_trap_t, out: *mut wasm_message_t) { - let mut buffer = Vec::new(); - buffer.extend_from_slice((*trap).trap.borrow().message().as_bytes()); - buffer.reserve_exact(1); - buffer.push(0); - (*out).set_buffer(buffer); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_trap_origin(_trap: *const wasm_trap_t) -> *mut wasm_frame_t { - ptr::null_mut() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_trap_trace(_trap: *const wasm_trap_t, out: *mut wasm_frame_vec_t) { - (*out).set_uninitialized(0); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_importtype_delete(ty: *mut wasm_importtype_t) { - let _ = Box::from_raw(ty); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_importtype_module( - it: *const wasm_importtype_t, -) -> *const wasm_name_t { - if (*it).module_cache.is_none() { - let it = (it as *mut wasm_importtype_t).as_mut().unwrap(); - it.module_cache = Some(wasm_name_t::from_name(&it.ty.module())); - } - (*it).module_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_importtype_name(it: *const wasm_importtype_t) -> *const wasm_name_t { - if (*it).name_cache.is_none() { - let it = (it as *mut wasm_importtype_t).as_mut().unwrap(); - it.name_cache = Some(wasm_name_t::from_name(&it.ty.name())); - } - (*it).name_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_importtype_type( - it: *const wasm_importtype_t, -) -> *const wasm_externtype_t { - if (*it).type_cache.is_none() { - let it = (it as *mut wasm_importtype_t).as_mut().unwrap(); - it.type_cache = Some(wasm_externtype_t { - ty: (*it).ty.ty().clone(), - cache: wasm_externtype_t_type_cache::Empty, - }); - } - (*it).type_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_importtype_vec_delete(vec: *mut wasm_importtype_vec_t) { - (*vec).uninitialize(); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_exporttype_delete(ty: *mut wasm_exporttype_t) { - let _ = Box::from_raw(ty); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_exporttype_name(et: *const wasm_exporttype_t) -> *const wasm_name_t { - if (*et).name_cache.is_none() { - let et = (et as *mut wasm_exporttype_t).as_mut().unwrap(); - et.name_cache = Some(wasm_name_t::from_name(&et.ty.name())); - } - (*et).name_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_exporttype_type( - et: *const wasm_exporttype_t, -) -> *const wasm_externtype_t { - if (*et).type_cache.is_none() { - let et = (et as *mut wasm_exporttype_t).as_mut().unwrap(); - et.type_cache = Some(wasm_externtype_t { - ty: (*et).ty.ty().clone(), - cache: wasm_externtype_t_type_cache::Empty, - }); - } - (*et).type_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_exporttype_vec_delete(et: *mut wasm_exporttype_vec_t) { - (*et).uninitialize(); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_kind(e: *const wasm_extern_t) -> wasm_externkind_t { - match (*e).which { - ExternHost::Func(_) => WASM_EXTERN_FUNC, - ExternHost::Global(_) => WASM_EXTERN_GLOBAL, - ExternHost::Table(_) => WASM_EXTERN_TABLE, - ExternHost::Memory(_) => WASM_EXTERN_MEMORY, - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_type(e: *const wasm_extern_t) -> *mut wasm_externtype_t { - let et = Box::new(wasm_externtype_t { - ty: match &(*e).which { - ExternHost::Func(f) => ExternType::Func(f.borrow().ty().clone()), - ExternHost::Global(f) => ExternType::Global(f.borrow().ty().clone()), - ExternHost::Table(f) => ExternType::Table(f.borrow().ty().clone()), - ExternHost::Memory(f) => ExternType::Memory(f.borrow().ty().clone()), - }, - cache: wasm_externtype_t_type_cache::Empty, - }); - Box::into_raw(et) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_functype_const( - et: *const wasm_externtype_t, -) -> *const wasm_functype_t { - if let wasm_externtype_t_type_cache::Empty = (*et).cache { - let functype = match (*et).ty.func() { - Some(f) => f.clone(), - None => return ptr::null(), - }; - let f = wasm_functype_t { - functype, - params_cache: None, - returns_cache: None, - }; - let et = (et as *mut wasm_externtype_t).as_mut().unwrap(); - et.cache = wasm_externtype_t_type_cache::Func(f); - } - match &(*et).cache { - wasm_externtype_t_type_cache::Func(f) => f, - _ => ptr::null(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_globaltype_const( - et: *const wasm_externtype_t, -) -> *const wasm_globaltype_t { - if let wasm_externtype_t_type_cache::Empty = (*et).cache { - let globaltype = match (*et).ty.global() { - Some(g) => g.clone(), - None => return ptr::null(), - }; - let g = wasm_globaltype_t { - globaltype, - content_cache: None, - }; - let et = (et as *mut wasm_externtype_t).as_mut().unwrap(); - et.cache = wasm_externtype_t_type_cache::Global(g); - } - match &(*et).cache { - wasm_externtype_t_type_cache::Global(g) => g, - _ => ptr::null(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_tabletype_const( - et: *const wasm_externtype_t, -) -> *const wasm_tabletype_t { - if let wasm_externtype_t_type_cache::Empty = (*et).cache { - let tabletype = match (*et).ty.table() { - Some(t) => t.clone(), - None => return ptr::null(), - }; - let t = wasm_tabletype_t { - tabletype, - element_cache: None, - limits_cache: None, - }; - let et = (et as *mut wasm_externtype_t).as_mut().unwrap(); - et.cache = wasm_externtype_t_type_cache::Table(t); - } - match &(*et).cache { - wasm_externtype_t_type_cache::Table(t) => t, - _ => ptr::null(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_memorytype_const( - et: *const wasm_externtype_t, -) -> *const wasm_memorytype_t { - if let wasm_externtype_t_type_cache::Empty = (*et).cache { - let memorytype = match (*et).ty.memory() { - Some(m) => m.clone(), - None => return ptr::null(), - }; - let m = wasm_memorytype_t { - memorytype, - limits_cache: None, - }; - let et = (et as *mut wasm_externtype_t).as_mut().unwrap(); - et.cache = wasm_externtype_t_type_cache::Memory(m); - } - match &(*et).cache { - wasm_externtype_t_type_cache::Memory(m) => m, - _ => ptr::null(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_delete(et: *mut wasm_externtype_t) { - let _ = Box::from_raw(et); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_kind(et: *const wasm_externtype_t) -> wasm_externkind_t { - match &(*et).ty { - ExternType::Func(_) => WASM_EXTERN_FUNC, - ExternType::Table(_) => WASM_EXTERN_TABLE, - ExternType::Global(_) => WASM_EXTERN_GLOBAL, - ExternType::Memory(_) => WASM_EXTERN_MEMORY, - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_type(f: *const wasm_func_t) -> *mut wasm_functype_t { - let ft = Box::new(wasm_functype_t { - functype: (*f).func().borrow().ty().clone(), - params_cache: None, - returns_cache: None, - }); - Box::into_raw(ft) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_param_arity(f: *const wasm_func_t) -> usize { - (*f).func().borrow().param_arity() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_result_arity(f: *const wasm_func_t) -> usize { - (*f).func().borrow().result_arity() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_params( - ft: *const wasm_functype_t, -) -> *const wasm_valtype_vec_t { - if (*ft).params_cache.is_none() { - let ft = (ft as *mut wasm_functype_t).as_mut().unwrap(); - let buffer = ft - .functype - .params() - .iter() - .map(|p| { - let ty = Box::new(wasm_valtype_t { ty: p.clone() }); - Box::into_raw(ty) - }) - .collect::>(); - ft.params_cache = Some(buffer.into()); - } - (*ft).params_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_results( - ft: *const wasm_functype_t, -) -> *const wasm_valtype_vec_t { - if (*ft).returns_cache.is_none() { - let ft = (ft as *mut wasm_functype_t).as_mut().unwrap(); - let buffer = ft - .functype - .results() - .iter() - .map(|p| { - let ty = Box::new(wasm_valtype_t { ty: p.clone() }); - Box::into_raw(ty) - }) - .collect::>(); - ft.returns_cache = Some(buffer.into()); - } - (*ft).returns_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_content( - gt: *const wasm_globaltype_t, -) -> *const wasm_valtype_t { - if (*gt).content_cache.is_none() { - let gt = (gt as *mut wasm_globaltype_t).as_mut().unwrap(); - gt.content_cache = Some(wasm_valtype_t { - ty: (*gt).globaltype.content().clone(), - }); - } - (*gt).content_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_mutability( - gt: *const wasm_globaltype_t, -) -> wasm_mutability_t { - use wasmtime::Mutability::*; - match (*gt).globaltype.mutability() { - Const => 0, - Var => 1, - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_limits( - mt: *const wasm_memorytype_t, -) -> *const wasm_limits_t { - if (*mt).limits_cache.is_none() { - let mt = (mt as *mut wasm_memorytype_t).as_mut().unwrap(); - let limits = (*mt).memorytype.limits(); - mt.limits_cache = Some(wasm_limits_t { - min: limits.min(), - max: limits.max().unwrap_or(u32::max_value()), - }); - } - (*mt).limits_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_module_exports( - module: *const wasm_module_t, - out: *mut wasm_exporttype_vec_t, -) { - let buffer = (*module) - .exports - .iter() - .map(|et| { - let et = Box::new(et.clone()); - Box::into_raw(et) - }) - .collect::>(); - (*out).set_buffer(buffer); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_module_imports( - module: *const wasm_module_t, - out: *mut wasm_importtype_vec_t, -) { - let buffer = (*module) - .imports - .iter() - .map(|it| { - let it = Box::new(it.clone()); - Box::into_raw(it) - }) - .collect::>(); - (*out).set_buffer(buffer); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_element( - tt: *const wasm_tabletype_t, -) -> *const wasm_valtype_t { - if (*tt).element_cache.is_none() { - let tt = (tt as *mut wasm_tabletype_t).as_mut().unwrap(); - tt.element_cache = Some(wasm_valtype_t { - ty: (*tt).tabletype.element().clone(), - }); - } - (*tt).element_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_limits( - tt: *const wasm_tabletype_t, -) -> *const wasm_limits_t { - if (*tt).limits_cache.is_none() { - let tt = (tt as *mut wasm_tabletype_t).as_mut().unwrap(); - let limits = (*tt).tabletype.limits(); - tt.limits_cache = Some(wasm_limits_t { - min: limits.min(), - max: limits.max().unwrap_or(u32::max_value()), - }); - } - (*tt).limits_cache.as_ref().unwrap() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_kind(vt: *const wasm_valtype_t) -> wasm_valkind_t { - from_valtype(&(*vt).ty) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_as_global(e: *mut wasm_extern_t) -> *mut wasm_global_t { - match &(*e).which { - ExternHost::Global(_) => e.cast(), - _ => ptr::null_mut(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_global_as_extern(g: *mut wasm_global_t) -> *mut wasm_extern_t { - &mut (*g).ext -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_global_delete(g: *mut wasm_global_t) { - let _ = Box::from_raw(g); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_global_copy(g: *const wasm_global_t) -> *mut wasm_global_t { - Box::into_raw(Box::new((*g).clone())) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_global_same( - g1: *const wasm_global_t, - g2: *const wasm_global_t, -) -> bool { - (*g1).global().ptr_eq(&(*g2).global()) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_global_new( - store: *mut wasm_store_t, - gt: *const wasm_globaltype_t, - val: *const wasm_val_t, -) -> *mut wasm_global_t { - let global = HostRef::new( - match Global::new( - &(*store).store.borrow(), - (*gt).globaltype.clone(), - (*val).val(), - ) { - Ok(g) => g, - Err(_) => return ptr::null_mut(), - }, - ); - let g = Box::new(wasm_global_t { - ext: wasm_extern_t { - which: ExternHost::Global(global), - }, - }); - Box::into_raw(g) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_global_type(g: *const wasm_global_t) -> *mut wasm_globaltype_t { - let globaltype = (*g).global().borrow().ty().clone(); - let g = Box::new(wasm_globaltype_t { - globaltype, - content_cache: None, - }); - Box::into_raw(g) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_global_get(g: *const wasm_global_t, out: *mut wasm_val_t) { - (*out).set((*g).global().borrow().get()); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_global_set(g: *mut wasm_global_t, val: *const wasm_val_t) { - let result = (*g).global().borrow().set((*val).val()); - drop(result); // TODO: should communicate this via the api somehow? -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_delete(gt: *mut wasm_globaltype_t) { - let _ = Box::from_raw(gt); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_new( - ty: *mut wasm_valtype_t, - mutability: wasm_mutability_t, -) -> *mut wasm_globaltype_t { - use wasmtime::Mutability::*; - let ty = Box::from_raw(ty); - let mutability = match mutability { - 0 => Const, - 1 => Var, - _ => panic!("mutability out-of-range"), - }; - let globaltype = GlobalType::new(ty.ty.clone(), mutability); - let gt = Box::new(wasm_globaltype_t { - globaltype, - content_cache: Some(*ty), - }); - Box::into_raw(gt) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_as_memory(e: *mut wasm_extern_t) -> *mut wasm_memory_t { - match &(*e).which { - ExternHost::Memory(_) => e.cast(), - _ => ptr::null_mut(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_as_extern(m: *mut wasm_memory_t) -> *mut wasm_extern_t { - &mut (*m).ext -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_delete(m: *mut wasm_memory_t) { - let _ = Box::from_raw(m); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_copy(m: *const wasm_memory_t) -> *mut wasm_memory_t { - Box::into_raw(Box::new((*m).clone())) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_same( - m1: *const wasm_memory_t, - m2: *const wasm_memory_t, -) -> bool { - (*m1).memory().ptr_eq(&(*m2).memory()) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_type(m: *const wasm_memory_t) -> *mut wasm_memorytype_t { - let ty = (*m).memory().borrow().ty().clone(); - Box::into_raw(Box::new(wasm_memorytype_t { - memorytype: ty, - limits_cache: None, - })) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_data(m: *mut wasm_memory_t) -> *mut u8 { - (*m).memory().borrow().data_ptr() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_data_size(m: *const wasm_memory_t) -> usize { - (*m).memory().borrow().data_size() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_size(m: *const wasm_memory_t) -> wasm_memory_pages_t { - (*m).memory().borrow().size() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_grow( - m: *mut wasm_memory_t, - delta: wasm_memory_pages_t, -) -> bool { - (*m).memory().borrow().grow(delta).is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memory_new( - store: *mut wasm_store_t, - mt: *const wasm_memorytype_t, -) -> *mut wasm_memory_t { - let memory = HostRef::new(Memory::new( - &(*store).store.borrow(), - (*mt).memorytype.clone(), - )); - let m = Box::new(wasm_memory_t { - ext: wasm_extern_t { - which: ExternHost::Memory(memory), - }, - }); - Box::into_raw(m) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_delete(mt: *mut wasm_memorytype_t) { - let _ = Box::from_raw(mt); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_new( - limits: *const wasm_limits_t, -) -> *mut wasm_memorytype_t { - let max = if (*limits).max == u32::max_value() { - None - } else { - Some((*limits).max) - }; - let limits = Limits::new((*limits).min, max); - let mt = Box::new(wasm_memorytype_t { - memorytype: MemoryType::new(limits), - limits_cache: None, - }); - Box::into_raw(mt) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_as_table(e: *mut wasm_extern_t) -> *mut wasm_table_t { - match &(*e).which { - ExternHost::Table(_) => e.cast(), - _ => ptr::null_mut(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_as_extern(t: *mut wasm_table_t) -> *mut wasm_extern_t { - &mut (*t).ext -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_as_ref(f: *mut wasm_func_t) -> *mut wasm_ref_t { - let r = (*f).func().anyref(); - let f = Box::new(wasm_ref_t { r }); - Box::into_raw(f) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_ref_delete(r: *mut wasm_ref_t) { - if !r.is_null() { - let _ = Box::from_raw(r); - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_delete(t: *mut wasm_table_t) { - let _ = Box::from_raw(t); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_copy(t: *const wasm_table_t) -> *mut wasm_table_t { - Box::into_raw(Box::new((*t).clone())) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_new( - store: *mut wasm_store_t, - tt: *const wasm_tabletype_t, - init: *mut wasm_ref_t, -) -> *mut wasm_table_t { - let init: Val = if !init.is_null() { - Box::from_raw(init).r.into() - } else { - Val::AnyRef(AnyRef::Null) - }; - let table = match Table::new(&(*store).store.borrow(), (*tt).tabletype.clone(), init) { - Ok(table) => table, - Err(_) => return ptr::null_mut(), - }; - let t = Box::new(wasm_table_t { - ext: wasm_extern_t { - which: ExternHost::Table(HostRef::new(table)), - }, - }); - Box::into_raw(t) -} - -unsafe fn into_funcref(val: Val) -> *mut wasm_ref_t { - if let Val::AnyRef(AnyRef::Null) = val { - return ptr::null_mut(); - } - let anyref = match val.anyref() { - Some(anyref) => anyref, - None => return ptr::null_mut(), - }; - let r = Box::new(wasm_ref_t { r: anyref }); - Box::into_raw(r) -} - -unsafe fn from_funcref(r: *mut wasm_ref_t) -> Val { - if !r.is_null() { - Box::from_raw(r).r.into() - } else { - Val::AnyRef(AnyRef::Null) - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_type(t: *const wasm_table_t) -> *mut wasm_tabletype_t { - let ty = (*t).table().borrow().ty().clone(); - Box::into_raw(Box::new(wasm_tabletype_t { - tabletype: ty, - limits_cache: None, - element_cache: None, - })) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_get( - t: *const wasm_table_t, - index: wasm_table_size_t, -) -> *mut wasm_ref_t { - match (*t).table().borrow().get(index) { - Some(val) => into_funcref(val), - None => into_funcref(Val::AnyRef(AnyRef::Null)), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_set( - t: *mut wasm_table_t, - index: wasm_table_size_t, - r: *mut wasm_ref_t, -) -> bool { - let val = from_funcref(r); - (*t).table().borrow().set(index, val).is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_size(t: *const wasm_table_t) -> wasm_table_size_t { - (*t).table().borrow().size() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_grow( - t: *mut wasm_table_t, - delta: wasm_table_size_t, - init: *mut wasm_ref_t, -) -> bool { - let init = from_funcref(init); - (*t).table().borrow().grow(delta, init).is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_table_same(t1: *const wasm_table_t, t2: *const wasm_table_t) -> bool { - (*t1).table().ptr_eq((*t2).table()) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_delete(tt: *mut wasm_tabletype_t) { - let _ = Box::from_raw(tt); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_new( - ty: *mut wasm_valtype_t, - limits: *const wasm_limits_t, -) -> *mut wasm_tabletype_t { - let ty = Box::from_raw(ty).ty; - let max = if (*limits).max == u32::max_value() { - None - } else { - Some((*limits).max) - }; - let limits = Limits::new((*limits).min, max); - let tt = Box::new(wasm_tabletype_t { - tabletype: TableType::new(ty, limits), - element_cache: None, - limits_cache: None, - }); - Box::into_raw(tt) -} - struct HostInfoState { info: *mut std::ffi::c_void, - finalizer: std::option::Option, + finalizer: Option, } -impl HostInfo for HostInfoState { - fn finalize(&mut self) { +impl Drop for HostInfoState { + fn drop(&mut self) { if let Some(f) = &self.finalizer { - unsafe { - f(self.info); - } + f(self.info); } } } - -#[no_mangle] -pub unsafe extern "C" fn wasm_instance_set_host_info_with_finalizer( - instance: *mut wasm_instance_t, - info: *mut std::ffi::c_void, - finalizer: std::option::Option, -) { - let info = if info.is_null() && finalizer.is_none() { - None - } else { - let b: Box = Box::new(HostInfoState { info, finalizer }); - Some(b) - }; - (*instance).instance.anyref().set_host_info(info); -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_vec_copy( - out: *mut wasm_valtype_vec_t, - src: *mut wasm_valtype_vec_t, -) { - let slice = slice::from_raw_parts((*src).data, (*src).size); - (*out).set_from_slice(slice); -} diff --git a/crates/c-api/src/linker.rs b/crates/c-api/src/linker.rs new file mode 100644 index 0000000000..549819db01 --- /dev/null +++ b/crates/c-api/src/linker.rs @@ -0,0 +1,86 @@ +use crate::{wasi_instance_t, wasm_extern_t, wasm_store_t, ExternHost}; +use crate::{wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t}; +use std::str; +use wasmtime::{Extern, Linker}; + +#[repr(C)] +pub struct wasmtime_linker_t { + linker: Linker, +} + +#[no_mangle] +pub extern "C" fn wasmtime_linker_new(store: &wasm_store_t) -> Box { + Box::new(wasmtime_linker_t { + linker: Linker::new(&store.store.borrow()), + }) +} + +#[no_mangle] +pub extern "C" fn wasmtime_linker_allow_shadowing( + linker: &mut wasmtime_linker_t, + allow_shadowing: bool, +) { + linker.linker.allow_shadowing(allow_shadowing); +} + +#[no_mangle] +pub extern "C" fn wasmtime_linker_delete(_linker: Box) {} + +#[no_mangle] +pub extern "C" fn wasmtime_linker_define( + linker: &mut wasmtime_linker_t, + module: &wasm_name_t, + name: &wasm_name_t, + item: &wasm_extern_t, +) -> bool { + let linker = &mut linker.linker; + let module = match str::from_utf8(module.as_slice()) { + Ok(s) => s, + Err(_) => return false, + }; + let name = match str::from_utf8(name.as_slice()) { + Ok(s) => s, + Err(_) => return false, + }; + let item = match &item.which { + ExternHost::Func(e) => Extern::Func(e.borrow().clone()), + ExternHost::Table(e) => Extern::Table(e.borrow().clone()), + ExternHost::Global(e) => Extern::Global(e.borrow().clone()), + ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()), + }; + linker.define(module, name, item).is_ok() +} + +#[no_mangle] +pub extern "C" fn wasmtime_linker_define_wasi( + linker: &mut wasmtime_linker_t, + instance: &wasi_instance_t, +) -> bool { + let linker = &mut linker.linker; + instance.add_to_linker(linker).is_ok() +} + +#[no_mangle] +pub extern "C" fn wasmtime_linker_define_instance( + linker: &mut wasmtime_linker_t, + name: &wasm_name_t, + instance: &wasm_instance_t, +) -> bool { + let linker = &mut linker.linker; + let name = match str::from_utf8(name.as_slice()) { + Ok(s) => s, + Err(_) => return false, + }; + linker.instance(name, &instance.instance.borrow()).is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn wasmtime_linker_instantiate( + linker: &wasmtime_linker_t, + module: &wasm_module_t, + trap: Option<&mut *mut wasm_trap_t>, +) -> Option> { + let linker = &linker.linker; + let result = linker.instantiate(&module.module.borrow()); + super::instance::handle_instantiate(result, trap) +} diff --git a/crates/c-api/src/memory.rs b/crates/c-api/src/memory.rs new file mode 100644 index 0000000000..ab814bc296 --- /dev/null +++ b/crates/c-api/src/memory.rs @@ -0,0 +1,76 @@ +use crate::{wasm_extern_t, wasm_memorytype_t, wasm_store_t, ExternHost}; +use wasmtime::{HostRef, Memory}; + +#[derive(Clone)] +#[repr(transparent)] +pub struct wasm_memory_t { + ext: wasm_extern_t, +} + +wasmtime_c_api_macros::declare_ref!(wasm_memory_t); + +pub type wasm_memory_pages_t = u32; + +impl wasm_memory_t { + pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_memory_t> { + match &e.which { + ExternHost::Memory(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } + + fn memory(&self) -> &HostRef { + match &self.ext.which { + ExternHost::Memory(m) => m, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } + + fn anyref(&self) -> wasmtime::AnyRef { + self.memory().anyref() + } +} + +#[no_mangle] +pub extern "C" fn wasm_memory_new( + store: &wasm_store_t, + mt: &wasm_memorytype_t, +) -> Box { + let memory = HostRef::new(Memory::new(&store.store.borrow(), mt.ty().ty.clone())); + Box::new(wasm_memory_t { + ext: wasm_extern_t { + which: ExternHost::Memory(memory), + }, + }) +} + +#[no_mangle] +pub extern "C" fn wasm_memory_as_extern(m: &wasm_memory_t) -> &wasm_extern_t { + &m.ext +} + +#[no_mangle] +pub extern "C" fn wasm_memory_type(m: &wasm_memory_t) -> Box { + let ty = m.memory().borrow().ty().clone(); + Box::new(wasm_memorytype_t::new(ty)) +} + +#[no_mangle] +pub extern "C" fn wasm_memory_data(m: &wasm_memory_t) -> *mut u8 { + m.memory().borrow().data_ptr() +} + +#[no_mangle] +pub extern "C" fn wasm_memory_data_size(m: &wasm_memory_t) -> usize { + m.memory().borrow().data_size() +} + +#[no_mangle] +pub extern "C" fn wasm_memory_size(m: &wasm_memory_t) -> wasm_memory_pages_t { + m.memory().borrow().size() +} + +#[no_mangle] +pub extern "C" fn wasm_memory_grow(m: &wasm_memory_t, delta: wasm_memory_pages_t) -> bool { + m.memory().borrow().grow(delta).is_ok() +} diff --git a/crates/c-api/src/module.rs b/crates/c-api/src/module.rs new file mode 100644 index 0000000000..4cf15bda06 --- /dev/null +++ b/crates/c-api/src/module.rs @@ -0,0 +1,71 @@ +use crate::{wasm_byte_vec_t, wasm_exporttype_vec_t, wasm_importtype_vec_t}; +use crate::{wasm_exporttype_t, wasm_importtype_t, wasm_store_t}; +use wasmtime::{HostRef, Module}; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_module_t { + pub(crate) module: HostRef, + pub(crate) imports: Vec, + pub(crate) exports: Vec, +} + +wasmtime_c_api_macros::declare_ref!(wasm_module_t); + +impl wasm_module_t { + fn anyref(&self) -> wasmtime::AnyRef { + self.module.anyref() + } +} + +#[no_mangle] +pub extern "C" fn wasm_module_new( + store: &wasm_store_t, + binary: &wasm_byte_vec_t, +) -> Option> { + let binary = binary.as_slice(); + let store = &store.store.borrow(); + let module = Module::from_binary(store, binary).ok()?; + let imports = module + .imports() + .iter() + .map(|i| wasm_importtype_t::new(i.clone())) + .collect::>(); + let exports = module + .exports() + .iter() + .map(|e| wasm_exporttype_t::new(e.clone())) + .collect::>(); + Some(Box::new(wasm_module_t { + module: HostRef::new(module), + imports, + exports, + })) +} + +#[no_mangle] +pub extern "C" fn wasm_module_validate(store: &wasm_store_t, binary: &wasm_byte_vec_t) -> bool { + let binary = binary.as_slice(); + let store = &store.store.borrow(); + Module::validate(store, binary).is_ok() +} + +#[no_mangle] +pub extern "C" fn wasm_module_exports(module: &wasm_module_t, out: &mut wasm_exporttype_vec_t) { + let buffer = module + .exports + .iter() + .map(|et| Some(Box::new(et.clone()))) + .collect::>(); + out.set_buffer(buffer); +} + +#[no_mangle] +pub extern "C" fn wasm_module_imports(module: &wasm_module_t, out: &mut wasm_importtype_vec_t) { + let buffer = module + .imports + .iter() + .map(|it| Some(Box::new(it.clone()))) + .collect::>(); + out.set_buffer(buffer); +} diff --git a/crates/c-api/src/ref.rs b/crates/c-api/src/ref.rs new file mode 100644 index 0000000000..4606cc41ef --- /dev/null +++ b/crates/c-api/src/ref.rs @@ -0,0 +1,64 @@ +use crate::HostInfoState; +use std::os::raw::c_void; +use wasmtime::AnyRef; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_ref_t { + pub(crate) r: AnyRef, +} + +wasmtime_c_api_macros::declare_own!(wasm_ref_t); + +#[no_mangle] +pub extern "C" fn wasm_ref_copy(r: &wasm_ref_t) -> Box { + Box::new(r.clone()) +} + +#[no_mangle] +pub extern "C" fn wasm_ref_same(a: &wasm_ref_t, b: &wasm_ref_t) -> bool { + a.r.ptr_eq(&b.r) +} + +pub(crate) fn get_host_info(r: &AnyRef) -> *mut c_void { + let host_info = match r.host_info() { + Some(info) => info, + None => return std::ptr::null_mut(), + }; + match host_info.downcast_ref::() { + Some(state) => state.info, + None => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub extern "C" fn wasm_ref_get_host_info(a: &wasm_ref_t) -> *mut c_void { + get_host_info(&a.r) +} + +pub(crate) fn set_host_info( + r: &AnyRef, + info: *mut c_void, + finalizer: Option, +) { + let info = if info.is_null() && finalizer.is_none() { + None + } else { + Some(Box::new(crate::HostInfoState { info, finalizer }) as Box) + }; + r.set_host_info(info); +} + +#[no_mangle] +pub extern "C" fn wasm_ref_set_host_info(a: &wasm_ref_t, info: *mut c_void) { + set_host_info(&a.r, info, None) +} + +#[no_mangle] +pub extern "C" fn wasm_ref_set_host_info_with_finalizer( + a: &wasm_ref_t, + info: *mut c_void, + finalizer: Option, +) { + set_host_info(&a.r, info, finalizer) +} diff --git a/crates/c-api/src/store.rs b/crates/c-api/src/store.rs new file mode 100644 index 0000000000..159df7da97 --- /dev/null +++ b/crates/c-api/src/store.rs @@ -0,0 +1,18 @@ +use crate::wasm_engine_t; +use wasmtime::{HostRef, Store}; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_store_t { + pub(crate) store: HostRef, +} + +wasmtime_c_api_macros::declare_own!(wasm_store_t); + +#[no_mangle] +pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box { + let engine = &engine.engine; + Box::new(wasm_store_t { + store: HostRef::new(Store::new(&engine.borrow())), + }) +} diff --git a/crates/c-api/src/table.rs b/crates/c-api/src/table.rs new file mode 100644 index 0000000000..8f4c0dca04 --- /dev/null +++ b/crates/c-api/src/table.rs @@ -0,0 +1,120 @@ +use crate::wasm_ref_t; +use crate::{wasm_extern_t, wasm_store_t, wasm_tabletype_t, ExternHost}; +use std::ptr; +use wasmtime::{AnyRef, HostRef, Table, Val}; + +#[derive(Clone)] +#[repr(transparent)] +pub struct wasm_table_t { + ext: wasm_extern_t, +} + +wasmtime_c_api_macros::declare_ref!(wasm_table_t); + +pub type wasm_table_size_t = u32; + +impl wasm_table_t { + pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_table_t> { + match &e.which { + ExternHost::Table(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } + + fn table(&self) -> &HostRef
{ + match &self.ext.which { + ExternHost::Table(t) => t, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } + + fn anyref(&self) -> wasmtime::AnyRef { + self.table().anyref() + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_new( + store: &wasm_store_t, + tt: &wasm_tabletype_t, + init: *mut wasm_ref_t, +) -> Option> { + let init: Val = if !init.is_null() { + Box::from_raw(init).r.into() + } else { + Val::AnyRef(AnyRef::Null) + }; + let table = Table::new(&store.store.borrow(), tt.ty().ty.clone(), init).ok()?; + Some(Box::new(wasm_table_t { + ext: wasm_extern_t { + which: ExternHost::Table(HostRef::new(table)), + }, + })) +} + +#[no_mangle] +pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box { + let ty = t.table().borrow().ty().clone(); + Box::new(wasm_tabletype_t::new(ty)) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_get( + t: &wasm_table_t, + index: wasm_table_size_t, +) -> *mut wasm_ref_t { + match t.table().borrow().get(index) { + Some(val) => into_funcref(val), + None => into_funcref(Val::AnyRef(AnyRef::Null)), + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_set( + t: &wasm_table_t, + index: wasm_table_size_t, + r: *mut wasm_ref_t, +) -> bool { + let val = from_funcref(r); + t.table().borrow().set(index, val).is_ok() +} + +unsafe fn into_funcref(val: Val) -> *mut wasm_ref_t { + if let Val::AnyRef(AnyRef::Null) = val { + return ptr::null_mut(); + } + let anyref = match val.anyref() { + Some(anyref) => anyref, + None => return ptr::null_mut(), + }; + let r = Box::new(wasm_ref_t { r: anyref }); + Box::into_raw(r) +} + +unsafe fn from_funcref(r: *mut wasm_ref_t) -> Val { + if !r.is_null() { + Box::from_raw(r).r.into() + } else { + Val::AnyRef(AnyRef::Null) + } +} + +#[no_mangle] +pub extern "C" fn wasm_table_size(t: &wasm_table_t) -> wasm_table_size_t { + t.table().borrow().size() +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_grow( + t: &wasm_table_t, + delta: wasm_table_size_t, + init: *mut wasm_ref_t, +) -> bool { + let init = from_funcref(init); + t.table().borrow().grow(delta, init).is_ok() +} + +#[no_mangle] +pub extern "C" fn wasm_table_as_extern(t: &wasm_table_t) -> &wasm_extern_t { + &t.ext +} diff --git a/crates/c-api/src/trap.rs b/crates/c-api/src/trap.rs new file mode 100644 index 0000000000..7c536efe1f --- /dev/null +++ b/crates/c-api/src/trap.rs @@ -0,0 +1,80 @@ +use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t}; +use wasmtime::{HostRef, Trap}; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_trap_t { + pub(crate) trap: HostRef, +} + +wasmtime_c_api_macros::declare_ref!(wasm_trap_t); + +impl wasm_trap_t { + fn anyref(&self) -> wasmtime::AnyRef { + self.trap.anyref() + } +} + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_frame_t { + _unused: [u8; 0], +} + +wasmtime_c_api_macros::declare_own!(wasm_frame_t); + +pub type wasm_message_t = wasm_name_t; + +#[no_mangle] +pub extern "C" fn wasm_trap_new( + _store: &wasm_store_t, + message: &wasm_message_t, +) -> Box { + let message = message.as_slice(); + if message[message.len() - 1] != 0 { + panic!("wasm_trap_new message stringz expected"); + } + let message = String::from_utf8_lossy(&message[..message.len() - 1]); + Box::new(wasm_trap_t { + trap: HostRef::new(Trap::new(message)), + }) +} + +#[no_mangle] +pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) { + let mut buffer = Vec::new(); + buffer.extend_from_slice(trap.trap.borrow().message().as_bytes()); + buffer.reserve_exact(1); + buffer.push(0); + out.set_buffer(buffer); +} + +#[no_mangle] +pub extern "C" fn wasm_trap_origin(_trap: &wasm_trap_t) -> Option> { + None +} + +#[no_mangle] +pub extern "C" fn wasm_trap_trace(_trap: &wasm_trap_t, out: &mut wasm_frame_vec_t) { + out.set_buffer(Vec::new()); +} + +#[no_mangle] +pub extern "C" fn wasm_frame_func_index(_arg1: *const wasm_frame_t) -> u32 { + unimplemented!("wasm_frame_func_index") +} + +#[no_mangle] +pub extern "C" fn wasm_frame_func_offset(_arg1: *const wasm_frame_t) -> usize { + unimplemented!("wasm_frame_func_offset") +} + +#[no_mangle] +pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t) -> *mut wasm_instance_t { + unimplemented!("wasm_frame_instance") +} + +#[no_mangle] +pub extern "C" fn wasm_frame_module_offset(_arg1: *const wasm_frame_t) -> usize { + unimplemented!("wasm_frame_module_offset") +} diff --git a/crates/c-api/src/types.rs b/crates/c-api/src/types.rs new file mode 100644 index 0000000000..a80083f1e7 --- /dev/null +++ b/crates/c-api/src/types.rs @@ -0,0 +1,36 @@ +use wasmtime::Limits; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_limits_t { + pub min: u32, + pub max: u32, +} + +impl wasm_limits_t { + pub(crate) fn to_wasmtime(&self) -> Limits { + let max = if self.max == u32::max_value() { + None + } else { + Some(self.max) + }; + Limits::new(self.min, max) + } +} + +mod export; +mod r#extern; +mod func; +mod global; +mod import; +mod memory; +mod table; +mod val; +pub use self::export::*; +pub use self::func::*; +pub use self::global::*; +pub use self::import::*; +pub use self::memory::*; +pub use self::r#extern::*; +pub use self::table::*; +pub use self::val::*; diff --git a/crates/c-api/src/types/export.rs b/crates/c-api/src/types/export.rs new file mode 100644 index 0000000000..90d69b96e6 --- /dev/null +++ b/crates/c-api/src/types/export.rs @@ -0,0 +1,47 @@ +use crate::{wasm_externtype_t, wasm_name_t}; +use once_cell::unsync::OnceCell; +use std::str; +use wasmtime::ExportType; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_exporttype_t { + ty: ExportType, + name_cache: OnceCell, + type_cache: OnceCell, +} + +wasmtime_c_api_macros::declare_ty!(wasm_exporttype_t); + +impl wasm_exporttype_t { + pub(crate) fn new(ty: ExportType) -> wasm_exporttype_t { + wasm_exporttype_t { + ty, + name_cache: OnceCell::new(), + type_cache: OnceCell::new(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_exporttype_new( + name: &mut wasm_name_t, + ty: Box, +) -> Option> { + let name = name.take(); + let name = str::from_utf8(&name).ok()?; + let ty = ExportType::new(name, ty.ty()); + Some(Box::new(wasm_exporttype_t::new(ty))) +} + +#[no_mangle] +pub extern "C" fn wasm_exporttype_name(et: &wasm_exporttype_t) -> &wasm_name_t { + et.name_cache + .get_or_init(|| wasm_name_t::from_name(&et.ty.name())) +} + +#[no_mangle] +pub extern "C" fn wasm_exporttype_type(et: &wasm_exporttype_t) -> &wasm_externtype_t { + et.type_cache + .get_or_init(|| wasm_externtype_t::new(et.ty.ty().clone())) +} diff --git a/crates/c-api/src/types/extern.rs b/crates/c-api/src/types/extern.rs new file mode 100644 index 0000000000..21278a25e7 --- /dev/null +++ b/crates/c-api/src/types/extern.rs @@ -0,0 +1,112 @@ +use crate::{wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t}; +use crate::{CFuncType, CGlobalType, CMemoryType, CTableType}; +use wasmtime::ExternType; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_externtype_t { + pub(crate) which: CExternType, +} + +wasmtime_c_api_macros::declare_ty!(wasm_externtype_t); + +#[derive(Clone)] +pub(crate) enum CExternType { + Func(CFuncType), + Global(CGlobalType), + Memory(CMemoryType), + Table(CTableType), +} + +pub type wasm_externkind_t = u8; + +pub const WASM_EXTERN_FUNC: wasm_externkind_t = 0; +pub const WASM_EXTERN_GLOBAL: wasm_externkind_t = 1; +pub const WASM_EXTERN_TABLE: wasm_externkind_t = 2; +pub const WASM_EXTERN_MEMORY: wasm_externkind_t = 3; + +impl wasm_externtype_t { + pub(crate) fn new(ty: ExternType) -> wasm_externtype_t { + wasm_externtype_t { + which: match ty { + ExternType::Func(f) => CExternType::Func(CFuncType::new(f)), + ExternType::Global(f) => CExternType::Global(CGlobalType::new(f)), + ExternType::Memory(f) => CExternType::Memory(CMemoryType::new(f)), + ExternType::Table(f) => CExternType::Table(CTableType::new(f)), + }, + } + } + + pub(crate) fn ty(&self) -> ExternType { + match &self.which { + CExternType::Func(f) => ExternType::Func(f.ty.clone()), + CExternType::Table(f) => ExternType::Table(f.ty.clone()), + CExternType::Global(f) => ExternType::Global(f.ty.clone()), + CExternType::Memory(f) => ExternType::Memory(f.ty.clone()), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkind_t { + match &et.which { + CExternType::Func(_) => WASM_EXTERN_FUNC, + CExternType::Table(_) => WASM_EXTERN_TABLE, + CExternType::Global(_) => WASM_EXTERN_GLOBAL, + CExternType::Memory(_) => WASM_EXTERN_MEMORY, + } +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_functype(et: &wasm_externtype_t) -> Option<&wasm_functype_t> { + wasm_externtype_as_functype_const(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_functype_const( + et: &wasm_externtype_t, +) -> Option<&wasm_functype_t> { + wasm_functype_t::try_from(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_globaltype( + et: &wasm_externtype_t, +) -> Option<&wasm_globaltype_t> { + wasm_externtype_as_globaltype_const(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_globaltype_const( + et: &wasm_externtype_t, +) -> Option<&wasm_globaltype_t> { + wasm_globaltype_t::try_from(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_tabletype( + et: &wasm_externtype_t, +) -> Option<&wasm_tabletype_t> { + wasm_externtype_as_tabletype_const(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_tabletype_const( + et: &wasm_externtype_t, +) -> Option<&wasm_tabletype_t> { + wasm_tabletype_t::try_from(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_memorytype( + et: &wasm_externtype_t, +) -> Option<&wasm_memorytype_t> { + wasm_externtype_as_memorytype_const(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_memorytype_const( + et: &wasm_externtype_t, +) -> Option<&wasm_memorytype_t> { + wasm_memorytype_t::try_from(et) +} diff --git a/crates/c-api/src/types/func.rs b/crates/c-api/src/types/func.rs new file mode 100644 index 0000000000..0417e3ac32 --- /dev/null +++ b/crates/c-api/src/types/func.rs @@ -0,0 +1,105 @@ +use crate::{wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t, CExternType}; +use once_cell::unsync::OnceCell; +use wasmtime::FuncType; + +#[repr(transparent)] +#[derive(Clone)] +pub struct wasm_functype_t { + ext: wasm_externtype_t, +} + +wasmtime_c_api_macros::declare_ty!(wasm_functype_t); + +#[derive(Clone)] +pub(crate) struct CFuncType { + pub(crate) ty: FuncType, + params_cache: OnceCell, + returns_cache: OnceCell, +} + +impl wasm_functype_t { + pub(crate) fn new(ty: FuncType) -> wasm_functype_t { + wasm_functype_t { + ext: wasm_externtype_t::new(ty.into()), + } + } + + pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_functype_t> { + match &e.which { + CExternType::Func(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } + + pub(crate) fn ty(&self) -> &CFuncType { + match &self.ext.which { + CExternType::Func(f) => &f, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } +} + +impl CFuncType { + pub(crate) fn new(ty: FuncType) -> CFuncType { + CFuncType { + ty, + params_cache: OnceCell::new(), + returns_cache: OnceCell::new(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_functype_new( + params: &mut wasm_valtype_vec_t, + results: &mut wasm_valtype_vec_t, +) -> Box { + let params = params + .take() + .into_iter() + .map(|vt| vt.unwrap().ty.clone()) + .collect::>(); + let results = results + .take() + .into_iter() + .map(|vt| vt.unwrap().ty.clone()) + .collect::>(); + let functype = FuncType::new(params.into_boxed_slice(), results.into_boxed_slice()); + Box::new(wasm_functype_t::new(functype)) +} + +#[no_mangle] +pub extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> &wasm_valtype_vec_t { + let ft = ft.ty(); + ft.params_cache.get_or_init(|| { + ft.ty + .params() + .iter() + .map(|p| Some(Box::new(wasm_valtype_t { ty: p.clone() }))) + .collect::>() + .into() + }) +} + +#[no_mangle] +pub extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> &wasm_valtype_vec_t { + let ft = ft.ty(); + ft.returns_cache.get_or_init(|| { + ft.ty + .results() + .iter() + .map(|p| Some(Box::new(wasm_valtype_t { ty: p.clone() }))) + .collect::>() + .into() + }) +} + +#[no_mangle] +pub extern "C" fn wasm_functype_as_externtype(ty: &wasm_functype_t) -> &wasm_externtype_t { + &ty.ext +} + +#[no_mangle] +pub extern "C" fn wasm_functype_as_externtype_const(ty: &wasm_functype_t) -> &wasm_externtype_t { + &ty.ext +} diff --git a/crates/c-api/src/types/global.rs b/crates/c-api/src/types/global.rs new file mode 100644 index 0000000000..9fde1f304d --- /dev/null +++ b/crates/c-api/src/types/global.rs @@ -0,0 +1,98 @@ +use crate::{wasm_externtype_t, wasm_valtype_t, CExternType}; +use once_cell::unsync::OnceCell; +use wasmtime::GlobalType; + +pub type wasm_mutability_t = u8; + +pub const WASM_CONST: wasm_mutability_t = 0; +pub const WASM_VAR: wasm_mutability_t = 1; + +#[repr(transparent)] +#[derive(Clone)] +pub struct wasm_globaltype_t { + ext: wasm_externtype_t, +} + +wasmtime_c_api_macros::declare_ty!(wasm_globaltype_t); + +#[derive(Clone)] +pub(crate) struct CGlobalType { + pub(crate) ty: GlobalType, + content_cache: OnceCell, +} + +impl wasm_globaltype_t { + pub(crate) fn new(ty: GlobalType) -> wasm_globaltype_t { + wasm_globaltype_t { + ext: wasm_externtype_t::new(ty.into()), + } + } + + pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_globaltype_t> { + match &e.which { + CExternType::Global(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } + + pub(crate) fn ty(&self) -> &CGlobalType { + match &self.ext.which { + CExternType::Global(f) => &f, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } +} + +impl CGlobalType { + pub(crate) fn new(ty: GlobalType) -> CGlobalType { + CGlobalType { + ty, + content_cache: OnceCell::new(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_globaltype_new( + ty: Box, + mutability: wasm_mutability_t, +) -> Option> { + use wasmtime::Mutability::*; + let mutability = match mutability { + WASM_CONST => Const, + WASM_VAR => Var, + _ => return None, + }; + let ty = GlobalType::new(ty.ty.clone(), mutability); + Some(Box::new(wasm_globaltype_t::new(ty))) +} + +#[no_mangle] +pub extern "C" fn wasm_globaltype_content(gt: &wasm_globaltype_t) -> &wasm_valtype_t { + let gt = gt.ty(); + gt.content_cache.get_or_init(|| wasm_valtype_t { + ty: gt.ty.content().clone(), + }) +} + +#[no_mangle] +pub extern "C" fn wasm_globaltype_mutability(gt: &wasm_globaltype_t) -> wasm_mutability_t { + use wasmtime::Mutability::*; + let gt = gt.ty(); + match gt.ty.mutability() { + Const => WASM_CONST, + Var => WASM_VAR, + } +} + +#[no_mangle] +pub extern "C" fn wasm_globaltype_as_externtype(ty: &wasm_globaltype_t) -> &wasm_externtype_t { + &ty.ext +} + +#[no_mangle] +pub extern "C" fn wasm_globaltype_as_externtype_const( + ty: &wasm_globaltype_t, +) -> &wasm_externtype_t { + &ty.ext +} diff --git a/crates/c-api/src/types/import.rs b/crates/c-api/src/types/import.rs new file mode 100644 index 0000000000..66306d2add --- /dev/null +++ b/crates/c-api/src/types/import.rs @@ -0,0 +1,58 @@ +use crate::{wasm_externtype_t, wasm_name_t}; +use once_cell::unsync::OnceCell; +use std::str; +use wasmtime::ImportType; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_importtype_t { + pub(crate) ty: ImportType, + module_cache: OnceCell, + name_cache: OnceCell, + type_cache: OnceCell, +} + +wasmtime_c_api_macros::declare_ty!(wasm_importtype_t); + +impl wasm_importtype_t { + pub(crate) fn new(ty: ImportType) -> wasm_importtype_t { + wasm_importtype_t { + ty, + module_cache: OnceCell::new(), + name_cache: OnceCell::new(), + type_cache: OnceCell::new(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_importtype_new( + module: &mut wasm_name_t, + name: &mut wasm_name_t, + ty: Box, +) -> Option> { + let module = module.take(); + let name = name.take(); + let module = str::from_utf8(&module).ok()?; + let name = str::from_utf8(&name).ok()?; + let ty = ImportType::new(module, name, ty.ty()); + Some(Box::new(wasm_importtype_t::new(ty))) +} + +#[no_mangle] +pub extern "C" fn wasm_importtype_module(it: &wasm_importtype_t) -> &wasm_name_t { + it.module_cache + .get_or_init(|| wasm_name_t::from_name(&it.ty.module())) +} + +#[no_mangle] +pub extern "C" fn wasm_importtype_name(it: &wasm_importtype_t) -> &wasm_name_t { + it.name_cache + .get_or_init(|| wasm_name_t::from_name(&it.ty.name())) +} + +#[no_mangle] +pub extern "C" fn wasm_importtype_type(it: &wasm_importtype_t) -> &wasm_externtype_t { + it.type_cache + .get_or_init(|| wasm_externtype_t::new(it.ty.ty().clone())) +} diff --git a/crates/c-api/src/types/memory.rs b/crates/c-api/src/types/memory.rs new file mode 100644 index 0000000000..59b92c0d64 --- /dev/null +++ b/crates/c-api/src/types/memory.rs @@ -0,0 +1,79 @@ +use crate::{wasm_externtype_t, wasm_limits_t, CExternType}; +use once_cell::unsync::OnceCell; +use wasmtime::MemoryType; + +#[repr(transparent)] +#[derive(Clone)] +pub struct wasm_memorytype_t { + ext: wasm_externtype_t, +} + +wasmtime_c_api_macros::declare_ty!(wasm_memorytype_t); + +#[derive(Clone)] +pub(crate) struct CMemoryType { + pub(crate) ty: MemoryType, + limits_cache: OnceCell, +} + +impl wasm_memorytype_t { + pub(crate) fn new(ty: MemoryType) -> wasm_memorytype_t { + wasm_memorytype_t { + ext: wasm_externtype_t::new(ty.into()), + } + } + + pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_memorytype_t> { + match &e.which { + CExternType::Memory(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } + + pub(crate) fn ty(&self) -> &CMemoryType { + match &self.ext.which { + CExternType::Memory(f) => &f, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } +} + +impl CMemoryType { + pub(crate) fn new(ty: MemoryType) -> CMemoryType { + CMemoryType { + ty, + limits_cache: OnceCell::new(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box { + Box::new(wasm_memorytype_t::new(MemoryType::new( + limits.to_wasmtime(), + ))) +} + +#[no_mangle] +pub extern "C" fn wasm_memorytype_limits(mt: &wasm_memorytype_t) -> &wasm_limits_t { + let mt = mt.ty(); + mt.limits_cache.get_or_init(|| { + let limits = mt.ty.limits(); + wasm_limits_t { + min: limits.min(), + max: limits.max().unwrap_or(u32::max_value()), + } + }) +} + +#[no_mangle] +pub extern "C" fn wasm_memorytype_as_externtype(ty: &wasm_memorytype_t) -> &wasm_externtype_t { + &ty.ext +} + +#[no_mangle] +pub extern "C" fn wasm_memorytype_as_externtype_const( + ty: &wasm_memorytype_t, +) -> &wasm_externtype_t { + &ty.ext +} diff --git a/crates/c-api/src/types/table.rs b/crates/c-api/src/types/table.rs new file mode 100644 index 0000000000..161d893863 --- /dev/null +++ b/crates/c-api/src/types/table.rs @@ -0,0 +1,91 @@ +use crate::{wasm_externtype_t, wasm_limits_t, wasm_valtype_t, CExternType}; +use once_cell::unsync::OnceCell; +use wasmtime::TableType; + +#[repr(transparent)] +#[derive(Clone)] +pub struct wasm_tabletype_t { + ext: wasm_externtype_t, +} + +wasmtime_c_api_macros::declare_ty!(wasm_tabletype_t); + +#[derive(Clone)] +pub(crate) struct CTableType { + pub(crate) ty: TableType, + element_cache: OnceCell, + limits_cache: OnceCell, +} + +impl wasm_tabletype_t { + pub(crate) fn new(ty: TableType) -> wasm_tabletype_t { + wasm_tabletype_t { + ext: wasm_externtype_t::new(ty.into()), + } + } + + pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_tabletype_t> { + match &e.which { + CExternType::Table(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } + + pub(crate) fn ty(&self) -> &CTableType { + match &self.ext.which { + CExternType::Table(f) => &f, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } +} + +impl CTableType { + pub(crate) fn new(ty: TableType) -> CTableType { + CTableType { + ty, + element_cache: OnceCell::new(), + limits_cache: OnceCell::new(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_tabletype_new( + ty: Box, + limits: &wasm_limits_t, +) -> Box { + Box::new(wasm_tabletype_t::new(TableType::new( + ty.ty, + limits.to_wasmtime(), + ))) +} + +#[no_mangle] +pub extern "C" fn wasm_tabletype_element(tt: &wasm_tabletype_t) -> &wasm_valtype_t { + let tt = tt.ty(); + tt.element_cache.get_or_init(|| wasm_valtype_t { + ty: tt.ty.element().clone(), + }) +} + +#[no_mangle] +pub extern "C" fn wasm_tabletype_limits(tt: &wasm_tabletype_t) -> &wasm_limits_t { + let tt = tt.ty(); + tt.limits_cache.get_or_init(|| { + let limits = tt.ty.limits(); + wasm_limits_t { + min: limits.min(), + max: limits.max().unwrap_or(u32::max_value()), + } + }) +} + +#[no_mangle] +pub extern "C" fn wasm_tabletype_as_externtype(ty: &wasm_tabletype_t) -> &wasm_externtype_t { + &ty.ext +} + +#[no_mangle] +pub extern "C" fn wasm_tabletype_as_externtype_const(ty: &wasm_tabletype_t) -> &wasm_externtype_t { + &ty.ext +} diff --git a/crates/c-api/src/types/val.rs b/crates/c-api/src/types/val.rs new file mode 100644 index 0000000000..5333ec6086 --- /dev/null +++ b/crates/c-api/src/types/val.rs @@ -0,0 +1,53 @@ +use wasmtime::ValType; + +#[repr(C)] +#[derive(Clone)] +pub struct wasm_valtype_t { + pub(crate) ty: ValType, +} + +wasmtime_c_api_macros::declare_ty!(wasm_valtype_t); + +pub type wasm_valkind_t = u8; +pub const WASM_I32: wasm_valkind_t = 0; +pub const WASM_I64: wasm_valkind_t = 1; +pub const WASM_F32: wasm_valkind_t = 2; +pub const WASM_F64: wasm_valkind_t = 3; +pub const WASM_ANYREF: wasm_valkind_t = 128; +pub const WASM_FUNCREF: wasm_valkind_t = 129; + +#[no_mangle] +pub extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> Box { + Box::new(wasm_valtype_t { + ty: into_valtype(kind), + }) +} + +#[no_mangle] +pub extern "C" fn wasm_valtype_kind(vt: &wasm_valtype_t) -> wasm_valkind_t { + from_valtype(&vt.ty) +} + +pub(crate) fn into_valtype(kind: wasm_valkind_t) -> ValType { + match kind { + WASM_I32 => ValType::I32, + WASM_I64 => ValType::I64, + WASM_F32 => ValType::F32, + WASM_F64 => ValType::F64, + WASM_ANYREF => ValType::AnyRef, + WASM_FUNCREF => ValType::FuncRef, + _ => panic!("unexpected kind: {}", kind), + } +} + +pub(crate) fn from_valtype(ty: &ValType) -> wasm_valkind_t { + match ty { + ValType::I32 => WASM_I32, + ValType::I64 => WASM_I64, + ValType::F32 => WASM_F32, + ValType::F64 => WASM_F64, + ValType::AnyRef => WASM_ANYREF, + ValType::FuncRef => WASM_FUNCREF, + _ => panic!("wasm_valkind_t has no known conversion for {:?}", ty), + } +} diff --git a/crates/c-api/src/val.rs b/crates/c-api/src/val.rs new file mode 100644 index 0000000000..4cd1cb2abd --- /dev/null +++ b/crates/c-api/src/val.rs @@ -0,0 +1,99 @@ +use crate::{from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, WASM_I32}; +use wasmtime::{Val, ValType}; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct wasm_val_t { + pub kind: wasm_valkind_t, + pub of: wasm_val_union, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union wasm_val_union { + pub i32: i32, + pub i64: i64, + pub u32: u32, + pub u64: u64, + pub f32: f32, + pub f64: f64, + pub ref_: *mut wasm_ref_t, +} + +impl Default for wasm_val_t { + fn default() -> Self { + wasm_val_t { + kind: WASM_I32, + of: wasm_val_union { i32: 0 }, + } + } +} + +impl wasm_val_t { + pub fn from_val(val: &Val) -> wasm_val_t { + match val { + Val::I32(i) => wasm_val_t { + kind: from_valtype(&ValType::I32), + of: wasm_val_union { i32: *i }, + }, + Val::I64(i) => wasm_val_t { + kind: from_valtype(&ValType::I64), + of: wasm_val_union { i64: *i }, + }, + Val::F32(f) => wasm_val_t { + kind: from_valtype(&ValType::F32), + of: wasm_val_union { u32: *f }, + }, + Val::F64(f) => wasm_val_t { + kind: from_valtype(&ValType::F64), + of: wasm_val_union { u64: *f }, + }, + _ => unimplemented!("wasm_val_t::from_val {:?}", val), + } + } + + pub fn set(&mut self, val: Val) { + match val { + Val::I32(i) => { + self.kind = from_valtype(&ValType::I32); + self.of = wasm_val_union { i32: i }; + } + Val::I64(i) => { + self.kind = from_valtype(&ValType::I64); + self.of = wasm_val_union { i64: i }; + } + Val::F32(f) => { + self.kind = from_valtype(&ValType::F32); + self.of = wasm_val_union { u32: f }; + } + Val::F64(f) => { + self.kind = from_valtype(&ValType::F64); + self.of = wasm_val_union { u64: f }; + } + _ => unimplemented!("wasm_val_t::from_val {:?}", val), + } + } + + pub fn val(&self) -> Val { + match into_valtype(self.kind) { + ValType::I32 => Val::from(unsafe { self.of.i32 }), + ValType::I64 => Val::from(unsafe { self.of.i64 }), + ValType::F32 => Val::from(unsafe { self.of.f32 }), + ValType::F64 => Val::from(unsafe { self.of.f64 }), + _ => unimplemented!("wasm_val_t::val {:?}", self.kind), + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_val_copy(out: *mut wasm_val_t, source: &wasm_val_t) { + *out = match into_valtype(source.kind) { + ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => *source, + _ => unimplemented!("wasm_val_copy arg"), + }; +} + +#[no_mangle] +pub extern "C" fn wasm_val_delete(_val: &mut wasm_val_t) { + // currently we only support integers/floats which need no deletion +} diff --git a/crates/c-api/src/vec.rs b/crates/c-api/src/vec.rs new file mode 100644 index 0000000000..252c7987ea --- /dev/null +++ b/crates/c-api/src/vec.rs @@ -0,0 +1,221 @@ +use crate::wasm_valtype_t; +use crate::{wasm_exporttype_t, wasm_extern_t, wasm_frame_t, wasm_val_t}; +use crate::{wasm_externtype_t, wasm_importtype_t, wasm_memorytype_t}; +use crate::{wasm_functype_t, wasm_globaltype_t, wasm_tabletype_t}; +use std::mem; +use std::ptr; +use std::slice; + +pub type wasm_name_t = wasm_byte_vec_t; + +impl wasm_name_t { + pub(crate) fn from_name(name: &str) -> wasm_name_t { + name.to_string().into_bytes().into() + } +} + +macro_rules! declare_vecs { + ( + $(( + name: $name:ident, + ty: $elem_ty:ty, + new: $new:ident, + empty: $empty:ident, + uninit: $uninit:ident, + copy: $copy:ident, + delete: $delete:ident, + ))* + ) => {$( + #[repr(C)] + #[derive(Clone)] + pub struct $name { + size: usize, + data: *mut $elem_ty, + } + + impl $name { + pub fn set_buffer(&mut self, buffer: Vec<$elem_ty>) { + let mut vec = buffer.into_boxed_slice(); + self.size = vec.len(); + self.data = vec.as_mut_ptr(); + mem::forget(vec); + } + + pub fn as_slice(&self) -> &[$elem_ty] { + unsafe { slice::from_raw_parts(self.data, self.size) } + } + + pub fn take(&mut self) -> Vec<$elem_ty> { + if self.data.is_null() { + return Vec::new(); + } + let vec = unsafe { + Vec::from_raw_parts(self.data, self.size, self.size) + }; + self.data = ptr::null_mut(); + self.size = 0; + return vec; + } + } + + impl From> for $name { + fn from(mut vec: Vec<$elem_ty>) -> Self { + assert_eq!(vec.len(), vec.capacity()); + let result = $name { + size: vec.len(), + data: vec.as_mut_ptr(), + }; + mem::forget(vec); + result + } + } + + impl Drop for $name { + fn drop(&mut self) { + drop(self.take()); + } + } + + #[no_mangle] + pub extern "C" fn $empty(out: &mut $name) { + out.size = 0; + out.data = ptr::null_mut(); + } + + #[no_mangle] + pub extern "C" fn $uninit(out: &mut $name, size: usize) { + out.set_buffer(vec![Default::default(); size]); + } + + #[no_mangle] + pub unsafe extern "C" fn $new( + out: &mut $name, + size: usize, + ptr: *const $elem_ty, + ) { + let slice = slice::from_raw_parts(ptr, size); + out.set_buffer(slice.to_vec()); + } + + #[no_mangle] + pub extern "C" fn $copy(out: &mut $name, src: &$name) { + out.set_buffer(src.as_slice().to_vec()); + } + + #[no_mangle] + pub extern "C" fn $delete(out: &mut $name) { + out.take(); + } + )*}; +} + +declare_vecs! { + ( + name: wasm_byte_vec_t, + ty: u8, + new: wasm_byte_vec_new, + empty: wasm_byte_vec_new_empty, + uninit: wasm_byte_vec_new_uninitialized, + copy: wasm_byte_vec_copy, + delete: wasm_byte_vec_delete, + ) + ( + name: wasm_valtype_vec_t, + ty: Option>, + new: wasm_valtype_vec_new, + empty: wasm_valtype_vec_new_empty, + uninit: wasm_valtype_vec_new_uninitialized, + copy: wasm_valtype_vec_copy, + delete: wasm_valtype_vec_delete, + ) + ( + name: wasm_functype_vec_t, + ty: Option>, + new: wasm_functype_vec_new, + empty: wasm_functype_vec_new_empty, + uninit: wasm_functype_vec_new_uninitialized, + copy: wasm_functype_vec_copy, + delete: wasm_functype_vec_delete, + ) + ( + name: wasm_globaltype_vec_t, + ty: Option>, + new: wasm_globaltype_vec_new, + empty: wasm_globaltype_vec_new_empty, + uninit: wasm_globaltype_vec_new_uninitialized, + copy: wasm_globaltype_vec_copy, + delete: wasm_globaltype_vec_delete, + ) + ( + name: wasm_tabletype_vec_t, + ty: Option>, + new: wasm_tabletype_vec_new, + empty: wasm_tabletype_vec_new_empty, + uninit: wasm_tabletype_vec_new_uninitialized, + copy: wasm_tabletype_vec_copy, + delete: wasm_tabletype_vec_delete, + ) + ( + name: wasm_memorytype_vec_t, + ty: Option>, + new: wasm_memorytype_vec_new, + empty: wasm_memorytype_vec_new_empty, + uninit: wasm_memorytype_vec_new_uninitialized, + copy: wasm_memorytype_vec_copy, + delete: wasm_memorytype_vec_delete, + ) + ( + name: wasm_externtype_vec_t, + ty: Option>, + new: wasm_externtype_vec_new, + empty: wasm_externtype_vec_new_empty, + uninit: wasm_externtype_vec_new_uninitialized, + copy: wasm_externtype_vec_copy, + delete: wasm_externtype_vec_delete, + ) + ( + name: wasm_importtype_vec_t, + ty: Option>, + new: wasm_importtype_vec_new, + empty: wasm_importtype_vec_new_empty, + uninit: wasm_importtype_vec_new_uninitialized, + copy: wasm_importtype_vec_copy, + delete: wasm_importtype_vec_delete, + ) + ( + name: wasm_exporttype_vec_t, + ty: Option>, + new: wasm_exporttype_vec_new, + empty: wasm_exporttype_vec_new_empty, + uninit: wasm_exporttype_vec_new_uninitialized, + copy: wasm_exporttype_vec_copy, + delete: wasm_exporttype_vec_delete, + ) + ( + name: wasm_val_vec_t, + ty: wasm_val_t, + new: wasm_val_vec_new, + empty: wasm_val_vec_new_empty, + uninit: wasm_val_vec_new_uninitialized, + copy: wasm_val_vec_copy, + delete: wasm_val_vec_delete, + ) + ( + name: wasm_frame_vec_t, + ty: Option>, + new: wasm_frame_vec_new, + empty: wasm_frame_vec_new_empty, + uninit: wasm_frame_vec_new_uninitialized, + copy: wasm_frame_vec_copy, + delete: wasm_frame_vec_delete, + ) + ( + name: wasm_extern_vec_t, + ty: Option>, + new: wasm_extern_vec_new, + empty: wasm_extern_vec_new_empty, + uninit: wasm_extern_vec_new_uninitialized, + copy: wasm_extern_vec_copy, + delete: wasm_extern_vec_delete, + ) +} diff --git a/crates/c-api/src/wasi.rs b/crates/c-api/src/wasi.rs index c05ff90a6c..96b3798090 100644 --- a/crates/c-api/src/wasi.rs +++ b/crates/c-api/src/wasi.rs @@ -1,5 +1,5 @@ //! The WASI embedding API definitions for Wasmtime. -use crate::{wasm_extern_t, wasm_importtype_t, wasm_store_t, wasm_trap_t, ExternHost, ExternType}; +use crate::{wasm_extern_t, wasm_importtype_t, wasm_store_t, wasm_trap_t, ExternHost}; use anyhow::Result; use std::collections::HashMap; use std::ffi::CStr; @@ -50,37 +50,35 @@ pub struct wasi_config_t { } #[no_mangle] -pub unsafe extern "C" fn wasi_config_new() -> *mut wasi_config_t { - Box::into_raw(Box::new(wasi_config_t::default())) +pub extern "C" fn wasi_config_new() -> Box { + Box::new(wasi_config_t::default()) } #[no_mangle] -pub unsafe extern "C" fn wasi_config_delete(config: *mut wasi_config_t) { - drop(Box::from_raw(config)); -} +pub extern "C" fn wasi_config_delete(_config: Box) {} #[no_mangle] pub unsafe extern "C" fn wasi_config_set_argv( - config: *mut wasi_config_t, + config: &mut wasi_config_t, argc: c_int, argv: *const *const c_char, ) { - (*config).args = slice::from_raw_parts(argv, argc as usize) + config.args = slice::from_raw_parts(argv, argc as usize) .iter() .map(|p| CStr::from_ptr(*p).to_bytes().to_owned()) .collect(); - (*config).inherit_args = false; + config.inherit_args = false; } #[no_mangle] -pub unsafe extern "C" fn wasi_config_inherit_argv(config: *mut wasi_config_t) { - (*config).args.clear(); - (*config).inherit_args = true; +pub extern "C" fn wasi_config_inherit_argv(config: &mut wasi_config_t) { + config.args.clear(); + config.inherit_args = true; } #[no_mangle] pub unsafe extern "C" fn wasi_config_set_env( - config: *mut wasi_config_t, + config: &mut wasi_config_t, envc: c_int, names: *const *const c_char, values: *const *const c_char, @@ -88,7 +86,7 @@ pub unsafe extern "C" fn wasi_config_set_env( let names = slice::from_raw_parts(names, envc as usize); let values = slice::from_raw_parts(values, envc as usize); - (*config).env = names + config.env = names .iter() .map(|p| CStr::from_ptr(*p).to_bytes().to_owned()) .zip( @@ -97,18 +95,18 @@ pub unsafe extern "C" fn wasi_config_set_env( .map(|p| CStr::from_ptr(*p).to_bytes().to_owned()), ) .collect(); - (*config).inherit_env = false; + config.inherit_env = false; } #[no_mangle] -pub unsafe extern "C" fn wasi_config_inherit_env(config: *mut wasi_config_t) { - (*config).env.clear(); - (*config).inherit_env = true; +pub extern "C" fn wasi_config_inherit_env(config: &mut wasi_config_t) { + config.env.clear(); + config.inherit_env = true; } #[no_mangle] pub unsafe extern "C" fn wasi_config_set_stdin_file( - config: *mut wasi_config_t, + config: &mut wasi_config_t, path: *const c_char, ) -> bool { let file = match open_file(path) { @@ -116,21 +114,21 @@ pub unsafe extern "C" fn wasi_config_set_stdin_file( None => return false, }; - (*config).stdin = Some(file); - (*config).inherit_stdin = false; + config.stdin = Some(file); + config.inherit_stdin = false; true } #[no_mangle] -pub unsafe extern "C" fn wasi_config_inherit_stdin(config: *mut wasi_config_t) { - (*config).stdin = None; - (*config).inherit_stdin = true; +pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { + config.stdin = None; + config.inherit_stdin = true; } #[no_mangle] pub unsafe extern "C" fn wasi_config_set_stdout_file( - config: *mut wasi_config_t, + config: &mut wasi_config_t, path: *const c_char, ) -> bool { let file = match create_file(path) { @@ -138,21 +136,21 @@ pub unsafe extern "C" fn wasi_config_set_stdout_file( None => return false, }; - (*config).stdout = Some(file); - (*config).inherit_stdout = false; + config.stdout = Some(file); + config.inherit_stdout = false; true } #[no_mangle] -pub unsafe extern "C" fn wasi_config_inherit_stdout(config: *mut wasi_config_t) { - (*config).stdout = None; - (*config).inherit_stdout = true; +pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { + config.stdout = None; + config.inherit_stdout = true; } #[no_mangle] pub unsafe extern "C" fn wasi_config_set_stderr_file( - config: *mut wasi_config_t, + config: &mut wasi_config_t, path: *const c_char, ) -> bool { let file = match create_file(path) { @@ -167,14 +165,14 @@ pub unsafe extern "C" fn wasi_config_set_stderr_file( } #[no_mangle] -pub unsafe extern "C" fn wasi_config_inherit_stderr(config: *mut wasi_config_t) { - (*config).stderr = None; - (*config).inherit_stderr = true; +pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { + config.stderr = None; + config.inherit_stderr = true; } #[no_mangle] pub unsafe extern "C" fn wasi_config_preopen_dir( - config: *mut wasi_config_t, + config: &mut wasi_config_t, path: *const c_char, guest_path: *const c_char, ) -> bool { @@ -278,13 +276,12 @@ impl wasi_instance_t { #[no_mangle] pub unsafe extern "C" fn wasi_instance_new( - store: *mut wasm_store_t, + store: &wasm_store_t, name: *const c_char, - config: *mut wasi_config_t, - trap: *mut *mut wasm_trap_t, -) -> *mut wasi_instance_t { - let store = &(*store).store.borrow(); - let config = Box::from_raw(config); + config: Box, + trap: &mut *mut wasm_trap_t, +) -> Option> { + let store = &store.store.borrow(); let result = match CStr::from_ptr(name).to_str().unwrap_or("") { "wasi_snapshot_preview1" => create_preview1_instance(store, *config), @@ -293,70 +290,58 @@ pub unsafe extern "C" fn wasi_instance_new( }; match result { - Ok(wasi) => Box::into_raw(Box::new(wasi_instance_t { + Ok(wasi) => Some(Box::new(wasi_instance_t { wasi, export_cache: HashMap::new(), })), Err(e) => { - (*trap) = Box::into_raw(Box::new(wasm_trap_t { + *trap = Box::into_raw(Box::new(wasm_trap_t { trap: HostRef::new(Trap::new(e.to_string())), })); - std::ptr::null_mut() + None } } } #[no_mangle] -pub unsafe extern "C" fn wasi_instance_delete(instance: *mut wasi_instance_t) { - drop(Box::from_raw(instance)); -} +pub extern "C" fn wasi_instance_delete(_instance: Box) {} #[no_mangle] -pub unsafe extern "C" fn wasi_instance_bind_import( - instance: *mut wasi_instance_t, - import: *const wasm_importtype_t, -) -> *const wasm_extern_t { - // The import should be a function (WASI only exports functions) - let func_type = match (*import).ty.ty() { - ExternType::Func(f) => f, - _ => return std::ptr::null_mut(), - }; +pub extern "C" fn wasi_instance_bind_import<'a>( + instance: &'a mut wasi_instance_t, + import: &wasm_importtype_t, +) -> Option<&'a wasm_extern_t> { + let module = import.ty.module(); + let name = import.ty.name(); - let module = (*import).ty.module(); - let name = (*import).ty.name(); - - let import = match &(*instance).wasi { + let export = match &instance.wasi { WasiInstance::Preview1(wasi) => { if module != "wasi_snapshot_preview1" { - return std::ptr::null(); + return None; } - wasi.get_export(name) + wasi.get_export(name)? } WasiInstance::Snapshot0(wasi) => { if module != "wasi_unstable" { - return std::ptr::null(); + return None; } - wasi.get_export(name) + wasi.get_export(name)? } }; - match import { - Some(export) => { - if export.ty() != func_type { - return std::ptr::null_mut(); - } - - &**(*instance) - .export_cache - .entry(name.to_string()) - .or_insert_with(|| { - Box::new(wasm_extern_t { - which: ExternHost::Func(HostRef::new(export.clone())), - }) - }) as *const wasm_extern_t - } - None => std::ptr::null_mut(), + if export.ty() != import.ty.ty().func()? { + return None; } + + let entry = instance + .export_cache + .entry(name.to_string()) + .or_insert_with(|| { + Box::new(wasm_extern_t { + which: ExternHost::Func(HostRef::new(export.clone())), + }) + }); + Some(entry) } diff --git a/crates/c-api/src/wat2wasm.rs b/crates/c-api/src/wat2wasm.rs new file mode 100644 index 0000000000..f0d9661636 --- /dev/null +++ b/crates/c-api/src/wat2wasm.rs @@ -0,0 +1,31 @@ +use crate::wasm_byte_vec_t; +use std::str; + +#[no_mangle] +pub extern "C" fn wasmtime_wat2wasm( + wat: &wasm_byte_vec_t, + ret: &mut wasm_byte_vec_t, + error: Option<&mut wasm_byte_vec_t>, +) -> bool { + let wat = match str::from_utf8(wat.as_slice()) { + Ok(s) => s, + Err(_) => { + if let Some(error) = error { + error.set_buffer(b"input was not valid utf-8".to_vec()); + } + return false; + } + }; + match wat::parse_str(wat) { + Ok(bytes) => { + ret.set_buffer(bytes.into()); + true + } + Err(e) => { + if let Some(error) = error { + error.set_buffer(e.to_string().into_bytes()); + } + false + } + } +}