Refactor and fill out wasmtime's C API (#1415)

* Refactor and improve safety of C API

This commit is intended to be a relatively large refactoring of the C
API which is targeted at improving the safety of our C API definitions.
Not all of the APIs have been updated yet but this is intended to be the
start.

The goal here is to make as many functions safe as we can, expressing
inputs/outputs as native Rust types rather than raw pointers wherever
possible. For example instead of `*const wasm_foo_t` we'd take
`&wasm_foo_t`. Instead of returning `*mut wasm_foo_t` we'd return
`Box<wasm_foo_t>`. No ABI/API changes are intended from this commit,
it's supposed to only change how we define all these functions
internally.

This commit also additionally implements a few more API bindings for
exposed vector types by unifying everything into one macro.

Finally, this commit moves many internal caches in the C API to the
`OnceCell` type which provides a safe interface for one-time
initialization.

* Split apart monolithic C API `lib.rs`

This commit splits the monolithic `src/lib.rs` in the C API crate into
lots of smaller files. The goal here is to make this a bit more readable
and digestable. Each module now contains only API bindings for a
particular type, roughly organized around the grouping in the wasm.h
header file already.

A few more extensions were added, such as filling out `*_as_*`
conversions with both const and non-const versions. Additionally many
APIs were made safer in the same style as the previous commit, generally
preferring Rust types rather than raw pointer types.

Overall no functional change is intended here, it should be mostly just
code movement and minor refactorings!

* Make a few wasi C bindings safer

Use safe Rust types where we can and touch up a few APIs here and there.

* Implement `wasm_*type_as_externtype*` APIs

This commit restructures `wasm_externtype_t` to be similar to
`wasm_extern_t` so type conversion between the `*_extern_*` variants to
the concrete variants are all simple casts. (checked in the case of
general to concrete, of course).

* Consistently imlpement host info functions in the API

This commit adds a small macro crate which is then used to consistently
define the various host-info-related functions in the C API. The goal
here is to try to mirror what the `wasm.h` header provides to provide a
full implementation of the header.
This commit is contained in:
Alex Crichton
2020-03-27 09:50:32 -05:00
committed by GitHub
parent 157aab50f5
commit 6ef09359b0
36 changed files with 2503 additions and 1974 deletions

View File

@@ -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]

View File

@@ -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)
///////////////////////////////////////////////////////////////////////////////

View File

@@ -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"

View File

@@ -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<extern "C" fn(*mut std::os::raw::c_void)>,
) {
crate::r#ref::set_host_info(&a.anyref(), info, finalizer)
}
#[no_mangle]
pub extern fn #as_ref(a: &#ty) -> Box<crate::wasm_ref_t> {
let r = a.anyref();
Box::new(crate::wasm_ref_t { r })
}
#[no_mangle]
pub extern fn #as_ref_const(a: &#ty) -> Box<crate::wasm_ref_t> {
#as_ref(a)
}
// TODO: implement `wasm_ref_as_#name#`
// TODO: implement `wasm_ref_as_#name#_const`
})
.into()
}

119
crates/c-api/src/config.rs Normal file
View File

@@ -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<wasm_config_t> {
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()
}

View File

@@ -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<Engine>,
}
wasmtime_c_api_macros::declare_own!(wasm_engine_t);
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
Box::new(wasm_engine_t {
engine: HostRef::new(Engine::default()),
})
}
#[no_mangle]
pub extern "C" fn wasm_engine_new_with_config(c: Box<wasm_config_t>) -> Box<wasm_engine_t> {
let config = c.config;
Box::new(wasm_engine_t {
engine: HostRef::new(Engine::new(&config)),
})
}

View File

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

View File

@@ -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<Func>),
Global(HostRef<Global>),
Memory(HostRef<Memory>),
Table(HostRef<Table>),
}
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<wasm_externtype_t> {
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)
}

243
crates/c-api/src/func.rs Normal file
View File

@@ -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<Box<wasm_trap_t>>;
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<Box<wasm_trap_t>>;
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<Box<wasm_trap_t>>;
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<Box<wasm_trap_t>>;
struct Finalizer {
env: *mut c_void,
finalizer: Option<extern "C" fn(*mut c_void)>,
}
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<Func> {
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<Box<wasm_trap_t>> + 'static,
) -> Box<wasm_func_t> {
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::<Vec<_>>();
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<wasm_func_t> {
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<wasm_func_t> {
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<extern "C" fn(arg1: *mut std::ffi::c_void)>,
) -> Box<wasm_func_t> {
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<extern "C" fn(*mut c_void)>,
) -> Box<wasm_func_t> {
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(&params)));
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::<String>() {
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<wasm_functype_t> {
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<Box<wasm_extern_t>> {
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 }))
}

View File

