1 //! This file declares `VMContext` and several related structs which contain
2 //! fields that compiled wasm code accesses directly.
3 
4 mod vm_host_func_context;
5 
6 use crate::runtime::vm::{GcStore, VMGcRef};
7 use sptr::Strict;
8 use std::cell::UnsafeCell;
9 use std::ffi::c_void;
10 use std::marker;
11 use std::mem;
12 use std::ptr::{self, NonNull};
13 use std::sync::atomic::{AtomicUsize, Ordering};
14 use std::u32;
15 pub use vm_host_func_context::{VMArrayCallHostFuncContext, VMNativeCallHostFuncContext};
16 use wasmtime_environ::{
17     BuiltinFunctionIndex, DefinedMemoryIndex, Unsigned, VMSharedTypeIndex, WasmHeapTopType,
18     WasmValType, VMCONTEXT_MAGIC,
19 };
20 
21 /// A function pointer that exposes the array calling convention.
22 ///
23 /// Regardless of the underlying Wasm function type, all functions using the
24 /// array calling convention have the same Rust signature.
25 ///
26 /// Arguments:
27 ///
28 /// * Callee `vmctx` for the function itself.
29 ///
30 /// * Caller's `vmctx` (so that host functions can access the linear memory of
31 ///   their Wasm callers).
32 ///
33 /// * A pointer to a buffer of `ValRaw`s where both arguments are passed into
34 ///   this function, and where results are returned from this function.
35 ///
36 /// * The capacity of the `ValRaw` buffer. Must always be at least
37 ///   `max(len(wasm_params), len(wasm_results))`.
38 pub type VMArrayCallFunction =
39     unsafe extern "C" fn(*mut VMOpaqueContext, *mut VMOpaqueContext, *mut ValRaw, usize);
40 
41 /// A function pointer that exposes the native calling convention.
42 ///
43 /// Different Wasm function types end up mapping to different Rust function
44 /// types, so this isn't simply a type alias the way that `VMArrayCallFunction`
45 /// is.
46 ///
47 /// This is the default calling convention for the target (e.g. System-V or
48 /// fast-call) except multiple return values are handled by returning the first
49 /// return value in a register and everything else through a return-pointer.
50 #[repr(transparent)]
51 pub struct VMNativeCallFunction(VMFunctionBody);
52 
53 /// A function pointer that exposes the Wasm calling convention.
54 ///
55 /// In practice, different Wasm function types end up mapping to different Rust
56 /// function types, so this isn't simply a type alias the way that
57 /// `VMArrayCallFunction` is. However, the exact details of the calling
58 /// convention are left to the Wasm compiler (e.g. Cranelift or Winch). Runtime
59 /// code never does anything with these function pointers except shuffle them
60 /// around and pass them back to Wasm.
61 #[repr(transparent)]
62 pub struct VMWasmCallFunction(VMFunctionBody);
63 
64 /// An imported function.
65 #[derive(Debug, Copy, Clone)]
66 #[repr(C)]
67 pub struct VMFunctionImport {
68     /// Function pointer to use when calling this imported function from Wasm.
69     pub wasm_call: NonNull<VMWasmCallFunction>,
70 
71     /// Function pointer to use when calling this imported function from native code.
72     pub native_call: NonNull<VMNativeCallFunction>,
73 
74     /// Function pointer to use when calling this imported function with the
75     /// "array" calling convention that `Func::new` et al use.
76     pub array_call: VMArrayCallFunction,
77 
78     /// The VM state associated with this function.
79     ///
80     /// For Wasm functions defined by core wasm instances this will be `*mut
81     /// VMContext`, but for lifted/lowered component model functions this will
82     /// be a `VMComponentContext`, and for a host function it will be a
83     /// `VMHostFuncContext`, etc.
84     pub vmctx: *mut VMOpaqueContext,
85 }
86 
87 // Declare that this type is send/sync, it's the responsibility of users of
88 // `VMFunctionImport` to uphold this guarantee.
89 unsafe impl Send for VMFunctionImport {}
90 unsafe impl Sync for VMFunctionImport {}
91 
92 #[cfg(test)]
93 mod test_vmfunction_import {
94     use super::VMFunctionImport;
95     use memoffset::offset_of;
96     use std::mem::size_of;
97     use wasmtime_environ::{Module, VMOffsets};
98 
99     #[test]
100     fn check_vmfunction_import_offsets() {
101         let module = Module::new();
102         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
103         assert_eq!(
104             size_of::<VMFunctionImport>(),
105             usize::from(offsets.size_of_vmfunction_import())
106         );
107         assert_eq!(
108             offset_of!(VMFunctionImport, wasm_call),
109             usize::from(offsets.vmfunction_import_wasm_call())
110         );
111         assert_eq!(
112             offset_of!(VMFunctionImport, native_call),
113             usize::from(offsets.vmfunction_import_native_call())
114         );
115         assert_eq!(
116             offset_of!(VMFunctionImport, array_call),
117             usize::from(offsets.vmfunction_import_array_call())
118         );
119         assert_eq!(
120             offset_of!(VMFunctionImport, vmctx),
121             usize::from(offsets.vmfunction_import_vmctx())
122         );
123     }
124 }
125 
126 /// A placeholder byte-sized type which is just used to provide some amount of type
127 /// safety when dealing with pointers to JIT-compiled function bodies. Note that it's
128 /// deliberately not Copy, as we shouldn't be carelessly copying function body bytes
129 /// around.
130 #[repr(C)]
131 pub struct VMFunctionBody(u8);
132 
133 #[cfg(test)]
134 mod test_vmfunction_body {
135     use super::VMFunctionBody;
136     use std::mem::size_of;
137 
138     #[test]
139     fn check_vmfunction_body_offsets() {
140         assert_eq!(size_of::<VMFunctionBody>(), 1);
141     }
142 }
143 
144 /// The fields compiled code needs to access to utilize a WebAssembly table
145 /// imported from another instance.
146 #[derive(Debug, Copy, Clone)]
147 #[repr(C)]
148 pub struct VMTableImport {
149     /// A pointer to the imported table description.
150     pub from: *mut VMTableDefinition,
151 
152     /// A pointer to the `VMContext` that owns the table description.
153     pub vmctx: *mut VMContext,
154 }
155 
156 // Declare that this type is send/sync, it's the responsibility of users of
157 // `VMTableImport` to uphold this guarantee.
158 unsafe impl Send for VMTableImport {}
159 unsafe impl Sync for VMTableImport {}
160 
161 #[cfg(test)]
162 mod test_vmtable_import {
163     use super::VMTableImport;
164     use memoffset::offset_of;
165     use std::mem::size_of;
166     use wasmtime_environ::{Module, VMOffsets};
167 
168     #[test]
169     fn check_vmtable_import_offsets() {
170         let module = Module::new();
171         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
172         assert_eq!(
173             size_of::<VMTableImport>(),
174             usize::from(offsets.size_of_vmtable_import())
175         );
176         assert_eq!(
177             offset_of!(VMTableImport, from),
178             usize::from(offsets.vmtable_import_from())
179         );
180         assert_eq!(
181             offset_of!(VMTableImport, vmctx),
182             usize::from(offsets.vmtable_import_vmctx())
183         );
184     }
185 }
186 
187 /// The fields compiled code needs to access to utilize a WebAssembly linear
188 /// memory imported from another instance.
189 #[derive(Debug, Copy, Clone)]
190 #[repr(C)]
191 pub struct VMMemoryImport {
192     /// A pointer to the imported memory description.
193     pub from: *mut VMMemoryDefinition,
194 
195     /// A pointer to the `VMContext` that owns the memory description.
196     pub vmctx: *mut VMContext,
197 
198     /// The index of the memory in the containing `vmctx`.
199     pub index: DefinedMemoryIndex,
200 }
201 
202 // Declare that this type is send/sync, it's the responsibility of users of
203 // `VMMemoryImport` to uphold this guarantee.
204 unsafe impl Send for VMMemoryImport {}
205 unsafe impl Sync for VMMemoryImport {}
206 
207 #[cfg(test)]
208 mod test_vmmemory_import {
209     use super::VMMemoryImport;
210     use memoffset::offset_of;
211     use std::mem::size_of;
212     use wasmtime_environ::{Module, VMOffsets};
213 
214     #[test]
215     fn check_vmmemory_import_offsets() {
216         let module = Module::new();
217         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
218         assert_eq!(
219             size_of::<VMMemoryImport>(),
220             usize::from(offsets.size_of_vmmemory_import())
221         );
222         assert_eq!(
223             offset_of!(VMMemoryImport, from),
224             usize::from(offsets.vmmemory_import_from())
225         );
226         assert_eq!(
227             offset_of!(VMMemoryImport, vmctx),
228             usize::from(offsets.vmmemory_import_vmctx())
229         );
230     }
231 }
232 
233 /// The fields compiled code needs to access to utilize a WebAssembly global
234 /// variable imported from another instance.
235 ///
236 /// Note that unlike with functions, tables, and memories, `VMGlobalImport`
237 /// doesn't include a `vmctx` pointer. Globals are never resized, and don't
238 /// require a `vmctx` pointer to access.
239 #[derive(Debug, Copy, Clone)]
240 #[repr(C)]
241 pub struct VMGlobalImport {
242     /// A pointer to the imported global variable description.
243     pub from: *mut VMGlobalDefinition,
244 }
245 
246 // Declare that this type is send/sync, it's the responsibility of users of
247 // `VMGlobalImport` to uphold this guarantee.
248 unsafe impl Send for VMGlobalImport {}
249 unsafe impl Sync for VMGlobalImport {}
250 
251 #[cfg(test)]
252 mod test_vmglobal_import {
253     use super::VMGlobalImport;
254     use memoffset::offset_of;
255     use std::mem::size_of;
256     use wasmtime_environ::{Module, VMOffsets};
257 
258     #[test]
259     fn check_vmglobal_import_offsets() {
260         let module = Module::new();
261         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
262         assert_eq!(
263             size_of::<VMGlobalImport>(),
264             usize::from(offsets.size_of_vmglobal_import())
265         );
266         assert_eq!(
267             offset_of!(VMGlobalImport, from),
268             usize::from(offsets.vmglobal_import_from())
269         );
270     }
271 }
272 
273 /// The fields compiled code needs to access to utilize a WebAssembly linear
274 /// memory defined within the instance, namely the start address and the
275 /// size in bytes.
276 #[derive(Debug)]
277 #[repr(C)]
278 pub struct VMMemoryDefinition {
279     /// The start address.
280     pub base: *mut u8,
281 
282     /// The current logical size of this linear memory in bytes.
283     ///
284     /// This is atomic because shared memories must be able to grow their length
285     /// atomically. For relaxed access, see
286     /// [`VMMemoryDefinition::current_length()`].
287     pub current_length: AtomicUsize,
288 }
289 
290 impl VMMemoryDefinition {
291     /// Return the current length of the [`VMMemoryDefinition`] by performing a
292     /// relaxed load; do not use this function for situations in which a precise
293     /// length is needed. Owned memories (i.e., non-shared) will always return a
294     /// precise result (since no concurrent modification is possible) but shared
295     /// memories may see an imprecise value--a `current_length` potentially
296     /// smaller than what some other thread observes. Since Wasm memory only
297     /// grows, this under-estimation may be acceptable in certain cases.
298     pub fn current_length(&self) -> usize {
299         self.current_length.load(Ordering::Relaxed)
300     }
301 
302     /// Return a copy of the [`VMMemoryDefinition`] using the relaxed value of
303     /// `current_length`; see [`VMMemoryDefinition::current_length()`].
304     pub unsafe fn load(ptr: *mut Self) -> Self {
305         let other = &*ptr;
306         VMMemoryDefinition {
307             base: other.base,
308             current_length: other.current_length().into(),
309         }
310     }
311 }
312 
313 #[cfg(test)]
314 mod test_vmmemory_definition {
315     use super::VMMemoryDefinition;
316     use memoffset::offset_of;
317     use std::mem::size_of;
318     use wasmtime_environ::{Module, PtrSize, VMOffsets};
319 
320     #[test]
321     fn check_vmmemory_definition_offsets() {
322         let module = Module::new();
323         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
324         assert_eq!(
325             size_of::<VMMemoryDefinition>(),
326             usize::from(offsets.ptr.size_of_vmmemory_definition())
327         );
328         assert_eq!(
329             offset_of!(VMMemoryDefinition, base),
330             usize::from(offsets.ptr.vmmemory_definition_base())
331         );
332         assert_eq!(
333             offset_of!(VMMemoryDefinition, current_length),
334             usize::from(offsets.ptr.vmmemory_definition_current_length())
335         );
336         /* TODO: Assert that the size of `current_length` matches.
337         assert_eq!(
338             size_of::<VMMemoryDefinition::current_length>(),
339             usize::from(offsets.size_of_vmmemory_definition_current_length())
340         );
341         */
342     }
343 }
344 
345 /// The fields compiled code needs to access to utilize a WebAssembly table
346 /// defined within the instance.
347 #[derive(Debug, Copy, Clone)]
348 #[repr(C)]
349 pub struct VMTableDefinition {
350     /// Pointer to the table data.
351     pub base: *mut u8,
352 
353     /// The current number of elements in the table.
354     pub current_elements: u32,
355 }
356 
357 #[cfg(test)]
358 mod test_vmtable_definition {
359     use super::VMTableDefinition;
360     use memoffset::offset_of;
361     use std::mem::size_of;
362     use wasmtime_environ::{Module, VMOffsets};
363 
364     #[test]
365     fn check_vmtable_definition_offsets() {
366         let module = Module::new();
367         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
368         assert_eq!(
369             size_of::<VMTableDefinition>(),
370             usize::from(offsets.size_of_vmtable_definition())
371         );
372         assert_eq!(
373             offset_of!(VMTableDefinition, base),
374             usize::from(offsets.vmtable_definition_base())
375         );
376         assert_eq!(
377             offset_of!(VMTableDefinition, current_elements),
378             usize::from(offsets.vmtable_definition_current_elements())
379         );
380     }
381 }
382 
383 /// The storage for a WebAssembly global defined within the instance.
384 ///
385 /// TODO: Pack the globals more densely, rather than using the same size
386 /// for every type.
387 #[derive(Debug)]
388 #[repr(C, align(16))]
389 pub struct VMGlobalDefinition {
390     storage: [u8; 16],
391     // If more elements are added here, remember to add offset_of tests below!
392 }
393 
394 #[cfg(test)]
395 mod test_vmglobal_definition {
396     use super::VMGlobalDefinition;
397     use std::mem::{align_of, size_of};
398     use wasmtime_environ::{Module, PtrSize, VMOffsets};
399 
400     #[test]
401     fn check_vmglobal_definition_alignment() {
402         assert!(align_of::<VMGlobalDefinition>() >= align_of::<i32>());
403         assert!(align_of::<VMGlobalDefinition>() >= align_of::<i64>());
404         assert!(align_of::<VMGlobalDefinition>() >= align_of::<f32>());
405         assert!(align_of::<VMGlobalDefinition>() >= align_of::<f64>());
406         assert!(align_of::<VMGlobalDefinition>() >= align_of::<[u8; 16]>());
407     }
408 
409     #[test]
410     fn check_vmglobal_definition_offsets() {
411         let module = Module::new();
412         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
413         assert_eq!(
414             size_of::<VMGlobalDefinition>(),
415             usize::from(offsets.ptr.size_of_vmglobal_definition())
416         );
417     }
418 
419     #[test]
420     fn check_vmglobal_begins_aligned() {
421         let module = Module::new();
422         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
423         assert_eq!(offsets.vmctx_globals_begin() % 16, 0);
424     }
425 
426     #[test]
427     #[cfg(feature = "gc")]
428     fn check_vmglobal_can_contain_gc_ref() {
429         assert!(size_of::<crate::runtime::vm::VMGcRef>() <= size_of::<VMGlobalDefinition>());
430     }
431 }
432 
433 impl VMGlobalDefinition {
434     /// Construct a `VMGlobalDefinition`.
435     pub fn new() -> Self {
436         Self { storage: [0; 16] }
437     }
438 
439     /// Create a `VMGlobalDefinition` from a `ValRaw`.
440     ///
441     /// # Unsafety
442     ///
443     /// This raw value's type must match the given `WasmValType`.
444     pub unsafe fn from_val_raw(wasm_ty: WasmValType, raw: ValRaw) -> Self {
445         let mut global = Self::new();
446         match wasm_ty {
447             WasmValType::I32 => *global.as_i32_mut() = raw.get_i32(),
448             WasmValType::I64 => *global.as_i64_mut() = raw.get_i64(),
449             WasmValType::F32 => *global.as_f32_bits_mut() = raw.get_f32(),
450             WasmValType::F64 => *global.as_f64_bits_mut() = raw.get_f64(),
451             WasmValType::V128 => *global.as_u128_mut() = raw.get_v128(),
452             WasmValType::Ref(r) => match r.heap_type.top() {
453                 WasmHeapTopType::Extern => {
454                     global.init_gc_ref(VMGcRef::from_raw_u32(raw.get_externref()))
455                 }
456                 WasmHeapTopType::Any => global.init_gc_ref(VMGcRef::from_raw_u32(raw.get_anyref())),
457                 WasmHeapTopType::Func => *global.as_func_ref_mut() = raw.get_funcref().cast(),
458             },
459         }
460         global
461     }
462 
463     /// Get this global's value as a `ValRaw`.
464     ///
465     /// # Unsafety
466     ///
467     /// This global's value's type must match the given `WasmValType`.
468     pub unsafe fn to_val_raw(&self, gc_store: &mut GcStore, wasm_ty: WasmValType) -> ValRaw {
469         match wasm_ty {
470             WasmValType::I32 => ValRaw::i32(*self.as_i32()),
471             WasmValType::I64 => ValRaw::i64(*self.as_i64()),
472             WasmValType::F32 => ValRaw::f32(*self.as_f32_bits()),
473             WasmValType::F64 => ValRaw::f64(*self.as_f64_bits()),
474             WasmValType::V128 => ValRaw::v128(*self.as_u128()),
475             WasmValType::Ref(r) => match r.heap_type.top() {
476                 WasmHeapTopType::Extern => ValRaw::externref(
477                     self.as_gc_ref()
478                         .map_or(0, |r| gc_store.clone_gc_ref(r).as_raw_u32()),
479                 ),
480                 WasmHeapTopType::Any => ValRaw::anyref(
481                     self.as_gc_ref()
482                         .map_or(0, |r| gc_store.clone_gc_ref(r).as_raw_u32()),
483                 ),
484                 WasmHeapTopType::Func => ValRaw::funcref(self.as_func_ref().cast()),
485             },
486         }
487     }
488 
489     /// Return a reference to the value as an i32.
490     pub unsafe fn as_i32(&self) -> &i32 {
491         &*(self.storage.as_ref().as_ptr().cast::<i32>())
492     }
493 
494     /// Return a mutable reference to the value as an i32.
495     pub unsafe fn as_i32_mut(&mut self) -> &mut i32 {
496         &mut *(self.storage.as_mut().as_mut_ptr().cast::<i32>())
497     }
498 
499     /// Return a reference to the value as a u32.
500     pub unsafe fn as_u32(&self) -> &u32 {
501         &*(self.storage.as_ref().as_ptr().cast::<u32>())
502     }
503 
504     /// Return a mutable reference to the value as an u32.
505     pub unsafe fn as_u32_mut(&mut self) -> &mut u32 {
506         &mut *(self.storage.as_mut().as_mut_ptr().cast::<u32>())
507     }
508 
509     /// Return a reference to the value as an i64.
510     pub unsafe fn as_i64(&self) -> &i64 {
511         &*(self.storage.as_ref().as_ptr().cast::<i64>())
512     }
513 
514     /// Return a mutable reference to the value as an i64.
515     pub unsafe fn as_i64_mut(&mut self) -> &mut i64 {
516         &mut *(self.storage.as_mut().as_mut_ptr().cast::<i64>())
517     }
518 
519     /// Return a reference to the value as an u64.
520     pub unsafe fn as_u64(&self) -> &u64 {
521         &*(self.storage.as_ref().as_ptr().cast::<u64>())
522     }
523 
524     /// Return a mutable reference to the value as an u64.
525     pub unsafe fn as_u64_mut(&mut self) -> &mut u64 {
526         &mut *(self.storage.as_mut().as_mut_ptr().cast::<u64>())
527     }
528 
529     /// Return a reference to the value as an f32.
530     pub unsafe fn as_f32(&self) -> &f32 {
531         &*(self.storage.as_ref().as_ptr().cast::<f32>())
532     }
533 
534     /// Return a mutable reference to the value as an f32.
535     pub unsafe fn as_f32_mut(&mut self) -> &mut f32 {
536         &mut *(self.storage.as_mut().as_mut_ptr().cast::<f32>())
537     }
538 
539     /// Return a reference to the value as f32 bits.
540     pub unsafe fn as_f32_bits(&self) -> &u32 {
541         &*(self.storage.as_ref().as_ptr().cast::<u32>())
542     }
543 
544     /// Return a mutable reference to the value as f32 bits.
545     pub unsafe fn as_f32_bits_mut(&mut self) -> &mut u32 {
546         &mut *(self.storage.as_mut().as_mut_ptr().cast::<u32>())
547     }
548 
549     /// Return a reference to the value as an f64.
550     pub unsafe fn as_f64(&self) -> &f64 {
551         &*(self.storage.as_ref().as_ptr().cast::<f64>())
552     }
553 
554     /// Return a mutable reference to the value as an f64.
555     pub unsafe fn as_f64_mut(&mut self) -> &mut f64 {
556         &mut *(self.storage.as_mut().as_mut_ptr().cast::<f64>())
557     }
558 
559     /// Return a reference to the value as f64 bits.
560     pub unsafe fn as_f64_bits(&self) -> &u64 {
561         &*(self.storage.as_ref().as_ptr().cast::<u64>())
562     }
563 
564     /// Return a mutable reference to the value as f64 bits.
565     pub unsafe fn as_f64_bits_mut(&mut self) -> &mut u64 {
566         &mut *(self.storage.as_mut().as_mut_ptr().cast::<u64>())
567     }
568 
569     /// Return a reference to the value as an u128.
570     pub unsafe fn as_u128(&self) -> &u128 {
571         &*(self.storage.as_ref().as_ptr().cast::<u128>())
572     }
573 
574     /// Return a mutable reference to the value as an u128.
575     pub unsafe fn as_u128_mut(&mut self) -> &mut u128 {
576         &mut *(self.storage.as_mut().as_mut_ptr().cast::<u128>())
577     }
578 
579     /// Return a reference to the value as u128 bits.
580     pub unsafe fn as_u128_bits(&self) -> &[u8; 16] {
581         &*(self.storage.as_ref().as_ptr().cast::<[u8; 16]>())
582     }
583 
584     /// Return a mutable reference to the value as u128 bits.
585     pub unsafe fn as_u128_bits_mut(&mut self) -> &mut [u8; 16] {
586         &mut *(self.storage.as_mut().as_mut_ptr().cast::<[u8; 16]>())
587     }
588 
589     /// Return a reference to the global value as a borrowed GC reference.
590     pub unsafe fn as_gc_ref(&self) -> Option<&VMGcRef> {
591         let raw_ptr = self.storage.as_ref().as_ptr().cast::<Option<VMGcRef>>();
592         let ret = (*raw_ptr).as_ref();
593         assert!(cfg!(feature = "gc") || ret.is_none());
594         ret
595     }
596 
597     /// Initialize a global to the given GC reference.
598     pub unsafe fn init_gc_ref(&mut self, gc_ref: Option<VMGcRef>) {
599         assert!(cfg!(feature = "gc") || gc_ref.is_none());
600         let raw_ptr = self.storage.as_mut().as_mut_ptr().cast::<Option<VMGcRef>>();
601         ptr::write(raw_ptr, gc_ref);
602     }
603 
604     /// Write a GC reference into this global value.
605     pub unsafe fn write_gc_ref(&mut self, gc_store: &mut GcStore, gc_ref: Option<&VMGcRef>) {
606         assert!(cfg!(feature = "gc") || gc_ref.is_none());
607 
608         let dest = &mut *(self.storage.as_mut().as_mut_ptr().cast::<Option<VMGcRef>>());
609         assert!(cfg!(feature = "gc") || dest.is_none());
610 
611         gc_store.write_gc_ref(dest, gc_ref)
612     }
613 
614     /// Return a reference to the value as a `VMFuncRef`.
615     pub unsafe fn as_func_ref(&self) -> *mut VMFuncRef {
616         *(self.storage.as_ref().as_ptr().cast::<*mut VMFuncRef>())
617     }
618 
619     /// Return a mutable reference to the value as a `VMFuncRef`.
620     pub unsafe fn as_func_ref_mut(&mut self) -> &mut *mut VMFuncRef {
621         &mut *(self.storage.as_mut().as_mut_ptr().cast::<*mut VMFuncRef>())
622     }
623 }
624 
625 #[cfg(test)]
626 mod test_vmshared_type_index {
627     use super::VMSharedTypeIndex;
628     use std::mem::size_of;
629     use wasmtime_environ::{Module, VMOffsets};
630 
631     #[test]
632     fn check_vmshared_type_index() {
633         let module = Module::new();
634         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
635         assert_eq!(
636             size_of::<VMSharedTypeIndex>(),
637             usize::from(offsets.size_of_vmshared_type_index())
638         );
639     }
640 }
641 
642 /// The VM caller-checked "funcref" record, for caller-side signature checking.
643 ///
644 /// It consists of function pointer(s), a type id to be checked by the
645 /// caller, and the vmctx closure associated with this function.
646 #[derive(Debug, Clone)]
647 #[repr(C)]
648 pub struct VMFuncRef {
649     /// Function pointer for this funcref if being called via the native calling
650     /// convention.
651     pub native_call: NonNull<VMNativeCallFunction>,
652 
653     /// Function pointer for this funcref if being called via the "array"
654     /// calling convention that `Func::new` et al use.
655     pub array_call: VMArrayCallFunction,
656 
657     /// Function pointer for this funcref if being called via the calling
658     /// convention we use when compiling Wasm.
659     ///
660     /// Most functions come with a function pointer that we can use when they
661     /// are called from Wasm. The notable exception is when we `Func::wrap` a
662     /// host function, and we don't have a Wasm compiler on hand to compile a
663     /// Wasm-to-native trampoline for the function. In this case, we leave
664     /// `wasm_call` empty until the function is passed as an import to Wasm (or
665     /// otherwise exposed to Wasm via tables/globals). At this point, we look up
666     /// a Wasm-to-native trampoline for the function in the the Wasm's compiled
667     /// module and use that fill in `VMFunctionImport::wasm_call`. **However**
668     /// there is no guarantee that the Wasm module has a trampoline for this
669     /// function's signature. The Wasm module only has trampolines for its
670     /// types, and if this function isn't of one of those types, then the Wasm
671     /// module will not have a trampoline for it. This is actually okay, because
672     /// it means that the Wasm cannot actually call this function. But it does
673     /// mean that this field needs to be an `Option` even though it is non-null
674     /// the vast vast vast majority of the time.
675     pub wasm_call: Option<NonNull<VMWasmCallFunction>>,
676 
677     /// Function signature's type id.
678     pub type_index: VMSharedTypeIndex,
679 
680     /// The VM state associated with this function.
681     ///
682     /// The actual definition of what this pointer points to depends on the
683     /// function being referenced: for core Wasm functions, this is a `*mut
684     /// VMContext`, for host functions it is a `*mut VMHostFuncContext`, and for
685     /// component functions it is a `*mut VMComponentContext`.
686     pub vmctx: *mut VMOpaqueContext,
687     // If more elements are added here, remember to add offset_of tests below!
688 }
689 
690 unsafe impl Send for VMFuncRef {}
691 unsafe impl Sync for VMFuncRef {}
692 
693 #[cfg(test)]
694 mod test_vm_func_ref {
695     use super::VMFuncRef;
696     use memoffset::offset_of;
697     use std::mem::size_of;
698     use wasmtime_environ::{Module, PtrSize, VMOffsets};
699 
700     #[test]
701     fn check_vm_func_ref_offsets() {
702         let module = Module::new();
703         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
704         assert_eq!(
705             size_of::<VMFuncRef>(),
706             usize::from(offsets.ptr.size_of_vm_func_ref())
707         );
708         assert_eq!(
709             offset_of!(VMFuncRef, native_call),
710             usize::from(offsets.ptr.vm_func_ref_native_call())
711         );
712         assert_eq!(
713             offset_of!(VMFuncRef, array_call),
714             usize::from(offsets.ptr.vm_func_ref_array_call())
715         );
716         assert_eq!(
717             offset_of!(VMFuncRef, wasm_call),
718             usize::from(offsets.ptr.vm_func_ref_wasm_call())
719         );
720         assert_eq!(
721             offset_of!(VMFuncRef, type_index),
722             usize::from(offsets.ptr.vm_func_ref_type_index())
723         );
724         assert_eq!(
725             offset_of!(VMFuncRef, vmctx),
726             usize::from(offsets.ptr.vm_func_ref_vmctx())
727         );
728     }
729 }
730 
731 macro_rules! define_builtin_array {
732     (
733         $(
734             $( #[$attr:meta] )*
735             $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
736         )*
737     ) => {
738         /// An array that stores addresses of builtin functions. We translate code
739         /// to use indirect calls. This way, we don't have to patch the code.
740         #[repr(C)]
741         pub struct VMBuiltinFunctionsArray {
742             $(
743                 $name: unsafe extern "C" fn(
744                     $(define_builtin_array!(@ty $param)),*
745                 ) $( -> define_builtin_array!(@ty $result))?,
746             )*
747         }
748 
749         impl VMBuiltinFunctionsArray {
750             #[allow(unused_doc_comments)]
751             pub const INIT: VMBuiltinFunctionsArray = VMBuiltinFunctionsArray {
752                 $(
753                     $name: crate::runtime::vm::libcalls::raw::$name,
754                 )*
755             };
756         }
757     };
758 
759     (@ty i32) => (u32);
760     (@ty i64) => (u64);
761     (@ty reference) => (*mut u8);
762     (@ty pointer) => (*mut u8);
763     (@ty vmctx) => (*mut VMContext);
764 }
765 
766 wasmtime_environ::foreach_builtin_function!(define_builtin_array);
767 
768 const _: () = {
769     assert!(
770         mem::size_of::<VMBuiltinFunctionsArray>()
771             == mem::size_of::<usize>()
772                 * (BuiltinFunctionIndex::builtin_functions_total_number() as usize)
773     )
774 };
775 
776 /// Structure used to control interrupting wasm code.
777 #[derive(Debug)]
778 #[repr(C)]
779 pub struct VMRuntimeLimits {
780     /// Current stack limit of the wasm module.
781     ///
782     /// For more information see `crates/cranelift/src/lib.rs`.
783     pub stack_limit: UnsafeCell<usize>,
784 
785     /// Indicator of how much fuel has been consumed and is remaining to
786     /// WebAssembly.
787     ///
788     /// This field is typically negative and increments towards positive. Upon
789     /// turning positive a wasm trap will be generated. This field is only
790     /// modified if wasm is configured to consume fuel.
791     pub fuel_consumed: UnsafeCell<i64>,
792 
793     /// Deadline epoch for interruption: if epoch-based interruption
794     /// is enabled and the global (per engine) epoch counter is
795     /// observed to reach or exceed this value, the guest code will
796     /// yield if running asynchronously.
797     pub epoch_deadline: UnsafeCell<u64>,
798 
799     /// The value of the frame pointer register when we last called from Wasm to
800     /// the host.
801     ///
802     /// Maintained by our Wasm-to-host trampoline, and cleared just before
803     /// calling into Wasm in `catch_traps`.
804     ///
805     /// This member is `0` when Wasm is actively running and has not called out
806     /// to the host.
807     ///
808     /// Used to find the start of a a contiguous sequence of Wasm frames when
809     /// walking the stack.
810     pub last_wasm_exit_fp: UnsafeCell<usize>,
811 
812     /// The last Wasm program counter before we called from Wasm to the host.
813     ///
814     /// Maintained by our Wasm-to-host trampoline, and cleared just before
815     /// calling into Wasm in `catch_traps`.
816     ///
817     /// This member is `0` when Wasm is actively running and has not called out
818     /// to the host.
819     ///
820     /// Used when walking a contiguous sequence of Wasm frames.
821     pub last_wasm_exit_pc: UnsafeCell<usize>,
822 
823     /// The last host stack pointer before we called into Wasm from the host.
824     ///
825     /// Maintained by our host-to-Wasm trampoline, and cleared just before
826     /// calling into Wasm in `catch_traps`.
827     ///
828     /// This member is `0` when Wasm is actively running and has not called out
829     /// to the host.
830     ///
831     /// When a host function is wrapped into a `wasmtime::Func`, and is then
832     /// called from the host, then this member has the sentinal value of `-1 as
833     /// usize`, meaning that this contiguous sequence of Wasm frames is the
834     /// empty sequence, and it is not safe to dereference the
835     /// `last_wasm_exit_fp`.
836     ///
837     /// Used to find the end of a contiguous sequence of Wasm frames when
838     /// walking the stack.
839     pub last_wasm_entry_sp: UnsafeCell<usize>,
840 }
841 
842 // The `VMRuntimeLimits` type is a pod-type with no destructor, and we don't
843 // access any fields from other threads, so add in these trait impls which are
844 // otherwise not available due to the `fuel_consumed` and `epoch_deadline`
845 // variables in `VMRuntimeLimits`.
846 unsafe impl Send for VMRuntimeLimits {}
847 unsafe impl Sync for VMRuntimeLimits {}
848 
849 impl Default for VMRuntimeLimits {
850     fn default() -> VMRuntimeLimits {
851         VMRuntimeLimits {
852             stack_limit: UnsafeCell::new(usize::max_value()),
853             fuel_consumed: UnsafeCell::new(0),
854             epoch_deadline: UnsafeCell::new(0),
855             last_wasm_exit_fp: UnsafeCell::new(0),
856             last_wasm_exit_pc: UnsafeCell::new(0),
857             last_wasm_entry_sp: UnsafeCell::new(0),
858         }
859     }
860 }
861 
862 #[cfg(test)]
863 mod test_vmruntime_limits {
864     use super::VMRuntimeLimits;
865     use memoffset::offset_of;
866     use std::mem::size_of;
867     use wasmtime_environ::{Module, PtrSize, VMOffsets};
868 
869     #[test]
870     fn vmctx_runtime_limits_offset() {
871         let module = Module::new();
872         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
873         assert_eq!(
874             offsets.vmctx_runtime_limits(),
875             u32::from(offsets.ptr.vmcontext_runtime_limits())
876         );
877     }
878 
879     #[test]
880     fn field_offsets() {
881         let module = Module::new();
882         let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
883         assert_eq!(
884             offset_of!(VMRuntimeLimits, stack_limit),
885             usize::from(offsets.ptr.vmruntime_limits_stack_limit())
886         );
887         assert_eq!(
888             offset_of!(VMRuntimeLimits, fuel_consumed),
889             usize::from(offsets.ptr.vmruntime_limits_fuel_consumed())
890         );
891         assert_eq!(
892             offset_of!(VMRuntimeLimits, epoch_deadline),
893             usize::from(offsets.ptr.vmruntime_limits_epoch_deadline())
894         );
895         assert_eq!(
896             offset_of!(VMRuntimeLimits, last_wasm_exit_fp),
897             usize::from(offsets.ptr.vmruntime_limits_last_wasm_exit_fp())
898         );
899         assert_eq!(
900             offset_of!(VMRuntimeLimits, last_wasm_exit_pc),
901             usize::from(offsets.ptr.vmruntime_limits_last_wasm_exit_pc())
902         );
903         assert_eq!(
904             offset_of!(VMRuntimeLimits, last_wasm_entry_sp),
905             usize::from(offsets.ptr.vmruntime_limits_last_wasm_entry_sp())
906         );
907     }
908 }
909 
910 /// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
911 /// This has information about globals, memories, tables, and other runtime
912 /// state associated with the current instance.
913 ///
914 /// The struct here is empty, as the sizes of these fields are dynamic, and
915 /// we can't describe them in Rust's type system. Sufficient memory is
916 /// allocated at runtime.
917 #[derive(Debug)]
918 #[repr(C, align(16))] // align 16 since globals are aligned to that and contained inside
919 pub struct VMContext {
920     /// There's some more discussion about this within `wasmtime/src/lib.rs` but
921     /// the idea is that we want to tell the compiler that this contains
922     /// pointers which transitively refers to itself, to suppress some
923     /// optimizations that might otherwise assume this doesn't exist.
924     ///
925     /// The self-referential pointer we care about is the `*mut Store` pointer
926     /// early on in this context, which if you follow through enough levels of
927     /// nesting, eventually can refer back to this `VMContext`
928     pub _marker: marker::PhantomPinned,
929 }
930 
931 impl VMContext {
932     /// Helper function to cast between context types using a debug assertion to
933     /// protect against some mistakes.
934     #[inline]
935     pub unsafe fn from_opaque(opaque: *mut VMOpaqueContext) -> *mut VMContext {
936         // Note that in general the offset of the "magic" field is stored in
937         // `VMOffsets::vmctx_magic`. Given though that this is a sanity check
938         // about converting this pointer to another type we ideally don't want
939         // to read the offset from potentially corrupt memory. Instead it would
940         // be better to catch errors here as soon as possible.
941         //
942         // To accomplish this the `VMContext` structure is laid out with the
943         // magic field at a statically known offset (here it's 0 for now). This
944         // static offset is asserted in `VMOffsets::from` and needs to be kept
945         // in sync with this line for this debug assertion to work.
946         //
947         // Also note that this magic is only ever invalid in the presence of
948         // bugs, meaning we don't actually read the magic and act differently
949         // at runtime depending what it is, so this is a debug assertion as
950         // opposed to a regular assertion.
951         debug_assert_eq!((*opaque).magic, VMCONTEXT_MAGIC);
952         opaque.cast()
953     }
954 }
955 
956 /// A "raw" and unsafe representation of a WebAssembly value.
957 ///
958 /// This is provided for use with the `Func::new_unchecked` and
959 /// `Func::call_unchecked` APIs. In general it's unlikely you should be using
960 /// this from Rust, rather using APIs like `Func::wrap` and `TypedFunc::call`.
961 ///
962 /// This is notably an "unsafe" way to work with `Val` and it's recommended to
963 /// instead use `Val` where possible. An important note about this union is that
964 /// fields are all stored in little-endian format, regardless of the endianness
965 /// of the host system.
966 #[allow(missing_docs)]
967 #[repr(C)]
968 #[derive(Copy, Clone)]
969 pub union ValRaw {
970     /// A WebAssembly `i32` value.
971     ///
972     /// Note that the payload here is a Rust `i32` but the WebAssembly `i32`
973     /// type does not assign an interpretation of the upper bit as either signed
974     /// or unsigned. The Rust type `i32` is simply chosen for convenience.
975     ///
976     /// This value is always stored in a little-endian format.
977     i32: i32,
978 
979     /// A WebAssembly `i64` value.
980     ///
981     /// Note that the payload here is a Rust `i64` but the WebAssembly `i64`
982     /// type does not assign an interpretation of the upper bit as either signed
983     /// or unsigned. The Rust type `i64` is simply chosen for convenience.
984     ///
985     /// This value is always stored in a little-endian format.
986     i64: i64,
987 
988     /// A WebAssembly `f32` value.
989     ///
990     /// Note that the payload here is a Rust `u32`. This is to allow passing any
991     /// representation of NaN into WebAssembly without risk of changing NaN
992     /// payload bits as its gets passed around the system. Otherwise though this
993     /// `u32` value is the return value of `f32::to_bits` in Rust.
994     ///
995     /// This value is always stored in a little-endian format.
996     f32: u32,
997 
998     /// A WebAssembly `f64` value.
999     ///
1000     /// Note that the payload here is a Rust `u64`. This is to allow passing any
1001     /// representation of NaN into WebAssembly without risk of changing NaN
1002     /// payload bits as its gets passed around the system. Otherwise though this
1003     /// `u64` value is the return value of `f64::to_bits` in Rust.
1004     ///
1005     /// This value is always stored in a little-endian format.
1006     f64: u64,
1007 
1008     /// A WebAssembly `v128` value.
1009     ///
1010     /// The payload here is a Rust `[u8; 16]` which has the same number of bits
1011     /// but note that `v128` in WebAssembly is often considered a vector type
1012     /// such as `i32x4` or `f64x2`. This means that the actual interpretation
1013     /// of the underlying bits is left up to the instructions which consume
1014     /// this value.
1015     ///
1016     /// This value is always stored in a little-endian format.
1017     v128: [u8; 16],
1018 
1019     /// A WebAssembly `funcref` value (or one of its subtypes).
1020     ///
1021     /// The payload here is a pointer which is runtime-defined. This is one of
1022     /// the main points of unsafety about the `ValRaw` type as the validity of
1023     /// the pointer here is not easily verified and must be preserved by
1024     /// carefully calling the correct functions throughout the runtime.
1025     ///
1026     /// This value is always stored in a little-endian format.
1027     funcref: *mut c_void,
1028 
1029     /// A WebAssembly `externref` value (or one of its subtypes).
1030     ///
1031     /// The payload here is a compressed pointer value which is
1032     /// runtime-defined. This is one of the main points of unsafety about the
1033     /// `ValRaw` type as the validity of the pointer here is not easily verified
1034     /// and must be preserved by carefully calling the correct functions
1035     /// throughout the runtime.
1036     ///
1037     /// This value is always stored in a little-endian format.
1038     externref: u32,
1039 
1040     /// A WebAssembly `anyref` value (or one of its subtypes).
1041     ///
1042     /// The payload here is a compressed pointer value which is
1043     /// runtime-defined. This is one of the main points of unsafety about the
1044     /// `ValRaw` type as the validity of the pointer here is not easily verified
1045     /// and must be preserved by carefully calling the correct functions
1046     /// throughout the runtime.
1047     ///
1048     /// This value is always stored in a little-endian format.
1049     anyref: u32,
1050 }
1051 
1052 // The `ValRaw` type is matched as `wasmtime_val_raw_t` in the C API so these
1053 // are some simple assertions about the shape of the type which are additionally
1054 // matched in C.
1055 const _: () = {
1056     assert!(std::mem::size_of::<ValRaw>() == 16);
1057     assert!(std::mem::align_of::<ValRaw>() == 8);
1058 };
1059 
1060 // This type is just a bag-of-bits so it's up to the caller to figure out how
1061 // to safely deal with threading concerns and safely access interior bits.
1062 unsafe impl Send for ValRaw {}
1063 unsafe impl Sync for ValRaw {}
1064 
1065 impl std::fmt::Debug for ValRaw {
1066     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1067         struct Hex<T>(T);
1068         impl<T: std::fmt::LowerHex> std::fmt::Debug for Hex<T> {
1069             fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1070                 let bytes = std::mem::size_of::<T>();
1071                 let hex_digits_per_byte = 2;
1072                 let hex_digits = bytes * hex_digits_per_byte;
1073                 write!(f, "0x{:0width$x}", self.0, width = hex_digits)
1074             }
1075         }
1076 
1077         unsafe {
1078             f.debug_struct("ValRaw")
1079                 .field("i32", &Hex(self.i32))
1080                 .field("i64", &Hex(self.i64))
1081                 .field("f32", &Hex(self.f32))
1082                 .field("f64", &Hex(self.f64))
1083                 .field("v128", &Hex(u128::from_le_bytes(self.v128)))
1084                 .field("funcref", &self.funcref)
1085                 .field("externref", &Hex(self.externref))
1086                 .field("anyref", &Hex(self.anyref))
1087                 .finish()
1088         }
1089     }
1090 }
1091 
1092 impl ValRaw {
1093     /// Create a null reference that is compatible with any of
1094     /// `{any,extern,func}ref`.
1095     pub fn null() -> ValRaw {
1096         unsafe {
1097             let raw = mem::MaybeUninit::<Self>::zeroed().assume_init();
1098             debug_assert_eq!(raw.get_anyref(), 0);
1099             debug_assert_eq!(raw.get_externref(), 0);
1100             debug_assert_eq!(raw.get_funcref(), ptr::null_mut());
1101             raw
1102         }
1103     }
1104 
1105     /// Creates a WebAssembly `i32` value
1106     #[inline]
1107     pub fn i32(i: i32) -> ValRaw {
1108         // Note that this is intentionally not setting the `i32` field, instead
1109         // setting the `i64` field with a zero-extended version of `i`. For more
1110         // information on this see the comments on `Lower for Result` in the
1111         // `wasmtime` crate. Otherwise though all `ValRaw` constructors are
1112         // otherwise constrained to guarantee that the initial 64-bits are
1113         // always initialized.
1114         ValRaw::u64(i.unsigned().into())
1115     }
1116 
1117     /// Creates a WebAssembly `i64` value
1118     #[inline]
1119     pub fn i64(i: i64) -> ValRaw {
1120         ValRaw { i64: i.to_le() }
1121     }
1122 
1123     /// Creates a WebAssembly `i32` value
1124     #[inline]
1125     pub fn u32(i: u32) -> ValRaw {
1126         // See comments in `ValRaw::i32` for why this is setting the upper
1127         // 32-bits as well.
1128         ValRaw::u64(i.into())
1129     }
1130 
1131     /// Creates a WebAssembly `i64` value
1132     #[inline]
1133     pub fn u64(i: u64) -> ValRaw {
1134         ValRaw::i64(i as i64)
1135     }
1136 
1137     /// Creates a WebAssembly `f32` value
1138     #[inline]
1139     pub fn f32(i: u32) -> ValRaw {
1140         // See comments in `ValRaw::i32` for why this is setting the upper
1141         // 32-bits as well.
1142         ValRaw::u64(i.into())
1143     }
1144 
1145     /// Creates a WebAssembly `f64` value
1146     #[inline]
1147     pub fn f64(i: u64) -> ValRaw {
1148         ValRaw { f64: i.to_le() }
1149     }
1150 
1151     /// Creates a WebAssembly `v128` value
1152     #[inline]
1153     pub fn v128(i: u128) -> ValRaw {
1154         ValRaw {
1155             v128: i.to_le_bytes(),
1156         }
1157     }
1158 
1159     /// Creates a WebAssembly `funcref` value
1160     #[inline]
1161     pub fn funcref(i: *mut c_void) -> ValRaw {
1162         ValRaw {
1163             funcref: Strict::map_addr(i, |i| i.to_le()),
1164         }
1165     }
1166 
1167     /// Creates a WebAssembly `externref` value
1168     #[inline]
1169     pub fn externref(e: u32) -> ValRaw {
1170         assert!(cfg!(feature = "gc") || e == 0);
1171         ValRaw {
1172             externref: e.to_le(),
1173         }
1174     }
1175 
1176     /// Creates a WebAssembly `anyref` value
1177     #[inline]
1178     pub fn anyref(r: u32) -> ValRaw {
1179         assert!(cfg!(feature = "gc") || r == 0);
1180         ValRaw { anyref: r.to_le() }
1181     }
1182 
1183     /// Gets the WebAssembly `i32` value
1184     #[inline]
1185     pub fn get_i32(&self) -> i32 {
1186         unsafe { i32::from_le(self.i32) }
1187     }
1188 
1189     /// Gets the WebAssembly `i64` value
1190     #[inline]
1191     pub fn get_i64(&self) -> i64 {
1192         unsafe { i64::from_le(self.i64) }
1193     }
1194 
1195     /// Gets the WebAssembly `i32` value
1196     #[inline]
1197     pub fn get_u32(&self) -> u32 {
1198         self.get_i32().unsigned()
1199     }
1200 
1201     /// Gets the WebAssembly `i64` value
1202     #[inline]
1203     pub fn get_u64(&self) -> u64 {
1204         self.get_i64().unsigned()
1205     }
1206 
1207     /// Gets the WebAssembly `f32` value
1208     #[inline]
1209     pub fn get_f32(&self) -> u32 {
1210         unsafe { u32::from_le(self.f32) }
1211     }
1212 
1213     /// Gets the WebAssembly `f64` value
1214     #[inline]
1215     pub fn get_f64(&self) -> u64 {
1216         unsafe { u64::from_le(self.f64) }
1217     }
1218 
1219     /// Gets the WebAssembly `v128` value
1220     #[inline]
1221     pub fn get_v128(&self) -> u128 {
1222         unsafe { u128::from_le_bytes(self.v128) }
1223     }
1224 
1225     /// Gets the WebAssembly `funcref` value
1226     #[inline]
1227     pub fn get_funcref(&self) -> *mut c_void {
1228         unsafe { Strict::map_addr(self.funcref, |i| usize::from_le(i)) }
1229     }
1230 
1231     /// Gets the WebAssembly `externref` value
1232     #[inline]
1233     pub fn get_externref(&self) -> u32 {
1234         let externref = u32::from_le(unsafe { self.externref });
1235         assert!(cfg!(feature = "gc") || externref == 0);
1236         externref
1237     }
1238 
1239     /// Gets the WebAssembly `anyref` value
1240     #[inline]
1241     pub fn get_anyref(&self) -> u32 {
1242         let anyref = u32::from_le(unsafe { self.anyref });
1243         assert!(cfg!(feature = "gc") || anyref == 0);
1244         anyref
1245     }
1246 }
1247 
1248 /// An "opaque" version of `VMContext` which must be explicitly casted to a
1249 /// target context.
1250 ///
1251 /// This context is used to represent that contexts specified in
1252 /// `VMFuncRef` can have any type and don't have an implicit
1253 /// structure. Neither wasmtime nor cranelift-generated code can rely on the
1254 /// structure of an opaque context in general and only the code which configured
1255 /// the context is able to rely on a particular structure. This is because the
1256 /// context pointer configured for `VMFuncRef` is guaranteed to be
1257 /// the first parameter passed.
1258 ///
1259 /// Note that Wasmtime currently has a layout where all contexts that are casted
1260 /// to an opaque context start with a 32-bit "magic" which can be used in debug
1261 /// mode to debug-assert that the casts here are correct and have at least a
1262 /// little protection against incorrect casts.
1263 pub struct VMOpaqueContext {
1264     pub(crate) magic: u32,
1265     _marker: marker::PhantomPinned,
1266 }
1267 
1268 impl VMOpaqueContext {
1269     /// Helper function to clearly indicate that casts are desired.
1270     #[inline]
1271     pub fn from_vmcontext(ptr: *mut VMContext) -> *mut VMOpaqueContext {
1272         ptr.cast()
1273     }
1274 
1275     /// Helper function to clearly indicate that casts are desired.
1276     #[inline]
1277     pub fn from_vm_array_call_host_func_context(
1278         ptr: *mut VMArrayCallHostFuncContext,
1279     ) -> *mut VMOpaqueContext {
1280         ptr.cast()
1281     }
1282 
1283     /// Helper function to clearly indicate that casts are desired.
1284     #[inline]
1285     pub fn from_vm_native_call_host_func_context(
1286         ptr: *mut VMNativeCallHostFuncContext,
1287     ) -> *mut VMOpaqueContext {
1288         ptr.cast()
1289     }
1290 }
1291