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