diff --git a/crates/api/examples/memory.rs b/crates/api/examples/memory.rs index 3c72d87bbb..2b84d81d03 100644 --- a/crates/api/examples/memory.rs +++ b/crates/api/examples/memory.rs @@ -51,7 +51,7 @@ macro_rules! call { ($func:expr, $($p:expr),*) => { match $func.borrow().call(&[$($p.into()),*]) { Ok(result) => { - let result: i32 = result[0].clone().into(); + let result: i32 = result[0].unwrap_i32(); result } Err(_) => { bail!("> Error on result, expected return"); } diff --git a/crates/api/examples/multi.rs b/crates/api/examples/multi.rs index 9fb4d4118f..d02e56cbc6 100644 --- a/crates/api/examples/multi.rs +++ b/crates/api/examples/multi.rs @@ -9,10 +9,10 @@ struct Callback; impl Callable for Callback { fn call(&self, args: &[Val], results: &mut [Val]) -> Result<(), HostRef> { println!("Calling back..."); - println!("> {} {}", args[0].i32(), args[1].i64()); + println!("> {} {}", args[0].unwrap_i32(), args[1].unwrap_i64()); - results[0] = Val::I64(args[1].i64() + 1); - results[1] = Val::I32(args[0].i32() + 1); + results[0] = Val::I64(args[1].unwrap_i64() + 1); + results[1] = Val::I32(args[0].unwrap_i32() + 1); Ok(()) } } @@ -88,10 +88,10 @@ fn main() -> Result<()> { .map_err(|e| format_err!("> Error calling g! {:?}", e))?; println!("Printing result..."); - println!("> {} {}", results[0].i64(), results[1].i32()); + println!("> {} {}", results[0].unwrap_i64(), results[1].unwrap_i32()); - debug_assert_eq!(results[0].i64(), 4); - debug_assert_eq!(results[1].i32(), 2); + debug_assert_eq!(results[0].unwrap_i64(), 4); + debug_assert_eq!(results[1].unwrap_i32(), 2); // Call `$round_trip_many`. println!("Calling export \"round_trip_many\"..."); @@ -115,7 +115,7 @@ fn main() -> Result<()> { println!("Printing result..."); print!(">"); for r in results.iter() { - print!(" {}", r.i64()); + print!(" {}", r.unwrap_i64()); } println!(); diff --git a/crates/api/src/externals.rs b/crates/api/src/externals.rs index 2c8ad3e887..b02589bf17 100644 --- a/crates/api/src/externals.rs +++ b/crates/api/src/externals.rs @@ -148,7 +148,7 @@ impl Func { } pub fn call(&self, params: &[Val]) -> Result, HostRef> { - let mut results = vec![Val::default(); self.result_arity()]; + let mut results = vec![Val::null(); self.result_arity()]; self.callable.call(params, &mut results)?; Ok(results.into_boxed_slice()) } @@ -215,8 +215,8 @@ impl Global { match self.r#type().content() { ValType::I32 => Val::from(*definition.as_i32()), ValType::I64 => Val::from(*definition.as_i64()), - ValType::F32 => Val::from_f32_bits(*definition.as_u32()), - ValType::F64 => Val::from_f64_bits(*definition.as_u64()), + ValType::F32 => Val::F32(*definition.as_u32()), + ValType::F64 => Val::F64(*definition.as_u64()), _ => unimplemented!("Global::get for {:?}", self.r#type().content()), } } diff --git a/crates/api/src/trampoline/func.rs b/crates/api/src/trampoline/func.rs index d2fcfb3d4c..d283370b44 100644 --- a/crates/api/src/trampoline/func.rs +++ b/crates/api/src/trampoline/func.rs @@ -80,7 +80,7 @@ unsafe extern "C" fn stub_fn(vmctx: *mut VMContext, call_id: u32, values_vec: *m (args, signature.returns.len()) }; - let mut returns = vec![Val::default(); returns_len]; + let mut returns = vec![Val::null(); returns_len]; let func = &instance .host_state() .downcast_mut::() diff --git a/crates/api/src/values.rs b/crates/api/src/values.rs index dc0d96e871..0d87ea6ddb 100644 --- a/crates/api/src/values.rs +++ b/crates/api/src/values.rs @@ -6,21 +6,71 @@ use std::ptr; use wasmtime_environ::ir; use wasmtime_jit::RuntimeValue; +/// Possible runtime values that a WebAssembly module can either consume or +/// produce. #[derive(Debug, Clone)] pub enum Val { + /// A 32-bit integer I32(i32), + + /// A 64-bit integer I64(i64), + + /// A 32-bit float. + /// + /// Note that the raw bits of the float are stored here, and you can use + /// `f32::from_bits` to create an `f32` value. F32(u32), + + /// A 64-bit float. + /// + /// Note that the raw bits of the float are stored here, and you can use + /// `f64::from_bits` to create an `f64` value. F64(u64), + + /// An `anyref` value which can hold opaque data to the wasm instance itself. + /// + /// Note that this is a nullable value as well. AnyRef(AnyRef), + + /// A first-class reference to a WebAssembly function. FuncRef(HostRef), + + /// A 128-bit number + V128([u8; 16]), +} + +macro_rules! accessors { + ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($( + /// Attempt to access the underlying value of this `Val`, returning + /// `None` if it is not the correct type. + pub fn $get(&self) -> Option<$ty> { + if let Val::$variant($bind) = self { + Some($cvt) + } else { + None + } + } + + /// Returns the underlying value of this `Val`, panicking if it's the + /// wrong type. + /// + /// # Panics + /// + /// Panics if `self` is not of the right type. + pub fn $unwrap(&self) -> $ty { + self.$get().expect(concat!("expected ", stringify!($ty))) + } + )*) } impl Val { - pub fn default() -> Val { + /// Returns a null `anyref` value. + pub fn null() -> Val { Val::AnyRef(AnyRef::null()) } + /// Returns the corresponding [`ValType`] for this `Val`. pub fn r#type(&self) -> ValType { match self { Val::I32(_) => ValType::I32, @@ -29,6 +79,7 @@ impl Val { Val::F64(_) => ValType::F64, Val::AnyRef(_) => ValType::AnyRef, Val::FuncRef(_) => ValType::FuncRef, + Val::V128(_) => ValType::V128, } } @@ -52,52 +103,36 @@ impl Val { } } - pub fn from_f32_bits(v: u32) -> Val { - Val::F32(v) + accessors! { + e + (I32(i32) i32 unwrap_i32 *e) + (I64(i64) i64 unwrap_i64 *e) + (F32(f32) f32 unwrap_f32 f32::from_bits(*e)) + (F64(f64) f64 unwrap_f64 f64::from_bits(*e)) + (FuncRef(&HostRef) funcref unwrap_funcref e) + (V128(&[u8; 16]) v128 unwrap_v128 e) } - pub fn from_f64_bits(v: u64) -> Val { - Val::F64(v) - } - - pub fn i32(&self) -> i32 { - if let Val::I32(i) = self { - *i - } else { - panic!("Invalid conversion of {:?} to i32.", self); + /// Attempt to access the underlying value of this `Val`, returning + /// `None` if it is not the correct type. + /// + /// This will return `Some` for both the `AnyRef` and `FuncRef` types. + pub fn anyref(&self) -> Option { + match self { + Val::AnyRef(e) => Some(e.clone()), + Val::FuncRef(e) => Some(e.anyref()), + _ => None, } } - pub fn i64(&self) -> i64 { - if let Val::I64(i) = self { - *i - } else { - panic!("Invalid conversion of {:?} to i64.", self); - } - } - - pub fn f32(&self) -> f32 { - RuntimeValue::F32(self.f32_bits()).unwrap_f32() - } - - pub fn f64(&self) -> f64 { - RuntimeValue::F64(self.f64_bits()).unwrap_f64() - } - - pub fn f32_bits(&self) -> u32 { - if let Val::F32(i) = self { - *i - } else { - panic!("Invalid conversion of {:?} to f32.", self); - } - } - - pub fn f64_bits(&self) -> u64 { - if let Val::F64(i) = self { - *i - } else { - panic!("Invalid conversion of {:?} to f64.", self); - } + /// Returns the underlying value of this `Val`, panicking if it's the + /// wrong type. + /// + /// # Panics + /// + /// Panics if `self` is not of the right type. + pub fn unwrap_anyref(&self) -> AnyRef { + self.anyref().expect("expected anyref") } } @@ -125,30 +160,6 @@ impl From for Val { } } -impl Into for Val { - fn into(self) -> i32 { - self.i32() - } -} - -impl Into for Val { - fn into(self) -> i64 { - self.i64() - } -} - -impl Into for Val { - fn into(self) -> f32 { - self.f32() - } -} - -impl Into for Val { - fn into(self) -> f64 { - self.f64() - } -} - impl From for Val { fn from(val: AnyRef) -> Val { match &val { @@ -170,16 +181,6 @@ impl From> for Val { } } -impl Into for Val { - fn into(self) -> AnyRef { - match self { - Val::AnyRef(r) => r, - Val::FuncRef(f) => f.anyref(), - _ => panic!("Invalid conversion of {:?} to anyref.", self), - } - } -} - impl From for Val { fn from(rv: RuntimeValue) -> Self { match rv { @@ -187,23 +188,7 @@ impl From for Val { RuntimeValue::I64(i) => Val::I64(i), RuntimeValue::F32(u) => Val::F32(u), RuntimeValue::F64(u) => Val::F64(u), - x => { - panic!("unsupported {:?}", x); - } - } - } -} - -impl Into for Val { - fn into(self) -> RuntimeValue { - match self { - Val::I32(i) => RuntimeValue::I32(i), - Val::I64(i) => RuntimeValue::I64(i), - Val::F32(u) => RuntimeValue::F32(u), - Val::F64(u) => RuntimeValue::F64(u), - x => { - panic!("unsupported {:?}", x); - } + RuntimeValue::V128(u) => Val::V128(u), } } } diff --git a/crates/api/src/wasm.rs b/crates/api/src/wasm.rs index 25f3946a63..5c58edaa10 100644 --- a/crates/api/src/wasm.rs +++ b/crates/api/src/wasm.rs @@ -1553,7 +1553,11 @@ unsafe fn into_funcref(val: Val) -> *mut wasm_ref_t { if let Val::AnyRef(AnyRef::Null) = val { return ptr::null_mut(); } - let r = Box::new(wasm_ref_t { r: val.into() }); + let anyref = match val.anyref() { + Some(anyref) => anyref, + None => return ptr::null_mut(), + }; + let r = Box::new(wasm_ref_t { r: anyref }); Box::into_raw(r) } diff --git a/crates/interface-types/src/lib.rs b/crates/interface-types/src/lib.rs index f505dbd136..512ec33222 100644 --- a/crates/interface-types/src/lib.rs +++ b/crates/interface-types/src/lib.rs @@ -152,7 +152,14 @@ impl ModuleData { Ok(values) => values .to_vec() .into_iter() - .map(|v: wasmtime::Val| v.into()) + .map(|v: wasmtime::Val| match v { + wasmtime::Val::I32(i) => RuntimeValue::I32(i), + wasmtime::Val::I64(i) => RuntimeValue::I64(i), + wasmtime::Val::F32(i) => RuntimeValue::F32(i), + wasmtime::Val::F64(i) => RuntimeValue::F64(i), + wasmtime::Val::V128(i) => RuntimeValue::V128(i), + _ => panic!("unsupported value {:?}", v), + }) .collect::>(), Err(trap) => bail!("trapped: {:?}", trap), };