==> src/instr.c <==1/* Decoding one instruction: opcode, sub-opcode, immediates. */
2#include "wasm/instr.h"
3
4#include <string.h>
5
6static void memarg(wasm_reader *r, wasm_instr *in) {
7 in->align = wasm_rd_u32(r);
8 in->mem = 0;
9 /* Multi-memory: bit 6 of the alignment says a memory index follows. */
10 if (in->align & 0x40) {
11 in->align &= ~0x40u;
12 in->mem = wasm_rd_u32(r);
13 }
14 in->moffset = wasm_rd_u64(r);
15}
16
17static void blocktype(wasm_reader *r, wasm_instr *in) {
18 size_t at = wasm_rd_offset(r);
19 int64_t bt = wasm_rd_s33(r);
20 in->blocktype = bt;
21 in->bt_val = 0;
22 if (bt >= 0 || bt == WASM_BT_EMPTY) return;
23 /* A negative one-byte s33 is a value type: 0x7f is -1, 0x6f is -17. */
24 if (bt < -64) {
25 wasm_rd_fail_at(r, at, "invalid block type");
26 return;
27 }
28 wasm_valtype t = (wasm_valtype)(bt + 0x80);
29 if (!wasm_is_valtype(t)) {
30 wasm_rd_fail_at(r, at, "invalid value type");
31 return;
32 }
33 in->bt_val = t;
34}
35
36static wasm_valtype reftype(wasm_reader *r) {
37 size_t at = wasm_rd_offset(r);
38 uint8_t t = wasm_rd_u8(r);
39 if (!r->failed && t != WASM_FUNCREF && t != WASM_EXTERNREF) wasm_rd_fail_at(r, at, "malformed reference type");
40 return t;
41}
42
43bool wasm_rd_instr(wasm_reader *r, wasm_instr *in) {
44 memset(in, 0, sizeof *in);
45 in->offset = wasm_rd_offset(r);
46 uint32_t op = wasm_rd_u8(r);
47 if (r->failed) return false;
48 if (op == WASM_PREFIX_FC || op == WASM_PREFIX_SIMD || op == WASM_PREFIX_ATOMIC) {
49 uint32_t sub = wasm_rd_u32(r);
50 if (r->failed) return false;
51 if (sub > 0xffff) return wasm_rd_fail_at(r, in->offset, "unknown 0x%02x subopcode: 0x%x", op, sub);
52 op = op << 16 | sub;
53 }
54 in->op = op;
55 if (!wasm_op_info(op, &in->info)) {
56 if (op > 0xff) return wasm_rd_fail_at(r, in->offset, "unknown 0x%02x subopcode: 0x%x", op >> 16, op & 0xffff);
57 return wasm_rd_fail_at(r, in->offset, "illegal opcode: 0x%x", op);
58 }
59 switch (in->info.imm) {
60 case WASM_IMM_NONE: break;
61 case WASM_IMM_BLOCK: blocktype(r, in); break;
62 case WASM_IMM_LABEL:
63 case WASM_IMM_FUNC:
64 case WASM_IMM_LOCAL:
65 case WASM_IMM_GLOBAL:
66 case WASM_IMM_TABLE:
67 case WASM_IMM_DATA:
68 case WASM_IMM_ELEM: in->a = wasm_rd_u32(r); break;
69 case WASM_IMM_MEMIDX: in->mem = wasm_rd_u32(r); break;
70 case WASM_IMM_BR_TABLE: {
71 in->ntargets = wasm_rd_count(r, 1, "br_table");
72 in->targets = r->p;
73 for (uint32_t i = 0; i < in->ntargets && !r->failed; i++) (void)wasm_rd_u32(r);
74 in->b = wasm_rd_u32(r); /* the default */
75 break;
76 }
77 case WASM_IMM_CALL_INDIRECT:
78 in->a = wasm_rd_u32(r); /* type */
79 in->b = wasm_rd_u32(r); /* table */
80 break;
81 case WASM_IMM_MEMARG: memarg(r, in); break;
82 case WASM_IMM_MEMARG_LANE:
83 memarg(r, in);
84 in->lane = wasm_rd_u8(r);
85 break;
86 case WASM_IMM_I32: in->i = wasm_rd_s32(r); break;
87 case WASM_IMM_I64: in->i = wasm_rd_s64(r); break;
88 case WASM_IMM_F32: in->f32 = wasm_rd_le32(r); break;
89 case WASM_IMM_F64: in->f64 = wasm_rd_le64(r); break;
90 case WASM_IMM_SELECT_T: {
91 size_t at = wasm_rd_offset(r);
92 in->nselect = wasm_rd_count(r, 1, "select types");
93 for (uint32_t i = 0; i < in->nselect && !r->failed; i++) {
94 size_t tat = wasm_rd_offset(r);
95 uint8_t t = wasm_rd_u8(r);
96 if (!r->failed && !wasm_is_valtype(t)) return wasm_rd_fail_at(r, tat, "invalid value type");
97 if (i == 0) in->select_type = t;
98 }
99 if (!r->failed && in->nselect != 1) return wasm_rd_fail_at(r, at, "invalid result arity");
100 break;
101 }
102 case WASM_IMM_REFTYPE: in->reftype = reftype(r); break;
103 case WASM_IMM_MEMORY_INIT:
104 in->a = wasm_rd_u32(r); /* data */
105 in->mem = wasm_rd_u32(r);
106 break;
107 case WASM_IMM_MEMORY_COPY:
108 in->mem = wasm_rd_u32(r); /* destination */
109 in->b = wasm_rd_u32(r); /* source */
110 break;
111 case WASM_IMM_TABLE_INIT:
112 in->a = wasm_rd_u32(r); /* element */
113 in->b = wasm_rd_u32(r); /* table */
114 break;
115 case WASM_IMM_TABLE_COPY:
116 in->a = wasm_rd_u32(r); /* destination */
117 in->b = wasm_rd_u32(r); /* source */
118 break;
119 case WASM_IMM_V128:
120 case WASM_IMM_SHUFFLE: in->v128 = wasm_rd_bytes(r, 16); break;
121 case WASM_IMM_LANE: in->lane = wasm_rd_u8(r); break;
122 case WASM_IMM_ZERO_BYTE: {
123 size_t at = wasm_rd_offset(r);
124 if (wasm_rd_u8(r) != 0 && !r->failed) return wasm_rd_fail_at(r, at, "nonzero byte after atomic.fence");
125 break;
126 }
127 }
128 return !r->failed;
129}
130
131void wasm_instr_targets(const wasm_instr *in, uint32_t *out) {
132 const uint8_t *p = in->targets;
133 for (uint32_t i = 0; i < in->ntargets; i++) {
134 uint32_t v = 0;
135 /* Already checked by wasm_rd_instr: these can't fail; bound by 5 bytes each. */
136 p += wasm_leb_u32(p, p + 5, &v);
137 out[i] = v;
138 }
139 out[in->ntargets] = in->b;
140}