wasmtime-c-api: Add support for externref values
This required that `wasm_val_t` have a `Drop` implementation, an explicit `Clone` implementation, and no longer be `Copy`, which rippled out through the crate a bit. Additionally, `wasm_func_call` and friends were creating references to uninitialized data for its out pointers and assigning to them. As soon as `wasm_val_t` gained a `Drop` impl and tried to drop the old value of the assignment (which is uninitialized data), then things blew up. The fix is to properly represent the out pointers with `MaybeUninit`, and use `ptr::write` to initialize them without dropping the old data. Part of #929
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
use crate::{from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, WASM_I32};
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
use wasmtime::{Val, ValType};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct wasm_val_t {
|
||||
pub kind: wasm_valkind_t,
|
||||
pub of: wasm_val_union,
|
||||
@@ -20,6 +21,34 @@ pub union wasm_val_union {
|
||||
pub ref_: *mut wasm_ref_t,
|
||||
}
|
||||
|
||||
impl Drop for wasm_val_t {
|
||||
fn drop(&mut self) {
|
||||
match into_valtype(self.kind) {
|
||||
ValType::ExternRef => unsafe {
|
||||
drop(Box::from_raw(self.of.ref_));
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for wasm_val_t {
|
||||
fn clone(&self) -> Self {
|
||||
match into_valtype(self.kind) {
|
||||
ValType::ExternRef => wasm_val_t {
|
||||
kind: self.kind,
|
||||
of: wasm_val_union {
|
||||
ref_: unsafe { Box::into_raw(Box::new((*self.of.ref_).clone())) },
|
||||
},
|
||||
},
|
||||
_ => wasm_val_t {
|
||||
kind: self.kind,
|
||||
of: self.of,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for wasm_val_t {
|
||||
fn default() -> Self {
|
||||
wasm_val_t {
|
||||
@@ -30,46 +59,30 @@ impl Default for wasm_val_t {
|
||||
}
|
||||
|
||||
impl wasm_val_t {
|
||||
pub fn from_val(val: &Val) -> wasm_val_t {
|
||||
pub fn from_val(val: Val) -> wasm_val_t {
|
||||
match val {
|
||||
Val::I32(i) => wasm_val_t {
|
||||
kind: from_valtype(&ValType::I32),
|
||||
of: wasm_val_union { i32: *i },
|
||||
of: wasm_val_union { i32: i },
|
||||
},
|
||||
Val::I64(i) => wasm_val_t {
|
||||
kind: from_valtype(&ValType::I64),
|
||||
of: wasm_val_union { i64: *i },
|
||||
of: wasm_val_union { i64: i },
|
||||
},
|
||||
Val::F32(f) => wasm_val_t {
|
||||
kind: from_valtype(&ValType::F32),
|
||||
of: wasm_val_union { u32: *f },
|
||||
of: wasm_val_union { u32: f },
|
||||
},
|
||||
Val::F64(f) => wasm_val_t {
|
||||
kind: from_valtype(&ValType::F64),
|
||||
of: wasm_val_union { u64: *f },
|
||||
of: wasm_val_union { u64: f },
|
||||
},
|
||||
Val::ExternRef(r) => wasm_val_t {
|
||||
kind: from_valtype(&ValType::ExternRef),
|
||||
of: wasm_val_union {
|
||||
ref_: Box::into_raw(Box::new(wasm_ref_t { r })),
|
||||
},
|
||||
},
|
||||
_ => unimplemented!("wasm_val_t::from_val {:?}", val),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, val: Val) {
|
||||
match val {
|
||||
Val::I32(i) => {
|
||||
self.kind = from_valtype(&ValType::I32);
|
||||
self.of = wasm_val_union { i32: i };
|
||||
}
|
||||
Val::I64(i) => {
|
||||
self.kind = from_valtype(&ValType::I64);
|
||||
self.of = wasm_val_union { i64: i };
|
||||
}
|
||||
Val::F32(f) => {
|
||||
self.kind = from_valtype(&ValType::F32);
|
||||
self.of = wasm_val_union { u32: f };
|
||||
}
|
||||
Val::F64(f) => {
|
||||
self.kind = from_valtype(&ValType::F64);
|
||||
self.of = wasm_val_union { u64: f };
|
||||
}
|
||||
_ => unimplemented!("wasm_val_t::from_val {:?}", val),
|
||||
}
|
||||
}
|
||||
@@ -80,20 +93,26 @@ impl wasm_val_t {
|
||||
ValType::I64 => Val::from(unsafe { self.of.i64 }),
|
||||
ValType::F32 => Val::from(unsafe { self.of.f32 }),
|
||||
ValType::F64 => Val::from(unsafe { self.of.f64 }),
|
||||
ValType::ExternRef => Val::ExternRef(unsafe { (*self.of.ref_).r.clone() }),
|
||||
_ => unimplemented!("wasm_val_t::val {:?}", self.kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_val_copy(out: *mut wasm_val_t, source: &wasm_val_t) {
|
||||
*out = match into_valtype(source.kind) {
|
||||
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => *source,
|
||||
_ => unimplemented!("wasm_val_copy arg"),
|
||||
};
|
||||
pub unsafe extern "C" fn wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source: &wasm_val_t) {
|
||||
ptr::write(
|
||||
out.as_mut_ptr(),
|
||||
match into_valtype(source.kind) {
|
||||
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::ExternRef => {
|
||||
source.clone()
|
||||
}
|
||||
_ => unimplemented!("wasm_val_copy arg"),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_val_delete(_val: &mut wasm_val_t) {
|
||||
// currently we only support integers/floats which need no deletion
|
||||
pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
|
||||
ptr::drop_in_place(val);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user