wasm_insn_table.h (3586B)
1 #ifndef KIT_WASM_INSN_TABLE_H 2 #define KIT_WASM_INSN_TABLE_H 3 4 /* Single source of truth for the Wasm instruction set. 5 * 6 * WasmInsnKind is the same logical instruction described five different ways: 7 * its opcode bytes (encode), its byte->kind map (decode), its WAT mnemonic 8 * (disassembler), its mnemonic->kind map (WAT parser), and the operand class 9 * that drives how immediates are read/written. Historically each of those was 10 * its own ~200-arm switch that had to stay in lockstep. WASM_INSN_TABLE below 11 * is that map, written once; encode/wat/disasm derive their behaviour from it 12 * by O(1) row lookup or a linear scan, and the mnemonic helper reads a column. 13 * 14 * Decode keeps hand-written arms for the irregular operand reads (two index 15 * immediates, block-type bytes, br_table vectors, ...), but the uniform memarg 16 * loads/stores/atomics derive their byte->kind mapping from this table via 17 * wasm_insn_by_byte rather than re-listing each opcode. The byte<->kind mapping 18 * therefore lives in exactly one place. */ 19 20 #include "wasm/wasm.h" 21 22 /* Opcode-space prefix for an instruction's encoding. */ 23 typedef enum WasmInsnPrefix { 24 WASM_PREFIX_NONE = 0, /* single-byte opcode, `byte` is the opcode */ 25 WASM_PREFIX_FC = 1, /* 0xfc-prefixed (misc: trunc_sat + bulk memory/table) */ 26 WASM_PREFIX_FE = 2, /* 0xfe-prefixed (threads/atomics) */ 27 } WasmInsnPrefix; 28 29 /* Operand-class column: how an instruction's immediates are spelled. Drives 30 * encode (write), the disassembler's render_operands (read), and the WAT 31 * parser's has_imm. Classes with a trailing comment of "has_imm" are the ones 32 * for which the WAT grammar parses a single trailing immediate token. */ 33 typedef enum WasmOperandClass { 34 WASM_OC_NONE = 0, /* no immediate */ 35 WASM_OC_SLEB, /* i32/i64.const signed leb (has_imm) */ 36 WASM_OC_FP, /* f32/f64.const float literal (has_imm) */ 37 WASM_OC_IDX, /* one uleb index immediate (has_imm) */ 38 WASM_OC_TYPED_REF, /* call_ref/return_call_ref: uleb typeidx, but WAT 39 * takes the type from context, so no trailing token */ 40 WASM_OC_REF_NULL, /* ref.null valtype (has_imm) */ 41 WASM_OC_CALL_INDIRECT, /* typeidx + tableidx */ 42 WASM_OC_BR_TABLE, /* label vector + default */ 43 WASM_OC_BLOCK_TYPE, /* block/loop/if: 0x40 blocktype byte */ 44 WASM_OC_MEMARG, /* memory access: align/offset/memidx */ 45 WASM_OC_MEM_IDX, /* memory.size/grow: single memidx */ 46 WASM_OC_BULK, /* 0xfc bulk memory/table ops, irregular index slots */ 47 WASM_OC_FENCE, /* atomic.fence: a single 0x00 byte */ 48 } WasmOperandClass; 49 50 typedef struct WasmInsnInfo { 51 uint8_t kind; /* WasmInsnKind; rows are enum-indexed */ 52 uint8_t prefix; /* WasmInsnPrefix */ 53 uint8_t byte; /* opcode byte (PREFIX_NONE) or sub-opcode otherwise */ 54 uint8_t operand_class; /* WasmOperandClass */ 55 const char* mnemonic; /* canonical WAT spelling; never NULL in-table */ 56 } WasmInsnInfo; 57 58 /* Row for `kind`, or NULL if out of range. O(1). */ 59 const WasmInsnInfo* wasm_insn_info(WasmInsnKind kind); 60 /* Row for the opcode `byte` in opcode space `prefix` (the byte->kind reverse of 61 * wasm_insn_info), or NULL if no instruction occupies that slot. Linear scan, 62 * matching wat.c's mnemonic->kind resolution. This is the decoder's single 63 * source for the byte<->kind mapping. */ 64 const WasmInsnInfo* wasm_insn_by_byte(WasmInsnPrefix prefix, uint8_t byte); 65 /* WAT operand-token presence derived from the operand class. */ 66 int wasm_operand_class_has_imm(WasmOperandClass oc); 67 68 #endif