Skip to main content

wasmtime_environ/
vmtypes.rs

1//! Centralized definitions of the various `VM*` types whose layout is shared
2//! between the runtime (which uses the actual structures) and the compiler
3//! (which uses the types' offsets and has per-type alias regions).
4//!
5//! To keep these in sync, the shape of each type is defined exactly once here,
6//! via the higher-order [`for_each_vm_type!`] macro, and each consumer
7//! generates its view of the type from that single source of truth.
8
9/// Invoke the given macro `$mac` once, passing it the definitions of each of the
10/// `VM*` types whose layout is shared between the runtime, compilation offsets,
11/// and Cranelift alias regions.
12///
13/// This is a higher-order macro: callers define a `macro_rules!` macro that
14/// matches the grammar defined below and pass its name as an argument to this
15/// macro's invocation, e.g. `for_each_vm_type!(define_vm_types)`.
16///
17/// # Grammar
18///
19/// Each type is either a `struct` or a `#[repr(C, _)]` `enum`, preceded by:
20///
21/// * Doc-comment attributes (`#[doc = "..."]`).
22///
23/// * An optional `#[cfg(...)]` attribute, gating the type on the Cargo features
24///   whose code actually uses it.
25///
26///   Only the runtime's `struct` definition (and its layout test) is gated by
27///   it. A type's offsets and alias regions are always generated because the
28///   `wasmtime-environ` and `wasmtime-internal-cranelift` crates do not have
29///   Cargo features for all the various Wasm features.
30///
31/// * An optional `#[derive(...)]` attribute.
32///
33/// * A `#[repr(...)]` attribute.
34///
35/// * A `#[snake_name = <ident>]` attribute giving the type's name in
36///   `snake_case`, used to generate accessor method names.
37///
38/// Each field may be preceded by doc-comment attributes and, optionally, these
39/// marker attributes, in this order:
40///
41/// * `#[aggregate]`: this field is a composite (a nested struct or array)
42///   rather than a single scalar. Compiled Wasm code accesses such a field's
43///   interior piecewise, so there is no one Cranelift type for the field as a
44///   whole and no alias-region accessor is generated for it. The field's offset
45///   is still generated, since that is what interior accesses are computed
46///   relative to.
47///
48/// * `#[indexed]`: this field is a fixed-size array of a scalar type, whose
49///   elements compiled Wasm code accesses individually by a compile-time
50///   constant index. Like `#[aggregate]`, the field has no single Cranelift
51///   type; unlike `#[aggregate]`, its elements all do, so an alias-region
52///   accessor taking that index is generated for it and each element gets its
53///   own alias region.
54///
55/// * `#[readonly]` and/or `#[can_move]`: describe how Cranelift may treat loads
56///   and stores of that field.
57///
58/// ## Enums
59///
60/// A type may also be an `enum`, which must be `#[repr(C, $tag)]` for an
61/// integer `$tag`:
62///
63/// ```ignore
64/// #[derive(Debug)]
65/// #[repr(C, u32)]
66/// #[snake_name = vm_example]
67/// pub enum VMExample {
68///     #[snake_name = variant_a]
69///     VariantA {
70///         field: u32,
71///     } = 0,
72///
73///     #[snake_name = variant_b]
74///     VariantB {
75///         other: u64,
76///     } = 1,
77/// }
78/// ```
79///
80/// Rust lays such an enum out as a `#[repr(C)]` struct of a `$tag` tag followed
81/// by a union of the variants, which is what lets the same offset machinery
82/// describe it. The `C` is what guarantees that, so it is required.
83///
84/// Beyond a struct's rules, each variant needs an explicit discriminant (the
85/// tag values compiled code compares against), braces even when empty, and its
86/// own `#[snake_name]` for its generated accessors. Variant fields take a
87/// struct field's marker attributes but no visibility.
88///
89/// An enum gets two alias regions rather than a struct's one per field: one for
90/// the tag, one shared by all variants' fields, because they overlap.
91#[macro_export]
92macro_rules! for_each_vm_type {
93    ($mac:ident) => {
94        $mac! {
95            /// The fields compiled code needs to access to utilize a WebAssembly linear
96            /// memory defined within the instance, namely the start address and the
97            /// size in bytes.
98            #[derive(Debug)]
99            #[repr(C)]
100            #[snake_name = vm_memory_definition]
101            pub struct VMMemoryDefinition {
102                /// The start address.
103                pub base: VmPtr<u8>,
104
105                /// The current logical size of this linear memory in bytes.
106                ///
107                /// This is atomic because shared memories must be able to grow their length
108                /// atomically. For relaxed access, see
109                /// [`VMMemoryDefinition::current_length()`].
110                pub current_length: AtomicUsize,
111            }
112
113            /// The fields compiled code needs to access to utilize a WebAssembly table
114            /// defined within the instance.
115            #[derive(Debug, Copy, Clone)]
116            #[repr(C)]
117            #[snake_name = vm_table_definition]
118            pub struct VMTableDefinition {
119                /// Pointer to the table data.
120                pub base: VmPtr<u8>,
121
122                /// The current number of elements in the table.
123                pub current_elements: usize,
124            }
125
126            /// A WebAssembly tag defined within the instance.
127            #[derive(Debug)]
128            #[repr(C)]
129            #[snake_name = vm_tag_definition]
130            pub struct VMTagDefinition {
131                /// Function signature's type id.
132                pub type_index: VMSharedTypeIndex,
133            }
134
135            /// The VM caller-checked "funcref" record, for caller-side signature checking.
136            ///
137            /// It consists of function pointer(s), a type id to be checked by the
138            /// caller, and the vmctx closure associated with this function.
139            #[derive(Debug, Clone)]
140            #[repr(C)]
141            #[snake_name = vm_func_ref]
142            pub struct VMFuncRef {
143                /// Function pointer for this funcref if being called via the "array"
144                /// calling convention that `Func::new` et al use.
145                pub array_call: VmPtr<VMArrayCallFunction>,
146
147                /// Function pointer for this funcref if being called via the calling
148                /// convention we use when compiling Wasm.
149                ///
150                /// Most functions come with a function pointer that we can use when they
151                /// are called from Wasm. The notable exception is when we `Func::wrap` a
152                /// host function, and we don't have a Wasm compiler on hand to compile a
153                /// Wasm-to-native trampoline for the function. In this case, we leave
154                /// `wasm_call` empty until the function is passed as an import to Wasm (or
155                /// otherwise exposed to Wasm via tables/globals). At this point, we look up
156                /// a Wasm-to-native trampoline for the function in the Wasm's compiled
157                /// module and use that fill in `VMFunctionImport::wasm_call`. **However**
158                /// there is no guarantee that the Wasm module has a trampoline for this
159                /// function's signature. The Wasm module only has trampolines for its
160                /// types, and if this function isn't of one of those types, then the Wasm
161                /// module will not have a trampoline for it. This is actually okay, because
162                /// it means that the Wasm cannot actually call this function. But it does
163                /// mean that this field needs to be an `Option` even though it is non-null
164                /// the vast vast vast majority of the time.
165                ///
166                /// Once a `VMFuncRef` is exposed to compiled code this field
167                /// never changes again, so accesses of it are `readonly`. It is
168                /// not `can_move`, however: the load may be the one that traps
169                /// on a null funcref, and moving it would move that trap.
170                #[readonly]
171                pub wasm_call: Option<VmPtr<VMWasmCallFunction>>,
172
173                /// Function signature's type id.
174                ///
175                /// See the note about `readonly` and not `can_move` on
176                /// `wasm_call`.
177                #[readonly]
178                pub type_index: VMSharedTypeIndex,
179
180                /// The VM state associated with this function.
181                ///
182                /// The actual definition of what this pointer points to depends on the
183                /// function being referenced: for core Wasm functions, this is a `*mut
184                /// VMContext`, for host functions it is a `*mut VMHostFuncContext`, and for
185                /// component functions it is a `*mut VMComponentContext`.
186                ///
187                /// See the note about `readonly` and not `can_move` on
188                /// `wasm_call`.
189                #[readonly]
190                pub vmctx: VmPtr<VMOpaqueContext>,
191            }
192
193            /// An imported function.
194            ///
195            /// Basically the same as `VMFuncRef`, except that `wasm_call` is not optional.
196            #[derive(Debug, Clone)]
197            #[repr(C)]
198            #[snake_name = vm_function_import]
199            pub struct VMFunctionImport {
200                /// Same as `VMFuncRef::array_call`.
201                #[readonly]
202                #[can_move]
203                pub array_call: VmPtr<VMArrayCallFunction>,
204
205                /// Same as `VMFuncRef::wasm_call`, except always non-null. Must be filled
206                /// in by the time Wasm is importing this function!
207                #[readonly]
208                #[can_move]
209                pub wasm_call: VmPtr<VMWasmCallFunction>,
210
211                /// Function signature's _actual_ type id.
212                ///
213                /// This is the type that the function was defined with, not the type that
214                /// it was imported as. These two can be different in the face of subtyping
215                /// and we need the former for to correctly implement dynamic downcasts.
216                #[readonly]
217                #[can_move]
218                pub type_index: VMSharedTypeIndex,
219
220                /// Same as `VMFuncRef::vmctx`.
221                #[readonly]
222                #[can_move]
223                pub vmctx: VmPtr<VMOpaqueContext>,
224            }
225
226            /// The fields compiled code needs to access to utilize a WebAssembly table
227            /// imported from another instance.
228            #[derive(Debug, Copy, Clone)]
229            #[repr(C)]
230            #[snake_name = vm_table_import]
231            pub struct VMTableImport {
232                /// A pointer to the imported table description.
233                #[readonly]
234                #[can_move]
235                pub from: VmPtr<VMTableDefinition>,
236
237                /// A pointer to the `VMContext` that owns the table description.
238                #[readonly]
239                #[can_move]
240                pub vmctx: VmPtr<VMContext>,
241
242                /// The table index, within `vmctx`, this definition resides at.
243                #[readonly]
244                #[can_move]
245                pub index: DefinedTableIndex,
246            }
247
248            /// The fields compiled code needs to access to utilize a WebAssembly linear
249            /// memory imported from another instance.
250            #[derive(Debug, Copy, Clone)]
251            #[repr(C)]
252            #[snake_name = vm_memory_import]
253            pub struct VMMemoryImport {
254                /// A pointer to the imported memory description.
255                #[readonly]
256                #[can_move]
257                pub from: VmPtr<VMMemoryDefinition>,
258
259                /// A pointer to the `VMContext` that owns the memory description.
260                #[readonly]
261                #[can_move]
262                pub vmctx: VmPtr<VMContext>,
263
264                /// The index of the memory in the containing `vmctx`.
265                #[readonly]
266                #[can_move]
267                pub index: DefinedMemoryIndex,
268            }
269
270            /// The fields compiled code needs to access to utilize a WebAssembly global
271            /// variable imported from another instance.
272            ///
273            /// Note that unlike with functions, tables, and memories, `VMGlobalImport`
274            /// doesn't include a `vmctx` pointer. Globals are never resized, and don't
275            /// require a `vmctx` pointer to access.
276            #[derive(Debug, Copy, Clone)]
277            #[repr(C)]
278            #[snake_name = vm_global_import]
279            pub struct VMGlobalImport {
280                /// A pointer to the imported global variable description.
281                #[readonly]
282                #[can_move]
283                pub from: VmPtr<VMGlobalDefinition>,
284
285                /// A pointer to the context that owns the global.
286                ///
287                /// Exactly what's stored here is dictated by `kind` below. This is `None`
288                /// for `VMGlobalKind::Host`, it's a `VMContext` for
289                /// `VMGlobalKind::Instance`, and it's `VMComponentContext` for
290                /// `VMGlobalKind::ComponentFlags`.
291                #[readonly]
292                #[can_move]
293                pub vmctx: Option<VmPtr<VMOpaqueContext>>,
294
295                /// The kind of global, and extra location information in addition to
296                /// `vmctx` above.
297                #[readonly]
298                #[can_move]
299                pub kind: VMGlobalKind,
300            }
301
302            /// The fields compiled code needs to access to utilize a WebAssembly
303            /// tag imported from another instance.
304            #[derive(Debug, Copy, Clone)]
305            #[repr(C)]
306            #[snake_name = vm_tag_import]
307            pub struct VMTagImport {
308                /// A pointer to the imported tag description.
309                #[readonly]
310                #[can_move]
311                pub from: VmPtr<VMTagDefinition>,
312
313                /// The instance that owns this tag.
314                #[readonly]
315                #[can_move]
316                pub vmctx: VmPtr<VMContext>,
317
318                /// The index of the tag in the containing `vmctx`.
319                #[readonly]
320                #[can_move]
321                pub index: DefinedTagIndex,
322            }
323
324            /// Structure that holds all mutable context that is shared across all instances
325            /// in a store, for example data related to fuel or epochs.
326            ///
327            /// `VMStoreContext`s are one-to-one with `wasmtime::Store`s, the same way that
328            /// `VMContext`s are one-to-one with `wasmtime::Instance`s. And the same way
329            /// that multiple `wasmtime::Instance`s may be associated with the same
330            /// `wasmtime::Store`, multiple `VMContext`s hold a pointer to the same
331            /// `VMStoreContext` when they are associated with the same `wasmtime::Store`.
332            #[derive(Debug)]
333            // NB: `align(8)` is forced rather than inferred because the i386
334            // System V ABI aligns 64-bit integers to 4 bytes, and `VMOffsets`
335            // can't tell that target apart from the ones that align them to 8,
336            // since it only knows the target's pointer width.
337            #[repr(C, align(8))]
338            #[snake_name = vm_store_context]
339            pub struct VMStoreContext {
340                // NB: 64-bit integer fields are located first with pointer-sized fields
341                // trailing afterwards. That makes the offsets in this structure easier to
342                // calculate on 32-bit platforms as we don't have to worry about the
343                // alignment of 64-bit integers.
344                //
345                /// Indicator of how much fuel has been consumed and is remaining to
346                /// WebAssembly.
347                ///
348                /// This field is typically negative and increments towards positive. Upon
349                /// turning positive a wasm trap will be generated. This field is only
350                /// modified if wasm is configured to consume fuel.
351                pub fuel_consumed: UnsafeCell<i64>,
352
353                /// Deadline epoch for interruption: if epoch-based interruption
354                /// is enabled and the global (per engine) epoch counter is
355                /// observed to reach or exceed this value, the guest code will
356                /// yield if running asynchronously.
357                pub epoch_deadline: UnsafeCell<u64>,
358
359                /// The "store version".
360                ///
361                /// This is used to test whether stack-frame handles referring to
362                /// suspended stack frames remain valid.
363                ///
364                /// The invariant that this upward-counting number must satisfy
365                /// is: the number must be incremented whenever execution starts
366                /// or resumes in the `Store` or when any stack is
367                /// dropped/freed. That way, if we take a reference to some
368                /// suspended stack frame and track the "version" at the time we
369                /// took that reference, if the version still matches, we can be
370                /// sure that nothing could have unwound the referenced Wasm
371                /// frame.
372                ///
373                /// This version number is incremented in exactly one place: the
374                /// Wasm-to-host trampolines, after return from host code. Note
375                /// that this captures both the normal "return into Wasm" case
376                /// (where Wasm frames can subsequently return normally and thus
377                /// invalidate frames), and the "trap/exception unwinds Wasm
378                /// frames" case, which is done internally via the `raise` libcall
379                /// invoked after the main hostcall returns an error, and after we
380                /// increment this version number.
381                ///
382                /// Note that this also handles the fiber/future-drop case because
383                /// because we *always* return into the trampoline to clean up;
384                /// that trampoline immediately raises an error and uses the
385                /// longjmp-like unwind within Cranelift frames to skip over all
386                /// the guest Wasm frames, but not before it increments the
387                /// store's execution version number.
388                ///
389                /// This field is in use only if guest debugging is enabled.
390                pub execution_version: u64,
391
392                /// Current stack limit of the wasm module.
393                ///
394                /// For more information see `crates/cranelift/src/lib.rs`.
395                pub stack_limit: UnsafeCell<usize>,
396
397                /// The `VMMemoryDefinition` for this store's GC heap.
398                #[aggregate]
399                pub gc_heap: UnsafeCell<VMMemoryDefinition>,
400
401                /// The value of the frame pointer register in the trampoline used
402                /// to call from Wasm to the host.
403                ///
404                /// Maintained by our Wasm-to-host trampoline, and cleared just
405                /// before calling into Wasm in `catch_traps`.
406                ///
407                /// This member is `0` when Wasm is actively running and has not called out
408                /// to the host.
409                ///
410                /// Used to find the start of a contiguous sequence of Wasm frames
411                /// when walking the stack. Note that we record the FP of the
412                /// *trampoline*'s frame, not the last Wasm frame, because we need
413                /// to know the SP (bottom of frame) of the last Wasm frame as
414                /// well in case we need to resume to an exception handler in that
415                /// frame. The FP of the last Wasm frame can be recovered by
416                /// loading the saved FP value at this FP address.
417                pub last_wasm_exit_trampoline_fp: UnsafeCell<usize>,
418
419                /// The last Wasm program counter before we called from Wasm to the host.
420                ///
421                /// Maintained by our Wasm-to-host trampoline, and cleared just before
422                /// calling into Wasm in `catch_traps`.
423                ///
424                /// This member is `0` when Wasm is actively running and has not called out
425                /// to the host.
426                ///
427                /// Used when walking a contiguous sequence of Wasm frames.
428                pub last_wasm_exit_pc: UnsafeCell<usize>,
429
430                /// The last host stack pointer before we called into Wasm from the host.
431                ///
432                /// Maintained by our host-to-Wasm trampoline. This member is `0` when Wasm
433                /// is not running, and it's set to nonzero once a host-to-wasm trampoline
434                /// is executed.
435                ///
436                /// When a host function is wrapped into a `wasmtime::Func`, and is then
437                /// called from the host, then this member is not changed meaning that the
438                /// previous activation in pointed to by `last_wasm_exit_trampoline_fp` is
439                /// still the last wasm set of frames on the stack.
440                ///
441                /// This field is saved/restored during fiber suspension/resumption
442                /// resumption as part of `CallThreadState::swap`.
443                ///
444                /// This field is used to find the end of a contiguous sequence of Wasm
445                /// frames when walking the stack. Additionally it's used when a trap is
446                /// raised as part of the set of parameters used to resume in the entry
447                /// trampoline's "catch" block.
448                pub last_wasm_entry_sp: UnsafeCell<usize>,
449
450                /// Same as `last_wasm_entry_sp`, but for the `fp` of the trampoline.
451                pub last_wasm_entry_fp: UnsafeCell<usize>,
452
453                /// The last trap handler from a host-to-wasm entry trampoline on the stack.
454                ///
455                /// This field is configured when the host calls into wasm by the trampoline
456                /// itself. It stores the `pc` of an exception handler suitable to handle
457                /// all traps (or uncaught exceptions).
458                pub last_wasm_entry_trap_handler: UnsafeCell<usize>,
459
460                /// Stack information used by stack switching instructions. See documentation
461                /// on `VMStackChain` for details.
462                #[aggregate]
463                pub stack_chain: UnsafeCell<VMStackChain>,
464
465                /// A pointer to the embedder's `T` inside a `Store<T>`, for use with the
466                /// `store-data-address` unsafe intrinsic.
467                ///
468                /// This pointer is fixed for the lifetime of the store, so loads
469                /// of it are `readonly` and `can_move`.
470                #[readonly]
471                #[can_move]
472                pub store_data: VmPtr<()>,
473
474                /// The range, in addresses, of the guard page that is currently in use.
475                ///
476                /// This field is used when signal handlers are run to determine whether a
477                /// faulting address lies within the guard page of an async stack for
478                /// example. If this happens then the signal handler aborts with a stack
479                /// overflow message similar to what would happen had the stack overflow
480                /// happened on the main thread. This field is, by default a null..null
481                /// range indicating that no async guard is in use (aka no fiber). In such a
482                /// situation while this field is read it'll never classify a fault as an
483                /// guard page fault.
484                #[aggregate]
485                pub async_guard_range: Range<*mut u8>,
486
487                /// The `context.{get,set}` values for the current thread in the component
488                /// model. This is only used for `component-model-async` and slot[1] is only
489                /// used for `component-model-threading`. Despite the conditional use nature
490                /// this is unconditionally present as it avoids the need to make logic in
491                /// `VMOffsets` conditional.
492                ///
493                /// This is saved/restored when threads are swapped in the component model.
494                ///
495                /// NB: `UnsafeCell` because JIT code writes to the slots.
496                #[indexed]
497                pub component_context: UnsafeCell<[u32; NUM_COMPONENT_CONTEXT_SLOTS]>,
498
499                /// JIT-visible current thread for the component model's sync-to-sync
500                /// adapter fast path.
501                ///
502                /// Like `component_context`, this is unconditionally present to keep
503                /// `VMOffsets` logic unconditional even though it is only used when
504                /// `component-model-async` is enabled.
505                ///
506                /// NB: `UnsafeCell` because JIT code writes to this field.
507                pub current_thread: UnsafeCell<VMLazyThread>,
508
509                /// Resource lends made under unforced `VMDeferredThread`s and not
510                /// yet reflected in any handle's `lend_count`.
511                ///
512                /// Holds `LAZY_LENDERS_CAPACITY` entries.
513                #[readonly]
514                #[can_move]
515                pub lazy_lenders: VmPtr<VMResourceIndex>,
516
517                /// Number of occupied slots at the front of `lazy_lenders`.
518                ///
519                /// NB: `UnsafeCell` because JIT code writes to this field.
520                pub lazy_lenders_len: UnsafeCell<usize>,
521            }
522
523            /// JIT-visible representation of the store's current thread for the component
524            /// model, encoded as a single pointer-sized integer so that generated JIT code
525            /// can load, store, and compare it with a handful of instructions.
526            ///
527            /// This is the inline fast-path counterpart to the host-side `CurrentThread`: a
528            /// fused sync-to-sync adapter records a lazy deferred thread here (a pointer to
529            /// a `VMDeferredThread` on its own stack frame) instead of eagerly allocating a
530            /// `GuestTask`/`GuestThread` in the host. Host code promotes the deferred
531            /// thread into a real one only when it actually needs it; see
532            /// `StoreOpaque::force_current_thread`.
533            ///
534            /// This type is a bitpacked equivalent of the following logical `enum`:
535            ///
536            /// ```ignore
537            /// enum VMLazyThread {
538            ///     /// No thread.
539            ///     None,
540            ///
541            ///     /// The lazy thread was promoted and materialized; get it from
542            ///     /// `ConcurrentState::current_thread`.
543            ///     Forced,
544            ///
545            ///     /// The lazy thread has not been materialized, here is a pointer to the
546            ///     /// stack-allocated data needed to do force that promotion.
547            ///     Deferred(*mut VMDeferredThread),
548            /// }
549            /// ```
550            ///
551            /// Bitpacking details:
552            ///
553            /// * `None`: `0`
554            ///
555            /// * `Forced`: A non-zero value with its low-bit set.
556            ///
557            /// * `Deferred`: A non-zero value with its low-bit clear.
558            #[derive(Debug, Copy, Clone, PartialEq, Eq)]
559            #[repr(transparent)]
560            #[snake_name = vm_lazy_thread]
561            pub struct VMLazyThread {
562                /// The bitpacked thread representation described above.
563                ///
564                /// Private: use the `VMLazyThread::{none,forced,deferred}` constructors
565                /// and the `is_*`/`as_deferred` accessors instead of touching this
566                /// directly.
567                thread: Option<VmPtr<VMDeferredThread>>,
568            }
569
570            /// JIT-visible encoding of a component-model resource handle, as stored in
571            /// the `VMStoreContext::lazy_lenders` buffer.
572            ///
573            /// This is the raw version of `TypedResourceIndex` that is exposed to Wasm
574            /// code; use `VMResourceIndex::{new,get}` to convert.
575            #[derive(Debug, Copy, Clone, PartialEq, Eq)]
576            #[repr(C)]
577            #[snake_name = vm_resource_index]
578            pub struct VMResourceIndex {
579                /// The raw `TypeResourceTableIndex`, or `u32::MAX` for a host resource.
580                pub(crate) ty: u32,
581
582                /// The handle's index within its table.
583                pub(crate) index: u32,
584            }
585
586            /// A deferred component-model thread.
587            ///
588            /// This is an on-stack record pushed by a fused sync-to-sync adapter's fast
589            /// path to defer the work that the `enter_sync_call` libcall would otherwise do
590            /// eagerly.
591            ///
592            /// The adapter allocates one of these in its own stack frame, links the
593            /// previous current-thread value to it via `parent`, and finally points
594            /// `VMStoreContext::current_thread` at it. When host code actually needs the
595            /// real thread, it walks the `parent` chain to materialize thread state (see
596            /// `StoreOpaque::force_current_thread`).
597            #[derive(Debug)]
598            #[repr(C)]
599            #[snake_name = vm_deferred_thread]
600            pub struct VMDeferredThread {
601                /// The previous value of `VMStoreContext::current_thread`.
602                pub parent: VMLazyThread,
603
604                /// Whether the callee is async-lifted (a deferred `enter_sync_call` arg).
605                pub callee_async: u32,
606
607                /// The callee component instance (a deferred `enter_sync_call` argument).
608                pub callee_instance: u32,
609
610                /// The caller thread's `context.{get,set}` slots, saved on entry and
611                /// restored on the fast-path exit (or recovered while forcing).
612                #[indexed]
613                pub saved_context: [u32; NUM_COMPONENT_CONTEXT_SLOTS],
614
615                /// `VMStoreContext::lazy_lenders_len` as of this frame's push, so
616                /// that the lends this frame recorded are everything at or after it.
617                ///
618                /// Frames nest with the call stack, so that is always a contiguous
619                /// suffix by the time this frame exits, and exiting an unforced frame
620                /// discards it by resetting `lazy_lenders_len` back to this.
621                pub lazy_lenders_start: usize,
622            }
623
624            /// This type is used to save (and subsequently restore) a subset of
625            /// the data in `VMStoreContext`.
626            ///
627            /// See documentation of `VMStackChain` for the exact uses.
628            #[derive(Debug, Default, Clone)]
629            #[repr(C)]
630            #[snake_name = vm_stack_limits]
631            pub struct VMStackLimits {
632                /// Saved version of the `stack_limit` field of `VMStoreContext`.
633                pub stack_limit: usize,
634                /// Saved version of the `last_wasm_entry_fp` field of
635                /// `VMStoreContext`.
636                pub last_wasm_entry_fp: usize,
637                /// Saved version of the `last_wasm_entry_sp` field of
638                /// `VMStoreContext`.
639                pub last_wasm_entry_sp: usize,
640                /// Saved version of the `last_wasm_entry_trap_handler` field of
641                /// `VMStoreContext`.
642                pub last_wasm_entry_trap_handler: usize,
643            }
644
645            /// A reference to a buffer ("array") allocated on a continuation's
646            /// stack.
647            ///
648            /// The elements are of whatever type the buffer's user expects;
649            /// `data` is an untyped pointer, and the runtime casts it at each
650            /// use site.
651            #[derive(Debug, Clone)]
652            #[repr(C)]
653            #[snake_name = vm_host_array]
654            pub struct VMHostArray {
655                /// Number of currently occupied slots.
656                pub length: u32,
657
658                /// Number of slots in the data buffer. Note that this is *not*
659                /// the size of the buffer in bytes!
660                pub capacity: u32,
661
662                /// The buffer itself, which lives on the continuation's stack
663                /// rather than in this object.
664                pub data: Option<VmPtr<u8>>,
665            }
666
667            /// Payload values exchanged with a continuation and the metadata
668            /// needed to trace GC references among them.
669            #[derive(Debug, Clone)]
670            #[repr(C)]
671            #[snake_name = vm_payloads]
672            pub struct VMPayloads {
673                /// The payload values themselves.
674                #[aggregate]
675                pub buffer: VMHostArray,
676
677                /// One marker byte per buffer slot, indicating whether that
678                /// slot contains a GC reference, or `None` when no slots do.
679                pub gc_ref_data: Option<VmPtr<u8>>,
680            }
681
682            /// AddressSanitizer bookkeeping associated with a stack.
683            #[derive(Debug, Clone, Default)]
684            #[repr(C)]
685            #[snake_name = vm_asan_stack_support]
686            pub struct VMAsanStackSupport {
687                /// Bottom of the usable stack range reported to ASan,
688                /// or `None` until ASan discovers an initial stack's
689                /// bounds. Technically only needed by the runtime,
690                /// but we are using `VmPtr` here to avoid introducing
691                /// macro rules for `*mut u8` just for the sake of ASan
692                /// builds.
693                pub stack_bottom: Option<VmPtr<u8>>,
694
695                /// Size of the usable stack range reported to ASan.
696                pub stack_size: usize,
697
698                /// The stack whose bounds ASan will report when the next
699                /// stack-switch handshake is completed on this stack.
700                /// `None` when no handshake is pending.
701                pub pending_source_csi: Option<VmPtr<VMCommonStackInformation>>,
702            }
703
704            /// The information saved for every stack, whether it is a
705            /// continuation's or the initial stack's.
706            #[derive(Debug, Clone)]
707            #[repr(C)]
708            #[snake_name = vm_common_stack_information]
709            pub struct VMCommonStackInformation {
710                /// The subset of `VMStoreContext` saved for this stack.
711                #[aggregate]
712                pub limits: VMStackLimits,
713
714                /// Where this stack is in its life cycle; a `VMStackState`
715                /// discriminant.
716                pub state: VMStackState,
717
718                /// The tags this stack handles, set while it is a `Parent`.
719                #[aggregate]
720                pub handlers: VMHostArray,
721
722                /// The index within `handlers` of the first `switch` handler.
723                pub first_switch_handler_index: u32,
724
725                /// AddressSanitizer bookkeeping for this stack.
726                #[aggregate]
727                pub asan: VMAsanStackSupport,
728            }
729
730            /// A continuation.
731            #[repr(C)]
732            #[snake_name = vm_cont_ref]
733            pub struct VMContRef {
734                /// The information saved for this continuation's stack.
735                #[aggregate]
736                pub common_stack_information: VMCommonStackInformation,
737
738                /// This continuation's parent: another continuation, the
739                /// initial stack, or absent.
740                #[aggregate]
741                pub parent_chain: VMStackChain,
742
743                /// Revision counter.
744                pub revision: usize,
745
746                /// The end of this continuation's parent chain while it is
747                /// `Suspended` or `Fresh`, and `None` while it is running.
748                pub last_ancestor: Option<VmPtr<VMContRef>>,
749
750                /// The stack this continuation runs on.
751                #[aggregate]
752                pub stack: VMContinuationStack,
753
754                /// The arguments to, and return values of, the function passed
755                /// to `cont.new`.
756                #[aggregate]
757                pub args: VMPayloads,
758
759                /// The payloads passed to and from this continuation once it
760                /// has been suspended.
761                #[aggregate]
762                pub values: VMPayloads,
763
764                /// Tells the compiler that this structure has potential
765                /// self-references, through `last_ancestor`.
766                ///
767                /// This is a zero-sized type in final position, so it affects
768                /// neither this type's size nor its alignment.
769                #[aggregate]
770                pub _marker: PhantomPinned,
771            }
772
773            /// A slight variation of `VMContObj` which allows the
774            /// `contref` to be instantiated to null,
775            /// i.e. `Option::None`. This representation is used by
776            /// the GC infrastructure to construct a canonical
777            /// null-esque continuation object.
778            #[cfg(all(feature = "gc", feature = "stack-switching"))]
779            #[repr(C)]
780            #[snake_name = vm_raw_cont_obj]
781            pub struct VMRawContObj {
782                pub contref: Option<VmPtr<u8>>,
783                pub revision: usize,
784            }
785
786            /// The deferred-reference-counting collector's JIT-accessible heap
787            /// data.
788            ///
789            /// This is a separate allocation, reached through the
790            /// `VMContext::gc_heap_data` pointer. Its fields are not GC heap
791            /// locations, so they get this type's own alias regions rather than
792            /// the GC heap's.
793            ///
794            /// `wasmtime::runtime::vm::gc::enabled::drc` owns one of these,
795            /// wrapped in a cell because compiled Wasm writes to it, and
796            /// accesses it only through that wrapper's methods.
797            #[cfg(feature = "gc-drc")]
798            #[derive(Default)]
799            #[repr(C)]
800            #[snake_name = vm_drc_heap_data]
801            pub struct VMDrcHeapData {
802                /// The head of the over-approximated-stack-roots list.
803                pub over_approximated_stack_roots: Option<VMGcRef>,
804
805                /// The current size of the over-approximated-stack-roots list.
806                pub current_over_approximated_stack_roots_len: u32,
807
808                /// The size of the over-approximated-stack-roots list
809                /// immediately after the last GC.
810                pub over_approximated_stack_roots_len_after_last_gc: u32,
811            }
812
813            /// The copying collector's JIT-accessible bump-allocation state.
814            ///
815            /// Like [`VMDrcHeapData`], this is a separate allocation reached
816            /// through `VMContext::gc_heap_data`, and is owned, wrapped in a
817            /// cell, by `wasmtime::runtime::vm::gc::enabled::copying`.
818            #[cfg(feature = "gc-copying")]
819            #[derive(Default)]
820            #[repr(C)]
821            #[snake_name = vm_copying_heap_data]
822            pub struct VMCopyingHeapData {
823                /// Current bump pointer (an index into the GC heap).
824                pub bump_ptr: u32,
825
826                /// End of the active semi-space.
827                pub active_space_end: u32,
828            }
829
830            /// The null collector's JIT-accessible bump-allocation state.
831            ///
832            /// Unlike the two above, this is not a separate allocation: it is
833            /// the first field of `NullHeap` (in
834            /// `wasmtime::runtime::vm::gc::enabled::null`), again wrapped in a
835            /// cell, and compiled Wasm reaches it through a pointer to that
836            /// field.
837            #[cfg(feature = "gc-null")]
838            #[repr(C)]
839            #[snake_name = vm_null_heap_data]
840            pub struct VMNullHeapData {
841                /// The bump-allocation finger, an index into the GC heap.
842                pub next: NonZeroU32,
843            }
844
845            /// The common header for all objects allocated in a GC heap.
846            ///
847            /// This header is shared across all collectors, although particular
848            /// collectors may always add their own trailing fields to this
849            /// header for all of their own GC objects.
850            ///
851            /// This is a bit-packed structure that logically has the following
852            /// fields:
853            ///
854            /// ```ignore
855            /// struct VMGcHeader {
856            ///     // Highest 5 bits.
857            ///     kind: VMGcKind,
858            ///
859            ///     // 27 bits available for the `GcRuntime` to make use of
860            ///     // however it sees fit.
861            ///     reserved: u27,
862            ///
863            ///     // The `VMSharedTypeIndex` for this GC object, if it isn't an
864            ///     // `externref` (or an `externref` re-wrapped as an
865            ///     // `anyref`). `None` is represented with
866            ///     // `VMSharedTypeIndex::reserved_value()`.
867            ///     ty: Option<VMSharedTypeIndex>,
868            /// }
869            /// ```
870            ///
871            /// NB: the `kind` and `reserved` fields share one word, and
872            /// therefore one alias region: splitting them would let Cranelift
873            /// forward a stale kind across a reserved-bits store.
874            #[derive(Debug, Clone, Copy)]
875            #[repr(C, align(8))]
876            #[snake_name = vm_gc_header]
877            pub struct VMGcHeader {
878                /// The object's `VMGcKind` and 27 bits of space reserved for
879                /// however the GC sees fit to use it.
880                pub(crate) kind: u32,
881
882                /// The object's type index.
883                pub(crate) ty: VMSharedTypeIndex,
884            }
885
886            /// The common header for all objects in the DRC collector.
887            ///
888            /// This adds a ref count and over-approximated-stack-roots list
889            /// link on top of the collector-agnostic [`VMGcHeader`].
890            #[cfg(feature = "gc-drc")]
891            #[repr(C)]
892            #[snake_name = vm_drc_header]
893            pub(crate) struct VMDrcHeader {
894                /// The collector-agnostic header.
895                #[aggregate]
896                pub(crate) header: VMGcHeader,
897
898                /// This object's reference count.
899                pub(crate) ref_count: u64,
900
901                /// The next object in the over-approximated-stack-roots list,
902                /// if this object is in that list.
903                pub(crate) next_over_approximated_stack_root: Option<VMGcRef>,
904
905                /// The size of this object in the GC heap.
906                ///
907                /// Written by the runtime at allocation time; compiled Wasm
908                /// never accesses it.
909                pub(crate) object_size: u32,
910            }
911
912            /// The common header for all objects in the copying collector.
913            #[cfg(feature = "gc-copying")]
914            #[repr(C)]
915            #[snake_name = vm_copying_header]
916            pub(crate) struct VMCopyingHeader {
917                /// The collector-agnostic header.
918                #[aggregate]
919                pub(crate) header: VMGcHeader,
920
921                /// The size of this object in the GC heap.
922                pub(crate) object_size: u32,
923            }
924        }
925    };
926}