kit

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

validate.c (41965B)


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