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 24, 2022
1 parent c0f8d04 commit 7c5aaa2
Show file tree
Hide file tree
Showing 28 changed files with 426 additions and 434 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
34 changes: 34 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,34 @@
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>,
}

/// 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>>) {}
126 changes: 23 additions & 103 deletions lib/c-api/src/wasm_c_api/externals/function.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use super::super::store::wasm_store_t;
use super::super::context::wasm_context_t;
use super::super::trap::wasm_trap_t;
use super::super::types::{wasm_functype_t, wasm_valkind_enum};
use super::super::value::{wasm_val_inner, wasm_val_t, wasm_val_vec_t};
use super::CApiExternTag;
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)]
Expand Down Expand Up @@ -44,17 +43,19 @@ 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>,
ctx: Option<&mut wasm_context_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 ctx = ctx?;

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 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 @@ -81,99 +82,12 @@ pub unsafe extern "C" fn wasm_func_new(
.take()
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.collect::<Result<Vec<Value>, _>>()
.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 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 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(env.env, &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_with_env(
&store.inner,
func_sig,
WrapperEnv {
env,
env_finalizer: Arc::new(Mutex::new(env_finalizer)),
},
trampoline,
);
let function = Function::new(&mut ctx.inner, func_sig, inner_callback);

Some(Box::new(wasm_func_t::new(function)))
}
Expand All @@ -191,7 +105,9 @@ pub unsafe extern "C" fn wasm_func_call(
func: Option<&wasm_func_t>,
args: Option<&wasm_val_vec_t>,
results: &mut wasm_val_vec_t,
ctx: Option<&mut wasm_context_t>,
) -> Option<Box<wasm_trap_t>> {
let ctx = ctx?;
let func = func?;
let args = args?;

Expand All @@ -200,10 +116,10 @@ pub unsafe extern "C" fn wasm_func_call(
.iter()
.cloned()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.collect::<Result<Vec<Value>, _>>()
.expect("Arguments conversion failed");

match func.inner.call(&params) {
match func.inner.call(&mut ctx.inner, &params) {
Ok(wasm_results) => {
for (slot, val) in results
.as_uninit_slice()
Expand All @@ -220,18 +136,22 @@ 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()
pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t, ctx: &wasm_context_t) -> usize {
func.inner.ty(&ctx.inner).params().len()
}

#[no_mangle]
pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize {
func.inner.ty().results().len()
pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t, ctx: &wasm_context_t) -> usize {
func.inner.ty(&ctx.inner).results().len()
}

#[no_mangle]
pub extern "C" fn wasm_func_type(func: Option<&wasm_func_t>) -> Option<Box<wasm_functype_t>> {
pub extern "C" fn wasm_func_type(
func: Option<&wasm_func_t>,
ctx: Option<&wasm_context_t>,
) -> Option<Box<wasm_functype_t>> {
let func = func?;
let ctx = ctx?;

Some(Box::new(wasm_functype_t::new(func.inner.ty().clone())))
Some(Box::new(wasm_functype_t::new(func.inner.ty(&ctx.inner))))
}
41 changes: 20 additions & 21 deletions lib/c-api/src/wasm_c_api/externals/global.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::super::store::wasm_store_t;
use super::super::context::wasm_context_t;
use super::super::types::wasm_globaltype_t;
use super::super::value::wasm_val_t;
use super::CApiExternTag;
use crate::error::update_last_error;
use std::convert::TryInto;
use wasmer_api::{Global, Val};
use wasmer_api::{Global, Value};

#[allow(non_camel_case_types)]
#[repr(C)]
Expand All @@ -25,21 +25,20 @@ impl wasm_global_t {

#[no_mangle]
pub unsafe extern "C" fn wasm_global_new(
store: Option<&wasm_store_t>,
ctx: Option<&mut wasm_context_t>,
global_type: Option<&wasm_globaltype_t>,
val: Option<&wasm_val_t>,
) -> Option<Box<wasm_global_t>> {
let store = store?;
let global_type = global_type?;
let ctx = ctx?;
let val = val?;

let global_type = &global_type.inner().global_type;
let wasm_val = val.try_into().ok()?;
let store = &store.inner;
let global = if global_type.mutability.is_mutable() {
Global::new_mut(store, wasm_val)
Global::new_mut(&mut ctx.inner, wasm_val)
} else {
Global::new(store, wasm_val)
Global::new(&mut ctx.inner, wasm_val)
};

Some(Box::new(wasm_global_t::new(global)))
Expand All @@ -59,33 +58,33 @@ pub unsafe extern "C" fn wasm_global_get(
global: &wasm_global_t,
// own
out: &mut wasm_val_t,
ctx: &mut wasm_context_t,
) {
let value = global.inner.get();
let value = global.inner.get(&mut ctx.inner);
*out = value.try_into().unwrap();
}

/// Note: This function returns nothing by design but it can raise an
/// error if setting a new value fails.
#[no_mangle]
pub unsafe extern "C" fn wasm_global_set(global: &mut wasm_global_t, val: &wasm_val_t) {
let value: Val = val.try_into().unwrap();
pub unsafe extern "C" fn wasm_global_set(
global: &mut wasm_global_t,
val: &wasm_val_t,
ctx: &mut wasm_context_t,
) {
let value: Value = val.try_into().unwrap();

if let Err(e) = global.inner.set(value) {
if let Err(e) = global.inner.set(&mut ctx.inner, value) {
update_last_error(e);
}
}

#[no_mangle]
pub unsafe extern "C" fn wasm_global_same(
wasm_global1: &wasm_global_t,
wasm_global2: &wasm_global_t,
) -> bool {
wasm_global1.inner.same(&wasm_global2.inner)
}

#[no_mangle]
pub extern "C" fn wasm_global_type(global: &wasm_global_t) -> Box<wasm_globaltype_t> {
Box::new(wasm_globaltype_t::new(*global.inner.ty()))
pub extern "C" fn wasm_global_type(
global: &wasm_global_t,
ctx: &wasm_context_t,
) -> Box<wasm_globaltype_t> {
Box::new(wasm_globaltype_t::new(global.inner.ty(&ctx.inner)))
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 7c5aaa2

Please sign in to comment.