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
1314#include "wasm/module.h"
1516#include <stdbool.h>
17#include <stddef.h>
18#include <stdint.h>
1920/* 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};
3536typedef struct {
37 uint16_t op;
38 uint16_t pad;
39 uint32_t a;
40 uint64_t b;
41} wasm_ins;
4243typedef struct {
44 uint32_t target;
45 uint32_t height;
46 uint32_t values;
47} wasm_br_entry;
4849typedef 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;
5859/* 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);
6364/* 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);
6667#endif