1 use crate::r#ref::ExternRef;
2 use crate::{Func, Store, ValType};
3 use anyhow::{bail, Result};
4 use std::ptr;
5 use wasmtime_runtime::VMExternRef;
6
7 /// Possible runtime values that a WebAssembly module can either consume or
8 /// produce.
9 #[derive(Debug, Clone)]
10 pub enum Val {
11 /// A 32-bit integer
12 I32(i32),
13
14 /// A 64-bit integer
15 I64(i64),
16
17 /// A 32-bit float.
18 ///
19 /// Note that the raw bits of the float are stored here, and you can use
20 /// `f32::from_bits` to create an `f32` value.
21 F32(u32),
22
23 /// A 64-bit float.
24 ///
25 /// Note that the raw bits of the float are stored here, and you can use
26 /// `f64::from_bits` to create an `f64` value.
27 F64(u64),
28
29 /// An `externref` value which can hold opaque data to the wasm instance itself.
30 ExternRef(Option<ExternRef>),
31
32 /// A first-class reference to a WebAssembly function.
33 FuncRef(Func),
34
35 /// A 128-bit number
36 V128(u128),
37 }
38
39 macro_rules! accessors {
40 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
41 /// Attempt to access the underlying value of this `Val`, returning
42 /// `None` if it is not the correct type.
43 pub fn $get(&self) -> Option<$ty> {
44 if let Val::$variant($bind) = self {
45 Some($cvt)
46 } else {
47 None
48 }
49 }
50
51 /// Returns the underlying value of this `Val`, panicking if it's the
52 /// wrong type.
53 ///
54 /// # Panics
55 ///
56 /// Panics if `self` is not of the right type.
57 pub fn $unwrap(&self) -> $ty {
58 self.$get().expect(concat!("expected ", stringify!($ty)))
59 }
60 )*)
61 }
62
63 impl Val {
64 /// Returns a null `externref` value.
null() -> Val65 pub fn null() -> Val {
66 Val::ExternRef(None)
67 }
68
69 /// Returns the corresponding [`ValType`] for this `Val`.
ty(&self) -> ValType70 pub fn ty(&self) -> ValType {
71 match self {
72 Val::I32(_) => ValType::I32,
73 Val::I64(_) => ValType::I64,
74 Val::F32(_) => ValType::F32,
75 Val::F64(_) => ValType::F64,
76 Val::ExternRef(_) => ValType::ExternRef,
77 Val::FuncRef(_) => ValType::FuncRef,
78 Val::V128(_) => ValType::V128,
79 }
80 }
81
write_value_to(&self, p: *mut u128)82 pub(crate) unsafe fn write_value_to(&self, p: *mut u128) {
83 match self {
84 Val::I32(i) => ptr::write(p as *mut i32, *i),
85 Val::I64(i) => ptr::write(p as *mut i64, *i),
86 Val::F32(u) => ptr::write(p as *mut u32, *u),
87 Val::F64(u) => ptr::write(p as *mut u64, *u),
88 Val::V128(b) => ptr::write(p as *mut u128, *b),
89 Val::ExternRef(None) => ptr::write(p, 0),
90 Val::ExternRef(Some(x)) => ptr::write(p as *mut *mut u8, x.inner.clone().into_raw()),
91 _ => unimplemented!("Val::write_value_to"),
92 }
93 }
94
read_value_from(store: &Store, p: *const u128, ty: &ValType) -> Val95 pub(crate) unsafe fn read_value_from(store: &Store, p: *const u128, ty: &ValType) -> Val {
96 match ty {
97 ValType::I32 => Val::I32(ptr::read(p as *const i32)),
98 ValType::I64 => Val::I64(ptr::read(p as *const i64)),
99 ValType::F32 => Val::F32(ptr::read(p as *const u32)),
100 ValType::F64 => Val::F64(ptr::read(p as *const u64)),
101 ValType::V128 => Val::V128(ptr::read(p as *const u128)),
102 ValType::ExternRef => {
103 let raw = ptr::read(p as *const *mut u8);
104 if raw.is_null() {
105 Val::ExternRef(None)
106 } else {
107 Val::ExternRef(Some(ExternRef {
108 inner: VMExternRef::from_raw(raw),
109 store: store.weak(),
110 }))
111 }
112 }
113 _ => unimplemented!("Val::read_value_from: {:?}", ty),
114 }
115 }
116
117 accessors! {
118 e
119 (I32(i32) i32 unwrap_i32 *e)
120 (I64(i64) i64 unwrap_i64 *e)
121 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
122 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
123 (FuncRef(&Func) funcref unwrap_funcref e)
124 (V128(u128) v128 unwrap_v128 *e)
125 }
126
127 /// Attempt to access the underlying `externref` value of this `Val`.
128 ///
129 /// If this is not an `externref`, then `None` is returned.
130 ///
131 /// If this is a null `externref`, then `Some(None)` is returned.
132 ///
133 /// If this is a non-null `externref`, then `Some(Some(..))` is returned.
externref(&self) -> Option<Option<ExternRef>>134 pub fn externref(&self) -> Option<Option<ExternRef>> {
135 match self {
136 Val::ExternRef(e) => Some(e.clone()),
137 _ => None,
138 }
139 }
140
141 /// Returns the underlying `externref` value of this `Val`, panicking if it's the
142 /// wrong type.
143 ///
144 /// If this is a null `externref`, then `None` is returned.
145 ///
146 /// If this is a non-null `externref`, then `Some(..)` is returned.
147 ///
148 /// # Panics
149 ///
150 /// Panics if `self` is not a (nullable) `externref`.
unwrap_externref(&self) -> Option<ExternRef>151 pub fn unwrap_externref(&self) -> Option<ExternRef> {
152 self.externref().expect("expected externref")
153 }
154
comes_from_same_store(&self, store: &Store) -> bool155 pub(crate) fn comes_from_same_store(&self, store: &Store) -> bool {
156 match self {
157 Val::FuncRef(f) => Store::same(store, f.store()),
158
159 // TODO: need to implement this once we actually finalize what
160 // `externref` will look like and it's actually implemented to pass it
161 // to compiled wasm as well.
162 Val::ExternRef(Some(e)) => e.store.ptr_eq(&store.weak()),
163 Val::ExternRef(None) => true,
164
165 // Integers have no association with any particular store, so
166 // they're always considered as "yes I came from that store",
167 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
168 }
169 }
170 }
171
172 impl From<i32> for Val {
from(val: i32) -> Val173 fn from(val: i32) -> Val {
174 Val::I32(val)
175 }
176 }
177
178 impl From<i64> for Val {
from(val: i64) -> Val179 fn from(val: i64) -> Val {
180 Val::I64(val)
181 }
182 }
183
184 impl From<f32> for Val {
from(val: f32) -> Val185 fn from(val: f32) -> Val {
186 Val::F32(val.to_bits())
187 }
188 }
189
190 impl From<f64> for Val {
from(val: f64) -> Val191 fn from(val: f64) -> Val {
192 Val::F64(val.to_bits())
193 }
194 }
195
196 impl From<ExternRef> for Val {
from(val: ExternRef) -> Val197 fn from(val: ExternRef) -> Val {
198 Val::ExternRef(Some(val))
199 }
200 }
201
202 impl From<Option<ExternRef>> for Val {
from(val: Option<ExternRef>) -> Val203 fn from(val: Option<ExternRef>) -> Val {
204 Val::ExternRef(val)
205 }
206 }
207
208 impl From<Func> for Val {
from(val: Func) -> Val209 fn from(val: Func) -> Val {
210 Val::FuncRef(val)
211 }
212 }
213
into_checked_anyfunc( val: Val, store: &Store, ) -> Result<wasmtime_runtime::VMCallerCheckedAnyfunc>214 pub(crate) fn into_checked_anyfunc(
215 val: Val,
216 store: &Store,
217 ) -> Result<wasmtime_runtime::VMCallerCheckedAnyfunc> {
218 if !val.comes_from_same_store(store) {
219 bail!("cross-`Store` values are not supported");
220 }
221 Ok(match val {
222 Val::ExternRef(None) => wasmtime_runtime::VMCallerCheckedAnyfunc {
223 func_ptr: ptr::null(),
224 type_index: wasmtime_runtime::VMSharedSignatureIndex::default(),
225 vmctx: ptr::null_mut(),
226 },
227 Val::FuncRef(f) => {
228 let f = f.wasmtime_function();
229 wasmtime_runtime::VMCallerCheckedAnyfunc {
230 func_ptr: f.address,
231 type_index: f.signature,
232 vmctx: f.vmctx,
233 }
234 }
235 _ => bail!("val is not funcref"),
236 })
237 }
238
from_checked_anyfunc( item: wasmtime_runtime::VMCallerCheckedAnyfunc, store: &Store, ) -> Val239 pub(crate) fn from_checked_anyfunc(
240 item: wasmtime_runtime::VMCallerCheckedAnyfunc,
241 store: &Store,
242 ) -> Val {
243 if item.type_index == wasmtime_runtime::VMSharedSignatureIndex::default() {
244 return Val::ExternRef(None);
245 }
246 let instance_handle = unsafe { wasmtime_runtime::InstanceHandle::from_vmctx(item.vmctx) };
247 let export = wasmtime_runtime::ExportFunction {
248 address: item.func_ptr,
249 signature: item.type_index,
250 vmctx: item.vmctx,
251 };
252 let instance = store.existing_instance_handle(instance_handle);
253 let f = Func::from_wasmtime_function(export, instance);
254 Val::FuncRef(f)
255 }
256