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