@@ -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<Global> {
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<Box<wasm_global_t>> {
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<wasm_globaltype_t> {
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);
}

View File

@@ -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<Instance>,
exports_cache: RefCell<Option<Vec<ExternHost>>>,
}
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<wasm_extern_t>,
result: Option<&mut *mut wasm_trap_t>,
) -> Option<Box<wasm_instance_t>> {
let mut externs: Vec<Extern> = 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<Instance>,
result: Option<&mut *mut wasm_trap_t>,
) -> Option<Box<wasm_instance_t>> {
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::<Trap>() {
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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -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<wasmtime_linker_t> {
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<wasmtime_linker_t>) {}
#[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<Box<wasm_instance_t>> {
let linker = &linker.linker;
let result = linker.instantiate(&module.module.borrow());
super::instance::handle_instantiate(result, trap)
}

View File

@@ -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<Memory> {
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<wasm_memory_t> {
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<wasm_memorytype_t> {
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()
}

View File

@@ -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<Module>,
pub(crate) imports: Vec<wasm_importtype_t>,
pub(crate) exports: Vec<wasm_exporttype_t>,
}
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<Box<wasm_module_t>> {
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::<Vec<_>>();
let exports = module
.exports()
.iter()
.map(|e| wasm_exporttype_t::new(e.clone()))
.collect::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
out.set_buffer(buffer);
}

64
crates/c-api/src/ref.rs Normal file
View File

@@ -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<wasm_ref_t> {
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::<HostInfoState>() {
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<extern "C" fn(*mut c_void)>,
) {
let info = if info.is_null() && finalizer.is_none() {
None
} else {
Some(Box::new(crate::HostInfoState { info, finalizer }) as Box<dyn std::any::Any>)
};
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<extern "C" fn(*mut c_void)>,
) {
set_host_info(&a.r, info, finalizer)
}

18
crates/c-api/src/store.rs Normal file
View File

@@ -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<Store>,
}
wasmtime_c_api_macros::declare_own!(wasm_store_t);
#[no_mangle]
pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> {
let engine = &engine.engine;
Box::new(wasm_store_t {
store: HostRef::new(Store::new(&engine.borrow())),
})
}

120
crates/c-api/src/table.rs Normal file
View File

@@ -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<Table> {
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<Box<wasm_table_t>> {
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<wasm_tabletype_t> {
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
}

80
crates/c-api/src/trap.rs Normal file
View File

@@ -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<Trap>,
}
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<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]);
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<Box<wasm_frame_t>> {
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")
}

36
crates/c-api/src/types.rs Normal file
View File

@@ -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::*;

View File

@@ -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<wasm_name_t>,
type_cache: OnceCell<wasm_externtype_t>,
}
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<wasm_externtype_t>,
) -> Option<Box<wasm_exporttype_t>> {
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()))
}

View File

@@ -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)
}

View File

@@ -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<wasm_valtype_vec_t>,
returns_cache: OnceCell<wasm_valtype_vec_t>,
}
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<wasm_functype_t> {
let params = params
.take()
.into_iter()
.map(|vt| vt.unwrap().ty.clone())
.collect::<Vec<_>>();
let results = results
.take()
.into_iter()
.map(|vt| vt.unwrap().ty.clone())
.collect::<Vec<_>>();
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::<Vec<_>>()
.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::<Vec<_>>()
.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
}

View File

@@ -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<wasm_valtype_t>,
}
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<wasm_valtype_t>,
mutability: wasm_mutability_t,
) -> Option<Box<wasm_globaltype_t>> {
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
}

View File

@@ -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<wasm_name_t>,
name_cache: OnceCell<wasm_name_t>,
type_cache: OnceCell<wasm_externtype_t>,
}
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<wasm_externtype_t>,
) -> Option<Box<wasm_importtype_t>> {
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()))
}

View File

@@ -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<wasm_limits_t>,
}
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<wasm_memorytype_t> {
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
}

View File

@@ -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<wasm_valtype_t>,
limits_cache: OnceCell<wasm_limits_t>,
}
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<wasm_valtype_t>,
limits: &wasm_limits_t,
) -> Box<wasm_tabletype_t> {
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
}

View File

@@ -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<wasm_valtype_t> {
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),
}
}

99
crates/c-api/src/val.rs Normal file
View File

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

221
crates/c-api/src/vec.rs Normal file
View File

@@ -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<Vec<$elem_ty>> 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<Box<wasm_valtype_t>>,
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<Box<wasm_functype_t>>,
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<Box<wasm_globaltype_t>>,
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<Box<wasm_tabletype_t>>,
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<Box<wasm_memorytype_t>>,
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<Box<wasm_externtype_t>>,
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<Box<wasm_importtype_t>>,
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<Box<wasm_exporttype_t>>,
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<Box<wasm_frame_t>>,
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<Box<wasm_extern_t>>,
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,
)
}

View File

@@ -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<wasi_config_t> {
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<wasi_config_t>) {}
#[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<wasi_config_t>,
trap: &mut *mut wasm_trap_t,
) -> Option<Box<wasi_instance_t>> {
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<wasi_instance_t>) {}
#[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)
}

View File

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