macro_rules! for_each_vmctx_type {
($mac:ident) => { ... };
}Expand description
Invoke the given macro $mac once, passing it the layout of each of
Wasmtime’s “vmctx” types.
This is a higher-order macro: callers define a macro_rules! macro that
matches the grammar described below and pass its name as an argument to this
macro’s invocation, e.g. for_each_vmctx_type!(define_vmctx_offsets).
§Grammar
The layout below is written in exactly the same grammar that it is handed to
$mac in: this macro has a single rule, and that rule does nothing but
forward those tokens along. Writing the layout in the grammar that consumers
match makes it more verbose than a bespoke input syntax would be, but in
exchange there is no normalization pass in between, so what a consumer matches
is exactly what a reader of the layout sees.
$mac receives one brace-delimited group per vmctx type:
{
VMContext vmctx
static { ...entries... }
dynamic { ...entries... }
}where vmctx is the name used for accessor methods of that type, static
holds the fixed-width prefix whose offsets depend only on the target pointer
size, and dynamic holds the rest, whose offsets additionally depend on the
module or component being compiled.
Each entry within a section is a keyword naming the entry’s shape followed by
a single delimited group, so that a consumer can iterate over a section with
$( ...$kind:ident $entry:tt... )* and dispatch on one whole entry at a time
instead of munching the section token by token. An entry is one of:
-
align { ptr }oralign { N }: round the running offset up to the target pointer size, or toNbytes. Alignment is always explicit: it is never derived from a field’s type, because the layout being described here does not necessarily align every field to its natural alignment, and inserting padding that the layout does not actually have would silently corrupt every subsequent offset. -
field { <attrs> <name>: <ty> }: a single field. -
array { <attrs> <name>[<count>; <IndexType>]: <ty> }(dynamiconly): an array ofself.<count>elements, indexed by<IndexType>. -
optional { <attrs> <name>[if <flag>]: <ty> }(dynamiconly): a field that is present whenself.<flag>is true and absent (zero-sized) otherwise.
A field’s type is always the last thing in its entry. Consumers capture it
as a trailing $($fty:tt)* and re-dispatch on its tokens only where they
actually need to classify it into a size or a Cranelift type; a :ty
capture would be opaque forever, and so could never be classified at
all.
<attrs> is a possibly-empty sequence of marker attributes, which consumers
match with $(# $fattr:tt)*. They do not affect the layout, but they do affect
the accesses generated for the field:
-
#[aggregate]: this field is a composite (a nested struct, or an array of them) rather than a single scalar. Compiled code accesses such a field’s interior piecewise, so there is no one Cranelift type for the field as a whole and no alias-region accessor is generated for it. Its offset is still generated, since that is what interior accesses are computed relative to. -
#[readonly]and/or#[can_move]: describe how Cranelift may treat loads and stores of this field. -
#[access_as = Type]: this field is declared with one type (because that is what determines its size and stride) but accessed as another. For example, the component context’smay_leaveflags are each stored in a wholeVMGlobalDefinitionbut only ever accessed as au32. -
#[ptr_size_offset](dynamiconly): this field’s offset is a function of the target pointer size alone, even though it lives in thedynamicsection, because it and everything before it have sizes that do not depend on the vmctx’s shape. These fields get generated accessors that do not need to be parameterized overVMOffsets, onlyGetPtrSize. -
#[pointee(<attrs> <Region> as <name> $([<IndexType>])? : <ty>)]: this field is a pointer to memory that lives outside the vmctx and so is not part of its layout at all, but that compiled code reaches only by loading this field first.<Region>names the alias region that memory belongs to,<name>is the accessor generated for it, and<ty>is the type it is accessed as. With an[<IndexType>], the pointee is an array of<ty>indexed by<IndexType>and each element gets its own alias region; without one, it is a single<ty>. The pointee’s<attrs>are its own: how compiled code may treat a load of the pointee is independent of how it may treat a load of the pointer.
Doc comments are deliberately not accepted on fields; use // comments for
prose about the layout. Accessor documentation is synthesized from the field
names instead, so that there is only one place a field can be described.
A consumer that only cares about one of the two types can filter with a literal-name arm followed by a catch-all, e.g.
(@one VMContext $snake:ident dynamic { $($dyn:tt)* }) => { ...generate... };
(@one $other:ident $snake:ident dynamic { $($dyn:tt)* }) => {};