1 use crate::{abort, WasmtimeStoreContextMut}; 2 use std::{mem::MaybeUninit, num::NonZeroU64, os::raw::c_void, ptr}; 3 use wasmtime::{AnyRef, ExternRef, ManuallyRooted, Ref, RootScope, Val, I31}; 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 `ManuallyRooted` 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 } 200 201 impl $c { 202 pub unsafe fn as_wasmtime(&self) -> Option<ManuallyRooted<$wasmtime>> { 203 let store_id = NonZeroU64::new(self.store_id)?; 204 Some(ManuallyRooted::from_raw_parts_for_c_api( 205 store_id, self.a, self.b, 206 )) 207 } 208 } 209 210 impl From<Option<ManuallyRooted<$wasmtime>>> for $c { 211 fn from(rooted: Option<ManuallyRooted<$wasmtime>>) -> $c { 212 let mut ret = $c { 213 store_id: 0, 214 a: 0, 215 b: 0, 216 }; 217 if let Some(rooted) = rooted { 218 let (store_id, a, b) = rooted.into_parts_for_c_api(); 219 ret.store_id = store_id.get(); 220 ret.a = a; 221 ret.b = b; 222 } 223 ret 224 } 225 } 226 }; 227 } 228 229 ref_wrapper!(AnyRef => wasmtime_anyref_t); 230 ref_wrapper!(ExternRef => wasmtime_externref_t); 231 232 #[unsafe(no_mangle)] 233 pub unsafe extern "C" fn wasmtime_anyref_clone( 234 cx: WasmtimeStoreContextMut<'_>, 235 anyref: Option<&wasmtime_anyref_t>, 236 out: &mut MaybeUninit<wasmtime_anyref_t>, 237 ) { 238 let anyref = anyref.and_then(|a| a.as_wasmtime()).map(|a| a.clone(cx)); 239 crate::initialize(out, anyref.into()); 240 } 241 242 #[unsafe(no_mangle)] 243 pub unsafe extern "C" fn wasmtime_anyref_unroot( 244 cx: WasmtimeStoreContextMut<'_>, 245 val: Option<&mut MaybeUninit<wasmtime_anyref_t>>, 246 ) { 247 if let Some(val) = val.and_then(|v| v.assume_init_read().as_wasmtime()) { 248 val.unroot(cx); 249 } 250 } 251 252 #[unsafe(no_mangle)] 253 pub unsafe extern "C" fn wasmtime_anyref_to_raw( 254 cx: WasmtimeStoreContextMut<'_>, 255 val: Option<&wasmtime_anyref_t>, 256 ) -> u32 { 257 val.and_then(|v| v.as_wasmtime()) 258 .and_then(|e| e.to_raw(cx).ok()) 259 .unwrap_or_default() 260 } 261 262 #[unsafe(no_mangle)] 263 pub unsafe extern "C" fn wasmtime_anyref_from_raw( 264 cx: WasmtimeStoreContextMut<'_>, 265 raw: u32, 266 val: &mut MaybeUninit<wasmtime_anyref_t>, 267 ) { 268 let mut scope = RootScope::new(cx); 269 let anyref = AnyRef::from_raw(&mut scope, raw) 270 .map(|a| a.to_manually_rooted(&mut scope).expect("in scope")); 271 crate::initialize(val, anyref.into()); 272 } 273 274 #[unsafe(no_mangle)] 275 pub extern "C" fn wasmtime_anyref_from_i31( 276 cx: WasmtimeStoreContextMut<'_>, 277 val: u32, 278 out: &mut MaybeUninit<wasmtime_anyref_t>, 279 ) { 280 let mut scope = RootScope::new(cx); 281 let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val)); 282 let anyref = anyref.to_manually_rooted(&mut scope).expect("in scope"); 283 crate::initialize(out, Some(anyref).into()) 284 } 285 286 #[unsafe(no_mangle)] 287 pub unsafe extern "C" fn wasmtime_anyref_i31_get_u( 288 cx: WasmtimeStoreContextMut<'_>, 289 anyref: Option<&wasmtime_anyref_t>, 290 dst: &mut MaybeUninit<u32>, 291 ) -> bool { 292 match anyref.and_then(|a| a.as_wasmtime()) { 293 Some(anyref) if anyref.is_i31(&cx).expect("ManuallyRooted always in scope") => { 294 let val = anyref 295 .unwrap_i31(&cx) 296 .expect("ManuallyRooted always in scope") 297 .get_u32(); 298 crate::initialize(dst, val); 299 true 300 } 301 _ => false, 302 } 303 } 304 305 #[unsafe(no_mangle)] 306 pub unsafe extern "C" fn wasmtime_anyref_i31_get_s( 307 cx: WasmtimeStoreContextMut<'_>, 308 anyref: Option<&wasmtime_anyref_t>, 309 dst: &mut MaybeUninit<i32>, 310 ) -> bool { 311 match anyref.and_then(|a| a.as_wasmtime()) { 312 Some(anyref) if anyref.is_i31(&cx).expect("ManuallyRooted always in scope") => { 313 let val = anyref 314 .unwrap_i31(&cx) 315 .expect("ManuallyRooted always in scope") 316 .get_i32(); 317 crate::initialize(dst, val); 318 true 319 } 320 _ => false, 321 } 322 } 323 324 #[unsafe(no_mangle)] 325 pub extern "C" fn wasmtime_externref_new( 326 cx: WasmtimeStoreContextMut<'_>, 327 data: *mut c_void, 328 finalizer: Option<extern "C" fn(*mut c_void)>, 329 out: &mut MaybeUninit<wasmtime_externref_t>, 330 ) -> bool { 331 let mut scope = RootScope::new(cx); 332 let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) { 333 Ok(e) => e, 334 Err(_) => return false, 335 }; 336 let e = e.to_manually_rooted(&mut scope).expect("in scope"); 337 crate::initialize(out, Some(e).into()); 338 true 339 } 340 341 #[unsafe(no_mangle)] 342 pub unsafe extern "C" fn wasmtime_externref_data( 343 cx: WasmtimeStoreContextMut<'_>, 344 externref: Option<&wasmtime_externref_t>, 345 ) -> *mut c_void { 346 externref 347 .and_then(|e| e.as_wasmtime()) 348 .and_then(|e| { 349 let data = e.data(cx).ok()??; 350 Some(data.downcast_ref::<crate::ForeignData>().unwrap().data) 351 }) 352 .unwrap_or(ptr::null_mut()) 353 } 354 355 #[unsafe(no_mangle)] 356 pub unsafe extern "C" fn wasmtime_externref_clone( 357 cx: WasmtimeStoreContextMut<'_>, 358 externref: Option<&wasmtime_externref_t>, 359 out: &mut MaybeUninit<wasmtime_externref_t>, 360 ) { 361 let externref = externref.and_then(|e| e.as_wasmtime()).map(|e| e.clone(cx)); 362 crate::initialize(out, externref.into()); 363 } 364 365 #[unsafe(no_mangle)] 366 pub unsafe extern "C" fn wasmtime_externref_unroot( 367 cx: WasmtimeStoreContextMut<'_>, 368 val: Option<&mut MaybeUninit<wasmtime_externref_t>>, 369 ) { 370 if let Some(val) = val.and_then(|v| v.assume_init_read().as_wasmtime()) { 371 val.unroot(cx); 372 } 373 } 374 375 #[unsafe(no_mangle)] 376 pub unsafe extern "C" fn wasmtime_externref_to_raw( 377 cx: WasmtimeStoreContextMut<'_>, 378 val: Option<&wasmtime_externref_t>, 379 ) -> u32 { 380 val.and_then(|e| e.as_wasmtime()) 381 .and_then(|e| e.to_raw(cx).ok()) 382 .unwrap_or_default() 383 } 384 385 #[unsafe(no_mangle)] 386 pub unsafe extern "C" fn wasmtime_externref_from_raw( 387 cx: WasmtimeStoreContextMut<'_>, 388 raw: u32, 389 val: &mut MaybeUninit<wasmtime_externref_t>, 390 ) { 391 let mut scope = RootScope::new(cx); 392 let rooted = ExternRef::from_raw(&mut scope, raw) 393 .map(|e| e.to_manually_rooted(&mut scope).expect("in scope")); 394 crate::initialize(val, rooted.into()); 395 } 396