Tweak the API of the Val type (#679)
* Tweak the API of the `Val` type A few updates to the API of the `Val` type: * Added a payload for `V128`. * Replace existing accessor methods with `Option`-returning versions. * Add `unwrap_xxx` family of methods to extract a value and panic. * Remove `Into` conversions which panic, since panicking in `From` or `Into` isn't idiomatic in Rust * Add documentation to all methods/values/enums/etc. * Rename `Val::default` to `Val::null` * Run rustfmt * Review comments
This commit is contained in:
@@ -51,7 +51,7 @@ macro_rules! call {
|
|||||||
($func:expr, $($p:expr),*) => {
|
($func:expr, $($p:expr),*) => {
|
||||||
match $func.borrow().call(&[$($p.into()),*]) {
|
match $func.borrow().call(&[$($p.into()),*]) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let result: i32 = result[0].clone().into();
|
let result: i32 = result[0].unwrap_i32();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
Err(_) => { bail!("> Error on result, expected return"); }
|
Err(_) => { bail!("> Error on result, expected return"); }
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ struct Callback;
|
|||||||
impl Callable for Callback {
|
impl Callable for Callback {
|
||||||
fn call(&self, args: &[Val], results: &mut [Val]) -> Result<(), HostRef<Trap>> {
|
fn call(&self, args: &[Val], results: &mut [Val]) -> Result<(), HostRef<Trap>> {
|
||||||
println!("Calling back...");
|
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[0] = Val::I64(args[1].unwrap_i64() + 1);
|
||||||
results[1] = Val::I32(args[0].i32() + 1);
|
results[1] = Val::I32(args[0].unwrap_i32() + 1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,10 +88,10 @@ fn main() -> Result<()> {
|
|||||||
.map_err(|e| format_err!("> Error calling g! {:?}", e))?;
|
.map_err(|e| format_err!("> Error calling g! {:?}", e))?;
|
||||||
|
|
||||||
println!("Printing result...");
|
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[0].unwrap_i64(), 4);
|
||||||
debug_assert_eq!(results[1].i32(), 2);
|
debug_assert_eq!(results[1].unwrap_i32(), 2);
|
||||||
|
|
||||||
// Call `$round_trip_many`.
|
// Call `$round_trip_many`.
|
||||||
println!("Calling export \"round_trip_many\"...");
|
println!("Calling export \"round_trip_many\"...");
|
||||||
@@ -115,7 +115,7 @@ fn main() -> Result<()> {
|
|||||||
println!("Printing result...");
|
println!("Printing result...");
|
||||||
print!(">");
|
print!(">");
|
||||||
for r in results.iter() {
|
for r in results.iter() {
|
||||||
print!(" {}", r.i64());
|
print!(" {}", r.unwrap_i64());
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ impl Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(&self, params: &[Val]) -> Result<Box<[Val]>, HostRef<Trap>> {
|
pub fn call(&self, params: &[Val]) -> Result<Box<[Val]>, HostRef<Trap>> {
|
||||||
let mut results = vec![Val::default(); self.result_arity()];
|
let mut results = vec![Val::null(); self.result_arity()];
|
||||||
self.callable.call(params, &mut results)?;
|
self.callable.call(params, &mut results)?;
|
||||||
Ok(results.into_boxed_slice())
|
Ok(results.into_boxed_slice())
|
||||||
}
|
}
|
||||||
@@ -215,8 +215,8 @@ impl Global {
|
|||||||
match self.r#type().content() {
|
match self.r#type().content() {
|
||||||
ValType::I32 => Val::from(*definition.as_i32()),
|
ValType::I32 => Val::from(*definition.as_i32()),
|
||||||
ValType::I64 => Val::from(*definition.as_i64()),
|
ValType::I64 => Val::from(*definition.as_i64()),
|
||||||
ValType::F32 => Val::from_f32_bits(*definition.as_u32()),
|
ValType::F32 => Val::F32(*definition.as_u32()),
|
||||||
ValType::F64 => Val::from_f64_bits(*definition.as_u64()),
|
ValType::F64 => Val::F64(*definition.as_u64()),
|
||||||
_ => unimplemented!("Global::get for {:?}", self.r#type().content()),
|
_ => unimplemented!("Global::get for {:?}", self.r#type().content()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ unsafe extern "C" fn stub_fn(vmctx: *mut VMContext, call_id: u32, values_vec: *m
|
|||||||
(args, signature.returns.len())
|
(args, signature.returns.len())
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut returns = vec![Val::default(); returns_len];
|
let mut returns = vec![Val::null(); returns_len];
|
||||||
let func = &instance
|
let func = &instance
|
||||||
.host_state()
|
.host_state()
|
||||||
.downcast_mut::<TrampolineState>()
|
.downcast_mut::<TrampolineState>()
|
||||||
|
|||||||
@@ -6,21 +6,71 @@ use std::ptr;
|
|||||||
use wasmtime_environ::ir;
|
use wasmtime_environ::ir;
|
||||||
use wasmtime_jit::RuntimeValue;
|
use wasmtime_jit::RuntimeValue;
|
||||||
|
|
||||||
|
/// Possible runtime values that a WebAssembly module can either consume or
|
||||||
|
/// produce.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Val {
|
pub enum Val {
|
||||||
|
/// A 32-bit integer
|
||||||
I32(i32),
|
I32(i32),
|
||||||
|
|
||||||
|
/// A 64-bit integer
|
||||||
I64(i64),
|
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),
|
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),
|
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),
|
AnyRef(AnyRef),
|
||||||
|
|
||||||
|
/// A first-class reference to a WebAssembly function.
|
||||||
FuncRef(HostRef<Func>),
|
FuncRef(HostRef<Func>),
|
||||||
|
|
||||||
|
/// 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 {
|
impl Val {
|
||||||
pub fn default() -> Val {
|
/// Returns a null `anyref` value.
|
||||||
|
pub fn null() -> Val {
|
||||||
Val::AnyRef(AnyRef::null())
|
Val::AnyRef(AnyRef::null())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the corresponding [`ValType`] for this `Val`.
|
||||||
pub fn r#type(&self) -> ValType {
|
pub fn r#type(&self) -> ValType {
|
||||||
match self {
|
match self {
|
||||||
Val::I32(_) => ValType::I32,
|
Val::I32(_) => ValType::I32,
|
||||||
@@ -29,6 +79,7 @@ impl Val {
|
|||||||
Val::F64(_) => ValType::F64,
|
Val::F64(_) => ValType::F64,
|
||||||
Val::AnyRef(_) => ValType::AnyRef,
|
Val::AnyRef(_) => ValType::AnyRef,
|
||||||
Val::FuncRef(_) => ValType::FuncRef,
|
Val::FuncRef(_) => ValType::FuncRef,
|
||||||
|
Val::V128(_) => ValType::V128,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,52 +103,36 @@ impl Val {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_f32_bits(v: u32) -> Val {
|
accessors! {
|
||||||
Val::F32(v)
|
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<Func>) funcref unwrap_funcref e)
|
||||||
|
(V128(&[u8; 16]) v128 unwrap_v128 e)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_f64_bits(v: u64) -> Val {
|
/// Attempt to access the underlying value of this `Val`, returning
|
||||||
Val::F64(v)
|
/// `None` if it is not the correct type.
|
||||||
}
|
///
|
||||||
|
/// This will return `Some` for both the `AnyRef` and `FuncRef` types.
|
||||||
pub fn i32(&self) -> i32 {
|
pub fn anyref(&self) -> Option<AnyRef> {
|
||||||
if let Val::I32(i) = self {
|
match self {
|
||||||
*i
|
Val::AnyRef(e) => Some(e.clone()),
|
||||||
} else {
|
Val::FuncRef(e) => Some(e.anyref()),
|
||||||
panic!("Invalid conversion of {:?} to i32.", self);
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn i64(&self) -> i64 {
|
/// Returns the underlying value of this `Val`, panicking if it's the
|
||||||
if let Val::I64(i) = self {
|
/// wrong type.
|
||||||
*i
|
///
|
||||||
} else {
|
/// # Panics
|
||||||
panic!("Invalid conversion of {:?} to i64.", self);
|
///
|
||||||
}
|
/// Panics if `self` is not of the right type.
|
||||||
}
|
pub fn unwrap_anyref(&self) -> AnyRef {
|
||||||
|
self.anyref().expect("expected anyref")
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,30 +160,6 @@ impl From<f64> for Val {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<i32> for Val {
|
|
||||||
fn into(self) -> i32 {
|
|
||||||
self.i32()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<i64> for Val {
|
|
||||||
fn into(self) -> i64 {
|
|
||||||
self.i64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<f32> for Val {
|
|
||||||
fn into(self) -> f32 {
|
|
||||||
self.f32()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<f64> for Val {
|
|
||||||
fn into(self) -> f64 {
|
|
||||||
self.f64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AnyRef> for Val {
|
impl From<AnyRef> for Val {
|
||||||
fn from(val: AnyRef) -> Val {
|
fn from(val: AnyRef) -> Val {
|
||||||
match &val {
|
match &val {
|
||||||
@@ -170,16 +181,6 @@ impl From<HostRef<Func>> for Val {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<AnyRef> 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<RuntimeValue> for Val {
|
impl From<RuntimeValue> for Val {
|
||||||
fn from(rv: RuntimeValue) -> Self {
|
fn from(rv: RuntimeValue) -> Self {
|
||||||
match rv {
|
match rv {
|
||||||
@@ -187,23 +188,7 @@ impl From<RuntimeValue> for Val {
|
|||||||
RuntimeValue::I64(i) => Val::I64(i),
|
RuntimeValue::I64(i) => Val::I64(i),
|
||||||
RuntimeValue::F32(u) => Val::F32(u),
|
RuntimeValue::F32(u) => Val::F32(u),
|
||||||
RuntimeValue::F64(u) => Val::F64(u),
|
RuntimeValue::F64(u) => Val::F64(u),
|
||||||
x => {
|
RuntimeValue::V128(u) => Val::V128(u),
|
||||||
panic!("unsupported {:?}", x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<RuntimeValue> 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1553,7 +1553,11 @@ unsafe fn into_funcref(val: Val) -> *mut wasm_ref_t {
|
|||||||
if let Val::AnyRef(AnyRef::Null) = val {
|
if let Val::AnyRef(AnyRef::Null) = val {
|
||||||
return ptr::null_mut();
|
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)
|
Box::into_raw(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,14 @@ impl ModuleData {
|
|||||||
Ok(values) => values
|
Ok(values) => values
|
||||||
.to_vec()
|
.to_vec()
|
||||||
.into_iter()
|
.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::<Vec<RuntimeValue>>(),
|
.collect::<Vec<RuntimeValue>>(),
|
||||||
Err(trap) => bail!("trapped: {:?}", trap),
|
Err(trap) => bail!("trapped: {:?}", trap),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user