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                /// The caller component instance (a deferred `enter_sync_call` argument).
553                pub caller_instance: u32,
554                /// Whether the callee is async-lifted (a deferred `enter_sync_call` arg).
555                pub callee_async: u32,
556                /// The callee component instance (a deferred `enter_sync_call` argument).
557                pub callee_instance: u32,
558                /// The caller thread's `context.{get,set}` slots, saved on entry and
559                /// restored on the fast-path exit (or recovered while forcing).
560                #[indexed]
561                pub saved_context: [u32; NUM_COMPONENT_CONTEXT_SLOTS],
562            }
563
564            /// This type is used to save (and subsequently restore) a subset of
565            /// the data in `VMStoreContext`.
566            ///
567            /// See documentation of `VMStackChain` for the exact uses.
568            #[derive(Debug, Default, Clone)]
569            #[repr(C)]
570            #[snake_name = vm_stack_limits]
571            pub struct VMStackLimits {
572                /// Saved version of the `stack_limit` field of `VMStoreContext`.
573                pub stack_limit: usize,
574                /// Saved version of the `last_wasm_entry_fp` field of
575                /// `VMStoreContext`.
576                pub last_wasm_entry_fp: usize,
577                /// Saved version of the `last_wasm_entry_sp` field of
578                /// `VMStoreContext`.
579                pub last_wasm_entry_sp: usize,
580                /// Saved version of the `last_wasm_entry_trap_handler` field of
581                /// `VMStoreContext`.
582                pub last_wasm_entry_trap_handler: usize,
583            }
584
585            /// A reference to a buffer ("array") allocated on a continuation's
586            /// stack.
587            ///
588            /// The elements are of whatever type the buffer's user expects;
589            /// `data` is an untyped pointer, and the runtime casts it at each
590            /// use site.
591            #[derive(Debug, Clone)]
592            #[repr(C)]
593            #[snake_name = vm_host_array]
594            pub struct VMHostArray {
595                /// Number of currently occupied slots.
596                pub length: u32,
597
598                /// Number of slots in the data buffer. Note that this is *not*
599                /// the size of the buffer in bytes!
600                pub capacity: u32,
601
602                /// The buffer itself, which lives on the continuation's stack
603                /// rather than in this object.
604                pub data: *mut u8,
605            }
606
607            /// The information saved for every stack, whether it is a
608            /// continuation's or the initial stack's.
609            #[derive(Debug, Clone)]
610            #[repr(C)]
611            #[snake_name = vm_common_stack_information]
612            pub struct VMCommonStackInformation {
613                /// The subset of `VMStoreContext` saved for this stack.
614                #[aggregate]
615                pub limits: VMStackLimits,
616
617                /// Where this stack is in its life cycle; a `VMStackState`
618                /// discriminant.
619                pub state: VMStackState,
620
621                /// The tags this stack handles, set while it is a `Parent`.
622                #[aggregate]
623                pub handlers: VMHostArray,
624
625                /// The index within `handlers` of the first `switch` handler.
626                pub first_switch_handler_index: u32,
627            }
628
629            /// A continuation.
630            #[repr(C)]
631            #[snake_name = vm_cont_ref]
632            pub struct VMContRef {
633                /// The information saved for this continuation's stack.
634                #[aggregate]
635                pub common_stack_information: VMCommonStackInformation,
636
637                /// This continuation's parent: another continuation, the
638                /// initial stack, or absent.
639                #[aggregate]
640                pub parent_chain: VMStackChain,
641
642                /// The end of this continuation's parent chain, used only while
643                /// it is `Suspended` or `Fresh`.
644                pub last_ancestor: *mut VMContRef,
645
646                /// Revision counter.
647                pub revision: usize,
648
649                /// The stack this continuation runs on.
650                #[aggregate]
651                pub stack: VMContinuationStack,
652
653                /// The arguments to, and return values of, the function passed
654                /// to `cont.new`.
655                #[aggregate]
656                pub args: VMHostArray,
657
658                /// The payloads passed to and from this continuation once it
659                /// has been suspended.
660                #[aggregate]
661                pub values: VMHostArray,
662
663                /// Tells the compiler that this structure has potential
664                /// self-references, through `last_ancestor`.
665                ///
666                /// This is a zero-sized type in final position, so it affects
667                /// neither this type's size nor its alignment.
668                #[aggregate]
669                pub _marker: PhantomPinned,
670            }
671
672            /// The deferred-reference-counting collector's JIT-accessible heap
673            /// data.
674            ///
675            /// This is a separate allocation, reached through the
676            /// `VMContext::gc_heap_data` pointer. Its fields are not GC heap
677            /// locations, so they get this type's own alias regions rather than
678            /// the GC heap's.
679            ///
680            /// `wasmtime::runtime::vm::gc::enabled::drc` owns one of these,
681            /// wrapped in a cell because compiled Wasm writes to it, and
682            /// accesses it only through that wrapper's methods.
683            #[cfg(feature = "gc-drc")]
684            #[derive(Default)]
685            #[repr(C)]
686            #[snake_name = vm_drc_heap_data]
687            pub struct VMDrcHeapData {
688                /// The head of the over-approximated-stack-roots list.
689                pub over_approximated_stack_roots: Option<VMGcRef>,
690
691                /// The current size of the over-approximated-stack-roots list.
692                pub current_over_approximated_stack_roots_len: u32,
693
694                /// The size of the over-approximated-stack-roots list
695                /// immediately after the last GC.
696                pub over_approximated_stack_roots_len_after_last_gc: u32,
697            }
698
699            /// The copying collector's JIT-accessible bump-allocation state.
700            ///
701            /// Like [`VMDrcHeapData`], this is a separate allocation reached
702            /// through `VMContext::gc_heap_data`, and is owned, wrapped in a
703            /// cell, by `wasmtime::runtime::vm::gc::enabled::copying`.
704            #[cfg(feature = "gc-copying")]
705            #[derive(Default)]
706            #[repr(C)]
707            #[snake_name = vm_copying_heap_data]
708            pub struct VMCopyingHeapData {
709                /// Current bump pointer (an index into the GC heap).
710                pub bump_ptr: u32,
711
712                /// End of the active semi-space.
713                pub active_space_end: u32,
714            }
715
716            /// The null collector's JIT-accessible bump-allocation state.
717            ///
718            /// Unlike the two above, this is not a separate allocation: it is
719            /// the first field of `NullHeap` (in
720            /// `wasmtime::runtime::vm::gc::enabled::null`), again wrapped in a
721            /// cell, and compiled Wasm reaches it through a pointer to that
722            /// field.
723            #[cfg(feature = "gc-null")]
724            #[repr(C)]
725            #[snake_name = vm_null_heap_data]
726            pub struct VMNullHeapData {
727                /// The bump-allocation finger, an index into the GC heap.
728                pub next: NonZeroU32,
729            }
730        }
731    };
732}