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:
@@ -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 }
|
||||
|
||||
@@ -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)))
|
||||
}
|
||||
|
||||
@@ -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, ¶ms, &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(¶ms, &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(¶ms)));
|
||||
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
f.call(func.ext.store.context_mut(), ¶ms)
|
||||
}));
|
||||
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, ¶ms)));
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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()), |()| {})
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 }));
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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>) {}
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>) {}
|
||||
|
||||
@@ -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>>,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user