1 use crate::{WasmtimeStoreContextMut, abort}; 2 use std::mem::{ManuallyDrop, MaybeUninit}; 3 use std::{num::NonZeroU64, os::raw::c_void, ptr}; 4 use wasmtime::{AnyRef, EqRef, ExnRef, ExternRef, I31, OwnedRooted, Ref, RootScope, Val}; 5 6 /// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by 7 /// the C API. Because we do not have a uniform representation for `funcref`s 8 /// and `externref`s, a `*mut wasm_ref_t` is morally a 9 /// `Option<Box<Either<ExternRef, Func>>>`. 10 /// 11 /// A null `*mut wasm_ref_t` is either a null `funcref` or a null `externref` 12 /// depending on context (e.g. the table's element type that it is going into or 13 /// coming out of). 14 /// 15 /// Note: this is not `#[repr(C)]` because it is an opaque type in the header, 16 /// and only ever referenced as `*mut wasm_ref_t`. This also lets us use a 17 /// regular, non-`repr(C)` `enum` to define `WasmRefInner`. 18 #[derive(Clone)] 19 pub struct wasm_ref_t { 20 pub(crate) r: Ref, 21 } 22 23 wasmtime_c_api_macros::declare_own!(wasm_ref_t); 24 25 impl wasm_ref_t { 26 pub(crate) fn new(r: Ref) -> Option<Box<wasm_ref_t>> { 27 if r.is_null() || !r.is_func() { 28 None 29 } else { 30 Some(Box::new(wasm_ref_t { r })) 31 } 32 } 33 } 34 35 pub(crate) fn ref_to_val(r: &wasm_ref_t) -> Val { 36 Val::from(r.r.clone()) 37 } 38 39 #[unsafe(no_mangle)] 40 pub extern "C" fn wasm_ref_copy(r: Option<&wasm_ref_t>) -> Option<Box<wasm_ref_t>> { 41 r.map(|r| Box::new(r.clone())) 42 } 43 44 #[unsafe(no_mangle)] 45 pub extern "C" fn wasm_ref_same(_a: Option<&wasm_ref_t>, _b: Option<&wasm_ref_t>) -> bool { 46 // We need a store to determine whether these are the same reference or not. 47 abort("wasm_ref_same") 48 } 49 50 #[unsafe(no_mangle)] 51 pub extern "C" fn wasm_ref_get_host_info(_ref: Option<&wasm_ref_t>) -> *mut c_void { 52 std::ptr::null_mut() 53 } 54 55 #[unsafe(no_mangle)] 56 pub extern "C" fn wasm_ref_set_host_info(_ref: Option<&wasm_ref_t>, _info: *mut c_void) { 57 abort("wasm_ref_set_host_info") 58 } 59 60 #[unsafe(no_mangle)] 61 pub extern "C" fn wasm_ref_set_host_info_with_finalizer( 62 _ref: Option<&wasm_ref_t>, 63 _info: *mut c_void, 64 _finalizer: Option<extern "C" fn(*mut c_void)>, 65 ) { 66 abort("wasm_ref_set_host_info_with_finalizer") 67 } 68 69 #[unsafe(no_mangle)] 70 pub extern "C" fn wasm_ref_as_extern(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_extern_t> { 71 abort("wasm_ref_as_extern") 72 } 73 74 #[unsafe(no_mangle)] 75 pub extern "C" fn wasm_ref_as_extern_const( 76 _ref: Option<&wasm_ref_t>, 77 ) -> Option<&crate::wasm_extern_t> { 78 abort("wasm_ref_as_extern_const") 79 } 80 81 #[unsafe(no_mangle)] 82 pub extern "C" fn wasm_ref_as_foreign(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_foreign_t> { 83 abort("wasm_ref_as_foreign") 84 } 85 86 #[unsafe(no_mangle)] 87 pub extern "C" fn wasm_ref_as_foreign_const( 88 _ref: Option<&wasm_ref_t>, 89 ) -> Option<&crate::wasm_foreign_t> { 90 abort("wasm_ref_as_foreign_const") 91 } 92 93 #[unsafe(no_mangle)] 94 pub extern "C" fn wasm_ref_as_func(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> { 95 abort("wasm_ref_as_func") 96 } 97 98 #[unsafe(no_mangle)] 99 pub extern "C" fn wasm_ref_as_func_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> { 100 abort("wasm_ref_as_func_const") 101 } 102 103 #[unsafe(no_mangle)] 104 pub extern "C" fn wasm_ref_as_global(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_global_t> { 105 abort("wasm_ref_as_global") 106 } 107 108 #[unsafe(no_mangle)] 109 pub extern "C" fn wasm_ref_as_global_const( 110 _ref: Option<&wasm_ref_t>, 111 ) -> Option<&crate::wasm_global_t> { 112 abort("wasm_ref_as_global_const") 113 } 114 115 #[unsafe(no_mangle)] 116 pub extern "C" fn wasm_ref_as_instance( 117 _ref: Option<&wasm_ref_t>, 118 ) -> Option<&crate::wasm_instance_t> { 119 abort("wasm_ref_as_instance") 120 } 121 122 #[unsafe(no_mangle)] 123 pub extern "C" fn wasm_ref_as_instance_const( 124 _ref: Option<&wasm_ref_t>, 125 ) -> Option<&crate::wasm_instance_t> { 126 abort("wasm_ref_as_instance_const") 127 } 128 129 #[unsafe(no_mangle)] 130 pub extern "C" fn wasm_ref_as_memory(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_memory_t> { 131 abort("wasm_ref_as_memory") 132 } 133 134 #[unsafe(no_mangle)] 135 pub extern "C" fn wasm_ref_as_memory_const( 136 _ref: Option<&wasm_ref_t>, 137 ) -> Option<&crate::wasm_memory_t> { 138 abort("wasm_ref_as_memory_const") 139 } 140 141 #[unsafe(no_mangle)] 142 pub extern "C" fn wasm_ref_as_module(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_module_t> { 143 abort("wasm_ref_as_module") 144 } 145 146 #[unsafe(no_mangle)] 147 pub extern "C" fn wasm_ref_as_module_const( 148 _ref: Option<&wasm_ref_t>, 149 ) -> Option<&crate::wasm_module_t> { 150 abort("wasm_ref_as_module_const") 151 } 152 153 #[unsafe(no_mangle)] 154 pub extern "C" fn wasm_ref_as_table(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_table_t> { 155 abort("wasm_ref_as_table") 156 } 157 158 #[unsafe(no_mangle)] 159 pub extern "C" fn wasm_ref_as_table_const( 160 _ref: Option<&wasm_ref_t>, 161 ) -> Option<&crate::wasm_table_t> { 162 abort("wasm_ref_as_table_const") 163 } 164 165 #[unsafe(no_mangle)] 166 pub extern "C" fn wasm_ref_as_trap(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> { 167 abort("wasm_ref_as_trap") 168 } 169 170 #[unsafe(no_mangle)] 171 pub extern "C" fn wasm_ref_as_trap_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> { 172 abort("wasm_ref_as_trap_const") 173 } 174 175 #[derive(Clone)] 176 #[repr(C)] 177 pub struct wasm_foreign_t {} 178 179 wasmtime_c_api_macros::declare_ref!(wasm_foreign_t); 180 181 #[unsafe(no_mangle)] 182 pub extern "C" fn wasm_foreign_new(_store: &crate::wasm_store_t) -> Box<wasm_foreign_t> { 183 abort("wasm_foreign_new") 184 } 185 186 /// C-API representation of `anyref`. 187 /// 188 /// This represented differently in the C API from the header to handle how 189 /// this is dispatched internally. Null anyref values are represented with a 190 /// `store_id` of zero, and otherwise the `rooted` field is valid. 191 /// 192 /// Note that this relies on the Wasmtime definition of `OwnedRooted` to have 193 /// a 64-bit store_id first. 194 macro_rules! ref_wrapper { 195 ($wasmtime:ident => $c:ident) => { 196 pub struct $c { 197 store_id: u64, 198 a: u32, 199 b: u32, 200 c: *const (), 201 } 202 203 impl $c { 204 pub unsafe fn as_wasmtime(&self) -> Option<OwnedRooted<$wasmtime>> { 205 let store_id = NonZeroU64::new(self.store_id)?; 206 Some(OwnedRooted::from_borrowed_raw_parts_for_c_api( 207 store_id, self.a, self.b, self.c, 208 )) 209 } 210 211 pub unsafe fn into_wasmtime(self) -> Option<OwnedRooted<$wasmtime>> { 212 ManuallyDrop::new(self).to_owned() 213 } 214 215 unsafe fn to_owned(&self) -> Option<OwnedRooted<$wasmtime>> { 216 let store_id = NonZeroU64::new(self.store_id)?; 217 Some(OwnedRooted::from_owned_raw_parts_for_c_api( 218 store_id, self.a, self.b, self.c, 219 )) 220 } 221 } 222 223 impl Drop for $c { 224 fn drop(&mut self) { 225 unsafe { 226 let _ = self.to_owned(); 227 } 228 } 229 } 230 231 impl From<Option<OwnedRooted<$wasmtime>>> for $c { 232 fn from(rooted: Option<OwnedRooted<$wasmtime>>) -> $c { 233 let mut ret = $c { 234 store_id: 0, 235 a: 0, 236 b: 0, 237 c: core::ptr::null(), 238 }; 239 if let Some(rooted) = rooted { 240 let (store_id, a, b, c) = rooted.into_parts_for_c_api(); 241 ret.store_id = store_id.get(); 242 ret.a = a; 243 ret.b = b; 244 ret.c = c; 245 } 246 ret 247 } 248 } 249 250 impl From<OwnedRooted<$wasmtime>> for $c { 251 fn from(rooted: OwnedRooted<$wasmtime>) -> $c { 252 Self::from(Some(rooted)) 253 } 254 } 255 256 // SAFETY: The `*const ()` comes from (and is converted back 257 // into) an `Arc<()>`, and is only accessed as such, so this 258 // type is both Send and Sync. These constraints are necessary 259 // in the async machinery in this crate. 260 unsafe impl Send for $c {} 261 unsafe impl Sync for $c {} 262 }; 263 } 264 265 ref_wrapper!(AnyRef => wasmtime_anyref_t); 266 ref_wrapper!(ExternRef => wasmtime_externref_t); 267 ref_wrapper!(EqRef => wasmtime_eqref_t); 268 ref_wrapper!(ExnRef => wasmtime_exnref_t); 269 270 #[unsafe(no_mangle)] 271 pub unsafe extern "C" fn wasmtime_anyref_clone( 272 anyref: Option<&wasmtime_anyref_t>, 273 out: &mut MaybeUninit<wasmtime_anyref_t>, 274 ) { 275 let anyref = anyref.and_then(|a| a.as_wasmtime()); 276 crate::initialize(out, anyref.into()); 277 } 278 279 #[unsafe(no_mangle)] 280 pub unsafe extern "C" fn wasmtime_anyref_unroot(val: Option<&mut ManuallyDrop<wasmtime_anyref_t>>) { 281 if let Some(val) = val { 282 unsafe { 283 ManuallyDrop::drop(val); 284 } 285 } 286 } 287 288 #[unsafe(no_mangle)] 289 pub unsafe extern "C" fn wasmtime_anyref_to_raw( 290 cx: WasmtimeStoreContextMut<'_>, 291 val: Option<&wasmtime_anyref_t>, 292 ) -> u32 { 293 val.and_then(|v| v.as_wasmtime()) 294 .and_then(|e| e.to_raw(cx).ok()) 295 .unwrap_or_default() 296 } 297 298 #[unsafe(no_mangle)] 299 pub unsafe extern "C" fn wasmtime_anyref_from_raw( 300 cx: WasmtimeStoreContextMut<'_>, 301 raw: u32, 302 val: &mut MaybeUninit<wasmtime_anyref_t>, 303 ) { 304 let mut scope = RootScope::new(cx); 305 let anyref = 306 AnyRef::from_raw(&mut scope, raw).map(|a| a.to_owned_rooted(&mut scope).expect("in scope")); 307 crate::initialize(val, anyref.into()); 308 } 309 310 #[unsafe(no_mangle)] 311 pub extern "C" fn wasmtime_anyref_from_i31( 312 cx: WasmtimeStoreContextMut<'_>, 313 val: u32, 314 out: &mut MaybeUninit<wasmtime_anyref_t>, 315 ) { 316 let mut scope = RootScope::new(cx); 317 let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val)); 318 let anyref = anyref.to_owned_rooted(&mut scope).expect("in scope"); 319 crate::initialize(out, Some(anyref).into()) 320 } 321 322 #[unsafe(no_mangle)] 323 pub unsafe extern "C" fn wasmtime_anyref_is_i31( 324 cx: WasmtimeStoreContextMut<'_>, 325 anyref: Option<&wasmtime_anyref_t>, 326 ) -> bool { 327 match anyref.and_then(|a| a.as_wasmtime()) { 328 Some(anyref) => anyref.is_i31(&cx).expect("OwnedRooted always in scope"), 329 None => false, 330 } 331 } 332 333 #[unsafe(no_mangle)] 334 pub unsafe extern "C" fn wasmtime_anyref_i31_get_u( 335 cx: WasmtimeStoreContextMut<'_>, 336 anyref: Option<&wasmtime_anyref_t>, 337 dst: &mut MaybeUninit<u32>, 338 ) -> bool { 339 match anyref.and_then(|a| a.as_wasmtime()) { 340 Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => { 341 let val = anyref 342 .unwrap_i31(&cx) 343 .expect("OwnedRooted always in scope") 344 .get_u32(); 345 crate::initialize(dst, val); 346 true 347 } 348 _ => false, 349 } 350 } 351 352 #[unsafe(no_mangle)] 353 pub unsafe extern "C" fn wasmtime_anyref_i31_get_s( 354 cx: WasmtimeStoreContextMut<'_>, 355 anyref: Option<&wasmtime_anyref_t>, 356 dst: &mut MaybeUninit<i32>, 357 ) -> bool { 358 match anyref.and_then(|a| a.as_wasmtime()) { 359 Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => { 360 let val = anyref 361 .unwrap_i31(&cx) 362 .expect("OwnedRooted always in scope") 363 .get_i32(); 364 crate::initialize(dst, val); 365 true 366 } 367 _ => false, 368 } 369 } 370 371 #[unsafe(no_mangle)] 372 pub extern "C" fn wasmtime_externref_new( 373 cx: WasmtimeStoreContextMut<'_>, 374 data: *mut c_void, 375 finalizer: Option<extern "C" fn(*mut c_void)>, 376 out: &mut MaybeUninit<wasmtime_externref_t>, 377 ) -> bool { 378 let mut scope = RootScope::new(cx); 379 let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) { 380 Ok(e) => e, 381 Err(_) => return false, 382 }; 383 let e = e.to_owned_rooted(&mut scope).expect("in scope"); 384 crate::initialize(out, Some(e).into()); 385 true 386 } 387 388 #[unsafe(no_mangle)] 389 pub unsafe extern "C" fn wasmtime_externref_data( 390 cx: WasmtimeStoreContextMut<'_>, 391 externref: Option<&wasmtime_externref_t>, 392 ) -> *mut c_void { 393 externref 394 .and_then(|e| e.as_wasmtime()) 395 .and_then(|e| { 396 let data = e.data(cx).ok()??; 397 Some(data.downcast_ref::<crate::ForeignData>().unwrap().data) 398 }) 399 .unwrap_or(ptr::null_mut()) 400 } 401 402 #[unsafe(no_mangle)] 403 pub unsafe extern "C" fn wasmtime_externref_clone( 404 externref: Option<&wasmtime_externref_t>, 405 out: &mut MaybeUninit<wasmtime_externref_t>, 406 ) { 407 let externref = externref.and_then(|e| e.as_wasmtime()); 408 crate::initialize(out, externref.into()); 409 } 410 411 #[unsafe(no_mangle)] 412 pub unsafe extern "C" fn wasmtime_externref_unroot( 413 val: Option<&mut ManuallyDrop<wasmtime_externref_t>>, 414 ) { 415 if let Some(val) = val { 416 unsafe { 417 ManuallyDrop::drop(val); 418 } 419 } 420 } 421 422 #[unsafe(no_mangle)] 423 pub unsafe extern "C" fn wasmtime_externref_to_raw( 424 cx: WasmtimeStoreContextMut<'_>, 425 val: Option<&wasmtime_externref_t>, 426 ) -> u32 { 427 val.and_then(|e| e.as_wasmtime()) 428 .and_then(|e| e.to_raw(cx).ok()) 429 .unwrap_or_default() 430 } 431 432 #[unsafe(no_mangle)] 433 pub unsafe extern "C" fn wasmtime_externref_from_raw( 434 cx: WasmtimeStoreContextMut<'_>, 435 raw: u32, 436 val: &mut MaybeUninit<wasmtime_externref_t>, 437 ) { 438 let mut scope = RootScope::new(cx); 439 let rooted = ExternRef::from_raw(&mut scope, raw) 440 .map(|e| e.to_owned_rooted(&mut scope).expect("in scope")); 441 crate::initialize(val, rooted.into()); 442 } 443 444 #[unsafe(no_mangle)] 445 pub unsafe extern "C" fn wasmtime_exnref_clone( 446 exnref: Option<&wasmtime_exnref_t>, 447 out: &mut MaybeUninit<wasmtime_exnref_t>, 448 ) { 449 let exnref = exnref.and_then(|e| e.as_wasmtime()); 450 crate::initialize(out, exnref.into()); 451 } 452 453 #[unsafe(no_mangle)] 454 pub unsafe extern "C" fn wasmtime_exnref_unroot(val: Option<&mut ManuallyDrop<wasmtime_exnref_t>>) { 455 if let Some(val) = val { 456 unsafe { 457 ManuallyDrop::drop(val); 458 } 459 } 460 } 461 462 #[unsafe(no_mangle)] 463 pub unsafe extern "C" fn wasmtime_eqref_clone( 464 eqref: Option<&wasmtime_eqref_t>, 465 out: &mut MaybeUninit<wasmtime_eqref_t>, 466 ) { 467 let eqref = eqref.and_then(|e| e.as_wasmtime()); 468 crate::initialize(out, eqref.into()); 469 } 470 471 #[unsafe(no_mangle)] 472 pub unsafe extern "C" fn wasmtime_eqref_unroot(val: Option<&mut ManuallyDrop<wasmtime_eqref_t>>) { 473 if let Some(val) = val { 474 unsafe { 475 ManuallyDrop::drop(val); 476 } 477 } 478 } 479 480 #[unsafe(no_mangle)] 481 pub unsafe extern "C" fn wasmtime_eqref_to_anyref( 482 eqref: Option<&wasmtime_eqref_t>, 483 out: &mut MaybeUninit<wasmtime_anyref_t>, 484 ) { 485 let anyref = eqref.and_then(|e| e.as_wasmtime()).map(|e| e.to_anyref()); 486 crate::initialize(out, anyref.into()); 487 } 488 489 #[unsafe(no_mangle)] 490 pub extern "C" fn wasmtime_eqref_from_i31( 491 cx: WasmtimeStoreContextMut<'_>, 492 val: u32, 493 out: &mut MaybeUninit<wasmtime_eqref_t>, 494 ) { 495 let mut scope = RootScope::new(cx); 496 let eqref = EqRef::from_i31(&mut scope, I31::wrapping_u32(val)); 497 let eqref = eqref.to_owned_rooted(&mut scope).expect("in scope"); 498 crate::initialize(out, Some(eqref).into()) 499 } 500 501 #[unsafe(no_mangle)] 502 pub unsafe extern "C" fn wasmtime_eqref_is_i31( 503 cx: WasmtimeStoreContextMut<'_>, 504 eqref: Option<&wasmtime_eqref_t>, 505 ) -> bool { 506 match eqref.and_then(|e| e.as_wasmtime()) { 507 Some(eqref) => eqref.is_i31(&cx).expect("OwnedRooted always in scope"), 508 None => false, 509 } 510 } 511 512 #[unsafe(no_mangle)] 513 pub unsafe extern "C" fn wasmtime_eqref_i31_get_u( 514 cx: WasmtimeStoreContextMut<'_>, 515 eqref: Option<&wasmtime_eqref_t>, 516 dst: &mut MaybeUninit<u32>, 517 ) -> bool { 518 let mut scope = RootScope::new(cx); 519 if let Some(eqref) = eqref.and_then(|e| e.as_wasmtime()) { 520 if let Some(val) = eqref.as_i31(&mut scope).expect("in scope") { 521 crate::initialize(dst, val.get_u32()); 522 return true; 523 } 524 } 525 false 526 } 527 528 #[unsafe(no_mangle)] 529 pub unsafe extern "C" fn wasmtime_eqref_i31_get_s( 530 cx: WasmtimeStoreContextMut<'_>, 531 eqref: Option<&wasmtime_eqref_t>, 532 dst: &mut MaybeUninit<i32>, 533 ) -> bool { 534 let mut scope = RootScope::new(cx); 535 if let Some(eqref) = eqref.and_then(|e| e.as_wasmtime()) { 536 if let Some(val) = eqref.as_i31(&mut scope).expect("in scope") { 537 crate::initialize(dst, val.get_i32()); 538 return true; 539 } 540 } 541 false 542 } 543