Skip to main content

wasmtime/runtime/vm/
vmcontext.rs

1//! This file declares `VMContext` and several related structs which contain
2//! fields that compiled wasm code accesses directly.
3
4mod vm_host_func_context;
5
6pub use self::vm_host_func_context::VMArrayCallHostFuncContext;
7use crate::prelude::*;
8use crate::runtime::vm::{InterpreterRef, VMGcRef, VmPtr, VmSafe, f32x4, f64x2, i8x16};
9use crate::store::StoreOpaque;
10use crate::vm::stack_switching::{VMContinuationStack, VMStackChain, VMStackState};
11use core::cell::UnsafeCell;
12use core::ffi::c_void;
13use core::fmt;
14use core::marker::{self, PhantomPinned};
15use core::mem::{self, ManuallyDrop, MaybeUninit};
16#[cfg(feature = "gc-null")]
17use core::num::NonZeroU32;
18use core::ops::Range;
19use core::ptr::{self, NonNull};
20use core::sync::atomic::{AtomicUsize, Ordering};
21use wasmtime_environ::{
22    BuiltinFunctionIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
23    DefinedTagIndex, NUM_COMPONENT_CONTEXT_SLOTS, VMCONTEXT_MAGIC, VMSharedTypeIndex,
24};
25
26/// A function pointer that exposes the array calling convention.
27///
28/// Regardless of the underlying Wasm function type, all functions using the
29/// array calling convention have the same Rust signature.
30///
31/// Arguments:
32///
33/// * Callee `vmctx` for the function itself.
34///
35/// * Caller's `vmctx` (so that host functions can access the linear memory of
36///   their Wasm callers).
37///
38/// * A pointer to a buffer of `ValRaw`s where both arguments are passed into
39///   this function, and where results are returned from this function.
40///
41/// * The capacity of the `ValRaw` buffer. Must always be at least
42///   `max(len(wasm_params), len(wasm_results))`.
43///
44/// Return value:
45///
46/// * `true` if this call succeeded.
47/// * `false` if this call failed and a trap was recorded in TLS.
48pub type VMArrayCallNative = unsafe extern "C" fn(
49    NonNull<VMOpaqueContext>,
50    NonNull<VMContext>,
51    NonNull<ValRaw>,
52    usize,
53) -> bool;
54
55/// An opaque function pointer which might be `VMArrayCallNative` or it might be
56/// pulley bytecode. Requires external knowledge to determine what kind of
57/// function pointer this is.
58#[repr(transparent)]
59pub struct VMArrayCallFunction(VMFunctionBody);
60
61/// A function pointer that exposes the Wasm calling convention.
62///
63/// In practice, different Wasm function types end up mapping to different Rust
64/// function types, so this isn't simply a type alias the way that
65/// `VMArrayCallFunction` is. However, the exact details of the calling
66/// convention are left to the Wasm compiler (e.g. Cranelift or Winch). Runtime
67/// code never does anything with these function pointers except shuffle them
68/// around and pass them back to Wasm.
69#[repr(transparent)]
70pub struct VMWasmCallFunction(VMFunctionBody);
71
72// SAFETY: `VMFunctionImport` is generated with `#[repr(C)]` and only contains
73// `VmSafe` fields.
74unsafe impl VmSafe for VMFunctionImport {}
75
76impl VMFunctionImport {
77    /// Convert `&VMFunctionImport` into `&VMFuncRef`.
78    pub fn as_func_ref(&self) -> &VMFuncRef {
79        // Safety: `VMFunctionImport` and `VMFuncRef` have the same
80        // representation.
81        unsafe { Self::as_non_null_func_ref(NonNull::from(self)).as_ref() }
82    }
83
84    /// Convert `NonNull<VMFunctionImport>` into `NonNull<VMFuncRef>`.
85    pub fn as_non_null_func_ref(p: NonNull<VMFunctionImport>) -> NonNull<VMFuncRef> {
86        p.cast()
87    }
88
89    /// Convert `*mut VMFunctionImport` into `*mut VMFuncRef`.
90    pub fn as_func_ref_ptr(p: *mut VMFunctionImport) -> *mut VMFuncRef {
91        p.cast()
92    }
93}
94
95#[cfg(test)]
96mod test_vmfunction_import {
97    use super::{VMFuncRef, VMFunctionImport};
98    use core::mem::offset_of;
99    use std::mem::size_of;
100
101    #[test]
102    fn vmfunction_import_and_vmfunc_ref_have_same_layout() {
103        assert_eq!(size_of::<VMFunctionImport>(), size_of::<VMFuncRef>());
104        assert_eq!(
105            offset_of!(VMFunctionImport, array_call),
106            offset_of!(VMFuncRef, array_call),
107        );
108        assert_eq!(
109            offset_of!(VMFunctionImport, wasm_call),
110            offset_of!(VMFuncRef, wasm_call),
111        );
112        assert_eq!(
113            offset_of!(VMFunctionImport, type_index),
114            offset_of!(VMFuncRef, type_index),
115        );
116        assert_eq!(
117            offset_of!(VMFunctionImport, vmctx),
118            offset_of!(VMFuncRef, 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)]
128pub struct VMFunctionBody(u8);
129
130// SAFETY: this structure is never read and is safe to pass to jit code.
131unsafe impl VmSafe for VMFunctionBody {}
132
133#[cfg(test)]
134mod 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// SAFETY: `VMTableImport` is generated with `#[repr(C)]` and only contains
145// `VmSafe` fields.
146unsafe impl VmSafe for VMTableImport {}
147
148#[cfg(test)]
149mod test_vmtable {
150    use wasmtime_environ::component::{Component, VMComponentOffsets};
151    use wasmtime_environ::{HostPtr, Module, PtrSize, StaticModuleIndex, VMOffsets};
152
153    #[test]
154    fn ensure_sizes_match() {
155        // Because we use `VMTableImport` for recording tables used by components, we
156        // want to make sure that the size calculations between `VMOffsets` and
157        // `VMComponentOffsets` stay the same.
158        let module = Module::new(StaticModuleIndex::from_u32(0));
159        let vm_offsets = VMOffsets::new(HostPtr, &module);
160        let component = Component::default();
161        let vm_component_offsets = VMComponentOffsets::new(HostPtr, &component);
162        assert_eq!(
163            vm_offsets.ptr.vm_table_import().size(),
164            vm_component_offsets.ptr.vm_table_import().size()
165        );
166    }
167}
168
169// SAFETY: `VMMemoryImport` is generated with `#[repr(C)]` and only contains
170// `VmSafe` fields.
171unsafe impl VmSafe for VMMemoryImport {}
172
173// SAFETY: `VMGlobalImport` is generated with `#[repr(C)]` and only contains
174// `VmSafe` fields.
175unsafe impl VmSafe for VMGlobalImport {}
176
177/// The kinds of globals that Wasmtime has.
178#[derive(Debug, Copy, Clone)]
179#[repr(C, u32)]
180pub enum VMGlobalKind {
181    /// Host globals, stored in a `StoreOpaque`.
182    Host(DefinedGlobalIndex),
183    /// Instance globals, stored in `VMContext`s
184    Instance(DefinedGlobalIndex),
185    /// Flags for a component instance, stored in `VMComponentContext`.
186    #[cfg(feature = "component-model")]
187    ComponentFlags(wasmtime_environ::component::RuntimeComponentInstanceIndex),
188}
189
190// SAFETY: the above enum is repr(C) and stores nothing else
191unsafe impl VmSafe for VMGlobalKind {}
192
193// SAFETY: `VMTagImport` is generated with `#[repr(C)]` and only contains
194// `VmSafe` fields.
195unsafe impl VmSafe for VMTagImport {}
196
197/// Define the runtime definitions of the shared `VM*` types.
198#[allow(
199    unused_macro_rules,
200    reason = "the `@test` arms are only expanded inside the `#[cfg(test)]` \
201              layout-test module, and the enum arms go unused whenever no \
202              `VM*` type is an enum"
203)]
204macro_rules! define_vm_types {
205    // Emit the layout test for one `struct` VM type: its size and alignment,
206    // plus each field's offset, checked against the real Rust type.
207    (@test [ $($cfg:tt)* ] $Name:ident $snake:ident [ $($fname:ident)* ]) => {
208        $($cfg)*
209        #[test]
210        fn $snake() {
211            use super::$Name;
212
213            let host = HostPtr;
214            let offsets = host.$snake();
215
216            let expected = usize::from(offsets.size());
217            let actual = size_of::<$Name>();
218            assert_eq!(
219                expected,
220                actual,
221                "size of {} failed: {expected} (expected) != {actual} (actual)",
222                stringify!($Name),
223            );
224
225            let expected = usize::from(offsets.align());
226            let actual = align_of::<$Name>();
227            assert_eq!(
228                expected,
229                actual,
230                "alignment of {} failed: {expected} (expected) != {actual} (actual)",
231                stringify!($Name),
232            );
233
234            $(
235                let expected = usize::from(offsets.$fname());
236                let actual = offset_of!($Name, $fname);
237                assert_eq!(
238                    expected,
239                    actual,
240                    "offset of {}::{} failed: {expected} (expected) != {actual} (actual)",
241                    stringify!($Name),
242                    stringify!($fname),
243                );
244            )*
245        }
246    };
247
248    // Emit the layout test for one `#[repr(C, $tag)]` enum VM type.
249    //
250    // `offset_of!` does not work on enum variants, so instead of measuring a
251    // variant field's offset this checks the generated offsets against the
252    // layout rule `#[repr(C, $tag)]` guarantees, evaluated with each field
253    // type's real `size_of`/`align_of`.
254    (@test_enum [ $($cfg:tt)* ] $Name:ident $snake:ident $tag:ty [
255        $( { $vsnake:ident $Variant:ident [ $( $fname:ident : $fty:ty , )* ] } )*
256    ]) => {
257        $($cfg)*
258        #[test]
259        fn $snake() {
260            use super::$Name;
261
262            let host = HostPtr;
263            let offsets = host.$snake();
264
265            let expected = usize::from(offsets.size());
266            let actual = size_of::<$Name>();
267            assert_eq!(
268                expected,
269                actual,
270                "size of {} failed: {expected} (expected) != {actual} (actual)",
271                stringify!($Name),
272            );
273
274            let expected = usize::from(offsets.align());
275            let actual = align_of::<$Name>();
276            assert_eq!(
277                expected,
278                actual,
279                "alignment of {} failed: {expected} (expected) != {actual} (actual)",
280                stringify!($Name),
281            );
282
283            let expected = usize::from(offsets.tag_size());
284            let actual = size_of::<$tag>();
285            assert_eq!(
286                expected,
287                actual,
288                "tag size of {} failed: {expected} (expected) != {actual} (actual)",
289                stringify!($Name),
290            );
291
292            // The payload of a `#[repr(C, $tag)]` enum starts just past the
293            // tag, rounded up to the enum's alignment.
294            let expected = usize::from(offsets.payload());
295            let actual = align_up(size_of::<$tag>(), align_of::<$Name>());
296            assert_eq!(
297                expected,
298                actual,
299                "payload offset of {} failed: {expected} (expected) != {actual} (actual)",
300                stringify!($Name),
301            );
302
303            $(
304                // A variant with no fields leaves both untouched.
305                #[allow(
306                    unused_assignments,
307                    unused_mut,
308                    unused_variables,
309                    reason = "a variant may have no fields, and the last \
310                              field's size is accumulated but never read"
311                )]
312                {
313                    let variant = offsets.$vsnake();
314                    let mut o = usize::from(offsets.payload());
315                    $(
316                        o = align_up(o, align_of::<$fty>());
317                        let expected = usize::from(variant.$fname());
318                        assert_eq!(
319                            expected,
320                            o,
321                            "offset of {}::{}::{} failed: \
322                             {expected} (expected) != {o} (actual)",
323                            stringify!($Name),
324                            stringify!($Variant),
325                            stringify!($fname),
326                        );
327                        o += size_of::<$fty>();
328                    )*
329                }
330            )*
331        }
332    };
333
334    // Munched one at a time rather than matched as a repetition because a
335    // `struct` and an `enum` do not share a body shape.
336    (@munch { $($defs:tt)* } { $($tests:tt)* }) => {
337        $($defs)*
338
339        #[cfg(test)]
340        #[allow(
341            unused_imports,
342            dead_code,
343            reason = "the glob import and `align_up` are only used by the enum \
344                      tests, and not every `VM*` type is an enum"
345        )]
346        mod test_vm_type_layouts {
347            // The enum tests name variant fields' types, so the module needs
348            // everything the definitions above were written against.
349            use super::*;
350            use core::mem::{align_of, offset_of, size_of};
351            use wasmtime_environ::{HostPtr, PtrSize};
352
353            /// Round `offset` up to a multiple of `align`.
354            fn align_up(offset: usize, align: usize) -> usize {
355                offset.next_multiple_of(align)
356            }
357
358            $($tests)*
359        }
360    };
361
362    (@munch { $($defs:tt)* } { $($tests:tt)* }
363        $(#[doc = $sdoc:literal])*
364        $(#[cfg($($scfg:tt)*)])?
365        $(#[derive($($d:ident),*)])?
366        #[repr(C, $tag:ident)]
367        #[snake_name = $snake:ident]
368        $svis:vis enum $Name:ident {
369            $(
370                $(#[doc = $vdoc:literal])*
371                #[snake_name = $vsnake:ident]
372                $Variant:ident {
373                    $(
374                        $(#[doc = $fdoc:literal])*
375                        $(#[aggregate])?
376                        $(#[indexed])?
377                        $(#[readonly])?
378                        $(#[can_move])?
379                        $fname:ident : $fty:ty ,
380                    )*
381                } = $disc:literal ,
382            )*
383        }
384        $($rest:tt)*
385    ) => {
386        define_vm_types!(
387            @munch
388            {
389                $($defs)*
390
391                $(#[doc = $sdoc])*
392                $(#[cfg($($scfg)*)])?
393                $(#[derive($($d),*)])?
394                #[repr(C, $tag)]
395                $svis enum $Name {
396                    $(
397                        $(#[doc = $vdoc])*
398                        $Variant {
399                            $(
400                                $(#[doc = $fdoc])*
401                                $fname: $fty,
402                            )*
403                        } = $disc,
404                    )*
405                }
406            }
407            {
408                $($tests)*
409
410                define_vm_types!(
411                    @test_enum
412                    [ $(#[cfg($($scfg)*)])? ]
413                    $Name $snake $tag
414                    [ $( { $vsnake $Variant [ $( $fname : $fty , )* ] } )* ]
415                );
416            }
417            $($rest)*
418        );
419    };
420
421    (@munch { $($defs:tt)* } { $($tests:tt)* }
422        $(#[doc = $sdoc:literal])*
423        $(#[cfg($($scfg:tt)*)])?
424        $(#[derive($($d:ident),*)])?
425        #[repr($($repr:tt)*)]
426        #[snake_name = $snake:ident]
427        $svis:vis struct $Name:ident {
428            $(
429                $(#[doc = $fdoc:literal])*
430                $(#[aggregate])?
431                $(#[indexed])?
432                $(#[readonly])?
433                $(#[can_move])?
434                // Unlike the offsets and alias-region consumers, this one only
435                // ever re-emits a field's type verbatim, so it can capture the
436                // whole type as one fragment instead of taking it apart.
437                $fvis:vis $fname:ident : $fty:ty ,
438            )*
439        }
440        $($rest:tt)*
441    ) => {
442        define_vm_types!(
443            @munch
444            {
445                $($defs)*
446
447                $(#[doc = $sdoc])*
448                $(#[cfg($($scfg)*)])?
449                $(#[derive($($d),*)])?
450                #[repr($($repr)*)]
451                $svis struct $Name {
452                    $(
453                        $(#[doc = $fdoc])*
454                        $fvis $fname: $fty,
455                    )*
456                }
457            }
458            {
459                $($tests)*
460
461                define_vm_types!(
462                    @test
463                    [ $(#[cfg($($scfg)*)])? ]
464                    $Name $snake
465                    [ $($fname)* ]
466                );
467            }
468            $($rest)*
469        );
470    };
471
472    ( $($defs:tt)* ) => {
473        define_vm_types!(@munch {} {} $($defs)*);
474    };
475}
476wasmtime_environ::for_each_vm_type!(define_vm_types);
477
478// SAFETY: `VMMemoryDefinition` is generated with `#[repr(C)]` and each field
479// individually implements `VmSafe`, which satisfies the requirements of this
480// trait.
481unsafe impl VmSafe for VMMemoryDefinition {}
482
483impl VMMemoryDefinition {
484    /// Return the current length (in bytes) of the [`VMMemoryDefinition`] by
485    /// performing a relaxed load; do not use this function for situations in
486    /// which a precise length is needed. Owned memories (i.e., non-shared) will
487    /// always return a precise result (since no concurrent modification is
488    /// possible) but shared memories may see an imprecise value--a
489    /// `current_length` potentially smaller than what some other thread
490    /// observes. Since Wasm memory only grows, this under-estimation may be
491    /// acceptable in certain cases.
492    #[inline]
493    pub fn current_length(&self) -> usize {
494        self.current_length.load(Ordering::Relaxed)
495    }
496
497    /// Return a copy of the [`VMMemoryDefinition`] using the relaxed value of
498    /// `current_length`; see [`VMMemoryDefinition::current_length()`].
499    #[inline]
500    pub unsafe fn load(ptr: *mut Self) -> Self {
501        let other = unsafe { &*ptr };
502        VMMemoryDefinition {
503            base: other.base,
504            current_length: other.current_length().into(),
505        }
506    }
507}
508
509// SAFETY: `VMTableDefinition` is generated with `#[repr(C)]` and only contains
510// `VmSafe` fields.
511unsafe impl VmSafe for VMTableDefinition {}
512
513// SAFETY: `VMGlobalDefinition` is `#[repr(C)]` and only contains `VmSafe`
514// fields.
515unsafe impl VmSafe for VMGlobalDefinition {}
516
517#[cfg(test)]
518mod test_vmglobal_definition {
519    use super::VMGlobalDefinition;
520    use std::mem::{align_of, size_of};
521    use wasmtime_environ::{HostPtr, Module, PtrSize, StaticModuleIndex, VMOffsets};
522
523    #[test]
524    fn check_vmglobal_definition_size() {
525        // The compiler lays out globals using this size; see
526        // `vmctx_field_size!` in `wasmtime-environ`.
527        assert_eq!(size_of::<VMGlobalDefinition>(), 16);
528        assert_eq!(
529            size_of::<VMGlobalDefinition>(),
530            usize::from(HostPtr.maximum_value_size())
531        );
532    }
533
534    #[test]
535    fn check_vmglobal_definition_alignment() {
536        assert_eq!(align_of::<VMGlobalDefinition>(), 16);
537        assert!(align_of::<VMGlobalDefinition>() >= align_of::<i32>());
538        assert!(align_of::<VMGlobalDefinition>() >= align_of::<i64>());
539        assert!(align_of::<VMGlobalDefinition>() >= align_of::<f32>());
540        assert!(align_of::<VMGlobalDefinition>() >= align_of::<f64>());
541        assert!(align_of::<VMGlobalDefinition>() >= align_of::<[u8; 16]>());
542        assert!(align_of::<VMGlobalDefinition>() >= align_of::<[f32; 4]>());
543        assert!(align_of::<VMGlobalDefinition>() >= align_of::<[f64; 2]>());
544    }
545
546    #[test]
547    fn check_vmglobal_begins_aligned() {
548        let module = Module::new(StaticModuleIndex::from_u32(0));
549        let offsets = VMOffsets::new(HostPtr, &module);
550        assert_eq!(offsets.globals().begin() % 16, 0);
551    }
552
553    #[test]
554    #[cfg(feature = "gc")]
555    fn check_vmglobal_can_contain_gc_ref() {
556        assert!(size_of::<crate::runtime::vm::VMGcRef>() <= size_of::<VMGlobalDefinition>());
557    }
558}
559
560/// The storage for a WebAssembly global defined within the instance.
561///
562/// Compiled code reads and writes this storage directly, as the field that
563/// matches the global's type. Scalars are stored in native-endian order, except
564/// `v128`, which is little-endian.
565///
566/// TODO: Pack the globals more densely, rather than using the same size for
567/// every type.
568#[repr(C, align(16))]
569pub union VMGlobalDefinition {
570    // These values are all stored in native-endian
571    i32: i32,
572    i64: i64,
573    f32: u32,
574    f64: u64,
575    gc_ref: ManuallyDrop<Option<VMGcRef>>,
576    func_ref: Option<VmPtr<VMFuncRef>>,
577    // This is stored in little-endian
578    v128: [u8; 16],
579}
580
581impl VMGlobalDefinition {
582    /// Construct a `VMGlobalDefinition`.
583    pub fn new() -> Self {
584        Self { v128: [0; 16] }
585    }
586
587    /// Returns the value of this `i32` global.
588    ///
589    /// # Safety
590    ///
591    /// This function requires that the type of this global is `i32`.
592    pub unsafe fn get_i32(&self) -> i32 {
593        unsafe { self.i32 }
594    }
595
596    /// Sets the value of this `i32` global.
597    ///
598    /// # Safety
599    ///
600    /// This function requires that the type of this global is `i32`.
601    pub unsafe fn set_i32(&mut self, val: i32) {
602        self.i32 = val;
603    }
604
605    /// Returns the value of this `i64` global.
606    ///
607    /// # Safety
608    ///
609    /// This function requires that the type of this global is `i64`.
610    pub unsafe fn get_i64(&self) -> i64 {
611        unsafe { self.i64 }
612    }
613
614    /// Sets the value of this `i64` global.
615    ///
616    /// # Safety
617    ///
618    /// This function requires that the type of this global is `i64`.
619    pub unsafe fn set_i64(&mut self, val: i64) {
620        self.i64 = val;
621    }
622
623    /// Returns the bits of this `f32` global.
624    ///
625    /// # Safety
626    ///
627    /// This function requires that the type of this global is `f32`.
628    pub unsafe fn get_f32_bits(&self) -> u32 {
629        unsafe { self.f32 }
630    }
631
632    /// Sets the bits of this `f32` global.
633    ///
634    /// # Safety
635    ///
636    /// This function requires that the type of this global is `f32`.
637    pub unsafe fn set_f32_bits(&mut self, bits: u32) {
638        self.f32 = bits;
639    }
640
641    /// Returns the bits of this `f64` global.
642    ///
643    /// # Safety
644    ///
645    /// This function requires that the type of this global is `f64`.
646    pub unsafe fn get_f64_bits(&self) -> u64 {
647        unsafe { self.f64 }
648    }
649
650    /// Sets the bits of this `f64` global.
651    ///
652    /// # Safety
653    ///
654    /// This function requires that the type of this global is `f64`.
655    pub unsafe fn set_f64_bits(&mut self, bits: u64) {
656        self.f64 = bits;
657    }
658
659    /// Returns the value of this `v128` global.
660    ///
661    /// # Safety
662    ///
663    /// This function requires that the type of this global is `v128`.
664    pub unsafe fn get_u128(&self) -> u128 {
665        u128::from_le_bytes(unsafe { self.v128 })
666    }
667
668    /// Sets the value of this `v128` global.
669    ///
670    /// # Safety
671    ///
672    /// This function requires that the type of this global is `v128`.
673    pub unsafe fn set_u128(&mut self, val: u128) {
674        self.v128 = val.to_le_bytes();
675    }
676
677    /// Returns the value of this GC reference global.
678    ///
679    /// # Safety
680    ///
681    /// This function requires that the type of this global is a GC reference,
682    /// for example `extrenref`, `anyref`, `exnref`, etc.
683    pub unsafe fn as_gc_ref(&self) -> Option<&VMGcRef> {
684        let ret = unsafe { (*self.gc_ref).as_ref() };
685        assert!(cfg!(feature = "gc") || ret.is_none());
686        ret
687    }
688
689    /// Returns the value of this GC reference global, mutably.
690    ///
691    /// # Safety
692    ///
693    /// This function requires that the type of this global is a GC reference,
694    /// for example `extrenref`, `anyref`, `exnref`, etc.
695    pub unsafe fn as_gc_ref_mut(&mut self) -> Option<&mut VMGcRef> {
696        let ret = unsafe { (*self.gc_ref).as_mut() };
697        assert!(cfg!(feature = "gc") || ret.is_none());
698        ret
699    }
700
701    /// Initialize this GC reference global to the given GC reference.
702    ///
703    /// # Safety
704    ///
705    /// This function requires that the type of this global is a GC reference,
706    /// for example `extrenref`, `anyref`, `exnref`, etc.
707    pub unsafe fn init_gc_ref(
708        &mut self,
709        store: &mut StoreOpaque,
710        gc_ref: Option<&VMGcRef>,
711    ) -> Result<()> {
712        // SAFETY: `MaybeUninit<T>` has the same layout as `T`, and this global
713        // is uninitialized, so it must not be read as a `VMGcRef`.
714        let dest = unsafe { &mut *(&raw mut self.gc_ref).cast::<MaybeUninit<Option<VMGcRef>>>() };
715        store.init_gc_ref(dest, gc_ref)
716    }
717
718    /// Write a GC reference into this GC reference global.
719    pub unsafe fn write_gc_ref(
720        &mut self,
721        store: &mut StoreOpaque,
722        gc_ref: Option<&VMGcRef>,
723    ) -> Result<()> {
724        let dest = unsafe { &mut *self.gc_ref };
725        store.write_gc_ref(dest, gc_ref)
726    }
727
728    /// Returns the value of this funcref global.
729    ///
730    /// # Safety
731    ///
732    /// This function requires that the type of this global is a `funcref` or
733    /// a concrete function type.
734    pub unsafe fn get_func_ref(&self) -> Option<NonNull<VMFuncRef>> {
735        unsafe { self.func_ref.map(|p| p.as_non_null()) }
736    }
737
738    /// Sets the value of this funcref global.
739    ///
740    /// # Safety
741    ///
742    /// This function requires that the type of this global is a `funcref` or
743    /// a concrete function type.
744    pub unsafe fn set_func_ref(&mut self, func_ref: Option<NonNull<VMFuncRef>>) {
745        self.func_ref = func_ref.map(VmPtr::from);
746    }
747}
748
749#[cfg(test)]
750mod test_vmshared_type_index {
751    use super::VMSharedTypeIndex;
752    use std::mem::size_of;
753    use wasmtime_environ::{HostPtr, Module, StaticModuleIndex, VMOffsets};
754
755    #[test]
756    fn check_vmshared_type_index() {
757        let module = Module::new(StaticModuleIndex::from_u32(0));
758        let offsets = VMOffsets::new(HostPtr, &module);
759        assert_eq!(
760            size_of::<VMSharedTypeIndex>(),
761            usize::from(offsets.size_of_vmshared_type_index())
762        );
763    }
764}
765
766impl VMTagDefinition {
767    pub fn new(type_index: VMSharedTypeIndex) -> Self {
768        Self { type_index }
769    }
770}
771
772// SAFETY: `VMTagDefinition` is generated with `#[repr(C)]` and only contains
773// `VmSafe` fields.
774unsafe impl VmSafe for VMTagDefinition {}
775
776#[cfg(test)]
777mod test_vmtag_definition {
778    use wasmtime_environ::{HostPtr, Module, StaticModuleIndex, VMOffsets};
779
780    #[test]
781    fn check_vmtag_begins_aligned() {
782        let module = Module::new(StaticModuleIndex::from_u32(0));
783        let offsets = VMOffsets::new(HostPtr, &module);
784        assert_eq!(offsets.tags().begin() % 16, 0);
785    }
786}
787
788// SAFETY: `VMFuncRef` is generated with `#[repr(C)]` and only contains
789// `VmSafe` fields.
790unsafe impl VmSafe for VMFuncRef {}
791
792impl VMFuncRef {
793    /// Invokes the `array_call` field of this `VMFuncRef` with the supplied
794    /// arguments.
795    ///
796    /// This will invoke the function pointer in the `array_call` field with:
797    ///
798    /// * the `callee` vmctx as `self.vmctx`
799    /// * the `caller` as `caller` specified here
800    /// * the args pointer as `args_and_results`
801    /// * the args length as `args_and_results`
802    ///
803    /// The `args_and_results` area must be large enough to both load all
804    /// arguments from and store all results to.
805    ///
806    /// Returns whether a trap was recorded in TLS for raising.
807    ///
808    /// # Unsafety
809    ///
810    /// This method is unsafe because it can be called with any pointers. They
811    /// must all be valid for this wasm function call to proceed. For example
812    /// the `caller` must be valid machine code if `pulley` is `None` or it must
813    /// be valid bytecode if `pulley` is `Some`. Additionally `args_and_results`
814    /// must be large enough to handle all the arguments/results for this call.
815    ///
816    /// Note that the unsafety invariants to maintain here are not currently
817    /// exhaustively documented.
818    #[inline]
819    pub unsafe fn array_call(
820        me: NonNull<VMFuncRef>,
821        pulley: Option<InterpreterRef<'_>>,
822        caller: NonNull<VMContext>,
823        args_and_results: NonNull<[ValRaw]>,
824    ) -> bool {
825        match pulley {
826            Some(vm) => unsafe { Self::array_call_interpreted(me, vm, caller, args_and_results) },
827            None => unsafe { Self::array_call_native(me, caller, args_and_results) },
828        }
829    }
830
831    unsafe fn array_call_interpreted(
832        me: NonNull<VMFuncRef>,
833        vm: InterpreterRef<'_>,
834        caller: NonNull<VMContext>,
835        args_and_results: NonNull<[ValRaw]>,
836    ) -> bool {
837        // If `caller` is actually a `VMArrayCallHostFuncContext` then skip the
838        // interpreter, even though it's available, as `array_call` will be
839        // native code.
840        unsafe {
841            if me.as_ref().vmctx.as_non_null().as_ref().magic
842                == wasmtime_environ::VM_ARRAY_CALL_HOST_FUNC_MAGIC
843            {
844                return Self::array_call_native(me, caller, args_and_results);
845            }
846            vm.call(
847                me.as_ref().array_call.as_non_null().cast(),
848                me.as_ref().vmctx.as_non_null(),
849                caller,
850                args_and_results,
851            )
852        }
853    }
854
855    #[inline]
856    unsafe fn array_call_native(
857        me: NonNull<VMFuncRef>,
858        caller: NonNull<VMContext>,
859        args_and_results: NonNull<[ValRaw]>,
860    ) -> bool {
861        unsafe {
862            union GetNativePointer {
863                native: VMArrayCallNative,
864                ptr: NonNull<VMArrayCallFunction>,
865            }
866            let native = GetNativePointer {
867                ptr: me.as_ref().array_call.as_non_null(),
868            }
869            .native;
870            native(
871                me.as_ref().vmctx.as_non_null(),
872                caller,
873                args_and_results.cast(),
874                args_and_results.len(),
875            )
876        }
877    }
878
879    pub(crate) fn as_vm_function_import(&self) -> Option<&VMFunctionImport> {
880        if self.wasm_call.is_some() {
881            // Safety: `VMFuncRef` and `VMFunctionImport` have the same layout
882            // and `wasm_call` is non-null.
883            Some(unsafe { NonNull::from(self).cast::<VMFunctionImport>().as_ref() })
884        } else {
885            None
886        }
887    }
888}
889
890macro_rules! define_builtin_array {
891    (
892        $(
893            $( #[$attr:meta] )*
894            $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
895        )*
896    ) => {
897        /// An array that stores addresses of builtin functions. We translate code
898        /// to use indirect calls. This way, we don't have to patch the code.
899        #[repr(C)]
900        #[allow(improper_ctypes_definitions, reason = "__m128i known not FFI-safe")]
901        pub struct VMBuiltinFunctionsArray {
902            $(
903                $name: unsafe extern "C" fn(
904                    $(define_builtin_array!(@ty $param)),*
905                ) $( -> define_builtin_array!(@ty $result))?,
906            )*
907        }
908
909        impl VMBuiltinFunctionsArray {
910            pub const INIT: VMBuiltinFunctionsArray = VMBuiltinFunctionsArray {
911                $(
912                    $name: crate::runtime::vm::libcalls::raw::$name,
913                )*
914            };
915
916            /// Helper to call `expose_provenance()` on all contained pointers.
917            ///
918            /// This is required to be called at least once before entering wasm
919            /// to inform the compiler that these function pointers may all be
920            /// loaded/stored and used on the "other end" to reacquire
921            /// provenance in Pulley. Pulley models hostcalls with a host
922            /// pointer as the first parameter that's a function pointer under
923            /// the hood, and this call ensures that the use of the function
924            /// pointer is considered valid.
925            pub fn expose_provenance(&self) -> NonNull<Self>{
926                $(
927                    (self.$name as *mut u8).expose_provenance();
928                )*
929                NonNull::from(self)
930            }
931        }
932    };
933
934    (@ty u32) => (u32);
935    (@ty u64) => (u64);
936    (@ty f32) => (f32);
937    (@ty f64) => (f64);
938    (@ty u8) => (u8);
939    (@ty i8x16) => (i8x16);
940    (@ty f32x4) => (f32x4);
941    (@ty f64x2) => (f64x2);
942    (@ty bool) => (bool);
943    (@ty pointer) => (*mut u8);
944    (@ty size) => (usize);
945    (@ty vmctx) => (NonNull<VMContext>);
946}
947
948// SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
949unsafe impl VmSafe for VMBuiltinFunctionsArray {}
950
951wasmtime_environ::foreach_builtin_function!(define_builtin_array);
952
953const _: () = {
954    assert!(
955        mem::size_of::<VMBuiltinFunctionsArray>()
956            == mem::size_of::<usize>() * (BuiltinFunctionIndex::len() as usize)
957    )
958};
959
960impl VMStoreContext {
961    /// From the current saved trampoline FP, get the FP of the last
962    /// Wasm frame. If the current saved trampoline FP is null, return
963    /// null.
964    ///
965    /// We store only the trampoline FP, because (i) we need the
966    /// trampoline FP, so we know the size (bottom) of the last Wasm
967    /// frame; and (ii) the last Wasm frame, just above the trampoline
968    /// frame, can be recovered via the FP chain.
969    ///
970    /// # Safety
971    ///
972    /// This function requires that the `last_wasm_exit_trampoline_fp`
973    /// field either points to an active trampoline frame or is a null
974    /// pointer.
975    pub(crate) unsafe fn last_wasm_exit_fp(&self) -> usize {
976        // SAFETY: the unsafe cell is safe to load (no other threads
977        // will be writing our store when we have control), and the
978        // helper function's safety condition is the same as ours.
979        unsafe {
980            let trampoline_fp = *self.last_wasm_exit_trampoline_fp.get();
981            Self::wasm_exit_fp_from_trampoline_fp(trampoline_fp)
982        }
983    }
984
985    /// From any saved trampoline FP, get the FP of the last Wasm
986    /// frame. If the given trampoline FP is null, return null.
987    ///
988    /// This differs from `last_wasm_exit_fp()` above in that it
989    /// allows accessing activations further up the stack as well,
990    /// e.g. via `CallThreadState::old_state`.
991    ///
992    /// # Safety
993    ///
994    /// This function requires that the provided FP value is valid,
995    /// and points to an active trampoline frame, or is null.
996    ///
997    /// This function depends on the invariant that on all supported
998    /// architectures, we store the previous FP value under the
999    /// current FP. This is a property of our ABI that we control and
1000    /// ensure.
1001    pub(crate) unsafe fn wasm_exit_fp_from_trampoline_fp(trampoline_fp: usize) -> usize {
1002        if trampoline_fp != 0 {
1003            // SAFETY: We require that trampoline_fp points to a valid
1004            // frame, which will (by definition) contain an old FP value
1005            // that we can load.
1006            unsafe { *(trampoline_fp as *const usize) }
1007        } else {
1008            0
1009        }
1010    }
1011
1012    #[cfg(feature = "component-model-async")]
1013    pub(crate) fn component_context_mut(&mut self) -> &mut [u32; NUM_COMPONENT_CONTEXT_SLOTS] {
1014        self.component_context.get_mut()
1015    }
1016
1017    #[cfg(feature = "component-model-async")]
1018    pub(crate) fn current_thread_mut(&mut self) -> &mut VMLazyThread {
1019        self.current_thread.get_mut()
1020    }
1021}
1022
1023// The `VMStoreContext` type is a pod-type with no destructor, and we don't
1024// access any fields from other threads, so add in these trait impls which are
1025// otherwise not available due to the `fuel_consumed` and `epoch_deadline`
1026// variables in `VMStoreContext`.
1027unsafe impl Send for VMStoreContext {}
1028unsafe impl Sync for VMStoreContext {}
1029
1030// SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
1031unsafe impl VmSafe for VMStoreContext {}
1032
1033impl Default for VMStoreContext {
1034    fn default() -> VMStoreContext {
1035        VMStoreContext {
1036            fuel_consumed: UnsafeCell::new(0),
1037            epoch_deadline: UnsafeCell::new(0),
1038            execution_version: 0,
1039            stack_limit: UnsafeCell::new(usize::MAX),
1040            gc_heap: UnsafeCell::new(VMMemoryDefinition {
1041                base: NonNull::dangling().into(),
1042                current_length: AtomicUsize::new(0),
1043            }),
1044            last_wasm_exit_trampoline_fp: UnsafeCell::new(0),
1045            last_wasm_exit_pc: UnsafeCell::new(0),
1046            last_wasm_entry_fp: UnsafeCell::new(0),
1047            last_wasm_entry_sp: UnsafeCell::new(0),
1048            last_wasm_entry_trap_handler: UnsafeCell::new(0),
1049            stack_chain: UnsafeCell::new(VMStackChain::Absent),
1050            async_guard_range: ptr::null_mut()..ptr::null_mut(),
1051            store_data: VmPtr::dangling(),
1052            component_context: UnsafeCell::new([0; NUM_COMPONENT_CONTEXT_SLOTS]),
1053            current_thread: UnsafeCell::new(VMLazyThread::none()),
1054        }
1055    }
1056}
1057
1058#[cfg(test)]
1059mod test_vmstore_context {
1060    use super::{VMMemoryDefinition, VMStoreContext};
1061    use core::mem::offset_of;
1062    use wasmtime_environ::{HostPtr, Module, PtrSize, StaticModuleIndex, VMOffsets};
1063
1064    /// Check the `VMStoreContext` offsets that `for_each_vm_type!` does *not*
1065    /// generate: the offsets reaching into the inlined `gc_heap`.
1066    ///
1067    /// Every field offset, plus the size and alignment of the type, is already
1068    /// checked by the generated `test_vm_type_layouts::vm_store_context`.
1069    #[test]
1070    fn derived_field_offsets() {
1071        let module = Module::new(StaticModuleIndex::from_u32(0));
1072        let offsets = VMOffsets::new(HostPtr, &module);
1073        assert_eq!(
1074            offset_of!(VMStoreContext, gc_heap) + offset_of!(VMMemoryDefinition, base),
1075            usize::from(offsets.ptr.vm_store_context().gc_heap_base())
1076        );
1077        assert_eq!(
1078            offset_of!(VMStoreContext, gc_heap) + offset_of!(VMMemoryDefinition, current_length),
1079            usize::from(offsets.ptr.vm_store_context().gc_heap_current_length())
1080        );
1081    }
1082}
1083
1084#[cfg(test)]
1085mod test_vm_cont_ref {
1086    use wasmtime_environ::PtrSize;
1087
1088    /// Check the one `VMContRef` property that `for_each_vm_type!` does *not*
1089    /// generate an assertion for: that `revision` lands at an eight-aligned
1090    /// offset for every target pointer width, not just the host's.
1091    ///
1092    /// Some 32-bit platforms need it to be 8-byte aligned and some don't, so we
1093    /// make sure that it always is, without padding to get there.
1094    ///
1095    /// Every field offset, plus the size and alignment of the type, is already
1096    /// checked by the generated `test_vm_type_layouts::vm_cont_ref`.
1097    #[test]
1098    fn revision_is_eight_aligned() {
1099        assert_eq!(4u8.vm_cont_ref().revision() % 8, 0);
1100        assert_eq!(8u8.vm_cont_ref().revision() % 8, 0);
1101    }
1102}
1103
1104impl VMLazyThread {
1105    const _ASSERT_SIZE: () = assert!(
1106        core::mem::size_of::<VMLazyThread>() == core::mem::size_of::<*mut VMDeferredThread>()
1107    );
1108    const _ASSERT_ALIGN: () = assert!(
1109        core::mem::align_of::<VMLazyThread>() == core::mem::align_of::<*mut VMDeferredThread>()
1110    );
1111
1112    const FORCED: VmPtr<VMDeferredThread> = VmPtr::<u8>::dangling().cast();
1113
1114    /// There is no current thread.
1115    pub const fn none() -> Self {
1116        Self { thread: None }
1117    }
1118
1119    /// A lazy thread that has already been promoted.
1120    pub const fn forced() -> Self {
1121        Self {
1122            thread: Some(Self::FORCED),
1123        }
1124    }
1125
1126    /// A deferred thread referencing the given on-stack [`VMDeferredThread`].
1127    pub fn deferred(ptr: NonNull<VMDeferredThread>) -> Self {
1128        debug_assert_eq!(ptr.addr().get() & Self::FORCED.addr().get(), 0);
1129        Self {
1130            thread: Some(ptr.into()),
1131        }
1132    }
1133
1134    /// Returns `true` if there is no current thread.
1135    pub fn is_none(self) -> bool {
1136        self.thread.is_none()
1137    }
1138
1139    /// Returns `true` if a deferred thread has been forced/promoted.
1140    pub fn is_forced(self) -> bool {
1141        self.thread.is_some_and(|p| p == Self::FORCED)
1142    }
1143
1144    /// Returns `true` if this is a deferred thread (i.e. neither `None` nor
1145    /// forced).
1146    pub fn is_deferred(self) -> bool {
1147        self.thread.is_some_and(|p| p != Self::FORCED)
1148    }
1149
1150    /// Returns the deferred [`VMDeferredThread`] pointer if this is a deferred
1151    /// thread.
1152    pub fn as_deferred(self) -> Option<VmPtr<VMDeferredThread>> {
1153        self.thread
1154            .and_then(|p| if p == Self::FORCED { None } else { Some(p) })
1155    }
1156}
1157
1158#[cfg(test)]
1159mod test_vmlazy_thread {
1160    use super::*;
1161
1162    #[test]
1163    fn vmlazy_thread_forced() {
1164        assert_eq!(
1165            VMLazyThread::forced().thread.unwrap().addr().get(),
1166            usize::try_from(wasmtime_environ::VM_LAZY_THREAD_FORCED).unwrap()
1167        );
1168    }
1169}
1170
1171/// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
1172/// This has information about globals, memories, tables, and other runtime
1173/// state associated with the current instance.
1174///
1175/// The struct here is empty, as the sizes of these fields are dynamic, and
1176/// we can't describe them in Rust's type system. Sufficient memory is
1177/// allocated at runtime.
1178#[derive(Debug)]
1179#[repr(C, align(16))] // align 16 since globals are aligned to that and contained inside
1180pub struct VMContext {
1181    _magic: u32,
1182}
1183
1184impl VMContext {
1185    /// Helper function to cast between context types using a debug assertion to
1186    /// protect against some mistakes.
1187    #[inline]
1188    pub unsafe fn from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMContext> {
1189        // Note that in general the offset of the "magic" field is stored in
1190        // `VMContext::magic`. Given though that this is a sanity check
1191        // about converting this pointer to another type we ideally don't want
1192        // to read the offset from potentially corrupt memory. Instead it would
1193        // be better to catch errors here as soon as possible.
1194        //
1195        // To accomplish this the `VMContext` structure is laid out with the
1196        // magic field at a statically known offset (here it's 0 for now). This
1197        // static offset is asserted in `VMOffsets::from` and needs to be kept
1198        // in sync with this line for this debug assertion to work.
1199        //
1200        // Also note that this magic is only ever invalid in the presence of
1201        // bugs, meaning we don't actually read the magic and act differently
1202        // at runtime depending what it is, so this is a debug assertion as
1203        // opposed to a regular assertion.
1204        unsafe {
1205            debug_assert_eq!(opaque.as_ref().magic, VMCONTEXT_MAGIC);
1206        }
1207        opaque.cast()
1208    }
1209}
1210
1211/// A "raw" and unsafe representation of a WebAssembly value.
1212///
1213/// This is provided for use with the `Func::new_unchecked` and
1214/// `Func::call_unchecked` APIs. In general it's unlikely you should be using
1215/// this from Rust, rather using APIs like `Func::wrap` and `TypedFunc::call`.
1216///
1217/// This is notably an "unsafe" way to work with `Val` and it's recommended to
1218/// instead use `Val` where possible. An important note about this union is that
1219/// fields are all stored in little-endian format, regardless of the endianness
1220/// of the host system.
1221#[repr(C)]
1222#[derive(Copy, Clone)]
1223pub union ValRaw {
1224    /// A WebAssembly `i32` value.
1225    ///
1226    /// Note that the payload here is a Rust `i32` but the WebAssembly `i32`
1227    /// type does not assign an interpretation of the upper bit as either signed
1228    /// or unsigned. The Rust type `i32` is simply chosen for convenience.
1229    ///
1230    /// This value is always stored in a little-endian format.
1231    i32: i32,
1232
1233    /// A WebAssembly `i64` value.
1234    ///
1235    /// Note that the payload here is a Rust `i64` but the WebAssembly `i64`
1236    /// type does not assign an interpretation of the upper bit as either signed
1237    /// or unsigned. The Rust type `i64` is simply chosen for convenience.
1238    ///
1239    /// This value is always stored in a little-endian format.
1240    i64: i64,
1241
1242    /// A WebAssembly `f32` value.
1243    ///
1244    /// Note that the payload here is a Rust `u32`. This is to allow passing any
1245    /// representation of NaN into WebAssembly without risk of changing NaN
1246    /// payload bits as its gets passed around the system. Otherwise though this
1247    /// `u32` value is the return value of `f32::to_bits` in Rust.
1248    ///
1249    /// This value is always stored in a little-endian format.
1250    f32: u32,
1251
1252    /// A WebAssembly `f64` value.
1253    ///
1254    /// Note that the payload here is a Rust `u64`. This is to allow passing any
1255    /// representation of NaN into WebAssembly without risk of changing NaN
1256    /// payload bits as its gets passed around the system. Otherwise though this
1257    /// `u64` value is the return value of `f64::to_bits` in Rust.
1258    ///
1259    /// This value is always stored in a little-endian format.
1260    f64: u64,
1261
1262    /// A WebAssembly `v128` value.
1263    ///
1264    /// The payload here is a Rust `[u8; 16]` which has the same number of bits
1265    /// but note that `v128` in WebAssembly is often considered a vector type
1266    /// such as `i32x4` or `f64x2`. This means that the actual interpretation
1267    /// of the underlying bits is left up to the instructions which consume
1268    /// this value.
1269    ///
1270    /// This value is always stored in a little-endian format.
1271    v128: [u8; 16],
1272
1273    /// A WebAssembly `funcref` value (or one of its subtypes).
1274    ///
1275    /// The payload here is a pointer which is runtime-defined. This is one of
1276    /// the main points of unsafety about the `ValRaw` type as the validity of
1277    /// the pointer here is not easily verified and must be preserved by
1278    /// carefully calling the correct functions throughout the runtime.
1279    ///
1280    /// This value is always stored in a little-endian format.
1281    funcref: *mut c_void,
1282
1283    /// A WebAssembly `externref` value (or one of its subtypes).
1284    ///
1285    /// The payload here is a compressed pointer value which is
1286    /// runtime-defined. This is one of the main points of unsafety about the
1287    /// `ValRaw` type as the validity of the pointer here is not easily verified
1288    /// and must be preserved by carefully calling the correct functions
1289    /// throughout the runtime.
1290    ///
1291    /// This value is always stored in a little-endian format.
1292    externref: u32,
1293
1294    /// A WebAssembly `anyref` value (or one of its subtypes).
1295    ///
1296    /// The payload here is a compressed pointer value which is
1297    /// runtime-defined. This is one of the main points of unsafety about the
1298    /// `ValRaw` type as the validity of the pointer here is not easily verified
1299    /// and must be preserved by carefully calling the correct functions
1300    /// throughout the runtime.
1301    ///
1302    /// This value is always stored in a little-endian format.
1303    anyref: u32,
1304
1305    /// A WebAssembly `exnref` value (or one of its subtypes).
1306    ///
1307    /// The payload here is a compressed pointer value which is
1308    /// runtime-defined. This is one of the main points of unsafety about the
1309    /// `ValRaw` type as the validity of the pointer here is not easily verified
1310    /// and must be preserved by carefully calling the correct functions
1311    /// throughout the runtime.
1312    ///
1313    /// This value is always stored in a little-endian format.
1314    exnref: u32,
1315}
1316
1317// The `ValRaw` type is matched as `wasmtime_val_raw_t` in the C API so these
1318// are some simple assertions about the shape of the type which are additionally
1319// matched in C.
1320const _: () = {
1321    assert!(mem::size_of::<ValRaw>() == 16);
1322    assert!(mem::align_of::<ValRaw>() == mem::align_of::<u64>());
1323};
1324
1325// This type is just a bag-of-bits so it's up to the caller to figure out how
1326// to safely deal with threading concerns and safely access interior bits.
1327unsafe impl Send for ValRaw {}
1328unsafe impl Sync for ValRaw {}
1329
1330impl fmt::Debug for ValRaw {
1331    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1332        struct Hex<T>(T);
1333        impl<T: fmt::LowerHex> fmt::Debug for Hex<T> {
1334            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1335                let bytes = mem::size_of::<T>();
1336                let hex_digits_per_byte = 2;
1337                let hex_digits = bytes * hex_digits_per_byte;
1338                write!(f, "0x{:0width$x}", self.0, width = hex_digits)
1339            }
1340        }
1341
1342        unsafe {
1343            f.debug_struct("ValRaw")
1344                .field("i32", &Hex(self.i32))
1345                .field("i64", &Hex(self.i64))
1346                .field("f32", &Hex(self.f32))
1347                .field("f64", &Hex(self.f64))
1348                .field("v128", &Hex(u128::from_le_bytes(self.v128)))
1349                .field("funcref", &self.funcref)
1350                .field("externref", &Hex(self.externref))
1351                .field("anyref", &Hex(self.anyref))
1352                .field("exnref", &Hex(self.exnref))
1353                .finish()
1354        }
1355    }
1356}
1357
1358impl ValRaw {
1359    /// Create a null reference that is compatible with any of
1360    /// `{any,extern,func,exn}ref`.
1361    pub fn null() -> ValRaw {
1362        unsafe {
1363            let raw = mem::MaybeUninit::<Self>::zeroed().assume_init();
1364            debug_assert_eq!(raw.get_anyref(), 0);
1365            debug_assert_eq!(raw.get_exnref(), 0);
1366            debug_assert_eq!(raw.get_externref(), 0);
1367            debug_assert_eq!(raw.get_funcref(), ptr::null_mut());
1368            raw
1369        }
1370    }
1371
1372    /// Creates a WebAssembly `i32` value
1373    #[inline]
1374    pub fn i32(i: i32) -> ValRaw {
1375        // Note that this is intentionally not setting the `i32` field, instead
1376        // setting the `i64` field with a zero-extended version of `i`. For more
1377        // information on this see the comments on `Lower for Result` in the
1378        // `wasmtime` crate. Otherwise though all `ValRaw` constructors are
1379        // otherwise constrained to guarantee that the initial 64-bits are
1380        // always initialized.
1381        ValRaw::u64(i.cast_unsigned().into())
1382    }
1383
1384    /// Creates a WebAssembly `i64` value
1385    #[inline]
1386    pub fn i64(i: i64) -> ValRaw {
1387        ValRaw { i64: i.to_le() }
1388    }
1389
1390    /// Creates a WebAssembly `i32` value
1391    #[inline]
1392    pub fn u32(i: u32) -> ValRaw {
1393        // See comments in `ValRaw::i32` for why this is setting the upper
1394        // 32-bits as well.
1395        ValRaw::u64(i.into())
1396    }
1397
1398    /// Creates a WebAssembly `i64` value
1399    #[inline]
1400    pub fn u64(i: u64) -> ValRaw {
1401        ValRaw::i64(i as i64)
1402    }
1403
1404    /// Creates a WebAssembly `f32` value
1405    #[inline]
1406    pub fn f32(i: u32) -> ValRaw {
1407        // See comments in `ValRaw::i32` for why this is setting the upper
1408        // 32-bits as well.
1409        ValRaw::u64(i.into())
1410    }
1411
1412    /// Creates a WebAssembly `f64` value
1413    #[inline]
1414    pub fn f64(i: u64) -> ValRaw {
1415        ValRaw { f64: i.to_le() }
1416    }
1417
1418    /// Creates a WebAssembly `v128` value
1419    #[inline]
1420    pub fn v128(i: u128) -> ValRaw {
1421        ValRaw {
1422            v128: i.to_le_bytes(),
1423        }
1424    }
1425
1426    /// Creates a WebAssembly `funcref` value
1427    #[inline]
1428    pub fn funcref(i: *mut c_void) -> ValRaw {
1429        ValRaw {
1430            funcref: i.map_addr(|i| i.to_le()),
1431        }
1432    }
1433
1434    /// Creates a WebAssembly `externref` value
1435    #[inline]
1436    pub fn externref(e: u32) -> ValRaw {
1437        assert!(cfg!(feature = "gc") || e == 0);
1438        ValRaw {
1439            externref: e.to_le(),
1440        }
1441    }
1442
1443    /// Creates a WebAssembly `anyref` value
1444    #[inline]
1445    pub fn anyref(r: u32) -> ValRaw {
1446        assert!(cfg!(feature = "gc") || r == 0);
1447        ValRaw { anyref: r.to_le() }
1448    }
1449
1450    /// Creates a WebAssembly `exnref` value
1451    #[inline]
1452    pub fn exnref(r: u32) -> ValRaw {
1453        assert!(cfg!(feature = "gc") || r == 0);
1454        ValRaw { exnref: r.to_le() }
1455    }
1456
1457    #[inline]
1458    pub(crate) fn vmgcref(r: Option<VMGcRef>) -> ValRaw {
1459        let raw = r.map_or(0, |r| r.as_raw_u32());
1460
1461        // NB: All `VMGcRef`-based `ValRaw`s are the same.
1462        debug_assert_eq!(raw, ValRaw::anyref(raw).get_exnref());
1463        debug_assert_eq!(raw, ValRaw::exnref(raw).get_externref());
1464        debug_assert_eq!(raw, ValRaw::externref(raw).get_anyref());
1465
1466        ValRaw::anyref(raw)
1467    }
1468
1469    /// Gets the WebAssembly `i32` value
1470    #[inline]
1471    pub fn get_i32(&self) -> i32 {
1472        unsafe { i32::from_le(self.i32) }
1473    }
1474
1475    /// Gets the WebAssembly `i64` value
1476    #[inline]
1477    pub fn get_i64(&self) -> i64 {
1478        unsafe { i64::from_le(self.i64) }
1479    }
1480
1481    /// Gets the WebAssembly `i32` value
1482    #[inline]
1483    pub fn get_u32(&self) -> u32 {
1484        self.get_i32().cast_unsigned()
1485    }
1486
1487    /// Gets the WebAssembly `i64` value
1488    #[inline]
1489    pub fn get_u64(&self) -> u64 {
1490        self.get_i64().cast_unsigned()
1491    }
1492
1493    /// Gets the WebAssembly `f32` value
1494    #[inline]
1495    pub fn get_f32(&self) -> u32 {
1496        unsafe { u32::from_le(self.f32) }
1497    }
1498
1499    /// Gets the WebAssembly `f64` value
1500    #[inline]
1501    pub fn get_f64(&self) -> u64 {
1502        unsafe { u64::from_le(self.f64) }
1503    }
1504
1505    /// Gets the WebAssembly `v128` value
1506    #[inline]
1507    pub fn get_v128(&self) -> u128 {
1508        unsafe { u128::from_le_bytes(self.v128) }
1509    }
1510
1511    /// Gets the WebAssembly `funcref` value
1512    #[inline]
1513    pub fn get_funcref(&self) -> *mut c_void {
1514        let addr = unsafe { usize::from_le(self.funcref.addr()) };
1515        core::ptr::with_exposed_provenance_mut(addr)
1516    }
1517
1518    /// Gets the WebAssembly `externref` value
1519    #[inline]
1520    pub fn get_externref(&self) -> u32 {
1521        let externref = u32::from_le(unsafe { self.externref });
1522        assert!(cfg!(feature = "gc") || externref == 0);
1523        externref
1524    }
1525
1526    /// Gets the WebAssembly `anyref` value
1527    #[inline]
1528    pub fn get_anyref(&self) -> u32 {
1529        let anyref = u32::from_le(unsafe { self.anyref });
1530        assert!(cfg!(feature = "gc") || anyref == 0);
1531        anyref
1532    }
1533
1534    /// Gets the WebAssembly `exnref` value
1535    #[inline]
1536    pub fn get_exnref(&self) -> u32 {
1537        let exnref = u32::from_le(unsafe { self.exnref });
1538        assert!(cfg!(feature = "gc") || exnref == 0);
1539        exnref
1540    }
1541
1542    /// Get the inner `VMGcRef`.
1543    pub(crate) fn get_vmgcref(&self) -> Option<crate::vm::VMGcRef> {
1544        debug_assert_eq!(self.get_anyref(), self.get_exnref());
1545        debug_assert_eq!(self.get_anyref(), self.get_externref());
1546        VMGcRef::from_raw_u32(self.get_anyref())
1547    }
1548}
1549
1550/// An "opaque" version of `VMContext` which must be explicitly casted to a
1551/// target context.
1552///
1553/// This context is used to represent that contexts specified in
1554/// `VMFuncRef` can have any type and don't have an implicit
1555/// structure. Neither wasmtime nor cranelift-generated code can rely on the
1556/// structure of an opaque context in general and only the code which configured
1557/// the context is able to rely on a particular structure. This is because the
1558/// context pointer configured for `VMFuncRef` is guaranteed to be
1559/// the first parameter passed.
1560///
1561/// Note that Wasmtime currently has a layout where all contexts that are casted
1562/// to an opaque context start with a 32-bit "magic" which can be used in debug
1563/// mode to debug-assert that the casts here are correct and have at least a
1564/// little protection against incorrect casts.
1565pub struct VMOpaqueContext {
1566    pub(crate) magic: u32,
1567    _marker: marker::PhantomPinned,
1568}
1569
1570impl VMOpaqueContext {
1571    /// Helper function to clearly indicate that casts are desired.
1572    #[inline]
1573    pub fn from_vmcontext(ptr: NonNull<VMContext>) -> NonNull<VMOpaqueContext> {
1574        ptr.cast()
1575    }
1576
1577    /// Helper function to clearly indicate that casts are desired.
1578    #[inline]
1579    pub fn from_vm_array_call_host_func_context(
1580        ptr: NonNull<VMArrayCallHostFuncContext>,
1581    ) -> NonNull<VMOpaqueContext> {
1582        ptr.cast()
1583    }
1584}