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::{GcStore, 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, Unsigned, 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.gc_store_mut()?, r.as_ref())
564                     }
565                     WasmHeapTopType::Any => {
566                         let r = VMGcRef::from_raw_u32(raw.get_anyref());
567                         global.init_gc_ref(store.gc_store_mut()?, 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.gc_store_mut()?, 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.gc_store_mut()?.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.gc_store_mut()?.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.gc_store_mut()?.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, gc_store: &mut GcStore, gc_ref: Option<&VMGcRef>) {
740         assert!(cfg!(feature = "gc") || gc_ref.is_none());
741 
742         let dest = unsafe {
743             &mut *(self
744                 .storage
745                 .as_mut()
746                 .as_mut_ptr()
747                 .cast::<MaybeUninit<Option<VMGcRef>>>())
748         };
749 
750         gc_store.init_gc_ref(dest, gc_ref)
751     }
752 
753     /// Write a GC reference into this global value.
754     pub unsafe fn write_gc_ref(&mut self, gc_store: &mut GcStore, gc_ref: Option<&VMGcRef>) {
755         assert!(cfg!(feature = "gc") || gc_ref.is_none());
756 
757         let dest = unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<Option<VMGcRef>>()) };
758         assert!(cfg!(feature = "gc") || dest.is_none());
759 
760         gc_store.write_gc_ref(dest, gc_ref)
761     }
762 
763     /// Return a reference to the value as a `VMFuncRef`.
764     pub unsafe fn as_func_ref(&self) -> *mut VMFuncRef {
765         unsafe { *(self.storage.as_ref().as_ptr().cast::<*mut VMFuncRef>()) }
766     }
767 
768     /// Return a mutable reference to the value as a `VMFuncRef`.
769     pub unsafe fn as_func_ref_mut(&mut self) -> &mut *mut VMFuncRef {
770         unsafe { &mut *(self.storage.as_mut().as_mut_ptr().cast::<*mut VMFuncRef>()) }
771     }
772 }
773 
774 #[cfg(test)]
775 mod test_vmshared_type_index {
776     use super::VMSharedTypeIndex;
777     use std::mem::size_of;
778     use wasmtime_environ::{HostPtr, Module, VMOffsets};
779 
780     #[test]
781     fn check_vmshared_type_index() {
782         let module = Module::new();
783         let offsets = VMOffsets::new(HostPtr, &module);
784         assert_eq!(
785             size_of::<VMSharedTypeIndex>(),
786             usize::from(offsets.size_of_vmshared_type_index())
787         );
788     }
789 }
790 
791 /// A WebAssembly tag defined within the instance.
792 ///
793 #[derive(Debug)]
794 #[repr(C)]
795 pub struct VMTagDefinition {
796     /// Function signature's type id.
797     pub type_index: VMSharedTypeIndex,
798 }
799 
800 impl VMTagDefinition {
801     pub fn new(type_index: VMSharedTypeIndex) -> Self {
802         Self { type_index }
803     }
804 }
805 
806 // SAFETY: the above structure is repr(C) and only contains VmSafe
807 // fields.
808 unsafe impl VmSafe for VMTagDefinition {}
809 
810 #[cfg(test)]
811 mod test_vmtag_definition {
812     use super::VMTagDefinition;
813     use std::mem::size_of;
814     use wasmtime_environ::{HostPtr, Module, PtrSize, VMOffsets};
815 
816     #[test]
817     fn check_vmtag_definition_offsets() {
818         let module = Module::new();
819         let offsets = VMOffsets::new(HostPtr, &module);
820         assert_eq!(
821             size_of::<VMTagDefinition>(),
822             usize::from(offsets.ptr.size_of_vmtag_definition())
823         );
824     }
825 
826     #[test]
827     fn check_vmtag_begins_aligned() {
828         let module = Module::new();
829         let offsets = VMOffsets::new(HostPtr, &module);
830         assert_eq!(offsets.vmctx_tags_begin() % 16, 0);
831     }
832 }
833 
834 /// The VM caller-checked "funcref" record, for caller-side signature checking.
835 ///
836 /// It consists of function pointer(s), a type id to be checked by the
837 /// caller, and the vmctx closure associated with this function.
838 #[derive(Debug, Clone)]
839 #[repr(C)]
840 pub struct VMFuncRef {
841     /// Function pointer for this funcref if being called via the "array"
842     /// calling convention that `Func::new` et al use.
843     pub array_call: VmPtr<VMArrayCallFunction>,
844 
845     /// Function pointer for this funcref if being called via the calling
846     /// convention we use when compiling Wasm.
847     ///
848     /// Most functions come with a function pointer that we can use when they
849     /// are called from Wasm. The notable exception is when we `Func::wrap` a
850     /// host function, and we don't have a Wasm compiler on hand to compile a
851     /// Wasm-to-native trampoline for the function. In this case, we leave
852     /// `wasm_call` empty until the function is passed as an import to Wasm (or
853     /// otherwise exposed to Wasm via tables/globals). At this point, we look up
854     /// a Wasm-to-native trampoline for the function in the Wasm's compiled
855     /// module and use that fill in `VMFunctionImport::wasm_call`. **However**
856     /// there is no guarantee that the Wasm module has a trampoline for this
857     /// function's signature. The Wasm module only has trampolines for its
858     /// types, and if this function isn't of one of those types, then the Wasm
859     /// module will not have a trampoline for it. This is actually okay, because
860     /// it means that the Wasm cannot actually call this function. But it does
861     /// mean that this field needs to be an `Option` even though it is non-null
862     /// the vast vast vast majority of the time.
863     pub wasm_call: Option<VmPtr<VMWasmCallFunction>>,
864 
865     /// Function signature's type id.
866     pub type_index: VMSharedTypeIndex,
867 
868     /// The VM state associated with this function.
869     ///
870     /// The actual definition of what this pointer points to depends on the
871     /// function being referenced: for core Wasm functions, this is a `*mut
872     /// VMContext`, for host functions it is a `*mut VMHostFuncContext`, and for
873     /// component functions it is a `*mut VMComponentContext`.
874     pub vmctx: VmPtr<VMOpaqueContext>,
875     // If more elements are added here, remember to add offset_of tests below!
876 }
877 
878 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
879 unsafe impl VmSafe for VMFuncRef {}
880 
881 impl VMFuncRef {
882     /// Invokes the `array_call` field of this `VMFuncRef` with the supplied
883     /// arguments.
884     ///
885     /// This will invoke the function pointer in the `array_call` field with:
886     ///
887     /// * the `callee` vmctx as `self.vmctx`
888     /// * the `caller` as `caller` specified here
889     /// * the args pointer as `args_and_results`
890     /// * the args length as `args_and_results`
891     ///
892     /// The `args_and_results` area must be large enough to both load all
893     /// arguments from and store all results to.
894     ///
895     /// Returns whether a trap was recorded in TLS for raising.
896     ///
897     /// # Unsafety
898     ///
899     /// This method is unsafe because it can be called with any pointers. They
900     /// must all be valid for this wasm function call to proceed. For example
901     /// the `caller` must be valid machine code if `pulley` is `None` or it must
902     /// be valid bytecode if `pulley` is `Some`. Additionally `args_and_results`
903     /// must be large enough to handle all the arguments/results for this call.
904     ///
905     /// Note that the unsafety invariants to maintain here are not currently
906     /// exhaustively documented.
907     #[inline]
908     pub unsafe fn array_call(
909         me: NonNull<VMFuncRef>,
910         pulley: Option<InterpreterRef<'_>>,
911         caller: NonNull<VMContext>,
912         args_and_results: NonNull<[ValRaw]>,
913     ) -> bool {
914         match pulley {
915             Some(vm) => unsafe { Self::array_call_interpreted(me, vm, caller, args_and_results) },
916             None => unsafe { Self::array_call_native(me, caller, args_and_results) },
917         }
918     }
919 
920     unsafe fn array_call_interpreted(
921         me: NonNull<VMFuncRef>,
922         vm: InterpreterRef<'_>,
923         caller: NonNull<VMContext>,
924         args_and_results: NonNull<[ValRaw]>,
925     ) -> bool {
926         // If `caller` is actually a `VMArrayCallHostFuncContext` then skip the
927         // interpreter, even though it's available, as `array_call` will be
928         // native code.
929         unsafe {
930             if me.as_ref().vmctx.as_non_null().as_ref().magic
931                 == wasmtime_environ::VM_ARRAY_CALL_HOST_FUNC_MAGIC
932             {
933                 return Self::array_call_native(me, caller, args_and_results);
934             }
935             vm.call(
936                 me.as_ref().array_call.as_non_null().cast(),
937                 me.as_ref().vmctx.as_non_null(),
938                 caller,
939                 args_and_results,
940             )
941         }
942     }
943 
944     #[inline]
945     unsafe fn array_call_native(
946         me: NonNull<VMFuncRef>,
947         caller: NonNull<VMContext>,
948         args_and_results: NonNull<[ValRaw]>,
949     ) -> bool {
950         unsafe {
951             union GetNativePointer {
952                 native: VMArrayCallNative,
953                 ptr: NonNull<VMArrayCallFunction>,
954             }
955             let native = GetNativePointer {
956                 ptr: me.as_ref().array_call.as_non_null(),
957             }
958             .native;
959             native(
960                 me.as_ref().vmctx.as_non_null(),
961                 caller,
962                 args_and_results.cast(),
963                 args_and_results.len(),
964             )
965         }
966     }
967 }
968 
969 #[cfg(test)]
970 mod test_vm_func_ref {
971     use super::VMFuncRef;
972     use core::mem::offset_of;
973     use std::mem::size_of;
974     use wasmtime_environ::{HostPtr, Module, PtrSize, VMOffsets};
975 
976     #[test]
977     fn check_vm_func_ref_offsets() {
978         let module = Module::new();
979         let offsets = VMOffsets::new(HostPtr, &module);
980         assert_eq!(
981             size_of::<VMFuncRef>(),
982             usize::from(offsets.ptr.size_of_vm_func_ref())
983         );
984         assert_eq!(
985             offset_of!(VMFuncRef, array_call),
986             usize::from(offsets.ptr.vm_func_ref_array_call())
987         );
988         assert_eq!(
989             offset_of!(VMFuncRef, wasm_call),
990             usize::from(offsets.ptr.vm_func_ref_wasm_call())
991         );
992         assert_eq!(
993             offset_of!(VMFuncRef, type_index),
994             usize::from(offsets.ptr.vm_func_ref_type_index())
995         );
996         assert_eq!(
997             offset_of!(VMFuncRef, vmctx),
998             usize::from(offsets.ptr.vm_func_ref_vmctx())
999         );
1000     }
1001 }
1002 
1003 macro_rules! define_builtin_array {
1004     (
1005         $(
1006             $( #[$attr:meta] )*
1007             $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
1008         )*
1009     ) => {
1010         /// An array that stores addresses of builtin functions. We translate code
1011         /// to use indirect calls. This way, we don't have to patch the code.
1012         #[repr(C)]
1013         #[allow(improper_ctypes_definitions, reason = "__m128i known not FFI-safe")]
1014         pub struct VMBuiltinFunctionsArray {
1015             $(
1016                 $name: unsafe extern "C" fn(
1017                     $(define_builtin_array!(@ty $param)),*
1018                 ) $( -> define_builtin_array!(@ty $result))?,
1019             )*
1020         }
1021 
1022         impl VMBuiltinFunctionsArray {
1023             pub const INIT: VMBuiltinFunctionsArray = VMBuiltinFunctionsArray {
1024                 $(
1025                     $name: crate::runtime::vm::libcalls::raw::$name,
1026                 )*
1027             };
1028 
1029             /// Helper to call `expose_provenance()` on all contained pointers.
1030             ///
1031             /// This is required to be called at least once before entering wasm
1032             /// to inform the compiler that these function pointers may all be
1033             /// loaded/stored and used on the "other end" to reacquire
1034             /// provenance in Pulley. Pulley models hostcalls with a host
1035             /// pointer as the first parameter that's a function pointer under
1036             /// the hood, and this call ensures that the use of the function
1037             /// pointer is considered valid.
1038             pub fn expose_provenance(&self) -> NonNull<Self>{
1039                 $(
1040                     (self.$name as *mut u8).expose_provenance();
1041                 )*
1042                 NonNull::from(self)
1043             }
1044         }
1045     };
1046 
1047     (@ty u32) => (u32);
1048     (@ty u64) => (u64);
1049     (@ty f32) => (f32);
1050     (@ty f64) => (f64);
1051     (@ty u8) => (u8);
1052     (@ty i8x16) => (i8x16);
1053     (@ty f32x4) => (f32x4);
1054     (@ty f64x2) => (f64x2);
1055     (@ty bool) => (bool);
1056     (@ty pointer) => (*mut u8);
1057     (@ty vmctx) => (NonNull<VMContext>);
1058 }
1059 
1060 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
1061 unsafe impl VmSafe for VMBuiltinFunctionsArray {}
1062 
1063 wasmtime_environ::foreach_builtin_function!(define_builtin_array);
1064 
1065 const _: () = {
1066     assert!(
1067         mem::size_of::<VMBuiltinFunctionsArray>()
1068             == mem::size_of::<usize>() * (BuiltinFunctionIndex::len() as usize)
1069     )
1070 };
1071 
1072 /// Structure that holds all mutable context that is shared across all instances
1073 /// in a store, for example data related to fuel or epochs.
1074 ///
1075 /// `VMStoreContext`s are one-to-one with `wasmtime::Store`s, the same way that
1076 /// `VMContext`s are one-to-one with `wasmtime::Instance`s. And the same way
1077 /// that multiple `wasmtime::Instance`s may be associated with the same
1078 /// `wasmtime::Store`, multiple `VMContext`s hold a pointer to the same
1079 /// `VMStoreContext` when they are associated with the same `wasmtime::Store`.
1080 #[derive(Debug)]
1081 #[repr(C)]
1082 pub struct VMStoreContext {
1083     // NB: 64-bit integer fields are located first with pointer-sized fields
1084     // trailing afterwards. That makes the offsets in this structure easier to
1085     // calculate on 32-bit platforms as we don't have to worry about the
1086     // alignment of 64-bit integers.
1087     //
1088     /// Indicator of how much fuel has been consumed and is remaining to
1089     /// WebAssembly.
1090     ///
1091     /// This field is typically negative and increments towards positive. Upon
1092     /// turning positive a wasm trap will be generated. This field is only
1093     /// modified if wasm is configured to consume fuel.
1094     pub fuel_consumed: UnsafeCell<i64>,
1095 
1096     /// Deadline epoch for interruption: if epoch-based interruption
1097     /// is enabled and the global (per engine) epoch counter is
1098     /// observed to reach or exceed this value, the guest code will
1099     /// yield if running asynchronously.
1100     pub epoch_deadline: UnsafeCell<u64>,
1101 
1102     /// Current stack limit of the wasm module.
1103     ///
1104     /// For more information see `crates/cranelift/src/lib.rs`.
1105     pub stack_limit: UnsafeCell<usize>,
1106 
1107     /// The `VMMemoryDefinition` for this store's GC heap.
1108     pub gc_heap: VMMemoryDefinition,
1109 
1110     /// The value of the frame pointer register when we last called from Wasm to
1111     /// the host.
1112     ///
1113     /// Maintained by our Wasm-to-host trampoline, and cleared just before
1114     /// calling into Wasm in `catch_traps`.
1115     ///
1116     /// This member is `0` when Wasm is actively running and has not called out
1117     /// to the host.
1118     ///
1119     /// Used to find the start of a contiguous sequence of Wasm frames when
1120     /// walking the stack.
1121     pub last_wasm_exit_fp: UnsafeCell<usize>,
1122 
1123     /// The last Wasm program counter before we called from Wasm to the host.
1124     ///
1125     /// Maintained by our Wasm-to-host trampoline, and cleared just before
1126     /// calling into Wasm in `catch_traps`.
1127     ///
1128     /// This member is `0` when Wasm is actively running and has not called out
1129     /// to the host.
1130     ///
1131     /// Used when walking a contiguous sequence of Wasm frames.
1132     pub last_wasm_exit_pc: UnsafeCell<usize>,
1133 
1134     /// The last host stack pointer before we called into Wasm from the host.
1135     ///
1136     /// Maintained by our host-to-Wasm trampoline, and cleared just before
1137     /// calling into Wasm in `catch_traps`.
1138     ///
1139     /// This member is `0` when Wasm is actively running and has not called out
1140     /// to the host.
1141     ///
1142     /// When a host function is wrapped into a `wasmtime::Func`, and is then
1143     /// called from the host, then this member has the sentinel value of `-1 as
1144     /// usize`, meaning that this contiguous sequence of Wasm frames is the
1145     /// empty sequence, and it is not safe to dereference the
1146     /// `last_wasm_exit_fp`.
1147     ///
1148     /// Used to find the end of a contiguous sequence of Wasm frames when
1149     /// walking the stack.
1150     pub last_wasm_entry_fp: UnsafeCell<usize>,
1151 
1152     /// Stack information used by stack switching instructions. See documentation
1153     /// on `VMStackChain` for details.
1154     pub stack_chain: UnsafeCell<VMStackChain>,
1155 
1156     /// The range, in addresses, of the guard page that is currently in use.
1157     ///
1158     /// This field is used when signal handlers are run to determine whether a
1159     /// faulting address lies within the guard page of an async stack for
1160     /// example. If this happens then the signal handler aborts with a stack
1161     /// overflow message similar to what would happen had the stack overflow
1162     /// happened on the main thread. This field is, by default a null..null
1163     /// range indicating that no async guard is in use (aka no fiber). In such a
1164     /// situation while this field is read it'll never classify a fault as an
1165     /// guard page fault.
1166     pub async_guard_range: Range<*mut u8>,
1167 }
1168 
1169 // The `VMStoreContext` type is a pod-type with no destructor, and we don't
1170 // access any fields from other threads, so add in these trait impls which are
1171 // otherwise not available due to the `fuel_consumed` and `epoch_deadline`
1172 // variables in `VMStoreContext`.
1173 unsafe impl Send for VMStoreContext {}
1174 unsafe impl Sync for VMStoreContext {}
1175 
1176 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
1177 unsafe impl VmSafe for VMStoreContext {}
1178 
1179 impl Default for VMStoreContext {
1180     fn default() -> VMStoreContext {
1181         VMStoreContext {
1182             fuel_consumed: UnsafeCell::new(0),
1183             epoch_deadline: UnsafeCell::new(0),
1184             stack_limit: UnsafeCell::new(usize::max_value()),
1185             gc_heap: VMMemoryDefinition {
1186                 base: NonNull::dangling().into(),
1187                 current_length: AtomicUsize::new(0),
1188             },
1189             last_wasm_exit_fp: UnsafeCell::new(0),
1190             last_wasm_exit_pc: UnsafeCell::new(0),
1191             last_wasm_entry_fp: UnsafeCell::new(0),
1192             stack_chain: UnsafeCell::new(VMStackChain::Absent),
1193             async_guard_range: ptr::null_mut()..ptr::null_mut(),
1194         }
1195     }
1196 }
1197 
1198 #[cfg(test)]
1199 mod test_vmstore_context {
1200     use super::{VMMemoryDefinition, VMStoreContext};
1201     use core::mem::offset_of;
1202     use wasmtime_environ::{HostPtr, Module, PtrSize, VMOffsets};
1203 
1204     #[test]
1205     fn field_offsets() {
1206         let module = Module::new();
1207         let offsets = VMOffsets::new(HostPtr, &module);
1208         assert_eq!(
1209             offset_of!(VMStoreContext, stack_limit),
1210             usize::from(offsets.ptr.vmstore_context_stack_limit())
1211         );
1212         assert_eq!(
1213             offset_of!(VMStoreContext, fuel_consumed),
1214             usize::from(offsets.ptr.vmstore_context_fuel_consumed())
1215         );
1216         assert_eq!(
1217             offset_of!(VMStoreContext, epoch_deadline),
1218             usize::from(offsets.ptr.vmstore_context_epoch_deadline())
1219         );
1220         assert_eq!(
1221             offset_of!(VMStoreContext, gc_heap),
1222             usize::from(offsets.ptr.vmstore_context_gc_heap())
1223         );
1224         assert_eq!(
1225             offset_of!(VMStoreContext, gc_heap) + offset_of!(VMMemoryDefinition, base),
1226             usize::from(offsets.ptr.vmstore_context_gc_heap_base())
1227         );
1228         assert_eq!(
1229             offset_of!(VMStoreContext, gc_heap) + offset_of!(VMMemoryDefinition, current_length),
1230             usize::from(offsets.ptr.vmstore_context_gc_heap_current_length())
1231         );
1232         assert_eq!(
1233             offset_of!(VMStoreContext, last_wasm_exit_fp),
1234             usize::from(offsets.ptr.vmstore_context_last_wasm_exit_fp())
1235         );
1236         assert_eq!(
1237             offset_of!(VMStoreContext, last_wasm_exit_pc),
1238             usize::from(offsets.ptr.vmstore_context_last_wasm_exit_pc())
1239         );
1240         assert_eq!(
1241             offset_of!(VMStoreContext, last_wasm_entry_fp),
1242             usize::from(offsets.ptr.vmstore_context_last_wasm_entry_fp())
1243         );
1244         assert_eq!(
1245             offset_of!(VMStoreContext, stack_chain),
1246             usize::from(offsets.ptr.vmstore_context_stack_chain())
1247         )
1248     }
1249 }
1250 
1251 /// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
1252 /// This has information about globals, memories, tables, and other runtime
1253 /// state associated with the current instance.
1254 ///
1255 /// The struct here is empty, as the sizes of these fields are dynamic, and
1256 /// we can't describe them in Rust's type system. Sufficient memory is
1257 /// allocated at runtime.
1258 #[derive(Debug)]
1259 #[repr(C, align(16))] // align 16 since globals are aligned to that and contained inside
1260 pub struct VMContext {
1261     _magic: u32,
1262 }
1263 
1264 impl VMContext {
1265     /// Helper function to cast between context types using a debug assertion to
1266     /// protect against some mistakes.
1267     #[inline]
1268     pub unsafe fn from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMContext> {
1269         // Note that in general the offset of the "magic" field is stored in
1270         // `VMOffsets::vmctx_magic`. Given though that this is a sanity check
1271         // about converting this pointer to another type we ideally don't want
1272         // to read the offset from potentially corrupt memory. Instead it would
1273         // be better to catch errors here as soon as possible.
1274         //
1275         // To accomplish this the `VMContext` structure is laid out with the
1276         // magic field at a statically known offset (here it's 0 for now). This
1277         // static offset is asserted in `VMOffsets::from` and needs to be kept
1278         // in sync with this line for this debug assertion to work.
1279         //
1280         // Also note that this magic is only ever invalid in the presence of
1281         // bugs, meaning we don't actually read the magic and act differently
1282         // at runtime depending what it is, so this is a debug assertion as
1283         // opposed to a regular assertion.
1284         unsafe {
1285             debug_assert_eq!(opaque.as_ref().magic, VMCONTEXT_MAGIC);
1286         }
1287         opaque.cast()
1288     }
1289 }
1290 
1291 /// A "raw" and unsafe representation of a WebAssembly value.
1292 ///
1293 /// This is provided for use with the `Func::new_unchecked` and
1294 /// `Func::call_unchecked` APIs. In general it's unlikely you should be using
1295 /// this from Rust, rather using APIs like `Func::wrap` and `TypedFunc::call`.
1296 ///
1297 /// This is notably an "unsafe" way to work with `Val` and it's recommended to
1298 /// instead use `Val` where possible. An important note about this union is that
1299 /// fields are all stored in little-endian format, regardless of the endianness
1300 /// of the host system.
1301 #[repr(C)]
1302 #[derive(Copy, Clone)]
1303 pub union ValRaw {
1304     /// A WebAssembly `i32` value.
1305     ///
1306     /// Note that the payload here is a Rust `i32` but the WebAssembly `i32`
1307     /// type does not assign an interpretation of the upper bit as either signed
1308     /// or unsigned. The Rust type `i32` is simply chosen for convenience.
1309     ///
1310     /// This value is always stored in a little-endian format.
1311     i32: i32,
1312 
1313     /// A WebAssembly `i64` value.
1314     ///
1315     /// Note that the payload here is a Rust `i64` but the WebAssembly `i64`
1316     /// type does not assign an interpretation of the upper bit as either signed
1317     /// or unsigned. The Rust type `i64` is simply chosen for convenience.
1318     ///
1319     /// This value is always stored in a little-endian format.
1320     i64: i64,
1321 
1322     /// A WebAssembly `f32` value.
1323     ///
1324     /// Note that the payload here is a Rust `u32`. This is to allow passing any
1325     /// representation of NaN into WebAssembly without risk of changing NaN
1326     /// payload bits as its gets passed around the system. Otherwise though this
1327     /// `u32` value is the return value of `f32::to_bits` in Rust.
1328     ///
1329     /// This value is always stored in a little-endian format.
1330     f32: u32,
1331 
1332     /// A WebAssembly `f64` value.
1333     ///
1334     /// Note that the payload here is a Rust `u64`. This is to allow passing any
1335     /// representation of NaN into WebAssembly without risk of changing NaN
1336     /// payload bits as its gets passed around the system. Otherwise though this
1337     /// `u64` value is the return value of `f64::to_bits` in Rust.
1338     ///
1339     /// This value is always stored in a little-endian format.
1340     f64: u64,
1341 
1342     /// A WebAssembly `v128` value.
1343     ///
1344     /// The payload here is a Rust `[u8; 16]` which has the same number of bits
1345     /// but note that `v128` in WebAssembly is often considered a vector type
1346     /// such as `i32x4` or `f64x2`. This means that the actual interpretation
1347     /// of the underlying bits is left up to the instructions which consume
1348     /// this value.
1349     ///
1350     /// This value is always stored in a little-endian format.
1351     v128: [u8; 16],
1352 
1353     /// A WebAssembly `funcref` value (or one of its subtypes).
1354     ///
1355     /// The payload here is a pointer which is runtime-defined. This is one of
1356     /// the main points of unsafety about the `ValRaw` type as the validity of
1357     /// the pointer here is not easily verified and must be preserved by
1358     /// carefully calling the correct functions throughout the runtime.
1359     ///
1360     /// This value is always stored in a little-endian format.
1361     funcref: *mut c_void,
1362 
1363     /// A WebAssembly `externref` value (or one of its subtypes).
1364     ///
1365     /// The payload here is a compressed pointer value which is
1366     /// runtime-defined. This is one of the main points of unsafety about the
1367     /// `ValRaw` type as the validity of the pointer here is not easily verified
1368     /// and must be preserved by carefully calling the correct functions
1369     /// throughout the runtime.
1370     ///
1371     /// This value is always stored in a little-endian format.
1372     externref: u32,
1373 
1374     /// A WebAssembly `anyref` value (or one of its subtypes).
1375     ///
1376     /// The payload here is a compressed pointer value which is
1377     /// runtime-defined. This is one of the main points of unsafety about the
1378     /// `ValRaw` type as the validity of the pointer here is not easily verified
1379     /// and must be preserved by carefully calling the correct functions
1380     /// throughout the runtime.
1381     ///
1382     /// This value is always stored in a little-endian format.
1383     anyref: u32,
1384 
1385     /// A WebAssembly `exnref` value (or one of its subtypes).
1386     ///
1387     /// The payload here is a compressed pointer value which is
1388     /// runtime-defined. This is one of the main points of unsafety about the
1389     /// `ValRaw` type as the validity of the pointer here is not easily verified
1390     /// and must be preserved by carefully calling the correct functions
1391     /// throughout the runtime.
1392     ///
1393     /// This value is always stored in a little-endian format.
1394     exnref: u32,
1395 }
1396 
1397 // The `ValRaw` type is matched as `wasmtime_val_raw_t` in the C API so these
1398 // are some simple assertions about the shape of the type which are additionally
1399 // matched in C.
1400 const _: () = {
1401     assert!(mem::size_of::<ValRaw>() == 16);
1402     assert!(mem::align_of::<ValRaw>() == mem::align_of::<u64>());
1403 };
1404 
1405 // This type is just a bag-of-bits so it's up to the caller to figure out how
1406 // to safely deal with threading concerns and safely access interior bits.
1407 unsafe impl Send for ValRaw {}
1408 unsafe impl Sync for ValRaw {}
1409 
1410 impl fmt::Debug for ValRaw {
1411     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1412         struct Hex<T>(T);
1413         impl<T: fmt::LowerHex> fmt::Debug for Hex<T> {
1414             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1415                 let bytes = mem::size_of::<T>();
1416                 let hex_digits_per_byte = 2;
1417                 let hex_digits = bytes * hex_digits_per_byte;
1418                 write!(f, "0x{:0width$x}", self.0, width = hex_digits)
1419             }
1420         }
1421 
1422         unsafe {
1423             f.debug_struct("ValRaw")
1424                 .field("i32", &Hex(self.i32))
1425                 .field("i64", &Hex(self.i64))
1426                 .field("f32", &Hex(self.f32))
1427                 .field("f64", &Hex(self.f64))
1428                 .field("v128", &Hex(u128::from_le_bytes(self.v128)))
1429                 .field("funcref", &self.funcref)
1430                 .field("externref", &Hex(self.externref))
1431                 .field("anyref", &Hex(self.anyref))
1432                 .field("exnref", &Hex(self.exnref))
1433                 .finish()
1434         }
1435     }
1436 }
1437 
1438 impl ValRaw {
1439     /// Create a null reference that is compatible with any of
1440     /// `{any,extern,func,exn}ref`.
1441     pub fn null() -> ValRaw {
1442         unsafe {
1443             let raw = mem::MaybeUninit::<Self>::zeroed().assume_init();
1444             debug_assert_eq!(raw.get_anyref(), 0);
1445             debug_assert_eq!(raw.get_exnref(), 0);
1446             debug_assert_eq!(raw.get_externref(), 0);
1447             debug_assert_eq!(raw.get_funcref(), ptr::null_mut());
1448             raw
1449         }
1450     }
1451 
1452     /// Creates a WebAssembly `i32` value
1453     #[inline]
1454     pub fn i32(i: i32) -> ValRaw {
1455         // Note that this is intentionally not setting the `i32` field, instead
1456         // setting the `i64` field with a zero-extended version of `i`. For more
1457         // information on this see the comments on `Lower for Result` in the
1458         // `wasmtime` crate. Otherwise though all `ValRaw` constructors are
1459         // otherwise constrained to guarantee that the initial 64-bits are
1460         // always initialized.
1461         ValRaw::u64(i.unsigned().into())
1462     }
1463 
1464     /// Creates a WebAssembly `i64` value
1465     #[inline]
1466     pub fn i64(i: i64) -> ValRaw {
1467         ValRaw { i64: i.to_le() }
1468     }
1469 
1470     /// Creates a WebAssembly `i32` value
1471     #[inline]
1472     pub fn u32(i: u32) -> ValRaw {
1473         // See comments in `ValRaw::i32` for why this is setting the upper
1474         // 32-bits as well.
1475         ValRaw::u64(i.into())
1476     }
1477 
1478     /// Creates a WebAssembly `i64` value
1479     #[inline]
1480     pub fn u64(i: u64) -> ValRaw {
1481         ValRaw::i64(i as i64)
1482     }
1483 
1484     /// Creates a WebAssembly `f32` value
1485     #[inline]
1486     pub fn f32(i: u32) -> ValRaw {
1487         // See comments in `ValRaw::i32` for why this is setting the upper
1488         // 32-bits as well.
1489         ValRaw::u64(i.into())
1490     }
1491 
1492     /// Creates a WebAssembly `f64` value
1493     #[inline]
1494     pub fn f64(i: u64) -> ValRaw {
1495         ValRaw { f64: i.to_le() }
1496     }
1497 
1498     /// Creates a WebAssembly `v128` value
1499     #[inline]
1500     pub fn v128(i: u128) -> ValRaw {
1501         ValRaw {
1502             v128: i.to_le_bytes(),
1503         }
1504     }
1505 
1506     /// Creates a WebAssembly `funcref` value
1507     #[inline]
1508     pub fn funcref(i: *mut c_void) -> ValRaw {
1509         ValRaw {
1510             funcref: i.map_addr(|i| i.to_le()),
1511         }
1512     }
1513 
1514     /// Creates a WebAssembly `externref` value
1515     #[inline]
1516     pub fn externref(e: u32) -> ValRaw {
1517         assert!(cfg!(feature = "gc") || e == 0);
1518         ValRaw {
1519             externref: e.to_le(),
1520         }
1521     }
1522 
1523     /// Creates a WebAssembly `anyref` value
1524     #[inline]
1525     pub fn anyref(r: u32) -> ValRaw {
1526         assert!(cfg!(feature = "gc") || r == 0);
1527         ValRaw { anyref: r.to_le() }
1528     }
1529 
1530     /// Creates a WebAssembly `exnref` value
1531     #[inline]
1532     pub fn exnref(r: u32) -> ValRaw {
1533         assert!(cfg!(feature = "gc") || r == 0);
1534         ValRaw { exnref: r.to_le() }
1535     }
1536 
1537     /// Gets the WebAssembly `i32` value
1538     #[inline]
1539     pub fn get_i32(&self) -> i32 {
1540         unsafe { i32::from_le(self.i32) }
1541     }
1542 
1543     /// Gets the WebAssembly `i64` value
1544     #[inline]
1545     pub fn get_i64(&self) -> i64 {
1546         unsafe { i64::from_le(self.i64) }
1547     }
1548 
1549     /// Gets the WebAssembly `i32` value
1550     #[inline]
1551     pub fn get_u32(&self) -> u32 {
1552         self.get_i32().unsigned()
1553     }
1554 
1555     /// Gets the WebAssembly `i64` value
1556     #[inline]
1557     pub fn get_u64(&self) -> u64 {
1558         self.get_i64().unsigned()
1559     }
1560 
1561     /// Gets the WebAssembly `f32` value
1562     #[inline]
1563     pub fn get_f32(&self) -> u32 {
1564         unsafe { u32::from_le(self.f32) }
1565     }
1566 
1567     /// Gets the WebAssembly `f64` value
1568     #[inline]
1569     pub fn get_f64(&self) -> u64 {
1570         unsafe { u64::from_le(self.f64) }
1571     }
1572 
1573     /// Gets the WebAssembly `v128` value
1574     #[inline]
1575     pub fn get_v128(&self) -> u128 {
1576         unsafe { u128::from_le_bytes(self.v128) }
1577     }
1578 
1579     /// Gets the WebAssembly `funcref` value
1580     #[inline]
1581     pub fn get_funcref(&self) -> *mut c_void {
1582         unsafe { self.funcref.map_addr(|i| usize::from_le(i)) }
1583     }
1584 
1585     /// Gets the WebAssembly `externref` value
1586     #[inline]
1587     pub fn get_externref(&self) -> u32 {
1588         let externref = u32::from_le(unsafe { self.externref });
1589         assert!(cfg!(feature = "gc") || externref == 0);
1590         externref
1591     }
1592 
1593     /// Gets the WebAssembly `anyref` value
1594     #[inline]
1595     pub fn get_anyref(&self) -> u32 {
1596         let anyref = u32::from_le(unsafe { self.anyref });
1597         assert!(cfg!(feature = "gc") || anyref == 0);
1598         anyref
1599     }
1600 
1601     /// Gets the WebAssembly `exnref` value
1602     #[inline]
1603     pub fn get_exnref(&self) -> u32 {
1604         let exnref = u32::from_le(unsafe { self.exnref });
1605         assert!(cfg!(feature = "gc") || exnref == 0);
1606         exnref
1607     }
1608 }
1609 
1610 /// An "opaque" version of `VMContext` which must be explicitly casted to a
1611 /// target context.
1612 ///
1613 /// This context is used to represent that contexts specified in
1614 /// `VMFuncRef` can have any type and don't have an implicit
1615 /// structure. Neither wasmtime nor cranelift-generated code can rely on the
1616 /// structure of an opaque context in general and only the code which configured
1617 /// the context is able to rely on a particular structure. This is because the
1618 /// context pointer configured for `VMFuncRef` is guaranteed to be
1619 /// the first parameter passed.
1620 ///
1621 /// Note that Wasmtime currently has a layout where all contexts that are casted
1622 /// to an opaque context start with a 32-bit "magic" which can be used in debug
1623 /// mode to debug-assert that the casts here are correct and have at least a
1624 /// little protection against incorrect casts.
1625 pub struct VMOpaqueContext {
1626     pub(crate) magic: u32,
1627     _marker: marker::PhantomPinned,
1628 }
1629 
1630 impl VMOpaqueContext {
1631     /// Helper function to clearly indicate that casts are desired.
1632     #[inline]
1633     pub fn from_vmcontext(ptr: NonNull<VMContext>) -> NonNull<VMOpaqueContext> {
1634         ptr.cast()
1635     }
1636 
1637     /// Helper function to clearly indicate that casts are desired.
1638     #[inline]
1639     pub fn from_vm_array_call_host_func_context(
1640         ptr: NonNull<VMArrayCallHostFuncContext>,
1641     ) -> NonNull<VMOpaqueContext> {
1642         ptr.cast()
1643     }
1644 }
1645