skip to content
==> include/wasm/lower.h <==
1/* @ajax/wasm-lower: validated function bodies to the code @ajax/wasm-interp runs.
2 *
3 * A function's code is an array of fixed-size instructions. Structured control flow is gone:
4 * every branch names its target index, the operand-stack height (in 64-bit slots, from the
5 * frame's base) its label's values move to, and how many values move. Locals are slots
6 * 0..nlocals of the frame; the operand stack starts after them. Loops start with an interrupt
7 * check (as wasmtime's epoch checks sit at loop headers and function entries). Dead code after
8 * br, br_table, return and unreachable is dropped.
9 *
10 * The input must be valid (@ajax/wasm-validate) and free of SIMD and atomics. */
11#ifndef WASM_LOWER_H
12#define WASM_LOWER_H
13
14#include "wasm/module.h"
15
16#include <stdbool.h>
17#include <stddef.h>
18#include <stdint.h>
19
20/* Internal opcodes: plain wasm instructions keep their one-byte opcode; 0xfc-prefixed ones are
21 * 0x100 + sub-opcode; the rest are below. */
22enum {
23    WASM_INS_FC = 0x100,
24    WASM_INS_BR = 0x200,   /* a: target; b: height << 32 | values */
25    WASM_INS_BR_IF,        /* the same, taken when the popped i32 isn't 0 */
26    WASM_INS_BR_UNLESS,    /* a: target, taken (no stack change) when the popped i32 is 0: `if` */
27    WASM_INS_JUMP,         /* a: target, no stack change: the end of an `if`'s then-branch */
28    WASM_INS_BR_TABLE,     /* a: first entry in the function's br table; b: entries (the default last) */
29    WASM_INS_RETURN,       /* a: results */
30    WASM_INS_CALL,         /* a: function index */
31    WASM_INS_CALL_INDIRECT, /* a: canonical type index; b: table index */
32    WASM_INS_INTERRUPT,    /* loop header: trap if the deadline passed */
33    WASM_INS_COUNT
34};
35
36typedef struct {
37    uint16_t op;
38    uint16_t pad;
39    uint32_t a;
40    uint64_t b;
41} wasm_ins;
42
43typedef struct {
44    uint32_t target;
45    uint32_t height;
46    uint32_t values;
47} wasm_br_entry;
48
49typedef struct {
50    wasm_ins *code;
51    uint32_t ncode;
52    wasm_br_entry *brs;
53    uint32_t nbrs;
54    uint32_t nparams, nresults;
55    uint32_t nlocals;     /* parameters included */
56    uint32_t frame_slots; /* nlocals + the deepest operand stack */
57} wasm_fn_code;
58
59/* Lowers defined function `func` of m into *out. false (with err) only when out of memory or when
60 * the body uses SIMD or atomics, which the interpreter doesn't run. */
61bool wasm_lower(const wasm_module *m, uint32_t func, wasm_fn_code *out, char *err, size_t errlen);
62void wasm_fn_code_free(wasm_fn_code *c);
63
64/* For call_indirect: canon[t] is the first type index whose signature equals type t's. */
65uint32_t *wasm_canonical_types(const wasm_module *m);
66
67#endif