wasmtime: Initial, partial support for externref

This is enough to get an `externref -> externref` identity function
passing.

However, `externref`s that are dropped by compiled Wasm code are (safely)
leaked. Follow up work will leverage cranelift's stack maps to resolve this
issue.
This commit is contained in:
Nick Fitzgerald
2020-05-22 17:12:45 -07:00
parent 137e182750
commit a8ee0554a9
41 changed files with 545 additions and 376 deletions

View File

@@ -96,7 +96,7 @@ pub fn declare_ref(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
#[no_mangle]
pub extern fn #as_ref(a: &#ty) -> Box<crate::wasm_ref_t> {
let r = a.externref();
let r = Some(a.externref());
Box::new(crate::wasm_ref_t { r })
}

View File

@@ -1,10 +1,10 @@
use crate::wasm_config_t;
use wasmtime::{Engine, HostRef};
use wasmtime::Engine;
#[repr(C)]
#[derive(Clone)]
pub struct wasm_engine_t {
pub(crate) engine: HostRef<Engine>,
pub(crate) engine: Engine,
}
wasmtime_c_api_macros::declare_own!(wasm_engine_t);
@@ -22,7 +22,7 @@ pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
drop(env_logger::try_init());
Box::new(wasm_engine_t {
engine: HostRef::new(Engine::default()),
engine: Engine::default(),
})
}
@@ -30,6 +30,6 @@ pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
pub extern "C" fn wasm_engine_new_with_config(c: Box<wasm_config_t>) -> Box<wasm_engine_t> {
let config = c.config;
Box::new(wasm_engine_t {
engine: HostRef::new(Engine::new(&config)),
engine: Engine::new(&config),
})
}

View File

