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