Implement RFC 11: Redesigning Wasmtime's APIs (#2897)

Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
This commit is contained in:
Alex Crichton
2021-06-03 09:10:53 -05:00
committed by GitHub
parent a5a28b1c5b
commit 7a1b7cdf92
233 changed files with 13349 additions and 11997 deletions

View File

@@ -1,6 +1,5 @@
use crate::{wasm_name_t, wasm_trap_t};
use crate::wasm_name_t;
use anyhow::{anyhow, Error, Result};
use wasmtime::Trap;
#[repr(C)]
pub struct wasmtime_error_t {
@@ -9,12 +8,6 @@ pub struct wasmtime_error_t {
wasmtime_c_api_macros::declare_own!(wasmtime_error_t);
impl wasmtime_error_t {
pub(crate) fn to_trap(self) -> Box<wasm_trap_t> {
Box::new(wasm_trap_t::new(Trap::from(self.error)))
}
}
impl From<Error> for wasmtime_error_t {
fn from(error: Error) -> wasmtime_error_t {
wasmtime_error_t { error }

View File

@@ -1,11 +1,13 @@
use crate::{
wasm_externkind_t, wasm_externtype_t, wasm_func_t, wasm_global_t, wasm_instance_t,
wasm_memory_t, wasm_module_t, wasm_table_t,
wasm_memory_t, wasm_module_t, wasm_table_t, wasmtime_module_t, CStoreContext, StoreRef,
};
use wasmtime::Extern;
use std::mem::ManuallyDrop;
use wasmtime::{Extern, Func, Global, Instance, Memory, Table};
#[derive(Clone)]
pub struct wasm_extern_t {
pub(crate) store: StoreRef,
pub(crate) which: Extern,
}
@@ -24,8 +26,8 @@ pub extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t {
}
#[no_mangle]
pub extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
Box::new(wasm_externtype_t::new(e.which.ty()))
pub unsafe extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
Box::new(wasm_externtype_t::new(e.which.ty(&e.store.context())))
}
#[no_mangle]
@@ -87,3 +89,97 @@ pub extern "C" fn wasm_extern_as_instance(e: &wasm_extern_t) -> Option<&wasm_ins
pub extern "C" fn wasm_extern_as_instance_const(e: &wasm_extern_t) -> Option<&wasm_instance_t> {
wasm_extern_as_instance(e)
}
#[repr(C)]
pub struct wasmtime_extern_t {
pub kind: wasmtime_extern_kind_t,
pub of: wasmtime_extern_union,
}
pub type wasmtime_extern_kind_t = u8;
pub const WASMTIME_EXTERN_FUNC: wasmtime_extern_kind_t = 0;
pub const WASMTIME_EXTERN_GLOBAL: wasmtime_extern_kind_t = 1;
pub const WASMTIME_EXTERN_TABLE: wasmtime_extern_kind_t = 2;
pub const WASMTIME_EXTERN_MEMORY: wasmtime_extern_kind_t = 3;
pub const WASMTIME_EXTERN_INSTANCE: wasmtime_extern_kind_t = 4;
pub const WASMTIME_EXTERN_MODULE: wasmtime_extern_kind_t = 5;
#[repr(C)]
pub union wasmtime_extern_union {
pub func: Func,
pub table: Table,
pub global: Global,
pub instance: Instance,
pub memory: Memory,
pub module: ManuallyDrop<Box<wasmtime_module_t>>,
}
impl wasmtime_extern_t {
pub unsafe fn to_extern(&self) -> Extern {
match self.kind {
WASMTIME_EXTERN_FUNC => Extern::Func(self.of.func),
WASMTIME_EXTERN_GLOBAL => Extern::Global(self.of.global),
WASMTIME_EXTERN_TABLE => Extern::Table(self.of.table),
WASMTIME_EXTERN_MEMORY => Extern::Memory(self.of.memory),
WASMTIME_EXTERN_INSTANCE => Extern::Instance(self.of.instance),
WASMTIME_EXTERN_MODULE => Extern::Module(self.of.module.module.clone()),
other => panic!("unknown wasm_extern_kind_t: {}", other),
}
}
}
impl From<Extern> for wasmtime_extern_t {
fn from(item: Extern) -> wasmtime_extern_t {
match item {
Extern::Func(func) => wasmtime_extern_t {
kind: WASMTIME_EXTERN_FUNC,
of: wasmtime_extern_union { func },
},
Extern::Global(global) => wasmtime_extern_t {
kind: WASMTIME_EXTERN_GLOBAL,
of: wasmtime_extern_union { global },
},
Extern::Table(table) => wasmtime_extern_t {
kind: WASMTIME_EXTERN_TABLE,
of: wasmtime_extern_union { table },
},
Extern::Memory(memory) => wasmtime_extern_t {
kind: WASMTIME_EXTERN_MEMORY,
of: wasmtime_extern_union { memory },
},
Extern::Instance(instance) => wasmtime_extern_t {
kind: WASMTIME_EXTERN_INSTANCE,
of: wasmtime_extern_union { instance },
},
Extern::Module(module) => wasmtime_extern_t {
kind: WASMTIME_EXTERN_MODULE,
of: wasmtime_extern_union {
module: ManuallyDrop::new(Box::new(wasmtime_module_t { module })),
},
},
}
}
}
impl Drop for wasmtime_extern_t {
fn drop(&mut self) {
if self.kind == WASMTIME_EXTERN_MODULE {
unsafe {
ManuallyDrop::drop(&mut self.of.module);
}
}
}
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_extern_delete(e: &mut ManuallyDrop<wasmtime_extern_t>) {
ManuallyDrop::drop(e);
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_extern_type(
store: CStoreContext<'_>,
e: &wasmtime_extern_t,
) -> Box<wasm_externtype_t> {
Box::new(wasm_externtype_t::new(e.to_extern().ty(store)))
}

View File

@@ -1,12 +1,15 @@
use crate::{wasm_extern_t, wasm_functype_t, wasm_store_t, wasm_val_t, wasm_val_vec_t};
use crate::{wasm_name_t, wasm_trap_t, wasmtime_error_t};
use crate::wasm_trap_t;
use crate::{
wasm_extern_t, wasm_functype_t, wasm_store_t, wasm_val_t, wasm_val_vec_t, wasmtime_error_t,
wasmtime_extern_t, wasmtime_val_t, wasmtime_val_union, CStoreContext, CStoreContextMut,
};
use anyhow::anyhow;
use std::ffi::c_void;
use std::mem::MaybeUninit;
use std::panic::{self, AssertUnwindSafe};
use std::ptr;
use std::str;
use wasmtime::{Caller, Extern, Func, Trap, Val};
use wasmtime::{AsContextMut, Caller, Extern, Func, Trap};
#[derive(Clone)]
#[repr(transparent)]
@@ -16,11 +19,6 @@ pub struct wasm_func_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_vec_t,
results: *mut wasm_val_vec_t,
@@ -32,32 +30,6 @@ pub type wasm_func_callback_with_env_t = extern "C" fn(
results: *mut wasm_val_vec_t,
) -> Option<Box<wasm_trap_t>>;
pub type wasmtime_func_callback_t = extern "C" fn(
caller: *const wasmtime_caller_t,
args: *const wasm_val_vec_t,
results: *mut wasm_val_vec_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_vec_t,
results: *mut wasm_val_vec_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 {
@@ -66,150 +38,90 @@ impl wasm_func_t {
}
}
pub(crate) fn func(&self) -> &Func {
match &self.ext.which {
pub(crate) fn func(&self) -> Func {
match self.ext.which {
Extern::Func(f) => f,
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
}
impl From<Func> for wasm_func_t {
fn from(func: Func) -> wasm_func_t {
wasm_func_t {
ext: wasm_extern_t { which: func.into() },
}
}
}
fn create_function(
store: &wasm_store_t,
unsafe fn create_function(
store: &mut wasm_store_t,
ty: &wasm_functype_t,
func: impl Fn(Caller<'_>, *const wasm_val_vec_t, *mut wasm_val_vec_t) -> Option<Box<wasm_trap_t>>
func: impl Fn(*const wasm_val_vec_t, *mut wasm_val_vec_t) -> Option<Box<wasm_trap_t>>
+ Send
+ Sync
+ 'static,
) -> Box<wasm_func_t> {
let store = &store.store;
let ty = ty.ty().ty.clone();
let func = Func::new(store, ty, move |caller, params, results| {
let params: wasm_val_vec_t = params
.iter()
.cloned()
.map(|p| wasm_val_t::from_val(p))
.collect::<Vec<_>>()
.into();
let mut out_results: wasm_val_vec_t = vec![wasm_val_t::default(); results.len()].into();
let out = func(caller, &params, &mut out_results);
if let Some(trap) = out {
return Err(trap.trap.clone());
}
let func = Func::new(
store.store.context_mut(),
ty,
move |_caller, params, results| {
let params: wasm_val_vec_t = params
.iter()
.cloned()
.map(|p| wasm_val_t::from_val(p))
.collect::<Vec<_>>()
.into();
let mut out_results: wasm_val_vec_t = vec![wasm_val_t::default(); results.len()].into();
let out = func(&params, &mut out_results);
if let Some(trap) = out {
return Err(trap.trap.clone());
}
let out_results = out_results.as_slice();
for i in 0..results.len() {
results[i] = out_results[i].val();
}
Ok(())
});
Box::new(func.into())
let out_results = out_results.as_slice();
for i in 0..results.len() {
results[i] = out_results[i].val();
}
Ok(())
},
);
Box::new(wasm_func_t {
ext: wasm_extern_t {
store: store.store.clone(),
which: func.into(),
},
})
}
#[no_mangle]
pub extern "C" fn wasm_func_new(
store: &wasm_store_t,
pub unsafe extern "C" fn wasm_func_new(
store: &mut 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)
})
create_function(store, ty, move |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,
pub unsafe extern "C" fn wasm_func_new_with_env(
store: &mut wasm_store_t,
ty: &wasm_functype_t,
callback: wasm_func_callback_with_env_t,
env: *mut c_void,
data: *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,
)
let finalizer = crate::ForeignData { data, finalizer };
create_function(store, ty, move |params, results| {
callback(finalizer.data, params, results)
})
}
#[no_mangle]
pub unsafe extern "C" fn wasm_func_call(
wasm_func: &wasm_func_t,
func: &mut wasm_func_t,
args: *const wasm_val_vec_t,
results: *mut wasm_val_vec_t,
) -> *mut wasm_trap_t {
let mut trap = ptr::null_mut();
let error = _wasmtime_func_call(
wasm_func,
(*args).as_slice(),
(*results).as_uninit_slice(),
&mut trap,
);
match error {
Some(err) => Box::into_raw(err.to_trap()),
None => trap,
}
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_func_call(
func: &wasm_func_t,
args: *const wasm_val_vec_t,
results: *mut wasm_val_vec_t,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
_wasmtime_func_call(
func,
(*args).as_slice(),
(*results).as_uninit_slice(),
trap_ptr,
)
}
fn _wasmtime_func_call(
func: &wasm_func_t,
args: &[wasm_val_t],
results: &mut [MaybeUninit<wasm_val_t>],
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
let func = func.func();
if results.len() != func.result_arity() {
return Some(Box::new(anyhow!("wrong number of results provided").into()));
let f = func.func();
let results = (*results).as_uninit_slice();
let args = (*args).as_slice();
if results.len() != f.ty(func.ext.store.context()).results().len() {
return Box::into_raw(Box::new(wasm_trap_t::new(
anyhow!("wrong number of results provided").into(),
)));
}
let params = args.iter().map(|i| i.val()).collect::<Vec<_>>();
@@ -217,20 +129,19 @@ fn _wasmtime_func_call(
// 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)));
let result = panic::catch_unwind(AssertUnwindSafe(|| {
f.call(func.ext.store.context_mut(), &params)
}));
match result {
Ok(Ok(out)) => {
for (slot, val) in results.iter_mut().zip(out.into_vec().into_iter()) {
crate::initialize(slot, wasm_val_t::from_val(val));
}
None
ptr::null_mut()
}
Ok(Err(trap)) => match trap.downcast::<Trap>() {
Ok(trap) => {
*trap_ptr = Box::into_raw(Box::new(wasm_trap_t::new(trap)));
None
}
Err(err) => Some(Box::new(err.into())),
Ok(trap) => Box::into_raw(Box::new(wasm_trap_t::new(trap))),
Err(err) => Box::into_raw(Box::new(wasm_trap_t::new(err.into()))),
},
Err(panic) => {
let trap = if let Some(msg) = panic.downcast_ref::<String>() {
@@ -241,25 +152,24 @@ fn _wasmtime_func_call(
Trap::new("rust panic happened")
};
let trap = Box::new(wasm_trap_t::new(trap));
*trap_ptr = Box::into_raw(trap);
None
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().ty()))
pub unsafe extern "C" fn wasm_func_type(f: &wasm_func_t) -> Box<wasm_functype_t> {
Box::new(wasm_functype_t::new(f.func().ty(f.ext.store.context())))
}
#[no_mangle]
pub extern "C" fn wasm_func_param_arity(f: &wasm_func_t) -> usize {
f.func().param_arity()
pub unsafe extern "C" fn wasm_func_param_arity(f: &wasm_func_t) -> usize {
f.func().ty(f.ext.store.context()).params().len()
}
#[no_mangle]
pub extern "C" fn wasm_func_result_arity(f: &wasm_func_t) -> usize {
f.func().result_arity()
pub unsafe extern "C" fn wasm_func_result_arity(f: &wasm_func_t) -> usize {
f.func().ty(f.ext.store.context()).results().len()
}
#[no_mangle]
@@ -268,29 +178,150 @@ pub extern "C" fn wasm_func_as_extern(f: &mut wasm_func_t) -> &mut wasm_extern_t
}
#[no_mangle]
pub 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 which = caller.caller.get_export(name)?;
Some(Box::new(wasm_extern_t { which }))
pub extern "C" fn wasm_func_as_extern_const(f: &wasm_func_t) -> &wasm_extern_t {
&(*f).ext
}
#[repr(C)]
pub struct wasmtime_caller_t<'a> {
caller: Caller<'a, crate::StoreData>,
}
#[no_mangle]
pub extern "C" fn wasmtime_func_as_funcref(
func: &wasm_func_t,
funcrefp: &mut MaybeUninit<wasm_val_t>,
pub unsafe extern "C" fn wasmtime_func_new(
store: CStoreContextMut<'_>,
ty: &wasm_functype_t,
callback: extern "C" fn(
*mut c_void,
*mut wasmtime_caller_t,
*const wasmtime_val_t,
usize,
*mut wasmtime_val_t,
usize,
) -> Option<Box<wasm_trap_t>>,
data: *mut c_void,
finalizer: Option<extern "C" fn(*mut std::ffi::c_void)>,
func: &mut Func,
) {
let funcref = wasm_val_t::from_val(Val::FuncRef(Some(func.func().clone())));
crate::initialize(funcrefp, funcref);
let foreign = crate::ForeignData { data, finalizer };
let ty = ty.ty().ty.clone();
let f = Func::new(store, ty, move |caller, params, results| {
let params = params
.iter()
.cloned()
.map(|p| wasmtime_val_t::from_val(p))
.collect::<Vec<_>>();
let mut out_results = (0..results.len())
.map(|_| wasmtime_val_t {
kind: crate::WASMTIME_I32,
of: wasmtime_val_union { i32: 0 },
})
.collect::<Vec<_>>();
let mut caller = wasmtime_caller_t { caller };
let out = callback(
foreign.data,
&mut caller,
params.as_ptr(),
params.len(),
out_results.as_mut_ptr(),
out_results.len(),
);
if let Some(trap) = out {
return Err(trap.trap);
}
for (i, result) in out_results.iter().enumerate() {
results[i] = unsafe { result.to_val() };
}
Ok(())
});
*func = f;
}
#[no_mangle]
pub extern "C" fn wasmtime_funcref_as_func(val: &wasm_val_t) -> Option<Box<wasm_func_t>> {
if let Val::FuncRef(Some(f)) = val.val() {
Some(Box::new(f.into()))
} else {
None
pub unsafe extern "C" fn wasmtime_func_call(
store: CStoreContextMut<'_>,
func: &Func,
args: *const wasmtime_val_t,
nargs: usize,
results: *mut MaybeUninit<wasmtime_val_t>,
nresults: usize,
trap_ret: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
if nresults != func.ty(&store).results().len() {
return Some(Box::new(wasmtime_error_t::from(anyhow!(
"wrong number of results provided"
))));
}
let params = crate::slice_from_raw_parts(args, nargs)
.iter()
.map(|i| i.to_val())
.collect::<Vec<_>>();
// 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(store, &params)));
match result {
Ok(Ok(out)) => {
let results = crate::slice_from_raw_parts_mut(results, nresults);
for (slot, val) in results.iter_mut().zip(out.into_vec().into_iter()) {
crate::initialize(slot, wasmtime_val_t::from_val(val));
}
None
}
Ok(Err(trap)) => match trap.downcast::<Trap>() {
Ok(trap) => {
*trap_ret = Box::into_raw(Box::new(wasm_trap_t::new(trap)));
None
}
Err(err) => Some(Box::new(wasmtime_error_t::from(err))),
},
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")
};
*trap_ret = Box::into_raw(Box::new(wasm_trap_t::new(trap)));
None
}
}
}
#[no_mangle]
pub extern "C" fn wasmtime_func_type(
store: CStoreContext<'_>,
func: &Func,
) -> Box<wasm_functype_t> {
Box::new(wasm_functype_t::new(func.ty(store)))
}
#[no_mangle]
pub extern "C" fn wasmtime_caller_context<'a>(
caller: &'a mut wasmtime_caller_t,
) -> CStoreContextMut<'a> {
caller.caller.as_context_mut()
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_caller_export_get(
caller: &mut wasmtime_caller_t,
name: *const u8,
name_len: usize,
item: &mut MaybeUninit<wasmtime_extern_t>,
) -> bool {
let name = match str::from_utf8(crate::slice_from_raw_parts(name, name_len)) {
Ok(name) => name,
Err(_) => return false,
};
let which = match caller.caller.get_export(name) {
Some(item) => item,
None => return false,
};
crate::initialize(item, which.into());
true
}

View File

@@ -1,7 +1,8 @@
use crate::{handle_result, wasmtime_error_t};
use crate::{wasm_extern_t, wasm_globaltype_t, wasm_store_t, wasm_val_t};
use crate::{
handle_result, wasm_extern_t, wasm_globaltype_t, wasm_store_t, wasm_val_t, wasmtime_error_t,
wasmtime_val_t, CStoreContext, CStoreContextMut,
};
use std::mem::MaybeUninit;
use std::ptr;
use wasmtime::{Extern, Global};
#[derive(Clone)]
@@ -20,8 +21,8 @@ impl wasm_global_t {
}
}
fn global(&self) -> &Global {
match &self.ext.which {
fn global(&self) -> Global {
match self.ext.which {
Extern::Global(g) => g,
_ => unsafe { std::hint::unreachable_unchecked() },
}
@@ -29,65 +30,88 @@ impl wasm_global_t {
}
#[no_mangle]
pub extern "C" fn wasm_global_new(
store: &wasm_store_t,
pub unsafe extern "C" fn wasm_global_new(
store: &mut wasm_store_t,
gt: &wasm_globaltype_t,
val: &wasm_val_t,
) -> Option<Box<wasm_global_t>> {
let mut global = ptr::null_mut();
match wasmtime_global_new(store, gt, val, &mut global) {
Some(_err) => None,
None => {
assert!(!global.is_null());
Some(unsafe { Box::from_raw(global) })
}
match Global::new(store.store.context_mut(), gt.ty().ty.clone(), val.val()) {
Ok(global) => Some(Box::new(wasm_global_t {
ext: wasm_extern_t {
store: store.store.clone(),
which: global.into(),
},
})),
Err(_) => None,
}
}
#[no_mangle]
pub extern "C" fn wasmtime_global_new(
store: &wasm_store_t,
gt: &wasm_globaltype_t,
val: &wasm_val_t,
ret: &mut *mut wasm_global_t,
) -> Option<Box<wasmtime_error_t>> {
let global = Global::new(&store.store, gt.ty().ty.clone(), val.val());
handle_result(global, |global| {
*ret = Box::into_raw(Box::new(wasm_global_t {
ext: wasm_extern_t {
which: global.into(),
},
}));
})
pub extern "C" fn wasm_global_as_extern(g: &mut wasm_global_t) -> &mut wasm_extern_t {
&mut g.ext
}
#[no_mangle]
pub extern "C" fn wasm_global_as_extern(g: &wasm_global_t) -> &wasm_extern_t {
pub extern "C" fn wasm_global_as_extern_const(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().ty();
pub unsafe extern "C" fn wasm_global_type(g: &wasm_global_t) -> Box<wasm_globaltype_t> {
let globaltype = g.global().ty(&g.ext.store.context());
Box::new(wasm_globaltype_t::new(globaltype))
}
#[no_mangle]
pub extern "C" fn wasm_global_get(g: &wasm_global_t, out: &mut MaybeUninit<wasm_val_t>) {
crate::initialize(out, wasm_val_t::from_val(g.global().get()));
pub unsafe extern "C" fn wasm_global_get(g: &mut wasm_global_t, out: &mut MaybeUninit<wasm_val_t>) {
let global = g.global();
crate::initialize(
out,
wasm_val_t::from_val(global.get(g.ext.store.context_mut())),
);
}
#[no_mangle]
pub extern "C" fn wasm_global_set(g: &wasm_global_t, val: &wasm_val_t) {
let result = g.global().set(val.val());
// FIXME(WebAssembly/wasm-c-api#131) should communicate the error here
drop(result);
pub unsafe extern "C" fn wasm_global_set(g: &mut wasm_global_t, val: &wasm_val_t) {
let global = g.global();
drop(global.set(g.ext.store.context_mut(), val.val()));
}
#[no_mangle]
pub extern "C" fn wasmtime_global_set(
g: &wasm_global_t,
val: &wasm_val_t,
pub unsafe extern "C" fn wasmtime_global_new(
store: CStoreContextMut<'_>,
gt: &wasm_globaltype_t,
val: &wasmtime_val_t,
ret: &mut Global,
) -> Option<Box<wasmtime_error_t>> {
handle_result(g.global().set(val.val()), |()| {})
let global = Global::new(store, gt.ty().ty.clone(), val.to_val());
handle_result(global, |global| {
*ret = global;
})
}
#[no_mangle]
pub extern "C" fn wasmtime_global_type(
store: CStoreContext<'_>,
global: &Global,
) -> Box<wasm_globaltype_t> {
Box::new(wasm_globaltype_t::new(global.ty(store)))
}
#[no_mangle]
pub extern "C" fn wasmtime_global_get(
store: CStoreContextMut<'_>,
global: &Global,
val: &mut MaybeUninit<wasmtime_val_t>,
) {
crate::initialize(val, wasmtime_val_t::from_val(global.get(store)))
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_global_set(
store: CStoreContextMut<'_>,
global: &Global,
val: &wasmtime_val_t,
) -> Option<Box<wasmtime_error_t>> {
handle_result(global.set(store, val.to_val()), |()| {})
}

View File

@@ -1,7 +1,9 @@
use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t};
use crate::{wasm_instancetype_t, wasm_store_t, wasmtime_error_t};
use anyhow::Result;
use std::ptr;
use crate::{
wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_store_t, wasm_trap_t, wasmtime_error_t,
wasmtime_extern_t, wasmtime_instancetype_t, wasmtime_module_t, CStoreContext, CStoreContextMut,
StoreRef,
};
use std::mem::MaybeUninit;
use wasmtime::{Extern, Instance, Trap};
#[derive(Clone)]
@@ -13,9 +15,10 @@ pub struct wasm_instance_t {
wasmtime_c_api_macros::declare_ref!(wasm_instance_t);
impl wasm_instance_t {
pub(crate) fn new(instance: Instance) -> wasm_instance_t {
pub(crate) fn new(store: StoreRef, instance: Instance) -> wasm_instance_t {
wasm_instance_t {
ext: wasm_extern_t {
store: store,
which: instance.into(),
},
}
@@ -28,8 +31,8 @@ impl wasm_instance_t {
}
}
pub(crate) fn instance(&self) -> &Instance {
match &self.ext.which {
pub(crate) fn instance(&self) -> Instance {
match self.ext.which {
Extern::Instance(i) => i,
_ => unreachable!(),
}
@@ -38,100 +41,30 @@ impl wasm_instance_t {
#[no_mangle]
pub unsafe extern "C" fn wasm_instance_new(
store: &wasm_store_t,
store: &mut wasm_store_t,
wasm_module: &wasm_module_t,
imports: *const wasm_extern_vec_t,
result: Option<&mut *mut wasm_trap_t>,
) -> Option<Box<wasm_instance_t>> {
let mut instance = ptr::null_mut();
let mut trap = ptr::null_mut();
let err = _wasmtime_instance_new(
store,
wasm_module,
(*imports).as_slice(),
&mut instance,
&mut trap,
);
match err {
Some(err) => {
assert!(trap.is_null());
assert!(instance.is_null());
if let Some(result) = result {
*result = Box::into_raw(err.to_trap());
}
None
}
None => {
if instance.is_null() {
assert!(!trap.is_null());
if let Some(result) = result {
*result = trap;
} else {
drop(Box::from_raw(trap))
}
None
} else {
assert!(trap.is_null());
Some(Box::from_raw(instance))
}
}
}
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_instance_new(
store: &wasm_store_t,
module: &wasm_module_t,
imports: *const wasm_extern_vec_t,
instance_ptr: &mut *mut wasm_instance_t,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
_wasmtime_instance_new(store, module, (*imports).as_slice(), instance_ptr, trap_ptr)
}
fn _wasmtime_instance_new(
store: &wasm_store_t,
module: &wasm_module_t,
imports: &[Option<Box<wasm_extern_t>>],
instance_ptr: &mut *mut wasm_instance_t,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
let store = &store.store;
let imports = imports
let imports = (*imports)
.as_slice()
.iter()
.filter_map(|import| match import {
Some(i) => Some(i.which.clone()),
None => None,
})
.collect::<Vec<_>>();
handle_instantiate(
Instance::new(store, module.module(), &imports),
instance_ptr,
trap_ptr,
)
}
pub fn handle_instantiate(
instance: Result<Instance>,
instance_ptr: &mut *mut wasm_instance_t,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
fn write<T>(ptr: &mut *mut T, val: T) {
*ptr = Box::into_raw(Box::new(val))
}
match instance {
Ok(instance) => {
write(instance_ptr, wasm_instance_t::new(instance));
match Instance::new(store.store.context_mut(), wasm_module.module(), &imports) {
Ok(instance) => Some(Box::new(wasm_instance_t::new(
store.store.clone(),
instance,
))),
Err(e) => {
if let Some(ptr) = result {
*ptr = Box::into_raw(Box::new(wasm_trap_t::new(e.into())));
}
None
}
Err(e) => match e.downcast::<Trap>() {
Ok(trap) => {
write(trap_ptr, wasm_trap_t::new(trap));
None
}
Err(e) => Some(Box::new(e.into())),
},
}
}
@@ -141,14 +74,19 @@ pub extern "C" fn wasm_instance_as_extern(m: &wasm_instance_t) -> &wasm_extern_t
}
#[no_mangle]
pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wasm_extern_vec_t) {
pub unsafe extern "C" fn wasm_instance_exports(
instance: &mut wasm_instance_t,
out: &mut wasm_extern_vec_t,
) {
let store = instance.ext.store.clone();
out.set_buffer(
instance
.instance()
.exports()
.exports(instance.ext.store.context_mut())
.map(|e| {
Some(Box::new(wasm_extern_t {
which: e.into_extern(),
store: store.clone(),
}))
})
.collect(),
@@ -156,6 +94,91 @@ pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wa
}
#[no_mangle]
pub extern "C" fn wasm_instance_type(f: &wasm_instance_t) -> Box<wasm_instancetype_t> {
Box::new(wasm_instancetype_t::new(f.instance().ty()))
pub unsafe extern "C" fn wasmtime_instance_new(
store: CStoreContextMut<'_>,
module: &wasmtime_module_t,
imports: *const wasmtime_extern_t,
nimports: usize,
instance: &mut Instance,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
let imports = crate::slice_from_raw_parts(imports, nimports)
.iter()
.map(|i| i.to_extern())
.collect::<Vec<_>>();
handle_instantiate(
Instance::new(store, &module.module, &imports),
instance,
trap_ptr,
)
}
pub(crate) fn handle_instantiate(
instance: anyhow::Result<Instance>,
instance_ptr: &mut Instance,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
match instance {
Ok(i) => {
*instance_ptr = i;
None
}
Err(e) => match e.downcast::<Trap>() {
Ok(trap) => {
*trap_ptr = Box::into_raw(Box::new(wasm_trap_t::new(trap)));
None
}
Err(e) => Some(Box::new(e.into())),
},
}
}
#[no_mangle]
pub extern "C" fn wasmtime_instance_type(
store: CStoreContext<'_>,
instance: &Instance,
) -> Box<wasmtime_instancetype_t> {
Box::new(wasmtime_instancetype_t::new(instance.ty(store)))
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_instance_export_get(
store: CStoreContextMut<'_>,
instance: &Instance,
name: *const u8,
name_len: usize,
item: &mut MaybeUninit<wasmtime_extern_t>,
) -> bool {
let name = crate::slice_from_raw_parts(name, name_len);
let name = match std::str::from_utf8(name) {
Ok(name) => name,
Err(_) => return false,
};
match instance.get_export(store, name) {
Some(e) => {
crate::initialize(item, e.into());
true
}
None => false,
}
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_instance_export_nth(
store: CStoreContextMut<'_>,
instance: &Instance,
index: usize,
name_ptr: &mut *const u8,
name_len: &mut usize,
item: &mut MaybeUninit<wasmtime_extern_t>,
) -> bool {
match instance.exports(store).nth(index) {
Some(e) => {
*name_ptr = e.name().as_ptr();
*name_len = e.name().len();
crate::initialize(item, e.into_extern().into());
true
}
None => false,
}
}

View File

@@ -1,11 +1,15 @@
//! This file defines the extern "C" API, which is compatible with the
//! [Wasm C API](https://github.com/WebAssembly/wasm-c-api).
//! This crate is the implementation of Wasmtime's C API.
//!
//! This crate is not intended to be used from Rust itself, for that see the
//! `wasmtime` crate. Otherwise this is typically compiled as a
//! cdylib/staticlib. Documentation for this crate largely lives in the header
//! files of the `include` directory for this crate.
//!
//! At a high level this crate implements the `wasm.h` API with some gymnastics,
//! but otherwise an accompanying `wasmtime.h` API is provided which is more
//! specific to Wasmtime and has fewer gymnastics to implement.
#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
#![allow(unknown_lints)]
#![allow(improper_ctypes_definitions)]
// TODO complete the C API
mod config;
mod engine;
@@ -53,18 +57,6 @@ mod wat2wasm;
#[cfg(feature = "wat")]
pub use crate::wat2wasm::*;
#[repr(C)]
#[derive(Clone)]
pub struct wasm_foreign_t {
_unused: [u8; 0],
}
#[repr(C)]
#[derive(Clone)]
pub struct wasm_shared_module_t {
_unused: [u8; 0],
}
/// Initialize a `MaybeUninit<T>`
///
/// TODO: Replace calls to this function with
@@ -75,3 +67,43 @@ pub(crate) fn initialize<T>(dst: &mut std::mem::MaybeUninit<T>, val: T) {
std::ptr::write(dst.as_mut_ptr(), val);
}
}
/// Helper for running a C-defined finalizer over some data when the Rust
/// structure is dropped.
pub struct ForeignData {
data: *mut std::ffi::c_void,
finalizer: Option<extern "C" fn(*mut std::ffi::c_void)>,
}
unsafe impl Send for ForeignData {}
unsafe impl Sync for ForeignData {}
impl Drop for ForeignData {
fn drop(&mut self) {
if let Some(f) = self.finalizer {
f(self.data);
}
}
}
/// Helper for creating Rust slices from C inputs.
///
/// This specifically disregards the `ptr` argument if the length is zero. The
/// `ptr` in that case maybe `NULL` or invalid, and it's not valid to have a
/// zero-length Rust slice with a `NULL` pointer.
unsafe fn slice_from_raw_parts<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
if len == 0 {
&[]
} else {
std::slice::from_raw_parts(ptr, len)
}
}
/// Same as above, but for `*_mut`
unsafe fn slice_from_raw_parts_mut<'a, T>(ptr: *mut T, len: usize) -> &'a mut [T] {
if len == 0 {
&mut []
} else {
std::slice::from_raw_parts_mut(ptr, len)
}
}

View File

@@ -1,18 +1,20 @@
use crate::{bad_utf8, handle_result, wasmtime_error_t};
use crate::{wasm_extern_t, wasm_store_t};
use crate::{wasm_func_t, wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t};
use crate::{
bad_utf8, handle_result, wasm_engine_t, wasm_trap_t, wasmtime_error_t, wasmtime_extern_t,
wasmtime_module_t, CStoreContextMut,
};
use std::mem::MaybeUninit;
use std::str;
use wasmtime::Linker;
use wasmtime::{Func, Instance, Linker};
#[repr(C)]
pub struct wasmtime_linker_t {
linker: Linker,
linker: Linker<crate::StoreData>,
}
#[no_mangle]
pub extern "C" fn wasmtime_linker_new(store: &wasm_store_t) -> Box<wasmtime_linker_t> {
pub extern "C" fn wasmtime_linker_new(engine: &wasm_engine_t) -> Box<wasmtime_linker_t> {
Box::new(wasmtime_linker_t {
linker: Linker::new(&store.store),
linker: Linker::new(&engine.engine),
})
}
@@ -27,23 +29,28 @@ pub extern "C" fn wasmtime_linker_allow_shadowing(
#[no_mangle]
pub extern "C" fn wasmtime_linker_delete(_linker: Box<wasmtime_linker_t>) {}
macro_rules! to_str {
($ptr:expr, $len:expr) => {
match str::from_utf8(crate::slice_from_raw_parts($ptr, $len)) {
Ok(s) => s,
Err(_) => return bad_utf8(),
}
};
}
#[no_mangle]
pub extern "C" fn wasmtime_linker_define(
pub unsafe extern "C" fn wasmtime_linker_define(
linker: &mut wasmtime_linker_t,
module: &wasm_name_t,
name: &wasm_name_t,
item: &wasm_extern_t,
module: *const u8,
module_len: usize,
name: *const u8,
name_len: usize,
item: &wasmtime_extern_t,
) -> Option<Box<wasmtime_error_t>> {
let linker = &mut linker.linker;
let module = match str::from_utf8(module.as_slice()) {
Ok(s) => s,
Err(_) => return bad_utf8(),
};
let name = match str::from_utf8(name.as_slice()) {
Ok(s) => s,
Err(_) => return bad_utf8(),
};
let item = item.which.clone();
let module = to_str!(module, module_len);
let name = to_str!(name, name_len);
let item = item.to_extern();
handle_result(linker.define(module, name, item), |_linker| ())
}
@@ -51,87 +58,92 @@ pub extern "C" fn wasmtime_linker_define(
#[no_mangle]
pub extern "C" fn wasmtime_linker_define_wasi(
linker: &mut wasmtime_linker_t,
instance: &crate::wasi_instance_t,
) -> Option<Box<wasmtime_error_t>> {
let linker = &mut linker.linker;
handle_result(instance.add_to_linker(linker), |_linker| ())
handle_result(
wasmtime_wasi::add_to_linker(&mut linker.linker, |cx| cx.wasi.as_mut().unwrap()),
|_linker| (),
)
}
#[no_mangle]
pub extern "C" fn wasmtime_linker_define_instance(
pub unsafe extern "C" fn wasmtime_linker_define_instance(
linker: &mut wasmtime_linker_t,
name: &wasm_name_t,
instance: &wasm_instance_t,
store: CStoreContextMut<'_>,
name: *const u8,
name_len: usize,
instance: &Instance,
) -> Option<Box<wasmtime_error_t>> {
let linker = &mut linker.linker;
let name = match str::from_utf8(name.as_slice()) {
Ok(s) => s,
Err(_) => return bad_utf8(),
};
handle_result(linker.instance(name, instance.instance()), |_linker| ())
let name = to_str!(name, name_len);
handle_result(linker.instance(store, name, *instance), |_linker| ())
}
#[no_mangle]
pub extern "C" fn wasmtime_linker_instantiate(
linker: &wasmtime_linker_t,
module: &wasm_module_t,
instance_ptr: &mut *mut wasm_instance_t,
store: CStoreContextMut<'_>,
module: &wasmtime_module_t,
instance_ptr: &mut Instance,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
let result = linker.linker.instantiate(module.module());
let result = linker.linker.instantiate(store, &module.module);
super::instance::handle_instantiate(result, instance_ptr, trap_ptr)
}
#[no_mangle]
pub extern "C" fn wasmtime_linker_module(
pub unsafe extern "C" fn wasmtime_linker_module(
linker: &mut wasmtime_linker_t,
name: &wasm_name_t,
module: &wasm_module_t,
store: CStoreContextMut<'_>,
name: *const u8,
name_len: usize,
module: &wasmtime_module_t,
) -> Option<Box<wasmtime_error_t>> {
let linker = &mut linker.linker;
let name = match str::from_utf8(name.as_slice()) {
Ok(s) => s,
Err(_) => return bad_utf8(),
};
handle_result(linker.module(name, module.module()), |_linker| ())
let name = to_str!(name, name_len);
handle_result(linker.module(store, name, &module.module), |_linker| ())
}
#[no_mangle]
pub extern "C" fn wasmtime_linker_get_default(
pub unsafe extern "C" fn wasmtime_linker_get_default(
linker: &wasmtime_linker_t,
name: &wasm_name_t,
func: &mut *mut wasm_func_t,
store: CStoreContextMut<'_>,
name: *const u8,
name_len: usize,
func: &mut Func,
) -> Option<Box<wasmtime_error_t>> {
let linker = &linker.linker;
let name = match str::from_utf8(name.as_slice()) {
Ok(s) => s,
Err(_) => return bad_utf8(),
};
handle_result(linker.get_default(name), |f| {
*func = Box::into_raw(Box::new(f.into()))
})
let name = to_str!(name, name_len);
handle_result(linker.get_default(store, name), |f| *func = f)
}
#[no_mangle]
pub extern "C" fn wasmtime_linker_get_one_by_name(
pub unsafe extern "C" fn wasmtime_linker_get(
linker: &wasmtime_linker_t,
module: &wasm_name_t,
name: Option<&wasm_name_t>,
item_ptr: &mut *mut wasm_extern_t,
) -> Option<Box<wasmtime_error_t>> {
store: CStoreContextMut<'_>,
module: *const u8,
module_len: usize,
name: *const u8,
name_len: usize,
item_ptr: &mut MaybeUninit<wasmtime_extern_t>,
) -> bool {
let linker = &linker.linker;
let module = match str::from_utf8(module.as_slice()) {
let module = match str::from_utf8(crate::slice_from_raw_parts(module, module_len)) {
Ok(s) => s,
Err(_) => return bad_utf8(),
Err(_) => return false,
};
let name = match name {
Some(name) => match str::from_utf8(name.as_slice()) {
let name = if name.is_null() {
None
} else {
match str::from_utf8(crate::slice_from_raw_parts(name, name_len)) {
Ok(s) => Some(s),
Err(_) => return bad_utf8(),
},
None => None,
Err(_) => return false,
}
};
handle_result(linker.get_one_by_name(module, name), |which| {
*item_ptr = Box::into_raw(Box::new(wasm_extern_t { which }))
})
match linker.get(store, module, name) {
Some(which) => {
crate::initialize(item_ptr, which.into());
true
}
None => false,
}
}

View File

@@ -1,4 +1,7 @@
use crate::{wasm_extern_t, wasm_memorytype_t, wasm_store_t};
use crate::{
handle_result, wasm_extern_t, wasm_memorytype_t, wasm_store_t, wasmtime_error_t, CStoreContext,
CStoreContextMut,
};
use wasmtime::{Extern, Memory};
#[derive(Clone)]
@@ -19,8 +22,8 @@ impl wasm_memory_t {
}
}
fn memory(&self) -> &Memory {
match &self.ext.which {
fn memory(&self) -> Memory {
match self.ext.which {
Extern::Memory(m) => m,
_ => unsafe { std::hint::unreachable_unchecked() },
}
@@ -28,45 +31,98 @@ impl wasm_memory_t {
}
#[no_mangle]
pub extern "C" fn wasm_memory_new(
store: &wasm_store_t,
pub unsafe extern "C" fn wasm_memory_new(
store: &mut wasm_store_t,
mt: &wasm_memorytype_t,
) -> Option<Box<wasm_memory_t>> {
let memory = Memory::new(&store.store, mt.ty().ty.clone()).ok()?;
let memory = Memory::new(store.store.context_mut(), mt.ty().ty.clone()).ok()?;
Some(Box::new(wasm_memory_t {
ext: wasm_extern_t {
store: store.store.clone(),
which: memory.into(),
},
}))
}
#[no_mangle]
pub extern "C" fn wasm_memory_as_extern(m: &wasm_memory_t) -> &wasm_extern_t {
pub extern "C" fn wasm_memory_as_extern(m: &mut wasm_memory_t) -> &mut wasm_extern_t {
&mut m.ext
}
#[no_mangle]
pub extern "C" fn wasm_memory_as_extern_const(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().ty();
pub unsafe extern "C" fn wasm_memory_type(m: &wasm_memory_t) -> Box<wasm_memorytype_t> {
let ty = m.memory().ty(m.ext.store.context());
Box::new(wasm_memorytype_t::new(ty))
}
#[no_mangle]
pub extern "C" fn wasm_memory_data(m: &wasm_memory_t) -> *mut u8 {
m.memory().data_ptr()
pub unsafe extern "C" fn wasm_memory_data(m: &wasm_memory_t) -> *mut u8 {
m.memory().data_ptr(m.ext.store.context())
}
#[no_mangle]
pub extern "C" fn wasm_memory_data_size(m: &wasm_memory_t) -> usize {
m.memory().data_size()
pub unsafe extern "C" fn wasm_memory_data_size(m: &wasm_memory_t) -> usize {
m.memory().data_size(m.ext.store.context())
}
#[no_mangle]
pub extern "C" fn wasm_memory_size(m: &wasm_memory_t) -> wasm_memory_pages_t {
m.memory().size()
pub unsafe extern "C" fn wasm_memory_size(m: &wasm_memory_t) -> wasm_memory_pages_t {
m.memory().size(m.ext.store.context())
}
#[no_mangle]
pub extern "C" fn wasm_memory_grow(m: &wasm_memory_t, delta: wasm_memory_pages_t) -> bool {
m.memory().grow(delta).is_ok()
pub unsafe extern "C" fn wasm_memory_grow(
m: &mut wasm_memory_t,
delta: wasm_memory_pages_t,
) -> bool {
let memory = m.memory();
let mut store = m.ext.store.context_mut();
memory.grow(&mut store, delta).is_ok()
}
#[no_mangle]
pub extern "C" fn wasmtime_memory_new(
store: CStoreContextMut<'_>,
ty: &wasm_memorytype_t,
ret: &mut Memory,
) -> Option<Box<wasmtime_error_t>> {
handle_result(Memory::new(store, ty.ty().ty.clone()), |mem| *ret = mem)
}
#[no_mangle]
pub extern "C" fn wasmtime_memory_type(
store: CStoreContext<'_>,
mem: &Memory,
) -> Box<wasm_memorytype_t> {
Box::new(wasm_memorytype_t::new(mem.ty(store)))
}
#[no_mangle]
pub extern "C" fn wasmtime_memory_data(store: CStoreContext<'_>, mem: &Memory) -> *const u8 {
mem.data(store).as_ptr()
}
#[no_mangle]
pub extern "C" fn wasmtime_memory_data_size(store: CStoreContext<'_>, mem: &Memory) -> usize {
mem.data(store).len()
}
#[no_mangle]
pub extern "C" fn wasmtime_memory_size(store: CStoreContext<'_>, mem: &Memory) -> u32 {
mem.size(store)
}
#[no_mangle]
pub extern "C" fn wasmtime_memory_grow(
store: CStoreContextMut<'_>,
mem: &Memory,
delta: u32,
prev_size: &mut u32,
) -> Option<Box<wasmtime_error_t>> {
handle_result(mem.grow(store, delta), |prev| *prev_size = prev)
}

View File

@@ -1,9 +1,8 @@
use crate::{
handle_result, wasm_byte_vec_t, wasm_engine_t, wasm_exporttype_t, wasm_exporttype_vec_t,
wasm_extern_t, wasm_importtype_t, wasm_importtype_vec_t, wasm_moduletype_t, wasm_store_t,
wasmtime_error_t,
wasm_extern_t, wasm_importtype_t, wasm_importtype_vec_t, wasm_store_t, wasmtime_error_t,
wasmtime_moduletype_t, StoreRef,
};
use std::ptr;
use wasmtime::{Engine, Extern, Module};
#[derive(Clone)]
@@ -15,9 +14,10 @@ pub struct wasm_module_t {
wasmtime_c_api_macros::declare_ref!(wasm_module_t);
impl wasm_module_t {
pub(crate) fn new(module: Module) -> wasm_module_t {
pub(crate) fn new(store: StoreRef, module: Module) -> wasm_module_t {
wasm_module_t {
ext: wasm_extern_t {
store: store,
which: module.into(),
},
}
@@ -47,48 +47,22 @@ pub struct wasm_shared_module_t {
wasmtime_c_api_macros::declare_own!(wasm_shared_module_t);
#[no_mangle]
pub extern "C" fn wasm_module_new(
store: &wasm_store_t,
pub unsafe extern "C" fn wasm_module_new(
store: &mut wasm_store_t,
binary: &wasm_byte_vec_t,
) -> Option<Box<wasm_module_t>> {
let mut ret = ptr::null_mut();
let engine = wasm_engine_t {
engine: store.store.engine().clone(),
};
match wasmtime_module_new(&engine, binary, &mut ret) {
Some(_err) => None,
None => {
assert!(!ret.is_null());
Some(unsafe { Box::from_raw(ret) })
}
match Module::from_binary(store.store.context().engine(), binary.as_slice()) {
Ok(module) => Some(Box::new(wasm_module_t::new(store.store.clone(), module))),
Err(_) => None,
}
}
#[no_mangle]
pub extern "C" fn wasmtime_module_new(
engine: &wasm_engine_t,
pub unsafe extern "C" fn wasm_module_validate(
store: &mut wasm_store_t,
binary: &wasm_byte_vec_t,
ret: &mut *mut wasm_module_t,
) -> Option<Box<wasmtime_error_t>> {
let binary = binary.as_slice();
handle_result(Module::from_binary(&engine.engine, binary), |module| {
let module = Box::new(wasm_module_t::new(module));
*ret = Box::into_raw(module);
})
}
#[no_mangle]
pub extern "C" fn wasm_module_validate(store: &wasm_store_t, binary: &wasm_byte_vec_t) -> bool {
wasmtime_module_validate(store, binary).is_none()
}
#[no_mangle]
pub extern "C" fn wasmtime_module_validate(
store: &wasm_store_t,
binary: &wasm_byte_vec_t,
) -> Option<Box<wasmtime_error_t>> {
let binary = binary.as_slice();
handle_result(Module::validate(store.store.engine(), binary), |()| {})
) -> bool {
Module::validate(store.store.context().engine(), binary.as_slice()).is_ok()
}
#[no_mangle]
@@ -135,66 +109,96 @@ pub extern "C" fn wasm_module_share(module: &wasm_module_t) -> Box<wasm_shared_m
}
#[no_mangle]
pub extern "C" fn wasm_module_obtain(
store: &wasm_store_t,
pub unsafe extern "C" fn wasm_module_obtain(
store: &mut wasm_store_t,
shared_module: &wasm_shared_module_t,
) -> Option<Box<wasm_module_t>> {
let module = shared_module.module.clone();
if !Engine::same(store.store.engine(), module.engine()) {
return None;
if Engine::same(store.store.context().engine(), module.engine()) {
Some(Box::new(wasm_module_t::new(store.store.clone(), module)))
} else {
None
}
Some(Box::new(wasm_module_t::new(module)))
}
#[no_mangle]
pub extern "C" fn wasm_module_serialize(module: &wasm_module_t, ret: &mut wasm_byte_vec_t) {
drop(wasmtime_module_serialize(module, ret));
}
#[no_mangle]
pub extern "C" fn wasm_module_deserialize(
store: &wasm_store_t,
binary: &wasm_byte_vec_t,
) -> Option<Box<wasm_module_t>> {
let mut ret = ptr::null_mut();
let engine = wasm_engine_t {
engine: store.store.engine().clone(),
};
match wasmtime_module_deserialize(&engine, binary, &mut ret) {
Some(_err) => None,
None => {
assert!(!ret.is_null());
Some(unsafe { Box::from_raw(ret) })
}
if let Ok(buf) = module.module().serialize() {
ret.set_buffer(buf);
}
}
#[no_mangle]
pub extern "C" fn wasmtime_module_serialize(
module: &wasm_module_t,
ret: &mut wasm_byte_vec_t,
) -> Option<Box<wasmtime_error_t>> {
handle_result(module.module().serialize(), |buf| {
ret.set_buffer(buf);
})
pub unsafe extern "C" fn wasm_module_deserialize(
store: &mut wasm_store_t,
binary: &wasm_byte_vec_t,
) -> Option<Box<wasm_module_t>> {
match Module::deserialize(store.store.context().engine(), binary.as_slice()) {
Ok(module) => Some(Box::new(wasm_module_t::new(store.store.clone(), module))),
Err(_) => None,
}
}
#[derive(Clone)]
pub struct wasmtime_module_t {
pub(crate) module: Module,
}
#[no_mangle]
pub extern "C" fn wasmtime_module_deserialize(
pub unsafe extern "C" fn wasmtime_module_new(
engine: &wasm_engine_t,
binary: &wasm_byte_vec_t,
ret: &mut *mut wasm_module_t,
wasm: *const u8,
len: usize,
out: &mut *mut wasmtime_module_t,
) -> Option<Box<wasmtime_error_t>> {
handle_result(
unsafe { Module::deserialize(&engine.engine, binary.as_slice()) },
Module::from_binary(&engine.engine, crate::slice_from_raw_parts(wasm, len)),
|module| {
let module = Box::new(wasm_module_t::new(module));
*ret = Box::into_raw(module);
*out = Box::into_raw(Box::new(wasmtime_module_t { module }));
},
)
}
#[no_mangle]
pub extern "C" fn wasm_module_type(f: &wasm_module_t) -> Box<wasm_moduletype_t> {
Box::new(wasm_moduletype_t::new(f.module().ty()))
pub extern "C" fn wasmtime_module_delete(_module: Box<wasmtime_module_t>) {}
#[no_mangle]
pub extern "C" fn wasmtime_module_clone(module: &wasmtime_module_t) -> Box<wasmtime_module_t> {
Box::new(module.clone())
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_module_validate(
engine: &wasm_engine_t,
wasm: *const u8,
len: usize,
) -> Option<Box<wasmtime_error_t>> {
let binary = crate::slice_from_raw_parts(wasm, len);
handle_result(Module::validate(&engine.engine, binary), |()| {})
}
#[no_mangle]
pub extern "C" fn wasmtime_module_type(m: &wasmtime_module_t) -> Box<wasmtime_moduletype_t> {
Box::new(wasmtime_moduletype_t::new(m.module.ty()))
}
#[no_mangle]
pub extern "C" fn wasmtime_module_serialize(
module: &wasmtime_module_t,
ret: &mut wasm_byte_vec_t,
) -> Option<Box<wasmtime_error_t>> {
handle_result(module.module.serialize(), |buf| ret.set_buffer(buf))
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_module_deserialize(
engine: &wasm_engine_t,
bytes: *const u8,
len: usize,
out: &mut *mut wasmtime_module_t,
) -> Option<Box<wasmtime_error_t>> {
let bytes = crate::slice_from_raw_parts(bytes, len);
handle_result(Module::deserialize(&engine.engine, bytes), |module| {
*out = Box::into_raw(Box::new(wasmtime_module_t { module }));
})
}

View File

@@ -1,8 +1,4 @@
use crate::wasm_val_t;
use std::any::Any;
use std::mem::MaybeUninit;
use std::os::raw::c_void;
use std::ptr;
use wasmtime::{ExternRef, Func, Val};
/// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by
@@ -54,6 +50,11 @@ pub extern "C" fn wasm_ref_copy(r: Option<&wasm_ref_t>) -> Option<Box<wasm_ref_t
r.map(|r| Box::new(r.clone()))
}
fn abort(name: &str) -> ! {
eprintln!("`{}` is not implemented", name);
std::process::abort();
}
#[no_mangle]
pub extern "C" fn wasm_ref_same(a: Option<&wasm_ref_t>, b: Option<&wasm_ref_t>) -> bool {
match (a.map(|a| &a.r), b.map(|b| &b.r)) {
@@ -72,8 +73,7 @@ pub extern "C" fn wasm_ref_get_host_info(_ref: Option<&wasm_ref_t>) -> *mut c_vo
#[no_mangle]
pub extern "C" fn wasm_ref_set_host_info(_ref: Option<&wasm_ref_t>, _info: *mut c_void) {
eprintln!("`wasm_ref_set_host_info` is not implemented");
std::process::abort();
abort("wasm_ref_set_host_info")
}
#[no_mangle]
@@ -82,63 +82,162 @@ pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
_info: *mut c_void,
_finalizer: Option<extern "C" fn(*mut c_void)>,
) {
eprintln!("`wasm_ref_set_host_info_with_finalizer` is not implemented");
std::process::abort();
}
type wasmtime_externref_finalizer_t = extern "C" fn(*mut c_void);
struct CExternRef {
data: *mut c_void,
finalizer: Option<wasmtime_externref_finalizer_t>,
}
impl Drop for CExternRef {
fn drop(&mut self) {
if let Some(f) = self.finalizer {
f(self.data);
}
}
abort("wasm_ref_set_host_info_with_finalizer")
}
#[no_mangle]
pub extern "C" fn wasmtime_externref_new(data: *mut c_void, valp: &mut MaybeUninit<wasm_val_t>) {
wasmtime_externref_new_with_finalizer(data, None, valp)
pub extern "C" fn wasm_ref_as_extern(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_extern_t> {
abort("wasm_ref_as_extern")
}
#[no_mangle]
pub extern "C" fn wasmtime_externref_new_with_finalizer(
data: *mut c_void,
finalizer: Option<wasmtime_externref_finalizer_t>,
valp: &mut MaybeUninit<wasm_val_t>,
pub extern "C" fn wasm_ref_as_extern_const(
_ref: Option<&wasm_ref_t>,
) -> Option<&crate::wasm_extern_t> {
abort("wasm_ref_as_extern_const")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_foreign(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_foreign_t> {
abort("wasm_ref_as_foreign")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_foreign_const(
_ref: Option<&wasm_ref_t>,
) -> Option<&crate::wasm_foreign_t> {
abort("wasm_ref_as_foreign_const")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_func(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
abort("wasm_ref_as_func")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_func_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
abort("wasm_ref_as_func_const")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_global(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_global_t> {
abort("wasm_ref_as_global")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_global_const(
_ref: Option<&wasm_ref_t>,
) -> Option<&crate::wasm_global_t> {
abort("wasm_ref_as_global_const")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_instance(
_ref: Option<&wasm_ref_t>,
) -> Option<&crate::wasm_instance_t> {
abort("wasm_ref_as_instance")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_instance_const(
_ref: Option<&wasm_ref_t>,
) -> Option<&crate::wasm_instance_t> {
abort("wasm_ref_as_instance_const")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_memory(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_memory_t> {
abort("wasm_ref_as_memory")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_memory_const(
_ref: Option<&wasm_ref_t>,
) -> Option<&crate::wasm_memory_t> {
abort("wasm_ref_as_memory_const")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_module(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_module_t> {
abort("wasm_ref_as_module")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_module_const(
_ref: Option<&wasm_ref_t>,
) -> Option<&crate::wasm_module_t> {
abort("wasm_ref_as_module_const")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_table(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_table_t> {
abort("wasm_ref_as_table")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_table_const(
_ref: Option<&wasm_ref_t>,
) -> Option<&crate::wasm_table_t> {
abort("wasm_ref_as_table_const")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_trap(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
abort("wasm_ref_as_trap")
}
#[no_mangle]
pub extern "C" fn wasm_ref_as_trap_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
abort("wasm_ref_as_trap_const")
}
#[derive(Clone)]
#[repr(C)]
pub struct wasm_foreign_t {}
#[no_mangle]
pub extern "C" fn wasm_foreign_new(_store: &crate::wasm_store_t) -> Box<wasm_foreign_t> {
abort("wasm_foreign_new")
}
#[no_mangle]
pub extern "C" fn wasm_foreign_delete(_foreign: Box<wasm_foreign_t>) {}
#[no_mangle]
pub extern "C" fn wasm_foreign_copy(r: &wasm_foreign_t) -> Box<wasm_foreign_t> {
Box::new(r.clone())
}
#[no_mangle]
pub extern "C" fn wasm_foreign_same(_a: &wasm_foreign_t, _b: &wasm_foreign_t) -> bool {
abort("wasm_foreign_same")
}
#[no_mangle]
pub extern "C" fn wasm_foreign_get_host_info(_foreign: &wasm_foreign_t) -> *mut c_void {
std::ptr::null_mut()
}
#[no_mangle]
pub extern "C" fn wasm_foreign_set_host_info(_foreign: &wasm_foreign_t, _info: *mut c_void) {
abort("wasm_foreign_set_host_info")
}
#[no_mangle]
pub extern "C" fn wasm_foreign_set_host_info_with_finalizer(
_foreign: &wasm_foreign_t,
_info: *mut c_void,
_finalizer: Option<extern "C" fn(*mut c_void)>,
) {
crate::initialize(
valp,
wasm_val_t::from_val(Val::ExternRef(Some(ExternRef::new(CExternRef {
data,
finalizer,
})))),
);
abort("wasm_foreign_set_host_info_with_finalizer")
}
#[no_mangle]
pub extern "C" fn wasmtime_externref_data(
val: &wasm_val_t,
datap: &mut MaybeUninit<*mut c_void>,
) -> bool {
match val.val() {
Val::ExternRef(None) => {
crate::initialize(datap, ptr::null_mut());
true
}
Val::ExternRef(Some(x)) => {
let data = match x.data().downcast_ref::<CExternRef>() {
Some(r) => r.data,
None => x.data() as *const dyn Any as *mut c_void,
};
crate::initialize(datap, data);
true
}
_ => false,
}
pub extern "C" fn wasm_foreign_as_ref(_: &wasm_foreign_t) -> &wasm_ref_t {
abort("wasm_foreign_as_ref")
}
#[no_mangle]
pub extern "C" fn wasm_foreign_as_ref_const(_: &wasm_foreign_t) -> Option<&wasm_ref_t> {
abort("wasm_foreign_as_ref_const")
}

View File

@@ -1,10 +1,38 @@
use crate::{wasm_engine_t, wasmtime_error_t};
use wasmtime::{InterruptHandle, Store};
use crate::{wasm_engine_t, wasmtime_error_t, ForeignData};
use std::cell::UnsafeCell;
use std::ffi::c_void;
use std::sync::Arc;
use wasmtime::{AsContext, AsContextMut, InterruptHandle, Store, StoreContext, StoreContextMut};
/// This representation of a `Store` is used to implement the `wasm.h` API.
///
/// This is stored alongside `Func` and such for `wasm.h` so each object is
/// independently owned. The usage of `Arc` here is mostly to just get it to be
/// safe to drop across multiple threads, but otherwise acquiring the `context`
/// values from this struct is considered unsafe due to it being unknown how the
/// aliasing is working on the C side of things.
///
/// The aliasing requirements are documented in the C API `wasm.h` itself (at
/// least Wasmtime's implementation).
#[derive(Clone)]
pub struct StoreRef {
store: Arc<UnsafeCell<Store<()>>>,
}
impl StoreRef {
pub unsafe fn context(&self) -> StoreContext<'_, ()> {
(*self.store.get()).as_context()
}
pub unsafe fn context_mut(&mut self) -> StoreContextMut<'_, ()> {
(*self.store.get()).as_context_mut()
}
}
#[repr(C)]
#[derive(Clone)]
pub struct wasm_store_t {
pub(crate) store: Store,
pub(crate) store: StoreRef,
}
wasmtime_c_api_macros::declare_own!(wasm_store_t);
@@ -12,14 +40,104 @@ 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;
let store = Store::new(engine, ());
Box::new(wasm_store_t {
store: Store::new(&engine),
store: StoreRef {
store: Arc::new(UnsafeCell::new(store)),
},
})
}
/// Representation of a `Store` for `wasmtime.h` This notably tries to move more
/// burden of aliasing on the caller rather than internally, allowing for a more
/// raw representation of contexts and such that requires less `unsafe` in the
/// implementation.
///
/// Note that this notably carries `StoreData` as a payload which allows storing
/// foreign data and configuring WASI as well.
#[repr(C)]
pub struct wasmtime_store_t {
pub(crate) store: Store<StoreData>,
}
pub type CStoreContext<'a> = StoreContext<'a, StoreData>;
pub type CStoreContextMut<'a> = StoreContextMut<'a, StoreData>;
pub struct StoreData {
foreign: crate::ForeignData,
#[cfg(feature = "wasi")]
pub(crate) wasi: Option<wasmtime_wasi::WasiCtx>,
}
#[no_mangle]
pub extern "C" fn wasmtime_store_delete(_: Box<wasmtime_store_t>) {}
#[no_mangle]
pub extern "C" fn wasmtime_store_new(
engine: &wasm_engine_t,
data: *mut c_void,
finalizer: Option<extern "C" fn(*mut c_void)>,
) -> Box<wasmtime_store_t> {
Box::new(wasmtime_store_t {
store: Store::new(
&engine.engine,
StoreData {
foreign: ForeignData { data, finalizer },
#[cfg(feature = "wasi")]
wasi: None,
},
),
})
}
#[no_mangle]
pub extern "C" fn wasmtime_store_gc(store: &wasm_store_t) {
store.store.gc();
pub extern "C" fn wasmtime_store_context(store: &mut wasmtime_store_t) -> CStoreContextMut<'_> {
store.store.as_context_mut()
}
#[no_mangle]
pub extern "C" fn wasmtime_context_get_data(store: CStoreContext<'_>) -> *mut c_void {
store.data().foreign.data
}
#[no_mangle]
pub extern "C" fn wasmtime_context_set_data(mut store: CStoreContextMut<'_>, data: *mut c_void) {
store.data_mut().foreign.data = data;
}
#[cfg(feature = "wasi")]
#[no_mangle]
pub extern "C" fn wasmtime_context_set_wasi(
mut context: CStoreContextMut<'_>,
wasi: Box<crate::wasi_config_t>,
) -> Option<Box<wasmtime_error_t>> {
crate::handle_result(wasi.into_wasi_ctx(), |wasi| {
context.data_mut().wasi = Some(wasi);
})
}
#[no_mangle]
pub extern "C" fn wasmtime_context_gc(mut context: CStoreContextMut<'_>) {
context.gc();
}
#[no_mangle]
pub extern "C" fn wasmtime_context_add_fuel(
mut store: CStoreContextMut<'_>,
fuel: u64,
) -> Option<Box<wasmtime_error_t>> {
crate::handle_result(store.add_fuel(fuel), |()| {})
}
#[no_mangle]
pub extern "C" fn wasmtime_context_fuel_consumed(store: CStoreContext<'_>, fuel: &mut u64) -> bool {
match store.fuel_consumed() {
Some(amt) => {
*fuel = amt;
true
}
None => false,
}
}
#[repr(C)]
@@ -27,14 +145,12 @@ pub struct wasmtime_interrupt_handle_t {
handle: InterruptHandle,
}
wasmtime_c_api_macros::declare_own!(wasmtime_interrupt_handle_t);
#[no_mangle]
pub extern "C" fn wasmtime_interrupt_handle_new(
store: &wasm_store_t,
store: CStoreContext<'_>,
) -> Option<Box<wasmtime_interrupt_handle_t>> {
Some(Box::new(wasmtime_interrupt_handle_t {
handle: store.store.interrupt_handle().ok()?,
handle: store.interrupt_handle().ok()?,
}))
}
@@ -44,20 +160,4 @@ pub extern "C" fn wasmtime_interrupt_handle_interrupt(handle: &wasmtime_interrup
}
#[no_mangle]
pub extern "C" fn wasmtime_store_add_fuel(
store: &wasm_store_t,
fuel: u64,
) -> Option<Box<wasmtime_error_t>> {
crate::handle_result(store.store.add_fuel(fuel), |()| {})
}
#[no_mangle]
pub extern "C" fn wasmtime_store_fuel_consumed(store: &wasm_store_t, fuel: &mut u64) -> bool {
match store.store.fuel_consumed() {
Some(amt) => {
*fuel = amt;
true
}
None => false,
}
}
pub extern "C" fn wasmtime_interrupt_handle_delete(_: Box<wasmtime_interrupt_handle_t>) {}

View File

@@ -1,7 +1,9 @@
use crate::r#ref::{ref_to_val, val_into_ref};
use crate::{handle_result, wasm_func_t, wasm_ref_t, wasmtime_error_t};
use crate::{wasm_extern_t, wasm_store_t, wasm_tabletype_t};
use std::ptr;
use crate::{
handle_result, wasm_extern_t, wasm_ref_t, wasm_store_t, wasm_tabletype_t, wasmtime_error_t,
wasmtime_val_t, CStoreContext, CStoreContextMut,
};
use std::mem::MaybeUninit;
use wasmtime::{Extern, Table, TableType, Val, ValType};
#[derive(Clone)]
@@ -22,8 +24,8 @@ impl wasm_table_t {
}
}
fn table(&self) -> &Table {
match &self.ext.which {
fn table(&self) -> Table {
match self.ext.which {
Extern::Table(t) => t,
_ => unsafe { std::hint::unreachable_unchecked() },
}
@@ -42,135 +44,138 @@ fn ref_to_val_for_table(r: Option<&wasm_ref_t>, table_ty: &TableType) -> Val {
}
#[no_mangle]
pub extern "C" fn wasm_table_new(
store: &wasm_store_t,
pub unsafe extern "C" fn wasm_table_new(
store: &mut wasm_store_t,
tt: &wasm_tabletype_t,
init: Option<&wasm_ref_t>,
) -> Option<Box<wasm_table_t>> {
let init = ref_to_val_for_table(init, &tt.ty().ty);
let table = Table::new(&store.store, tt.ty().ty.clone(), init).ok()?;
let table = Table::new(store.store.context_mut(), tt.ty().ty.clone(), init).ok()?;
Some(Box::new(wasm_table_t {
ext: wasm_extern_t {
store: store.store.clone(),
which: table.into(),
},
}))
}
#[no_mangle]
pub extern "C" fn wasmtime_funcref_table_new(
store: &wasm_store_t,
tt: &wasm_tabletype_t,
init: Option<&wasm_func_t>,
out: &mut *mut wasm_table_t,
) -> Option<Box<wasmtime_error_t>> {
let init: Val = match init {
Some(val) => Val::FuncRef(Some(val.func().clone())),
None => Val::FuncRef(None),
};
handle_result(
Table::new(&store.store, tt.ty().ty.clone(), init),
|table| {
*out = Box::into_raw(Box::new(wasm_table_t {
ext: wasm_extern_t {
which: table.into(),
},
}));
},
)
pub unsafe extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
let table = t.table();
let store = t.ext.store.context();
Box::new(wasm_tabletype_t::new(table.ty(&store)))
}
#[no_mangle]
pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
let ty = t.table().ty();
Box::new(wasm_tabletype_t::new(ty))
}
#[no_mangle]
pub extern "C" fn wasm_table_get(
t: &wasm_table_t,
pub unsafe extern "C" fn wasm_table_get(
t: &mut wasm_table_t,
index: wasm_table_size_t,
) -> Option<Box<wasm_ref_t>> {
let val = t.table().get(index)?;
let table = t.table();
let val = table.get(t.ext.store.context_mut(), index)?;
val_into_ref(val)
}
#[no_mangle]
pub extern "C" fn wasmtime_funcref_table_get(
t: &wasm_table_t,
index: wasm_table_size_t,
ptr: &mut *mut wasm_func_t,
) -> bool {
match t.table().get(index) {
Some(val) => {
*ptr = match val {
Val::FuncRef(None) => ptr::null_mut(),
Val::FuncRef(Some(f)) => Box::into_raw(Box::new(f.into())),
_ => return false,
};
}
_ => return false,
}
true
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_set(
t: &wasm_table_t,
t: &mut wasm_table_t,
index: wasm_table_size_t,
r: Option<&wasm_ref_t>,
) -> bool {
let val = ref_to_val_for_table(r, &t.table().ty());
t.table().set(index, val).is_ok()
let table = t.table();
let val = ref_to_val_for_table(r, &table.ty(t.ext.store.context()));
table.set(t.ext.store.context_mut(), index, val).is_ok()
}
#[no_mangle]
pub extern "C" fn wasmtime_funcref_table_set(
t: &wasm_table_t,
index: wasm_table_size_t,
val: Option<&wasm_func_t>,
) -> Option<Box<wasmtime_error_t>> {
let val = match val {
Some(val) => Val::FuncRef(Some(val.func().clone())),
None => Val::FuncRef(None),
};
handle_result(t.table().set(index, val), |()| {})
}
#[no_mangle]
pub extern "C" fn wasm_table_size(t: &wasm_table_t) -> wasm_table_size_t {
t.table().size()
pub unsafe extern "C" fn wasm_table_size(t: &wasm_table_t) -> wasm_table_size_t {
let table = t.table();
let store = t.ext.store.context();
table.size(&store)
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_grow(
t: &wasm_table_t,
t: &mut wasm_table_t,
delta: wasm_table_size_t,
init: Option<&wasm_ref_t>,
) -> bool {
let init = ref_to_val_for_table(init, &t.table().ty());
t.table().grow(delta, init).is_ok()
let table = t.table();
let init = ref_to_val_for_table(init, &table.ty(t.ext.store.context()));
table.grow(t.ext.store.context_mut(), delta, init).is_ok()
}
#[no_mangle]
pub extern "C" fn wasmtime_funcref_table_grow(
t: &wasm_table_t,
delta: wasm_table_size_t,
init: Option<&wasm_func_t>,
prev_size: Option<&mut wasm_table_size_t>,
) -> Option<Box<wasmtime_error_t>> {
let val = match init {
Some(val) => Val::FuncRef(Some(val.func().clone())),
None => Val::FuncRef(None),
};
handle_result(t.table().grow(delta, val), |prev| {
if let Some(ptr) = prev_size {
*ptr = prev;
}
})
pub extern "C" fn wasm_table_as_extern(t: &mut wasm_table_t) -> &mut wasm_extern_t {
&mut t.ext
}
#[no_mangle]
pub extern "C" fn wasm_table_as_extern(t: &wasm_table_t) -> &wasm_extern_t {
pub extern "C" fn wasm_table_as_extern_const(t: &wasm_table_t) -> &wasm_extern_t {
&t.ext
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_table_new(
store: CStoreContextMut<'_>,
tt: &wasm_tabletype_t,
init: &wasmtime_val_t,
out: &mut Table,
) -> Option<Box<wasmtime_error_t>> {
handle_result(
Table::new(store, tt.ty().ty.clone(), init.to_val()),
|table| *out = table,
)
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_table_type(
store: CStoreContext<'_>,
table: &Table,
) -> Box<wasm_tabletype_t> {
Box::new(wasm_tabletype_t::new(table.ty(store)))
}
#[no_mangle]
pub extern "C" fn wasmtime_table_get(
store: CStoreContextMut<'_>,
table: &Table,
index: u32,
ret: &mut MaybeUninit<wasmtime_val_t>,
) -> bool {
match table.get(store, index) {
Some(val) => {
crate::initialize(ret, wasmtime_val_t::from_val(val));
true
}
None => false,
}
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_table_set(
store: CStoreContextMut<'_>,
table: &Table,
index: u32,
val: &wasmtime_val_t,
) -> Option<Box<wasmtime_error_t>> {
handle_result(table.set(store, index, val.to_val()), |()| {})
}
#[no_mangle]
pub extern "C" fn wasmtime_table_size(store: CStoreContext<'_>, table: &Table) -> u32 {
table.size(store)
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_table_grow(
store: CStoreContextMut<'_>,
table: &Table,
delta: u32,
val: &wasmtime_val_t,
prev_size: &mut u32,
) -> Option<Box<wasmtime_error_t>> {
handle_result(table.grow(store, delta, val.to_val()), |prev| {
*prev_size = prev
})
}

View File

@@ -44,6 +44,15 @@ pub extern "C" fn wasm_trap_new(
})
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_trap_new(message: *const u8, len: usize) -> Box<wasm_trap_t> {
let bytes = crate::slice_from_raw_parts(message, len);
let message = String::from_utf8_lossy(&bytes);
Box::new(wasm_trap_t {
trap: 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();
@@ -136,3 +145,8 @@ pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t) -> *mut wasm_i
pub extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t) -> usize {
frame.trap.trace()[frame.idx].module_offset()
}
#[no_mangle]
pub extern "C" fn wasm_frame_copy(frame: &wasm_frame_t) -> Box<wasm_frame_t> {
Box::new(frame.clone())
}

View File

@@ -1,5 +1,5 @@
use crate::{wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t};
use crate::{wasm_instancetype_t, wasm_moduletype_t};
use crate::{wasmtime_instancetype_t, wasmtime_moduletype_t};
use crate::{CFuncType, CGlobalType, CInstanceType, CMemoryType, CModuleType, CTableType};
use wasmtime::ExternType;
@@ -123,29 +123,15 @@ pub extern "C" fn wasm_externtype_as_memorytype_const(
}
#[no_mangle]
pub extern "C" fn wasm_externtype_as_moduletype(
pub extern "C" fn wasmtime_externtype_as_moduletype(
et: &wasm_externtype_t,
) -> Option<&wasm_moduletype_t> {
wasm_externtype_as_moduletype_const(et)
) -> Option<&wasmtime_moduletype_t> {
wasmtime_moduletype_t::try_from(et)
}
#[no_mangle]
pub extern "C" fn wasm_externtype_as_moduletype_const(
pub extern "C" fn wasmtime_externtype_as_instancetype(
et: &wasm_externtype_t,
) -> Option<&wasm_moduletype_t> {
wasm_moduletype_t::try_from(et)
}
#[no_mangle]
pub extern "C" fn wasm_externtype_as_instancetype(
et: &wasm_externtype_t,
) -> Option<&wasm_instancetype_t> {
wasm_externtype_as_instancetype_const(et)
}
#[no_mangle]
pub extern "C" fn wasm_externtype_as_instancetype_const(
et: &wasm_externtype_t,
) -> Option<&wasm_instancetype_t> {
wasm_instancetype_t::try_from(et)
) -> Option<&wasmtime_instancetype_t> {
wasmtime_instancetype_t::try_from(et)
}

View File

@@ -3,25 +3,25 @@ use wasmtime::InstanceType;
#[repr(transparent)]
#[derive(Clone)]
pub struct wasm_instancetype_t {
pub struct wasmtime_instancetype_t {
ext: wasm_externtype_t,
}
wasmtime_c_api_macros::declare_ty!(wasm_instancetype_t);
wasmtime_c_api_macros::declare_ty!(wasmtime_instancetype_t);
#[derive(Clone)]
pub(crate) struct CInstanceType {
pub(crate) ty: InstanceType,
}
impl wasm_instancetype_t {
pub(crate) fn new(ty: InstanceType) -> wasm_instancetype_t {
wasm_instancetype_t {
impl wasmtime_instancetype_t {
pub(crate) fn new(ty: InstanceType) -> wasmtime_instancetype_t {
wasmtime_instancetype_t {
ext: wasm_externtype_t::new(ty.into()),
}
}
pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_instancetype_t> {
pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasmtime_instancetype_t> {
match &e.which {
CExternType::Instance(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
@@ -42,20 +42,15 @@ impl CInstanceType {
}
}
#[no_mangle]
pub extern "C" fn wasm_instancetype_as_externtype(ty: &wasm_instancetype_t) -> &wasm_externtype_t {
&ty.ext
}
#[no_mangle]
pub extern "C" fn wasm_instancetype_as_externtype_const(
ty: &wasm_instancetype_t,
pub extern "C" fn wasmtime_instancetype_as_externtype(
ty: &wasmtime_instancetype_t,
) -> &wasm_externtype_t {
&ty.ext
}
#[no_mangle]
pub extern "C" fn wasm_instancetype_exports(
instance: &wasm_instancetype_t,
pub extern "C" fn wasmtime_instancetype_exports(
instance: &wasmtime_instancetype_t,
out: &mut wasm_exporttype_vec_t,
) {
let exports = instance

View File

@@ -6,25 +6,25 @@ use wasmtime::ModuleType;
#[repr(transparent)]
#[derive(Clone)]
pub struct wasm_moduletype_t {
pub struct wasmtime_moduletype_t {
ext: wasm_externtype_t,
}
wasmtime_c_api_macros::declare_ty!(wasm_moduletype_t);
wasmtime_c_api_macros::declare_ty!(wasmtime_moduletype_t);
#[derive(Clone)]
pub(crate) struct CModuleType {
pub(crate) ty: ModuleType,
}
impl wasm_moduletype_t {
pub(crate) fn new(ty: ModuleType) -> wasm_moduletype_t {
wasm_moduletype_t {
impl wasmtime_moduletype_t {
pub(crate) fn new(ty: ModuleType) -> wasmtime_moduletype_t {
wasmtime_moduletype_t {
ext: wasm_externtype_t::new(ty.into()),
}
}
pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_moduletype_t> {
pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasmtime_moduletype_t> {
match &e.which {
CExternType::Module(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
@@ -46,20 +46,15 @@ impl CModuleType {
}
#[no_mangle]
pub extern "C" fn wasm_moduletype_as_externtype(ty: &wasm_moduletype_t) -> &wasm_externtype_t {
&ty.ext
}
#[no_mangle]
pub extern "C" fn wasm_moduletype_as_externtype_const(
ty: &wasm_moduletype_t,
pub extern "C" fn wasmtime_moduletype_as_externtype(
ty: &wasmtime_moduletype_t,
) -> &wasm_externtype_t {
&ty.ext
}
#[no_mangle]
pub extern "C" fn wasm_moduletype_exports(
module: &wasm_moduletype_t,
pub extern "C" fn wasmtime_moduletype_exports(
module: &wasmtime_moduletype_t,
out: &mut wasm_exporttype_vec_t,
) {
let exports = module
@@ -77,8 +72,8 @@ pub extern "C" fn wasm_moduletype_exports(
}
#[no_mangle]
pub extern "C" fn wasm_moduletype_imports(
module: &wasm_moduletype_t,
pub extern "C" fn wasmtime_moduletype_imports(
module: &wasmtime_moduletype_t,
out: &mut wasm_importtype_vec_t,
) {
let imports = module

View File

@@ -36,6 +36,7 @@ pub(crate) fn into_valtype(kind: wasm_valkind_t) -> ValType {
WASM_F64 => ValType::F64,
WASM_EXTERNREF => ValType::ExternRef,
WASM_FUNCREF => ValType::FuncRef,
WASMTIME_V128 => ValType::V128,
_ => panic!("unexpected kind: {}", kind),
}
}
@@ -48,6 +49,15 @@ pub(crate) fn from_valtype(ty: &ValType) -> wasm_valkind_t {
ValType::F64 => WASM_F64,
ValType::ExternRef => WASM_EXTERNREF,
ValType::FuncRef => WASM_FUNCREF,
_ => panic!("wasm_valkind_t has no known conversion for {:?}", ty),
ValType::V128 => WASMTIME_V128,
}
}
pub type wasmtime_valkind_t = u8;
pub const WASMTIME_I32: wasmtime_valkind_t = 0;
pub const WASMTIME_I64: wasmtime_valkind_t = 1;
pub const WASMTIME_F32: wasmtime_valkind_t = 2;
pub const WASMTIME_F64: wasmtime_valkind_t = 3;
pub const WASMTIME_V128: wasmtime_valkind_t = 4;
pub const WASMTIME_FUNCREF: wasmtime_valkind_t = 5;
pub const WASMTIME_EXTERNREF: wasmtime_valkind_t = 6;

View File

@@ -1,8 +1,9 @@
use crate::r#ref::{ref_to_val, WasmRefInner};
use crate::{from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, WASM_I32};
use std::mem::MaybeUninit;
use crate::{from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, wasmtime_valkind_t, WASM_I32};
use std::ffi::c_void;
use std::mem::{self, ManuallyDrop, MaybeUninit};
use std::ptr;
use wasmtime::{Val, ValType};
use wasmtime::{ExternRef, Func, Val, ValType};
#[repr(C)]
pub struct wasm_val_t {
@@ -147,3 +148,143 @@ pub unsafe extern "C" fn wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source
pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
ptr::drop_in_place(val);
}
#[repr(C)]
pub struct wasmtime_val_t {
pub kind: wasmtime_valkind_t,
pub of: wasmtime_val_union,
}
#[repr(C)]
pub union wasmtime_val_union {
pub i32: i32,
pub i64: i64,
pub f32: u32,
pub f64: u64,
pub funcref: wasmtime_func_t,
pub externref: ManuallyDrop<Option<ExternRef>>,
pub v128: [u8; 16],
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct wasmtime_func_t {
pub store_id: u64,
pub index: usize,
}
impl wasmtime_val_t {
pub fn from_val(val: Val) -> wasmtime_val_t {
match val {
Val::I32(i) => wasmtime_val_t {
kind: crate::WASMTIME_I32,
of: wasmtime_val_union { i32: i },
},
Val::I64(i) => wasmtime_val_t {
kind: crate::WASMTIME_I64,
of: wasmtime_val_union { i64: i },
},
Val::F32(i) => wasmtime_val_t {
kind: crate::WASMTIME_F32,
of: wasmtime_val_union { f32: i },
},
Val::F64(i) => wasmtime_val_t {
kind: crate::WASMTIME_F64,
of: wasmtime_val_union { f64: i },
},
Val::ExternRef(i) => wasmtime_val_t {
kind: crate::WASMTIME_EXTERNREF,
of: wasmtime_val_union {
externref: ManuallyDrop::new(i),
},
},
Val::FuncRef(i) => wasmtime_val_t {
kind: crate::WASMTIME_FUNCREF,
of: wasmtime_val_union {
funcref: match i {
Some(func) => unsafe { mem::transmute::<Func, wasmtime_func_t>(func) },
None => wasmtime_func_t {
store_id: 0,
index: 0,
},
},
},
},
Val::V128(val) => wasmtime_val_t {
kind: crate::WASMTIME_V128,
of: wasmtime_val_union {
v128: val.to_le_bytes(),
},
},
}
}
pub unsafe fn to_val(&self) -> Val {
match self.kind {
crate::WASMTIME_I32 => Val::I32(self.of.i32),
crate::WASMTIME_I64 => Val::I64(self.of.i64),
crate::WASMTIME_F32 => Val::F32(self.of.f32),
crate::WASMTIME_F64 => Val::F64(self.of.f64),
crate::WASMTIME_V128 => Val::V128(u128::from_le_bytes(self.of.v128)),
crate::WASMTIME_FUNCREF => {
let store = self.of.funcref.store_id;
let index = self.of.funcref.index;
Val::FuncRef(if store == 0 && index == 0 {
None
} else {
Some(mem::transmute::<wasmtime_func_t, Func>(self.of.funcref))
})
}
crate::WASMTIME_EXTERNREF => Val::ExternRef((*self.of.externref).clone()),
other => panic!("unknown wasmtime_valkind_t: {}", other),
}
}
}
impl Drop for wasmtime_val_t {
fn drop(&mut self) {
if self.kind == crate::WASMTIME_EXTERNREF {
unsafe {
ManuallyDrop::drop(&mut self.of.externref);
}
}
}
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_val_delete(val: &mut ManuallyDrop<wasmtime_val_t>) {
ManuallyDrop::drop(val)
}
#[no_mangle]
pub unsafe extern "C" fn wasmtime_val_copy(
dst: &mut MaybeUninit<wasmtime_val_t>,
src: &wasmtime_val_t,
) {
crate::initialize(dst, wasmtime_val_t::from_val(src.to_val()))
}
#[no_mangle]
pub extern "C" fn wasmtime_externref_new(
data: *mut c_void,
finalizer: Option<extern "C" fn(*mut c_void)>,
) -> ExternRef {
ExternRef::new(crate::ForeignData { data, finalizer })
}
#[no_mangle]
pub extern "C" fn wasmtime_externref_data(externref: ManuallyDrop<ExternRef>) -> *mut c_void {
externref
.data()
.downcast_ref::<crate::ForeignData>()
.unwrap()
.data
}
#[no_mangle]
pub extern "C" fn wasmtime_externref_clone(externref: ManuallyDrop<ExternRef>) -> ExternRef {
(*externref).clone()
}
#[no_mangle]
pub extern "C" fn wasmtime_externref_delete(_val: Option<ExternRef>) {}

View File

@@ -1,7 +1,7 @@
use crate::{
wasm_exporttype_t, wasm_extern_t, wasm_externtype_t, wasm_frame_t, wasm_functype_t,
wasm_globaltype_t, wasm_importtype_t, wasm_instancetype_t, wasm_memorytype_t,
wasm_moduletype_t, wasm_tabletype_t, wasm_val_t, wasm_valtype_t,
wasm_globaltype_t, wasm_importtype_t, wasm_memorytype_t, wasm_tabletype_t, wasm_val_t,
wasm_valtype_t,
};
use std::mem;
use std::mem::MaybeUninit;
@@ -186,24 +186,6 @@ declare_vecs! {
copy: wasm_memorytype_vec_copy,
delete: wasm_memorytype_vec_delete,
)
(
name: wasm_instancetype_vec_t,
ty: Option<Box<wasm_instancetype_t>>,
new: wasm_instancetype_vec_new,
empty: wasm_instancetype_vec_new_empty,
uninit: wasm_instancetype_vec_new_uninitialized,
copy: wasm_instancetype_vec_copy,
delete: wasm_instancetype_vec_delete,
)
(
name: wasm_moduletype_vec_t,
ty: Option<Box<wasm_moduletype_t>>,
new: wasm_moduletype_vec_new,
empty: wasm_moduletype_vec_new_empty,
uninit: wasm_moduletype_vec_new_uninitialized,
copy: wasm_moduletype_vec_copy,
delete: wasm_moduletype_vec_delete,
)
(
name: wasm_externtype_vec_t,
ty: Option<Box<wasm_externtype_t>>,

View File

@@ -1,21 +1,13 @@
//! The WASI embedding API definitions for Wasmtime.
use crate::{wasm_extern_t, wasm_importtype_t, wasm_store_t, wasm_trap_t};
use anyhow::Result;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ffi::CStr;
use std::fs::File;
use std::os::raw::{c_char, c_int};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::slice;
use std::str;
use wasmtime::{Extern, Linker, Trap};
use wasmtime_wasi::{
sync::{
snapshots::preview_0::Wasi as WasiSnapshot0, snapshots::preview_1::Wasi as WasiPreview1,
Dir, WasiCtxBuilder,
},
sync::{Dir, WasiCtxBuilder},
WasiCtx,
};
@@ -31,13 +23,6 @@ unsafe fn create_file(path: *const c_char) -> Option<File> {
File::create(cstr_to_path(path)?).ok()
}
pub enum WasiModule {
Snapshot0(WasiSnapshot0),
Preview1(WasiPreview1),
}
impl WasiModule {}
#[repr(C)]
#[derive(Default)]
pub struct wasi_config_t {
@@ -54,6 +39,61 @@ pub struct wasi_config_t {
inherit_stderr: bool,
}
impl wasi_config_t {
pub fn into_wasi_ctx(self) -> Result<WasiCtx> {
let mut builder = WasiCtxBuilder::new();
if self.inherit_args {
builder = builder.inherit_args()?;
} else if !self.args.is_empty() {
let args = self
.args
.into_iter()
.map(|bytes| Ok(String::from_utf8(bytes)?))
.collect::<Result<Vec<String>>>()?;
builder = builder.args(&args)?;
}
if self.inherit_env {
builder = builder.inherit_env()?;
} else if !self.env.is_empty() {
let env = self
.env
.into_iter()
.map(|(kbytes, vbytes)| {
let k = String::from_utf8(kbytes)?;
let v = String::from_utf8(vbytes)?;
Ok((k, v))
})
.collect::<Result<Vec<(String, String)>>>()?;
builder = builder.envs(&env)?;
}
if self.inherit_stdin {
builder = builder.inherit_stdin();
} else if let Some(file) = self.stdin {
let file = unsafe { cap_std::fs::File::from_std(file) };
let file = wasi_cap_std_sync::file::File::from_cap_std(file);
builder = builder.stdin(Box::new(file));
}
if self.inherit_stdout {
builder = builder.inherit_stdout();
} else if let Some(file) = self.stdout {
let file = unsafe { cap_std::fs::File::from_std(file) };
let file = wasi_cap_std_sync::file::File::from_cap_std(file);
builder = builder.stdout(Box::new(file));
}
if self.inherit_stderr {
builder = builder.inherit_stderr();
} else if let Some(file) = self.stderr {
let file = unsafe { cap_std::fs::File::from_std(file) };
let file = wasi_cap_std_sync::file::File::from_cap_std(file);
builder = builder.stderr(Box::new(file));
}
for (dir, path) in self.preopens {
builder = builder.preopened_dir(dir, path)?;
}
Ok(builder.build())
}
}
#[no_mangle]
pub extern "C" fn wasi_config_new() -> Box<wasi_config_t> {
Box::new(wasi_config_t::default())
@@ -198,151 +238,3 @@ pub unsafe extern "C" fn wasi_config_preopen_dir(
true
}
enum WasiInstance {
Preview1(WasiPreview1),
Snapshot0(WasiSnapshot0),
}
fn create_wasi_ctx(config: wasi_config_t) -> Result<Rc<RefCell<WasiCtx>>> {
let mut builder = WasiCtxBuilder::new();
if config.inherit_args {
builder = builder.inherit_args()?;
} else if !config.args.is_empty() {
let args = config
.args
.into_iter()
.map(|bytes| Ok(String::from_utf8(bytes)?))
.collect::<Result<Vec<String>>>()?;
builder = builder.args(&args)?;
}
if config.inherit_env {
builder = builder.inherit_env()?;
} else if !config.env.is_empty() {
let env = config
.env
.into_iter()
.map(|(kbytes, vbytes)| {
let k = String::from_utf8(kbytes)?;
let v = String::from_utf8(vbytes)?;
Ok((k, v))
})
.collect::<Result<Vec<(String, String)>>>()?;
builder = builder.envs(&env)?;
}
if config.inherit_stdin {
builder = builder.inherit_stdin();
} else if let Some(file) = config.stdin {
let file = unsafe { cap_std::fs::File::from_std(file) };
let file = wasi_cap_std_sync::file::File::from_cap_std(file);
builder = builder.stdin(Box::new(file));
}
if config.inherit_stdout {
builder = builder.inherit_stdout();
} else if let Some(file) = config.stdout {
let file = unsafe { cap_std::fs::File::from_std(file) };
let file = wasi_cap_std_sync::file::File::from_cap_std(file);
builder = builder.stdout(Box::new(file));
}
if config.inherit_stderr {
builder = builder.inherit_stderr();
} else if let Some(file) = config.stderr {
let file = unsafe { cap_std::fs::File::from_std(file) };
let file = wasi_cap_std_sync::file::File::from_cap_std(file);
builder = builder.stderr(Box::new(file));
}
for (dir, path) in config.preopens {
builder = builder.preopened_dir(dir, path)?;
}
Ok(Rc::new(RefCell::new(builder.build())))
}
#[repr(C)]
pub struct wasi_instance_t {
wasi: WasiInstance,
export_cache: HashMap<String, Box<wasm_extern_t>>,
}
impl wasi_instance_t {
pub fn add_to_linker(&self, linker: &mut Linker) -> Result<()> {
match &self.wasi {
WasiInstance::Snapshot0(w) => w.add_to_linker(linker),
WasiInstance::Preview1(w) => w.add_to_linker(linker),
}
}
}
#[no_mangle]
pub unsafe extern "C" fn wasi_instance_new(
store: &wasm_store_t,
name: *const c_char,
config: Box<wasi_config_t>,
trap: &mut *mut wasm_trap_t,
) -> Option<Box<wasi_instance_t>> {
let store = &store.store;
let result = match CStr::from_ptr(name).to_str().unwrap_or("") {
"wasi_snapshot_preview1" => {
create_wasi_ctx(*config).map(|cx| WasiInstance::Preview1(WasiPreview1::new(store, cx)))
}
"wasi_unstable" => create_wasi_ctx(*config)
.map(|cx| WasiInstance::Snapshot0(WasiSnapshot0::new(store, cx))),
_ => Err(anyhow::anyhow!("unsupported WASI version")),
};
match result {
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: Trap::from(e),
}));
None
}
}
}
#[no_mangle]
pub extern "C" fn wasi_instance_delete(_instance: Box<wasi_instance_t>) {}
#[no_mangle]
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.module;
let name = str::from_utf8(import.name.as_ref()?.as_bytes()).ok()?;
let export = match &instance.wasi {
WasiInstance::Preview1(wasi) => {
if module != "wasi_snapshot_preview1" {
return None;
}
wasi.get_export(&name)?
}
WasiInstance::Snapshot0(wasi) => {
if module != "wasi_unstable" {
return None;
}
wasi.get_export(&name)?
}
};
if &export.ty() != import.ty.func()? {
return None;
}
let entry = instance
.export_cache
.entry(name.to_string())
.or_insert_with(|| {
Box::new(wasm_extern_t {
which: Extern::Func(export.clone()),
})
});
Some(entry)
}

View File

@@ -1,11 +1,13 @@
use crate::{bad_utf8, handle_result, wasm_byte_vec_t, wasmtime_error_t};
#[no_mangle]
pub extern "C" fn wasmtime_wat2wasm(
wat: &wasm_byte_vec_t,
pub unsafe extern "C" fn wasmtime_wat2wasm(
wat: *const u8,
wat_len: usize,
ret: &mut wasm_byte_vec_t,
) -> Option<Box<wasmtime_error_t>> {
let wat = match std::str::from_utf8(wat.as_slice()) {
let wat = crate::slice_from_raw_parts(wat, wat_len);
let wat = match std::str::from_utf8(wat) {
Ok(s) => s,
Err(_) => return bad_utf8(),
};