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}