substrate_wasmtime/
values.rs1use crate::r#ref::ExternRef;
2use crate::{Func, Store, ValType};
3use anyhow::{bail, Result};
4use std::ptr;
5use wasmtime_runtime::{self as runtime, VMExternRef};
6
7#[derive(Debug, Clone)]
10pub enum Val {
11 I32(i32),
13
14 I64(i64),
16
17 F32(u32),
22
23 F64(u64),
28
29 ExternRef(Option<ExternRef>),
35
36 FuncRef(Option<Func>),
41
42 V128(u128),
44}
45
46macro_rules! accessors {
47 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
48 pub fn $get(&self) -> Option<$ty> {
51 if let Val::$variant($bind) = self {
52 Some($cvt)
53 } else {
54 None
55 }
56 }
57
58 pub fn $unwrap(&self) -> $ty {
65 self.$get().expect(concat!("expected ", stringify!($ty)))
66 }
67 )*)
68}
69
70impl Val {
71 pub fn null() -> Val {
73 Val::ExternRef(None)
74 }
75
76 pub fn ty(&self) -> ValType {
78 match self {
79 Val::I32(_) => ValType::I32,
80 Val::I64(_) => ValType::I64,
81 Val::F32(_) => ValType::F32,
82 Val::F64(_) => ValType::F64,
83 Val::ExternRef(_) => ValType::ExternRef,
84 Val::FuncRef(_) => ValType::FuncRef,
85 Val::V128(_) => ValType::V128,
86 }
87 }
88
89 pub(crate) unsafe fn write_value_to(self, store: &Store, p: *mut u128) {
90 match self {
91 Val::I32(i) => ptr::write(p as *mut i32, i),
92 Val::I64(i) => ptr::write(p as *mut i64, i),
93 Val::F32(u) => ptr::write(p as *mut u32, u),
94 Val::F64(u) => ptr::write(p as *mut u64, u),
95 Val::V128(b) => ptr::write(p as *mut u128, b),
96 Val::ExternRef(None) => ptr::write(p, 0),
97 Val::ExternRef(Some(x)) => {
98 let externref_ptr = x.inner.as_raw();
99 store
100 .externref_activations_table()
101 .insert_with_gc(x.inner, store.stack_map_registry());
102 ptr::write(p as *mut *mut u8, externref_ptr)
103 }
104 Val::FuncRef(f) => ptr::write(
105 p as *mut *mut runtime::VMCallerCheckedAnyfunc,
106 if let Some(f) = f {
107 f.caller_checked_anyfunc().as_ptr()
108 } else {
109 ptr::null_mut()
110 },
111 ),
112 }
113 }
114
115 pub(crate) unsafe fn read_value_from(store: &Store, p: *const u128, ty: &ValType) -> Val {
116 match ty {
117 ValType::I32 => Val::I32(ptr::read(p as *const i32)),
118 ValType::I64 => Val::I64(ptr::read(p as *const i64)),
119 ValType::F32 => Val::F32(ptr::read(p as *const u32)),
120 ValType::F64 => Val::F64(ptr::read(p as *const u64)),
121 ValType::V128 => Val::V128(ptr::read(p as *const u128)),
122 ValType::ExternRef => {
123 let raw = ptr::read(p as *const *mut u8);
124 if raw.is_null() {
125 Val::ExternRef(None)
126 } else {
127 Val::ExternRef(Some(ExternRef {
128 inner: VMExternRef::clone_from_raw(raw),
129 }))
130 }
131 }
132 ValType::FuncRef => {
133 let func = ptr::read(p as *const *mut runtime::VMCallerCheckedAnyfunc);
134 from_checked_anyfunc(func, store)
135 }
136 }
137 }
138
139 accessors! {
140 e
141 (I32(i32) i32 unwrap_i32 *e)
142 (I64(i64) i64 unwrap_i64 *e)
143 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
144 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
145 (FuncRef(Option<&Func>) funcref unwrap_funcref e.as_ref())
146 (V128(u128) v128 unwrap_v128 *e)
147 }
148
149 pub fn externref(&self) -> Option<Option<ExternRef>> {
157 match self {
158 Val::ExternRef(e) => Some(e.clone()),
159 _ => None,
160 }
161 }
162
163 pub fn unwrap_externref(&self) -> Option<ExternRef> {
174 self.externref().expect("expected externref")
175 }
176
177 pub(crate) fn into_table_element(self) -> Result<runtime::TableElement> {
178 match self {
179 Val::FuncRef(Some(f)) => Ok(runtime::TableElement::FuncRef(
180 f.caller_checked_anyfunc().as_ptr(),
181 )),
182 Val::FuncRef(None) => Ok(runtime::TableElement::FuncRef(ptr::null_mut())),
183 Val::ExternRef(Some(x)) => Ok(runtime::TableElement::ExternRef(Some(x.inner))),
184 Val::ExternRef(None) => Ok(runtime::TableElement::ExternRef(None)),
185 _ => bail!("value does not match table element type"),
186 }
187 }
188
189 pub(crate) fn comes_from_same_store(&self, store: &Store) -> bool {
190 match self {
191 Val::FuncRef(Some(f)) => Store::same(store, f.store()),
192 Val::FuncRef(None) => true,
193
194 Val::I32(_)
198 | Val::I64(_)
199 | Val::F32(_)
200 | Val::F64(_)
201 | Val::V128(_)
202 | Val::ExternRef(_) => true,
203 }
204 }
205}
206
207impl From<i32> for Val {
208 fn from(val: i32) -> Val {
209 Val::I32(val)
210 }
211}
212
213impl From<i64> for Val {
214 fn from(val: i64) -> Val {
215 Val::I64(val)
216 }
217}
218
219impl From<f32> for Val {
220 fn from(val: f32) -> Val {
221 Val::F32(val.to_bits())
222 }
223}
224
225impl From<f64> for Val {
226 fn from(val: f64) -> Val {
227 Val::F64(val.to_bits())
228 }
229}
230
231impl From<ExternRef> for Val {
232 fn from(val: ExternRef) -> Val {
233 Val::ExternRef(Some(val))
234 }
235}
236
237impl From<Option<ExternRef>> for Val {
238 fn from(val: Option<ExternRef>) -> Val {
239 Val::ExternRef(val)
240 }
241}
242
243impl From<Option<Func>> for Val {
244 fn from(val: Option<Func>) -> Val {
245 Val::FuncRef(val)
246 }
247}
248
249impl From<Func> for Val {
250 fn from(val: Func) -> Val {
251 Val::FuncRef(Some(val))
252 }
253}
254
255pub(crate) fn into_checked_anyfunc(
256 val: Val,
257 store: &Store,
258) -> Result<*mut wasmtime_runtime::VMCallerCheckedAnyfunc> {
259 if !val.comes_from_same_store(store) {
260 bail!("cross-`Store` values are not supported");
261 }
262 Ok(match val {
263 Val::FuncRef(None) => ptr::null_mut(),
264 Val::FuncRef(Some(f)) => f.caller_checked_anyfunc().as_ptr(),
265 _ => bail!("val is not funcref"),
266 })
267}
268
269pub(crate) unsafe fn from_checked_anyfunc(
270 anyfunc: *mut wasmtime_runtime::VMCallerCheckedAnyfunc,
271 store: &Store,
272) -> Val {
273 Val::FuncRef(Func::from_caller_checked_anyfunc(store, anyfunc))
274}