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 + } + } +}