1 use crate::r#ref::ref_to_val; 2 use crate::{ 3 WASM_I32, from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, wasmtime_anyref_t, 4 wasmtime_externref_t, wasmtime_valkind_t, 5 }; 6 use std::mem::{ManuallyDrop, MaybeUninit}; 7 use std::ptr; 8 use wasmtime::{AsContextMut, Func, HeapType, Ref, RootScope, Val, ValType}; 9 10 #[repr(C)] 11 pub struct wasm_val_t { 12 pub kind: wasm_valkind_t, 13 pub of: wasm_val_union, 14 } 15 16 #[repr(C)] 17 #[derive(Copy, Clone)] 18 pub union wasm_val_union { 19 pub i32: i32, 20 pub i64: i64, 21 pub u32: u32, 22 pub u64: u64, 23 pub f32: f32, 24 pub f64: f64, 25 pub ref_: *mut wasm_ref_t, 26 } 27 28 impl Drop for wasm_val_t { 29 fn drop(&mut self) { 30 match into_valtype(self.kind) { 31 ValType::Ref(_) => unsafe { 32 if !self.of.ref_.is_null() { 33 drop(Box::from_raw(self.of.ref_)); 34 } 35 }, 36 _ => {} 37 } 38 } 39 } 40 41 impl Clone for wasm_val_t { 42 fn clone(&self) -> Self { 43 let mut ret = wasm_val_t { 44 kind: self.kind, 45 of: self.of, 46 }; 47 unsafe { 48 match into_valtype(self.kind) { 49 ValType::Ref(_) if !self.of.ref_.is_null() => { 50 ret.of.ref_ = Box::into_raw(Box::new((*self.of.ref_).clone())); 51 } 52 _ => {} 53 } 54 } 55 return ret; 56 } 57 } 58 59 impl Default for wasm_val_t { 60 fn default() -> Self { 61 wasm_val_t { 62 kind: WASM_I32, 63 of: wasm_val_union { i32: 0 }, 64 } 65 } 66 } 67 68 impl wasm_val_t { 69 pub fn from_val(val: Val) -> wasm_val_t { 70 match val { 71 Val::I32(i) => wasm_val_t { 72 kind: from_valtype(&ValType::I32), 73 of: wasm_val_union { i32: i }, 74 }, 75 Val::I64(i) => wasm_val_t { 76 kind: from_valtype(&ValType::I64), 77 of: wasm_val_union { i64: i }, 78 }, 79 Val::F32(f) => wasm_val_t { 80 kind: from_valtype(&ValType::F32), 81 of: wasm_val_union { u32: f }, 82 }, 83 Val::F64(f) => wasm_val_t { 84 kind: from_valtype(&ValType::F64), 85 of: wasm_val_union { u64: f }, 86 }, 87 Val::FuncRef(f) => wasm_val_t { 88 kind: from_valtype(&ValType::FUNCREF), 89 of: wasm_val_union { 90 ref_: f.map_or(ptr::null_mut(), |f| { 91 Box::into_raw(Box::new(wasm_ref_t { 92 r: Ref::Func(Some(f)), 93 })) 94 }), 95 }, 96 }, 97 Val::AnyRef(_) => crate::abort("creating a wasm_val_t from an anyref"), 98 Val::ExternRef(_) => crate::abort("creating a wasm_val_t from an externref"), 99 Val::ExnRef(_) => crate::abort("creating a wasm_val_t from an exnref"), 100 Val::V128(_) => crate::abort("creating a wasm_val_t from a v128"), 101 Val::ContRef(_) => crate::abort("creating a wasm_val_t from a contref"), 102 } 103 } 104 105 pub fn val(&self) -> Val { 106 match into_valtype(self.kind) { 107 ValType::I32 => Val::from(unsafe { self.of.i32 }), 108 ValType::I64 => Val::from(unsafe { self.of.i64 }), 109 ValType::F32 => Val::from(unsafe { self.of.f32 }), 110 ValType::F64 => Val::from(unsafe { self.of.f64 }), 111 ValType::Ref(r) => match r.heap_type() { 112 HeapType::Func => unsafe { 113 if self.of.ref_.is_null() { 114 assert!(r.is_nullable()); 115 Val::FuncRef(None) 116 } else { 117 ref_to_val(&*self.of.ref_) 118 } 119 }, 120 _ => unreachable!("wasm_val_t cannot contain non-function reference values"), 121 }, 122 ValType::V128 => unimplemented!("wasm_val_t: v128"), 123 } 124 } 125 } 126 127 #[unsafe(no_mangle)] 128 pub unsafe extern "C" fn wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source: &wasm_val_t) { 129 crate::initialize(out, source.clone()); 130 } 131 132 #[unsafe(no_mangle)] 133 pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) { 134 ptr::drop_in_place(val); 135 } 136 137 #[repr(C)] 138 pub struct wasmtime_val_t { 139 pub kind: wasmtime_valkind_t, 140 pub of: wasmtime_val_union, 141 } 142 143 #[repr(C)] 144 pub union wasmtime_val_union { 145 pub i32: i32, 146 pub i64: i64, 147 pub f32: u32, 148 pub f64: u64, 149 pub anyref: ManuallyDrop<wasmtime_anyref_t>, 150 pub externref: ManuallyDrop<wasmtime_externref_t>, 151 pub funcref: wasmtime_func_t, 152 pub v128: [u8; 16], 153 } 154 155 const _: () = { 156 // This is forced to 24 or 20 bytes by `anyref` and `externref`. 157 assert!(std::mem::size_of::<wasmtime_val_union>() <= 24); 158 assert!(std::mem::align_of::<wasmtime_val_union>() == std::mem::align_of::<u64>()); 159 }; 160 161 impl Drop for wasmtime_val_t { 162 fn drop(&mut self) { 163 unsafe { 164 match self.kind { 165 crate::WASMTIME_ANYREF => { 166 let _ = ManuallyDrop::take(&mut self.of.anyref); 167 } 168 crate::WASMTIME_EXTERNREF => { 169 let _ = ManuallyDrop::take(&mut self.of.externref); 170 } 171 _ => {} 172 } 173 } 174 } 175 } 176 177 // The raw pointers are actually optional boxes. 178 unsafe impl Send for wasmtime_val_union 179 where 180 Option<Box<wasmtime_anyref_t>>: Send, 181 Option<Box<wasmtime_externref_t>>: Send, 182 { 183 } 184 unsafe impl Sync for wasmtime_val_union 185 where 186 Option<Box<wasmtime_anyref_t>>: Sync, 187 Option<Box<wasmtime_externref_t>>: Sync, 188 { 189 } 190 191 #[repr(C)] 192 #[derive(Clone, Copy)] 193 pub union wasmtime_func_t { 194 store_id: u64, 195 func: Func, 196 } 197 198 impl wasmtime_func_t { 199 unsafe fn as_wasmtime(&self) -> Option<Func> { 200 if self.store_id == 0 { 201 None 202 } else { 203 Some(self.func) 204 } 205 } 206 } 207 208 impl From<Option<Func>> for wasmtime_func_t { 209 fn from(func: Option<Func>) -> wasmtime_func_t { 210 match func { 211 Some(func) => wasmtime_func_t { func }, 212 None => wasmtime_func_t { store_id: 0 }, 213 } 214 } 215 } 216 217 impl wasmtime_val_t { 218 /// Creates a new `wasmtime_val_t` from a `wasmtime::Val`. 219 /// 220 /// Note that this requires a `RootScope` to be present to serve as proof 221 /// that `val` is not require to be rooted in the store itself which would 222 /// prevent GC. Callers should prefer this API where possible, creating a 223 /// temporary `RootScope` when needed. 224 pub fn from_val(cx: &mut RootScope<impl AsContextMut>, val: Val) -> wasmtime_val_t { 225 Self::from_val_unscoped(cx, val) 226 } 227 228 /// Equivalent of [`wasmtime_val_t::from_val`] except that a `RootScope` 229 /// is not required. 230 /// 231 /// This method should only be used when a `RootScope` is known to be 232 /// elsewhere on the stack. For example this is used when we call back out 233 /// to the embedder. In such a situation we know we previously entered with 234 /// some other call so the root scope is on the stack there. 235 pub fn from_val_unscoped(cx: impl AsContextMut, val: Val) -> wasmtime_val_t { 236 match val { 237 Val::I32(i) => wasmtime_val_t { 238 kind: crate::WASMTIME_I32, 239 of: wasmtime_val_union { i32: i }, 240 }, 241 Val::I64(i) => wasmtime_val_t { 242 kind: crate::WASMTIME_I64, 243 of: wasmtime_val_union { i64: i }, 244 }, 245 Val::F32(i) => wasmtime_val_t { 246 kind: crate::WASMTIME_F32, 247 of: wasmtime_val_union { f32: i }, 248 }, 249 Val::F64(i) => wasmtime_val_t { 250 kind: crate::WASMTIME_F64, 251 of: wasmtime_val_union { f64: i }, 252 }, 253 Val::AnyRef(a) => wasmtime_val_t { 254 kind: crate::WASMTIME_ANYREF, 255 of: wasmtime_val_union { 256 anyref: ManuallyDrop::new(a.and_then(|a| a.to_owned_rooted(cx).ok()).into()), 257 }, 258 }, 259 Val::ExternRef(e) => wasmtime_val_t { 260 kind: crate::WASMTIME_EXTERNREF, 261 of: wasmtime_val_union { 262 externref: ManuallyDrop::new(e.and_then(|e| e.to_owned_rooted(cx).ok()).into()), 263 }, 264 }, 265 Val::FuncRef(func) => wasmtime_val_t { 266 kind: crate::WASMTIME_FUNCREF, 267 of: wasmtime_val_union { 268 funcref: func.into(), 269 }, 270 }, 271 Val::ExnRef(_) => crate::abort("exnrefs not yet supported in C API"), 272 Val::V128(val) => wasmtime_val_t { 273 kind: crate::WASMTIME_V128, 274 of: wasmtime_val_union { 275 v128: val.as_u128().to_le_bytes(), 276 }, 277 }, 278 Val::ContRef(_) => crate::abort("contrefs not yet supported in C API (#10248)"), 279 } 280 } 281 282 /// Convert this `wasmtime_val_t` into a `wasmtime::Val`. 283 /// 284 /// See [`wasmtime_val_t::from_val`] for notes on the `RootScope` 285 /// requirement here. Note that this is particularly meaningful for this 286 /// API as the `Val` returned may contain a `Rooted<T>` which requires a 287 /// `RootScope` if we don't want the value to live for the entire lifetime 288 /// of the `Store`. 289 pub unsafe fn to_val(&self, cx: &mut RootScope<impl AsContextMut>) -> Val { 290 self.to_val_unscoped(cx) 291 } 292 293 /// Equivalent of `to_val` except doesn't require a `RootScope`. 294 /// 295 /// See notes on [`wasmtime_val_t::from_val_unscoped`] for notes on when to 296 /// use this. 297 pub unsafe fn to_val_unscoped(&self, cx: impl AsContextMut) -> Val { 298 match self.kind { 299 crate::WASMTIME_I32 => Val::I32(self.of.i32), 300 crate::WASMTIME_I64 => Val::I64(self.of.i64), 301 crate::WASMTIME_F32 => Val::F32(self.of.f32), 302 crate::WASMTIME_F64 => Val::F64(self.of.f64), 303 crate::WASMTIME_V128 => Val::V128(u128::from_le_bytes(self.of.v128).into()), 304 crate::WASMTIME_ANYREF => { 305 Val::AnyRef(self.of.anyref.as_wasmtime().map(|a| a.to_rooted(cx))) 306 } 307 crate::WASMTIME_EXTERNREF => { 308 Val::ExternRef(self.of.externref.as_wasmtime().map(|e| e.to_rooted(cx))) 309 } 310 crate::WASMTIME_FUNCREF => Val::FuncRef(self.of.funcref.as_wasmtime()), 311 other => panic!("unknown wasmtime_valkind_t: {other}"), 312 } 313 } 314 } 315 316 #[unsafe(no_mangle)] 317 pub unsafe extern "C" fn wasmtime_val_unroot(val: &mut ManuallyDrop<wasmtime_val_t>) { 318 ManuallyDrop::drop(val); 319 } 320 321 #[unsafe(no_mangle)] 322 pub unsafe extern "C" fn wasmtime_val_clone( 323 src: &wasmtime_val_t, 324 dst: &mut MaybeUninit<wasmtime_val_t>, 325 ) { 326 let of = match src.kind { 327 crate::WASMTIME_ANYREF => wasmtime_val_union { 328 anyref: ManuallyDrop::new(src.of.anyref.as_wasmtime().into()), 329 }, 330 crate::WASMTIME_EXTERNREF => wasmtime_val_union { 331 externref: ManuallyDrop::new(src.of.externref.as_wasmtime().into()), 332 }, 333 crate::WASMTIME_I32 => wasmtime_val_union { i32: src.of.i32 }, 334 crate::WASMTIME_I64 => wasmtime_val_union { i64: src.of.i64 }, 335 crate::WASMTIME_F32 => wasmtime_val_union { f32: src.of.f32 }, 336 crate::WASMTIME_F64 => wasmtime_val_union { f64: src.of.f64 }, 337 crate::WASMTIME_V128 => wasmtime_val_union { v128: src.of.v128 }, 338 crate::WASMTIME_FUNCREF => wasmtime_val_union { 339 funcref: src.of.funcref, 340 }, 341 _ => unreachable!(), 342 }; 343 dst.write(wasmtime_val_t { kind: src.kind, of }); 344 } 345