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 <, &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 <, &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]], <0, 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 <, &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 }