Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(c-api) Update wasm-c-api repository #1699

Merged
merged 30 commits into from
Oct 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1872970
feat(c-api) Update `wasm-c-api` repository.
Hywan Oct 9, 2020
8b38dd5
feat(c-api) Implement `wasm_val_vec_t`.
Hywan Oct 12, 2020
d8dcb41
feat(c-api) Update the definitions of `wasm_func_callback*_t`.
Hywan Oct 12, 2020
5dffd97
feat(c-api) Update `wasm_func_new`.
Hywan Oct 12, 2020
7f09838
faet(c-api) Update `wasm_func_new_with_env`.
Hywan Oct 12, 2020
e9cd710
feat(c-api) Update `wasm_func_call`.
Hywan Oct 12, 2020
fa7fe83
feat(c-api) Update `wasm_instance_new`.
Hywan Oct 12, 2020
fea156d
feat(c-api) Update `wasi_get_imports` to use a `wasm_extern_vec_t`…
Hywan Oct 12, 2020
202ffe7
fix(c-api) Fix `wasm_func_call` when params are empty.
Hywan Oct 12, 2020
35f8e17
Merge branch 'master' into feat-c-api-update-wasm-h
Hywan Oct 12, 2020
4584a53
fix(c-api) Remove `rustc` warnings.
Hywan Oct 12, 2020
5bf9055
test(c-api) Fix the `early-exit` test.
Hywan Oct 12, 2020
4186d1c
test(c-api) Use `wasm_extern_vec_t` for `wasm_get_imports`.
Hywan Oct 12, 2020
0b4ef7a
test(c-api) Don't pass `NULL` for zero args/results to `wasm_func_call`!
Hywan Oct 12, 2020
437426d
feat(c-api) Update `wasmer_wasm.h`.
Hywan Oct 12, 2020
122ba83
Merge branch 'master' into feat-c-api-update-wasm-h
Hywan Oct 12, 2020
2023016
doc(changelog) Add #1699.
Hywan Oct 12, 2020
bf389f9
Merge branch 'master' into feat-c-api-update-wasm-h
Hywan Oct 12, 2020
4463294
doc(changelog) Add #1685.
Hywan Oct 12, 2020
e29ea25
feat(c-api) Simplify code with `unwrap_or_default`.
Hywan Oct 16, 2020
d7d40e5
Merge branch 'master' into feat-c-api-update-wasm-h
Hywan Oct 16, 2020
ddf2459
chore(changelog) Fix merge.
Hywan Oct 16, 2020
4f9932c
feat(cli) Update the `crate_exe_main.c` file to the latest Wasm C API.
Hywan Oct 16, 2020
5601ecb
test(integration) Add `-x c` to force `clang++` to treat code as C.
Hywan Oct 16, 2020
cb5afa1
test(integration) Update to use the latest Wasm C API.
Hywan Oct 16, 2020
2fc1aaa
chore(test) Format code.
Hywan Oct 16, 2020
3b05c26
fix(c-api) Fix last edit of the `wasmer_create_exe_main.c` file.
Hywan Oct 16, 2020
1cdb5b5
fix(c-api) Fix another typo. Damn.
Hywan Oct 16, 2020
9955da1
test: Remove a warning fix for Windows.
Hywan Oct 16, 2020
a73e457
Merge branch 'master' into feat-c-api-update-wasm-h
Hywan Oct 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not be the same, we should be careful of the difference between fat pointers and thin pointers.

as_ptr and as_mut_ptr generally pass word sized pointers, references to slices are double words and references to vecs are different data entirely

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

processed_args and results are now of kind wasm_val_vec_t. I believe it is safe to use & in this case.

// 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")
Hywan marked this conversation as resolved.
Show resolved Hide resolved
})
.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())
Hywan marked this conversation as resolved.
Show resolved Hide resolved
.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