@@ -1,6 +1,6 @@
use crate::{wasm_name_t, wasm_trap_t};
use anyhow::{anyhow, Error, Result};
use wasmtime::Trap;
use wasmtime::{Store, Trap};
#[repr(C)]
pub struct wasmtime_error_t {
@@ -10,8 +10,8 @@ pub struct wasmtime_error_t {
wasmtime_c_api_macros::declare_own!(wasmtime_error_t);
impl wasmtime_error_t {
pub(crate) fn to_trap(self) -> Box<wasm_trap_t> {
Box::new(wasm_trap_t::new(Trap::from(self.error)))
pub(crate) fn to_trap(self, store: &Store) -> Box<wasm_trap_t> {
Box::new(wasm_trap_t::new(store, Trap::from(self.error)))
}
}

View File

@@ -18,12 +18,12 @@ pub(crate) enum ExternHost {
}
impl wasm_extern_t {
fn externref(&self) -> wasmtime::ExternRef {
pub(crate) fn externref(&self) -> wasmtime::ExternRef {
match &self.which {
ExternHost::Func(f) => f.externref(),
ExternHost::Global(f) => f.externref(),
ExternHost::Memory(f) => f.externref(),
ExternHost::Table(f) => f.externref(),
ExternHost::Func(f) => f.clone().into(),
ExternHost::Global(f) => f.clone().into(),
ExternHost::Memory(f) => f.clone().into(),
ExternHost::Table(f) => f.clone().into(),
}
}
}

View File

@@ -71,7 +71,7 @@ impl wasm_func_t {
}
fn externref(&self) -> wasmtime::ExternRef {
self.func().externref()
self.func().clone().into()
}
}
@@ -90,7 +90,7 @@ fn create_function(
ty: &wasm_functype_t,
func: impl Fn(Caller<'_>, *const wasm_val_t, *mut wasm_val_t) -> Option<Box<wasm_trap_t>> + 'static,
) -> Box<wasm_func_t> {
let store = &store.store.borrow();
let store = &store.store;
let ty = ty.ty().ty.clone();
let func = Func::new(store, ty, move |caller, params, results| {
let params = params
@@ -107,7 +107,7 @@ fn create_function(
}
Ok(())
});
Box::new(HostRef::new(func).into())
Box::new(HostRef::new(store, func).into())
}
#[no_mangle]
@@ -182,7 +182,7 @@ pub unsafe extern "C" fn wasm_func_call(
&mut trap,
);
match error {
Some(err) => Box::into_raw(err.to_trap()),
Some(err) => Box::into_raw(err.to_trap(&wasm_func.ext.externref().store().unwrap())),
None => trap,
}
}
@@ -210,6 +210,7 @@ fn _wasmtime_func_call(
results: &mut [wasm_val_t],
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
let store = &func.ext.externref().store().unwrap();
let func = func.func().borrow();
if results.len() != func.result_arity() {
return Some(Box::new(anyhow!("wrong number of results provided").into()));
@@ -230,7 +231,7 @@ fn _wasmtime_func_call(
}
Ok(Err(trap)) => match trap.downcast::<Trap>() {
Ok(trap) => {
*trap_ptr = Box::into_raw(Box::new(wasm_trap_t::new(trap)));
*trap_ptr = Box::into_raw(Box::new(wasm_trap_t::new(store, trap)));
None
}
Err(err) => Some(Box::new(err.into())),
@@ -243,7 +244,7 @@ fn _wasmtime_func_call(
} else {
Trap::new("rust panic happened")
};
let trap = Box::new(wasm_trap_t::new(trap));
let trap = Box::new(wasm_trap_t::new(store, trap));
*trap_ptr = Box::into_raw(trap);
None
}
@@ -277,11 +278,12 @@ pub unsafe extern "C" fn wasmtime_caller_export_get(
) -> Option<Box<wasm_extern_t>> {
let name = str::from_utf8(name.as_slice()).ok()?;
let export = caller.caller.get_export(name)?;
let store = caller.caller.store();
let which = match export {
Extern::Func(f) => ExternHost::Func(HostRef::new(f)),
Extern::Global(g) => ExternHost::Global(HostRef::new(g)),
Extern::Memory(m) => ExternHost::Memory(HostRef::new(m)),
Extern::Table(t) => ExternHost::Table(HostRef::new(t)),
Extern::Func(f) => ExternHost::Func(HostRef::new(&store, f)),
Extern::Global(g) => ExternHost::Global(HostRef::new(&store, g)),
Extern::Memory(m) => ExternHost::Memory(HostRef::new(&store, m)),
Extern::Table(t) => ExternHost::Table(HostRef::new(&store, t)),
};
Some(Box::new(wasm_extern_t { which }))
}

View File

@@ -27,7 +27,7 @@ impl wasm_global_t {
}
fn externref(&self) -> wasmtime::ExternRef {
self.global().externref()
self.global().clone().into()
}
}
@@ -54,11 +54,11 @@ pub extern "C" fn wasmtime_global_new(
val: &wasm_val_t,
ret: &mut *mut wasm_global_t,
) -> Option<Box<wasmtime_error_t>> {
let global = Global::new(&store.store.borrow(), gt.ty().ty.clone(), val.val());
let global = Global::new(&store.store, gt.ty().ty.clone(), val.val());
handle_result(global, |global| {
*ret = Box::into_raw(Box::new(wasm_global_t {
ext: wasm_extern_t {
which: ExternHost::Global(HostRef::new(global)),
which: ExternHost::Global(HostRef::new(&store.store, global)),
},
}));
})

View File

@@ -16,14 +16,15 @@ wasmtime_c_api_macros::declare_ref!(wasm_instance_t);
impl wasm_instance_t {
pub(crate) fn new(instance: Instance) -> wasm_instance_t {
let store = instance.store().clone();
wasm_instance_t {
instance: HostRef::new(instance),
instance: HostRef::new(&store, instance),
exports_cache: RefCell::new(None),
}
}
fn externref(&self) -> wasmtime::ExternRef {
self.instance.externref()
self.instance.clone().into()
}
}
@@ -34,12 +35,12 @@ pub unsafe extern "C" fn wasm_instance_new(
imports: *const Box<wasm_extern_t>,
result: Option<&mut *mut wasm_trap_t>,
) -> Option<Box<wasm_instance_t>> {
let store = &store.store.borrow();
let store = &store.store;
let module = &wasm_module.module.borrow();
if !Store::same(&store, module.store()) {
if let Some(result) = result {
let trap = Trap::new("wasm_store_t must match store in wasm_module_t");
let trap = Box::new(wasm_trap_t::new(trap));
let trap = Box::new(wasm_trap_t::new(store, trap));
*result = Box::into_raw(trap);
}
return None;
@@ -58,7 +59,7 @@ pub unsafe extern "C" fn wasm_instance_new(
assert!(trap.is_null());
assert!(instance.is_null());
if let Some(result) = result {
*result = Box::into_raw(err.to_trap());
*result = Box::into_raw(err.to_trap(store));
}
None
}
@@ -111,10 +112,16 @@ fn _wasmtime_instance_new(
})
.collect::<Vec<_>>();
let module = &module.module.borrow();
handle_instantiate(Instance::new(module, &imports), instance_ptr, trap_ptr)
handle_instantiate(
module.store(),
Instance::new(module, &imports),
instance_ptr,
trap_ptr,
)
}
pub fn handle_instantiate(
store: &Store,
instance: Result<Instance>,
instance_ptr: &mut *mut wasm_instance_t,
trap_ptr: &mut *mut wasm_trap_t,
@@ -130,7 +137,7 @@ pub fn handle_instantiate(
}
Err(e) => match e.downcast::<Trap>() {
Ok(trap) => {
write(trap_ptr, wasm_trap_t::new(trap));
write(trap_ptr, wasm_trap_t::new(store, trap));
None
}
Err(e) => Some(Box::new(e.into())),
@@ -146,10 +153,10 @@ pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wa
instance
.exports()
.map(|e| match e.into_extern() {
Extern::Func(f) => ExternHost::Func(HostRef::new(f)),
Extern::Global(f) => ExternHost::Global(HostRef::new(f)),
Extern::Memory(f) => ExternHost::Memory(HostRef::new(f)),
Extern::Table(f) => ExternHost::Table(HostRef::new(f)),
Extern::Func(f) => ExternHost::Func(HostRef::new(instance.store(), f)),
Extern::Global(f) => ExternHost::Global(HostRef::new(instance.store(), f)),
Extern::Memory(f) => ExternHost::Memory(HostRef::new(instance.store(), f)),
Extern::Table(f) => ExternHost::Table(HostRef::new(instance.store(), f)),
})
.collect()
});

View File

@@ -12,7 +12,7 @@ pub struct wasmtime_linker_t {
#[no_mangle]
pub extern "C" fn wasmtime_linker_new(store: &wasm_store_t) -> Box<wasmtime_linker_t> {
Box::new(wasmtime_linker_t {
linker: Linker::new(&store.store.borrow()),
linker: Linker::new(&store.store),
})
}
@@ -87,7 +87,7 @@ pub unsafe extern "C" fn wasmtime_linker_instantiate(
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
let result = linker.linker.instantiate(&module.module.borrow());
super::instance::handle_instantiate(result, instance_ptr, trap_ptr)
super::instance::handle_instantiate(linker.linker.store(), result, instance_ptr, trap_ptr)
}
#[no_mangle]
@@ -116,6 +116,6 @@ pub unsafe extern "C" fn wasmtime_linker_get_default(
Err(_) => return bad_utf8(),
};
handle_result(linker.get_default(name), |f| {
*func = Box::into_raw(Box::new(HostRef::new(f).into()))
*func = Box::into_raw(Box::new(HostRef::new(linker.store(), f).into()))
})
}

View File

@@ -27,7 +27,7 @@ impl wasm_memory_t {
}
fn externref(&self) -> wasmtime::ExternRef {
self.memory().externref()
self.memory().clone().into()
}
}
@@ -36,7 +36,7 @@ pub extern "C" fn wasm_memory_new(
store: &wasm_store_t,
mt: &wasm_memorytype_t,
) -> Box<wasm_memory_t> {
let memory = HostRef::new(Memory::new(&store.store.borrow(), mt.ty().ty.clone()));
let memory = HostRef::new(&store.store, Memory::new(&store.store, mt.ty().ty.clone()));
Box::new(wasm_memory_t {
ext: wasm_extern_t {
which: ExternHost::Memory(memory),

View File

@@ -16,7 +16,7 @@ wasmtime_c_api_macros::declare_ref!(wasm_module_t);
impl wasm_module_t {
fn externref(&self) -> wasmtime::ExternRef {
self.module.externref()
self.module.clone().into()
}
}
@@ -42,7 +42,7 @@ pub extern "C" fn wasmtime_module_new(
ret: &mut *mut wasm_module_t,
) -> Option<Box<wasmtime_error_t>> {
let binary = binary.as_slice();
let store = &store.store.borrow();
let store = &store.store;
handle_result(Module::from_binary(store, binary), |module| {
let imports = module
.imports()
@@ -53,7 +53,7 @@ pub extern "C" fn wasmtime_module_new(
.map(|e| wasm_exporttype_t::new(e.name().to_owned(), e.ty()))
.collect::<Vec<_>>();
let module = Box::new(wasm_module_t {
module: HostRef::new(module),
module: HostRef::new(store, module),
imports,
exports,
});
@@ -72,7 +72,7 @@ pub extern "C" fn wasmtime_module_validate(
binary: &wasm_byte_vec_t,
) -> Option<Box<wasmtime_error_t>> {
let binary = binary.as_slice();
let store = &store.store.borrow();
let store = &store.store;
handle_result(Module::validate(store, binary), |()| {})
}

View File

@@ -5,7 +5,7 @@ use wasmtime::ExternRef;
#[repr(C)]
#[derive(Clone)]
pub struct wasm_ref_t {
pub(crate) r: ExternRef,
pub(crate) r: Option<ExternRef>,
}
wasmtime_c_api_macros::declare_own!(wasm_ref_t);
@@ -17,7 +17,11 @@ pub extern "C" fn wasm_ref_copy(r: &wasm_ref_t) -> Box<wasm_ref_t> {
#[no_mangle]
pub extern "C" fn wasm_ref_same(a: &wasm_ref_t, b: &wasm_ref_t) -> bool {
a.r.ptr_eq(&b.r)
match (a.r.as_ref(), b.r.as_ref()) {
(Some(a), Some(b)) => a.ptr_eq(b),
(None, None) => true,
_ => false,
}
}
pub(crate) fn get_host_info(r: &ExternRef) -> *mut c_void {
@@ -25,6 +29,7 @@ pub(crate) fn get_host_info(r: &ExternRef) -> *mut c_void {
Some(info) => info,
None => return std::ptr::null_mut(),
};
let host_info = host_info.borrow();
match host_info.downcast_ref::<HostInfoState>() {
Some(state) => state.info,
None => std::ptr::null_mut(),
@@ -33,7 +38,8 @@ pub(crate) fn get_host_info(r: &ExternRef) -> *mut c_void {
#[no_mangle]
pub extern "C" fn wasm_ref_get_host_info(a: &wasm_ref_t) -> *mut c_void {
get_host_info(&a.r)
a.r.as_ref()
.map_or(std::ptr::null_mut(), |r| get_host_info(r))
}
pub(crate) fn set_host_info(
@@ -51,7 +57,7 @@ pub(crate) fn set_host_info(
#[no_mangle]
pub extern "C" fn wasm_ref_set_host_info(a: &wasm_ref_t, info: *mut c_void) {
set_host_info(&a.r, info, None)
a.r.as_ref().map(|r| set_host_info(r, info, None));
}
#[no_mangle]
@@ -60,5 +66,5 @@ pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
info: *mut c_void,
finalizer: Option<extern "C" fn(*mut c_void)>,
) {
set_host_info(&a.r, info, finalizer)
a.r.as_ref().map(|r| set_host_info(r, info, finalizer));
}

View File

@@ -1,10 +1,10 @@
use crate::wasm_engine_t;
use wasmtime::{HostRef, InterruptHandle, Store};
use wasmtime::{InterruptHandle, Store};
#[repr(C)]
#[derive(Clone)]
pub struct wasm_store_t {
pub(crate) store: HostRef<Store>,
pub(crate) store: Store,
}
wasmtime_c_api_macros::declare_own!(wasm_store_t);
@@ -13,7 +13,7 @@ wasmtime_c_api_macros::declare_own!(wasm_store_t);
pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> {
let engine = &engine.engine;
Box::new(wasm_store_t {
store: HostRef::new(Store::new(&engine.borrow())),
store: Store::new(&engine),
})
}
@@ -29,7 +29,7 @@ pub extern "C" fn wasmtime_interrupt_handle_new(
store: &wasm_store_t,
) -> Option<Box<wasmtime_interrupt_handle_t>> {
Some(Box::new(wasmtime_interrupt_handle_t {
handle: store.store.borrow().interrupt_handle().ok()?,
handle: store.store.interrupt_handle().ok()?,
}))
}

View File

@@ -1,7 +1,7 @@
use crate::{handle_result, wasm_func_t, wasm_ref_t, wasmtime_error_t};
use crate::{wasm_extern_t, wasm_store_t, wasm_tabletype_t, ExternHost};
use std::ptr;
use wasmtime::{ExternRef, HostRef, Table, Val};
use wasmtime::{HostRef, Table, Val};
#[derive(Clone)]
#[repr(transparent)]
@@ -29,7 +29,7 @@ impl wasm_table_t {
}
fn externref(&self) -> wasmtime::ExternRef {
self.table().externref()
self.table().clone().into()
}
}
@@ -41,12 +41,12 @@ pub extern "C" fn wasm_table_new(
) -> Option<Box<wasm_table_t>> {
let init: Val = match init {
Some(init) => init.r.into(),
None => Val::ExternRef(ExternRef::Null),
None => Val::ExternRef(None),
};
let table = Table::new(&store.store.borrow(), tt.ty().ty.clone(), init).ok()?;
let table = Table::new(&store.store, tt.ty().ty.clone(), init).ok()?;
Some(Box::new(wasm_table_t {
ext: wasm_extern_t {
which: ExternHost::Table(HostRef::new(table)),
which: ExternHost::Table(HostRef::new(&store.store, table)),
},
}))
}
@@ -60,14 +60,14 @@ pub extern "C" fn wasmtime_funcref_table_new(
) -> Option<Box<wasmtime_error_t>> {
let init: Val = match init {
Some(val) => Val::FuncRef(val.func().borrow().clone()),
None => Val::ExternRef(ExternRef::Null),
None => Val::ExternRef(None),
};
handle_result(
Table::new(&store.store.borrow(), tt.ty().ty.clone(), init),
Table::new(&store.store, tt.ty().ty.clone(), init),
|table| {
*out = Box::into_raw(Box::new(wasm_table_t {
ext: wasm_extern_t {
which: ExternHost::Table(HostRef::new(table)),
which: ExternHost::Table(HostRef::new(&store.store, table)),
},
}));
},
@@ -84,7 +84,7 @@ pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
pub extern "C" fn wasm_table_get(t: &wasm_table_t, index: wasm_table_size_t) -> *mut wasm_ref_t {
match t.table().borrow().get(index) {
Some(val) => into_funcref(val),
None => into_funcref(Val::ExternRef(ExternRef::Null)),
None => into_funcref(Val::ExternRef(None)),
}
}
@@ -98,8 +98,14 @@ pub extern "C" fn wasmtime_funcref_table_get(
Some(val) => {
*ptr = match val {
// TODO: what do do about creating new `HostRef` handles here?
Val::FuncRef(f) => Box::into_raw(Box::new(HostRef::new(f).into())),
Val::ExternRef(ExternRef::Null) => ptr::null_mut(),
Val::FuncRef(f) => {
let store = match t.table().as_ref().store() {
None => return false,
Some(store) => store,
};
Box::into_raw(Box::new(HostRef::new(&store, f).into()))
}
Val::ExternRef(None) => ptr::null_mut(),
_ => return false,
};
}
@@ -127,13 +133,13 @@ pub extern "C" fn wasmtime_funcref_table_set(
) -> Option<Box<wasmtime_error_t>> {
let val = match val {
Some(val) => Val::FuncRef(val.func().borrow().clone()),
None => Val::ExternRef(ExternRef::Null),
None => Val::ExternRef(None),
};
handle_result(t.table().borrow().set(index, val), |()| {})
}
fn into_funcref(val: Val) -> *mut wasm_ref_t {
if let Val::ExternRef(ExternRef::Null) = val {
if let Val::ExternRef(None) = val {
return ptr::null_mut();
}
let externref = match val.externref() {
@@ -148,7 +154,7 @@ unsafe fn from_funcref(r: *mut wasm_ref_t) -> Val {
if !r.is_null() {
Box::from_raw(r).r.into()
} else {
Val::ExternRef(ExternRef::Null)
Val::ExternRef(None)
}
}
@@ -176,7 +182,7 @@ pub extern "C" fn wasmtime_funcref_table_grow(
) -> Option<Box<wasmtime_error_t>> {
let val = match init {
Some(val) => Val::FuncRef(val.func().borrow().clone()),
None => Val::ExternRef(ExternRef::Null),
None => Val::ExternRef(None),
};
handle_result(t.table().borrow().grow(delta, val), |prev| {
if let Some(ptr) = prev_size {

View File

@@ -1,6 +1,6 @@
use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
use once_cell::unsync::OnceCell;
use wasmtime::{HostRef, Trap};
use wasmtime::{HostRef, Store, Trap};
#[repr(C)]
#[derive(Clone)]
@@ -11,14 +11,14 @@ pub struct wasm_trap_t {
wasmtime_c_api_macros::declare_ref!(wasm_trap_t);
impl wasm_trap_t {
pub(crate) fn new(trap: Trap) -> wasm_trap_t {
pub(crate) fn new(store: &Store, trap: Trap) -> wasm_trap_t {
wasm_trap_t {
trap: HostRef::new(trap),
trap: HostRef::new(store, trap),
}
}
fn externref(&self) -> wasmtime::ExternRef {
self.trap.externref()
self.trap.clone().into()
}
}
@@ -37,7 +37,7 @@ pub type wasm_message_t = wasm_name_t;
#[no_mangle]
pub extern "C" fn wasm_trap_new(
_store: &wasm_store_t,
store: &wasm_store_t,
message: &wasm_message_t,
) -> Box<wasm_trap_t> {
let message = message.as_slice();
@@ -46,7 +46,7 @@ pub extern "C" fn wasm_trap_new(
}
let message = String::from_utf8_lossy(&message[..message.len() - 1]);
Box::new(wasm_trap_t {
trap: HostRef::new(Trap::new(message)),
trap: HostRef::new(&store.store, Trap::new(message)),
})
}

View File

@@ -282,7 +282,7 @@ pub unsafe extern "C" fn wasi_instance_new(
config: Box<wasi_config_t>,
trap: &mut *mut wasm_trap_t,
) -> Option<Box<wasi_instance_t>> {
let store = &store.store.borrow();
let store = &store.store;
let result = match CStr::from_ptr(name).to_str().unwrap_or("") {
"wasi_snapshot_preview1" => create_preview1_instance(store, *config),
@@ -297,7 +297,7 @@ pub unsafe extern "C" fn wasi_instance_new(
})),
Err(e) => {
*trap = Box::into_raw(Box::new(wasm_trap_t {
trap: HostRef::new(Trap::new(e)),
trap: HostRef::new(store, Trap::new(e)),
}));
None
@@ -335,13 +335,14 @@ pub extern "C" fn wasi_instance_bind_import<'a>(
if &export.ty() != import.ty.func()? {
return None;
}
let store = export.store();
let entry = instance
.export_cache
.entry(name.to_string())
.or_insert_with(|| {
Box::new(wasm_extern_t {
which: ExternHost::Func(HostRef::new(export.clone())),
which: ExternHost::Func(HostRef::new(store, export.clone())),
})
});
Some(entry)