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 pub use self::vm_host_func_context::VMArrayCallHostFuncContext;
7 use crate::prelude::*;
8 use crate::runtime::vm::{InterpreterRef, VMGcRef, VmPtr, VmSafe, f32x4, f64x2, i8x16};
9 use crate::store::StoreOpaque;
10 use crate::vm::stack_switching::VMStackChain;
11 use core::cell::UnsafeCell;
12 use core::ffi::c_void;
13 use core::fmt;
14 use core::marker;
15 use core::mem::{self, MaybeUninit};
16 use core::ops::Range;
17 use core::ptr::{self, NonNull};
18 use core::sync::atomic::{AtomicUsize, Ordering};
19 use wasmtime_environ::{
20     BuiltinFunctionIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
21     DefinedTagIndex, VMCONTEXT_MAGIC, VMSharedTypeIndex, WasmHeapTopType, WasmValType,
22 };
23 
24 /// A function pointer that exposes the array calling convention.
25 ///
26 /// Regardless of the underlying Wasm function type, all functions using the
27 /// array calling convention have the same Rust signature.
28 ///
29 /// Arguments:
30 ///
31 /// * Callee `vmctx` for the function itself.
32 ///
33 /// * Caller's `vmctx` (so that host functions can access the linear memory of
34 ///   their Wasm callers).
35 ///
36 /// * A pointer to a buffer of `ValRaw`s where both arguments are passed into
37 ///   this function, and where results are returned from this function.
38 ///
39 /// * The capacity of the `ValRaw` buffer. Must always be at least
40 ///   `max(len(wasm_params), len(wasm_results))`.
41 ///
42 /// Return value:
43 ///
44 /// * `true` if this call succeeded.
45 /// * `false` if this call failed and a trap was recorded in TLS.
46 pub type VMArrayCallNative = unsafe extern "C" fn(
47     NonNull<VMOpaqueContext>,
48     NonNull<VMContext>,
49     NonNull<ValRaw>,
50     usize,
51 ) -> bool;
52 
53 /// An opaque function pointer which might be `VMArrayCallNative` or it might be
54 /// pulley bytecode. Requires external knowledge to determine what kind of
55 /// function pointer this is.
56 #[repr(transparent)]
57 pub struct VMArrayCallFunction(VMFunctionBody);
58 
59 /// A function pointer that exposes the Wasm calling convention.
60 ///
61 /// In practice, different Wasm function types end up mapping to different Rust
62 /// function types, so this isn't simply a type alias the way that
63 /// `VMArrayCallFunction` is. However, the exact details of the calling
64 /// convention are left to the Wasm compiler (e.g. Cranelift or Winch). Runtime
65 /// code never does anything with these function pointers except shuffle them
66 /// around and pass them back to Wasm.
67 #[repr(transparent)]
68 pub struct VMWasmCallFunction(VMFunctionBody);
69 
70 /// An imported function.
71 #[derive(Debug, Copy, Clone)]
72 #[repr(C)]
73 pub struct VMFunctionImport {
74     /// Function pointer to use when calling this imported function from Wasm.
75     pub wasm_call: VmPtr<VMWasmCallFunction>,
76 
77     /// Function pointer to use when calling this imported function with the
78     /// "array" calling convention that `Func::new` et al use.
79     pub array_call: VmPtr<VMArrayCallFunction>,
80 
81     /// The VM state associated with this function.
82     ///
83     /// For Wasm functions defined by core wasm instances this will be `*mut
84     /// VMContext`, but for lifted/lowered component model functions this will
85     /// be a `VMComponentContext`, and for a host function it will be a
86     /// `VMHostFuncContext`, etc.
87     pub vmctx: VmPtr<VMOpaqueContext>,
88 }
89 
90 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
91 unsafe impl VmSafe for VMFunctionImport {}
92 
93 #[cfg(test)]
94 mod test_vmfunction_import {
95     use super::VMFunctionImport;
96     use core::mem::offset_of;
97     use std::mem::size_of;
98     use wasmtime_environ::{HostPtr, Module, VMOffsets};
99 
100     #[test]
101     fn check_vmfunction_import_offsets() {
102         let module = Module::new();
103         let offsets = VMOffsets::new(HostPtr, &module);
104         assert_eq!(
105             size_of::<VMFunctionImport>(),
106             usize::from(offsets.size_of_vmfunction_import())
107         );
108         assert_eq!(
109             offset_of!(VMFunctionImport, wasm_call),
110             usize::from(offsets.vmfunction_import_wasm_call())
111         );
112         assert_eq!(
113             offset_of!(VMFunctionImport, array_call),
114             usize::from(offsets.vmfunction_import_array_call())
115         );
116         assert_eq!(
117             offset_of!(VMFunctionImport, vmctx),
118             usize::from(offsets.vmfunction_import_vmctx())
119         );
120     }
121 }
122 
123 /// A placeholder byte-sized type which is just used to provide some amount of type
124 /// safety when dealing with pointers to JIT-compiled function bodies. Note that it's
125 /// deliberately not Copy, as we shouldn't be carelessly copying function body bytes
126 /// around.
127 #[repr(C)]
128 pub struct VMFunctionBody(u8);
129 
130 // SAFETY: this structure is never read and is safe to pass to jit code.
131 unsafe impl VmSafe for VMFunctionBody {}
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: VmPtr<VMTableDefinition>,
151 
152     /// A pointer to the `VMContext` that owns the table description.
153     pub vmctx: VmPtr<VMContext>,
154 
155     /// The table index, within `vmctx`, this definition resides at.
156     pub index: DefinedTableIndex,
157 }
158 
159 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
160 unsafe impl VmSafe for VMTableImport {}
161 
162 #[cfg(test)]
163 mod test_vmtable {
164     use super::VMTableImport;
165     use core::mem::offset_of;
166     use std::mem::size_of;
167     use wasmtime_environ::component::{Component, VMComponentOffsets};
168     use wasmtime_environ::{HostPtr, Module, VMOffsets};
169 
170     #[test]
171     fn check_vmtable_offsets() {
172         let module = Module::new();
173         let offsets = VMOffsets::new(HostPtr, &module);
174         assert_eq!(
175             size_of::<VMTableImport>(),
176             usize::from(offsets.size_of_vmtable_import())
177         );
178         assert_eq!(
179             offset_of!(VMTableImport, from),
180             usize::from(offsets.vmtable_import_from())
181         );
182         assert_eq!(
183             offset_of!(VMTableImport, vmctx),
184             usize::from(offsets.vmtable_import_vmctx())
185         );
186         assert_eq!(
187             offset_of!(VMTableImport, index),
188             usize::from(offsets.vmtable_import_index())
189         );
190     }
191 
192     #[test]
193     fn ensure_sizes_match() {
194         // Because we use `VMTableImport` for recording tables used by components, we
195         // want to make sure that the size calculations between `VMOffsets` and
196         // `VMComponentOffsets` stay the same.
197         let module = Module::new();
198         let vm_offsets = VMOffsets::new(HostPtr, &module);
199         let component = Component::default();
200         let vm_component_offsets = VMComponentOffsets::new(HostPtr, &component);
201         assert_eq!(
202             vm_offsets.size_of_vmtable_import(),
203             vm_component_offsets.size_of_vmtable_import()
204         );
205     }
206 }
207 
208 /// The fields compiled code needs to access to utilize a WebAssembly linear
209 /// memory imported from another instance.
210 #[derive(Debug, Copy, Clone)]
211 #[repr(C)]
212 pub struct VMMemoryImport {
213     /// A pointer to the imported memory description.
214     pub from: VmPtr<VMMemoryDefinition>,
215 
216     /// A pointer to the `VMContext` that owns the memory description.
217     pub vmctx: VmPtr<VMContext>,
218 
219     /// The index of the memory in the containing `vmctx`.
220     pub index: DefinedMemoryIndex,
221 }
222 
223 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
224 unsafe impl VmSafe for VMMemoryImport {}
225 
226 #[cfg(test)]
227 mod test_vmmemory_import {
228     use super::VMMemoryImport;
229     use core::mem::offset_of;
230     use std::mem::size_of;
231     use wasmtime_environ::{HostPtr, Module, VMOffsets};
232 
233     #[test]
234     fn check_vmmemory_import_offsets() {
235         let module = Module::new();
236         let offsets = VMOffsets::new(HostPtr, &module);
237         assert_eq!(
238             size_of::<VMMemoryImport>(),
239             usize::from(offsets.size_of_vmmemory_import())
240         );
241         assert_eq!(
242             offset_of!(VMMemoryImport, from),
243             usize::from(offsets.vmmemory_import_from())
244         );
245         assert_eq!(
246             offset_of!(VMMemoryImport, vmctx),
247             usize::from(offsets.vmmemory_import_vmctx())
248         );
249         assert_eq!(
250             offset_of!(VMMemoryImport, index),
251             usize::from(offsets.vmmemory_import_index())
252         );
253     }
254 }
255 
256 /// The fields compiled code needs to access to utilize a WebAssembly global
257 /// variable imported from another instance.
258 ///
259 /// Note that unlike with functions, tables, and memories, `VMGlobalImport`
260 /// doesn't include a `vmctx` pointer. Globals are never resized, and don't
261 /// require a `vmctx` pointer to access.
262 #[derive(Debug, Copy, Clone)]
263 #[repr(C)]
264 pub struct VMGlobalImport {
265     /// A pointer to the imported global variable description.
266     pub from: VmPtr<VMGlobalDefinition>,
267 
268     /// A pointer to the context that owns the global.
269     ///
270     /// Exactly what's stored here is dictated by `kind` below. This is `None`
271     /// for `VMGlobalKind::Host`, it's a `VMContext` for
272     /// `VMGlobalKind::Instance`, and it's `VMComponentContext` for
273     /// `VMGlobalKind::ComponentFlags`.
274     pub vmctx: Option<VmPtr<VMOpaqueContext>>,
275 
276     /// The kind of global, and extra location information in addition to
277     /// `vmctx` above.
278     pub kind: VMGlobalKind,
279 }
280 
281 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
282 unsafe impl VmSafe for VMGlobalImport {}
283 
284 /// The kinds of globals that Wasmtime has.
285 #[derive(Debug, Copy, Clone)]
286 #[repr(C, u32)]
287 pub enum VMGlobalKind {
288     /// Host globals, stored in a `StoreOpaque`.
289     Host(DefinedGlobalIndex),
290     /// Instance globals, stored in `VMContext`s
291     Instance(DefinedGlobalIndex),
292     /// Flags for a component instance, stored in `VMComponentContext`.
293     #[cfg(feature = "component-model")]
294     ComponentFlags(wasmtime_environ::component::RuntimeComponentInstanceIndex),
295 }
296 
297 // SAFETY: the above enum is repr(C) and stores nothing else
298 unsafe impl VmSafe for VMGlobalKind {}
299 
300 #[cfg(test)]
301 mod test_vmglobal_import {
302     use super::VMGlobalImport;
303     use core::mem::offset_of;
304     use std::mem::size_of;
305     use wasmtime_environ::{HostPtr, Module, VMOffsets};
306 
307     #[test]
308     fn check_vmglobal_import_offsets() {
309         let module = Module::new();
310         let offsets = VMOffsets::new(HostPtr, &module);
311         assert_eq!(
312             size_of::<VMGlobalImport>(),
313             usize::from(offsets.size_of_vmglobal_import())
314         );
315         assert_eq!(
316             offset_of!(VMGlobalImport, from),
317             usize::from(offsets.vmglobal_import_from())
318         );
319     }
320 }
321 
322 /// The fields compiled code needs to access to utilize a WebAssembly
323 /// tag imported from another instance.
324 #[derive(Debug, Copy, Clone)]
325 #[repr(C)]
326 pub struct VMTagImport {
327     /// A pointer to the imported tag description.
328     pub from: VmPtr<VMTagDefinition>,
329 
330     /// The instance that owns this tag.
331     pub vmctx: VmPtr<VMContext>,
332 
333     /// The index of the tag in the containing `vmctx`.
334     pub index: DefinedTagIndex,
335 }
336 
337 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
338 unsafe impl VmSafe for VMTagImport {}
339 
340 #[cfg(test)]
341 mod test_vmtag_import {
342     use super::VMTagImport;
343     use core::mem::{offset_of, size_of};
344     use wasmtime_environ::{HostPtr, Module, VMOffsets};
345 
346     #[test]
347     fn check_vmtag_import_offsets() {
348         let module = Module::new();
349         let offsets = VMOffsets::new(HostPtr, &module);
350         assert_eq!(
351             size_of::<VMTagImport>(),
352             usize::from(offsets.size_of_vmtag_import())
353         );
354         assert_eq!(
355             offset_of!(VMTagImport, from),
356             usize::from(offsets.vmtag_import_from())
357         );
358     }
359 }
360 
361 /// The fields compiled code needs to access to utilize a WebAssembly linear
362 /// memory defined within the instance, namely the start address and the
363 /// size in bytes.
364 #[derive(Debug)]
365 #[repr(C)]
366 pub struct VMMemoryDefinition {
367     /// The start address.
368     pub base: VmPtr<u8>,
369 
370     /// The current logical size of this linear memory in bytes.
371     ///
372     /// This is atomic because shared memories must be able to grow their length
373     /// atomically. For relaxed access, see
374     /// [`VMMemoryDefinition::current_length()`].
375     pub current_length: AtomicUsize,
376 }
377 
378 // SAFETY: the above definition has `repr(C)` and each field individually
379 // implements `VmSafe`, which satisfies the requirements of this trait.
380 unsafe impl VmSafe for VMMemoryDefinition {}
381 
382 impl VMMemoryDefinition {
383     /// Return the current length (in bytes) of the [`VMMemoryDefinition`] by
384     /// performing a relaxed load; do not use this function for situations in
385     /// which a precise length is needed. Owned memories (i.e., non-shared) will
386     /// always return a precise result (since no concurrent modification is
387     /// possible) but shared memories may see an imprecise value--a
388     /// `current_length` potentially smaller than what some other thread
389     /// observes. Since Wasm memory only grows, this under-estimation may be
390     /// acceptable in certain cases.
391     #[inline]
392     pub fn current_length(&self) -> usize {
393         self.current_length.load(Ordering::Relaxed)
394     }
395 
396     /// Return a copy of the [`VMMemoryDefinition`] using the relaxed value of
397     /// `current_length`; see [`VMMemoryDefinition::current_length()`].
398     #[inline]
399     pub unsafe fn load(ptr: *mut Self) -> Self {
400         let other = unsafe { &*ptr };
401         VMMemoryDefinition {
402             base: other.base,
403             current_length: other.current_length().into(),
404         }
405     }
406 }
407 
408 #[cfg(test)]
409 mod test_vmmemory_definition {
410     use super::VMMemoryDefinition;
411     use core::mem::offset_of;
412     use std::mem::size_of;
413     use wasmtime_environ::{HostPtr, Module, PtrSize, VMOffsets};
414 
415     #[test]
416     fn check_vmmemory_definition_offsets() {
417         let module = Module::new();
418         let offsets = VMOffsets::new(HostPtr, &module);
419         assert_eq!(
420             size_of::<VMMemoryDefinition>(),
421             usize::from(offsets.ptr.size_of_vmmemory_definition())
422         );
423         assert_eq!(
424             offset_of!(VMMemoryDefinition, base),
425             usize::from(offsets.ptr.vmmemory_definition_base())
426         );
427         assert_eq!(
428             offset_of!(VMMemoryDefinition, current_length),
429             usize::from(offsets.ptr.vmmemory_definition_current_length())
430         );
431         /* TODO: Assert that the size of `current_length` matches.
432         assert_eq!(
433             size_of::<VMMemoryDefinition::current_length>(),
434             usize::from(offsets.size_of_vmmemory_definition_current_length())
435         );
436         */
437     }
438 }
439 
440 /// The fields compiled code needs to access to utilize a WebAssembly table
441 /// defined within the instance.
442 #[derive(Debug, Copy, Clone)]
443 #[repr(C)]
444 pub struct VMTableDefinition {
445     /// Pointer to the table data.
446     pub base: VmPtr<u8>,
447 
448     /// The current number of elements in the table.
449     pub current_elements: usize,
450 }
451 
452 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
453 unsafe impl VmSafe for VMTableDefinition {}
454 
455 #[cfg(test)]
456 mod test_vmtable_definition {
457     use super::VMTableDefinition;
458     use core::mem::offset_of;
459     use std::mem::size_of;
460     use wasmtime_environ::{HostPtr, Module, VMOffsets};
461 
462     #[test]
463     fn check_vmtable_definition_offsets() {
464         let module = Module::new();
465         let offsets = VMOffsets::new(HostPtr, &module);
466         assert_eq!(
467             size_of::<VMTableDefinition>(),
468             usize::from(offsets.size_of_vmtable_definition())
469         );
470         assert_eq!(
471             offset_of!(VMTableDefinition, base),
472             usize::from(offsets.vmtable_definition_base())
473         );
474         assert_eq!(
475             offset_of!(VMTableDefinition, current_elements),
476             usize::from(offsets.vmtable_definition_current_elements())
477         );
478     }
479 }
480 
481 /// The storage for a WebAssembly global defined within the instance.
482 ///
483 /// TODO: Pack the globals more densely, rather than using the same size
484 /// for every type.
485 #[derive(Debug)]
486 #[repr(C, align(16))]
487 pub struct VMGlobalDefinition {
488     storage: [u8; 16],
489     // If more elements are added here, remember to add offset_of tests below!
490 }
491 
492 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
493 unsafe impl VmSafe for VMGlobalDefinition {}
494 
495 #[cfg(test)]
496 mod test_vmglobal_definition {
497     use super::VMGlobalDefinition;
498     use std::mem::{align_of, size_of};
499     use wasmtime_environ::{HostPtr, Module, PtrSize, VMOffsets};
500 
501     #[test]
502     fn check_vmglobal_definition_alignment() {
503         assert!(align_of::<VMGlobalDefinition>() >= align_of::<i32>());
504         assert!(align_of::<VMGlobalDefinition>() >= align_of::<i64>());
505         assert!(align_of::<VMGlobalDefinition>() >= align_of::<f32>());
506         assert!(align_of::<VMGlobalDefinition>() >= align_of::<f64>());
507         assert!(align_of::<VMGlobalDefinition>() >= align_of::<[u8; 16]>());
508         assert!(align_of::<VMGlobalDefinition>() >= align_of::<[f32; 4]>());
509         assert!(align_of::<VMGlobalDefinition>() >= align_of::<[f64; 2]>());
510     }
511 
512     #[test]
513     fn check_vmglobal_definition_offsets() {
514         let module = Module::new();
515         let offsets = VMOffsets::new(HostPtr, &module);
516         assert_eq!(
517             size_of::<VMGlobalDefinition>(),
518             usize::from(offsets.ptr.size_of_vmglobal_definition())
519         );
520     }
521 
522     #[test]
523     fn check_vmglobal_begins_aligned() {
524         let module = Module::new();
525         let offsets = VMOffsets::new(HostPtr, &module);
526         assert_eq!(offsets.vmctx_globals_begin() % 16, 0);
527     }
528 
529     #[test]
530     #[cfg(feature = "gc")]
531     fn check_vmglobal_can_contain_gc_ref() {
532         assert!(size_of::<crate::runtime::vm::VMGcRef>() <= size_of::<VMGlobalDefinition>());
533     }
534 }
535 
536 impl VMGlobalDefinition {
537     /// Construct a `VMGlobalDefinition`.
538     pub fn new() -> Self {
539         Self { storage: [0; 16] }
540     }
541 
542     /// Create a `VMGlobalDefinition` from a `ValRaw`.
543     ///
544     /// # Unsafety
545     ///
546     /// This raw value's type must match the given `WasmValType`.
547     pub unsafe fn from_val_raw(
548         store: &mut StoreOpaque,
549         wasm_ty: WasmValType,
550         raw: ValRaw,
551     ) -> Result<Self> {
552         let mut global = Self::new();
553         unsafe {
554             match wasm_ty {
555                 WasmValType::I32 => *global.as_i32_mut() = raw.get_i32(),
556                 WasmValType::I64 => *global.as_i64_mut() = raw.get_i64(),
557                 WasmValType::F32 => *global.as_f32_bits_mut() = raw.get_f32(),
558                 WasmValType::F64 => *global.as_f64_bits_mut() = raw.get_f64(),
559                 WasmValType::V128 => global.set_u128(raw.get_v128()),
560                 WasmValType::Ref(r) => match r.heap_type.top() {
561                     WasmHeapTopType::Extern => {
562                         let r = VMGcRef::from_raw_u32(raw.get_externref());
563                         global.init_gc_ref(store, r.as_ref())
564                     }
565                     WasmHeapTopType::Any => {
566                         let r = VMGcRef::from_raw_u32(raw.get_anyref());
567                         global.init_gc_ref(store, r.as_ref())
568                     }
569                     WasmHeapTopType::Func => *global.as_func_ref_mut() = raw.get_funcref().cast(),
570                     WasmHeapTopType::Cont => *global.as_func_ref_mut() = raw.get_funcref().cast(), // TODO(#10248): temporary hack.
571                     WasmHeapTopType::Exn => {
572                         let r = VMGcRef::from_raw_u32(raw.get_exnref());
573                         global.init_gc_ref(store, r.as_ref())
574                     }
575                 },
576             }
577         }
578         Ok(global)
579     }
580 
581     /// Get this global's value as a `ValRaw`.
582     ///
583     /// # Unsafety
584     ///
585     /// This global's value's type must match the given `WasmValType`.
586     pub unsafe fn to_val_raw(
587         &self,
588         store: &mut StoreOpaque,
589         wasm_ty: WasmValType,
590     ) -> Result<ValRaw> {
591         unsafe {
592             Ok(match wasm_ty {
593                 WasmValType::I32 => ValRaw::i32(*self.as_i32()),
594                 WasmValType::I64 => ValRaw::i64(*self.as_i64()),
595                 WasmValType::F32 => ValRaw::f32(*self.as_f32_bits()),
596                 WasmValType::F64 => ValRaw::f64(*self.as_f64_bits()),
597                 WasmValType::V128 => ValRaw::v128(self.get_u128()),
598                 WasmValType::Ref(r) => match r.heap_type.top() {
599                     WasmHeapTopType::Extern => ValRaw::externref(match self.as_gc_ref() {
600                         Some(r) => store.clone_gc_ref(r).as_raw_u32(),
601                         None => 0,
602                     }),
603                     WasmHeapTopType::Any => ValRaw::anyref({
604                         match self.as_gc_ref() {
605                             Some(r) => store.clone_gc_ref(r).as_raw_u32(),
606                             None => 0,
607                         }
608                     }),
609                     WasmHeapTopType::Exn => ValRaw::exnref({
610                         match self.as_gc_ref() {
611                             Some(r) => store.clone_gc_ref(r).as_raw_u32(),
612                             None => 0,
613                         }
614                     }),
615                     WasmHeapTopType::Func => ValRaw::funcref(self.as_func_ref().cast()),
616                     WasmHeapTopType::Cont => todo!(), // FIXME: #10248 stack switching support.
617                 },
618             })
619         }
620     }
621 
622     /// Return a reference to the value as an i32.
623     pub unsafe fn as_i32(&self) -> &i32 {
624         unsafe { &*(self.storage.as_ref().as_ptr().cast::<i32>()) }
625     }
626 
627     /// Return a mutable reference to the value as an i32.
628     pub unsafe fn as_i32_mut(&mut self) -> &mut i32 {
629         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<i32>()) }
630     }
631 
632     /// Return a reference to the value as a u32.
633     pub unsafe fn as_u32(&self) -> &u32 {
634         unsafe { &*(self.storage.as_ref().as_ptr().cast::<u32>()) }
635     }
636 
637     /// Return a mutable reference to the value as an u32.
638     pub unsafe fn as_u32_mut(&mut self) -> &mut u32 {
639         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<u32>()) }
640     }
641 
642     /// Return a reference to the value as an i64.
643     pub unsafe fn as_i64(&self) -> &i64 {
644         unsafe { &*(self.storage.as_ref().as_ptr().cast::<i64>()) }
645     }
646 
647     /// Return a mutable reference to the value as an i64.
648     pub unsafe fn as_i64_mut(&mut self) -> &mut i64 {
649         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<i64>()) }
650     }
651 
652     /// Return a reference to the value as an u64.
653     pub unsafe fn as_u64(&self) -> &u64 {
654         unsafe { &*(self.storage.as_ref().as_ptr().cast::<u64>()) }
655     }
656 
657     /// Return a mutable reference to the value as an u64.
658     pub unsafe fn as_u64_mut(&mut self) -> &mut u64 {
659         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<u64>()) }
660     }
661 
662     /// Return a reference to the value as an f32.
663     pub unsafe fn as_f32(&self) -> &f32 {
664         unsafe { &*(self.storage.as_ref().as_ptr().cast::<f32>()) }
665     }
666 
667     /// Return a mutable reference to the value as an f32.
668     pub unsafe fn as_f32_mut(&mut self) -> &mut f32 {
669         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<f32>()) }
670     }
671 
672     /// Return a reference to the value as f32 bits.
673     pub unsafe fn as_f32_bits(&self) -> &u32 {
674         unsafe { &*(self.storage.as_ref().as_ptr().cast::<u32>()) }
675     }
676 
677     /// Return a mutable reference to the value as f32 bits.
678     pub unsafe fn as_f32_bits_mut(&mut self) -> &mut u32 {
679         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<u32>()) }
680     }
681 
682     /// Return a reference to the value as an f64.
683     pub unsafe fn as_f64(&self) -> &f64 {
684         unsafe { &*(self.storage.as_ref().as_ptr().cast::<f64>()) }
685     }
686 
687     /// Return a mutable reference to the value as an f64.
688     pub unsafe fn as_f64_mut(&mut self) -> &mut f64 {
689         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<f64>()) }
690     }
691 
692     /// Return a reference to the value as f64 bits.
693     pub unsafe fn as_f64_bits(&self) -> &u64 {
694         unsafe { &*(self.storage.as_ref().as_ptr().cast::<u64>()) }
695     }
696 
697     /// Return a mutable reference to the value as f64 bits.
698     pub unsafe fn as_f64_bits_mut(&mut self) -> &mut u64 {
699         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<u64>()) }
700     }
701 
702     /// Gets the underlying 128-bit vector value.
703     //
704     // Note that vectors are stored in little-endian format while other types
705     // are stored in native-endian format.
706     pub unsafe fn get_u128(&self) -> u128 {
707         unsafe { u128::from_le(*(self.storage.as_ref().as_ptr().cast::<u128>())) }
708     }
709 
710     /// Sets the 128-bit vector values.
711     //
712     // Note that vectors are stored in little-endian format while other types
713     // are stored in native-endian format.
714     pub unsafe fn set_u128(&mut self, val: u128) {
715         unsafe {
716             *self.storage.as_mut().as_mut_ptr().cast::<u128>() = val.to_le();
717         }
718     }
719 
720     /// Return a reference to the value as u128 bits.
721     pub unsafe fn as_u128_bits(&self) -> &[u8; 16] {
722         unsafe { &*(self.storage.as_ref().as_ptr().cast::<[u8; 16]>()) }
723     }
724 
725     /// Return a mutable reference to the value as u128 bits.
726     pub unsafe fn as_u128_bits_mut(&mut self) -> &mut [u8; 16] {
727         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<[u8; 16]>()) }
728     }
729 
730     /// Return a reference to the global value as a borrowed GC reference.
731     pub unsafe fn as_gc_ref(&self) -> Option<&VMGcRef> {
732         let raw_ptr = self.storage.as_ref().as_ptr().cast::<Option<VMGcRef>>();
733         let ret = unsafe { (*raw_ptr).as_ref() };
734         assert!(cfg!(feature = "gc") || ret.is_none());
735         ret
736     }
737 
738     /// Initialize a global to the given GC reference.
739     pub unsafe fn init_gc_ref(&mut self, store: &mut StoreOpaque, gc_ref: Option<&VMGcRef>) {
740         let dest = unsafe {
741             &mut *(self
742                 .storage
743                 .as_mut()
744                 .as_mut_ptr()
745                 .cast::<MaybeUninit<Option<VMGcRef>>>())
746         };
747 
748         store.init_gc_ref(dest, gc_ref)
749     }
750 
751     /// Write a GC reference into this global value.
752     pub unsafe fn write_gc_ref(&mut self, store: &mut StoreOpaque, gc_ref: Option<&VMGcRef>) {
753         let dest = unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<Option<VMGcRef>>()) };
754         store.write_gc_ref(dest, gc_ref)
755     }
756 
757     /// Return a reference to the value as a `VMFuncRef`.
758     pub unsafe fn as_func_ref(&self) -> *mut VMFuncRef {
759         unsafe { *(self.storage.as_ref().as_ptr().cast::<*mut VMFuncRef>()) }
760     }
761 
762     /// Return a mutable reference to the value as a `VMFuncRef`.
763     pub unsafe fn as_func_ref_mut(&mut self) -> &mut *mut VMFuncRef {
764         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<*mut VMFuncRef>()) }
765     }
766 }
767 
768 #[cfg(test)]
769 mod test_vmshared_type_index {
770     use super::VMSharedTypeIndex;
771     use std::mem::size_of;
772     use wasmtime_environ::{HostPtr, Module, VMOffsets};
773 
774     #[test]
775     fn check_vmshared_type_index() {
776         let module = Module::new();
777         let offsets = VMOffsets::new(HostPtr, &module);
778         assert_eq!(
779             size_of::<VMSharedTypeIndex>(),
780             usize::from(offsets.size_of_vmshared_type_index())
781         );
782     }
783 }
784 
785 /// A WebAssembly tag defined within the instance.
786 ///
787 #[derive(Debug)]
788 #[repr(C)]
789 pub struct VMTagDefinition {
790     /// Function signature's type id.
791     pub type_index: VMSharedTypeIndex,
792 }
793 
794 impl VMTagDefinition {
795     pub fn new(type_index: VMSharedTypeIndex) -> Self {
796         Self { type_index }
797     }
798 }
799 
800 // SAFETY: the above structure is repr(C) and only contains VmSafe
801 // fields.
802 unsafe impl VmSafe for VMTagDefinition {}
803 
804 #[cfg(test)]
805 mod test_vmtag_definition {
806     use super::VMTagDefinition;
807     use std::mem::size_of;
808     use wasmtime_environ::{HostPtr, Module, PtrSize, VMOffsets};
809 
810     #[test]
811     fn check_vmtag_definition_offsets() {
812         let module = Module::new();
813         let offsets = VMOffsets::new(HostPtr, &module);
814         assert_eq!(
815             size_of::<VMTagDefinition>(),
816             usize::from(offsets.ptr.size_of_vmtag_definition())
817         );
818     }
819 
820     #[test]
821     fn check_vmtag_begins_aligned() {
822         let module = Module::new();
823         let offsets = VMOffsets::new(HostPtr, &module);
824         assert_eq!(offsets.vmctx_tags_begin() % 16, 0);
825     }
826 }
827 
828 /// The VM caller-checked "funcref" record, for caller-side signature checking.
829 ///
830 /// It consists of function pointer(s), a type id to be checked by the
831 /// caller, and the vmctx closure associated with this function.
832 #[derive(Debug, Clone)]
833 #[repr(C)]
834 pub struct VMFuncRef {
835     /// Function pointer for this funcref if being called via the "array"
836     /// calling convention that `Func::new` et al use.
837     pub array_call: VmPtr<VMArrayCallFunction>,
838 
839     /// Function pointer for this funcref if being called via the calling
840     /// convention we use when compiling Wasm.
841     ///
842     /// Most functions come with a function pointer that we can use when they
843     /// are called from Wasm. The notable exception is when we `Func::wrap` a
844     /// host function, and we don't have a Wasm compiler on hand to compile a
845     /// Wasm-to-native trampoline for the function. In this case, we leave
846     /// `wasm_call` empty until the function is passed as an import to Wasm (or
847     /// otherwise exposed to Wasm via tables/globals). At this point, we look up
848     /// a Wasm-to-native trampoline for the function in the Wasm's compiled
849     /// module and use that fill in `VMFunctionImport::wasm_call`. **However**
850     /// there is no guarantee that the Wasm module has a trampoline for this
851     /// function's signature. The Wasm module only has trampolines for its
852     /// types, and if this function isn't of one of those types, then the Wasm
853     /// module will not have a trampoline for it. This is actually okay, because
854     /// it means that the Wasm cannot actually call this function. But it does
855     /// mean that this field needs to be an `Option` even though it is non-null
856     /// the vast vast vast majority of the time.
857     pub wasm_call: Option<VmPtr<VMWasmCallFunction>>,
858 
859     /// Function signature's type id.
860     pub type_index: VMSharedTypeIndex,
861 
862     /// The VM state associated with this function.
863     ///
864     /// The actual definition of what this pointer points to depends on the
865     /// function being referenced: for core Wasm functions, this is a `*mut
866     /// VMContext`, for host functions it is a `*mut VMHostFuncContext`, and for
867     /// component functions it is a `*mut VMComponentContext`.
868     pub vmctx: VmPtr<VMOpaqueContext>,
869     // If more elements are added here, remember to add offset_of tests below!
870 }
871 
872 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
873 unsafe impl VmSafe for VMFuncRef {}
874 
875 impl VMFuncRef {
876     /// Invokes the `array_call` field of this `VMFuncRef` with the supplied
877     /// arguments.
878     ///
879     /// This will invoke the function pointer in the `array_call` field with:
880     ///
881     /// * the `callee` vmctx as `self.vmctx`
882     /// * the `caller` as `caller` specified here
883     /// * the args pointer as `args_and_results`
884     /// * the args length as `args_and_results`
885     ///
886     /// The `args_and_results` area must be large enough to both load all
887     /// arguments from and store all results to.
888     ///
889     /// Returns whether a trap was recorded in TLS for raising.
890     ///
891     /// # Unsafety
892     ///
893     /// This method is unsafe because it can be called with any pointers. They
894     /// must all be valid for this wasm function call to proceed. For example
895     /// the `caller` must be valid machine code if `pulley` is `None` or it must
896     /// be valid bytecode if `pulley` is `Some`. Additionally `args_and_results`
897     /// must be large enough to handle all the arguments/results for this call.
898     ///
899     /// Note that the unsafety invariants to maintain here are not currently
900     /// exhaustively documented.
901     #[inline]
902     pub unsafe fn array_call(
903         me: NonNull<VMFuncRef>,
904         pulley: Option<InterpreterRef<'_>>,
905         caller: NonNull<VMContext>,
906         args_and_results: NonNull<[ValRaw]>,
907     ) -> bool {
908         match pulley {
909             Some(vm) => unsafe { Self::array_call_interpreted(me, vm, caller, args_and_results) },
910             None => unsafe { Self::array_call_native(me, caller, args_and_results) },
911         }
912     }
913 
914     unsafe fn array_call_interpreted(
915         me: NonNull<VMFuncRef>,
916         vm: InterpreterRef<'_>,
917         caller: NonNull<VMContext>,
918         args_and_results: NonNull<[ValRaw]>,
919     ) -> bool {
920         // If `caller` is actually a `VMArrayCallHostFuncContext` then skip the
921         // interpreter, even though it's available, as `array_call` will be
922         // native code.
923         unsafe {
924             if me.as_ref().vmctx.as_non_null().as_ref().magic
925                 == wasmtime_environ::VM_ARRAY_CALL_HOST_FUNC_MAGIC
926             {
927                 return Self::array_call_native(me, caller, args_and_results);
928             }
929             vm.call(
930                 me.as_ref().array_call.as_non_null().cast(),
931                 me.as_ref().vmctx.as_non_null(),
932                 caller,
933                 args_and_results,
934             )
935         }
936     }
937 
938     #[inline]
939     unsafe fn array_call_native(
940         me: NonNull<VMFuncRef>,
941         caller: NonNull<VMContext>,
942         args_and_results: NonNull<[ValRaw]>,
943     ) -> bool {
944         unsafe {
945             union GetNativePointer {
946                 native: VMArrayCallNative,
947                 ptr: NonNull<VMArrayCallFunction>,
948             }
949             let native = GetNativePointer {
950                 ptr: me.as_ref().array_call.as_non_null(),
951             }
952             .native;
953             native(
954                 me.as_ref().vmctx.as_non_null(),
955                 caller,
956                 args_and_results.cast(),
957                 args_and_results.len(),
958             )
959         }
960     }
961 }
962 
963 #[cfg(test)]
964 mod test_vm_func_ref {
965     use super::VMFuncRef;
966     use core::mem::offset_of;
967     use std::mem::size_of;
968     use wasmtime_environ::{HostPtr, Module, PtrSize, VMOffsets};
969 
970     #[test]
971     fn check_vm_func_ref_offsets() {
972         let module = Module::new();
973         let offsets = VMOffsets::new(HostPtr, &module);
974         assert_eq!(
975             size_of::<VMFuncRef>(),
976             usize::from(offsets.ptr.size_of_vm_func_ref())
977         );
978         assert_eq!(
979             offset_of!(VMFuncRef, array_call),
980             usize::from(offsets.ptr.vm_func_ref_array_call())
981         );
982         assert_eq!(
983             offset_of!(VMFuncRef, wasm_call),
984             usize::from(offsets.ptr.vm_func_ref_wasm_call())
985         );
986         assert_eq!(
987             offset_of!(VMFuncRef, type_index),
988             usize::from(offsets.ptr.vm_func_ref_type_index())
989         );
990         assert_eq!(
991             offset_of!(VMFuncRef, vmctx),
992             usize::from(offsets.ptr.vm_func_ref_vmctx())
993         );
994     }
995 }
996 
997 macro_rules! define_builtin_array {
998     (
999         $(
1000             $( #[$attr:meta] )*
1001             $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
1002         )*
1003     ) => {
1004         /// An array that stores addresses of builtin functions. We translate code
1005         /// to use indirect calls. This way, we don't have to patch the code.
1006         #[repr(C)]
1007         #[allow(improper_ctypes_definitions, reason = "__m128i known not FFI-safe")]
1008         pub struct VMBuiltinFunctionsArray {
1009             $(
1010                 $name: unsafe extern "C" fn(
1011                     $(define_builtin_array!(@ty $param)),*
1012                 ) $( -> define_builtin_array!(@ty $result))?,
1013             )*
1014         }
1015 
1016         impl VMBuiltinFunctionsArray {
1017             pub const INIT: VMBuiltinFunctionsArray = VMBuiltinFunctionsArray {
1018                 $(
1019                     $name: crate::runtime::vm::libcalls::raw::$name,
1020                 )*
1021             };
1022 
1023             /// Helper to call `expose_provenance()` on all contained pointers.
1024             ///
1025             /// This is required to be called at least once before entering wasm
1026             /// to inform the compiler that these function pointers may all be
1027             /// loaded/stored and used on the "other end" to reacquire
1028             /// provenance in Pulley. Pulley models hostcalls with a host
1029             /// pointer as the first parameter that's a function pointer under
1030             /// the hood, and this call ensures that the use of the function
1031             /// pointer is considered valid.
1032             pub fn expose_provenance(&self) -> NonNull<Self>{
1033                 $(
1034                     (self.$name as *mut u8).expose_provenance();
1035                 )*
1036                 NonNull::from(self)
1037             }
1038         }
1039     };
1040 
1041     (@ty u32) => (u32);
1042     (@ty u64) => (u64);
1043     (@ty f32) => (f32);
1044     (@ty f64) => (f64);
1045     (@ty u8) => (u8);
1046     (@ty i8x16) => (i8x16);
1047     (@ty f32x4) => (f32x4);
1048     (@ty f64x2) => (f64x2);
1049     (@ty bool) => (bool);
1050     (@ty pointer) => (*mut u8);
1051     (@ty vmctx) => (NonNull<VMContext>);
1052 }
1053 
1054 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
1055 unsafe impl VmSafe for VMBuiltinFunctionsArray {}
1056 
1057 wasmtime_environ::foreach_builtin_function!(define_builtin_array);
1058 
1059 const _: () = {
1060     assert!(
1061         mem::size_of::<VMBuiltinFunctionsArray>()
1062             == mem::size_of::<usize>() * (BuiltinFunctionIndex::len() as usize)
1063     )
1064 };
1065 
1066 /// Structure that holds all mutable context that is shared across all instances
1067 /// in a store, for example data related to fuel or epochs.
1068 ///
1069 /// `VMStoreContext`s are one-to-one with `wasmtime::Store`s, the same way that
1070 /// `VMContext`s are one-to-one with `wasmtime::Instance`s. And the same way
1071 /// that multiple `wasmtime::Instance`s may be associated with the same
1072 /// `wasmtime::Store`, multiple `VMContext`s hold a pointer to the same
1073 /// `VMStoreContext` when they are associated with the same `wasmtime::Store`.
1074 #[derive(Debug)]
1075 #[repr(C)]
1076 pub struct VMStoreContext {
1077     // NB: 64-bit integer fields are located first with pointer-sized fields
1078     // trailing afterwards. That makes the offsets in this structure easier to
1079     // calculate on 32-bit platforms as we don't have to worry about the
1080     // alignment of 64-bit integers.
1081     //
1082     /// Indicator of how much fuel has been consumed and is remaining to
1083     /// WebAssembly.
1084     ///
1085     /// This field is typically negative and increments towards positive. Upon
1086     /// turning positive a wasm trap will be generated. This field is only
1087     /// modified if wasm is configured to consume fuel.
1088     pub fuel_consumed: UnsafeCell<i64>,
1089 
1090     /// Deadline epoch for interruption: if epoch-based interruption
1091     /// is enabled and the global (per engine) epoch counter is
1092     /// observed to reach or exceed this value, the guest code will
1093     /// yield if running asynchronously.
1094     pub epoch_deadline: UnsafeCell<u64>,
1095 
1096     /// Current stack limit of the wasm module.
1097     ///
1098     /// For more information see `crates/cranelift/src/lib.rs`.
1099     pub stack_limit: UnsafeCell<usize>,
1100 
1101     /// The `VMMemoryDefinition` for this store's GC heap.
1102     pub gc_heap: VMMemoryDefinition,
1103 
1104     /// The value of the frame pointer register when we last called from Wasm to
1105     /// the host.
1106     ///
1107     /// Maintained by our Wasm-to-host trampoline, and cleared just before
1108     /// calling into Wasm in `catch_traps`.
1109     ///
1110     /// This member is `0` when Wasm is actively running and has not called out
1111     /// to the host.
1112     ///
1113     /// Used to find the start of a contiguous sequence of Wasm frames when
1114     /// walking the stack.
1115     pub last_wasm_exit_fp: UnsafeCell<usize>,
1116 
1117     /// The last Wasm program counter before we called from Wasm to the host.
1118     ///
1119     /// Maintained by our Wasm-to-host trampoline, and cleared just before
1120     /// calling into Wasm in `catch_traps`.
1121     ///
1122     /// This member is `0` when Wasm is actively running and has not called out
1123     /// to the host.
1124     ///
1125     /// Used when walking a contiguous sequence of Wasm frames.
1126     pub last_wasm_exit_pc: UnsafeCell<usize>,
1127 
1128     /// The last host stack pointer before we called into Wasm from the host.
1129     ///
1130     /// Maintained by our host-to-Wasm trampoline, and cleared just before
1131     /// calling into Wasm in `catch_traps`.
1132     ///
1133     /// This member is `0` when Wasm is actively running and has not called out
1134     /// to the host.
1135     ///
1136     /// When a host function is wrapped into a `wasmtime::Func`, and is then
1137     /// called from the host, then this member has the sentinel value of `-1 as
1138     /// usize`, meaning that this contiguous sequence of Wasm frames is the
1139     /// empty sequence, and it is not safe to dereference the
1140     /// `last_wasm_exit_fp`.
1141     ///
1142     /// Used to find the end of a contiguous sequence of Wasm frames when
1143     /// walking the stack.
1144     pub last_wasm_entry_fp: UnsafeCell<usize>,
1145 
1146     /// Stack information used by stack switching instructions. See documentation
1147     /// on `VMStackChain` for details.
1148     pub stack_chain: UnsafeCell<VMStackChain>,
1149 
1150     /// The range, in addresses, of the guard page that is currently in use.
1151     ///
1152     /// This field is used when signal handlers are run to determine whether a
1153     /// faulting address lies within the guard page of an async stack for
1154     /// example. If this happens then the signal handler aborts with a stack
1155     /// overflow message similar to what would happen had the stack overflow
1156     /// happened on the main thread. This field is, by default a null..null
1157     /// range indicating that no async guard is in use (aka no fiber). In such a
1158     /// situation while this field is read it'll never classify a fault as an
1159     /// guard page fault.
1160     pub async_guard_range: Range<*mut u8>,
1161 }
1162 
1163 // The `VMStoreContext` type is a pod-type with no destructor, and we don't
1164 // access any fields from other threads, so add in these trait impls which are
1165 // otherwise not available due to the `fuel_consumed` and `epoch_deadline`
1166 // variables in `VMStoreContext`.
1167 unsafe impl Send for VMStoreContext {}
1168 unsafe impl Sync for VMStoreContext {}
1169 
1170 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
1171 unsafe impl VmSafe for VMStoreContext {}
1172 
1173 impl Default for VMStoreContext {
1174     fn default() -> VMStoreContext {
1175         VMStoreContext {
1176             fuel_consumed: UnsafeCell::new(0),
1177             epoch_deadline: UnsafeCell::new(0),
1178             stack_limit: UnsafeCell::new(usize::max_value()),
1179             gc_heap: VMMemoryDefinition {
1180                 base: NonNull::dangling().into(),
1181                 current_length: AtomicUsize::new(0),
1182             },
1183             last_wasm_exit_fp: UnsafeCell::new(0),
1184             last_wasm_exit_pc: UnsafeCell::new(0),
1185             last_wasm_entry_fp: UnsafeCell::new(0),
1186             stack_chain: UnsafeCell::new(VMStackChain::Absent),
1187             async_guard_range: ptr::null_mut()..ptr::null_mut(),
1188         }
1189     }
1190 }
1191 
1192 #[cfg(test)]
1193 mod test_vmstore_context {
1194     use super::{VMMemoryDefinition, VMStoreContext};
1195     use core::mem::offset_of;
1196     use wasmtime_environ::{HostPtr, Module, PtrSize, VMOffsets};
1197 
1198     #[test]
1199     fn field_offsets() {
1200         let module = Module::new();
1201         let offsets = VMOffsets::new(HostPtr, &module);
1202         assert_eq!(
1203             offset_of!(VMStoreContext, stack_limit),
1204             usize::from(offsets.ptr.vmstore_context_stack_limit())
1205         );
1206         assert_eq!(
1207             offset_of!(VMStoreContext, fuel_consumed),
1208             usize::from(offsets.ptr.vmstore_context_fuel_consumed())
1209         );
1210         assert_eq!(
1211             offset_of!(VMStoreContext, epoch_deadline),
1212             usize::from(offsets.ptr.vmstore_context_epoch_deadline())
1213         );
1214         assert_eq!(
1215             offset_of!(VMStoreContext, gc_heap),
1216             usize::from(offsets.ptr.vmstore_context_gc_heap())
1217         );
1218         assert_eq!(
1219             offset_of!(VMStoreContext, gc_heap) + offset_of!(VMMemoryDefinition, base),
1220             usize::from(offsets.ptr.vmstore_context_gc_heap_base())
1221         );
1222         assert_eq!(
1223             offset_of!(VMStoreContext, gc_heap) + offset_of!(VMMemoryDefinition, current_length),
1224             usize::from(offsets.ptr.vmstore_context_gc_heap_current_length())
1225         );
1226         assert_eq!(
1227             offset_of!(VMStoreContext, last_wasm_exit_fp),
1228             usize::from(offsets.ptr.vmstore_context_last_wasm_exit_fp())
1229         );
1230         assert_eq!(
1231             offset_of!(VMStoreContext, last_wasm_exit_pc),
1232             usize::from(offsets.ptr.vmstore_context_last_wasm_exit_pc())
1233         );
1234         assert_eq!(
1235             offset_of!(VMStoreContext, last_wasm_entry_fp),
1236             usize::from(offsets.ptr.vmstore_context_last_wasm_entry_fp())
1237         );
1238         assert_eq!(
1239             offset_of!(VMStoreContext, stack_chain),
1240             usize::from(offsets.ptr.vmstore_context_stack_chain())
1241         )
1242     }
1243 }
1244 
1245 /// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
1246 /// This has information about globals, memories, tables, and other runtime
1247 /// state associated with the current instance.
1248 ///
1249 /// The struct here is empty, as the sizes of these fields are dynamic, and
1250 /// we can't describe them in Rust's type system. Sufficient memory is
1251 /// allocated at runtime.
1252 #[derive(Debug)]
1253 #[repr(C, align(16))] // align 16 since globals are aligned to that and contained inside
1254 pub struct VMContext {
1255     _magic: u32,
1256 }
1257 
1258 impl VMContext {
1259     /// Helper function to cast between context types using a debug assertion to
1260     /// protect against some mistakes.
1261     #[inline]
1262     pub unsafe fn from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMContext> {
1263         // Note that in general the offset of the "magic" field is stored in
1264         // `VMOffsets::vmctx_magic`. Given though that this is a sanity check
1265         // about converting this pointer to another type we ideally don't want
1266         // to read the offset from potentially corrupt memory. Instead it would
1267         // be better to catch errors here as soon as possible.
1268         //
1269         // To accomplish this the `VMContext` structure is laid out with the
1270         // magic field at a statically known offset (here it's 0 for now). This
1271         // static offset is asserted in `VMOffsets::from` and needs to be kept
1272         // in sync with this line for this debug assertion to work.
1273         //
1274         // Also note that this magic is only ever invalid in the presence of
1275         // bugs, meaning we don't actually read the magic and act differently
1276         // at runtime depending what it is, so this is a debug assertion as
1277         // opposed to a regular assertion.
1278         unsafe {
1279             debug_assert_eq!(opaque.as_ref().magic, VMCONTEXT_MAGIC);
1280         }
1281         opaque.cast()
1282     }
1283 }
1284 
1285 /// A "raw" and unsafe representation of a WebAssembly value.
1286 ///
1287 /// This is provided for use with the `Func::new_unchecked` and
1288 /// `Func::call_unchecked` APIs. In general it's unlikely you should be using
1289 /// this from Rust, rather using APIs like `Func::wrap` and `TypedFunc::call`.
1290 ///
1291 /// This is notably an "unsafe" way to work with `Val` and it's recommended to
1292 /// instead use `Val` where possible. An important note about this union is that
1293 /// fields are all stored in little-endian format, regardless of the endianness
1294 /// of the host system.
1295 #[repr(C)]
1296 #[derive(Copy, Clone)]
1297 pub union ValRaw {
1298     /// A WebAssembly `i32` value.
1299     ///
1300     /// Note that the payload here is a Rust `i32` but the WebAssembly `i32`
1301     /// type does not assign an interpretation of the upper bit as either signed
1302     /// or unsigned. The Rust type `i32` is simply chosen for convenience.
1303     ///
1304     /// This value is always stored in a little-endian format.
1305     i32: i32,
1306 
1307     /// A WebAssembly `i64` value.
1308     ///
1309     /// Note that the payload here is a Rust `i64` but the WebAssembly `i64`
1310     /// type does not assign an interpretation of the upper bit as either signed
1311     /// or unsigned. The Rust type `i64` is simply chosen for convenience.
1312     ///
1313     /// This value is always stored in a little-endian format.
1314     i64: i64,
1315 
1316     /// A WebAssembly `f32` value.
1317     ///
1318     /// Note that the payload here is a Rust `u32`. This is to allow passing any
1319     /// representation of NaN into WebAssembly without risk of changing NaN
1320     /// payload bits as its gets passed around the system. Otherwise though this
1321     /// `u32` value is the return value of `f32::to_bits` in Rust.
1322     ///
1323     /// This value is always stored in a little-endian format.
1324     f32: u32,
1325 
1326     /// A WebAssembly `f64` value.
1327     ///
1328     /// Note that the payload here is a Rust `u64`. This is to allow passing any
1329     /// representation of NaN into WebAssembly without risk of changing NaN
1330     /// payload bits as its gets passed around the system. Otherwise though this
1331     /// `u64` value is the return value of `f64::to_bits` in Rust.
1332     ///
1333     /// This value is always stored in a little-endian format.
1334     f64: u64,
1335 
1336     /// A WebAssembly `v128` value.
1337     ///
1338     /// The payload here is a Rust `[u8; 16]` which has the same number of bits
1339     /// but note that `v128` in WebAssembly is often considered a vector type
1340     /// such as `i32x4` or `f64x2`. This means that the actual interpretation
1341     /// of the underlying bits is left up to the instructions which consume
1342     /// this value.
1343     ///
1344     /// This value is always stored in a little-endian format.
1345     v128: [u8; 16],
1346 
1347     /// A WebAssembly `funcref` value (or one of its subtypes).
1348     ///
1349     /// The payload here is a pointer which is runtime-defined. This is one of
1350     /// the main points of unsafety about the `ValRaw` type as the validity of
1351     /// the pointer here is not easily verified and must be preserved by
1352     /// carefully calling the correct functions throughout the runtime.
1353     ///
1354     /// This value is always stored in a little-endian format.
1355     funcref: *mut c_void,
1356 
1357     /// A WebAssembly `externref` value (or one of its subtypes).
1358     ///
1359     /// The payload here is a compressed pointer value which is
1360     /// runtime-defined. This is one of the main points of unsafety about the
1361     /// `ValRaw` type as the validity of the pointer here is not easily verified
1362     /// and must be preserved by carefully calling the correct functions
1363     /// throughout the runtime.
1364     ///
1365     /// This value is always stored in a little-endian format.
1366     externref: u32,
1367 
1368     /// A WebAssembly `anyref` value (or one of its subtypes).
1369     ///
1370     /// The payload here is a compressed pointer value which is
1371     /// runtime-defined. This is one of the main points of unsafety about the
1372     /// `ValRaw` type as the validity of the pointer here is not easily verified
1373     /// and must be preserved by carefully calling the correct functions
1374     /// throughout the runtime.
1375     ///
1376     /// This value is always stored in a little-endian format.
1377     anyref: u32,
1378 
1379     /// A WebAssembly `exnref` value (or one of its subtypes).
1380     ///
1381     /// The payload here is a compressed pointer value which is
1382     /// runtime-defined. This is one of the main points of unsafety about the
1383     /// `ValRaw` type as the validity of the pointer here is not easily verified
1384     /// and must be preserved by carefully calling the correct functions
1385     /// throughout the runtime.
1386     ///
1387     /// This value is always stored in a little-endian format.
1388     exnref: u32,
1389 }
1390 
1391 // The `ValRaw` type is matched as `wasmtime_val_raw_t` in the C API so these
1392 // are some simple assertions about the shape of the type which are additionally
1393 // matched in C.
1394 const _: () = {
1395     assert!(mem::size_of::<ValRaw>() == 16);
1396     assert!(mem::align_of::<ValRaw>() == mem::align_of::<u64>());
1397 };
1398 
1399 // This type is just a bag-of-bits so it's up to the caller to figure out how
1400 // to safely deal with threading concerns and safely access interior bits.
1401 unsafe impl Send for ValRaw {}
1402 unsafe impl Sync for ValRaw {}
1403 
1404 impl fmt::Debug for ValRaw {
1405     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1406         struct Hex<T>(T);
1407         impl<T: fmt::LowerHex> fmt::Debug for Hex<T> {
1408             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1409                 let bytes = mem::size_of::<T>();
1410                 let hex_digits_per_byte = 2;
1411                 let hex_digits = bytes * hex_digits_per_byte;
1412                 write!(f, "0x{:0width$x}", self.0, width = hex_digits)
1413             }
1414         }
1415 
1416         unsafe {
1417             f.debug_struct("ValRaw")
1418                 .field("i32", &Hex(self.i32))
1419                 .field("i64", &Hex(self.i64))
1420                 .field("f32", &Hex(self.f32))
1421                 .field("f64", &Hex(self.f64))
1422                 .field("v128", &Hex(u128::from_le_bytes(self.v128)))
1423                 .field("funcref", &self.funcref)
1424                 .field("externref", &Hex(self.externref))
1425                 .field("anyref", &Hex(self.anyref))
1426                 .field("exnref", &Hex(self.exnref))
1427                 .finish()
1428         }
1429     }
1430 }
1431 
1432 impl ValRaw {
1433     /// Create a null reference that is compatible with any of
1434     /// `{any,extern,func,exn}ref`.
1435     pub fn null() -> ValRaw {
1436         unsafe {
1437             let raw = mem::MaybeUninit::<Self>::zeroed().assume_init();
1438             debug_assert_eq!(raw.get_anyref(), 0);
1439             debug_assert_eq!(raw.get_exnref(), 0);
1440             debug_assert_eq!(raw.get_externref(), 0);
1441             debug_assert_eq!(raw.get_funcref(), ptr::null_mut());
1442             raw
1443         }
1444     }
1445 
1446     /// Creates a WebAssembly `i32` value
1447     #[inline]
1448     pub fn i32(i: i32) -> ValRaw {
1449         // Note that this is intentionally not setting the `i32` field, instead
1450         // setting the `i64` field with a zero-extended version of `i`. For more
1451         // information on this see the comments on `Lower for Result` in the
1452         // `wasmtime` crate. Otherwise though all `ValRaw` constructors are
1453         // otherwise constrained to guarantee that the initial 64-bits are
1454         // always initialized.
1455         ValRaw::u64(i.cast_unsigned().into())
1456     }
1457 
1458     /// Creates a WebAssembly `i64` value
1459     #[inline]
1460     pub fn i64(i: i64) -> ValRaw {
1461         ValRaw { i64: i.to_le() }
1462     }
1463 
1464     /// Creates a WebAssembly `i32` value
1465     #[inline]
1466     pub fn u32(i: u32) -> ValRaw {
1467         // See comments in `ValRaw::i32` for why this is setting the upper
1468         // 32-bits as well.
1469         ValRaw::u64(i.into())
1470     }
1471 
1472     /// Creates a WebAssembly `i64` value
1473     #[inline]
1474     pub fn u64(i: u64) -> ValRaw {
1475         ValRaw::i64(i as i64)
1476     }
1477 
1478     /// Creates a WebAssembly `f32` value
1479     #[inline]
1480     pub fn f32(i: u32) -> ValRaw {
1481         // See comments in `ValRaw::i32` for why this is setting the upper
1482         // 32-bits as well.
1483         ValRaw::u64(i.into())
1484     }
1485 
1486     /// Creates a WebAssembly `f64` value
1487     #[inline]
1488     pub fn f64(i: u64) -> ValRaw {
1489         ValRaw { f64: i.to_le() }
1490     }
1491 
1492     /// Creates a WebAssembly `v128` value
1493     #[inline]
1494     pub fn v128(i: u128) -> ValRaw {
1495         ValRaw {
1496             v128: i.to_le_bytes(),
1497         }
1498     }
1499 
1500     /// Creates a WebAssembly `funcref` value
1501     #[inline]
1502     pub fn funcref(i: *mut c_void) -> ValRaw {
1503         ValRaw {
1504             funcref: i.map_addr(|i| i.to_le()),
1505         }
1506     }
1507 
1508     /// Creates a WebAssembly `externref` value
1509     #[inline]
1510     pub fn externref(e: u32) -> ValRaw {
1511         assert!(cfg!(feature = "gc") || e == 0);
1512         ValRaw {
1513             externref: e.to_le(),
1514         }
1515     }
1516 
1517     /// Creates a WebAssembly `anyref` value
1518     #[inline]
1519     pub fn anyref(r: u32) -> ValRaw {
1520         assert!(cfg!(feature = "gc") || r == 0);
1521         ValRaw { anyref: r.to_le() }
1522     }
1523 
1524     /// Creates a WebAssembly `exnref` value
1525     #[inline]
1526     pub fn exnref(r: u32) -> ValRaw {
1527         assert!(cfg!(feature = "gc") || r == 0);
1528         ValRaw { exnref: r.to_le() }
1529     }
1530 
1531     /// Gets the WebAssembly `i32` value
1532     #[inline]
1533     pub fn get_i32(&self) -> i32 {
1534         unsafe { i32::from_le(self.i32) }
1535     }
1536 
1537     /// Gets the WebAssembly `i64` value
1538     #[inline]
1539     pub fn get_i64(&self) -> i64 {
1540         unsafe { i64::from_le(self.i64) }
1541     }
1542 
1543     /// Gets the WebAssembly `i32` value
1544     #[inline]
1545     pub fn get_u32(&self) -> u32 {
1546         self.get_i32().cast_unsigned()
1547     }
1548 
1549     /// Gets the WebAssembly `i64` value
1550     #[inline]
1551     pub fn get_u64(&self) -> u64 {
1552         self.get_i64().cast_unsigned()
1553     }
1554 
1555     /// Gets the WebAssembly `f32` value
1556     #[inline]
1557     pub fn get_f32(&self) -> u32 {
1558         unsafe { u32::from_le(self.f32) }
1559     }
1560 
1561     /// Gets the WebAssembly `f64` value
1562     #[inline]
1563     pub fn get_f64(&self) -> u64 {
1564         unsafe { u64::from_le(self.f64) }
1565     }
1566 
1567     /// Gets the WebAssembly `v128` value
1568     #[inline]
1569     pub fn get_v128(&self) -> u128 {
1570         unsafe { u128::from_le_bytes(self.v128) }
1571     }
1572 
1573     /// Gets the WebAssembly `funcref` value
1574     #[inline]
1575     pub fn get_funcref(&self) -> *mut c_void {
1576         unsafe { self.funcref.map_addr(|i| usize::from_le(i)) }
1577     }
1578 
1579     /// Gets the WebAssembly `externref` value
1580     #[inline]
1581     pub fn get_externref(&self) -> u32 {
1582         let externref = u32::from_le(unsafe { self.externref });
1583         assert!(cfg!(feature = "gc") || externref == 0);
1584         externref
1585     }
1586 
1587     /// Gets the WebAssembly `anyref` value
1588     #[inline]
1589     pub fn get_anyref(&self) -> u32 {
1590         let anyref = u32::from_le(unsafe { self.anyref });
1591         assert!(cfg!(feature = "gc") || anyref == 0);
1592         anyref
1593     }
1594 
1595     /// Gets the WebAssembly `exnref` value
1596     #[inline]
1597     pub fn get_exnref(&self) -> u32 {
1598         let exnref = u32::from_le(unsafe { self.exnref });
1599         assert!(cfg!(feature = "gc") || exnref == 0);
1600         exnref
1601     }
1602 }
1603 
1604 /// An "opaque" version of `VMContext` which must be explicitly casted to a
1605 /// target context.
1606 ///
1607 /// This context is used to represent that contexts specified in
1608 /// `VMFuncRef` can have any type and don't have an implicit
1609 /// structure. Neither wasmtime nor cranelift-generated code can rely on the
1610 /// structure of an opaque context in general and only the code which configured
1611 /// the context is able to rely on a particular structure. This is because the
1612 /// context pointer configured for `VMFuncRef` is guaranteed to be
1613 /// the first parameter passed.
1614 ///
1615 /// Note that Wasmtime currently has a layout where all contexts that are casted
1616 /// to an opaque context start with a 32-bit "magic" which can be used in debug
1617 /// mode to debug-assert that the casts here are correct and have at least a
1618 /// little protection against incorrect casts.
1619 pub struct VMOpaqueContext {
1620     pub(crate) magic: u32,
1621     _marker: marker::PhantomPinned,
1622 }
1623 
1624 impl VMOpaqueContext {
1625     /// Helper function to clearly indicate that casts are desired.
1626     #[inline]
1627     pub fn from_vmcontext(ptr: NonNull<VMContext>) -> NonNull<VMOpaqueContext> {
1628         ptr.cast()
1629     }
1630 
1631     /// Helper function to clearly indicate that casts are desired.
1632     #[inline]
1633     pub fn from_vm_array_call_host_func_context(
1634         ptr: NonNull<VMArrayCallHostFuncContext>,
1635     ) -> NonNull<VMOpaqueContext> {
1636         ptr.cast()
1637     }
1638 }
1639