Skip to content

Commit

Permalink
Port C API to new Context API
Browse files Browse the repository at this point in the history
  • Loading branch information
epilys committed Jun 26, 2022
1 parent c0f8d04 commit d647351
Show file tree
Hide file tree
Showing 29 changed files with 523 additions and 421 deletions.
8 changes: 8 additions & 0 deletions lib/api/src/sys/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ impl<T> Context<T> {
pub fn store(&self) -> &Store {
&self.inner.store
}

/// For use with the C API
/// # Safety
///
/// This is unsafe.
pub unsafe fn transmute_data<U>(&mut self) -> &mut Context<U> {
core::mem::transmute::<&mut Self, &mut Context<U>>(self)
}
}

/// A temporary handle to a [`Context`].
Expand Down
5 changes: 3 additions & 2 deletions lib/api/src/sys/externals/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl Extern {
}

/// Create an `Extern` from an `wasmer_engine::Export`.
pub(crate) fn from_vm_extern(ctx: &mut impl AsContextMut, vm_extern: VMExtern) -> Self {
pub fn from_vm_extern(ctx: &mut impl AsContextMut, vm_extern: VMExtern) -> Self {
match vm_extern {
VMExtern::Function(f) => Self::Function(Function::from_vm_extern(ctx, f)),
VMExtern::Memory(m) => Self::Memory(Memory::from_vm_extern(ctx, m)),
Expand All @@ -63,7 +63,8 @@ impl Extern {
}
}

pub(crate) fn to_vm_extern(&self) -> VMExtern {
/// To `VMExtern`.
pub fn to_vm_extern(&self) -> VMExtern {
match self {
Self::Function(f) => f.to_vm_extern(),
Self::Global(g) => g.to_vm_extern(),
Expand Down
40 changes: 40 additions & 0 deletions lib/c-api/src/wasm_c_api/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use crate::wasm_c_api::store::wasm_store_t;
use libc::c_void;
use wasmer_api::Context;

/// Opaque type representing a WebAssembly context.
#[allow(non_camel_case_types)]
pub struct wasm_context_t {
pub(crate) inner: Context<*mut c_void>,
}

impl core::fmt::Debug for wasm_context_t {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "wasm_context_t")
}
}

/// Creates a new WebAssembly Context given a specific [engine][super::engine].
///
/// # Example
///
/// See the module's documentation.
#[no_mangle]
pub unsafe extern "C" fn wasm_context_new(
store: Option<&wasm_store_t>,
data: *mut c_void,
) -> Option<Box<wasm_context_t>> {
let store = store?;

Some(Box::new(wasm_context_t {
inner: Context::new(&store.inner, data),
}))
}

/// Deletes a WebAssembly context.
///
/// # Example
///
/// See the module's documentation.
#[no_mangle]
pub unsafe extern "C" fn wasm_context_delete(_context: Option<Box<wasm_context_t>>) {}
129 changes: 30 additions & 99 deletions lib/c-api/src/wasm_c_api/externals/function.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::super::context::wasm_context_t;
use super::super::store::wasm_store_t;
use super::super::trap::wasm_trap_t;
use super::super::types::{wasm_functype_t, wasm_valkind_enum};
Expand All @@ -7,21 +8,23 @@ use std::convert::TryInto;
use std::ffi::c_void;
use std::mem::MaybeUninit;
use std::sync::{Arc, Mutex};
use wasmer_api::{Function, RuntimeError, Val};
use wasmer_api::{Function, RuntimeError, Value};

#[derive(Debug, Clone)]
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct wasm_func_t {
pub(crate) tag: CApiExternTag,
pub(crate) inner: Box<Function>,
pub(crate) context: Option<Arc<Mutex<wasm_context_t>>>,
}

impl wasm_func_t {
pub(crate) fn new(function: Function) -> Self {
Self {
tag: CApiExternTag::Function,
inner: Box::new(function),
context: None,
}
}
}
Expand All @@ -44,95 +47,20 @@ pub type wasm_env_finalizer_t = unsafe extern "C" fn(*mut c_void);

#[no_mangle]
pub unsafe extern "C" fn wasm_func_new(
store: Option<&wasm_store_t>,
store: Option<&mut wasm_store_t>,
function_type: Option<&wasm_functype_t>,
callback: Option<wasm_func_callback_t>,
) -> Option<Box<wasm_func_t>> {
let store = store?;
let function_type = function_type?;
let callback = callback?;

let func_sig = &function_type.inner().function_type;
let num_rets = func_sig.results().len();
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
let processed_args: wasm_val_vec_t = args
.iter()
.map(TryInto::try_into)
.collect::<Result<Vec<wasm_val_t>, _>>()
.expect("Argument conversion failed")
.into();

let mut results: wasm_val_vec_t = vec![
wasm_val_t {
kind: wasm_valkind_enum::WASM_I64 as _,
of: wasm_val_inner { int64_t: 0 },
};
num_rets
]
.into();

let trap = callback(&processed_args, &mut results);

if let Some(trap) = trap {
return Err(trap.inner);
}

let processed_results = results
.take()
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.expect("Result conversion failed");

Ok(processed_results)
};
let function = Function::new(&store.inner, func_sig, inner_callback);

Some(Box::new(wasm_func_t::new(function)))
}

#[no_mangle]
pub unsafe extern "C" fn wasm_func_new_with_env(
store: Option<&wasm_store_t>,
function_type: Option<&wasm_functype_t>,
callback: Option<wasm_func_callback_with_env_t>,
env: *mut c_void,
env_finalizer: Option<wasm_env_finalizer_t>,
) -> Option<Box<wasm_func_t>> {
let store = store?;
let function_type = function_type?;
let callback = callback?;
let ctx = store.context.as_mut()?;

let func_sig = &function_type.inner().function_type;
let num_rets = func_sig.results().len();

#[derive(Clone)]
#[repr(C)]
struct WrapperEnv {
env: *mut c_void,
env_finalizer: Arc<Mutex<Option<wasm_env_finalizer_t>>>,
}

impl wasmer_api::WasmerEnv for WrapperEnv {}

// Only relevant when using multiple threads in the C API;
// Synchronization will be done via the C API / on the C side.
unsafe impl Send for WrapperEnv {}
unsafe impl Sync for WrapperEnv {}

impl Drop for WrapperEnv {
fn drop(&mut self) {
if let Ok(mut guard) = self.env_finalizer.lock() {
if Arc::strong_count(&self.env_finalizer) == 1 {
if let Some(env_finalizer) = guard.take() {
unsafe { (env_finalizer)(self.env as _) };
}
}
}
}
}

let trampoline = move |env: &WrapperEnv, args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
let inner_callback = move |_ctx: wasmer_api::ContextMut<'_, *mut c_void>,
args: &[Value]|
-> Result<Vec<Value>, RuntimeError> {
let processed_args: wasm_val_vec_t = args
.iter()
.map(TryInto::try_into)
Expand All @@ -149,7 +77,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
]
.into();

let trap = callback(env.env, &processed_args, &mut results);
let trap = callback(&processed_args, &mut results);

if let Some(trap) = trap {
return Err(trap.inner);
Expand All @@ -159,23 +87,18 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
.take()
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.collect::<Result<Vec<Value>, _>>()
.expect("Result conversion failed");

Ok(processed_results)
};
let mut lck = ctx.lock().unwrap();
let function = Function::new(&mut lck.inner, func_sig, inner_callback);
drop(lck);
let mut retval = Box::new(wasm_func_t::new(function));
retval.context = store.context.clone();

let function = Function::new_with_env(
&store.inner,
func_sig,
WrapperEnv {
env,
env_finalizer: Arc::new(Mutex::new(env_finalizer)),
},
trampoline,
);

Some(Box::new(wasm_func_t::new(function)))
Some(retval)
}

#[no_mangle]
Expand All @@ -194,16 +117,18 @@ pub unsafe extern "C" fn wasm_func_call(
) -> Option<Box<wasm_trap_t>> {
let func = func?;
let args = args?;
let ctx = func.context.as_ref()?;

let params = args
.as_slice()
.iter()
.cloned()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.collect::<Result<Vec<Value>, _>>()
.expect("Arguments conversion failed");

match func.inner.call(&params) {
let mut lck = ctx.lock().unwrap();
match func.inner.call(&mut lck.inner, &params) {
Ok(wasm_results) => {
for (slot, val) in results
.as_uninit_slice()
Expand All @@ -221,17 +146,23 @@ pub unsafe extern "C" fn wasm_func_call(

#[no_mangle]
pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t) -> usize {
func.inner.ty().params().len()
let ctx = func.context.as_ref().unwrap();
let lck = ctx.lock().unwrap();
func.inner.ty(&lck.inner).params().len()
}

#[no_mangle]
pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize {
func.inner.ty().results().len()
let ctx = func.context.as_ref().unwrap();
let lck = ctx.lock().unwrap();
func.inner.ty(&lck.inner).results().len()
}

#[no_mangle]
pub extern "C" fn wasm_func_type(func: Option<&wasm_func_t>) -> Option<Box<wasm_functype_t>> {
let func = func?;
let ctx = func.context.as_ref().unwrap();
let lck = ctx.lock().unwrap();

Some(Box::new(wasm_functype_t::new(func.inner.ty().clone())))
Some(Box::new(wasm_functype_t::new(func.inner.ty(&lck.inner))))
}
Loading

0 comments on commit d647351

Please sign in to comment.