Skip to main content

for_each_vm_type

Macro for_each_vm_type 

Source
macro_rules! for_each_vm_type {
    ($mac:ident) => { ... };
}
Expand description

Invoke the given macro $mac once, passing it the definitions of each of the VM* types whose layout is shared between the runtime, compilation offsets, and Cranelift alias regions.

This is a higher-order macro: callers define a macro_rules! macro that matches the grammar defined below and pass its name as an argument to this macro’s invocation, e.g. for_each_vm_type!(define_vm_types).

§Grammar

Each type is either a struct or a #[repr(C, _)] enum, preceded by:

  • Doc-comment attributes (#[doc = "..."]).

  • An optional #[cfg(...)] attribute, gating the type on the Cargo features whose code actually uses it.

    Only the runtime’s struct definition (and its layout test) is gated by it. A type’s offsets and alias regions are always generated because the wasmtime-environ and wasmtime-internal-cranelift crates do not have Cargo features for all the various Wasm features.

  • An optional #[derive(...)] attribute.

  • A #[repr(...)] attribute.

  • A #[snake_name = <ident>] attribute giving the type’s name in snake_case, used to generate accessor method names.

Each field may be preceded by doc-comment attributes and, optionally, these marker attributes, in this order:

  • #[aggregate]: this field is a composite (a nested struct or array) rather than a single scalar. Compiled Wasm 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. The field’s offset is still generated, since that is what interior accesses are computed relative to.

  • #[indexed]: this field is a fixed-size array of a scalar type, whose elements compiled Wasm code accesses individually by a compile-time constant index. Like #[aggregate], the field has no single Cranelift type; unlike #[aggregate], its elements all do, so an alias-region accessor taking that index is generated for it and each element gets its own alias region.

  • #[readonly] and/or #[can_move]: describe how Cranelift may treat loads and stores of that field.

§Enums

A type may also be an enum, which must be #[repr(C, $tag)] for an integer $tag:

ⓘ
#[derive(Debug)]
#[repr(C, u32)]
#[snake_name = vm_example]
pub enum VMExample {
    #[snake_name = variant_a]
    VariantA {
        field: u32,
    } = 0,

    #[snake_name = variant_b]
    VariantB {
        other: u64,
    } = 1,
}

Rust lays such an enum out as a #[repr(C)] struct of a $tag tag followed by a union of the variants, which is what lets the same offset machinery describe it. The C is what guarantees that, so it is required.

Beyond a struct’s rules, each variant needs an explicit discriminant (the tag values compiled code compares against), braces even when empty, and its own #[snake_name] for its generated accessors. Variant fields take a struct field’s marker attributes but no visibility.

An enum gets two alias regions rather than a struct’s one per field: one for the tag, one shared by all variants’ fields, because they overlap.