kit

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

validate.c (48055B)


      1 #include "wasm/wasm.h"
      2 
      3 typedef struct WasmValStack {
      4   WasmValType vals[256];
      5   uint32_t depth;
      6   KitSrcLoc loc;
      7 } WasmValStack;
      8 
      9 /* Inline cap for a block/loop/if signature's param and result vectors. Block
     10  * signatures are tiny in practice; a function type referenced by a typeidx
     11  * blocktype with more entries than this is rejected with a clean diagnostic
     12  * rather than overflowing. */
     13 #define WASM_CTRL_SIG_MAX 64u
     14 
     15 typedef struct WasmControlFrame {
     16   uint8_t kind;
     17   int seen_else;
     18   int unreachable;
     19   /* Stack height at block entry, recorded AFTER the block params were popped
     20    * and BEFORE they were pushed back (the spec's push_ctrl height). */
     21   uint32_t height;
     22   /* The block's resolved signature [params*] -> [results*]. A branch to a
     23    * loop transfers its params; a branch to a block/if transfers its results
     24    * (see wasm_branch_label_types). */
     25   WasmValType params[WASM_CTRL_SIG_MAX];
     26   uint32_t nparams;
     27   WasmValType results[WASM_CTRL_SIG_MAX];
     28   uint32_t nresults;
     29 } WasmControlFrame;
     30 
     31 static int wasm_valtypes_eq(const WasmValType* a, uint32_t na,
     32                             const WasmValType* b, uint32_t nb) {
     33   return na == nb && (na == 0 || memcmp(a, b, sizeof(WasmValType) * na) == 0);
     34 }
     35 
     36 /* The value types a branch to control frame `f` transfers: a branch to a loop
     37  * targets its params (continues the loop), a branch to a block/if targets its
     38  * results (exits the block). */
     39 static void wasm_branch_label_types(const WasmControlFrame* f,
     40                                     const WasmValType** types, uint32_t* n) {
     41   if (f->kind == WASM_INSN_LOOP) {
     42     *types = f->params;
     43     *n = f->nparams;
     44   } else {
     45     *types = f->results;
     46     *n = f->nresults;
     47   }
     48 }
     49 
     50 static WasmValType wasm_global_init_type(const WasmInsn* in) {
     51   switch (in->kind) {
     52     case WASM_INSN_I32_CONST:
     53       return WASM_VAL_I32;
     54     case WASM_INSN_I64_CONST:
     55       return WASM_VAL_I64;
     56     case WASM_INSN_F32_CONST:
     57       return WASM_VAL_F32;
     58     case WASM_INSN_F64_CONST:
     59       return WASM_VAL_F64;
     60     default:
     61       return 0;
     62   }
     63 }
     64 
     65 static uint64_t wasm_memory_initial_bytes(KitCompiler* c,
     66                                           const WasmMemory* mem) {
     67   if (mem->min_pages > UINT64_MAX / 65536u)
     68     wasm_error(c, wasm_loc(0, 0), "wasm: memory minimum overflows");
     69   return mem->min_pages * 65536u;
     70 }
     71 
     72 static uint32_t wasm_mem_align_log2(uint32_t width) {
     73   uint32_t lg = 0;
     74   while (width > 1u) {
     75     width >>= 1u;
     76     lg++;
     77   }
     78   return lg;
     79 }
     80 
     81 static void wasm_validate_memarg(KitCompiler* c, const WasmInsn* in,
     82                                  const char* what) {
     83   uint32_t max_align = wasm_mem_align_log2(wasm_mem_width(in->kind));
     84   if (in->align > max_align)
     85     wasm_error(c, in->loc, "wasm: bad %s alignment", what);
     86 }
     87 
     88 static void wasm_stack_push(KitCompiler* c, WasmValStack* s, WasmValType vt) {
     89   if (s->depth >= 256u) wasm_error(c, s->loc, "wasm: operand stack too deep");
     90   s->vals[s->depth++] = vt;
     91 }
     92 
     93 static int wasm_stack_pop(KitCompiler* c, WasmValStack* s,
     94                           WasmControlFrame* frames, uint32_t nframes,
     95                           WasmValType expected, const char* what) {
     96   WasmControlFrame* top = &frames[nframes - 1u];
     97   if (s->depth <= top->height) {
     98     if (top->unreachable) return 1;
     99     wasm_error(c, s->loc, "wasm: operand stack underflow");
    100   }
    101   if (expected && s->vals[s->depth - 1u] != expected)
    102     wasm_error(c, s->loc, "wasm: %s type mismatch (expected=0x%x got=0x%x)",
    103                what, (unsigned)expected, (unsigned)s->vals[s->depth - 1u]);
    104   s->depth--;
    105   return 1;
    106 }
    107 
    108 static WasmValType wasm_stack_pop_any(KitCompiler* c, WasmValStack* s,
    109                                       WasmControlFrame* frames,
    110                                       uint32_t nframes, const char* what) {
    111   WasmControlFrame* top = &frames[nframes - 1u];
    112   WasmValType vt;
    113   if (s->depth <= top->height) {
    114     if (top->unreachable) return WASM_VAL_I32;
    115     wasm_error(c, s->loc, "wasm: operand stack underflow");
    116   }
    117   vt = s->vals[s->depth - 1u];
    118   if (!vt) wasm_error(c, s->loc, "wasm: %s type mismatch", what);
    119   s->depth--;
    120   return vt;
    121 }
    122 
    123 static void wasm_stack_pop_ref(KitCompiler* c, WasmValStack* s,
    124                                WasmControlFrame* frames, uint32_t nframes,
    125                                const char* what) {
    126   WasmValType vt = wasm_stack_pop_any(c, s, frames, nframes, what);
    127   if (!wasm_is_ref_type(vt))
    128     wasm_error(c, s->loc, "wasm: %s type mismatch", what);
    129 }
    130 
    131 static void wasm_mark_unreachable(WasmValStack* s, WasmControlFrame* frames,
    132                                   uint32_t nframes) {
    133   WasmControlFrame* top = &frames[nframes - 1u];
    134   s->depth = top->height;
    135   top->unreachable = 1;
    136 }
    137 
    138 /* Pop a value vector in reverse (top of stack is types[n-1]). */
    139 static void wasm_stack_pop_vec(KitCompiler* c, WasmValStack* s,
    140                                WasmControlFrame* frames, uint32_t nframes,
    141                                const WasmValType* types, uint32_t n,
    142                                const char* what) {
    143   uint32_t k;
    144   for (k = 0; k < n; ++k)
    145     wasm_stack_pop(c, s, frames, nframes, types[n - 1u - k], what);
    146 }
    147 
    148 /* Push a value vector bottom-to-top. */
    149 static void wasm_stack_push_vec(KitCompiler* c, WasmValStack* s,
    150                                 const WasmValType* types, uint32_t n) {
    151   uint32_t k;
    152   for (k = 0; k < n; ++k) wasm_stack_push(c, s, types[k]);
    153 }
    154 
    155 /* Resolve a block/loop/if instruction's blocktype into `fr`'s param/result
    156  * vectors: void (no params, no results), the single-result shorthand, or a
    157  * function-type index (the multi-value form). */
    158 static void wasm_resolve_blocktype(KitCompiler* c, WasmModule* m,
    159                                    const WasmInsn* in, WasmControlFrame* fr) {
    160   fr->nparams = 0;
    161   fr->nresults = 0;
    162   if (wasm_insn_blocktype_is_typeidx(in)) {
    163     uint32_t idx = wasm_insn_blocktype_typeidx(in);
    164     const WasmFuncType* t;
    165     if (idx >= m->ntypes)
    166       wasm_error(c, in->loc, "wasm: block type index out of range");
    167     t = &m->types[idx];
    168     if (t->nparams > WASM_CTRL_SIG_MAX || t->nresults > WASM_CTRL_SIG_MAX)
    169       wasm_error(c, in->loc, "wasm: block signature too large");
    170     fr->nparams = t->nparams;
    171     if (t->nparams) memcpy(fr->params, t->params, sizeof(WasmValType) * t->nparams);
    172     fr->nresults = t->nresults;
    173     if (t->nresults)
    174       memcpy(fr->results, t->results, sizeof(WasmValType) * t->nresults);
    175   } else if (in->type) {
    176     fr->nresults = 1;
    177     fr->results[0] = (WasmValType)in->type;
    178   }
    179 }
    180 
    181 /* Double the control-frame stack. Caller passes the current capacity by
    182  * reference; it is updated to the new capacity. */
    183 static WasmControlFrame* wasm_ctrl_grow(KitCompiler* c, WasmModule* m,
    184                                         WasmControlFrame* frames, uint32_t* cap,
    185                                         KitSrcLoc loc) {
    186   uint32_t nc = *cap * 2u;
    187   WasmControlFrame* p = (WasmControlFrame*)wasm_realloc(
    188       m->heap, frames, sizeof(WasmControlFrame) * *cap,
    189       sizeof(WasmControlFrame) * nc);
    190   if (!p) wasm_error(c, loc, "wasm: out of memory");
    191   *cap = nc;
    192   return p;
    193 }
    194 
    195 void wasm_validate(WasmModule* m, KitCompiler* c) {
    196   uint32_t i, j;
    197   for (i = 0; i < m->ntypes; ++i) {
    198     for (j = 0; j < m->types[i].nparams; ++j)
    199       if (!wasm_is_frontend_value_type(m->types[i].params[j]))
    200         wasm_error(c, wasm_loc(0, 0), "wasm: unsupported parameter type");
    201     for (j = 0; j < m->types[i].nresults; ++j)
    202       if (!wasm_is_frontend_value_type(m->types[i].results[j]))
    203         wasm_error(c, wasm_loc(0, 0), "wasm: unsupported result type");
    204   }
    205   for (i = 0; i < m->nmemories; ++i) {
    206     if (m->memories[i].has_max &&
    207         m->memories[i].max_pages < m->memories[i].min_pages)
    208       wasm_error(c, wasm_loc(0, 0), "wasm: memory maximum below minimum");
    209     if (m->memories[i].shared && !m->memories[i].has_max)
    210       wasm_error(c, wasm_loc(0, 0), "wasm: shared memory requires maximum");
    211   }
    212   for (i = 0; i < m->ntables; ++i) {
    213     if (m->tables[i].elem_type != WASM_VAL_FUNCREF)
    214       wasm_error(c, wasm_loc(0, 0),
    215                  "wasm: reference type is unsupported for tables");
    216     if (m->tables[i].has_max && m->tables[i].max < m->tables[i].min)
    217       wasm_error(c, wasm_loc(0, 0), "wasm: table maximum below minimum");
    218   }
    219   for (i = 0; i < m->nglobals; ++i) {
    220     WasmGlobal* g = &m->globals[i];
    221     if (!wasm_is_num_type(g->type))
    222       wasm_error(c, wasm_loc(0, 0), "wasm: unsupported global type");
    223     if (!g->is_import && wasm_global_init_type(&g->init) != g->type)
    224       wasm_error(c, wasm_loc(0, 0), "wasm: global initializer type mismatch");
    225   }
    226   for (i = 0; i < m->nexports; ++i) {
    227     WasmExport* ex = &m->exports[i];
    228     if ((ex->kind == 0 && ex->index >= m->nfuncs) ||
    229         (ex->kind == 1 && ex->index >= m->ntables) ||
    230         (ex->kind == 2 && ex->index >= m->nmemories) ||
    231         (ex->kind == 3 && ex->index >= m->nglobals))
    232       wasm_error(c, wasm_loc(0, 0), "wasm: export index out of range");
    233   }
    234   if (m->has_start) {
    235     if (m->start_func >= m->nfuncs)
    236       wasm_error(c, wasm_loc(0, 0), "wasm: start function index out of range");
    237     if (m->funcs[m->start_func].nparams || m->funcs[m->start_func].nresults)
    238       wasm_error(c, wasm_loc(0, 0),
    239                  "wasm: start function must have no params or results");
    240   }
    241   for (i = 0; i < m->ndata; ++i) {
    242     const WasmDataSegment* d = &m->data[i];
    243     uint64_t memory_bytes;
    244     uint64_t offset;
    245     if (d->mode != WASM_SEG_ACTIVE) continue;
    246     if (d->memidx >= m->nmemories)
    247       wasm_error(c, wasm_loc(0, 0), "wasm: data memory index out of range");
    248     if (d->offset < 0) wasm_error(c, wasm_loc(0, 0), "wasm: bad data offset");
    249     memory_bytes = wasm_memory_initial_bytes(c, &m->memories[d->memidx]);
    250     offset = (uint64_t)d->offset;
    251     if (offset > memory_bytes || d->nbytes > memory_bytes - offset)
    252       wasm_error(c, wasm_loc(0, 0), "wasm: data segment out of range");
    253   }
    254   for (i = 0; i < m->nelems; ++i) {
    255     if (m->elems[i].elem_type != WASM_VAL_FUNCREF)
    256       wasm_error(c, wasm_loc(0, 0), "wasm: unsupported element segment type");
    257     if (m->elems[i].mode == WASM_SEG_ACTIVE) {
    258       uint32_t table_min;
    259       uint64_t offset;
    260       if (m->elems[i].tableidx >= m->ntables)
    261         wasm_error(c, wasm_loc(0, 0), "wasm: element table index out of range");
    262       table_min = m->tables[m->elems[i].tableidx].min;
    263       if (m->elems[i].offset < 0)
    264         wasm_error(c, wasm_loc(0, 0), "wasm: element segment out of range");
    265       offset = (uint64_t)m->elems[i].offset;
    266       if (offset > table_min || m->elems[i].nfuncs > table_min - offset)
    267         wasm_error(c, wasm_loc(0, 0), "wasm: element segment out of range");
    268     }
    269     for (j = 0; j < m->elems[i].nfuncs; ++j)
    270       if (m->elems[i].funcs[j] >= m->nfuncs)
    271         wasm_error(c, wasm_loc(0, 0),
    272                    "wasm: element function index out of range");
    273   }
    274   for (i = 0; i < m->nfuncs; ++i) wasm_validate_func(c, m, &m->funcs[i]);
    275 }
    276 
    277 void wasm_validate_func(KitCompiler* c, WasmModule* m, WasmFunc* f) {
    278   WasmValStack stack;
    279   /* The control stack grows with structured-block nesting. Deeply nested
    280    * shapes — e.g. a switch with hundreds of cases lowered to a tower of
    281    * blocks — can run far past any fixed cap, so grow it on demand. On the
    282    * error path wasm_error aborts the whole compile, so the leak is moot
    283    * (matching the wasm frontend's growable control stack in lang/wasm/cg.c). */
    284   uint32_t control_cap = 64u;
    285   WasmControlFrame* control = (WasmControlFrame*)m->heap->alloc(
    286       m->heap, sizeof(WasmControlFrame) * control_cap,
    287       _Alignof(WasmControlFrame));
    288   uint32_t ncontrol = 1;
    289   uint32_t j;
    290   if (!control) wasm_error(c, f->loc, "wasm: out of memory");
    291   memset(&stack, 0, sizeof stack);
    292   memset(control, 0, sizeof(WasmControlFrame) * control_cap);
    293   control[0].kind = 0xffu;
    294   control[0].height = 0;
    295   if (f->is_import) {
    296     if (f->ninsns)
    297       wasm_error(c, wasm_loc(0, 0), "wasm: imported function has body");
    298     m->heap->free(m->heap, control, sizeof(WasmControlFrame) * control_cap);
    299     return;
    300   }
    301   {
    302     for (j = 0; j < f->ninsns; ++j) {
    303       WasmInsn* in = &f->insns[j];
    304       WasmValType vt, src, dst;
    305       stack.loc = in->loc;
    306 #define wasm_loc(line, col) (in->loc)
    307       switch (in->kind) {
    308         case WASM_INSN_F32_CONST:
    309           wasm_stack_push(c, &stack, WASM_VAL_F32);
    310           break;
    311         case WASM_INSN_F64_CONST:
    312           wasm_stack_push(c, &stack, WASM_VAL_F64);
    313           break;
    314         case WASM_INSN_I32_CONST:
    315           wasm_stack_push(c, &stack, WASM_VAL_I32);
    316           break;
    317         case WASM_INSN_I64_CONST:
    318           wasm_stack_push(c, &stack, WASM_VAL_I64);
    319           break;
    320         case WASM_INSN_LOCAL_GET:
    321           if (in->imm < 0 ||
    322               (uint64_t)in->imm >= (uint64_t)f->nparams + f->nlocals)
    323             wasm_error(c, wasm_loc(0, 0), "wasm: local index out of range");
    324           wasm_stack_push(c, &stack,
    325                           wasm_func_local_type(f, (uint32_t)in->imm));
    326           break;
    327         case WASM_INSN_LOCAL_SET:
    328         case WASM_INSN_LOCAL_TEE:
    329           if (in->imm < 0 ||
    330               (uint64_t)in->imm >= (uint64_t)f->nparams + f->nlocals)
    331             wasm_error(c, wasm_loc(0, 0), "wasm: local index out of range");
    332           wasm_stack_pop(c, &stack, control, ncontrol,
    333                          wasm_func_local_type(f, (uint32_t)in->imm), "local");
    334           if (in->kind == WASM_INSN_LOCAL_TEE)
    335             wasm_stack_push(c, &stack,
    336                             wasm_func_local_type(f, (uint32_t)in->imm));
    337           break;
    338         case WASM_INSN_CALL:
    339         case WASM_INSN_RETURN_CALL:
    340           if (in->imm < 0 || (uint64_t)in->imm >= m->nfuncs)
    341             wasm_error(c, wasm_loc(0, 0), "wasm: call index out of range");
    342           if (in->kind == WASM_INSN_RETURN_CALL) {
    343             wasm_require_feature(c, m, WASM_FEATURE_TAIL_CALLS, "tail calls",
    344                                  "return_call");
    345             if (!wasm_valtypes_eq(m->funcs[in->imm].results,
    346                                   m->funcs[in->imm].nresults, f->results,
    347                                   f->nresults))
    348               wasm_error(c, wasm_loc(0, 0),
    349                          "wasm: return_call result type mismatch");
    350           }
    351           for (uint32_t k = 0; k < m->funcs[in->imm].nparams; ++k) {
    352             uint32_t param = m->funcs[in->imm].nparams - 1u - k;
    353             wasm_stack_pop(c, &stack, control, ncontrol,
    354                            m->funcs[in->imm].params[param], "call argument");
    355           }
    356           if (in->kind == WASM_INSN_RETURN_CALL) {
    357             wasm_mark_unreachable(&stack, control, ncontrol);
    358           } else {
    359             wasm_stack_push_vec(c, &stack, m->funcs[in->imm].results,
    360                                 m->funcs[in->imm].nresults);
    361           }
    362           break;
    363         case WASM_INSN_CALL_INDIRECT: {
    364           WasmFuncType* t;
    365           if (in->imm < 0 || (uint64_t)in->imm >= m->ntypes)
    366             wasm_error(c, wasm_loc(0, 0),
    367                        "wasm: call_indirect type index out of range");
    368           if (in->align >= m->ntables)
    369             wasm_error(c, wasm_loc(0, 0),
    370                        "wasm: call_indirect table index out of range");
    371           t = &m->types[in->imm];
    372           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    373                          "call_indirect index");
    374           for (uint32_t k = 0; k < t->nparams; ++k) {
    375             uint32_t param = t->nparams - 1u - k;
    376             wasm_stack_pop(c, &stack, control, ncontrol, t->params[param],
    377                            "call_indirect argument");
    378           }
    379           wasm_stack_push_vec(c, &stack, t->results, t->nresults);
    380           break;
    381         }
    382         case WASM_INSN_RETURN_CALL_INDIRECT: {
    383           WasmFuncType* t;
    384           wasm_require_feature(c, m, WASM_FEATURE_TAIL_CALLS, "tail calls",
    385                                "return_call_indirect");
    386           if (in->imm < 0 || (uint64_t)in->imm >= m->ntypes)
    387             wasm_error(c, wasm_loc(0, 0),
    388                        "wasm: return_call_indirect type index out of range");
    389           if (in->align >= m->ntables)
    390             wasm_error(c, wasm_loc(0, 0),
    391                        "wasm: return_call_indirect table index out of range");
    392           t = &m->types[in->imm];
    393           if (!wasm_valtypes_eq(t->results, t->nresults, f->results,
    394                                 f->nresults))
    395             wasm_error(c, wasm_loc(0, 0),
    396                        "wasm: return_call_indirect result type mismatch");
    397           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    398                          "return_call_indirect index");
    399           for (uint32_t k = 0; k < t->nparams; ++k) {
    400             uint32_t param = t->nparams - 1u - k;
    401             wasm_stack_pop(c, &stack, control, ncontrol, t->params[param],
    402                            "return_call_indirect argument");
    403           }
    404           wasm_mark_unreachable(&stack, control, ncontrol);
    405           break;
    406         }
    407         case WASM_INSN_REF_NULL:
    408           wasm_require_feature(c, m, WASM_FEATURE_TYPED_FUNC_REFS,
    409                                "typed function references", "ref.null");
    410           if (!wasm_is_ref_type((WasmValType)in->imm))
    411             wasm_error(c, wasm_loc(0, 0), "wasm: bad ref.null type");
    412           if ((WasmValType)in->imm != WASM_VAL_FUNCREF)
    413             wasm_error(c, wasm_loc(0, 0), "wasm: unsupported reference type");
    414           wasm_stack_push(c, &stack, (WasmValType)in->imm);
    415           break;
    416         case WASM_INSN_REF_FUNC:
    417           wasm_require_feature(c, m, WASM_FEATURE_TYPED_FUNC_REFS,
    418                                "typed function references", "ref.func");
    419           if (in->imm < 0 || (uint64_t)in->imm >= m->nfuncs)
    420             wasm_error(c, wasm_loc(0, 0), "wasm: ref.func index out of range");
    421           wasm_stack_push(c, &stack, WASM_VAL_FUNCREF);
    422           break;
    423         case WASM_INSN_REF_IS_NULL:
    424           wasm_require_feature(c, m, WASM_FEATURE_TYPED_FUNC_REFS,
    425                                "typed function references", "ref.is_null");
    426           wasm_stack_pop_ref(c, &stack, control, ncontrol, "ref.is_null");
    427           wasm_stack_push(c, &stack, WASM_VAL_I32);
    428           break;
    429         case WASM_INSN_CALL_REF:
    430         case WASM_INSN_RETURN_CALL_REF: {
    431           WasmFuncType* t;
    432           wasm_require_feature(c, m, WASM_FEATURE_TYPED_FUNC_REFS,
    433                                "typed function references", "call_ref");
    434           if (in->kind == WASM_INSN_RETURN_CALL_REF)
    435             wasm_require_feature(c, m, WASM_FEATURE_TAIL_CALLS, "tail calls",
    436                                  "return_call_ref");
    437           if (in->imm < 0 || (uint64_t)in->imm >= m->ntypes)
    438             wasm_error(c, wasm_loc(0, 0),
    439                        "wasm: call_ref type index out of range");
    440           t = &m->types[in->imm];
    441           if (in->kind == WASM_INSN_RETURN_CALL_REF &&
    442               !wasm_valtypes_eq(t->results, t->nresults, f->results,
    443                                 f->nresults))
    444             wasm_error(c, wasm_loc(0, 0),
    445                        "wasm: return_call_ref result type mismatch");
    446           wasm_stack_pop_ref(c, &stack, control, ncontrol, "call_ref callee");
    447           for (uint32_t k = 0; k < t->nparams; ++k) {
    448             uint32_t param = t->nparams - 1u - k;
    449             wasm_stack_pop(c, &stack, control, ncontrol, t->params[param],
    450                            "call_ref argument");
    451           }
    452           if (in->kind == WASM_INSN_RETURN_CALL_REF)
    453             wasm_mark_unreachable(&stack, control, ncontrol);
    454           else
    455             wasm_stack_push_vec(c, &stack, t->results, t->nresults);
    456           break;
    457         }
    458         case WASM_INSN_GLOBAL_GET:
    459           if (in->imm < 0 || (uint64_t)in->imm >= m->nglobals)
    460             wasm_error(c, wasm_loc(0, 0), "wasm: global index out of range");
    461           wasm_stack_push(c, &stack, m->globals[in->imm].type);
    462           break;
    463         case WASM_INSN_GLOBAL_SET:
    464           if (in->imm < 0 || (uint64_t)in->imm >= m->nglobals)
    465             wasm_error(c, wasm_loc(0, 0), "wasm: global index out of range");
    466           if (!m->globals[in->imm].mutable_)
    467             wasm_error(c, wasm_loc(0, 0), "wasm: global is immutable");
    468           wasm_stack_pop(c, &stack, control, ncontrol, m->globals[in->imm].type,
    469                          "global");
    470           break;
    471         case WASM_INSN_RETURN:
    472           wasm_stack_pop_vec(c, &stack, control, ncontrol, f->results,
    473                              f->nresults, "return");
    474           wasm_mark_unreachable(&stack, control, ncontrol);
    475           break;
    476         case WASM_INSN_DROP:
    477           wasm_stack_pop(c, &stack, control, ncontrol, 0, "drop");
    478           break;
    479         case WASM_INSN_I32_EQZ:
    480           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "eqz");
    481           wasm_stack_push(c, &stack, WASM_VAL_I32);
    482           break;
    483         case WASM_INSN_I64_EQZ:
    484           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I64, "eqz");
    485           wasm_stack_push(c, &stack, WASM_VAL_I32);
    486           break;
    487         case WASM_INSN_BLOCK:
    488         case WASM_INSN_LOOP:
    489         case WASM_INSN_IF: {
    490           WasmControlFrame* fr;
    491           if (in->kind == WASM_INSN_IF)
    492             wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "if");
    493           if (ncontrol == control_cap)
    494             control = wasm_ctrl_grow(c, m, control, &control_cap, in->loc);
    495           fr = &control[ncontrol];
    496           fr->kind = in->kind;
    497           fr->seen_else = 0;
    498           fr->unreachable = 0;
    499           wasm_resolve_blocktype(c, m, in, fr);
    500           /* Pop the block's params off the enclosing stack, record the entry
    501            * height there, then re-push the params so the block body sees them.
    502            * A branch back to a loop or out of a block re-establishes exactly
    503            * this shape. */
    504           wasm_stack_pop_vec(c, &stack, control, ncontrol, fr->params,
    505                              fr->nparams, "block param");
    506           fr->height = stack.depth;
    507           ncontrol++;
    508           wasm_stack_push_vec(c, &stack, fr->params, fr->nparams);
    509           break;
    510         }
    511         case WASM_INSN_ELSE: {
    512           WasmControlFrame* fr = &control[ncontrol - 1u];
    513           if (ncontrol <= 1u || fr->kind != WASM_INSN_IF)
    514             wasm_error(c, wasm_loc(0, 0), "wasm: else without if");
    515           /* The then-arm must leave exactly the block's results on the stack
    516            * (above the entry height). */
    517           wasm_stack_pop_vec(c, &stack, control, ncontrol, fr->results,
    518                              fr->nresults, "if branch result");
    519           if (!fr->unreachable && stack.depth != fr->height)
    520             wasm_error(c, wasm_loc(0, 0), "wasm: if branch result mismatch");
    521           /* The else-arm re-enters with the block's params on the stack. */
    522           stack.depth = fr->height;
    523           wasm_stack_push_vec(c, &stack, fr->params, fr->nparams);
    524           fr->seen_else = 1;
    525           fr->unreachable = 0;
    526           break;
    527         }
    528         case WASM_INSN_END: {
    529           WasmControlFrame* fr = &control[ncontrol - 1u];
    530           if (ncontrol <= 1u)
    531             wasm_error(c, wasm_loc(0, 0), "wasm: end without block");
    532           /* An if with no else arm has an implicit empty else, well-typed only
    533            * when the block's params already equal its results. */
    534           if (fr->kind == WASM_INSN_IF && !fr->seen_else &&
    535               !wasm_valtypes_eq(fr->params, fr->nparams, fr->results,
    536                                 fr->nresults))
    537             wasm_error(c, wasm_loc(0, 0),
    538                        "wasm: if without else cannot yield a result");
    539           wasm_stack_pop_vec(c, &stack, control, ncontrol, fr->results,
    540                              fr->nresults, "block result");
    541           if (!fr->unreachable && stack.depth != fr->height)
    542             wasm_error(c, wasm_loc(0, 0), "wasm: block result mismatch");
    543           stack.depth = fr->height;
    544           ncontrol--;
    545           /* Push the block's results for the enclosing scope to consume. */
    546           wasm_stack_push_vec(c, &stack, fr->results, fr->nresults);
    547           break;
    548         }
    549         case WASM_INSN_BR: {
    550           const WasmValType* lt;
    551           uint32_t nlt;
    552           if (in->imm < 0 || (uint64_t)in->imm >= ncontrol - 1u)
    553             wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range");
    554           wasm_branch_label_types(&control[ncontrol - 1u - (uint32_t)in->imm],
    555                                   &lt, &nlt);
    556           wasm_stack_pop_vec(c, &stack, control, ncontrol, lt, nlt, "br");
    557           wasm_mark_unreachable(&stack, control, ncontrol);
    558           break;
    559         }
    560         case WASM_INSN_BR_IF: {
    561           const WasmValType* lt;
    562           uint32_t nlt;
    563           if (in->imm < 0 || (uint64_t)in->imm >= ncontrol - 1u)
    564             wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range");
    565           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "br_if");
    566           /* The branch label types stay on the stack for the fall-through
    567            * path; they are required to be present (and re-supplied) on the
    568            * taken path. */
    569           wasm_branch_label_types(&control[ncontrol - 1u - (uint32_t)in->imm],
    570                                   &lt, &nlt);
    571           wasm_stack_pop_vec(c, &stack, control, ncontrol, lt, nlt, "br_if");
    572           wasm_stack_push_vec(c, &stack, lt, nlt);
    573           break;
    574         }
    575         case WASM_INSN_BR_TABLE: {
    576           const WasmValType* lt0;
    577           uint32_t nlt0;
    578           if (in->ntargets == 0)
    579             wasm_error(c, wasm_loc(0, 0), "wasm: br_table without targets");
    580           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    581                          "br_table selector");
    582           for (uint32_t k = 0; k < in->ntargets; ++k)
    583             if (in->targets[k] >= ncontrol - 1u)
    584               wasm_error(c, wasm_loc(0, 0),
    585                          "wasm: br_table depth out of range");
    586           /* All targets must share one label signature (the default's), and
    587            * those values must be on the stack. */
    588           wasm_branch_label_types(
    589               &control[ncontrol - 1u - in->targets[in->ntargets - 1u]], &lt0,
    590               &nlt0);
    591           for (uint32_t k = 0; k < in->ntargets; ++k) {
    592             const WasmValType* lt;
    593             uint32_t nlt;
    594             wasm_branch_label_types(&control[ncontrol - 1u - in->targets[k]],
    595                                     &lt, &nlt);
    596             if (!wasm_valtypes_eq(lt, nlt, lt0, nlt0))
    597               wasm_error(c, wasm_loc(0, 0),
    598                          "wasm: br_table target type mismatch");
    599           }
    600           wasm_stack_pop_vec(c, &stack, control, ncontrol, lt0, nlt0,
    601                              "br_table");
    602           wasm_mark_unreachable(&stack, control, ncontrol);
    603           break;
    604         }
    605         case WASM_INSN_SELECT: {
    606           WasmValType rhs, lhs;
    607           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "select");
    608           if (stack.depth <= control[ncontrol - 1u].height &&
    609               control[ncontrol - 1u].unreachable) {
    610             in->type = WASM_VAL_I32;
    611             break;
    612           }
    613           if (stack.depth < control[ncontrol - 1u].height + 2u)
    614             wasm_error(c, wasm_loc(0, 0), "wasm: operand stack underflow");
    615           rhs = stack.vals[--stack.depth];
    616           lhs = stack.vals[--stack.depth];
    617           if (lhs != rhs)
    618             wasm_error(c, wasm_loc(0, 0), "wasm: select type mismatch");
    619           in->type = (uint8_t)lhs;
    620           wasm_stack_push(c, &stack, lhs);
    621           break;
    622         }
    623         case WASM_INSN_MEMORY_SIZE:
    624           if (in->memidx >= m->nmemories)
    625             wasm_error(c, wasm_loc(0, 0), "wasm: memory.size without memory");
    626           wasm_stack_push(
    627               c, &stack,
    628               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32);
    629           break;
    630         case WASM_INSN_MEMORY_GROW:
    631           if (in->memidx >= m->nmemories)
    632             wasm_error(c, wasm_loc(0, 0), "wasm: memory.grow without memory");
    633           wasm_stack_pop(
    634               c, &stack, control, ncontrol,
    635               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    636               "memory.grow");
    637           wasm_stack_push(
    638               c, &stack,
    639               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32);
    640           break;
    641         case WASM_INSN_ATOMIC_FENCE:
    642           wasm_require_feature(c, m, WASM_FEATURE_THREADS, "threads",
    643                                "atomic.fence");
    644           break;
    645         case WASM_INSN_I32_ATOMIC_LOAD:
    646         case WASM_INSN_I64_ATOMIC_LOAD:
    647         case WASM_INSN_I32_ATOMIC_LOAD8_U:
    648         case WASM_INSN_I32_ATOMIC_LOAD16_U:
    649         case WASM_INSN_I64_ATOMIC_LOAD8_U:
    650         case WASM_INSN_I64_ATOMIC_LOAD16_U:
    651         case WASM_INSN_I64_ATOMIC_LOAD32_U:
    652           wasm_require_feature(c, m, WASM_FEATURE_THREADS, "threads",
    653                                "atomic load");
    654           if (in->memidx >= m->nmemories)
    655             wasm_error(c, wasm_loc(0, 0), "wasm: atomic load without memory");
    656           if (!m->memories[in->memidx].shared)
    657             wasm_error(c, wasm_loc(0, 0),
    658                        "wasm: atomic load requires shared memory");
    659           wasm_validate_memarg(c, in, "atomic");
    660           wasm_stack_pop(
    661               c, &stack, control, ncontrol,
    662               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    663               "atomic load");
    664           wasm_stack_push(c, &stack, wasm_atomic_value_type(in->kind));
    665           break;
    666         case WASM_INSN_I32_ATOMIC_STORE:
    667         case WASM_INSN_I64_ATOMIC_STORE:
    668         case WASM_INSN_I32_ATOMIC_STORE8:
    669         case WASM_INSN_I32_ATOMIC_STORE16:
    670         case WASM_INSN_I64_ATOMIC_STORE8:
    671         case WASM_INSN_I64_ATOMIC_STORE16:
    672         case WASM_INSN_I64_ATOMIC_STORE32:
    673           wasm_require_feature(c, m, WASM_FEATURE_THREADS, "threads",
    674                                "atomic store");
    675           if (in->memidx >= m->nmemories)
    676             wasm_error(c, wasm_loc(0, 0), "wasm: atomic store without memory");
    677           if (!m->memories[in->memidx].shared)
    678             wasm_error(c, wasm_loc(0, 0),
    679                        "wasm: atomic store requires shared memory");
    680           wasm_validate_memarg(c, in, "atomic");
    681           wasm_stack_pop(c, &stack, control, ncontrol,
    682                          wasm_atomic_value_type(in->kind), "atomic store");
    683           wasm_stack_pop(
    684               c, &stack, control, ncontrol,
    685               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    686               "atomic store");
    687           break;
    688         case WASM_INSN_I32_ATOMIC_RMW_ADD:
    689         case WASM_INSN_I64_ATOMIC_RMW_ADD:
    690         case WASM_INSN_I32_ATOMIC_RMW_SUB:
    691         case WASM_INSN_I64_ATOMIC_RMW_SUB:
    692         case WASM_INSN_I32_ATOMIC_RMW_AND:
    693         case WASM_INSN_I64_ATOMIC_RMW_AND:
    694         case WASM_INSN_I32_ATOMIC_RMW_OR:
    695         case WASM_INSN_I64_ATOMIC_RMW_OR:
    696         case WASM_INSN_I32_ATOMIC_RMW_XOR:
    697         case WASM_INSN_I64_ATOMIC_RMW_XOR:
    698         case WASM_INSN_I32_ATOMIC_RMW_XCHG:
    699         case WASM_INSN_I64_ATOMIC_RMW_XCHG:
    700           wasm_require_feature(c, m, WASM_FEATURE_THREADS, "threads",
    701                                "atomic rmw");
    702           if (in->memidx >= m->nmemories)
    703             wasm_error(c, wasm_loc(0, 0), "wasm: atomic rmw without memory");
    704           if (!m->memories[in->memidx].shared)
    705             wasm_error(c, wasm_loc(0, 0),
    706                        "wasm: atomic rmw requires shared memory");
    707           wasm_validate_memarg(c, in, "atomic");
    708           wasm_stack_pop(c, &stack, control, ncontrol,
    709                          wasm_atomic_value_type(in->kind), "atomic rmw");
    710           wasm_stack_pop(
    711               c, &stack, control, ncontrol,
    712               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    713               "atomic rmw");
    714           wasm_stack_push(c, &stack, wasm_atomic_value_type(in->kind));
    715           break;
    716         case WASM_INSN_I32_ATOMIC_RMW_CMPXCHG:
    717         case WASM_INSN_I64_ATOMIC_RMW_CMPXCHG:
    718           wasm_require_feature(c, m, WASM_FEATURE_THREADS, "threads",
    719                                "atomic cmpxchg");
    720           if (in->memidx >= m->nmemories)
    721             wasm_error(c, wasm_loc(0, 0),
    722                        "wasm: atomic cmpxchg without memory");
    723           if (!m->memories[in->memidx].shared)
    724             wasm_error(c, wasm_loc(0, 0),
    725                        "wasm: atomic cmpxchg requires shared memory");
    726           wasm_validate_memarg(c, in, "atomic");
    727           wasm_stack_pop(c, &stack, control, ncontrol,
    728                          wasm_atomic_value_type(in->kind), "atomic cmpxchg");
    729           wasm_stack_pop(c, &stack, control, ncontrol,
    730                          wasm_atomic_value_type(in->kind), "atomic cmpxchg");
    731           wasm_stack_pop(
    732               c, &stack, control, ncontrol,
    733               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    734               "atomic cmpxchg");
    735           wasm_stack_push(c, &stack, wasm_atomic_value_type(in->kind));
    736           break;
    737         case WASM_INSN_I32_ATOMIC_WAIT:
    738         case WASM_INSN_I64_ATOMIC_WAIT:
    739           wasm_require_feature(c, m, WASM_FEATURE_THREADS, "threads",
    740                                "atomic wait");
    741           if (in->memidx >= m->nmemories)
    742             wasm_error(c, wasm_loc(0, 0), "wasm: atomic wait without memory");
    743           if (!m->memories[in->memidx].shared)
    744             wasm_error(c, wasm_loc(0, 0),
    745                        "wasm: atomic wait requires shared memory");
    746           wasm_validate_memarg(c, in, "atomic");
    747           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I64,
    748                          "atomic wait timeout");
    749           wasm_stack_pop(c, &stack, control, ncontrol,
    750                          wasm_atomic_value_type(in->kind),
    751                          "atomic wait expected");
    752           wasm_stack_pop(
    753               c, &stack, control, ncontrol,
    754               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    755               "atomic wait address");
    756           wasm_stack_push(c, &stack, WASM_VAL_I32);
    757           break;
    758         case WASM_INSN_MEMORY_ATOMIC_NOTIFY:
    759           wasm_require_feature(c, m, WASM_FEATURE_THREADS, "threads",
    760                                "atomic notify");
    761           if (in->memidx >= m->nmemories)
    762             wasm_error(c, wasm_loc(0, 0), "wasm: atomic notify without memory");
    763           if (!m->memories[in->memidx].shared)
    764             wasm_error(c, wasm_loc(0, 0),
    765                        "wasm: atomic notify requires shared memory");
    766           wasm_validate_memarg(c, in, "atomic");
    767           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    768                          "atomic notify count");
    769           wasm_stack_pop(
    770               c, &stack, control, ncontrol,
    771               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    772               "atomic notify address");
    773           wasm_stack_push(c, &stack, WASM_VAL_I32);
    774           break;
    775         case WASM_INSN_I32_LOAD:
    776         case WASM_INSN_I64_LOAD:
    777         case WASM_INSN_F32_LOAD:
    778         case WASM_INSN_F64_LOAD:
    779         case WASM_INSN_I32_LOAD8_S:
    780         case WASM_INSN_I32_LOAD8_U:
    781         case WASM_INSN_I32_LOAD16_S:
    782         case WASM_INSN_I32_LOAD16_U:
    783         case WASM_INSN_I64_LOAD8_S:
    784         case WASM_INSN_I64_LOAD8_U:
    785         case WASM_INSN_I64_LOAD16_S:
    786         case WASM_INSN_I64_LOAD16_U:
    787         case WASM_INSN_I64_LOAD32_S:
    788         case WASM_INSN_I64_LOAD32_U:
    789           if (in->memidx >= m->nmemories)
    790             wasm_error(c, wasm_loc(0, 0), "wasm: load without memory");
    791           wasm_validate_memarg(c, in, "load");
    792           wasm_stack_pop(
    793               c, &stack, control, ncontrol,
    794               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    795               "load");
    796           wasm_stack_push(c, &stack, wasm_load_result_type(in->kind));
    797           break;
    798         case WASM_INSN_I32_STORE:
    799         case WASM_INSN_I64_STORE:
    800         case WASM_INSN_F32_STORE:
    801         case WASM_INSN_F64_STORE:
    802         case WASM_INSN_I32_STORE8:
    803         case WASM_INSN_I32_STORE16:
    804         case WASM_INSN_I64_STORE8:
    805         case WASM_INSN_I64_STORE16:
    806         case WASM_INSN_I64_STORE32:
    807           if (in->memidx >= m->nmemories)
    808             wasm_error(c, wasm_loc(0, 0), "wasm: store without memory");
    809           wasm_validate_memarg(c, in, "store");
    810           wasm_stack_pop(c, &stack, control, ncontrol,
    811                          wasm_store_value_type(in->kind), "store");
    812           wasm_stack_pop(
    813               c, &stack, control, ncontrol,
    814               m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32,
    815               "store");
    816           break;
    817         case WASM_INSN_UNREACHABLE:
    818           wasm_mark_unreachable(&stack, control, ncontrol);
    819           break;
    820         case WASM_INSN_NOP:
    821           break;
    822         case WASM_INSN_MEMORY_COPY: {
    823           WasmValType dst_vt, src_vt;
    824           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    825                                "memory.copy");
    826           if (in->memidx >= m->nmemories || in->aux_idx >= m->nmemories)
    827             wasm_error(c, wasm_loc(0, 0),
    828                        "wasm: memory.copy memory index out of range");
    829           dst_vt = m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32;
    830           src_vt = m->memories[in->aux_idx].is64 ? WASM_VAL_I64 : WASM_VAL_I32;
    831           wasm_stack_pop(c, &stack, control, ncontrol, dst_vt, "memory.copy n");
    832           wasm_stack_pop(c, &stack, control, ncontrol, src_vt,
    833                          "memory.copy src");
    834           wasm_stack_pop(c, &stack, control, ncontrol, dst_vt,
    835                          "memory.copy dst");
    836           break;
    837         }
    838         case WASM_INSN_MEMORY_FILL: {
    839           WasmValType vt;
    840           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    841                                "memory.fill");
    842           if (in->memidx >= m->nmemories)
    843             wasm_error(c, wasm_loc(0, 0),
    844                        "wasm: memory.fill memory index out of range");
    845           vt = m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32;
    846           wasm_stack_pop(c, &stack, control, ncontrol, vt, "memory.fill n");
    847           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    848                          "memory.fill value");
    849           wasm_stack_pop(c, &stack, control, ncontrol, vt, "memory.fill dst");
    850           break;
    851         }
    852         case WASM_INSN_MEMORY_INIT: {
    853           WasmValType vt;
    854           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    855                                "memory.init");
    856           if (in->imm < 0 || (uint64_t)in->imm >= m->ndata)
    857             wasm_error(c, wasm_loc(0, 0),
    858                        "wasm: memory.init data index out of range");
    859           if (m->data[in->imm].mode != WASM_SEG_PASSIVE)
    860             wasm_error(c, wasm_loc(0, 0),
    861                        "wasm: memory.init requires passive data segment");
    862           if (in->memidx >= m->nmemories)
    863             wasm_error(c, wasm_loc(0, 0),
    864                        "wasm: memory.init memory index out of range");
    865           vt = m->memories[in->memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32;
    866           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    867                          "memory.init n");
    868           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    869                          "memory.init src");
    870           wasm_stack_pop(c, &stack, control, ncontrol, vt, "memory.init dst");
    871           break;
    872         }
    873         case WASM_INSN_DATA_DROP:
    874           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    875                                "data.drop");
    876           if (in->imm < 0 || (uint64_t)in->imm >= m->ndata)
    877             wasm_error(c, wasm_loc(0, 0),
    878                        "wasm: data.drop data index out of range");
    879           if (m->data[in->imm].mode != WASM_SEG_PASSIVE)
    880             wasm_error(c, wasm_loc(0, 0),
    881                        "wasm: data.drop requires passive data segment");
    882           break;
    883         case WASM_INSN_TABLE_COPY:
    884           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    885                                "table.copy");
    886           if (in->imm < 0 || (uint64_t)in->imm >= m->ntables ||
    887               in->aux_idx >= m->ntables)
    888             wasm_error(c, wasm_loc(0, 0),
    889                        "wasm: table.copy table index out of range");
    890           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    891                          "table.copy n");
    892           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    893                          "table.copy src");
    894           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    895                          "table.copy dst");
    896           break;
    897         case WASM_INSN_TABLE_INIT:
    898           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    899                                "table.init");
    900           if (in->imm < 0 || (uint64_t)in->imm >= m->nelems)
    901             wasm_error(c, wasm_loc(0, 0),
    902                        "wasm: table.init elem index out of range");
    903           if (m->elems[in->imm].mode != WASM_SEG_PASSIVE)
    904             wasm_error(c, wasm_loc(0, 0),
    905                        "wasm: table.init requires passive element segment");
    906           if (in->aux_idx >= m->ntables)
    907             wasm_error(c, wasm_loc(0, 0),
    908                        "wasm: table.init table index out of range");
    909           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    910                          "table.init n");
    911           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    912                          "table.init src");
    913           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    914                          "table.init dst");
    915           break;
    916         case WASM_INSN_ELEM_DROP:
    917           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    918                                "elem.drop");
    919           if (in->imm < 0 || (uint64_t)in->imm >= m->nelems)
    920             wasm_error(c, wasm_loc(0, 0),
    921                        "wasm: elem.drop elem index out of range");
    922           if (m->elems[in->imm].mode != WASM_SEG_PASSIVE)
    923             wasm_error(c, wasm_loc(0, 0),
    924                        "wasm: elem.drop requires passive element segment");
    925           break;
    926         case WASM_INSN_TABLE_SIZE:
    927           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    928                                "table.size");
    929           if (in->imm < 0 || (uint64_t)in->imm >= m->ntables)
    930             wasm_error(c, wasm_loc(0, 0),
    931                        "wasm: table.size table index out of range");
    932           wasm_stack_push(c, &stack, WASM_VAL_I32);
    933           break;
    934         case WASM_INSN_TABLE_GROW:
    935           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    936                                "table.grow");
    937           if (in->imm < 0 || (uint64_t)in->imm >= m->ntables)
    938             wasm_error(c, wasm_loc(0, 0),
    939                        "wasm: table.grow table index out of range");
    940           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    941                          "table.grow delta");
    942           wasm_stack_pop_ref(c, &stack, control, ncontrol, "table.grow value");
    943           wasm_stack_push(c, &stack, WASM_VAL_I32);
    944           break;
    945         case WASM_INSN_TABLE_FILL:
    946           wasm_require_feature(c, m, WASM_FEATURE_BULK_MEMORY, "bulk memory",
    947                                "table.fill");
    948           if (in->imm < 0 || (uint64_t)in->imm >= m->ntables)
    949             wasm_error(c, wasm_loc(0, 0),
    950                        "wasm: table.fill table index out of range");
    951           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    952                          "table.fill n");
    953           wasm_stack_pop_ref(c, &stack, control, ncontrol, "table.fill value");
    954           wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32,
    955                          "table.fill dst");
    956           break;
    957         case WASM_INSN_I32_TRUNC_SAT_F32_S:
    958         case WASM_INSN_I32_TRUNC_SAT_F64_S:
    959         case WASM_INSN_I32_TRUNC_SAT_F32_U:
    960         case WASM_INSN_I32_TRUNC_SAT_F64_U:
    961         case WASM_INSN_I64_TRUNC_SAT_F32_S:
    962         case WASM_INSN_I64_TRUNC_SAT_F64_S:
    963         case WASM_INSN_I64_TRUNC_SAT_F32_U:
    964         case WASM_INSN_I64_TRUNC_SAT_F64_U: {
    965           WasmValType sat_src = (in->kind == WASM_INSN_I32_TRUNC_SAT_F32_S ||
    966                                  in->kind == WASM_INSN_I32_TRUNC_SAT_F32_U ||
    967                                  in->kind == WASM_INSN_I64_TRUNC_SAT_F32_S ||
    968                                  in->kind == WASM_INSN_I64_TRUNC_SAT_F32_U)
    969                                     ? WASM_VAL_F32
    970                                     : WASM_VAL_F64;
    971           WasmValType sat_dst = (in->kind == WASM_INSN_I32_TRUNC_SAT_F32_S ||
    972                                  in->kind == WASM_INSN_I32_TRUNC_SAT_F32_U ||
    973                                  in->kind == WASM_INSN_I32_TRUNC_SAT_F64_S ||
    974                                  in->kind == WASM_INSN_I32_TRUNC_SAT_F64_U)
    975                                     ? WASM_VAL_I32
    976                                     : WASM_VAL_I64;
    977           wasm_require_feature(c, m, WASM_FEATURE_NONTRAPPING_FTOI,
    978                                "non-trapping float-to-int", "trunc_sat");
    979           wasm_stack_pop(c, &stack, control, ncontrol, sat_src, "trunc_sat");
    980           wasm_stack_push(c, &stack, sat_dst);
    981           break;
    982         }
    983         default:
    984           if (wasm_int_unop_kind(in->kind, &vt)) {
    985             wasm_stack_pop(c, &stack, control, ncontrol, vt, "unary operand");
    986             wasm_stack_push(c, &stack, vt);
    987             break;
    988           }
    989           if (wasm_fp_unop_kind(in->kind, &vt)) {
    990             wasm_stack_pop(c, &stack, control, ncontrol, vt,
    991                            "fp unary operand");
    992             wasm_stack_push(c, &stack, vt);
    993             break;
    994           }
    995           if (wasm_fp_binop_kind(in->kind, &vt)) {
    996             wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp operand");
    997             wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp operand");
    998             wasm_stack_push(c, &stack, vt);
    999             break;
   1000           }
   1001           if (wasm_fp_cmp_kind(in->kind, &vt)) {
   1002             wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp compare");
   1003             wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp compare");
   1004             wasm_stack_push(c, &stack, WASM_VAL_I32);
   1005             break;
   1006           }
   1007           if (wasm_conversion_kind(in->kind, &src, &dst)) {
   1008             wasm_stack_pop(c, &stack, control, ncontrol, src, "conversion");
   1009             wasm_stack_push(c, &stack, dst);
   1010             break;
   1011           }
   1012           {
   1013             KitCgIntCmpOp cmp;
   1014             WasmValType rhs, lhs;
   1015             rhs = stack.depth > control[ncontrol - 1u].height
   1016                       ? stack.vals[stack.depth - 1u]
   1017                       : WASM_VAL_I32;
   1018             wasm_stack_pop(c, &stack, control, ncontrol, 0, "operand");
   1019             lhs = stack.depth > control[ncontrol - 1u].height
   1020                       ? stack.vals[stack.depth - 1u]
   1021                       : rhs;
   1022             wasm_stack_pop(c, &stack, control, ncontrol, rhs, "operand");
   1023             if (lhs != rhs)
   1024               wasm_error(
   1025                   c, wasm_loc(0, 0),
   1026                   "wasm: operand type mismatch (kind=0x%x lhs=0x%x rhs=0x%x)",
   1027                   (unsigned)in->kind, (unsigned)lhs, (unsigned)rhs);
   1028             wasm_stack_push(
   1029                 c, &stack,
   1030                 wasm_int_cmp_op(in->kind, &cmp) ? WASM_VAL_I32 : lhs);
   1031             break;
   1032           }
   1033 #undef wasm_loc
   1034       }
   1035     }
   1036     if (ncontrol != 1u)
   1037       wasm_error(c, wasm_loc(0, 0), "wasm: unterminated control block");
   1038     if (!control[0].unreachable) {
   1039       if (stack.depth != f->nresults)
   1040         wasm_error(c, wasm_loc(0, 0), "wasm: function result count mismatch");
   1041       for (j = 0; j < f->nresults; ++j)
   1042         if (stack.vals[j] != f->results[j])
   1043           wasm_error(c, wasm_loc(0, 0), "wasm: function result type mismatch");
   1044     }
   1045   }
   1046   m->heap->free(m->heap, control, sizeof(WasmControlFrame) * control_cap);
   1047 }