Skip to content

Improve alignment and memory layout of Wasmi operators #1738

@Robbepop

Description

@Robbepop

With #1650 new Wasmi operators have been introduced together with 2 different modes of bytecode layout: indirect-dispatch and !indirect-dispatch.

  • indirect-dispatch encodes all operators with a 16-bit op-code.
  • !indirect-dispatch encodes all operators with a pointer sized function pointer to the execution handler.

Thus, indirect-dispatch offsets all operands by 2 bytes whereas !indirect-dispatch offsets operands by either 4 bytes (32-bit) or 8 bytes (64-bit).

Ideally, operators are laid out differently depending on those constraints.
For example, i64.add_ssi has 3 operators:

  1. result: Slot (2 bytes)
  2. lhs: Slot (2 bytes)
  3. rhs: i64 (8 bytes)

This requires different layouts on different configs:

  1. indirect-dispatch:
struct I64Add_Ssi {
    pub result: Slot,
    pub lhs: Slot,
    #[cfg(target_pointer_width = "64")]
    _pad: Padding<4>,
    pub rhs: i64,
}

Where Padding<N> is defined as:

#[derive(Debug, Default, Copy, Clone)]
pub struct Padding<const N: usize> {
    marker: [u8; N],
}

And has a Decode and Encode impl that simply forwards the decoder or encoder cursor while decoding or encoding nothing. Its bytes are always zeroed and cannot be changed. It simply exist to create padding bytes in between operands.

  1. !indirect-dispatch

This is a bit more tricky since we either have a 4-byte offset (32-bit) or an 8-byte offset (64-bit).

struct I64Add_Ssi {
    pub result: Slot,
    pub lhs: Slot,
    #[cfg(target_pointer_width = "64")]
    _pad: Padding<4>,
    pub rhs: i64,
}

or we could also re-order fields which is what the Rust compiler would do:

#[cfg(target_pointer_width = "64")]
struct I64Add_Ssi {
    pub rhs: i64,
    pub result: Slot,
    pub lhs: Slot,
    _pad: Padding<4>, // so the next operator starts at alignment of 4
}

#[cfg(target_pointer_width = "32")]
struct I64Add_Ssi {
    pub result: Slot,
    pub lhs: Slot,
    pub rhs: i64,
}

All in all this can get complex very quickly due to the different modes of memory layout.

Metadata

Metadata

Assignees

No one assigned

    Labels

    optimizationAn performance optimization issue.researchResearch intense work item.

    Type

    No type

    Projects

    Status

    Open

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions