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.
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)* }) => {};