kit

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

decode.c (48694B)


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