kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

decode.c (41477B)


      1 #include "wasm/wasm.h"
      2 #include "wasm/wasm_insn_table.h"
      3 
      4 typedef struct BinReader {
      5   KitCompiler* c;
      6   const uint8_t* data;
      7   size_t len;
      8   size_t pos;
      9   WasmModule* module;
     10 } BinReader;
     11 
     12 static uint8_t bin_u8(BinReader* r) {
     13   if (r->pos >= r->len)
     14     wasm_error(r->c, wasm_loc(0, 0), "wasm: unexpected end of file");
     15   return r->data[r->pos++];
     16 }
     17 
     18 static uint32_t bin_uleb(BinReader* r) {
     19   uint32_t result = 0, shift = 0;
     20   uint32_t nbytes = 0;
     21   for (;;) {
     22     uint8_t b = bin_u8(r);
     23     if (nbytes++ >= 5u || (shift == 28u && (b & 0xf0u)))
     24       wasm_error(r->c, wasm_loc(0, 0), "wasm: invalid uleb128");
     25     result |= (uint32_t)(b & 0x7fu) << shift;
     26     if (!(b & 0x80u)) return result;
     27     shift += 7u;
     28   }
     29 }
     30 
     31 static uint64_t bin_uleb64(BinReader* r) {
     32   uint64_t result = 0;
     33   uint32_t shift = 0;
     34   uint32_t nbytes = 0;
     35   for (;;) {
     36     uint8_t b = bin_u8(r);
     37     if (nbytes++ >= 10u || (shift == 63u && (b & 0xfeu)))
     38       wasm_error(r->c, wasm_loc(0, 0), "wasm: invalid uleb128");
     39     result |= (uint64_t)(b & 0x7fu) << shift;
     40     if (!(b & 0x80u)) return result;
     41     shift += 7u;
     42   }
     43 }
     44 
     45 static int64_t bin_sleb(BinReader* r, uint32_t bits) {
     46   /* Accumulate in the unsigned domain: a 7-bit group can land in bit 63
     47      (shift == 63 for a 10-byte i64), where a signed left shift is UB. */
     48   uint64_t result = 0;
     49   uint32_t shift = 0;
     50   uint32_t max_bytes = (bits + 6u) / 7u;
     51   uint32_t nbytes = 0;
     52   uint8_t b;
     53   do {
     54     if (nbytes++ >= max_bytes)
     55       wasm_error(r->c, wasm_loc(0, 0), "wasm: invalid sleb128");
     56     b = bin_u8(r);
     57     result |= (uint64_t)(b & 0x7fu) << shift;
     58     shift += 7u;
     59   } while (b & 0x80u);
     60   if (shift < bits && (b & 0x40u)) result |= ~(uint64_t)0 << shift;
     61   return (int64_t)result;
     62 }
     63 
     64 static double bin_f32(BinReader* r) {
     65   uint32_t bits = 0;
     66   float f;
     67   for (uint32_t i = 0; i < 4u; ++i) bits |= (uint32_t)bin_u8(r) << (i * 8u);
     68   memcpy(&f, &bits, sizeof f);
     69   return (double)f;
     70 }
     71 
     72 static double bin_f64(BinReader* r) {
     73   uint64_t bits = 0;
     74   double d;
     75   for (uint32_t i = 0; i < 8u; ++i) bits |= (uint64_t)bin_u8(r) << (i * 8u);
     76   memcpy(&d, &bits, sizeof d);
     77   return d;
     78 }
     79 
     80 static void bin_memarg(BinReader* r, uint32_t* align, uint64_t* offset,
     81                        uint32_t* memidx) {
     82   uint32_t a = bin_uleb(r);
     83   *memidx = 0;
     84   if (a >= 64u && a < 128u) {
     85     *align = a - 64u;
     86     *memidx = bin_uleb(r);
     87   } else if (a < 64u) {
     88     *align = a;
     89   } else {
     90     wasm_error(r->c, wasm_loc(0, 0), "wasm: bad memory alignment");
     91   }
     92   *offset = bin_uleb64(r);
     93 }
     94 
     95 static void bin_need(BinReader* r, size_t n) {
     96   if (n > r->len || r->pos > r->len - n)
     97     wasm_error(r->c, wasm_loc(0, 0), "wasm: section length out of bounds");
     98 }
     99 
    100 static char* bin_name(BinReader* r, uint32_t* len_out) {
    101   uint32_t n = bin_uleb(r);
    102   char* name;
    103   bin_need(r, n);
    104   name = wasm_strdup(r->module->heap, (const char*)(r->data + r->pos), n);
    105   if (!name) wasm_error(r->c, wasm_loc(0, 0), "wasm: out of memory");
    106   r->pos += n;
    107   if (len_out) *len_out = n;
    108   return name;
    109 }
    110 
    111 static WasmValType bin_val_type(BinReader* r, int refs_ok) {
    112   uint8_t b = bin_u8(r);
    113   switch (b) {
    114     case WASM_VAL_I32:
    115     case WASM_VAL_I64:
    116     case WASM_VAL_F32:
    117     case WASM_VAL_F64:
    118       return (WasmValType)b;
    119     case WASM_VAL_FUNCREF:
    120     case WASM_VAL_EXTERNREF:
    121       if (refs_ok) return (WasmValType)b;
    122       break;
    123     default:
    124       break;
    125   }
    126   wasm_error(r->c, wasm_loc(0, 0), "wasm: unsupported value type 0x%02x", b);
    127   return WASM_VAL_I32;
    128 }
    129 
    130 /* Decode a structured-control blocktype immediate into `in` (already appended).
    131  * The blocktype is an s33: a negative value is the shorthand form (0x40 -> void,
    132  * a value-type byte for a single result), a non-negative value is a function-
    133  * type index (the multi-value form: block params and/or multiple results).
    134  * The shorthand result type lands in in->type (0 == void); the typeidx form is
    135  * recorded via wasm_insn_set_blocktype_typeidx (sentinel in type, index in
    136  * imm). */
    137 static void bin_blocktype(BinReader* r, WasmModule* out, WasmInsn* in) {
    138   int64_t s = bin_sleb(r, 33);
    139   if (s < 0) {
    140     uint8_t b = (uint8_t)(s & 0x7fu);
    141     if (b == 0x40u) {
    142       in->type = 0;
    143       return;
    144     }
    145     if (wasm_is_frontend_value_type((WasmValType)b)) {
    146       in->type = b;
    147       return;
    148     }
    149     wasm_error(r->c, wasm_loc(0, 0),
    150                "wasm: unsupported block result type 0x%02x", b);
    151     in->type = 0;
    152     return;
    153   }
    154   if ((uint64_t)s >= out->ntypes)
    155     wasm_error(r->c, wasm_loc(0, 0), "wasm: block type index out of range");
    156   wasm_insn_set_blocktype_typeidx(in, (uint32_t)s);
    157 }
    158 
    159 /* Decode a memarg operand (align/offset/memidx) and append a single memory
    160  * instruction of `kind`. Every WASM_OC_MEMARG opcode decodes identically; only
    161  * the kind differs, so the base loads/stores (0x28..0x3e) and the 0xfe atomics
    162  * share this body, reading their kind from WASM_INSN_TABLE rather than each
    163  * spelling out its own arm. */
    164 static void decode_memarg_insn(BinReader* r, KitCompiler* c, WasmModule* out,
    165                                WasmFunc* f, WasmInsnKind kind) {
    166   uint32_t ma, mi;
    167   uint64_t mo;
    168   bin_memarg(r, &ma, &mo, &mi);
    169   wasm_func_add_mem_insn(c, out, f, kind, ma, mo, mi);
    170 }
    171 
    172 /* Decode one instruction opcode body (everything except the body-terminating
    173  * 0x0b end) into f's instruction list, advancing *rp. Shared verbatim with the
    174  * function-body decode loop so the opcode mapping has a single source of truth;
    175  * reused by wasm_decode_one_insn for the disassembler. */
    176 static void decode_body_insn(BinReader* rp, WasmModule* out, WasmFunc* f,
    177                              uint8_t op, uint32_t* pcontrol_depth) {
    178   BinReader r = *rp;
    179   KitCompiler* c = r.c;
    180   uint32_t control_depth = *pcontrol_depth;
    181   switch (op) {
    182     case 0x00:
    183       wasm_func_add_insn(c, out, f, WASM_INSN_UNREACHABLE, 0);
    184       break;
    185     case 0x01:
    186       wasm_func_add_insn(c, out, f, WASM_INSN_NOP, 0);
    187       break;
    188     case 0x02:
    189       control_depth++;
    190       wasm_func_add_insn(c, out, f, WASM_INSN_BLOCK, 0);
    191       bin_blocktype(&r, out, &f->insns[f->ninsns - 1u]);
    192       break;
    193     case 0x03:
    194       control_depth++;
    195       wasm_func_add_insn(c, out, f, WASM_INSN_LOOP, 0);
    196       bin_blocktype(&r, out, &f->insns[f->ninsns - 1u]);
    197       break;
    198     case 0x04:
    199       control_depth++;
    200       wasm_func_add_insn(c, out, f, WASM_INSN_IF, 0);
    201       bin_blocktype(&r, out, &f->insns[f->ninsns - 1u]);
    202       break;
    203     case 0x05:
    204       wasm_func_add_insn(c, out, f, WASM_INSN_ELSE, 0);
    205       break;
    206     case 0x0c:
    207       wasm_func_add_insn(c, out, f, WASM_INSN_BR, bin_uleb(&r));
    208       break;
    209     case 0x0d:
    210       wasm_func_add_insn(c, out, f, WASM_INSN_BR_IF, bin_uleb(&r));
    211       break;
    212     case 0x0e: {
    213       WasmInsn* in;
    214       uint32_t n = bin_uleb(&r);
    215       /* Each target is at least one byte, so a count exceeding the
    216        * remaining input is malformed — reject before allocating. */
    217       if ((uint64_t)n >= r.len - r.pos)
    218         wasm_error(c, wasm_loc(0, 0),
    219                    "wasm: br_table target count exceeds input");
    220       wasm_func_add_insn(c, out, f, WASM_INSN_BR_TABLE, 0);
    221       in = &f->insns[f->ninsns - 1u];
    222       wasm_insn_set_targets(c, out, in, NULL, n + 1u);
    223       for (uint32_t k = 0; k < n; ++k) in->targets[k] = bin_uleb(&r);
    224       in->targets[n] = bin_uleb(&r);
    225       break;
    226     }
    227     case 0x0f:
    228       wasm_func_add_insn(c, out, f, WASM_INSN_RETURN, 0);
    229       break;
    230     case 0x1a:
    231       wasm_func_add_insn(c, out, f, WASM_INSN_DROP, 0);
    232       break;
    233     case 0x1b:
    234       wasm_func_add_insn(c, out, f, WASM_INSN_SELECT, 0);
    235       break;
    236     case 0x3f:
    237       wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_SIZE, 0);
    238       f->insns[f->ninsns - 1u].memidx = bin_uleb(&r);
    239       break;
    240     case 0x40:
    241       wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_GROW, 0);
    242       f->insns[f->ninsns - 1u].memidx = bin_uleb(&r);
    243       break;
    244     case 0x10:
    245       wasm_func_add_insn(c, out, f, WASM_INSN_CALL, bin_uleb(&r));
    246       break;
    247     case 0x11: {
    248       WasmInsn* in;
    249       wasm_func_add_insn(c, out, f, WASM_INSN_CALL_INDIRECT, bin_uleb(&r));
    250       in = &f->insns[f->ninsns - 1u];
    251       in->align = bin_uleb(&r);
    252       break;
    253     }
    254     case 0x12:
    255       wasm_func_add_insn(c, out, f, WASM_INSN_RETURN_CALL, bin_uleb(&r));
    256       break;
    257     case 0x13: {
    258       WasmInsn* in;
    259       wasm_func_add_insn(c, out, f, WASM_INSN_RETURN_CALL_INDIRECT,
    260                          bin_uleb(&r));
    261       in = &f->insns[f->ninsns - 1u];
    262       in->align = bin_uleb(&r);
    263       break;
    264     }
    265     case 0x14:
    266       wasm_func_add_insn(c, out, f, WASM_INSN_CALL_REF, bin_uleb(&r));
    267       break;
    268     case 0x15:
    269       wasm_func_add_insn(c, out, f, WASM_INSN_RETURN_CALL_REF, bin_uleb(&r));
    270       break;
    271     case 0x20:
    272       wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_GET, bin_uleb(&r));
    273       break;
    274     case 0x21:
    275       wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_SET, bin_uleb(&r));
    276       break;
    277     case 0x22:
    278       wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_TEE, bin_uleb(&r));
    279       break;
    280     case 0x23:
    281       wasm_func_add_insn(c, out, f, WASM_INSN_GLOBAL_GET, bin_uleb(&r));
    282       break;
    283     case 0x24:
    284       wasm_func_add_insn(c, out, f, WASM_INSN_GLOBAL_SET, bin_uleb(&r));
    285       break;
    286     case 0x41:
    287       wasm_func_add_insn(c, out, f, WASM_INSN_I32_CONST, bin_sleb(&r, 32));
    288       break;
    289     case 0x42:
    290       wasm_func_add_insn(c, out, f, WASM_INSN_I64_CONST, bin_sleb(&r, 64));
    291       break;
    292     case 0x43:
    293       wasm_func_add_fp_insn(c, out, f, WASM_INSN_F32_CONST, bin_f32(&r));
    294       break;
    295     case 0x44:
    296       wasm_func_add_fp_insn(c, out, f, WASM_INSN_F64_CONST, bin_f64(&r));
    297       break;
    298     case 0xd0:
    299       wasm_func_add_insn(c, out, f, WASM_INSN_REF_NULL, bin_val_type(&r, 1));
    300       break;
    301     case 0xd1:
    302       wasm_func_add_insn(c, out, f, WASM_INSN_REF_IS_NULL, 0);
    303       break;
    304     case 0xd2:
    305       wasm_func_add_insn(c, out, f, WASM_INSN_REF_FUNC, bin_uleb(&r));
    306       break;
    307     case 0x45:
    308       wasm_func_add_insn(c, out, f, WASM_INSN_I32_EQZ, 0);
    309       break;
    310     case 0x46:
    311       wasm_func_add_insn(c, out, f, WASM_INSN_I32_EQ, 0);
    312       break;
    313     case 0x47:
    314       wasm_func_add_insn(c, out, f, WASM_INSN_I32_NE, 0);
    315       break;
    316     case 0x48:
    317       wasm_func_add_insn(c, out, f, WASM_INSN_I32_LT_S, 0);
    318       break;
    319     case 0x49:
    320       wasm_func_add_insn(c, out, f, WASM_INSN_I32_LT_U, 0);
    321       break;
    322     case 0x4a:
    323       wasm_func_add_insn(c, out, f, WASM_INSN_I32_GT_S, 0);
    324       break;
    325     case 0x4b:
    326       wasm_func_add_insn(c, out, f, WASM_INSN_I32_GT_U, 0);
    327       break;
    328     case 0x4c:
    329       wasm_func_add_insn(c, out, f, WASM_INSN_I32_LE_S, 0);
    330       break;
    331     case 0x4d:
    332       wasm_func_add_insn(c, out, f, WASM_INSN_I32_LE_U, 0);
    333       break;
    334     case 0x4e:
    335       wasm_func_add_insn(c, out, f, WASM_INSN_I32_GE_S, 0);
    336       break;
    337     case 0x4f:
    338       wasm_func_add_insn(c, out, f, WASM_INSN_I32_GE_U, 0);
    339       break;
    340     case 0x50:
    341       wasm_func_add_insn(c, out, f, WASM_INSN_I64_EQZ, 0);
    342       break;
    343     case 0x51:
    344       wasm_func_add_insn(c, out, f, WASM_INSN_I64_EQ, 0);
    345       break;
    346     case 0x52:
    347       wasm_func_add_insn(c, out, f, WASM_INSN_I64_NE, 0);
    348       break;
    349     case 0x53:
    350       wasm_func_add_insn(c, out, f, WASM_INSN_I64_LT_S, 0);
    351       break;
    352     case 0x54:
    353       wasm_func_add_insn(c, out, f, WASM_INSN_I64_LT_U, 0);
    354       break;
    355     case 0x55:
    356       wasm_func_add_insn(c, out, f, WASM_INSN_I64_GT_S, 0);
    357       break;
    358     case 0x56:
    359       wasm_func_add_insn(c, out, f, WASM_INSN_I64_GT_U, 0);
    360       break;
    361     case 0x57:
    362       wasm_func_add_insn(c, out, f, WASM_INSN_I64_LE_S, 0);
    363       break;
    364     case 0x58:
    365       wasm_func_add_insn(c, out, f, WASM_INSN_I64_LE_U, 0);
    366       break;
    367     case 0x59:
    368       wasm_func_add_insn(c, out, f, WASM_INSN_I64_GE_S, 0);
    369       break;
    370     case 0x5a:
    371       wasm_func_add_insn(c, out, f, WASM_INSN_I64_GE_U, 0);
    372       break;
    373     case 0x6a:
    374       wasm_func_add_insn(c, out, f, WASM_INSN_I32_ADD, 0);
    375       break;
    376     case 0x6b:
    377       wasm_func_add_insn(c, out, f, WASM_INSN_I32_SUB, 0);
    378       break;
    379     case 0x6c:
    380       wasm_func_add_insn(c, out, f, WASM_INSN_I32_MUL, 0);
    381       break;
    382     case 0x6d:
    383       wasm_func_add_insn(c, out, f, WASM_INSN_I32_DIV_S, 0);
    384       break;
    385     case 0x6e:
    386       wasm_func_add_insn(c, out, f, WASM_INSN_I32_DIV_U, 0);
    387       break;
    388     case 0x6f:
    389       wasm_func_add_insn(c, out, f, WASM_INSN_I32_REM_S, 0);
    390       break;
    391     case 0x70:
    392       wasm_func_add_insn(c, out, f, WASM_INSN_I32_REM_U, 0);
    393       break;
    394     case 0x71:
    395       wasm_func_add_insn(c, out, f, WASM_INSN_I32_AND, 0);
    396       break;
    397     case 0x72:
    398       wasm_func_add_insn(c, out, f, WASM_INSN_I32_OR, 0);
    399       break;
    400     case 0x73:
    401       wasm_func_add_insn(c, out, f, WASM_INSN_I32_XOR, 0);
    402       break;
    403     case 0x74:
    404       wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHL, 0);
    405       break;
    406     case 0x75:
    407       wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHR_S, 0);
    408       break;
    409     case 0x76:
    410       wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHR_U, 0);
    411       break;
    412     case 0x67:
    413       wasm_func_add_insn(c, out, f, WASM_INSN_I32_CLZ, 0);
    414       break;
    415     case 0x68:
    416       wasm_func_add_insn(c, out, f, WASM_INSN_I32_CTZ, 0);
    417       break;
    418     case 0x69:
    419       wasm_func_add_insn(c, out, f, WASM_INSN_I32_POPCNT, 0);
    420       break;
    421     case 0x77:
    422       wasm_func_add_insn(c, out, f, WASM_INSN_I32_ROTL, 0);
    423       break;
    424     case 0x78:
    425       wasm_func_add_insn(c, out, f, WASM_INSN_I32_ROTR, 0);
    426       break;
    427     case 0x79:
    428       wasm_func_add_insn(c, out, f, WASM_INSN_I64_CLZ, 0);
    429       break;
    430     case 0x7a:
    431       wasm_func_add_insn(c, out, f, WASM_INSN_I64_CTZ, 0);
    432       break;
    433     case 0x7b:
    434       wasm_func_add_insn(c, out, f, WASM_INSN_I64_POPCNT, 0);
    435       break;
    436     case 0x7c:
    437       wasm_func_add_insn(c, out, f, WASM_INSN_I64_ADD, 0);
    438       break;
    439     case 0x7d:
    440       wasm_func_add_insn(c, out, f, WASM_INSN_I64_SUB, 0);
    441       break;
    442     case 0x7e:
    443       wasm_func_add_insn(c, out, f, WASM_INSN_I64_MUL, 0);
    444       break;
    445     case 0x7f:
    446       wasm_func_add_insn(c, out, f, WASM_INSN_I64_DIV_S, 0);
    447       break;
    448     case 0x80:
    449       wasm_func_add_insn(c, out, f, WASM_INSN_I64_DIV_U, 0);
    450       break;
    451     case 0x81:
    452       wasm_func_add_insn(c, out, f, WASM_INSN_I64_REM_S, 0);
    453       break;
    454     case 0x82:
    455       wasm_func_add_insn(c, out, f, WASM_INSN_I64_REM_U, 0);
    456       break;
    457     case 0x83:
    458       wasm_func_add_insn(c, out, f, WASM_INSN_I64_AND, 0);
    459       break;
    460     case 0x84:
    461       wasm_func_add_insn(c, out, f, WASM_INSN_I64_OR, 0);
    462       break;
    463     case 0x85:
    464       wasm_func_add_insn(c, out, f, WASM_INSN_I64_XOR, 0);
    465       break;
    466     case 0x86:
    467       wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHL, 0);
    468       break;
    469     case 0x87:
    470       wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHR_S, 0);
    471       break;
    472     case 0x88:
    473       wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHR_U, 0);
    474       break;
    475     case 0x89:
    476       wasm_func_add_insn(c, out, f, WASM_INSN_I64_ROTL, 0);
    477       break;
    478     case 0x8a:
    479       wasm_func_add_insn(c, out, f, WASM_INSN_I64_ROTR, 0);
    480       break;
    481     case 0x92:
    482       wasm_func_add_insn(c, out, f, WASM_INSN_F32_ADD, 0);
    483       break;
    484     case 0x93:
    485       wasm_func_add_insn(c, out, f, WASM_INSN_F32_SUB, 0);
    486       break;
    487     case 0x94:
    488       wasm_func_add_insn(c, out, f, WASM_INSN_F32_MUL, 0);
    489       break;
    490     case 0x95:
    491       wasm_func_add_insn(c, out, f, WASM_INSN_F32_DIV, 0);
    492       break;
    493     case 0xa0:
    494       wasm_func_add_insn(c, out, f, WASM_INSN_F64_ADD, 0);
    495       break;
    496     case 0xa1:
    497       wasm_func_add_insn(c, out, f, WASM_INSN_F64_SUB, 0);
    498       break;
    499     case 0xa2:
    500       wasm_func_add_insn(c, out, f, WASM_INSN_F64_MUL, 0);
    501       break;
    502     case 0xa3:
    503       wasm_func_add_insn(c, out, f, WASM_INSN_F64_DIV, 0);
    504       break;
    505     case 0x5b:
    506       wasm_func_add_insn(c, out, f, WASM_INSN_F32_EQ, 0);
    507       break;
    508     case 0x5c:
    509       wasm_func_add_insn(c, out, f, WASM_INSN_F32_NE, 0);
    510       break;
    511     case 0x5d:
    512       wasm_func_add_insn(c, out, f, WASM_INSN_F32_LT, 0);
    513       break;
    514     case 0x5e:
    515       wasm_func_add_insn(c, out, f, WASM_INSN_F32_GT, 0);
    516       break;
    517     case 0x5f:
    518       wasm_func_add_insn(c, out, f, WASM_INSN_F32_LE, 0);
    519       break;
    520     case 0x60:
    521       wasm_func_add_insn(c, out, f, WASM_INSN_F32_GE, 0);
    522       break;
    523     case 0x61:
    524       wasm_func_add_insn(c, out, f, WASM_INSN_F64_EQ, 0);
    525       break;
    526     case 0x62:
    527       wasm_func_add_insn(c, out, f, WASM_INSN_F64_NE, 0);
    528       break;
    529     case 0x63:
    530       wasm_func_add_insn(c, out, f, WASM_INSN_F64_LT, 0);
    531       break;
    532     case 0x64:
    533       wasm_func_add_insn(c, out, f, WASM_INSN_F64_GT, 0);
    534       break;
    535     case 0x65:
    536       wasm_func_add_insn(c, out, f, WASM_INSN_F64_LE, 0);
    537       break;
    538     case 0x66:
    539       wasm_func_add_insn(c, out, f, WASM_INSN_F64_GE, 0);
    540       break;
    541     case 0x8c:
    542       wasm_func_add_insn(c, out, f, WASM_INSN_F32_NEG, 0);
    543       break;
    544     case 0x9a:
    545       wasm_func_add_insn(c, out, f, WASM_INSN_F64_NEG, 0);
    546       break;
    547     case 0xa7:
    548       wasm_func_add_insn(c, out, f, WASM_INSN_I32_WRAP_I64, 0);
    549       break;
    550     case 0xa8:
    551       wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F32_S, 0);
    552       break;
    553     case 0xa9:
    554       wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F32_U, 0);
    555       break;
    556     case 0xaa:
    557       wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F64_S, 0);
    558       break;
    559     case 0xab:
    560       wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F64_U, 0);
    561       break;
    562     case 0xac:
    563       wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND_I32_S, 0);
    564       break;
    565     case 0xad:
    566       wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND_I32_U, 0);
    567       break;
    568     case 0xae:
    569       wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F32_S, 0);
    570       break;
    571     case 0xaf:
    572       wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F32_U, 0);
    573       break;
    574     case 0xb0:
    575       wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F64_S, 0);
    576       break;
    577     case 0xb1:
    578       wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F64_U, 0);
    579       break;
    580     case 0xb2:
    581       wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I32_S, 0);
    582       break;
    583     case 0xb3:
    584       wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I32_U, 0);
    585       break;
    586     case 0xb4:
    587       wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I64_S, 0);
    588       break;
    589     case 0xb5:
    590       wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I64_U, 0);
    591       break;
    592     case 0xb6:
    593       wasm_func_add_insn(c, out, f, WASM_INSN_F32_DEMOTE_F64, 0);
    594       break;
    595     case 0xb7:
    596       wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I32_S, 0);
    597       break;
    598     case 0xb8:
    599       wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I32_U, 0);
    600       break;
    601     case 0xb9:
    602       wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I64_S, 0);
    603       break;
    604     case 0xba:
    605       wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I64_U, 0);
    606       break;
    607     case 0xbb:
    608       wasm_func_add_insn(c, out, f, WASM_INSN_F64_PROMOTE_F32, 0);
    609       break;
    610     case 0xbc:
    611       wasm_func_add_insn(c, out, f, WASM_INSN_I32_REINTERPRET_F32, 0);
    612       break;
    613     case 0xbd:
    614       wasm_func_add_insn(c, out, f, WASM_INSN_I64_REINTERPRET_F64, 0);
    615       break;
    616     case 0xbe:
    617       wasm_func_add_insn(c, out, f, WASM_INSN_F32_REINTERPRET_I32, 0);
    618       break;
    619     case 0xbf:
    620       wasm_func_add_insn(c, out, f, WASM_INSN_F64_REINTERPRET_I64, 0);
    621       break;
    622     case 0xc0:
    623       wasm_func_add_insn(c, out, f, WASM_INSN_I32_EXTEND8_S, 0);
    624       break;
    625     case 0xc1:
    626       wasm_func_add_insn(c, out, f, WASM_INSN_I32_EXTEND16_S, 0);
    627       break;
    628     case 0xc2:
    629       wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND8_S, 0);
    630       break;
    631     case 0xc3:
    632       wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND16_S, 0);
    633       break;
    634     case 0xc4:
    635       wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND32_S, 0);
    636       break;
    637     case 0xfc: {
    638       uint32_t sub = bin_uleb(&r);
    639       switch (sub) {
    640         case 0x00:
    641           wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_SAT_F32_S, 0);
    642           break;
    643         case 0x01:
    644           wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_SAT_F32_U, 0);
    645           break;
    646         case 0x02:
    647           wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_SAT_F64_S, 0);
    648           break;
    649         case 0x03:
    650           wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_SAT_F64_U, 0);
    651           break;
    652         case 0x04:
    653           wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_SAT_F32_S, 0);
    654           break;
    655         case 0x05:
    656           wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_SAT_F32_U, 0);
    657           break;
    658         case 0x06:
    659           wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_SAT_F64_S, 0);
    660           break;
    661         case 0x07:
    662           wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_SAT_F64_U, 0);
    663           break;
    664         case 0x08: { /* memory.init dataidx memidx */
    665           uint32_t dataidx = bin_uleb(&r);
    666           uint32_t mi = bin_uleb(&r);
    667           wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_INIT,
    668                              (int64_t)dataidx);
    669           f->insns[f->ninsns - 1u].memidx = mi;
    670           break;
    671         }
    672         case 0x09: { /* data.drop dataidx */
    673           uint32_t dataidx = bin_uleb(&r);
    674           wasm_func_add_insn(c, out, f, WASM_INSN_DATA_DROP, (int64_t)dataidx);
    675           break;
    676         }
    677         case 0x0a: { /* memory.copy dst_memidx src_memidx */
    678           uint32_t dst = bin_uleb(&r);
    679           uint32_t src = bin_uleb(&r);
    680           wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_COPY, 0);
    681           f->insns[f->ninsns - 1u].memidx = dst;
    682           f->insns[f->ninsns - 1u].aux_idx = src;
    683           break;
    684         }
    685         case 0x0b: { /* memory.fill memidx */
    686           uint32_t mi = bin_uleb(&r);
    687           wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_FILL, 0);
    688           f->insns[f->ninsns - 1u].memidx = mi;
    689           break;
    690         }
    691         case 0x0c: { /* table.init elemidx tableidx */
    692           uint32_t elemidx = bin_uleb(&r);
    693           uint32_t ti = bin_uleb(&r);
    694           wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_INIT, (int64_t)elemidx);
    695           f->insns[f->ninsns - 1u].aux_idx = ti;
    696           break;
    697         }
    698         case 0x0d: { /* elem.drop elemidx */
    699           uint32_t elemidx = bin_uleb(&r);
    700           wasm_func_add_insn(c, out, f, WASM_INSN_ELEM_DROP, (int64_t)elemidx);
    701           break;
    702         }
    703         case 0x0e: { /* table.copy dst_tableidx src_tableidx */
    704           uint32_t dst = bin_uleb(&r);
    705           uint32_t src = bin_uleb(&r);
    706           wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_COPY, (int64_t)dst);
    707           f->insns[f->ninsns - 1u].aux_idx = src;
    708           break;
    709         }
    710         case 0x0f: { /* table.grow tableidx */
    711           uint32_t ti = bin_uleb(&r);
    712           wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_GROW, (int64_t)ti);
    713           break;
    714         }
    715         case 0x10: { /* table.size tableidx */
    716           uint32_t ti = bin_uleb(&r);
    717           wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_SIZE, (int64_t)ti);
    718           break;
    719         }
    720         case 0x11: { /* table.fill tableidx */
    721           uint32_t ti = bin_uleb(&r);
    722           wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_FILL, (int64_t)ti);
    723           break;
    724         }
    725         default:
    726           wasm_error(c, wasm_loc(0, 0), "wasm: unsupported 0xfc opcode 0x%x",
    727                      sub);
    728       }
    729       break;
    730     }
    731     case 0xfe: {
    732       uint32_t sub = bin_uleb(&r);
    733       /* atomic.fence is the lone irregular 0xfe op (its operand is a single
    734        * 0x00 byte, not a memarg); every other 0xfe op is a memarg atomic and
    735        * decodes uniformly via the table. */
    736       if (sub == 0x03u) {
    737         if (bin_u8(&r) != 0)
    738           wasm_error(c, wasm_loc(0, 0), "wasm: bad atomic.fence");
    739         wasm_func_add_insn(c, out, f, WASM_INSN_ATOMIC_FENCE, 0);
    740       } else {
    741         const WasmInsnInfo* info =
    742             sub <= 0xffu ? wasm_insn_by_byte(WASM_PREFIX_FE, (uint8_t)sub)
    743                          : NULL;
    744         if (!info || info->operand_class != WASM_OC_MEMARG)
    745           wasm_error(c, wasm_loc(0, 0), "wasm: unsupported threads opcode 0x%x",
    746                      sub);
    747         decode_memarg_insn(&r, c, out, f, (WasmInsnKind)info->kind);
    748       }
    749       break;
    750     }
    751     default: {
    752       /* The base loads/stores (0x28..0x3e) are a contiguous run of memarg ops;
    753        * each decodes identically save for its kind, which the table carries.
    754        * Everything else here is genuinely unknown. */
    755       const WasmInsnInfo* info = wasm_insn_by_byte(WASM_PREFIX_NONE, op);
    756       if (!info || info->operand_class != WASM_OC_MEMARG)
    757         wasm_error(c, wasm_loc(0, 0), "wasm: unsupported opcode 0x%02x", op);
    758       decode_memarg_insn(&r, c, out, f, (WasmInsnKind)info->kind);
    759     }
    760   }
    761 
    762   *pcontrol_depth = control_depth;
    763   *rp = r;
    764 }
    765 
    766 /* Canonical known-section ordering rank. Section ids otherwise appear in
    767  * strictly increasing order, except the bulk-memory DataCount section (id 12),
    768  * which the spec places between the Element (9) and Code (10) sections. Map ids
    769  * to a rank so the monotonicity check accepts the standard sequence
    770  * ...,9,12,10,11 (emitted by clang/wasm-ld and emscripten whenever passive data
    771  * segments or memory.init are used) while still rejecting genuinely
    772  * out-of-order or duplicated sections. Custom sections (id 0) are unordered and
    773  * handled separately by the caller. */
    774 static uint32_t wasm_section_rank(uint8_t id) {
    775   switch (id) {
    776     case 12: return 10; /* DataCount: after Element, before Code */
    777     case 10: return 11; /* Code */
    778     case 11: return 12; /* Data */
    779     default: return id; /* 1..9 keep their natural rank */
    780   }
    781 }
    782 
    783 void wasm_decode_binary(KitCompiler* c, const KitSlice* input,
    784                         WasmModule* out) {
    785   BinReader r;
    786   uint32_t nfunc_types = 0;
    787   uint8_t last_id = 0;
    788   memset(&r, 0, sizeof r);
    789   r.c = c;
    790   r.data = input->data;
    791   r.len = input->len;
    792   r.module = out;
    793   if (r.len < 8 || memcmp(r.data, "\0asm\1\0\0\0", 8) != 0)
    794     wasm_error(c, wasm_loc(0, 0), "wasm: bad magic or version");
    795   r.pos = 8;
    796   while (r.pos < r.len) {
    797     uint8_t id = bin_u8(&r);
    798     uint32_t size = bin_uleb(&r);
    799     size_t end;
    800     bin_need(&r, size);
    801     end = r.pos + size;
    802     if (id != 0 && wasm_section_rank(id) <= wasm_section_rank(last_id))
    803       wasm_error(c, wasm_loc(0, 0), "wasm: sections out of order");
    804     if (id != 0) last_id = id;
    805     if (id == 0) {
    806       uint32_t name_len = bin_uleb(&r);
    807       bin_need(&r, name_len);
    808       if (name_len == 7u && memcmp(r.data + r.pos, "linking", 7) == 0)
    809         wasm_error(c, wasm_loc(0, 0),
    810                    "wasm: relocatable object metadata is not frontend input");
    811       {
    812         WasmCustom* cs = wasm_add_custom(c, out);
    813         cs->name =
    814             wasm_strdup(out->heap, (const char*)(r.data + r.pos), name_len);
    815         if (!cs->name) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory");
    816         r.pos += name_len;
    817         if (kit_slice_eq_cstr(kit_slice_cstr(cs->name), "target_features") ||
    818             kit_slice_eq_cstr(kit_slice_cstr(cs->name), "target-feature"))
    819           out->has_target_features = 1;
    820         cs->len = (uint32_t)(end - r.pos);
    821         if (cs->len) {
    822           cs->data = (uint8_t*)out->heap->alloc(out->heap, cs->len, 1);
    823           if (!cs->data) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory");
    824           memcpy(cs->data, r.data + r.pos, cs->len);
    825         }
    826       }
    827       r.pos = end;
    828       continue;
    829     }
    830     if (id == 1) {
    831       uint32_t i, count = bin_uleb(&r);
    832       for (i = 0; i < count; ++i) {
    833         WasmFuncType* t = wasm_add_type(c, out);
    834         uint32_t j, nparam, nresult;
    835         if (bin_u8(&r) != 0x60u)
    836           wasm_error(c, wasm_loc(0, 0), "wasm: expected function type");
    837         nparam = bin_uleb(&r);
    838         for (j = 0; j < nparam; ++j)
    839           wasm_type_push_param(c, out, t, bin_val_type(&r, 1));
    840         nresult = bin_uleb(&r);
    841         for (j = 0; j < nresult; ++j)
    842           wasm_type_push_result(c, out, t, bin_val_type(&r, 1));
    843       }
    844     } else if (id == 2) {
    845       uint32_t i, count = bin_uleb(&r);
    846       for (i = 0; i < count; ++i) {
    847         char* mod = bin_name(&r, NULL);
    848         char* name = bin_name(&r, NULL);
    849         uint8_t kind = bin_u8(&r);
    850         if (kind == 0) {
    851           uint32_t typeidx = bin_uleb(&r);
    852           WasmFunc* f;
    853           if (typeidx >= out->ntypes)
    854             wasm_error(c, wasm_loc(0, 0), "wasm: bad import type index");
    855           f = wasm_add_func(c, out);
    856           f->is_import = 1;
    857           f->import_module = mod;
    858           f->import_name = name;
    859           f->typeidx = typeidx;
    860           f->has_typeidx = 1;
    861           wasm_func_set_params(c, out, f, out->types[typeidx].params,
    862                                out->types[typeidx].nparams);
    863           wasm_func_set_results(c, out, f, out->types[typeidx].results,
    864                                 out->types[typeidx].nresults);
    865         } else if (kind == 1) {
    866           WasmTable* t = wasm_add_table(c, out);
    867           t->is_import = 1;
    868           t->import_module = mod;
    869           t->import_name = name;
    870           t->elem_type = bin_val_type(&r, 1);
    871           {
    872             uint32_t flags = bin_uleb(&r);
    873             if (flags & ~1u)
    874               wasm_error(c, wasm_loc(0, 0), "wasm: unsupported table limits");
    875             t->has_max = (flags & 1u) != 0;
    876             t->min = bin_uleb(&r);
    877             if (t->has_max) t->max = bin_uleb(&r);
    878           }
    879         } else if (kind == 2) {
    880           uint32_t flags;
    881           WasmMemory* mem = wasm_add_memory(c, out);
    882           mem->is_import = 1;
    883           mem->import_module = mod;
    884           mem->import_name = name;
    885           flags = bin_uleb(&r);
    886           if (flags & ~7u)
    887             wasm_error(c, wasm_loc(0, 0), "wasm: unsupported memory limits");
    888           mem->has_max = (flags & 1u) != 0;
    889           mem->shared = (flags & 2u) != 0;
    890           mem->is64 = (flags & 4u) != 0;
    891           mem->min_pages = mem->is64 ? bin_uleb64(&r) : bin_uleb(&r);
    892           if (mem->has_max)
    893             mem->max_pages = mem->is64 ? bin_uleb64(&r) : bin_uleb(&r);
    894         } else if (kind == 3) {
    895           WasmGlobal* g = wasm_add_global(c, out);
    896           g->is_import = 1;
    897           g->import_module = mod;
    898           g->import_name = name;
    899           g->type = bin_val_type(&r, 0);
    900           g->mutable_ = bin_u8(&r);
    901           if (g->mutable_ > 1u)
    902             wasm_error(c, wasm_loc(0, 0), "wasm: bad global mutability");
    903         } else {
    904           wasm_error(c, wasm_loc(0, 0), "wasm: unsupported import kind");
    905         }
    906       }
    907     } else if (id == 3) {
    908       uint32_t i, count = bin_uleb(&r);
    909       for (i = 0; i < count; ++i) {
    910         uint32_t typeidx = bin_uleb(&r);
    911         WasmFunc* f;
    912         if (typeidx >= out->ntypes)
    913           wasm_error(c, wasm_loc(0, 0), "wasm: bad function type index");
    914         f = wasm_add_func(c, out);
    915         f->typeidx = typeidx;
    916         f->has_typeidx = 1;
    917         wasm_func_set_params(c, out, f, out->types[typeidx].params,
    918                              out->types[typeidx].nparams);
    919         wasm_func_set_results(c, out, f, out->types[typeidx].results,
    920                               out->types[typeidx].nresults);
    921         nfunc_types++;
    922       }
    923     } else if (id == 5) {
    924       uint32_t count = bin_uleb(&r);
    925       for (uint32_t mi = 0; mi < count; ++mi) {
    926         uint32_t flags = bin_uleb(&r);
    927         WasmMemory* mem = wasm_add_memory(c, out);
    928         if (flags & ~7u)
    929           wasm_error(c, wasm_loc(0, 0), "wasm: unsupported memory limits");
    930         mem->has_max = (flags & 1u) != 0;
    931         mem->shared = (flags & 2u) != 0;
    932         mem->is64 = (flags & 4u) != 0;
    933         mem->min_pages = mem->is64 ? bin_uleb64(&r) : bin_uleb(&r);
    934         if (mem->has_max)
    935           mem->max_pages = mem->is64 ? bin_uleb64(&r) : bin_uleb(&r);
    936       }
    937     } else if (id == 4) {
    938       uint32_t i, count = bin_uleb(&r);
    939       for (i = 0; i < count; ++i) {
    940         WasmTable* t = wasm_add_table(c, out);
    941         uint32_t flags;
    942         t->elem_type = bin_val_type(&r, 1);
    943         flags = bin_uleb(&r);
    944         if (flags & ~1u)
    945           wasm_error(c, wasm_loc(0, 0), "wasm: unsupported table limits");
    946         t->has_max = (flags & 1u) != 0;
    947         t->min = bin_uleb(&r);
    948         if (t->has_max) t->max = bin_uleb(&r);
    949       }
    950     } else if (id == 6) {
    951       uint32_t i, count = bin_uleb(&r);
    952       for (i = 0; i < count; ++i) {
    953         WasmGlobal* g = wasm_add_global(c, out);
    954         uint8_t op;
    955         g->type = bin_val_type(&r, 0);
    956         g->mutable_ = bin_u8(&r);
    957         if (g->mutable_ > 1u)
    958           wasm_error(c, wasm_loc(0, 0), "wasm: bad global mutability");
    959         op = bin_u8(&r);
    960         switch (op) {
    961           case 0x41:
    962             g->init.kind = WASM_INSN_I32_CONST;
    963             g->init.imm = bin_sleb(&r, 32);
    964             break;
    965           case 0x42:
    966             g->init.kind = WASM_INSN_I64_CONST;
    967             g->init.imm = bin_sleb(&r, 64);
    968             break;
    969           case 0x43:
    970             g->init.kind = WASM_INSN_F32_CONST;
    971             g->init.fp = bin_f32(&r);
    972             break;
    973           case 0x44:
    974             g->init.kind = WASM_INSN_F64_CONST;
    975             g->init.fp = bin_f64(&r);
    976             break;
    977           default:
    978             wasm_error(c, wasm_loc(0, 0),
    979                        "wasm: unsupported global initializer");
    980         }
    981         if (bin_u8(&r) != 0x0bu)
    982           wasm_error(c, wasm_loc(0, 0), "wasm: malformed global initializer");
    983       }
    984     } else if (id == 7) {
    985       uint32_t i, count = bin_uleb(&r);
    986       for (i = 0; i < count; ++i) {
    987         char* name;
    988         uint8_t kind;
    989         uint32_t idx;
    990         WasmExport* ex;
    991         name = bin_name(&r, NULL);
    992         kind = bin_u8(&r);
    993         idx = bin_uleb(&r);
    994         if (kind > 3u) wasm_error(c, wasm_loc(0, 0), "wasm: bad export kind");
    995         ex = wasm_add_export(c, out);
    996         ex->name = name;
    997         ex->kind = kind;
    998         ex->index = idx;
    999         if (kind == 0 && idx < out->nfuncs) {
   1000           out->funcs[idx].export_name =
   1001               wasm_strdup(out->heap, name, kit_slice_cstr(name).len);
   1002         } else if (kind == 1 && idx < out->ntables) {
   1003           out->tables[idx].export_name =
   1004               wasm_strdup(out->heap, name, kit_slice_cstr(name).len);
   1005         } else if (kind == 2 && idx < out->nmemories) {
   1006           out->memories[idx].export_name =
   1007               wasm_strdup(out->heap, name, kit_slice_cstr(name).len);
   1008         } else if (kind == 3 && idx < out->nglobals) {
   1009           out->globals[idx].export_name =
   1010               wasm_strdup(out->heap, name, kit_slice_cstr(name).len);
   1011         }
   1012       }
   1013     } else if (id == 8) {
   1014       out->has_start = 1;
   1015       out->start_func = bin_uleb(&r);
   1016     } else if (id == 9) {
   1017       uint32_t i, count = bin_uleb(&r);
   1018       for (i = 0; i < count; ++i) {
   1019         WasmElemSegment* e = wasm_add_elem(c, out);
   1020         uint32_t flags = bin_uleb(&r);
   1021         uint32_t n;
   1022         e->elem_type = WASM_VAL_FUNCREF;
   1023         if (flags == 0u) {
   1024           e->mode = WASM_SEG_ACTIVE;
   1025           e->tableidx = 0;
   1026           if (bin_u8(&r) != 0x41)
   1027             wasm_error(c, wasm_loc(0, 0),
   1028                        "wasm: expected i32.const element offset");
   1029           e->offset = bin_sleb(&r, 32);
   1030           if (bin_u8(&r) != 0x0b || e->offset < 0)
   1031             wasm_error(c, wasm_loc(0, 0), "wasm: bad element offset");
   1032         } else if (flags == 1u) {
   1033           e->mode = WASM_SEG_PASSIVE;
   1034           if (bin_u8(&r) != 0x00)
   1035             wasm_error(c, wasm_loc(0, 0),
   1036                        "wasm: unsupported passive element kind");
   1037         } else if (flags == 2u) {
   1038           e->mode = WASM_SEG_ACTIVE;
   1039           e->tableidx = bin_uleb(&r);
   1040           if (bin_u8(&r) != 0x41)
   1041             wasm_error(c, wasm_loc(0, 0),
   1042                        "wasm: expected i32.const element offset");
   1043           e->offset = bin_sleb(&r, 32);
   1044           if (bin_u8(&r) != 0x0b || e->offset < 0)
   1045             wasm_error(c, wasm_loc(0, 0), "wasm: bad element offset");
   1046           if (bin_u8(&r) != 0x00)
   1047             wasm_error(c, wasm_loc(0, 0), "wasm: unsupported element kind");
   1048         } else if (flags == 3u) {
   1049           e->mode = WASM_SEG_DECLARATIVE;
   1050           if (bin_u8(&r) != 0x00)
   1051             wasm_error(c, wasm_loc(0, 0),
   1052                        "wasm: unsupported declarative element kind");
   1053         } else {
   1054           wasm_error(c, wasm_loc(0, 0),
   1055                      "wasm: unsupported element segment flags 0x%x", flags);
   1056         }
   1057         n = bin_uleb(&r);
   1058         for (uint32_t k = 0; k < n; ++k)
   1059           wasm_elem_push_func(c, out, e, bin_uleb(&r));
   1060       }
   1061     } else if (id == 10) {
   1062       uint32_t i, count = bin_uleb(&r);
   1063       uint32_t func_index = 0;
   1064       if (count != nfunc_types)
   1065         wasm_error(c, wasm_loc(0, 0), "wasm: function/code count mismatch");
   1066       for (i = 0; i < count; ++i) {
   1067         uint32_t body_size = bin_uleb(&r);
   1068         size_t body_end;
   1069         uint32_t local_groups, j;
   1070         uint32_t control_depth = 0;
   1071         int saw_body_end = 0;
   1072         WasmFunc* f;
   1073         while (func_index < out->nfuncs && out->funcs[func_index].is_import)
   1074           func_index++;
   1075         if (func_index >= out->nfuncs)
   1076           wasm_error(c, wasm_loc(0, 0), "wasm: code body without function");
   1077         f = &out->funcs[func_index++];
   1078         bin_need(&r, body_size);
   1079         body_end = r.pos + body_size;
   1080         local_groups = bin_uleb(&r);
   1081         for (j = 0; j < local_groups; ++j) {
   1082           uint32_t k, nlocals = bin_uleb(&r);
   1083           WasmValType vt = bin_val_type(&r, 1);
   1084           for (k = 0; k < nlocals; ++k) wasm_func_push_local(c, out, f, vt);
   1085         }
   1086         while (r.pos < body_end) {
   1087           uint8_t op = bin_u8(&r);
   1088           if (op == 0x0bu) {
   1089             if (!control_depth) {
   1090               saw_body_end = 1;
   1091               break;
   1092             }
   1093             control_depth--;
   1094             wasm_func_add_insn(c, out, f, WASM_INSN_END, 0);
   1095             continue;
   1096           }
   1097           decode_body_insn(&r, out, f, op, &control_depth);
   1098         }
   1099         if (!saw_body_end)
   1100           wasm_error(c, wasm_loc(0, 0), "wasm: function body missing end");
   1101         r.pos = body_end;
   1102       }
   1103     } else if (id == 11) {
   1104       uint32_t i, count = bin_uleb(&r);
   1105       for (i = 0; i < count; ++i) {
   1106         WasmDataSegment* d = wasm_add_data(c, out);
   1107         uint32_t flags = bin_uleb(&r);
   1108         uint32_t n;
   1109         if (flags == 0u) {
   1110           d->mode = WASM_SEG_ACTIVE;
   1111           d->memidx = 0;
   1112           {
   1113             uint8_t op = bin_u8(&r);
   1114             if (op == 0x41)
   1115               d->offset = bin_sleb(&r, 32);
   1116             else if (op == 0x42)
   1117               d->offset = bin_sleb(&r, 64);
   1118             else
   1119               wasm_error(c, wasm_loc(0, 0), "wasm: expected const data offset");
   1120           }
   1121           if (bin_u8(&r) != 0x0b || d->offset < 0)
   1122             wasm_error(c, wasm_loc(0, 0), "wasm: bad data offset");
   1123         } else if (flags == 1u) {
   1124           d->mode = WASM_SEG_PASSIVE;
   1125         } else if (flags == 2u) {
   1126           d->mode = WASM_SEG_ACTIVE;
   1127           d->memidx = bin_uleb(&r);
   1128           {
   1129             uint8_t op = bin_u8(&r);
   1130             if (op == 0x41)
   1131               d->offset = bin_sleb(&r, 32);
   1132             else if (op == 0x42)
   1133               d->offset = bin_sleb(&r, 64);
   1134             else
   1135               wasm_error(c, wasm_loc(0, 0), "wasm: expected const data offset");
   1136           }
   1137           if (bin_u8(&r) != 0x0b || d->offset < 0)
   1138             wasm_error(c, wasm_loc(0, 0), "wasm: bad data offset");
   1139         } else {
   1140           wasm_error(c, wasm_loc(0, 0),
   1141                      "wasm: unsupported data segment flags 0x%x", flags);
   1142         }
   1143         n = bin_uleb(&r);
   1144         bin_need(&r, n);
   1145         wasm_data_set_bytes(c, out, d, r.data + r.pos, (uint64_t)n);
   1146         r.pos += n;
   1147       }
   1148     } else if (id == 12) {
   1149       /* Data count section. Conservatively accept and discard; bulk-memory
   1150        * validation only needs it for forward-references during streaming
   1151        * validation, which we don't do here. */
   1152       (void)bin_uleb(&r);
   1153     } else {
   1154       r.pos = end;
   1155     }
   1156     if (r.pos != end)
   1157       wasm_error(c, wasm_loc(0, 0), "wasm: malformed section length");
   1158   }
   1159 }
   1160 
   1161 int wasm_is_binary(const KitSlice* input) {
   1162   return input->len >= 4u && input->data[0] == 0x00 && input->data[1] == 0x61 &&
   1163          input->data[2] == 0x73 && input->data[3] == 0x6d;
   1164 }
   1165 
   1166 /* Decode exactly one instruction at data[pos..] into *out, returning the number
   1167  * of bytes consumed (0 if none). The control-flow opcodes block/loop/if/end are
   1168  * returned as plain instructions; callers that care about nesting track depth
   1169  * themselves. `scratch` is a caller-owned reusable module (init via
   1170  * wasm_module_init); its first function is reused as a decode buffer so this is
   1171  * allocation-free after the first call. Malformed input is fatal, matching
   1172  * wasm_decode_binary. */
   1173 size_t wasm_decode_one_insn(KitCompiler* c, WasmModule* scratch,
   1174                             const uint8_t* data, size_t len, size_t pos,
   1175                             WasmInsn* out) {
   1176   BinReader r;
   1177   WasmFunc* f;
   1178   uint8_t op;
   1179   uint32_t control_depth = 0;
   1180   if (pos >= len) return 0;
   1181   if (scratch->nfuncs == 0) (void)wasm_add_func(c, scratch);
   1182   f = &scratch->funcs[0];
   1183   f->ninsns = 0;
   1184   memset(&r, 0, sizeof r);
   1185   r.c = c;
   1186   r.data = data;
   1187   r.len = len;
   1188   r.pos = pos;
   1189   r.module = scratch;
   1190   op = bin_u8(&r);
   1191   if (op == 0x0bu) {
   1192     memset(out, 0, sizeof *out);
   1193     out->kind = WASM_INSN_END;
   1194     return r.pos - pos;
   1195   }
   1196   decode_body_insn(&r, scratch, f, op, &control_depth);
   1197   if (f->ninsns == 0) return 0;
   1198   *out = f->insns[f->ninsns - 1u];
   1199   return r.pos - pos;
   1200 }