Update the C API with module linking support (#2472)

* Update the C API with module linking support

This commit does everything necessary (ideally) to support the module
linking proposal in the C API. The changes here are:

* New `wasm_{module,instance}type_t` types and accessors
* New `wasm_{module,instance}_type` functions
* Conversions between `wasm_extern_t` and `wasm_{instance,module}_t`, as
  well as `wasm_externtype_t` and the new types.
* Addition of `WASM_EXTERN_{MODULE,INSTANCE}` constants
* New `wasm_config_t` modifier to enable/disable module linking

With these functions it should be possible to pass instances/modules to
instances and also acquire them from exports. Altogether this should
enable everything for module linking.

An important point for this is that I've opted to add all these items
under the `wasm_*` name prefix instead of `wasmtime_*`. I've done this
since they're all following the idioms of existing APIs and while not
standard the intention would be to standardize them (unlike many other
Wasmtime-specific APIs).

cc #2094

* Appease doxygen
This commit is contained in:
Alex Crichton
2020-12-03 15:51:38 -06:00
committed by GitHub
parent 0f1dc9a735
commit 41caf67af3
11 changed files with 553 additions and 114 deletions

View File

@@ -85,6 +85,11 @@ pub extern "C" fn wasmtime_config_wasm_multi_value_set(c: &mut wasm_config_t, en
c.config.wasm_multi_value(enable);
}
#[no_mangle]
pub extern "C" fn wasmtime_config_wasm_module_linking_set(c: &mut wasm_config_t, enable: bool) {
c.config.wasm_module_linking(enable);
}
#[no_mangle]
pub extern "C" fn wasmtime_config_strategy_set(
c: &mut wasm_config_t,

View File

@@ -1,5 +1,7 @@
use crate::wasm_externkind_t;
use crate::{wasm_externtype_t, wasm_func_t, wasm_global_t, wasm_memory_t, wasm_table_t};
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,
};
use wasmtime::Extern;
#[derive(Clone)]
@@ -16,10 +18,8 @@ pub extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t {
Extern::Global(_) => crate::WASM_EXTERN_GLOBAL,
Extern::Table(_) => crate::WASM_EXTERN_TABLE,
Extern::Memory(_) => crate::WASM_EXTERN_MEMORY,
// FIXME(#2094)
Extern::Instance(_) => unimplemented!(),
Extern::Module(_) => unimplemented!(),
Extern::Instance(_) => crate::WASM_EXTERN_INSTANCE,
Extern::Module(_) => crate::WASM_EXTERN_MODULE,
}
}
@@ -67,3 +67,23 @@ pub extern "C" fn wasm_extern_as_memory(e: &wasm_extern_t) -> Option<&wasm_memor
pub extern "C" fn wasm_extern_as_memory_const(e: &wasm_extern_t) -> Option<&wasm_memory_t> {
wasm_extern_as_memory(e)
}
#[no_mangle]
pub extern "C" fn wasm_extern_as_module(e: &wasm_extern_t) -> Option<&wasm_module_t> {
wasm_module_t::try_from(e)
}
#[no_mangle]
pub extern "C" fn wasm_extern_as_module_const(e: &wasm_extern_t) -> Option<&wasm_module_t> {
wasm_extern_as_module(e)
}
#[no_mangle]
pub extern "C" fn wasm_extern_as_instance(e: &wasm_extern_t) -> Option<&wasm_instance_t> {
wasm_instance_t::try_from(e)
}
#[no_mangle]
pub extern "C" fn wasm_extern_as_instance_const(e: &wasm_extern_t) -> Option<&wasm_instance_t> {
wasm_extern_as_instance(e)
}

View File

