Skip to content

Commit

Permalink
Merge #1699
Browse files Browse the repository at this point in the history
1699: feat(c-api) Update `wasm-c-api` repository r=Hywan a=Hywan

This change is important because `wasm.h` contains new functions, like
`wasm_name_new_from_string_nt`, which are useful for the Go
implementation.

Co-authored-by: Ivan Enderlin <ivan@mnt.io>
  • Loading branch information
bors[bot] and Hywan authored Oct 19, 2020
2 parents 1bb3b99 + a73e457 commit aeea0d6
Show file tree
Hide file tree
Showing 42 changed files with 540 additions and 438 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

### Added

- [#1699](https://github.com/wasmerio/wasmer/pull/1699) Update `wasm.h` to its latest version.
- [#1685](https://github.com/wasmerio/wasmer/pull/1685) Implement `wasm_exporttype_delete` in the Wasm C API.
- [#1725](https://github.com/wasmerio/wasmer/pull/1725) Implement `wasm_func_type` in the Wasm C API.
- [#1715](https://github.com/wasmerio/wasmer/pull/1715) Register errors from `wasm_module_serialize` in the Wasm C API.
- [#1709](https://github.com/wasmerio/wasmer/pull/1709) Implement `wasm_module_name` and `wasm_module_set_name` in the Wasm(er) C API.
Expand Down
2 changes: 2 additions & 0 deletions lib/c-api/src/wasm_c_api/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub extern "C" fn wasm_config_set_engine(config: &mut wasm_config_t, engine: was
}

/// cbindgen:ignore
#[allow(non_camel_case_types)]
pub struct wasm_engine_t {
pub(crate) inner: Arc<dyn Engine + Send + Sync>,
}
Expand Down Expand Up @@ -170,6 +171,7 @@ pub extern "C" fn wasm_engine_new_with_config(
// TODO: return useful error messages in failure branches
cfg_if! {
if #[cfg(feature = "compiler")] {
#[allow(unused_mut)]
let mut compiler_config: Box<dyn CompilerConfig> = match config.compiler {
wasmer_compiler_t::CRANELIFT => {
cfg_if! {
Expand Down
74 changes: 48 additions & 26 deletions lib/c-api/src/wasm_c_api/externals/function.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::super::store::wasm_store_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};
use super::super::value::{wasm_val_inner, wasm_val_t, wasm_val_vec_t};
use std::convert::TryInto;
use std::ffi::c_void;
use std::sync::Arc;
Expand All @@ -15,14 +15,16 @@ pub struct wasm_func_t {
}

#[allow(non_camel_case_types)]
pub type wasm_func_callback_t =
unsafe extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> *mut wasm_trap_t;
pub type wasm_func_callback_t = unsafe extern "C" fn(
args: *const wasm_val_vec_t,
results: *mut wasm_val_vec_t,
) -> *mut wasm_trap_t;

#[allow(non_camel_case_types)]
pub type wasm_func_callback_with_env_t = unsafe extern "C" fn(
*mut c_void,
args: *const wasm_val_t,
results: *mut wasm_val_t,
args: *const wasm_val_vec_t,
results: *mut wasm_val_vec_t,
) -> *mut wasm_trap_t;

#[allow(non_camel_case_types)]
Expand All @@ -38,31 +40,37 @@ pub unsafe extern "C" fn wasm_func_new(
let func_sig = ft.sig();
let num_rets = func_sig.results().len();
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
let processed_args = args
let processed_args: wasm_val_vec_t = args
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<wasm_val_t>, _>>()
.expect("Argument conversion failed");
.expect("Argument conversion failed")
.into();

let mut results = vec![
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);

let trap = callback(processed_args.as_ptr(), results.as_mut_ptr());
if !trap.is_null() {
let trap: Box<wasm_trap_t> = Box::from_raw(trap);
RuntimeError::raise(Box::new(trap.inner));
}

let processed_results = results
.into_slice()
.expect("Failed to convert `results` into a slice")
.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);
Expand All @@ -86,30 +94,36 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
let num_rets = func_sig.results().len();
let inner_callback =
move |env: &mut *mut c_void, args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
let processed_args = args
let processed_args: wasm_val_vec_t = args
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<wasm_val_t>, _>>()
.expect("Argument conversion failed");
.expect("Argument conversion failed")
.into();

let mut results = vec![
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 _traps = callback(*env, processed_args.as_ptr(), results.as_mut_ptr());
let _traps = callback(*env, &processed_args, &mut results);
// TODO: do something with `traps`

let processed_results = results
.into_slice()
.expect("Failed to convert `results` into a slice")
.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, env, inner_callback);

Some(Box::new(wasm_func_t {
Expand All @@ -124,21 +138,29 @@ pub unsafe extern "C" fn wasm_func_delete(_func: Option<Box<wasm_func_t>>) {}
#[no_mangle]
pub unsafe extern "C" fn wasm_func_call(
func: &wasm_func_t,
args: *const wasm_val_t,
results: *mut wasm_val_t,
args: &wasm_val_vec_t,
results: &mut wasm_val_vec_t,
) -> Option<Box<wasm_trap_t>> {
let num_params = func.inner.ty().params().len();
let params: Vec<Val> = (0..num_params)
.map(|i| (&(*args.add(i))).try_into())
.collect::<Result<_, _>>()
.ok()?;
let params = args
.into_slice()
.map(|slice| {
slice
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.expect("Argument conversion failed")
})
.unwrap_or_default();

match func.inner.call(&params) {
Ok(wasm_results) => {
for (i, actual_result) in wasm_results.iter().enumerate() {
let result_loc = &mut (*results.add(i));
*result_loc = (&*actual_result).try_into().ok()?;
}
*results = wasm_results
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<wasm_val_t>, _>>()
.expect("Argument conversion failed")
.into();

None
}
Err(e) => Some(Box::new(e.into())),
Expand Down
43 changes: 4 additions & 39 deletions lib/c-api/src/wasm_c_api/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,56 +12,21 @@ pub struct wasm_instance_t {
pub(crate) inner: Arc<Instance>,
}

struct CArrayIter<T: Sized + 'static> {
cur_entry: *const *const T,
}

impl<T: Sized + 'static> CArrayIter<T> {
fn new(array: *const *const T) -> Option<Self> {
if array.is_null() {
None
} else {
Some(CArrayIter { cur_entry: array })
}
}
}

impl<T: Sized + 'static> Iterator for CArrayIter<T> {
type Item = &'static T;

fn next(&mut self) -> Option<Self::Item> {
let next_entry_candidate = unsafe { *self.cur_entry };
if next_entry_candidate.is_null() {
None
} else {
self.cur_entry = unsafe { self.cur_entry.add(1) };
Some(unsafe { &*next_entry_candidate })
}
}
}

// reads from null-terminated array of `wasm_extern_t`s
unsafe fn argument_import_iter(
imports: *const *const wasm_extern_t,
) -> Box<dyn Iterator<Item = &'static wasm_extern_t>> {
CArrayIter::new(imports)
.map(|it| Box::new(it) as _)
.unwrap_or_else(|| Box::new(std::iter::empty()) as _)
}

#[no_mangle]
pub unsafe extern "C" fn wasm_instance_new(
_store: &wasm_store_t,
module: &wasm_module_t,
imports: *const *const wasm_extern_t,
imports: &wasm_extern_vec_t,
// own
_traps: *mut *mut wasm_trap_t,
) -> Option<Box<wasm_instance_t>> {
let wasm_module = &module.inner;
let module_imports = wasm_module.imports();
let module_import_count = module_imports.len();
let imports = argument_import_iter(imports);
let resolver: OrderedResolver = imports
.into_slice()
.map(|imports| imports.iter())
.unwrap_or_else(|| [].iter())
.map(|imp| &imp.inner)
.take(module_import_count)
.cloned()
Expand Down
2 changes: 2 additions & 0 deletions lib/c-api/src/wasm_c_api/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub struct wasm_val_t {
pub of: wasm_val_inner,
}

wasm_declare_vec!(val);

impl Clone for wasm_val_t {
fn clone(&self) -> Self {
wasm_val_t {
Expand Down
44 changes: 25 additions & 19 deletions lib/c-api/src/wasm_c_api/wasi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
mod capture_files;

use super::{
externals::{wasm_extern_t, wasm_func_t, wasm_memory_t},
externals::{wasm_extern_t, wasm_extern_vec_t, wasm_func_t, wasm_memory_t},
instance::wasm_instance_t,
module::wasm_module_t,
store::wasm_store_t,
Expand Down Expand Up @@ -300,7 +300,7 @@ pub unsafe extern "C" fn wasi_get_imports(
store: &wasm_store_t,
module: &wasm_module_t,
wasi_env: &wasi_env_t,
imports: *mut *mut wasm_extern_t,
imports: &mut wasm_extern_vec_t,
) -> bool {
wasi_get_imports_inner(store, module, wasi_env, imports).is_some()
}
Expand All @@ -310,7 +310,7 @@ unsafe fn wasi_get_imports_inner(
store: &wasm_store_t,
module: &wasm_module_t,
wasi_env: &wasi_env_t,
imports: *mut *mut wasm_extern_t,
imports: &mut wasm_extern_vec_t,
) -> Option<()> {
let store = &store.inner;

Expand All @@ -322,22 +322,28 @@ unsafe fn wasi_get_imports_inner(

let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version);

for (i, it) in module.inner.imports().enumerate() {
let export = c_try!(import_object
.resolve_by_name(it.module(), it.name())
.ok_or_else(|| CApiError {
msg: format!(
"Failed to resolve import \"{}\" \"{}\"",
it.module(),
it.name()
),
}));
let inner = Extern::from_export(store, export);
*imports.add(i) = Box::into_raw(Box::new(wasm_extern_t {
instance: None,
inner,
}));
}
*imports = module
.inner
.imports()
.map(|import_type| {
let export = c_try!(import_object
.resolve_by_name(import_type.module(), import_type.name())
.ok_or_else(|| CApiError {
msg: format!(
"Failed to resolve import \"{}\" \"{}\"",
import_type.module(),
import_type.name()
),
}));
let inner = Extern::from_export(store, export);

Some(Box::new(wasm_extern_t {
instance: None,
inner,
}))
})
.collect::<Option<Vec<_>>>()?
.into();

Some(())
}
Expand Down
25 changes: 15 additions & 10 deletions lib/c-api/tests/wasm_c_api/test-early-exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ void print_frame(wasm_frame_t* frame) {

wasm_store_t *store = NULL;

own wasm_trap_t *early_exit(const wasm_val_t args[], wasm_val_t results[]) {
own wasm_trap_t* early_exit(const wasm_val_vec_t* args, wasm_val_vec_t* results) {
own wasm_message_t trap_message;
wasm_name_new_from_string(&trap_message, "trapping from a host import");
wasm_name_new_from_string_nt(&trap_message, "trapping from a host import");
own wasm_trap_t *trap = wasm_trap_new(store, &trap_message);
wasm_name_delete(&trap_message);
return trap;
Expand Down Expand Up @@ -77,9 +77,13 @@ int main(int argc, const char *argv[]) {

wasm_functype_delete(host_func_type);

const wasm_extern_t *imports[] = {wasm_func_as_extern(host_func)};
wasm_extern_vec_t imports;
wasm_extern_vec_new_uninitialized(&imports, 1);
imports.data[0] = wasm_func_as_extern(host_func);

own wasm_instance_t *instance =
wasm_instance_new(store, module, imports, NULL);
wasm_instance_new(store, module, &imports, NULL);

if (!instance) {
printf("> Error instantiating module!\n");
print_wasmer_error();
Expand Down Expand Up @@ -110,12 +114,12 @@ int main(int argc, const char *argv[]) {

// Call.
printf("Calling export...\n");
own const wasm_val_t args[] = {
{.kind = WASM_I32, .of = {.i32 = 1}},
{.kind = WASM_I32, .of = {.i32 = 7}},
};
own wasm_val_t rets[1] = {};
own wasm_trap_t *trap = wasm_func_call(run_func, args, rets);
wasm_val_t values[2] = { WASM_I32_VAL(1), WASM_I32_VAL(7) };
own wasm_val_vec_t args = WASM_ARRAY_VEC(values);
wasm_val_t result = WASM_INIT_VAL;
own wasm_val_vec_t rets = { 1, &result };
own wasm_trap_t *trap = wasm_func_call(run_func, &args, &rets);

if (!trap) {
printf("> Error calling function: expected trap!\n");
return 1;
Expand Down Expand Up @@ -151,6 +155,7 @@ int main(int argc, const char *argv[]) {
wasm_name_delete(&message);

wasm_extern_vec_delete(&exports);
wasm_extern_vec_delete(&imports);

// Shut down.
printf("Shutting down...\n");
Expand Down
Loading

0 comments on commit aeea0d6

Please sign in to comment.