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