1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
//! This module contains a data structure to allow in-place interpretation
//!
//! Control-flow in WASM is denoted in labels. To avoid linear search through the WASM binary or
//! stack for the respective label of a branch, a sidetable is generated during validation, which
//! stores the offset on the current instruction pointer for the branch. A sidetable entry hence
//! allows to translate the implicit control flow information ("jump to the next `else`") to
//! explicit modifications of the instruction pointer (`instruction_pointer += 13`).
//!
//! Branches in WASM can only go outwards, they either `break` out of a block or `continue` to the
//! head of a loob block. Put differently, a label can only be referenced from within its
//! associated structured control instruction.
//!
//! Noteworthy, branching can also have side-effects on the operand stack:
//!
//! - Taking a branch unwinds the operand stack, down to where the targeted structured control flow
//! instruction was entered. [`SidetableEntry::popcnt`] holds information on how many values to
//! pop from the operand stack when a branch is taken.
//! - When a branch is taken, it may consume arguments from the operand stack. These are pushed
//! back on the operand stack after unwinding. This behavior can be emulated by copying the
//! uppermost [`SidetableEntry::valcnt`] operands on the operand stack before taking a branch
//! into a structured control instruction.
//!
//! # Reference
//!
//! - Core / Syntax / Instructions / Control Instructions, WASM Spec,
//! <https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions>
//! - "A fast in-place interpreter for WebAssembly", Ben L. Titzer,
//! <https://arxiv.org/abs/2205.01183>
use alloc::vec::Vec;
// A sidetable
pub type Sidetable = Vec<SidetableEntry>;
/// Entry to translate the current branches implicit target into an explicit offset to the instruction pointer, as well as the side table pointer
///
/// Each of the following constructs requires a [`SidetableEntry`]:
///
/// - br
/// - br_if
/// - br_table
/// - else
// TODO hide implementation
// TODO Remove Clone trait from sidetables
#[derive(Debug, Clone)]
pub struct SidetableEntry {
/// Δpc: the amount to adjust the instruction pointer by if the branch is taken
pub delta_pc: isize,
/// Δstp: the amount to adjust the side-table index by if the branch is taken
pub delta_stp: isize,
/// valcnt: the number of values that will be copied if the branch is taken
///
/// Branches may additionally consume operands themselves, which they push back on the operand
/// stack after unwinding.
pub valcnt: usize,
/// popcnt: the number of values that will be popped if the branch is taken
///
/// Taking a branch unwinds the operand stack down to the height where the targeted structured
/// control instruction was entered.
pub popcnt: usize,
}