@@ -1,20 +1,38 @@
use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t};
use crate::{wasm_store_t, wasmtime_error_t};
use crate::{wasm_instancetype_t, wasm_store_t, wasmtime_error_t};
use anyhow::Result;
use std::ptr;
use wasmtime::{Instance, Trap};
use wasmtime::{Extern, Instance, Trap};
#[repr(C)]
#[derive(Clone)]
#[repr(transparent)]
pub struct wasm_instance_t {
pub(crate) instance: Instance,
ext: wasm_extern_t,
}
wasmtime_c_api_macros::declare_ref!(wasm_instance_t);
impl wasm_instance_t {
pub(crate) fn new(instance: Instance) -> wasm_instance_t {
wasm_instance_t { instance: instance }
wasm_instance_t {
ext: wasm_extern_t {
which: instance.into(),
},
}
}
pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_instance_t> {
match &e.which {
Extern::Instance(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
}
}
pub(crate) fn instance(&self) -> &Instance {
match &self.ext.which {
Extern::Instance(i) => i,
_ => unreachable!(),
}
}
}
@@ -31,7 +49,7 @@ pub unsafe extern "C" fn wasm_instance_new(
store,
wasm_module,
imports,
wasm_module.imports.len(),
wasm_module.module().imports().len(),
&mut instance,
&mut trap,
);
@@ -92,7 +110,7 @@ fn _wasmtime_instance_new(
.map(|import| import.which.clone())
.collect::<Vec<_>>();
handle_instantiate(
Instance::new(store, &module.module, &imports),
Instance::new(store, module.module(), &imports),
instance_ptr,
trap_ptr,
)
@@ -122,11 +140,16 @@ pub fn handle_instantiate(
}
}
#[no_mangle]
pub extern "C" fn wasm_instance_as_extern(m: &wasm_instance_t) -> &wasm_extern_t {
&m.ext
}
#[no_mangle]
pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wasm_extern_vec_t) {
out.set_buffer(
instance
.instance
.instance()
.exports()
.map(|e| {
Some(Box::new(wasm_extern_t {
@@ -136,3 +159,8 @@ pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wa
.collect(),
);
}
#[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()))
}

View File

@@ -68,7 +68,7 @@ pub extern "C" fn wasmtime_linker_define_instance(
Ok(s) => s,
Err(_) => return bad_utf8(),
};
handle_result(linker.instance(name, &instance.instance), |_linker| ())
handle_result(linker.instance(name, instance.instance()), |_linker| ())
}
#[no_mangle]
@@ -78,7 +78,7 @@ pub extern "C" fn wasmtime_linker_instantiate(
instance_ptr: &mut *mut wasm_instance_t,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
let result = linker.linker.instantiate(&module.module);
let result = linker.linker.instantiate(module.module());
super::instance::handle_instantiate(result, instance_ptr, trap_ptr)
}
@@ -93,7 +93,7 @@ pub extern "C" fn wasmtime_linker_module(
Ok(s) => s,
Err(_) => return bad_utf8(),
};
handle_result(linker.module(name, &module.module), |_linker| ())
handle_result(linker.module(name, module.module()), |_linker| ())
}
#[no_mangle]

View File

@@ -1,20 +1,43 @@
use crate::{
handle_result, wasm_byte_vec_t, wasm_engine_t, wasm_exporttype_t, wasm_exporttype_vec_t,
wasm_importtype_t, wasm_importtype_vec_t, wasm_store_t, wasmtime_error_t,
wasm_extern_t, wasm_importtype_t, wasm_importtype_vec_t, wasm_moduletype_t, wasm_store_t,
wasmtime_error_t,
};
use std::ptr;
use wasmtime::{Engine, Module};
use wasmtime::{Engine, Extern, Module};
#[repr(C)]
#[derive(Clone)]
#[repr(transparent)]
pub struct wasm_module_t {
pub(crate) module: Module,
pub(crate) imports: Vec<wasm_importtype_t>,
pub(crate) exports: Vec<wasm_exporttype_t>,
ext: wasm_extern_t,
}
wasmtime_c_api_macros::declare_ref!(wasm_module_t);
impl wasm_module_t {
pub(crate) fn new(module: Module) -> wasm_module_t {
wasm_module_t {
ext: wasm_extern_t {
which: module.into(),
},
}
}
pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_module_t> {
match &e.which {
Extern::Module(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
}
}
pub(crate) fn module(&self) -> &Module {
match &self.ext.which {
Extern::Module(i) => i,
_ => unreachable!(),
}
}
}
#[repr(C)]
#[derive(Clone)]
pub struct wasm_shared_module_t {
@@ -49,25 +72,7 @@ pub extern "C" fn wasmtime_module_new(
) -> Option<Box<wasmtime_error_t>> {
let binary = binary.as_slice();
handle_result(Module::from_binary(&engine.engine, binary), |module| {
let imports = module
.imports()
.map(|i| {
wasm_importtype_t::new(
i.module().to_owned(),
i.name().map(|s| s.to_owned()),
i.ty(),
)
})
.collect::<Vec<_>>();
let exports = module
.exports()
.map(|e| wasm_exporttype_t::new(e.name().to_owned(), e.ty()))
.collect::<Vec<_>>();
let module = Box::new(wasm_module_t {
module: module,
imports,
exports,
});
let module = Box::new(wasm_module_t::new(module));
*ret = Box::into_raw(module);
})
}
@@ -86,30 +91,46 @@ pub extern "C" fn wasmtime_module_validate(
handle_result(Module::validate(store.store.engine(), binary), |()| {})
}
#[no_mangle]
pub extern "C" fn wasm_module_as_extern(m: &wasm_module_t) -> &wasm_extern_t {
&m.ext
}
#[no_mangle]
pub extern "C" fn wasm_module_exports(module: &wasm_module_t, out: &mut wasm_exporttype_vec_t) {
let buffer = module
.exports
.iter()
.map(|et| Some(Box::new(et.clone())))
let exports = module
.module()
.exports()
.map(|e| {
Some(Box::new(wasm_exporttype_t::new(
e.name().to_owned(),
e.ty(),
)))
})
.collect::<Vec<_>>();
out.set_buffer(buffer);
out.set_buffer(exports);
}
#[no_mangle]
pub extern "C" fn wasm_module_imports(module: &wasm_module_t, out: &mut wasm_importtype_vec_t) {
let buffer = module
.imports
.iter()
.map(|it| Some(Box::new(it.clone())))
let imports = module
.module()
.imports()
.map(|i| {
Some(Box::new(wasm_importtype_t::new(
i.module().to_owned(),
i.name().map(|s| s.to_owned()),
i.ty(),
)))
})
.collect::<Vec<_>>();
out.set_buffer(buffer);
out.set_buffer(imports);
}
#[no_mangle]
pub extern "C" fn wasm_module_share(module: &wasm_module_t) -> Box<wasm_shared_module_t> {
Box::new(wasm_shared_module_t {
module: module.module.clone(),
module: module.module().clone(),
})
}
@@ -122,25 +143,7 @@ pub extern "C" fn wasm_module_obtain(
if !Engine::same(store.store.engine(), module.engine()) {
return None;
}
let imports = module
.imports()
.map(|i| {
wasm_importtype_t::new(
i.module().to_owned(),
i.name().map(|s| s.to_owned()),
i.ty(),
)
})
.collect::<Vec<_>>();
let exports = module
.exports()
.map(|e| wasm_exporttype_t::new(e.name().to_owned(), e.ty()))
.collect::<Vec<_>>();
Some(Box::new(wasm_module_t {
module: module,
imports,
exports,
}))
Some(Box::new(wasm_module_t::new(module)))
}
#[no_mangle]
@@ -171,7 +174,7 @@ 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| {
handle_result(module.module().serialize(), |buf| {
ret.set_buffer(buf);
})
}
@@ -185,26 +188,13 @@ pub extern "C" fn wasmtime_module_deserialize(
handle_result(
Module::deserialize(&engine.engine, binary.as_slice()),
|module| {
let imports = module
.imports()
.map(|i| {
wasm_importtype_t::new(
i.module().to_owned(),
i.name().map(|s| s.to_owned()),
i.ty(),
)
})
.collect::<Vec<_>>();
let exports = module
.exports()
.map(|e| wasm_exporttype_t::new(e.name().to_owned(), e.ty()))
.collect::<Vec<_>>();
let module = Box::new(wasm_module_t {
module: module,
imports,
exports,
});
let module = Box::new(wasm_module_t::new(module));
*ret = Box::into_raw(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()))
}

View File

@@ -27,8 +27,8 @@ pub const WASM_EXTERN_FUNC: wasm_externkind_t = 0;
pub const WASM_EXTERN_GLOBAL: wasm_externkind_t = 1;
pub const WASM_EXTERN_TABLE: wasm_externkind_t = 2;
pub const WASM_EXTERN_MEMORY: wasm_externkind_t = 3;
pub const WASMTIME_EXTERN_MODULE: wasm_externkind_t = 4;
pub const WASMTIME_EXTERN_INSTANCE: wasm_externkind_t = 5;
pub const WASM_EXTERN_MODULE: wasm_externkind_t = 4;
pub const WASM_EXTERN_INSTANCE: wasm_externkind_t = 5;
impl wasm_externtype_t {
pub(crate) fn new(ty: ExternType) -> wasm_externtype_t {
@@ -63,8 +63,8 @@ pub extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkin
CExternType::Table(_) => WASM_EXTERN_TABLE,
CExternType::Global(_) => WASM_EXTERN_GLOBAL,
CExternType::Memory(_) => WASM_EXTERN_MEMORY,
CExternType::Instance(_) => WASMTIME_EXTERN_INSTANCE,
CExternType::Module(_) => WASMTIME_EXTERN_MODULE,
CExternType::Instance(_) => WASM_EXTERN_INSTANCE,
CExternType::Module(_) => WASM_EXTERN_MODULE,
}
}

View File

@@ -1,5 +1,4 @@
use crate::{wasm_externtype_t, wasm_limits_t, CExternType};
use once_cell::unsync::OnceCell;
use crate::{wasm_exporttype_t, wasm_exporttype_vec_t, wasm_externtype_t, CExternType};
use wasmtime::InstanceType;
#[repr(transparent)]
@@ -13,24 +12,33 @@ wasmtime_c_api_macros::declare_ty!(wasm_instancetype_t);
#[derive(Clone)]
pub(crate) struct CInstanceType {
pub(crate) ty: InstanceType,
limits_cache: OnceCell<wasm_limits_t>,
}
impl wasm_instancetype_t {
pub(crate) fn new(ty: InstanceType) -> wasm_instancetype_t {
wasm_instancetype_t {
ext: wasm_externtype_t::new(ty.into()),
}
}
pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_instancetype_t> {
match &e.which {
CExternType::Instance(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
}
}
pub(crate) fn ty(&self) -> &CInstanceType {
match &self.ext.which {
CExternType::Instance(f) => &f,
_ => unreachable!(),
}
}
}
impl CInstanceType {
pub(crate) fn new(ty: InstanceType) -> CInstanceType {
CInstanceType {
ty,
limits_cache: OnceCell::new(),
}
CInstanceType { ty }
}
}
#[no_mangle]
@@ -44,3 +52,22 @@ pub extern "C" fn wasm_instancetype_as_externtype_const(
) -> &wasm_externtype_t {
&ty.ext
}
#[no_mangle]
pub extern "C" fn wasm_instancetype_exports(
instance: &wasm_instancetype_t,
out: &mut wasm_exporttype_vec_t,
) {
let exports = instance
.ty()
.ty
.exports()
.map(|e| {
Some(Box::new(wasm_exporttype_t::new(
e.name().to_owned(),
e.ty(),
)))
})
.collect::<Vec<_>>();
out.set_buffer(exports);
}

View File

@@ -1,5 +1,7 @@
use crate::{wasm_externtype_t, wasm_limits_t, CExternType};
use once_cell::unsync::OnceCell;
use crate::{
wasm_exporttype_t, wasm_exporttype_vec_t, wasm_externtype_t, wasm_importtype_t,
wasm_importtype_vec_t, CExternType,
};
use wasmtime::ModuleType;
#[repr(transparent)]
@@ -13,24 +15,33 @@ wasmtime_c_api_macros::declare_ty!(wasm_moduletype_t);
#[derive(Clone)]
pub(crate) struct CModuleType {
pub(crate) ty: ModuleType,
limits_cache: OnceCell<wasm_limits_t>,
}
impl wasm_moduletype_t {
pub(crate) fn new(ty: ModuleType) -> wasm_moduletype_t {
wasm_moduletype_t {
ext: wasm_externtype_t::new(ty.into()),
}
}
pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_moduletype_t> {
match &e.which {
CExternType::Module(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
}
}
pub(crate) fn ty(&self) -> &CModuleType {
match &self.ext.which {
CExternType::Module(f) => &f,
_ => unreachable!(),
}
}
}
impl CModuleType {
pub(crate) fn new(ty: ModuleType) -> CModuleType {
CModuleType {
ty,
limits_cache: OnceCell::new(),
}
CModuleType { ty }
}
}
@@ -45,3 +56,42 @@ pub extern "C" fn wasm_moduletype_as_externtype_const(
) -> &wasm_externtype_t {
&ty.ext
}
#[no_mangle]
pub extern "C" fn wasm_moduletype_exports(
module: &wasm_moduletype_t,
out: &mut wasm_exporttype_vec_t,
) {
let exports = module
.ty()
.ty
.exports()
.map(|e| {
Some(Box::new(wasm_exporttype_t::new(
e.name().to_owned(),
e.ty(),
)))
})
.collect::<Vec<_>>();
out.set_buffer(exports);
}
#[no_mangle]
pub extern "C" fn wasm_moduletype_imports(
module: &wasm_moduletype_t,
out: &mut wasm_importtype_vec_t,
) {
let imports = module
.ty()
.ty
.imports()
.map(|i| {
Some(Box::new(wasm_importtype_t::new(
i.module().to_owned(),
i.name().map(|s| s.to_owned()),
i.ty(),
)))
})
.collect::<Vec<_>>();
out.set_buffer(imports);
}

View File

@@ -1,7 +1,8 @@
use crate::wasm_valtype_t;
use crate::{wasm_exporttype_t, wasm_extern_t, wasm_frame_t, wasm_val_t};
use crate::{wasm_externtype_t, wasm_importtype_t, wasm_memorytype_t};
use crate::{wasm_functype_t, wasm_globaltype_t, wasm_tabletype_t};
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,
};
use std::mem;
use std::ptr;
use std::slice;
@@ -172,6 +173,24 @@ 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>>,