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, 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 // SAFETY: The `*const ()` comes from (and is converted back 251 // into) an `Arc<()>`, and is only accessed as such, so this 252 // type is both Send and Sync. These constraints are necessary 253 // in the async machinery in this crate. 254 unsafe impl Send for $c {} 255 unsafe impl Sync for $c {} 256 }; 257 } 258 259 ref_wrapper!(AnyRef => wasmtime_anyref_t); 260 ref_wrapper!(ExternRef => wasmtime_externref_t); 261 262 #[unsafe(no_mangle)] 263 pub unsafe extern "C" fn wasmtime_anyref_clone( 264 anyref: Option<&wasmtime_anyref_t>, 265 out: &mut MaybeUninit<wasmtime_anyref_t>, 266 ) { 267 let anyref = anyref.and_then(|a| a.as_wasmtime()); 268 crate::initialize(out, anyref.into()); 269 } 270 271 #[unsafe(no_mangle)] 272 pub unsafe extern "C" fn wasmtime_anyref_unroot(val: Option<&mut ManuallyDrop<wasmtime_anyref_t>>) { 273 if let Some(val) = val { 274 unsafe { 275 ManuallyDrop::drop(val); 276 } 277 } 278 } 279 280 #[unsafe(no_mangle)] 281 pub unsafe extern "C" fn wasmtime_anyref_to_raw( 282 cx: WasmtimeStoreContextMut<'_>, 283 val: Option<&wasmtime_anyref_t>, 284 ) -> u32 { 285 val.and_then(|v| v.as_wasmtime()) 286 .and_then(|e| e.to_raw(cx).ok()) 287 .unwrap_or_default() 288 } 289 290 #[unsafe(no_mangle)] 291 pub unsafe extern "C" fn wasmtime_anyref_from_raw( 292 cx: WasmtimeStoreContextMut<'_>, 293 raw: u32, 294 val: &mut MaybeUninit<wasmtime_anyref_t>, 295 ) { 296 let mut scope = RootScope::new(cx); 297 let anyref = 298 AnyRef::from_raw(&mut scope, raw).map(|a| a.to_owned_rooted(&mut scope).expect("in scope")); 299 crate::initialize(val, anyref.into()); 300 } 301 302 #[unsafe(no_mangle)] 303 pub extern "C" fn wasmtime_anyref_from_i31( 304 cx: WasmtimeStoreContextMut<'_>, 305 val: u32, 306 out: &mut MaybeUninit<wasmtime_anyref_t>, 307 ) { 308 let mut scope = RootScope::new(cx); 309 let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val)); 310 let anyref = anyref.to_owned_rooted(&mut scope).expect("in scope"); 311 crate::initialize(out, Some(anyref).into()) 312 } 313 314 #[unsafe(no_mangle)] 315 pub unsafe extern "C" fn wasmtime_anyref_i31_get_u( 316 cx: WasmtimeStoreContextMut<'_>, 317 anyref: Option<&wasmtime_anyref_t>, 318 dst: &mut MaybeUninit<u32>, 319 ) -> bool { 320 match anyref.and_then(|a| a.as_wasmtime()) { 321 Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => { 322 let val = anyref 323 .unwrap_i31(&cx) 324 .expect("OwnedRooted always in scope") 325 .get_u32(); 326 crate::initialize(dst, val); 327 true 328 } 329 _ => false, 330 } 331 } 332 333 #[unsafe(no_mangle)] 334 pub unsafe extern "C" fn wasmtime_anyref_i31_get_s( 335 cx: WasmtimeStoreContextMut<'_>, 336 anyref: Option<&wasmtime_anyref_t>, 337 dst: &mut MaybeUninit<i32>, 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_i32(); 345 crate::initialize(dst, val); 346 true 347 } 348 _ => false, 349 } 350 } 351 352 #[unsafe(no_mangle)] 353 pub extern "C" fn wasmtime_externref_new( 354 cx: WasmtimeStoreContextMut<'_>, 355 data: *mut c_void, 356 finalizer: Option<extern "C" fn(*mut c_void)>, 357 out: &mut MaybeUninit<wasmtime_externref_t>, 358 ) -> bool { 359 let mut scope = RootScope::new(cx); 360 let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) { 361 Ok(e) => e, 362 Err(_) => return false, 363 }; 364 let e = e.to_owned_rooted(&mut scope).expect("in scope"); 365 crate::initialize(out, Some(e).into()); 366 true 367 } 368 369 #[unsafe(no_mangle)] 370 pub unsafe extern "C" fn wasmtime_externref_data( 371 cx: WasmtimeStoreContextMut<'_>, 372 externref: Option<&wasmtime_externref_t>, 373 ) -> *mut c_void { 374 externref 375 .and_then(|e| e.as_wasmtime()) 376 .and_then(|e| { 377 let data = e.data(cx).ok()??; 378 Some(data.downcast_ref::<crate::ForeignData>().unwrap().data) 379 }) 380 .unwrap_or(ptr::null_mut()) 381 } 382 383 #[unsafe(no_mangle)] 384 pub unsafe extern "C" fn wasmtime_externref_clone( 385 externref: Option<&wasmtime_externref_t>, 386 out: &mut MaybeUninit<wasmtime_externref_t>, 387 ) { 388 let externref = externref.and_then(|e| e.as_wasmtime()); 389 crate::initialize(out, externref.into()); 390 } 391 392 #[unsafe(no_mangle)] 393 pub unsafe extern "C" fn wasmtime_externref_unroot( 394 val: Option<&mut ManuallyDrop<wasmtime_externref_t>>, 395 ) { 396 if let Some(val) = val { 397 unsafe { 398 ManuallyDrop::drop(val); 399 } 400 } 401 } 402 403 #[unsafe(no_mangle)] 404 pub unsafe extern "C" fn wasmtime_externref_to_raw( 405 cx: WasmtimeStoreContextMut<'_>, 406 val: Option<&wasmtime_externref_t>, 407 ) -> u32 { 408 val.and_then(|e| e.as_wasmtime()) 409 .and_then(|e| e.to_raw(cx).ok()) 410 .unwrap_or_default() 411 } 412 413 #[unsafe(no_mangle)] 414 pub unsafe extern "C" fn wasmtime_externref_from_raw( 415 cx: WasmtimeStoreContextMut<'_>, 416 raw: u32, 417 val: &mut MaybeUninit<wasmtime_externref_t>, 418 ) { 419 let mut scope = RootScope::new(cx); 420 let rooted = ExternRef::from_raw(&mut scope, raw) 421 .map(|e| e.to_owned_rooted(&mut scope).expect("in scope")); 422 crate::initialize(val, rooted.into()); 423 } 424