1// Copyright 2017 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#if !V8_ENABLE_WEBASSEMBLY 6#error This header should only be included if WebAssembly is enabled. 7#endif // !V8_ENABLE_WEBASSEMBLY 8 9#ifndef V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_ 10#define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_ 11 12// Do only include this header for implementing new Interface of the 13// WasmFullDecoder. 14 15#include <inttypes.h> 16 17#include "src/base/platform/elapsed-timer.h" 18#include "src/base/platform/wrappers.h" 19#include "src/base/small-vector.h" 20#include "src/base/strings.h" 21#include "src/utils/bit-vector.h" 22#include "src/wasm/decoder.h" 23#include "src/wasm/function-body-decoder.h" 24#include "src/wasm/value-type.h" 25#include "src/wasm/wasm-features.h" 26#include "src/wasm/wasm-limits.h" 27#include "src/wasm/wasm-module.h" 28#include "src/wasm/wasm-opcodes.h" 29#include "src/wasm/wasm-subtyping.h" 30 31namespace v8 { 32namespace internal { 33namespace wasm { 34 35struct WasmGlobal; 36struct WasmTag; 37 38#define TRACE(...) \ 39 do { \ 40 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 41 } while (false) 42 43#define TRACE_INST_FORMAT " @%-8d #%-30s|" 44 45// Return the evaluation of `condition` if validate==true, DCHECK that it's 46// true and always return true otherwise. 47#define VALIDATE(condition) \ 48 (validate ? V8_LIKELY(condition) : [&] { \ 49 DCHECK(condition); \ 50 return true; \ 51 }()) 52 53#define CHECK_PROTOTYPE_OPCODE(feat) \ 54 DCHECK(this->module_->origin == kWasmOrigin); \ 55 if (!VALIDATE(this->enabled_.has_##feat())) { \ 56 this->DecodeError( \ 57 "Invalid opcode 0x%02x (enable with --experimental-wasm-" #feat ")", \ 58 opcode); \ 59 return 0; \ 60 } \ 61 this->detected_->Add(kFeature_##feat); 62 63#define ATOMIC_OP_LIST(V) \ 64 V(AtomicNotify, Uint32) \ 65 V(I32AtomicWait, Uint32) \ 66 V(I64AtomicWait, Uint64) \ 67 V(I32AtomicLoad, Uint32) \ 68 V(I64AtomicLoad, Uint64) \ 69 V(I32AtomicLoad8U, Uint8) \ 70 V(I32AtomicLoad16U, Uint16) \ 71 V(I64AtomicLoad8U, Uint8) \ 72 V(I64AtomicLoad16U, Uint16) \ 73 V(I64AtomicLoad32U, Uint32) \ 74 V(I32AtomicAdd, Uint32) \ 75 V(I32AtomicAdd8U, Uint8) \ 76 V(I32AtomicAdd16U, Uint16) \ 77 V(I64AtomicAdd, Uint64) \ 78 V(I64AtomicAdd8U, Uint8) \ 79 V(I64AtomicAdd16U, Uint16) \ 80 V(I64AtomicAdd32U, Uint32) \ 81 V(I32AtomicSub, Uint32) \ 82 V(I64AtomicSub, Uint64) \ 83 V(I32AtomicSub8U, Uint8) \ 84 V(I32AtomicSub16U, Uint16) \ 85 V(I64AtomicSub8U, Uint8) \ 86 V(I64AtomicSub16U, Uint16) \ 87 V(I64AtomicSub32U, Uint32) \ 88 V(I32AtomicAnd, Uint32) \ 89 V(I64AtomicAnd, Uint64) \ 90 V(I32AtomicAnd8U, Uint8) \ 91 V(I32AtomicAnd16U, Uint16) \ 92 V(I64AtomicAnd8U, Uint8) \ 93 V(I64AtomicAnd16U, Uint16) \ 94 V(I64AtomicAnd32U, Uint32) \ 95 V(I32AtomicOr, Uint32) \ 96 V(I64AtomicOr, Uint64) \ 97 V(I32AtomicOr8U, Uint8) \ 98 V(I32AtomicOr16U, Uint16) \ 99 V(I64AtomicOr8U, Uint8) \ 100 V(I64AtomicOr16U, Uint16) \ 101 V(I64AtomicOr32U, Uint32) \ 102 V(I32AtomicXor, Uint32) \ 103 V(I64AtomicXor, Uint64) \ 104 V(I32AtomicXor8U, Uint8) \ 105 V(I32AtomicXor16U, Uint16) \ 106 V(I64AtomicXor8U, Uint8) \ 107 V(I64AtomicXor16U, Uint16) \ 108 V(I64AtomicXor32U, Uint32) \ 109 V(I32AtomicExchange, Uint32) \ 110 V(I64AtomicExchange, Uint64) \ 111 V(I32AtomicExchange8U, Uint8) \ 112 V(I32AtomicExchange16U, Uint16) \ 113 V(I64AtomicExchange8U, Uint8) \ 114 V(I64AtomicExchange16U, Uint16) \ 115 V(I64AtomicExchange32U, Uint32) \ 116 V(I32AtomicCompareExchange, Uint32) \ 117 V(I64AtomicCompareExchange, Uint64) \ 118 V(I32AtomicCompareExchange8U, Uint8) \ 119 V(I32AtomicCompareExchange16U, Uint16) \ 120 V(I64AtomicCompareExchange8U, Uint8) \ 121 V(I64AtomicCompareExchange16U, Uint16) \ 122 V(I64AtomicCompareExchange32U, Uint32) 123 124#define ATOMIC_STORE_OP_LIST(V) \ 125 V(I32AtomicStore, Uint32) \ 126 V(I64AtomicStore, Uint64) \ 127 V(I32AtomicStore8U, Uint8) \ 128 V(I32AtomicStore16U, Uint16) \ 129 V(I64AtomicStore8U, Uint8) \ 130 V(I64AtomicStore16U, Uint16) \ 131 V(I64AtomicStore32U, Uint32) 132 133// Decoder error with explicit PC and format arguments. 134template <Decoder::ValidateFlag validate, typename... Args> 135void DecodeError(Decoder* decoder, const byte* pc, const char* str, 136 Args&&... args) { 137 CHECK(validate == Decoder::kFullValidation || 138 validate == Decoder::kBooleanValidation); 139 STATIC_ASSERT(sizeof...(Args) > 0); 140 if (validate == Decoder::kBooleanValidation) { 141 decoder->MarkError(); 142 } else { 143 decoder->errorf(pc, str, std::forward<Args>(args)...); 144 } 145} 146 147// Decoder error with explicit PC and no format arguments. 148template <Decoder::ValidateFlag validate> 149void DecodeError(Decoder* decoder, const byte* pc, const char* str) { 150 CHECK(validate == Decoder::kFullValidation || 151 validate == Decoder::kBooleanValidation); 152 if (validate == Decoder::kBooleanValidation) { 153 decoder->MarkError(); 154 } else { 155 decoder->error(pc, str); 156 } 157} 158 159// Decoder error without explicit PC, but with format arguments. 160template <Decoder::ValidateFlag validate, typename... Args> 161void DecodeError(Decoder* decoder, const char* str, Args&&... args) { 162 CHECK(validate == Decoder::kFullValidation || 163 validate == Decoder::kBooleanValidation); 164 STATIC_ASSERT(sizeof...(Args) > 0); 165 if (validate == Decoder::kBooleanValidation) { 166 decoder->MarkError(); 167 } else { 168 decoder->errorf(str, std::forward<Args>(args)...); 169 } 170} 171 172// Decoder error without explicit PC and without format arguments. 173template <Decoder::ValidateFlag validate> 174void DecodeError(Decoder* decoder, const char* str) { 175 CHECK(validate == Decoder::kFullValidation || 176 validate == Decoder::kBooleanValidation); 177 if (validate == Decoder::kBooleanValidation) { 178 decoder->MarkError(); 179 } else { 180 decoder->error(str); 181 } 182} 183 184namespace value_type_reader { 185 186// If {module} is not null, the read index will be checked against the module's 187// type capacity. 188template <Decoder::ValidateFlag validate> 189HeapType read_heap_type(Decoder* decoder, const byte* pc, 190 uint32_t* const length, const WasmModule* module, 191 const WasmFeatures& enabled) { 192 int64_t heap_index = decoder->read_i33v<validate>(pc, length, "heap type"); 193 if (heap_index < 0) { 194 int64_t min_1_byte_leb128 = -64; 195 if (!VALIDATE(heap_index >= min_1_byte_leb128)) { 196 DecodeError<validate>(decoder, pc, "Unknown heap type %" PRId64, 197 heap_index); 198 return HeapType(HeapType::kBottom); 199 } 200 uint8_t uint_7_mask = 0x7F; 201 uint8_t code = static_cast<ValueTypeCode>(heap_index) & uint_7_mask; 202 switch (code) { 203 case kEqRefCode: 204 case kI31RefCode: 205 case kDataRefCode: 206 case kArrayRefCode: 207 case kAnyRefCodeAlias: 208 if (!VALIDATE(enabled.has_gc())) { 209 DecodeError<validate>( 210 decoder, pc, 211 "invalid heap type '%s', enable with --experimental-wasm-gc", 212 HeapType::from_code(code).name().c_str()); 213 return HeapType(HeapType::kBottom); 214 } 215 V8_FALLTHROUGH; 216 case kAnyRefCode: 217 case kFuncRefCode: 218 return HeapType::from_code(code); 219 default: 220 DecodeError<validate>(decoder, pc, "Unknown heap type %" PRId64, 221 heap_index); 222 return HeapType(HeapType::kBottom); 223 } 224 } else { 225 if (!VALIDATE(enabled.has_typed_funcref())) { 226 DecodeError<validate>(decoder, pc, 227 "Invalid indexed heap type, enable with " 228 "--experimental-wasm-typed-funcref"); 229 return HeapType(HeapType::kBottom); 230 } 231 uint32_t type_index = static_cast<uint32_t>(heap_index); 232 if (!VALIDATE(type_index < kV8MaxWasmTypes)) { 233 DecodeError<validate>( 234 decoder, pc, 235 "Type index %u is greater than the maximum number %zu " 236 "of type definitions supported by V8", 237 type_index, kV8MaxWasmTypes); 238 return HeapType(HeapType::kBottom); 239 } 240 // We use capacity over size so this works mid-DecodeTypeSection. 241 if (!VALIDATE(module == nullptr || type_index < module->types.capacity())) { 242 DecodeError<validate>(decoder, pc, "Type index %u is out of bounds", 243 type_index); 244 return HeapType(HeapType::kBottom); 245 } 246 return HeapType(type_index); 247 } 248} 249 250HeapType consume_heap_type(Decoder* decoder, const WasmModule* module, 251 const WasmFeatures& enabled); 252 253// Read a value type starting at address {pc} using {decoder}. 254// No bytes are consumed. 255// The length of the read value type is written in {length}. 256// Registers an error for an invalid type only if {validate} is not 257// kNoValidate. 258template <Decoder::ValidateFlag validate> 259ValueType read_value_type(Decoder* decoder, const byte* pc, 260 uint32_t* const length, const WasmModule* module, 261 const WasmFeatures& enabled) { 262 *length = 1; 263 byte val = decoder->read_u8<validate>(pc, "value type opcode"); 264 if (decoder->failed()) { 265 *length = 0; 266 return kWasmBottom; 267 } 268 ValueTypeCode code = static_cast<ValueTypeCode>(val); 269 switch (code) { 270 case kEqRefCode: 271 case kI31RefCode: 272 case kDataRefCode: 273 case kArrayRefCode: 274 case kAnyRefCodeAlias: 275 if (!VALIDATE(enabled.has_gc())) { 276 DecodeError<validate>( 277 decoder, pc, 278 "invalid value type '%sref', enable with --experimental-wasm-gc", 279 HeapType::from_code(code).name().c_str()); 280 return kWasmBottom; 281 } 282 V8_FALLTHROUGH; 283 case kAnyRefCode: 284 case kFuncRefCode: { 285 HeapType heap_type = HeapType::from_code(code); 286 Nullability nullability = 287 code == kI31RefCode || code == kDataRefCode || code == kArrayRefCode 288 ? kNonNullable 289 : kNullable; 290 return ValueType::Ref(heap_type, nullability); 291 } 292 case kI32Code: 293 return kWasmI32; 294 case kI64Code: 295 return kWasmI64; 296 case kF32Code: 297 return kWasmF32; 298 case kF64Code: 299 return kWasmF64; 300 case kRefCode: 301 case kOptRefCode: { 302 Nullability nullability = code == kOptRefCode ? kNullable : kNonNullable; 303 if (!VALIDATE(enabled.has_typed_funcref())) { 304 DecodeError<validate>(decoder, pc, 305 "Invalid type '(ref%s <heaptype>)', enable with " 306 "--experimental-wasm-typed-funcref", 307 nullability == kNullable ? " null" : ""); 308 return kWasmBottom; 309 } 310 HeapType heap_type = 311 read_heap_type<validate>(decoder, pc + 1, length, module, enabled); 312 *length += 1; 313 return heap_type.is_bottom() ? kWasmBottom 314 : ValueType::Ref(heap_type, nullability); 315 } 316 // TODO(7748): This is here only for backwards compatibility, and the parsed 317 // depth is ignored. 318 case kRttWithDepthCode: 319 case kRttCode: { 320 if (!VALIDATE(enabled.has_gc())) { 321 DecodeError<validate>( 322 decoder, pc, 323 "invalid value type 'rtt', enable with --experimental-wasm-gc"); 324 return kWasmBottom; 325 } 326 if (code == kRttWithDepthCode) { 327 uint32_t depth = decoder->read_u32v<validate>(pc + 1, length, "depth"); 328 *length += 1; 329 if (!VALIDATE(depth <= kV8MaxRttSubtypingDepth)) { 330 DecodeError<validate>( 331 decoder, pc, 332 "subtyping depth %u is greater than the maximum depth " 333 "%u supported by V8", 334 depth, kV8MaxRttSubtypingDepth); 335 return kWasmBottom; 336 } 337 } 338 uint32_t type_index_length; 339 uint32_t type_index = 340 decoder->read_u32v<validate>(pc + *length, &type_index_length); 341 *length += type_index_length; 342 if (!VALIDATE(type_index < kV8MaxWasmTypes)) { 343 DecodeError<validate>( 344 decoder, pc, 345 "Type index %u is greater than the maximum number %zu " 346 "of type definitions supported by V8", 347 type_index, kV8MaxWasmTypes); 348 return kWasmBottom; 349 } 350 // We use capacity over size so this works mid-DecodeTypeSection. 351 if (!VALIDATE(module == nullptr || 352 type_index < module->types.capacity())) { 353 DecodeError<validate>(decoder, pc, "Type index %u is out of bounds", 354 type_index); 355 return kWasmBottom; 356 } 357 return ValueType::Rtt(type_index); 358 } 359 case kS128Code: { 360 if (!VALIDATE(enabled.has_simd())) { 361 DecodeError<validate>( 362 decoder, pc, 363 "invalid value type 's128', enable with --experimental-wasm-simd"); 364 return kWasmBottom; 365 } 366 if (!VALIDATE(CheckHardwareSupportsSimd())) { 367 DecodeError<validate>(decoder, pc, "Wasm SIMD unsupported"); 368 return kWasmBottom; 369 } 370 return kWasmS128; 371 } 372 // Although these codes are included in ValueTypeCode, they technically 373 // do not correspond to value types and are only used in specific 374 // contexts. The caller of this function is responsible for handling them. 375 case kVoidCode: 376 case kI8Code: 377 case kI16Code: 378 if (validate) { 379 DecodeError<validate>(decoder, pc, "invalid value type 0x%x", code); 380 } 381 return kWasmBottom; 382 } 383 // Anything that doesn't match an enumeration value is an invalid type code. 384 if (validate) { 385 DecodeError<validate>(decoder, pc, "invalid value type 0x%x", code); 386 } 387 return kWasmBottom; 388} 389} // namespace value_type_reader 390 391enum DecodingMode { kFunctionBody, kInitExpression }; 392 393// Helpers for decoding different kinds of immediates which follow bytecodes. 394template <Decoder::ValidateFlag validate> 395struct ImmI32Immediate { 396 int32_t value; 397 uint32_t length; 398 ImmI32Immediate(Decoder* decoder, const byte* pc) { 399 value = decoder->read_i32v<validate>(pc, &length, "immi32"); 400 } 401}; 402 403template <Decoder::ValidateFlag validate> 404struct ImmI64Immediate { 405 int64_t value; 406 uint32_t length; 407 ImmI64Immediate(Decoder* decoder, const byte* pc) { 408 value = decoder->read_i64v<validate>(pc, &length, "immi64"); 409 } 410}; 411 412template <Decoder::ValidateFlag validate> 413struct ImmF32Immediate { 414 float value; 415 uint32_t length = 4; 416 ImmF32Immediate(Decoder* decoder, const byte* pc) { 417 // We can't use bit_cast here because calling any helper function that 418 // returns a float would potentially flip NaN bits per C++ semantics, so we 419 // have to inline the memcpy call directly. 420 uint32_t tmp = decoder->read_u32<validate>(pc, "immf32"); 421 memcpy(&value, &tmp, sizeof(value)); 422 } 423}; 424 425template <Decoder::ValidateFlag validate> 426struct ImmF64Immediate { 427 double value; 428 uint32_t length = 8; 429 ImmF64Immediate(Decoder* decoder, const byte* pc) { 430 // Avoid bit_cast because it might not preserve the signalling bit of a NaN. 431 uint64_t tmp = decoder->read_u64<validate>(pc, "immf64"); 432 memcpy(&value, &tmp, sizeof(value)); 433 } 434}; 435 436// This is different than IndexImmediate because {index} is a byte. 437template <Decoder::ValidateFlag validate> 438struct MemoryIndexImmediate { 439 uint8_t index = 0; 440 uint32_t length = 1; 441 MemoryIndexImmediate(Decoder* decoder, const byte* pc) { 442 index = decoder->read_u8<validate>(pc, "memory index"); 443 } 444}; 445 446// Parent class for all Immediates which read a u32v index value in their 447// constructor. 448template <Decoder::ValidateFlag validate> 449struct IndexImmediate { 450 uint32_t index; 451 uint32_t length; 452 453 IndexImmediate(Decoder* decoder, const byte* pc, const char* name) { 454 index = decoder->read_u32v<validate>(pc, &length, name); 455 } 456}; 457 458template <Decoder::ValidateFlag validate> 459struct TagIndexImmediate : public IndexImmediate<validate> { 460 const WasmTag* tag = nullptr; 461 462 TagIndexImmediate(Decoder* decoder, const byte* pc) 463 : IndexImmediate<validate>(decoder, pc, "tag index") {} 464}; 465 466template <Decoder::ValidateFlag validate> 467struct GlobalIndexImmediate : public IndexImmediate<validate> { 468 const WasmGlobal* global = nullptr; 469 470 GlobalIndexImmediate(Decoder* decoder, const byte* pc) 471 : IndexImmediate<validate>(decoder, pc, "global index") {} 472}; 473 474template <Decoder::ValidateFlag validate> 475struct StructIndexImmediate : public IndexImmediate<validate> { 476 const StructType* struct_type = nullptr; 477 478 StructIndexImmediate(Decoder* decoder, const byte* pc) 479 : IndexImmediate<validate>(decoder, pc, "struct index") {} 480}; 481 482template <Decoder::ValidateFlag validate> 483struct ArrayIndexImmediate : public IndexImmediate<validate> { 484 const ArrayType* array_type = nullptr; 485 486 ArrayIndexImmediate(Decoder* decoder, const byte* pc) 487 : IndexImmediate<validate>(decoder, pc, "array index") {} 488}; 489template <Decoder::ValidateFlag validate> 490struct CallFunctionImmediate : public IndexImmediate<validate> { 491 const FunctionSig* sig = nullptr; 492 493 CallFunctionImmediate(Decoder* decoder, const byte* pc) 494 : IndexImmediate<validate>(decoder, pc, "function index") {} 495}; 496 497template <Decoder::ValidateFlag validate> 498struct SelectTypeImmediate { 499 uint32_t length; 500 ValueType type; 501 502 SelectTypeImmediate(const WasmFeatures& enabled, Decoder* decoder, 503 const byte* pc, const WasmModule* module) { 504 uint8_t num_types = 505 decoder->read_u32v<validate>(pc, &length, "number of select types"); 506 if (!VALIDATE(num_types == 1)) { 507 DecodeError<validate>( 508 decoder, pc + 1, 509 "Invalid number of types. Select accepts exactly one type"); 510 return; 511 } 512 uint32_t type_length; 513 type = value_type_reader::read_value_type<validate>( 514 decoder, pc + length, &type_length, module, enabled); 515 length += type_length; 516 } 517}; 518 519template <Decoder::ValidateFlag validate> 520struct BlockTypeImmediate { 521 uint32_t length = 1; 522 ValueType type = kWasmVoid; 523 uint32_t sig_index = 0; 524 const FunctionSig* sig = nullptr; 525 526 BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder, 527 const byte* pc, const WasmModule* module) { 528 int64_t block_type = 529 decoder->read_i33v<validate>(pc, &length, "block type"); 530 if (block_type < 0) { 531 // All valid negative types are 1 byte in length, so we check against the 532 // minimum 1-byte LEB128 value. 533 constexpr int64_t min_1_byte_leb128 = -64; 534 if (!VALIDATE(block_type >= min_1_byte_leb128)) { 535 DecodeError<validate>(decoder, pc, "invalid block type %" PRId64, 536 block_type); 537 return; 538 } 539 if (static_cast<ValueTypeCode>(block_type & 0x7F) == kVoidCode) return; 540 type = value_type_reader::read_value_type<validate>(decoder, pc, &length, 541 module, enabled); 542 } else { 543 type = kWasmBottom; 544 sig_index = static_cast<uint32_t>(block_type); 545 } 546 } 547 548 uint32_t in_arity() const { 549 if (type != kWasmBottom) return 0; 550 return static_cast<uint32_t>(sig->parameter_count()); 551 } 552 uint32_t out_arity() const { 553 if (type == kWasmVoid) return 0; 554 if (type != kWasmBottom) return 1; 555 return static_cast<uint32_t>(sig->return_count()); 556 } 557 ValueType in_type(uint32_t index) { 558 DCHECK_EQ(kWasmBottom, type); 559 return sig->GetParam(index); 560 } 561 ValueType out_type(uint32_t index) { 562 if (type == kWasmBottom) return sig->GetReturn(index); 563 DCHECK_NE(kWasmVoid, type); 564 DCHECK_EQ(0, index); 565 return type; 566 } 567}; 568 569template <Decoder::ValidateFlag validate> 570struct BranchDepthImmediate { 571 uint32_t depth; 572 uint32_t length; 573 BranchDepthImmediate(Decoder* decoder, const byte* pc) { 574 depth = decoder->read_u32v<validate>(pc, &length, "branch depth"); 575 } 576}; 577 578template <Decoder::ValidateFlag validate> 579struct FieldImmediate { 580 StructIndexImmediate<validate> struct_imm; 581 IndexImmediate<validate> field_imm; 582 uint32_t length; 583 FieldImmediate(Decoder* decoder, const byte* pc) 584 : struct_imm(decoder, pc), 585 field_imm(decoder, pc + struct_imm.length, "field index"), 586 length(struct_imm.length + field_imm.length) {} 587}; 588 589template <Decoder::ValidateFlag validate> 590struct CallIndirectImmediate { 591 IndexImmediate<validate> sig_imm; 592 IndexImmediate<validate> table_imm; 593 uint32_t length; 594 const FunctionSig* sig = nullptr; 595 CallIndirectImmediate(Decoder* decoder, const byte* pc) 596 : sig_imm(decoder, pc, "singature index"), 597 table_imm(decoder, pc + sig_imm.length, "table index"), 598 length(sig_imm.length + table_imm.length) {} 599}; 600 601template <Decoder::ValidateFlag validate> 602struct BranchTableImmediate { 603 uint32_t table_count; 604 const byte* start; 605 const byte* table; 606 BranchTableImmediate(Decoder* decoder, const byte* pc) { 607 start = pc; 608 uint32_t len = 0; 609 table_count = decoder->read_u32v<validate>(pc, &len, "table count"); 610 table = pc + len; 611 } 612}; 613 614// A helper to iterate over a branch table. 615template <Decoder::ValidateFlag validate> 616class BranchTableIterator { 617 public: 618 uint32_t cur_index() { return index_; } 619 bool has_next() { return VALIDATE(decoder_->ok()) && index_ <= table_count_; } 620 uint32_t next() { 621 DCHECK(has_next()); 622 index_++; 623 uint32_t length; 624 uint32_t result = 625 decoder_->read_u32v<validate>(pc_, &length, "branch table entry"); 626 pc_ += length; 627 return result; 628 } 629 // length, including the length of the {BranchTableImmediate}, but not the 630 // opcode. 631 uint32_t length() { 632 while (has_next()) next(); 633 return static_cast<uint32_t>(pc_ - start_); 634 } 635 const byte* pc() { return pc_; } 636 637 BranchTableIterator(Decoder* decoder, 638 const BranchTableImmediate<validate>& imm) 639 : decoder_(decoder), 640 start_(imm.start), 641 pc_(imm.table), 642 table_count_(imm.table_count) {} 643 644 private: 645 Decoder* const decoder_; 646 const byte* start_; 647 const byte* pc_; 648 uint32_t index_ = 0; // the current index. 649 const uint32_t table_count_; // the count of entries, not including default. 650}; 651 652template <Decoder::ValidateFlag validate, 653 DecodingMode decoding_mode = kFunctionBody> 654class WasmDecoder; 655 656template <Decoder::ValidateFlag validate> 657struct MemoryAccessImmediate { 658 uint32_t alignment; 659 uint64_t offset; 660 uint32_t length = 0; 661 MemoryAccessImmediate(Decoder* decoder, const byte* pc, 662 uint32_t max_alignment, bool is_memory64) { 663 uint32_t alignment_length; 664 alignment = 665 decoder->read_u32v<validate>(pc, &alignment_length, "alignment"); 666 if (!VALIDATE(alignment <= max_alignment)) { 667 DecodeError<validate>( 668 decoder, pc, 669 "invalid alignment; expected maximum alignment is %u, " 670 "actual alignment is %u", 671 max_alignment, alignment); 672 } 673 uint32_t offset_length; 674 offset = is_memory64 ? decoder->read_u64v<validate>( 675 pc + alignment_length, &offset_length, "offset") 676 : decoder->read_u32v<validate>( 677 pc + alignment_length, &offset_length, "offset"); 678 length = alignment_length + offset_length; 679 } 680}; 681 682// Immediate for SIMD lane operations. 683template <Decoder::ValidateFlag validate> 684struct SimdLaneImmediate { 685 uint8_t lane; 686 uint32_t length = 1; 687 688 SimdLaneImmediate(Decoder* decoder, const byte* pc) { 689 lane = decoder->read_u8<validate>(pc, "lane"); 690 } 691}; 692 693// Immediate for SIMD S8x16 shuffle operations. 694template <Decoder::ValidateFlag validate> 695struct Simd128Immediate { 696 uint8_t value[kSimd128Size] = {0}; 697 698 Simd128Immediate(Decoder* decoder, const byte* pc) { 699 for (uint32_t i = 0; i < kSimd128Size; ++i) { 700 value[i] = decoder->read_u8<validate>(pc + i, "value"); 701 } 702 } 703}; 704 705template <Decoder::ValidateFlag validate> 706struct MemoryInitImmediate { 707 IndexImmediate<validate> data_segment; 708 MemoryIndexImmediate<validate> memory; 709 uint32_t length; 710 711 MemoryInitImmediate(Decoder* decoder, const byte* pc) 712 : data_segment(decoder, pc, "data segment index"), 713 memory(decoder, pc + data_segment.length), 714 length(data_segment.length + memory.length) {} 715}; 716 717template <Decoder::ValidateFlag validate> 718struct MemoryCopyImmediate { 719 MemoryIndexImmediate<validate> memory_src; 720 MemoryIndexImmediate<validate> memory_dst; 721 uint32_t length; 722 723 MemoryCopyImmediate(Decoder* decoder, const byte* pc) 724 : memory_src(decoder, pc), 725 memory_dst(decoder, pc + memory_src.length), 726 length(memory_src.length + memory_dst.length) {} 727}; 728 729template <Decoder::ValidateFlag validate> 730struct TableInitImmediate { 731 IndexImmediate<validate> element_segment; 732 IndexImmediate<validate> table; 733 uint32_t length; 734 735 TableInitImmediate(Decoder* decoder, const byte* pc) 736 : element_segment(decoder, pc, "element segment index"), 737 table(decoder, pc + element_segment.length, "table index"), 738 length(element_segment.length + table.length) {} 739}; 740 741template <Decoder::ValidateFlag validate> 742struct TableCopyImmediate { 743 IndexImmediate<validate> table_dst; 744 IndexImmediate<validate> table_src; 745 uint32_t length; 746 747 TableCopyImmediate(Decoder* decoder, const byte* pc) 748 : table_dst(decoder, pc, "table index"), 749 table_src(decoder, pc + table_dst.length, "table index"), 750 length(table_src.length + table_dst.length) {} 751}; 752 753template <Decoder::ValidateFlag validate> 754struct HeapTypeImmediate { 755 uint32_t length = 1; 756 HeapType type; 757 HeapTypeImmediate(const WasmFeatures& enabled, Decoder* decoder, 758 const byte* pc, const WasmModule* module) 759 : type(value_type_reader::read_heap_type<validate>(decoder, pc, &length, 760 module, enabled)) {} 761}; 762 763template <Decoder::ValidateFlag validate> 764struct PcForErrors { 765 PcForErrors(const byte* /* pc */) {} 766 767 const byte* pc() const { return nullptr; } 768}; 769 770template <> 771struct PcForErrors<Decoder::kFullValidation> { 772 const byte* pc_for_errors = nullptr; 773 774 PcForErrors(const byte* pc) : pc_for_errors(pc) {} 775 776 const byte* pc() const { return pc_for_errors; } 777}; 778 779// An entry on the value stack. 780template <Decoder::ValidateFlag validate> 781struct ValueBase : public PcForErrors<validate> { 782 ValueType type = kWasmVoid; 783 784 ValueBase(const byte* pc, ValueType type) 785 : PcForErrors<validate>(pc), type(type) {} 786}; 787 788template <typename Value> 789struct Merge { 790 uint32_t arity = 0; 791 union { // Either multiple values or a single value. 792 Value* array; 793 Value first; 794 } vals = {nullptr}; // Initialize {array} with {nullptr}. 795 796 // Tracks whether this merge was ever reached. Uses precise reachability, like 797 // Reachability::kReachable. 798 bool reached; 799 800 explicit Merge(bool reached = false) : reached(reached) {} 801 802 Value& operator[](uint32_t i) { 803 DCHECK_GT(arity, i); 804 return arity == 1 ? vals.first : vals.array[i]; 805 } 806}; 807 808enum ControlKind : uint8_t { 809 kControlIf, 810 kControlIfElse, 811 kControlBlock, 812 kControlLoop, 813 kControlLet, 814 kControlTry, 815 kControlTryCatch, 816 kControlTryCatchAll, 817}; 818 819enum Reachability : uint8_t { 820 // reachable code. 821 kReachable, 822 // reachable code in unreachable block (implies normal validation). 823 kSpecOnlyReachable, 824 // code unreachable in its own block (implies polymorphic validation). 825 kUnreachable 826}; 827 828// An entry on the control stack (i.e. if, block, loop, or try). 829template <typename Value, Decoder::ValidateFlag validate> 830struct ControlBase : public PcForErrors<validate> { 831 ControlKind kind = kControlBlock; 832 uint32_t locals_count = 0; // Additional locals introduced in this 'let'. 833 uint32_t stack_depth = 0; // Stack height at the beginning of the construct. 834 uint32_t init_stack_depth = 0; // Height of "locals initialization" stack 835 // at the beginning of the construct. 836 int32_t previous_catch = -1; // Depth of the innermost catch containing this 837 // 'try'. 838 Reachability reachability = kReachable; 839 840 // Values merged into the start or end of this control construct. 841 Merge<Value> start_merge; 842 Merge<Value> end_merge; 843 844 MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ControlBase); 845 846 ControlBase(ControlKind kind, uint32_t locals_count, uint32_t stack_depth, 847 uint32_t init_stack_depth, const uint8_t* pc, 848 Reachability reachability) 849 : PcForErrors<validate>(pc), 850 kind(kind), 851 locals_count(locals_count), 852 stack_depth(stack_depth), 853 init_stack_depth(init_stack_depth), 854 reachability(reachability), 855 start_merge(reachability == kReachable) { 856 DCHECK(kind == kControlLet || locals_count == 0); 857 } 858 859 // Check whether the current block is reachable. 860 bool reachable() const { return reachability == kReachable; } 861 862 // Check whether the rest of the block is unreachable. 863 // Note that this is different from {!reachable()}, as there is also the 864 // "indirect unreachable state", for which both {reachable()} and 865 // {unreachable()} return false. 866 bool unreachable() const { return reachability == kUnreachable; } 867 868 // Return the reachability of new control structs started in this block. 869 Reachability innerReachability() const { 870 return reachability == kReachable ? kReachable : kSpecOnlyReachable; 871 } 872 873 bool is_if() const { return is_onearmed_if() || is_if_else(); } 874 bool is_onearmed_if() const { return kind == kControlIf; } 875 bool is_if_else() const { return kind == kControlIfElse; } 876 bool is_block() const { return kind == kControlBlock; } 877 bool is_let() const { return kind == kControlLet; } 878 bool is_loop() const { return kind == kControlLoop; } 879 bool is_incomplete_try() const { return kind == kControlTry; } 880 bool is_try_catch() const { return kind == kControlTryCatch; } 881 bool is_try_catchall() const { return kind == kControlTryCatchAll; } 882 bool is_try() const { 883 return is_incomplete_try() || is_try_catch() || is_try_catchall(); 884 } 885 886 Merge<Value>* br_merge() { 887 return is_loop() ? &this->start_merge : &this->end_merge; 888 } 889}; 890 891// This is the list of callback functions that an interface for the 892// WasmFullDecoder should implement. 893// F(Name, args...) 894#define INTERFACE_FUNCTIONS(F) \ 895 INTERFACE_META_FUNCTIONS(F) \ 896 INTERFACE_CONSTANT_FUNCTIONS(F) \ 897 INTERFACE_NON_CONSTANT_FUNCTIONS(F) 898 899#define INTERFACE_META_FUNCTIONS(F) \ 900 F(StartFunction) \ 901 F(StartFunctionBody, Control* block) \ 902 F(FinishFunction) \ 903 F(OnFirstError) \ 904 F(NextInstruction, WasmOpcode) \ 905 F(Forward, const Value& from, Value* to) 906 907#define INTERFACE_CONSTANT_FUNCTIONS(F) \ 908 F(I32Const, Value* result, int32_t value) \ 909 F(I64Const, Value* result, int64_t value) \ 910 F(F32Const, Value* result, float value) \ 911 F(F64Const, Value* result, double value) \ 912 F(S128Const, Simd128Immediate<validate>& imm, Value* result) \ 913 F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \ 914 Value* result) \ 915 F(RefNull, ValueType type, Value* result) \ 916 F(RefFunc, uint32_t function_index, Value* result) \ 917 F(GlobalGet, Value* result, const GlobalIndexImmediate<validate>& imm) \ 918 F(StructNewWithRtt, const StructIndexImmediate<validate>& imm, \ 919 const Value& rtt, const Value args[], Value* result) \ 920 F(StructNewDefault, const StructIndexImmediate<validate>& imm, \ 921 const Value& rtt, Value* result) \ 922 F(ArrayInit, const ArrayIndexImmediate<validate>& imm, \ 923 const base::Vector<Value>& elements, const Value& rtt, Value* result) \ 924 F(ArrayInitFromData, const ArrayIndexImmediate<validate>& array_imm, \ 925 const IndexImmediate<validate>& data_segment, const Value& offset, \ 926 const Value& length, const Value& rtt, Value* result) \ 927 F(RttCanon, uint32_t type_index, Value* result) \ 928 F(DoReturn, uint32_t drop_values) 929 930#define INTERFACE_NON_CONSTANT_FUNCTIONS(F) /* force 80 columns */ \ 931 /* Control: */ \ 932 F(Block, Control* block) \ 933 F(Loop, Control* block) \ 934 F(Try, Control* block) \ 935 F(If, const Value& cond, Control* if_block) \ 936 F(FallThruTo, Control* c) \ 937 F(PopControl, Control* block) \ 938 /* Instructions: */ \ 939 F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \ 940 F(RefAsNonNull, const Value& arg, Value* result) \ 941 F(Drop) \ 942 F(LocalGet, Value* result, const IndexImmediate<validate>& imm) \ 943 F(LocalSet, const Value& value, const IndexImmediate<validate>& imm) \ 944 F(LocalTee, const Value& value, Value* result, \ 945 const IndexImmediate<validate>& imm) \ 946 F(AllocateLocals, base::Vector<Value> local_values) \ 947 F(DeallocateLocals, uint32_t count) \ 948 F(GlobalSet, const Value& value, const GlobalIndexImmediate<validate>& imm) \ 949 F(TableGet, const Value& index, Value* result, \ 950 const IndexImmediate<validate>& imm) \ 951 F(TableSet, const Value& index, const Value& value, \ 952 const IndexImmediate<validate>& imm) \ 953 F(Trap, TrapReason reason) \ 954 F(NopForTestingUnsupportedInLiftoff) \ 955 F(Select, const Value& cond, const Value& fval, const Value& tval, \ 956 Value* result) \ 957 F(BrOrRet, uint32_t depth, uint32_t drop_values) \ 958 F(BrIf, const Value& cond, uint32_t depth) \ 959 F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \ 960 F(Else, Control* if_block) \ 961 F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \ 962 const Value& index, Value* result) \ 963 F(LoadTransform, LoadType type, LoadTransformationKind transform, \ 964 const MemoryAccessImmediate<validate>& imm, const Value& index, \ 965 Value* result) \ 966 F(LoadLane, LoadType type, const Value& value, const Value& index, \ 967 const MemoryAccessImmediate<validate>& imm, const uint8_t laneidx, \ 968 Value* result) \ 969 F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \ 970 const Value& index, const Value& value) \ 971 F(StoreLane, StoreType type, const MemoryAccessImmediate<validate>& imm, \ 972 const Value& index, const Value& value, const uint8_t laneidx) \ 973 F(CurrentMemoryPages, Value* result) \ 974 F(MemoryGrow, const Value& value, Value* result) \ 975 F(CallDirect, const CallFunctionImmediate<validate>& imm, \ 976 const Value args[], Value returns[]) \ 977 F(CallIndirect, const Value& index, \ 978 const CallIndirectImmediate<validate>& imm, const Value args[], \ 979 Value returns[]) \ 980 F(CallRef, const Value& func_ref, const FunctionSig* sig, \ 981 uint32_t sig_index, const Value args[], const Value returns[]) \ 982 F(ReturnCallRef, const Value& func_ref, const FunctionSig* sig, \ 983 uint32_t sig_index, const Value args[]) \ 984 F(ReturnCall, const CallFunctionImmediate<validate>& imm, \ 985 const Value args[]) \ 986 F(ReturnCallIndirect, const Value& index, \ 987 const CallIndirectImmediate<validate>& imm, const Value args[]) \ 988 F(BrOnNull, const Value& ref_object, uint32_t depth, \ 989 bool pass_null_along_branch, Value* result_on_fallthrough) \ 990 F(BrOnNonNull, const Value& ref_object, uint32_t depth) \ 991 F(SimdOp, WasmOpcode opcode, base::Vector<Value> args, Value* result) \ 992 F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \ 993 const base::Vector<Value> inputs, Value* result) \ 994 F(S128Const, const Simd128Immediate<validate>& imm, Value* result) \ 995 F(Simd8x16ShuffleOp, const Simd128Immediate<validate>& imm, \ 996 const Value& input0, const Value& input1, Value* result) \ 997 F(Throw, const TagIndexImmediate<validate>& imm, \ 998 const base::Vector<Value>& args) \ 999 F(Rethrow, Control* block) \ 1000 F(CatchException, const TagIndexImmediate<validate>& imm, Control* block, \ 1001 base::Vector<Value> caught_values) \ 1002 F(Delegate, uint32_t depth, Control* block) \ 1003 F(CatchAll, Control* block) \ 1004 F(AtomicOp, WasmOpcode opcode, base::Vector<Value> args, \ 1005 const MemoryAccessImmediate<validate>& imm, Value* result) \ 1006 F(AtomicFence) \ 1007 F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \ 1008 const Value& src, const Value& size) \ 1009 F(DataDrop, const IndexImmediate<validate>& imm) \ 1010 F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst, \ 1011 const Value& src, const Value& size) \ 1012 F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \ 1013 const Value& value, const Value& size) \ 1014 F(TableInit, const TableInitImmediate<validate>& imm, \ 1015 base::Vector<Value> args) \ 1016 F(ElemDrop, const IndexImmediate<validate>& imm) \ 1017 F(TableCopy, const TableCopyImmediate<validate>& imm, \ 1018 base::Vector<Value> args) \ 1019 F(TableGrow, const IndexImmediate<validate>& imm, const Value& value, \ 1020 const Value& delta, Value* result) \ 1021 F(TableSize, const IndexImmediate<validate>& imm, Value* result) \ 1022 F(TableFill, const IndexImmediate<validate>& imm, const Value& start, \ 1023 const Value& value, const Value& count) \ 1024 F(StructGet, const Value& struct_object, \ 1025 const FieldImmediate<validate>& field, bool is_signed, Value* result) \ 1026 F(StructSet, const Value& struct_object, \ 1027 const FieldImmediate<validate>& field, const Value& field_value) \ 1028 F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \ 1029 const Value& length, const Value& initial_value, const Value& rtt, \ 1030 Value* result) \ 1031 F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm, \ 1032 const Value& length, const Value& rtt, Value* result) \ 1033 F(ArrayGet, const Value& array_obj, \ 1034 const ArrayIndexImmediate<validate>& imm, const Value& index, \ 1035 bool is_signed, Value* result) \ 1036 F(ArraySet, const Value& array_obj, \ 1037 const ArrayIndexImmediate<validate>& imm, const Value& index, \ 1038 const Value& value) \ 1039 F(ArrayLen, const Value& array_obj, Value* result) \ 1040 F(ArrayCopy, const Value& src, const Value& src_index, const Value& dst, \ 1041 const Value& dst_index, const Value& length) \ 1042 F(I31New, const Value& input, Value* result) \ 1043 F(I31GetS, const Value& input, Value* result) \ 1044 F(I31GetU, const Value& input, Value* result) \ 1045 F(RefTest, const Value& obj, const Value& rtt, Value* result) \ 1046 F(RefCast, const Value& obj, const Value& rtt, Value* result) \ 1047 F(AssertNull, const Value& obj, Value* result) \ 1048 F(BrOnCast, const Value& obj, const Value& rtt, Value* result_on_branch, \ 1049 uint32_t depth) \ 1050 F(BrOnCastFail, const Value& obj, const Value& rtt, \ 1051 Value* result_on_fallthrough, uint32_t depth) \ 1052 F(RefIsFunc, const Value& object, Value* result) \ 1053 F(RefIsData, const Value& object, Value* result) \ 1054 F(RefIsI31, const Value& object, Value* result) \ 1055 F(RefIsArray, const Value& object, Value* result) \ 1056 F(RefAsFunc, const Value& object, Value* result) \ 1057 F(RefAsData, const Value& object, Value* result) \ 1058 F(RefAsI31, const Value& object, Value* result) \ 1059 F(RefAsArray, const Value& object, Value* result) \ 1060 F(BrOnFunc, const Value& object, Value* value_on_branch, uint32_t br_depth) \ 1061 F(BrOnData, const Value& object, Value* value_on_branch, uint32_t br_depth) \ 1062 F(BrOnI31, const Value& object, Value* value_on_branch, uint32_t br_depth) \ 1063 F(BrOnArray, const Value& object, Value* value_on_branch, uint32_t br_depth) \ 1064 F(BrOnNonFunc, const Value& object, Value* value_on_fallthrough, \ 1065 uint32_t br_depth) \ 1066 F(BrOnNonData, const Value& object, Value* value_on_fallthrough, \ 1067 uint32_t br_depth) \ 1068 F(BrOnNonI31, const Value& object, Value* value_on_fallthrough, \ 1069 uint32_t br_depth) \ 1070 F(BrOnNonArray, const Value& object, Value* value_on_fallthrough, \ 1071 uint32_t br_depth) 1072 1073// Generic Wasm bytecode decoder with utilities for decoding immediates, 1074// lengths, etc. 1075template <Decoder::ValidateFlag validate, DecodingMode decoding_mode> 1076class WasmDecoder : public Decoder { 1077 public: 1078 WasmDecoder(Zone* zone, const WasmModule* module, const WasmFeatures& enabled, 1079 WasmFeatures* detected, const FunctionSig* sig, const byte* start, 1080 const byte* end, uint32_t buffer_offset = 0) 1081 : Decoder(start, end, buffer_offset), 1082 local_types_(zone), 1083 initialized_locals_(zone), 1084 locals_initializers_stack_(zone), 1085 module_(module), 1086 enabled_(enabled), 1087 detected_(detected), 1088 sig_(sig) {} 1089 1090 Zone* zone() const { return local_types_.get_allocator().zone(); } 1091 1092 uint32_t num_locals() const { 1093 DCHECK_EQ(num_locals_, local_types_.size()); 1094 return num_locals_; 1095 } 1096 1097 ValueType local_type(uint32_t index) const { return local_types_[index]; } 1098 1099 void InitializeLocalsFromSig() { 1100 DCHECK_NOT_NULL(sig_); 1101 DCHECK_EQ(0, this->local_types_.size()); 1102 local_types_.assign(sig_->parameters().begin(), sig_->parameters().end()); 1103 num_locals_ = static_cast<uint32_t>(sig_->parameters().size()); 1104 } 1105 1106 // Decodes local definitions in the current decoder. 1107 // Returns the number of newly defined locals, or -1 if decoding failed. 1108 // Writes the total length of decoded locals in {total_length}. 1109 // If {insert_position} is defined, the decoded locals will be inserted into 1110 // the {this->local_types_}. The decoder's pc is not advanced. 1111 int DecodeLocals(const byte* pc, uint32_t* total_length, 1112 const base::Optional<uint32_t> insert_position) { 1113 uint32_t length; 1114 *total_length = 0; 1115 int total_count = 0; 1116 1117 // The 'else' value is useless, we pass it for convenience. 1118 auto insert_iterator = insert_position.has_value() 1119 ? local_types_.begin() + insert_position.value() 1120 : local_types_.begin(); 1121 1122 // Decode local declarations, if any. 1123 uint32_t entries = read_u32v<validate>(pc, &length, "local decls count"); 1124 if (!VALIDATE(ok())) { 1125 DecodeError(pc + *total_length, "invalid local decls count"); 1126 return -1; 1127 } 1128 *total_length += length; 1129 TRACE("local decls count: %u\n", entries); 1130 1131 while (entries-- > 0) { 1132 if (!VALIDATE(more())) { 1133 DecodeError(end(), 1134 "expected more local decls but reached end of input"); 1135 return -1; 1136 } 1137 1138 uint32_t count = 1139 read_u32v<validate>(pc + *total_length, &length, "local count"); 1140 if (!VALIDATE(ok())) { 1141 DecodeError(pc + *total_length, "invalid local count"); 1142 return -1; 1143 } 1144 DCHECK_LE(local_types_.size(), kV8MaxWasmFunctionLocals); 1145 if (!VALIDATE(count <= kV8MaxWasmFunctionLocals - local_types_.size())) { 1146 DecodeError(pc + *total_length, "local count too large"); 1147 return -1; 1148 } 1149 *total_length += length; 1150 1151 ValueType type = value_type_reader::read_value_type<validate>( 1152 this, pc + *total_length, &length, this->module_, enabled_); 1153 if (!VALIDATE(type != kWasmBottom)) return -1; 1154 *total_length += length; 1155 total_count += count; 1156 1157 if (insert_position.has_value()) { 1158 // Move the insertion iterator to the end of the newly inserted locals. 1159 insert_iterator = 1160 local_types_.insert(insert_iterator, count, type) + count; 1161 num_locals_ += count; 1162 } 1163 } 1164 1165 DCHECK(ok()); 1166 return total_count; 1167 } 1168 1169 // Shorthand that forwards to the {DecodeError} functions above, passing our 1170 // {validate} flag. 1171 template <typename... Args> 1172 void DecodeError(Args... args) { 1173 wasm::DecodeError<validate>(this, std::forward<Args>(args)...); 1174 } 1175 1176 // Returns a BitVector of length {locals_count + 1} representing the set of 1177 // variables that are assigned in the loop starting at {pc}. The additional 1178 // position at the end of the vector represents possible assignments to 1179 // the instance cache. 1180 static BitVector* AnalyzeLoopAssignment(WasmDecoder* decoder, const byte* pc, 1181 uint32_t locals_count, Zone* zone) { 1182 if (pc >= decoder->end()) return nullptr; 1183 if (*pc != kExprLoop) return nullptr; 1184 // The number of locals_count is augmented by 1 so that the 'locals_count' 1185 // index can be used to track the instance cache. 1186 BitVector* assigned = zone->New<BitVector>(locals_count + 1, zone); 1187 int depth = -1; // We will increment the depth to 0 when we decode the 1188 // starting 'loop' opcode. 1189 // Since 'let' can add additional locals at the beginning of the locals 1190 // index space, we need to track this offset for every depth up to the 1191 // current depth. 1192 base::SmallVector<uint32_t, 8> local_offsets(8); 1193 // Iteratively process all AST nodes nested inside the loop. 1194 while (pc < decoder->end() && VALIDATE(decoder->ok())) { 1195 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 1196 switch (opcode) { 1197 case kExprLoop: 1198 case kExprIf: 1199 case kExprBlock: 1200 case kExprTry: 1201 depth++; 1202 local_offsets.resize_no_init(depth + 1); 1203 // No additional locals. 1204 local_offsets[depth] = depth > 0 ? local_offsets[depth - 1] : 0; 1205 break; 1206 case kExprLet: { 1207 depth++; 1208 local_offsets.resize_no_init(depth + 1); 1209 BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 1210 nullptr); 1211 uint32_t locals_length; 1212 int new_locals_count = decoder->DecodeLocals( 1213 pc + 1 + imm.length, &locals_length, base::Optional<uint32_t>()); 1214 local_offsets[depth] = local_offsets[depth - 1] + new_locals_count; 1215 break; 1216 } 1217 case kExprLocalSet: 1218 case kExprLocalTee: { 1219 IndexImmediate<validate> imm(decoder, pc + 1, "local index"); 1220 // Unverified code might have an out-of-bounds index. 1221 if (imm.index >= local_offsets[depth] && 1222 imm.index - local_offsets[depth] < locals_count) { 1223 assigned->Add(imm.index - local_offsets[depth]); 1224 } 1225 break; 1226 } 1227 case kExprMemoryGrow: 1228 case kExprCallFunction: 1229 case kExprCallIndirect: 1230 case kExprCallRef: 1231 // Add instance cache to the assigned set. 1232 assigned->Add(locals_count); 1233 break; 1234 case kExprEnd: 1235 depth--; 1236 break; 1237 default: 1238 break; 1239 } 1240 if (depth < 0) break; 1241 pc += OpcodeLength(decoder, pc); 1242 } 1243 return VALIDATE(decoder->ok()) ? assigned : nullptr; 1244 } 1245 1246 bool Validate(const byte* pc, TagIndexImmediate<validate>& imm) { 1247 if (!VALIDATE(imm.index < module_->tags.size())) { 1248 DecodeError(pc, "Invalid tag index: %u", imm.index); 1249 return false; 1250 } 1251 imm.tag = &module_->tags[imm.index]; 1252 return true; 1253 } 1254 1255 bool Validate(const byte* pc, GlobalIndexImmediate<validate>& imm) { 1256 // We compare with the current size of the globals vector. This is important 1257 // if we are decoding a constant expression in the global section. 1258 if (!VALIDATE(imm.index < module_->globals.size())) { 1259 DecodeError(pc, "Invalid global index: %u", imm.index); 1260 return false; 1261 } 1262 imm.global = &module_->globals[imm.index]; 1263 1264 if (decoding_mode == kInitExpression) { 1265 if (!VALIDATE(!imm.global->mutability)) { 1266 this->DecodeError(pc, 1267 "mutable globals cannot be used in initializer " 1268 "expressions"); 1269 return false; 1270 } 1271 if (!VALIDATE(imm.global->imported || this->enabled_.has_gc())) { 1272 this->DecodeError( 1273 pc, 1274 "non-imported globals cannot be used in initializer expressions"); 1275 return false; 1276 } 1277 } 1278 1279 return true; 1280 } 1281 1282 bool Validate(const byte* pc, StructIndexImmediate<validate>& imm) { 1283 if (!VALIDATE(module_->has_struct(imm.index))) { 1284 DecodeError(pc, "invalid struct index: %u", imm.index); 1285 return false; 1286 } 1287 imm.struct_type = module_->struct_type(imm.index); 1288 return true; 1289 } 1290 1291 bool Validate(const byte* pc, FieldImmediate<validate>& imm) { 1292 if (!Validate(pc, imm.struct_imm)) return false; 1293 if (!VALIDATE(imm.field_imm.index < 1294 imm.struct_imm.struct_type->field_count())) { 1295 DecodeError(pc + imm.struct_imm.length, "invalid field index: %u", 1296 imm.field_imm.index); 1297 return false; 1298 } 1299 return true; 1300 } 1301 1302 bool Validate(const byte* pc, ArrayIndexImmediate<validate>& imm) { 1303 if (!VALIDATE(module_->has_array(imm.index))) { 1304 DecodeError(pc, "invalid array index: %u", imm.index); 1305 return false; 1306 } 1307 imm.array_type = module_->array_type(imm.index); 1308 return true; 1309 } 1310 1311 bool CanReturnCall(const FunctionSig* target_sig) { 1312 if (sig_->return_count() != target_sig->return_count()) return false; 1313 auto target_sig_it = target_sig->returns().begin(); 1314 for (ValueType ret_type : sig_->returns()) { 1315 if (!IsSubtypeOf(*target_sig_it++, ret_type, this->module_)) return false; 1316 } 1317 return true; 1318 } 1319 1320 bool Validate(const byte* pc, CallFunctionImmediate<validate>& imm) { 1321 if (!VALIDATE(imm.index < module_->functions.size())) { 1322 DecodeError(pc, "function index #%u is out of bounds", imm.index); 1323 return false; 1324 } 1325 imm.sig = module_->functions[imm.index].sig; 1326 return true; 1327 } 1328 1329 bool Validate(const byte* pc, CallIndirectImmediate<validate>& imm) { 1330 if (!ValidateSignature(pc, imm.sig_imm)) return false; 1331 if (!ValidateTable(pc + imm.sig_imm.length, imm.table_imm)) { 1332 return false; 1333 } 1334 ValueType table_type = module_->tables[imm.table_imm.index].type; 1335 if (!VALIDATE(IsSubtypeOf(table_type, kWasmFuncRef, module_))) { 1336 DecodeError( 1337 pc, "call_indirect: immediate table #%u is not of a function type", 1338 imm.table_imm.index); 1339 return false; 1340 } 1341 1342 // Check that the dynamic signature for this call is a subtype of the static 1343 // type of the table the function is defined in. 1344 ValueType immediate_type = ValueType::Ref(imm.sig_imm.index, kNonNullable); 1345 if (!VALIDATE(IsSubtypeOf(immediate_type, table_type, module_))) { 1346 DecodeError(pc, 1347 "call_indirect: Immediate signature #%u is not a subtype of " 1348 "immediate table #%u", 1349 imm.sig_imm.index, imm.table_imm.index); 1350 return false; 1351 } 1352 1353 imm.sig = module_->signature(imm.sig_imm.index); 1354 return true; 1355 } 1356 1357 bool Validate(const byte* pc, BranchDepthImmediate<validate>& imm, 1358 size_t control_depth) { 1359 if (!VALIDATE(imm.depth < control_depth)) { 1360 DecodeError(pc, "invalid branch depth: %u", imm.depth); 1361 return false; 1362 } 1363 return true; 1364 } 1365 1366 bool Validate(const byte* pc, BranchTableImmediate<validate>& imm, 1367 size_t block_depth) { 1368 if (!VALIDATE(imm.table_count <= kV8MaxWasmFunctionBrTableSize)) { 1369 DecodeError(pc, "invalid table count (> max br_table size): %u", 1370 imm.table_count); 1371 return false; 1372 } 1373 return checkAvailable(imm.table_count); 1374 } 1375 1376 bool Validate(const byte* pc, WasmOpcode opcode, 1377 SimdLaneImmediate<validate>& imm) { 1378 uint8_t num_lanes = 0; 1379 switch (opcode) { 1380 case kExprF64x2ExtractLane: 1381 case kExprF64x2ReplaceLane: 1382 case kExprI64x2ExtractLane: 1383 case kExprI64x2ReplaceLane: 1384 case kExprS128Load64Lane: 1385 case kExprS128Store64Lane: 1386 num_lanes = 2; 1387 break; 1388 case kExprF32x4ExtractLane: 1389 case kExprF32x4ReplaceLane: 1390 case kExprI32x4ExtractLane: 1391 case kExprI32x4ReplaceLane: 1392 case kExprS128Load32Lane: 1393 case kExprS128Store32Lane: 1394 num_lanes = 4; 1395 break; 1396 case kExprI16x8ExtractLaneS: 1397 case kExprI16x8ExtractLaneU: 1398 case kExprI16x8ReplaceLane: 1399 case kExprS128Load16Lane: 1400 case kExprS128Store16Lane: 1401 num_lanes = 8; 1402 break; 1403 case kExprI8x16ExtractLaneS: 1404 case kExprI8x16ExtractLaneU: 1405 case kExprI8x16ReplaceLane: 1406 case kExprS128Load8Lane: 1407 case kExprS128Store8Lane: 1408 num_lanes = 16; 1409 break; 1410 default: 1411 UNREACHABLE(); 1412 break; 1413 } 1414 if (!VALIDATE(imm.lane >= 0 && imm.lane < num_lanes)) { 1415 DecodeError(pc, "invalid lane index"); 1416 return false; 1417 } else { 1418 return true; 1419 } 1420 } 1421 1422 bool Validate(const byte* pc, Simd128Immediate<validate>& imm) { 1423 uint8_t max_lane = 0; 1424 for (uint32_t i = 0; i < kSimd128Size; ++i) { 1425 max_lane = std::max(max_lane, imm.value[i]); 1426 } 1427 // Shuffle indices must be in [0..31] for a 16 lane shuffle. 1428 if (!VALIDATE(max_lane < 2 * kSimd128Size)) { 1429 DecodeError(pc, "invalid shuffle mask"); 1430 return false; 1431 } 1432 return true; 1433 } 1434 1435 bool Validate(const byte* pc, BlockTypeImmediate<validate>& imm) { 1436 if (imm.type != kWasmBottom) return true; 1437 if (!VALIDATE(module_->has_signature(imm.sig_index))) { 1438 DecodeError(pc, "block type index %u is not a signature definition", 1439 imm.sig_index); 1440 return false; 1441 } 1442 imm.sig = module_->signature(imm.sig_index); 1443 return true; 1444 } 1445 1446 bool Validate(const byte* pc, MemoryIndexImmediate<validate>& imm) { 1447 if (!VALIDATE(this->module_->has_memory)) { 1448 this->DecodeError(pc, "memory instruction with no memory"); 1449 return false; 1450 } 1451 if (!VALIDATE(imm.index == uint8_t{0})) { 1452 DecodeError(pc, "expected memory index 0, found %u", imm.index); 1453 return false; 1454 } 1455 return true; 1456 } 1457 1458 bool Validate(const byte* pc, MemoryAccessImmediate<validate>& imm) { 1459 if (!VALIDATE(this->module_->has_memory)) { 1460 this->DecodeError(pc, "memory instruction with no memory"); 1461 return false; 1462 } 1463 return true; 1464 } 1465 1466 bool Validate(const byte* pc, MemoryInitImmediate<validate>& imm) { 1467 return ValidateDataSegment(pc, imm.data_segment) && 1468 Validate(pc + imm.data_segment.length, imm.memory); 1469 } 1470 1471 bool Validate(const byte* pc, MemoryCopyImmediate<validate>& imm) { 1472 return Validate(pc, imm.memory_src) && 1473 Validate(pc + imm.memory_src.length, imm.memory_dst); 1474 } 1475 1476 bool Validate(const byte* pc, TableInitImmediate<validate>& imm) { 1477 if (!ValidateElementSegment(pc, imm.element_segment)) return false; 1478 if (!ValidateTable(pc + imm.element_segment.length, imm.table)) { 1479 return false; 1480 } 1481 ValueType elem_type = 1482 module_->elem_segments[imm.element_segment.index].type; 1483 if (!VALIDATE(IsSubtypeOf(elem_type, module_->tables[imm.table.index].type, 1484 module_))) { 1485 DecodeError(pc, "table %u is not a super-type of %s", imm.table.index, 1486 elem_type.name().c_str()); 1487 return false; 1488 } 1489 return true; 1490 } 1491 1492 bool Validate(const byte* pc, TableCopyImmediate<validate>& imm) { 1493 if (!ValidateTable(pc, imm.table_src)) return false; 1494 if (!ValidateTable(pc + imm.table_src.length, imm.table_dst)) return false; 1495 ValueType src_type = module_->tables[imm.table_src.index].type; 1496 if (!VALIDATE(IsSubtypeOf( 1497 src_type, module_->tables[imm.table_dst.index].type, module_))) { 1498 DecodeError(pc, "table %u is not a super-type of %s", imm.table_dst.index, 1499 src_type.name().c_str()); 1500 return false; 1501 } 1502 return true; 1503 } 1504 1505 // The following Validate* functions all validate an IndexImmediate, albeit 1506 // differently according to context. 1507 bool ValidateTable(const byte* pc, IndexImmediate<validate>& imm) { 1508 if (imm.index > 0 || imm.length > 1) { 1509 this->detected_->Add(kFeature_reftypes); 1510 } 1511 if (!VALIDATE(imm.index < module_->tables.size())) { 1512 DecodeError(pc, "invalid table index: %u", imm.index); 1513 return false; 1514 } 1515 return true; 1516 } 1517 1518 bool ValidateElementSegment(const byte* pc, IndexImmediate<validate>& imm) { 1519 if (!VALIDATE(imm.index < module_->elem_segments.size())) { 1520 DecodeError(pc, "invalid element segment index: %u", imm.index); 1521 return false; 1522 } 1523 return true; 1524 } 1525 1526 bool ValidateLocal(const byte* pc, IndexImmediate<validate>& imm) { 1527 if (!VALIDATE(imm.index < num_locals())) { 1528 DecodeError(pc, "invalid local index: %u", imm.index); 1529 return false; 1530 } 1531 return true; 1532 } 1533 1534 bool ValidateType(const byte* pc, IndexImmediate<validate>& imm) { 1535 if (!VALIDATE(module_->has_type(imm.index))) { 1536 DecodeError(pc, "invalid type index: %u", imm.index); 1537 return false; 1538 } 1539 return true; 1540 } 1541 1542 bool ValidateSignature(const byte* pc, IndexImmediate<validate>& imm) { 1543 if (!VALIDATE(module_->has_signature(imm.index))) { 1544 DecodeError(pc, "invalid signature index: %u", imm.index); 1545 return false; 1546 } 1547 return true; 1548 } 1549 1550 bool ValidateFunction(const byte* pc, IndexImmediate<validate>& imm) { 1551 if (!VALIDATE(imm.index < module_->functions.size())) { 1552 DecodeError(pc, "function index #%u is out of bounds", imm.index); 1553 return false; 1554 } 1555 if (decoding_mode == kFunctionBody && 1556 !VALIDATE(module_->functions[imm.index].declared)) { 1557 DecodeError(pc, "undeclared reference to function #%u", imm.index); 1558 return false; 1559 } 1560 return true; 1561 } 1562 1563 bool ValidateDataSegment(const byte* pc, IndexImmediate<validate>& imm) { 1564 if (!VALIDATE(imm.index < module_->num_declared_data_segments)) { 1565 DecodeError(pc, "invalid data segment index: %u", imm.index); 1566 return false; 1567 } 1568 return true; 1569 } 1570 1571 // Returns the length of the opcode under {pc}. 1572 static uint32_t OpcodeLength(WasmDecoder* decoder, const byte* pc) { 1573 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 1574 // We don't have information about the module here, so we just assume that 1575 // memory64 is enabled when parsing memory access immediates. This is 1576 // backwards-compatible; decode errors will be detected at another time when 1577 // actually decoding that opcode. 1578 constexpr bool kConservativelyAssumeMemory64 = true; 1579 switch (opcode) { 1580 /********** Control opcodes **********/ 1581 case kExprUnreachable: 1582 case kExprNop: 1583 case kExprNopForTestingUnsupportedInLiftoff: 1584 case kExprElse: 1585 case kExprEnd: 1586 case kExprReturn: 1587 return 1; 1588 case kExprTry: 1589 case kExprIf: 1590 case kExprLoop: 1591 case kExprBlock: { 1592 BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 1593 nullptr); 1594 return 1 + imm.length; 1595 } 1596 case kExprRethrow: 1597 case kExprBr: 1598 case kExprBrIf: 1599 case kExprBrOnNull: 1600 case kExprBrOnNonNull: 1601 case kExprDelegate: { 1602 BranchDepthImmediate<validate> imm(decoder, pc + 1); 1603 return 1 + imm.length; 1604 } 1605 case kExprBrTable: { 1606 BranchTableImmediate<validate> imm(decoder, pc + 1); 1607 BranchTableIterator<validate> iterator(decoder, imm); 1608 return 1 + iterator.length(); 1609 } 1610 case kExprThrow: 1611 case kExprCatch: { 1612 TagIndexImmediate<validate> imm(decoder, pc + 1); 1613 return 1 + imm.length; 1614 } 1615 case kExprLet: { 1616 BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 1617 nullptr); 1618 uint32_t locals_length; 1619 int new_locals_count = decoder->DecodeLocals( 1620 pc + 1 + imm.length, &locals_length, base::Optional<uint32_t>()); 1621 return 1 + imm.length + ((new_locals_count >= 0) ? locals_length : 0); 1622 } 1623 1624 /********** Misc opcodes **********/ 1625 case kExprCallFunction: 1626 case kExprReturnCall: { 1627 CallFunctionImmediate<validate> imm(decoder, pc + 1); 1628 return 1 + imm.length; 1629 } 1630 case kExprCallIndirect: 1631 case kExprReturnCallIndirect: { 1632 CallIndirectImmediate<validate> imm(decoder, pc + 1); 1633 return 1 + imm.length; 1634 } 1635 case kExprCallRef: 1636 case kExprReturnCallRef: 1637 case kExprDrop: 1638 case kExprSelect: 1639 case kExprCatchAll: 1640 return 1; 1641 case kExprSelectWithType: { 1642 SelectTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 1643 nullptr); 1644 return 1 + imm.length; 1645 } 1646 1647 case kExprLocalGet: 1648 case kExprLocalSet: 1649 case kExprLocalTee: { 1650 IndexImmediate<validate> imm(decoder, pc + 1, "local index"); 1651 return 1 + imm.length; 1652 } 1653 case kExprGlobalGet: 1654 case kExprGlobalSet: { 1655 GlobalIndexImmediate<validate> imm(decoder, pc + 1); 1656 return 1 + imm.length; 1657 } 1658 case kExprTableGet: 1659 case kExprTableSet: { 1660 IndexImmediate<validate> imm(decoder, pc + 1, "table index"); 1661 return 1 + imm.length; 1662 } 1663 case kExprI32Const: { 1664 ImmI32Immediate<validate> imm(decoder, pc + 1); 1665 return 1 + imm.length; 1666 } 1667 case kExprI64Const: { 1668 ImmI64Immediate<validate> imm(decoder, pc + 1); 1669 return 1 + imm.length; 1670 } 1671 case kExprF32Const: 1672 return 5; 1673 case kExprF64Const: 1674 return 9; 1675 case kExprRefNull: { 1676 HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1, 1677 nullptr); 1678 return 1 + imm.length; 1679 } 1680 case kExprRefIsNull: { 1681 return 1; 1682 } 1683 case kExprRefFunc: { 1684 IndexImmediate<validate> imm(decoder, pc + 1, "function index"); 1685 return 1 + imm.length; 1686 } 1687 case kExprRefAsNonNull: 1688 return 1; 1689 1690#define DECLARE_OPCODE_CASE(name, ...) case kExpr##name: 1691 // clang-format off 1692 /********** Simple and memory opcodes **********/ 1693 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) 1694 FOREACH_SIMPLE_PROTOTYPE_OPCODE(DECLARE_OPCODE_CASE) 1695 return 1; 1696 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) 1697 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) { 1698 MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX, 1699 kConservativelyAssumeMemory64); 1700 return 1 + imm.length; 1701 } 1702 // clang-format on 1703 case kExprMemoryGrow: 1704 case kExprMemorySize: { 1705 MemoryIndexImmediate<validate> imm(decoder, pc + 1); 1706 return 1 + imm.length; 1707 } 1708 1709 /********** Prefixed opcodes **********/ 1710 case kNumericPrefix: { 1711 uint32_t length = 0; 1712 opcode = decoder->read_prefixed_opcode<validate>(pc, &length); 1713 switch (opcode) { 1714 case kExprI32SConvertSatF32: 1715 case kExprI32UConvertSatF32: 1716 case kExprI32SConvertSatF64: 1717 case kExprI32UConvertSatF64: 1718 case kExprI64SConvertSatF32: 1719 case kExprI64UConvertSatF32: 1720 case kExprI64SConvertSatF64: 1721 case kExprI64UConvertSatF64: 1722 return length; 1723 case kExprMemoryInit: { 1724 MemoryInitImmediate<validate> imm(decoder, pc + length); 1725 return length + imm.length; 1726 } 1727 case kExprDataDrop: { 1728 IndexImmediate<validate> imm(decoder, pc + length, 1729 "data segment index"); 1730 return length + imm.length; 1731 } 1732 case kExprMemoryCopy: { 1733 MemoryCopyImmediate<validate> imm(decoder, pc + length); 1734 return length + imm.length; 1735 } 1736 case kExprMemoryFill: { 1737 MemoryIndexImmediate<validate> imm(decoder, pc + length); 1738 return length + imm.length; 1739 } 1740 case kExprTableInit: { 1741 TableInitImmediate<validate> imm(decoder, pc + length); 1742 return length + imm.length; 1743 } 1744 case kExprElemDrop: { 1745 IndexImmediate<validate> imm(decoder, pc + length, 1746 "element segment index"); 1747 return length + imm.length; 1748 } 1749 case kExprTableCopy: { 1750 TableCopyImmediate<validate> imm(decoder, pc + length); 1751 return length + imm.length; 1752 } 1753 case kExprTableGrow: 1754 case kExprTableSize: 1755 case kExprTableFill: { 1756 IndexImmediate<validate> imm(decoder, pc + length, "table index"); 1757 return length + imm.length; 1758 } 1759 default: 1760 if (validate) { 1761 decoder->DecodeError(pc, "invalid numeric opcode"); 1762 } 1763 return length; 1764 } 1765 } 1766 case kSimdPrefix: { 1767 uint32_t length = 0; 1768 opcode = decoder->read_prefixed_opcode<validate>(pc, &length); 1769 switch (opcode) { 1770 // clang-format off 1771 FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) 1772 return length; 1773 FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) 1774 return length + 1; 1775 FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE) { 1776 MemoryAccessImmediate<validate> imm(decoder, pc + length, 1777 UINT32_MAX, 1778 kConservativelyAssumeMemory64); 1779 return length + imm.length; 1780 } 1781 FOREACH_SIMD_MEM_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { 1782 MemoryAccessImmediate<validate> imm( 1783 decoder, pc + length, UINT32_MAX, 1784 kConservativelyAssumeMemory64); 1785 // 1 more byte for lane index immediate. 1786 return length + imm.length + 1; 1787 } 1788 // clang-format on 1789 // Shuffles require a byte per lane, or 16 immediate bytes. 1790 case kExprS128Const: 1791 case kExprI8x16Shuffle: 1792 return length + kSimd128Size; 1793 default: 1794 if (validate) { 1795 decoder->DecodeError(pc, "invalid SIMD opcode"); 1796 } 1797 return length; 1798 } 1799 } 1800 case kAtomicPrefix: { 1801 uint32_t length = 0; 1802 opcode = decoder->read_prefixed_opcode<validate>(pc, &length, 1803 "atomic_index"); 1804 switch (opcode) { 1805 FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE) { 1806 MemoryAccessImmediate<validate> imm(decoder, pc + length, 1807 UINT32_MAX, 1808 kConservativelyAssumeMemory64); 1809 return length + imm.length; 1810 } 1811 FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { 1812 return length + 1; 1813 } 1814 default: 1815 if (validate) { 1816 decoder->DecodeError(pc, "invalid Atomics opcode"); 1817 } 1818 return length; 1819 } 1820 } 1821 case kGCPrefix: { 1822 uint32_t length = 0; 1823 opcode = 1824 decoder->read_prefixed_opcode<validate>(pc, &length, "gc_index"); 1825 switch (opcode) { 1826 case kExprStructNew: 1827 case kExprStructNewWithRtt: 1828 case kExprStructNewDefault: 1829 case kExprStructNewDefaultWithRtt: { 1830 StructIndexImmediate<validate> imm(decoder, pc + length); 1831 return length + imm.length; 1832 } 1833 case kExprStructGet: 1834 case kExprStructGetS: 1835 case kExprStructGetU: 1836 case kExprStructSet: { 1837 FieldImmediate<validate> imm(decoder, pc + length); 1838 return length + imm.length; 1839 } 1840 case kExprArrayNew: 1841 case kExprArrayNewWithRtt: 1842 case kExprArrayNewDefault: 1843 case kExprArrayNewDefaultWithRtt: 1844 case kExprArrayGet: 1845 case kExprArrayGetS: 1846 case kExprArrayGetU: 1847 case kExprArraySet: 1848 case kExprArrayLen: { 1849 ArrayIndexImmediate<validate> imm(decoder, pc + length); 1850 return length + imm.length; 1851 } 1852 case kExprArrayInit: 1853 case kExprArrayInitStatic: { 1854 ArrayIndexImmediate<validate> array_imm(decoder, pc + length); 1855 IndexImmediate<validate> length_imm( 1856 decoder, pc + length + array_imm.length, "array length"); 1857 return length + array_imm.length + length_imm.length; 1858 } 1859 case kExprArrayCopy: { 1860 ArrayIndexImmediate<validate> dst_imm(decoder, pc + length); 1861 ArrayIndexImmediate<validate> src_imm(decoder, 1862 pc + length + dst_imm.length); 1863 return length + dst_imm.length + src_imm.length; 1864 } 1865 case kExprArrayInitFromData: 1866 case kExprArrayInitFromDataStatic: { 1867 ArrayIndexImmediate<validate> array_imm(decoder, pc + length); 1868 IndexImmediate<validate> data_imm( 1869 decoder, pc + length + array_imm.length, "data segment index"); 1870 return length + array_imm.length + data_imm.length; 1871 } 1872 case kExprBrOnCast: 1873 case kExprBrOnCastFail: 1874 case kExprBrOnData: 1875 case kExprBrOnFunc: 1876 case kExprBrOnI31: { 1877 BranchDepthImmediate<validate> imm(decoder, pc + length); 1878 return length + imm.length; 1879 } 1880 case kExprRttCanon: 1881 case kExprRefTestStatic: 1882 case kExprRefCastStatic: 1883 case kExprBrOnCastStatic: 1884 case kExprBrOnCastStaticFail: { 1885 IndexImmediate<validate> imm(decoder, pc + length, "type index"); 1886 return length + imm.length; 1887 } 1888 case kExprI31New: 1889 case kExprI31GetS: 1890 case kExprI31GetU: 1891 case kExprRefAsData: 1892 case kExprRefAsFunc: 1893 case kExprRefAsI31: 1894 case kExprRefIsData: 1895 case kExprRefIsFunc: 1896 case kExprRefIsI31: 1897 case kExprRefTest: 1898 case kExprRefCast: 1899 return length; 1900 default: 1901 // This is unreachable except for malformed modules. 1902 if (validate) { 1903 decoder->DecodeError(pc, "invalid gc opcode"); 1904 } 1905 return length; 1906 } 1907 } 1908 1909 // clang-format off 1910 /********** Asmjs opcodes **********/ 1911 FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE) 1912 return 1; 1913 1914 // Prefixed opcodes (already handled, included here for completeness of 1915 // switch) 1916 FOREACH_SIMD_OPCODE(DECLARE_OPCODE_CASE) 1917 FOREACH_NUMERIC_OPCODE(DECLARE_OPCODE_CASE, DECLARE_OPCODE_CASE) 1918 FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE) 1919 FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) 1920 FOREACH_GC_OPCODE(DECLARE_OPCODE_CASE) 1921 UNREACHABLE(); 1922 // clang-format on 1923#undef DECLARE_OPCODE_CASE 1924 } 1925 // Invalid modules will reach this point. 1926 if (validate) { 1927 decoder->DecodeError(pc, "invalid opcode"); 1928 } 1929 return 1; 1930 } 1931 1932 // TODO(clemensb): This is only used by the interpreter; move there. 1933 V8_EXPORT_PRIVATE std::pair<uint32_t, uint32_t> StackEffect(const byte* pc) { 1934 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 1935 // Handle "simple" opcodes with a fixed signature first. 1936 const FunctionSig* sig = WasmOpcodes::Signature(opcode); 1937 if (!sig) sig = WasmOpcodes::AsmjsSignature(opcode); 1938 if (sig) return {sig->parameter_count(), sig->return_count()}; 1939 1940#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 1941 // clang-format off 1942 switch (opcode) { 1943 case kExprSelect: 1944 case kExprSelectWithType: 1945 return {3, 1}; 1946 case kExprTableSet: 1947 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) 1948 return {2, 0}; 1949 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) 1950 case kExprTableGet: 1951 case kExprLocalTee: 1952 case kExprMemoryGrow: 1953 case kExprRefAsNonNull: 1954 case kExprBrOnNull: 1955 case kExprRefIsNull: 1956 return {1, 1}; 1957 case kExprLocalSet: 1958 case kExprGlobalSet: 1959 case kExprDrop: 1960 case kExprBrIf: 1961 case kExprBrTable: 1962 case kExprIf: 1963 case kExprBrOnNonNull: 1964 return {1, 0}; 1965 case kExprLocalGet: 1966 case kExprGlobalGet: 1967 case kExprI32Const: 1968 case kExprI64Const: 1969 case kExprF32Const: 1970 case kExprF64Const: 1971 case kExprRefNull: 1972 case kExprRefFunc: 1973 case kExprMemorySize: 1974 return {0, 1}; 1975 case kExprCallFunction: { 1976 CallFunctionImmediate<validate> imm(this, pc + 1); 1977 CHECK(Validate(pc + 1, imm)); 1978 return {imm.sig->parameter_count(), imm.sig->return_count()}; 1979 } 1980 case kExprCallIndirect: { 1981 CallIndirectImmediate<validate> imm(this, pc + 1); 1982 CHECK(Validate(pc + 1, imm)); 1983 // Indirect calls pop an additional argument for the table index. 1984 return {imm.sig->parameter_count() + 1, 1985 imm.sig->return_count()}; 1986 } 1987 case kExprThrow: { 1988 TagIndexImmediate<validate> imm(this, pc + 1); 1989 CHECK(Validate(pc + 1, imm)); 1990 DCHECK_EQ(0, imm.tag->sig->return_count()); 1991 return {imm.tag->sig->parameter_count(), 0}; 1992 } 1993 case kExprBr: 1994 case kExprBlock: 1995 case kExprLoop: 1996 case kExprEnd: 1997 case kExprElse: 1998 case kExprTry: 1999 case kExprCatch: 2000 case kExprCatchAll: 2001 case kExprDelegate: 2002 case kExprRethrow: 2003 case kExprNop: 2004 case kExprNopForTestingUnsupportedInLiftoff: 2005 case kExprReturn: 2006 case kExprReturnCall: 2007 case kExprReturnCallIndirect: 2008 case kExprUnreachable: 2009 return {0, 0}; 2010 case kExprLet: 2011 // TODO(7748): Implement 2012 return {0, 0}; 2013 case kNumericPrefix: 2014 case kAtomicPrefix: 2015 case kSimdPrefix: { 2016 opcode = this->read_prefixed_opcode<validate>(pc); 2017 switch (opcode) { 2018 FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE) 2019 return {1, 1}; 2020 FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE) 2021 FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE) 2022 return {2, 1}; 2023 FOREACH_SIMD_CONST_OPCODE(DECLARE_OPCODE_CASE) 2024 return {0, 1}; 2025 // Special case numeric opcodes without fixed signature. 2026 case kExprMemoryInit: 2027 case kExprMemoryCopy: 2028 case kExprMemoryFill: 2029 return {3, 0}; 2030 case kExprTableGrow: 2031 return {2, 1}; 2032 case kExprTableFill: 2033 return {3, 0}; 2034 default: { 2035 sig = WasmOpcodes::Signature(opcode); 2036 DCHECK_NOT_NULL(sig); 2037 return {sig->parameter_count(), sig->return_count()}; 2038 } 2039 } 2040 } 2041 case kGCPrefix: { 2042 opcode = this->read_prefixed_opcode<validate>(pc); 2043 switch (opcode) { 2044 case kExprStructNewDefaultWithRtt: 2045 case kExprStructGet: 2046 case kExprStructGetS: 2047 case kExprStructGetU: 2048 case kExprI31New: 2049 case kExprI31GetS: 2050 case kExprI31GetU: 2051 case kExprArrayNewDefault: 2052 case kExprArrayLen: 2053 case kExprRefTestStatic: 2054 case kExprRefCastStatic: 2055 case kExprBrOnCastStatic: 2056 case kExprBrOnCastStaticFail: 2057 return {1, 1}; 2058 case kExprStructSet: 2059 return {2, 0}; 2060 case kExprArrayNew: 2061 case kExprArrayNewDefaultWithRtt: 2062 case kExprArrayInitFromDataStatic: 2063 case kExprArrayGet: 2064 case kExprArrayGetS: 2065 case kExprArrayGetU: 2066 case kExprRefTest: 2067 case kExprRefCast: 2068 case kExprBrOnCast: 2069 case kExprBrOnCastFail: 2070 return {2, 1}; 2071 case kExprArraySet: 2072 return {3, 0}; 2073 case kExprArrayCopy: 2074 return {5, 0}; 2075 case kExprRttCanon: 2076 case kExprStructNewDefault: 2077 return {0, 1}; 2078 case kExprArrayNewWithRtt: 2079 case kExprArrayInitFromData: 2080 return {3, 1}; 2081 case kExprStructNewWithRtt: { 2082 StructIndexImmediate<validate> imm(this, pc + 2); 2083 CHECK(Validate(pc + 2, imm)); 2084 return {imm.struct_type->field_count() + 1, 1}; 2085 } 2086 case kExprStructNew: { 2087 StructIndexImmediate<validate> imm(this, pc + 2); 2088 CHECK(Validate(pc + 2, imm)); 2089 return {imm.struct_type->field_count(), 1}; 2090 } 2091 case kExprArrayInit: 2092 case kExprArrayInitStatic: { 2093 ArrayIndexImmediate<validate> array_imm(this, pc + 2); 2094 IndexImmediate<validate> length_imm(this, pc + 2 + array_imm.length, 2095 "array length"); 2096 return {length_imm.index + (opcode == kExprArrayInit ? 1 : 0), 1}; 2097 } 2098 default: 2099 UNREACHABLE(); 2100 } 2101 } 2102 default: 2103 FATAL("unimplemented opcode: %x (%s)", opcode, 2104 WasmOpcodes::OpcodeName(opcode)); 2105 return {0, 0}; 2106 } 2107#undef DECLARE_OPCODE_CASE 2108 // clang-format on 2109 } 2110 2111 bool is_local_initialized(uint32_t local_index) { 2112 return initialized_locals_[local_index]; 2113 } 2114 2115 void set_local_initialized(uint32_t local_index) { 2116 if (!enabled_.has_nn_locals()) return; 2117 // This implicitly covers defaultable locals too (which are always 2118 // initialized). 2119 if (is_local_initialized(local_index)) return; 2120 initialized_locals_[local_index] = true; 2121 locals_initializers_stack_.push_back(local_index); 2122 } 2123 2124 uint32_t locals_initialization_stack_depth() const { 2125 return static_cast<uint32_t>(locals_initializers_stack_.size()); 2126 } 2127 2128 void RollbackLocalsInitialization(uint32_t previous_stack_height) { 2129 if (!enabled_.has_nn_locals()) return; 2130 while (locals_initializers_stack_.size() > previous_stack_height) { 2131 uint32_t local_index = locals_initializers_stack_.back(); 2132 locals_initializers_stack_.pop_back(); 2133 initialized_locals_[local_index] = false; 2134 } 2135 } 2136 2137 void InitializeInitializedLocalsTracking(int non_defaultable_locals) { 2138 initialized_locals_.assign(num_locals_, false); 2139 // Parameters count as initialized... 2140 const uint32_t num_params = static_cast<uint32_t>(sig_->parameter_count()); 2141 for (uint32_t i = 0; i < num_params; i++) { 2142 initialized_locals_[i] = true; 2143 } 2144 // ...and so do defaultable locals. 2145 for (uint32_t i = num_params; i < num_locals_; i++) { 2146 if (local_types_[i].is_defaultable()) initialized_locals_[i] = true; 2147 } 2148 if (non_defaultable_locals == 0) return; 2149 locals_initializers_stack_.reserve(non_defaultable_locals); 2150 } 2151 2152 // The {Zone} is implicitly stored in the {ZoneAllocator} which is part of 2153 // this {ZoneVector}. Hence save one field and just get it from there if 2154 // needed (see {zone()} accessor below). 2155 ZoneVector<ValueType> local_types_; 2156 2157 // Cached value, for speed (yes, it's measurably faster to load this value 2158 // than to load the start and end pointer from a vector, subtract and shift). 2159 uint32_t num_locals_ = 0; 2160 2161 // Indicates whether the local with the given index is currently initialized. 2162 // Entries for defaultable locals are meaningless; we have a bit for each 2163 // local because we expect that the effort required to densify this bit 2164 // vector would more than offset the memory savings. 2165 ZoneVector<bool> initialized_locals_; 2166 // Keeps track of initializing assignments to non-defaultable locals that 2167 // happened, so they can be discarded at the end of the current block. 2168 // Contains no duplicates, so the size of this stack is bounded (and pre- 2169 // allocated) to the number of non-defaultable locals in the function. 2170 ZoneVector<uint32_t> locals_initializers_stack_; 2171 2172 const WasmModule* module_; 2173 const WasmFeatures enabled_; 2174 WasmFeatures* detected_; 2175 const FunctionSig* sig_; 2176}; 2177 2178// Only call this in contexts where {current_code_reachable_and_ok_} is known to 2179// hold. 2180#define CALL_INTERFACE(name, ...) \ 2181 do { \ 2182 DCHECK(!control_.empty()); \ 2183 DCHECK(current_code_reachable_and_ok_); \ 2184 DCHECK_EQ(current_code_reachable_and_ok_, \ 2185 this->ok() && control_.back().reachable()); \ 2186 interface_.name(this, ##__VA_ARGS__); \ 2187 } while (false) 2188#define CALL_INTERFACE_IF_OK_AND_REACHABLE(name, ...) \ 2189 do { \ 2190 DCHECK(!control_.empty()); \ 2191 DCHECK_EQ(current_code_reachable_and_ok_, \ 2192 this->ok() && control_.back().reachable()); \ 2193 if (V8_LIKELY(current_code_reachable_and_ok_)) { \ 2194 interface_.name(this, ##__VA_ARGS__); \ 2195 } \ 2196 } while (false) 2197#define CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(name, ...) \ 2198 do { \ 2199 DCHECK(!control_.empty()); \ 2200 if (VALIDATE(this->ok()) && \ 2201 (control_.size() == 1 || control_at(1)->reachable())) { \ 2202 interface_.name(this, ##__VA_ARGS__); \ 2203 } \ 2204 } while (false) 2205 2206template <Decoder::ValidateFlag validate, typename Interface, 2207 DecodingMode decoding_mode = kFunctionBody> 2208class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> { 2209 using Value = typename Interface::Value; 2210 using Control = typename Interface::Control; 2211 using ArgVector = base::Vector<Value>; 2212 using ReturnVector = base::SmallVector<Value, 2>; 2213 2214 // All Value types should be trivially copyable for performance. We push, pop, 2215 // and store them in local variables. 2216 ASSERT_TRIVIALLY_COPYABLE(Value); 2217 2218 public: 2219 template <typename... InterfaceArgs> 2220 WasmFullDecoder(Zone* zone, const WasmModule* module, 2221 const WasmFeatures& enabled, WasmFeatures* detected, 2222 const FunctionBody& body, InterfaceArgs&&... interface_args) 2223 : WasmDecoder<validate, decoding_mode>(zone, module, enabled, detected, 2224 body.sig, body.start, body.end, 2225 body.offset), 2226 interface_(std::forward<InterfaceArgs>(interface_args)...), 2227 control_(zone) {} 2228 2229 Interface& interface() { return interface_; } 2230 2231 bool Decode() { 2232 DCHECK_EQ(stack_end_, stack_); 2233 DCHECK(control_.empty()); 2234 DCHECK_LE(this->pc_, this->end_); 2235 DCHECK_EQ(this->num_locals(), 0); 2236 2237 locals_offset_ = this->pc_offset(); 2238 this->InitializeLocalsFromSig(); 2239 uint32_t params_count = static_cast<uint32_t>(this->num_locals()); 2240 uint32_t locals_length; 2241 this->DecodeLocals(this->pc(), &locals_length, params_count); 2242 if (this->failed()) return TraceFailed(); 2243 this->consume_bytes(locals_length); 2244 int non_defaultable = 0; 2245 for (uint32_t index = params_count; index < this->num_locals(); index++) { 2246 if (!VALIDATE(this->enabled_.has_nn_locals() || 2247 this->enabled_.has_unsafe_nn_locals() || 2248 this->local_type(index).is_defaultable())) { 2249 this->DecodeError( 2250 "Cannot define function-level local of non-defaultable type %s", 2251 this->local_type(index).name().c_str()); 2252 return this->TraceFailed(); 2253 } 2254 if (!this->local_type(index).is_defaultable()) non_defaultable++; 2255 } 2256 this->InitializeInitializedLocalsTracking(non_defaultable); 2257 2258 // Cannot use CALL_INTERFACE_* macros because control is empty. 2259 interface().StartFunction(this); 2260 DecodeFunctionBody(); 2261 if (this->failed()) return TraceFailed(); 2262 2263 if (!VALIDATE(control_.empty())) { 2264 if (control_.size() > 1) { 2265 this->DecodeError(control_.back().pc(), 2266 "unterminated control structure"); 2267 } else { 2268 this->DecodeError("function body must end with \"end\" opcode"); 2269 } 2270 return TraceFailed(); 2271 } 2272 // Cannot use CALL_INTERFACE_* macros because control is empty. 2273 interface().FinishFunction(this); 2274 if (this->failed()) return TraceFailed(); 2275 2276 TRACE("wasm-decode ok\n\n"); 2277 return true; 2278 } 2279 2280 bool TraceFailed() { 2281 if (this->error_.offset()) { 2282 TRACE("wasm-error module+%-6d func+%d: %s\n\n", this->error_.offset(), 2283 this->GetBufferRelativeOffset(this->error_.offset()), 2284 this->error_.message().c_str()); 2285 } else { 2286 TRACE("wasm-error: %s\n\n", this->error_.message().c_str()); 2287 } 2288 return false; 2289 } 2290 2291 const char* SafeOpcodeNameAt(const byte* pc) { 2292 if (!pc) return "<null>"; 2293 if (pc >= this->end_) return "<end>"; 2294 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 2295 if (!WasmOpcodes::IsPrefixOpcode(opcode)) { 2296 return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(opcode)); 2297 } 2298 opcode = this->template read_prefixed_opcode<Decoder::kFullValidation>(pc); 2299 return WasmOpcodes::OpcodeName(opcode); 2300 } 2301 2302 WasmCodePosition position() const { 2303 int offset = static_cast<int>(this->pc_ - this->start_); 2304 DCHECK_EQ(this->pc_ - this->start_, offset); // overflows cannot happen 2305 return offset; 2306 } 2307 2308 uint32_t control_depth() const { 2309 return static_cast<uint32_t>(control_.size()); 2310 } 2311 2312 Control* control_at(uint32_t depth) { 2313 DCHECK_GT(control_.size(), depth); 2314 return &control_.back() - depth; 2315 } 2316 2317 uint32_t stack_size() const { 2318 DCHECK_GE(stack_end_, stack_); 2319 DCHECK_GE(kMaxUInt32, stack_end_ - stack_); 2320 return static_cast<uint32_t>(stack_end_ - stack_); 2321 } 2322 2323 Value* stack_value(uint32_t depth) const { 2324 DCHECK_LT(0, depth); 2325 DCHECK_GE(stack_size(), depth); 2326 return stack_end_ - depth; 2327 } 2328 2329 int32_t current_catch() const { return current_catch_; } 2330 2331 uint32_t control_depth_of_current_catch() const { 2332 return control_depth() - 1 - current_catch(); 2333 } 2334 2335 void SetSucceedingCodeDynamicallyUnreachable() { 2336 Control* current = &control_.back(); 2337 if (current->reachable()) { 2338 current->reachability = kSpecOnlyReachable; 2339 current_code_reachable_and_ok_ = false; 2340 } 2341 } 2342 2343 uint32_t pc_relative_offset() const { 2344 return this->pc_offset() - locals_offset_; 2345 } 2346 2347 void DecodeFunctionBody() { 2348 TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n", this->start(), 2349 this->end(), this->pc_offset(), 2350 static_cast<int>(this->end() - this->start())); 2351 2352 // Set up initial function block. 2353 { 2354 DCHECK(control_.empty()); 2355 constexpr uint32_t kLocalsCount = 0; 2356 constexpr uint32_t kStackDepth = 0; 2357 constexpr uint32_t kInitStackDepth = 0; 2358 control_.emplace_back(kControlBlock, kLocalsCount, kStackDepth, 2359 kInitStackDepth, this->pc_, kReachable); 2360 Control* c = &control_.back(); 2361 if (decoding_mode == kFunctionBody) { 2362 InitMerge(&c->start_merge, 0, [](uint32_t) -> Value { UNREACHABLE(); }); 2363 InitMerge(&c->end_merge, 2364 static_cast<uint32_t>(this->sig_->return_count()), 2365 [&](uint32_t i) { 2366 return Value{this->pc_, this->sig_->GetReturn(i)}; 2367 }); 2368 } else { 2369 DCHECK_EQ(this->sig_->parameter_count(), 0); 2370 DCHECK_EQ(this->sig_->return_count(), 1); 2371 c->start_merge.arity = 0; 2372 c->end_merge.arity = 1; 2373 c->end_merge.vals.first = Value{this->pc_, this->sig_->GetReturn(0)}; 2374 } 2375 CALL_INTERFACE_IF_OK_AND_REACHABLE(StartFunctionBody, c); 2376 } 2377 2378 // Decode the function body. 2379 while (this->pc_ < this->end_) { 2380 // Most operations only grow the stack by at least one element (unary and 2381 // binary operations, local.get, constants, ...). Thus check that there is 2382 // enough space for those operations centrally, and avoid any bounds 2383 // checks in those operations. 2384 EnsureStackSpace(1); 2385 uint8_t first_byte = *this->pc_; 2386 WasmOpcode opcode = static_cast<WasmOpcode>(first_byte); 2387 CALL_INTERFACE_IF_OK_AND_REACHABLE(NextInstruction, opcode); 2388 int len; 2389 // Allowing two of the most common decoding functions to get inlined 2390 // appears to be the sweet spot. 2391 // Handling _all_ opcodes via a giant switch-statement has been tried 2392 // and found to be slower than calling through the handler table. 2393 if (opcode == kExprLocalGet) { 2394 len = WasmFullDecoder::DecodeLocalGet(this, opcode); 2395 } else if (opcode == kExprI32Const) { 2396 len = WasmFullDecoder::DecodeI32Const(this, opcode); 2397 } else { 2398 OpcodeHandler handler = GetOpcodeHandler(first_byte); 2399 len = (*handler)(this, opcode); 2400 } 2401 this->pc_ += len; 2402 } 2403 2404 if (!VALIDATE(this->pc_ == this->end_)) { 2405 this->DecodeError("Beyond end of code"); 2406 } 2407 } 2408 2409 private: 2410 uint32_t locals_offset_ = 0; 2411 Interface interface_; 2412 2413 // The value stack, stored as individual pointers for maximum performance. 2414 Value* stack_ = nullptr; 2415 Value* stack_end_ = nullptr; 2416 Value* stack_capacity_end_ = nullptr; 2417 ASSERT_TRIVIALLY_COPYABLE(Value); 2418 2419 // stack of blocks, loops, and ifs. 2420 ZoneVector<Control> control_; 2421 2422 // Controls whether code should be generated for the current block (basically 2423 // a cache for {ok() && control_.back().reachable()}). 2424 bool current_code_reachable_and_ok_ = true; 2425 2426 // Depth of the current try block. 2427 int32_t current_catch_ = -1; 2428 2429 static Value UnreachableValue(const uint8_t* pc) { 2430 return Value{pc, kWasmBottom}; 2431 } 2432 2433 bool CheckSimdFeatureFlagOpcode(WasmOpcode opcode) { 2434 if (!FLAG_experimental_wasm_relaxed_simd && 2435 WasmOpcodes::IsRelaxedSimdOpcode(opcode)) { 2436 this->DecodeError( 2437 "simd opcode not available, enable with --experimental-relaxed-simd"); 2438 return false; 2439 } 2440 2441 return true; 2442 } 2443 2444 MemoryAccessImmediate<validate> MakeMemoryAccessImmediate( 2445 uint32_t pc_offset, uint32_t max_alignment) { 2446 return MemoryAccessImmediate<validate>( 2447 this, this->pc_ + pc_offset, max_alignment, this->module_->is_memory64); 2448 } 2449 2450#ifdef DEBUG 2451 class TraceLine { 2452 public: 2453 explicit TraceLine(WasmFullDecoder* decoder) : decoder_(decoder) { 2454 WasmOpcode opcode = static_cast<WasmOpcode>(*decoder->pc()); 2455 if (!WasmOpcodes::IsPrefixOpcode(opcode)) AppendOpcode(opcode); 2456 } 2457 2458 void AppendOpcode(WasmOpcode opcode) { 2459 DCHECK(!WasmOpcodes::IsPrefixOpcode(opcode)); 2460 Append(TRACE_INST_FORMAT, decoder_->startrel(decoder_->pc_), 2461 WasmOpcodes::OpcodeName(opcode)); 2462 } 2463 2464 ~TraceLine() { 2465 if (!FLAG_trace_wasm_decoder) return; 2466 AppendStackState(); 2467 PrintF("%.*s\n", len_, buffer_); 2468 } 2469 2470 // Appends a formatted string. 2471 PRINTF_FORMAT(2, 3) 2472 void Append(const char* format, ...) { 2473 if (!FLAG_trace_wasm_decoder) return; 2474 va_list va_args; 2475 va_start(va_args, format); 2476 size_t remaining_len = kMaxLen - len_; 2477 base::Vector<char> remaining_msg_space(buffer_ + len_, remaining_len); 2478 int len = base::VSNPrintF(remaining_msg_space, format, va_args); 2479 va_end(va_args); 2480 len_ += len < 0 ? remaining_len : len; 2481 } 2482 2483 private: 2484 void AppendStackState() { 2485 DCHECK(FLAG_trace_wasm_decoder); 2486 Append(" "); 2487 for (Control& c : decoder_->control_) { 2488 switch (c.kind) { 2489 case kControlIf: 2490 Append("I"); 2491 break; 2492 case kControlBlock: 2493 Append("B"); 2494 break; 2495 case kControlLoop: 2496 Append("L"); 2497 break; 2498 case kControlTry: 2499 Append("T"); 2500 break; 2501 case kControlIfElse: 2502 Append("E"); 2503 break; 2504 case kControlTryCatch: 2505 Append("C"); 2506 break; 2507 case kControlTryCatchAll: 2508 Append("A"); 2509 break; 2510 case kControlLet: 2511 Append("D"); 2512 break; 2513 } 2514 if (c.start_merge.arity) Append("%u-", c.start_merge.arity); 2515 Append("%u", c.end_merge.arity); 2516 if (!c.reachable()) Append("%c", c.unreachable() ? '*' : '#'); 2517 } 2518 Append(" | "); 2519 for (size_t i = 0; i < decoder_->stack_size(); ++i) { 2520 Value& val = decoder_->stack_[i]; 2521 Append(" %c", val.type.short_name()); 2522 } 2523 } 2524 2525 static constexpr int kMaxLen = 512; 2526 2527 char buffer_[kMaxLen]; 2528 int len_ = 0; 2529 WasmFullDecoder* const decoder_; 2530 }; 2531#else 2532 class TraceLine { 2533 public: 2534 explicit TraceLine(WasmFullDecoder*) {} 2535 2536 void AppendOpcode(WasmOpcode) {} 2537 2538 PRINTF_FORMAT(2, 3) 2539 void Append(const char* format, ...) {} 2540 }; 2541#endif 2542 2543#define DECODE(name) \ 2544 static int Decode##name(WasmFullDecoder* decoder, WasmOpcode opcode) { \ 2545 TraceLine trace_msg(decoder); \ 2546 return decoder->Decode##name##Impl(&trace_msg, opcode); \ 2547 } \ 2548 V8_INLINE int Decode##name##Impl(TraceLine* trace_msg, WasmOpcode opcode) 2549 2550 DECODE(Nop) { return 1; } 2551 2552 DECODE(NopForTestingUnsupportedInLiftoff) { 2553 if (!VALIDATE(FLAG_enable_testing_opcode_in_wasm)) { 2554 this->DecodeError("Invalid opcode 0x%x", opcode); 2555 return 0; 2556 } 2557 CALL_INTERFACE_IF_OK_AND_REACHABLE(NopForTestingUnsupportedInLiftoff); 2558 return 1; 2559 } 2560 2561#define BUILD_SIMPLE_OPCODE(op, _, sig) \ 2562 DECODE(op) { return BuildSimpleOperator_##sig(kExpr##op); } 2563 FOREACH_SIMPLE_NON_CONST_OPCODE(BUILD_SIMPLE_OPCODE) 2564#undef BUILD_SIMPLE_OPCODE 2565 2566#define BUILD_SIMPLE_OPCODE(op, _, sig) \ 2567 DECODE(op) { \ 2568 if (decoding_mode == kInitExpression) { \ 2569 if (!VALIDATE(this->enabled_.has_extended_const())) { \ 2570 NonConstError(this, kExpr##op); \ 2571 return 0; \ 2572 } \ 2573 } \ 2574 return BuildSimpleOperator_##sig(kExpr##op); \ 2575 } 2576 FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(BUILD_SIMPLE_OPCODE) 2577#undef BUILD_SIMPLE_OPCODE 2578 2579 DECODE(Block) { 2580 BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 2581 this->module_); 2582 if (!this->Validate(this->pc_ + 1, imm)) return 0; 2583 ArgVector args = PeekArgs(imm.sig); 2584 Control* block = PushControl(kControlBlock, 0, args.length()); 2585 SetBlockType(block, imm, args.begin()); 2586 CALL_INTERFACE_IF_OK_AND_REACHABLE(Block, block); 2587 DropArgs(imm.sig); 2588 PushMergeValues(block, &block->start_merge); 2589 return 1 + imm.length; 2590 } 2591 2592 DECODE(Rethrow) { 2593 CHECK_PROTOTYPE_OPCODE(eh); 2594 BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 2595 if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 2596 Control* c = control_at(imm.depth); 2597 if (!VALIDATE(c->is_try_catchall() || c->is_try_catch())) { 2598 this->error("rethrow not targeting catch or catch-all"); 2599 return 0; 2600 } 2601 CALL_INTERFACE_IF_OK_AND_REACHABLE(Rethrow, c); 2602 EndControl(); 2603 return 1 + imm.length; 2604 } 2605 2606 DECODE(Throw) { 2607 CHECK_PROTOTYPE_OPCODE(eh); 2608 TagIndexImmediate<validate> imm(this, this->pc_ + 1); 2609 if (!this->Validate(this->pc_ + 1, imm)) return 0; 2610 ArgVector args = PeekArgs(imm.tag->ToFunctionSig()); 2611 CALL_INTERFACE_IF_OK_AND_REACHABLE(Throw, imm, base::VectorOf(args)); 2612 DropArgs(imm.tag->ToFunctionSig()); 2613 EndControl(); 2614 return 1 + imm.length; 2615 } 2616 2617 DECODE(Try) { 2618 CHECK_PROTOTYPE_OPCODE(eh); 2619 BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 2620 this->module_); 2621 if (!this->Validate(this->pc_ + 1, imm)) return 0; 2622 ArgVector args = PeekArgs(imm.sig); 2623 Control* try_block = PushControl(kControlTry, 0, args.length()); 2624 SetBlockType(try_block, imm, args.begin()); 2625 try_block->previous_catch = current_catch_; 2626 current_catch_ = static_cast<int>(control_depth() - 1); 2627 CALL_INTERFACE_IF_OK_AND_REACHABLE(Try, try_block); 2628 DropArgs(imm.sig); 2629 PushMergeValues(try_block, &try_block->start_merge); 2630 return 1 + imm.length; 2631 } 2632 2633 DECODE(Catch) { 2634 CHECK_PROTOTYPE_OPCODE(eh); 2635 TagIndexImmediate<validate> imm(this, this->pc_ + 1); 2636 if (!this->Validate(this->pc_ + 1, imm)) return 0; 2637 DCHECK(!control_.empty()); 2638 Control* c = &control_.back(); 2639 if (!VALIDATE(c->is_try())) { 2640 this->DecodeError("catch does not match a try"); 2641 return 0; 2642 } 2643 if (!VALIDATE(!c->is_try_catchall())) { 2644 this->DecodeError("catch after catch-all for try"); 2645 return 0; 2646 } 2647 FallThrough(); 2648 c->kind = kControlTryCatch; 2649 // TODO(jkummerow): Consider moving the stack manipulation after the 2650 // INTERFACE call for consistency. 2651 DCHECK_LE(stack_ + c->stack_depth, stack_end_); 2652 stack_end_ = stack_ + c->stack_depth; 2653 c->reachability = control_at(1)->innerReachability(); 2654 const WasmTagSig* sig = imm.tag->sig; 2655 EnsureStackSpace(static_cast<int>(sig->parameter_count())); 2656 for (ValueType type : sig->parameters()) Push(CreateValue(type)); 2657 base::Vector<Value> values(stack_ + c->stack_depth, sig->parameter_count()); 2658 current_catch_ = c->previous_catch; // Pop try scope. 2659 CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(CatchException, imm, c, values); 2660 current_code_reachable_and_ok_ = this->ok() && c->reachable(); 2661 return 1 + imm.length; 2662 } 2663 2664 DECODE(Delegate) { 2665 CHECK_PROTOTYPE_OPCODE(eh); 2666 BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 2667 // -1 because the current try block is not included in the count. 2668 if (!this->Validate(this->pc_ + 1, imm, control_depth() - 1)) return 0; 2669 Control* c = &control_.back(); 2670 if (!VALIDATE(c->is_incomplete_try())) { 2671 this->DecodeError("delegate does not match a try"); 2672 return 0; 2673 } 2674 // +1 because the current try block is not included in the count. 2675 uint32_t target_depth = imm.depth + 1; 2676 while (target_depth < control_depth() - 1 && 2677 (!control_at(target_depth)->is_try() || 2678 control_at(target_depth)->is_try_catch() || 2679 control_at(target_depth)->is_try_catchall())) { 2680 target_depth++; 2681 } 2682 FallThrough(); 2683 CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(Delegate, target_depth, c); 2684 current_catch_ = c->previous_catch; 2685 EndControl(); 2686 PopControl(); 2687 return 1 + imm.length; 2688 } 2689 2690 DECODE(CatchAll) { 2691 CHECK_PROTOTYPE_OPCODE(eh); 2692 DCHECK(!control_.empty()); 2693 Control* c = &control_.back(); 2694 if (!VALIDATE(c->is_try())) { 2695 this->DecodeError("catch-all does not match a try"); 2696 return 0; 2697 } 2698 if (!VALIDATE(!c->is_try_catchall())) { 2699 this->error("catch-all already present for try"); 2700 return 0; 2701 } 2702 FallThrough(); 2703 c->kind = kControlTryCatchAll; 2704 c->reachability = control_at(1)->innerReachability(); 2705 current_catch_ = c->previous_catch; // Pop try scope. 2706 CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(CatchAll, c); 2707 stack_end_ = stack_ + c->stack_depth; 2708 current_code_reachable_and_ok_ = this->ok() && c->reachable(); 2709 return 1; 2710 } 2711 2712 DECODE(BrOnNull) { 2713 CHECK_PROTOTYPE_OPCODE(typed_funcref); 2714 BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 2715 if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 2716 Value ref_object = Peek(0); 2717 Control* c = control_at(imm.depth); 2718 if (!VALIDATE(TypeCheckBranch<true>(c, 1))) return 0; 2719 switch (ref_object.type.kind()) { 2720 case kBottom: 2721 // We are in a polymorphic stack. Leave the stack as it is. 2722 DCHECK(!current_code_reachable_and_ok_); 2723 break; 2724 case kRef: 2725 // For a non-nullable value, we won't take the branch, and can leave 2726 // the stack as it is. 2727 break; 2728 case kOptRef: { 2729 Value result = CreateValue( 2730 ValueType::Ref(ref_object.type.heap_type(), kNonNullable)); 2731 // The result of br_on_null has the same value as the argument (but a 2732 // non-nullable type). 2733 if (V8_LIKELY(current_code_reachable_and_ok_)) { 2734 CALL_INTERFACE(BrOnNull, ref_object, imm.depth, false, &result); 2735 c->br_merge()->reached = true; 2736 } 2737 // In unreachable code, we still have to push a value of the correct 2738 // type onto the stack. 2739 Drop(ref_object); 2740 Push(result); 2741 break; 2742 } 2743 default: 2744 PopTypeError(0, ref_object, "object reference"); 2745 return 0; 2746 } 2747 return 1 + imm.length; 2748 } 2749 2750 DECODE(BrOnNonNull) { 2751 CHECK_PROTOTYPE_OPCODE(gc); 2752 BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 2753 if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 2754 Value ref_object = Peek(0, 0, kWasmAnyRef); 2755 Drop(ref_object); 2756 // Typechecking the branch and creating the branch merges requires the 2757 // non-null value on the stack, so we push it temporarily. 2758 Value result = CreateValue(ref_object.type.AsNonNull()); 2759 Push(result); 2760 Control* c = control_at(imm.depth); 2761 if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 2762 switch (ref_object.type.kind()) { 2763 case kBottom: 2764 // We are in unreachable code. Do nothing. 2765 DCHECK(!current_code_reachable_and_ok_); 2766 break; 2767 case kRef: 2768 // For a non-nullable value, we always take the branch. 2769 if (V8_LIKELY(current_code_reachable_and_ok_)) { 2770 CALL_INTERFACE(Forward, ref_object, stack_value(1)); 2771 CALL_INTERFACE(BrOrRet, imm.depth, 0); 2772 // We know that the following code is not reachable, but according 2773 // to the spec it technically is. Set it to spec-only reachable. 2774 SetSucceedingCodeDynamicallyUnreachable(); 2775 c->br_merge()->reached = true; 2776 } 2777 break; 2778 case kOptRef: { 2779 if (V8_LIKELY(current_code_reachable_and_ok_)) { 2780 CALL_INTERFACE(Forward, ref_object, stack_value(1)); 2781 CALL_INTERFACE(BrOnNonNull, ref_object, imm.depth); 2782 c->br_merge()->reached = true; 2783 } 2784 break; 2785 } 2786 default: 2787 PopTypeError(0, ref_object, "object reference"); 2788 return 0; 2789 } 2790 // If we stay in the branch, {ref_object} is null. Drop it from the stack. 2791 Drop(result); 2792 return 1 + imm.length; 2793 } 2794 2795 DECODE(Let) { 2796 CHECK_PROTOTYPE_OPCODE(typed_funcref); 2797 BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 2798 this->module_); 2799 if (!this->Validate(this->pc_ + 1, imm)) return 0; 2800 // Temporarily add the let-defined values to the beginning of the function 2801 // locals. 2802 uint32_t locals_length; 2803 int new_locals_count = 2804 this->DecodeLocals(this->pc() + 1 + imm.length, &locals_length, 0); 2805 if (new_locals_count < 0) { 2806 return 0; 2807 } 2808 ArgVector let_local_values = 2809 PeekArgs(base::VectorOf(this->local_types_.data(), new_locals_count)); 2810 ArgVector args = PeekArgs(imm.sig, new_locals_count); 2811 Control* let_block = PushControl(kControlLet, new_locals_count, 2812 let_local_values.length() + args.length()); 2813 SetBlockType(let_block, imm, args.begin()); 2814 CALL_INTERFACE_IF_OK_AND_REACHABLE(Block, let_block); 2815 CALL_INTERFACE_IF_OK_AND_REACHABLE(AllocateLocals, 2816 base::VectorOf(let_local_values)); 2817 Drop(new_locals_count); // Drop {let_local_values}. 2818 DropArgs(imm.sig); // Drop {args}. 2819 PushMergeValues(let_block, &let_block->start_merge); 2820 return 1 + imm.length + locals_length; 2821 } 2822 2823 DECODE(Loop) { 2824 BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 2825 this->module_); 2826 if (!this->Validate(this->pc_ + 1, imm)) return 0; 2827 ArgVector args = PeekArgs(imm.sig); 2828 Control* block = PushControl(kControlLoop, 0, args.length()); 2829 SetBlockType(&control_.back(), imm, args.begin()); 2830 CALL_INTERFACE_IF_OK_AND_REACHABLE(Loop, block); 2831 DropArgs(imm.sig); 2832 PushMergeValues(block, &block->start_merge); 2833 return 1 + imm.length; 2834 } 2835 2836 DECODE(If) { 2837 BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 2838 this->module_); 2839 if (!this->Validate(this->pc_ + 1, imm)) return 0; 2840 Value cond = Peek(0, 0, kWasmI32); 2841 ArgVector args = PeekArgs(imm.sig, 1); 2842 if (!VALIDATE(this->ok())) return 0; 2843 Control* if_block = PushControl(kControlIf, 0, 1 + args.length()); 2844 SetBlockType(if_block, imm, args.begin()); 2845 CALL_INTERFACE_IF_OK_AND_REACHABLE(If, cond, if_block); 2846 Drop(cond); 2847 DropArgs(imm.sig); // Drop {args}. 2848 PushMergeValues(if_block, &if_block->start_merge); 2849 return 1 + imm.length; 2850 } 2851 2852 DECODE(Else) { 2853 DCHECK(!control_.empty()); 2854 Control* c = &control_.back(); 2855 if (!VALIDATE(c->is_if())) { 2856 this->DecodeError("else does not match an if"); 2857 return 0; 2858 } 2859 if (!VALIDATE(c->is_onearmed_if())) { 2860 this->DecodeError("else already present for if"); 2861 return 0; 2862 } 2863 if (!VALIDATE(TypeCheckFallThru())) return 0; 2864 c->kind = kControlIfElse; 2865 CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(Else, c); 2866 if (c->reachable()) c->end_merge.reached = true; 2867 PushMergeValues(c, &c->start_merge); 2868 c->reachability = control_at(1)->innerReachability(); 2869 current_code_reachable_and_ok_ = this->ok() && c->reachable(); 2870 return 1; 2871 } 2872 2873 DECODE(End) { 2874 DCHECK(!control_.empty()); 2875 if (decoding_mode == kFunctionBody) { 2876 Control* c = &control_.back(); 2877 if (c->is_incomplete_try()) { 2878 // Catch-less try, fall through to the implicit catch-all. 2879 c->kind = kControlTryCatch; 2880 current_catch_ = c->previous_catch; // Pop try scope. 2881 } 2882 if (c->is_try_catch()) { 2883 // Emulate catch-all + re-throw. 2884 FallThrough(); 2885 c->reachability = control_at(1)->innerReachability(); 2886 CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(CatchAll, c); 2887 current_code_reachable_and_ok_ = 2888 this->ok() && control_.back().reachable(); 2889 CALL_INTERFACE_IF_OK_AND_REACHABLE(Rethrow, c); 2890 EndControl(); 2891 PopControl(); 2892 return 1; 2893 } 2894 if (c->is_onearmed_if()) { 2895 if (!VALIDATE(TypeCheckOneArmedIf(c))) return 0; 2896 } 2897 2898 if (c->is_let()) { 2899 CALL_INTERFACE_IF_OK_AND_REACHABLE(DeallocateLocals, c->locals_count); 2900 this->local_types_.erase(this->local_types_.begin(), 2901 this->local_types_.begin() + c->locals_count); 2902 this->num_locals_ -= c->locals_count; 2903 } 2904 } 2905 2906 if (control_.size() == 1) { 2907 // We need to call this first because the interface might set 2908 // {this->end_}, making the next check pass. 2909 DoReturn<kStrictCounting, decoding_mode == kFunctionBody 2910 ? kFallthroughMerge 2911 : kInitExprMerge>(); 2912 // If at the last (implicit) control, check we are at end. 2913 if (!VALIDATE(this->pc_ + 1 == this->end_)) { 2914 this->DecodeError(this->pc_ + 1, "trailing code after function end"); 2915 return 0; 2916 } 2917 // The result of the block is the return value. 2918 trace_msg->Append("\n" TRACE_INST_FORMAT, startrel(this->pc_), 2919 "(implicit) return"); 2920 control_.clear(); 2921 return 1; 2922 } 2923 2924 if (!VALIDATE(TypeCheckFallThru())) return 0; 2925 PopControl(); 2926 return 1; 2927 } 2928 2929 DECODE(Select) { 2930 Value cond = Peek(0, 2, kWasmI32); 2931 Value fval = Peek(1); 2932 Value tval = Peek(2, 0, fval.type); 2933 ValueType type = tval.type == kWasmBottom ? fval.type : tval.type; 2934 if (!VALIDATE(!type.is_reference())) { 2935 this->DecodeError( 2936 "select without type is only valid for value type inputs"); 2937 return 0; 2938 } 2939 Value result = CreateValue(type); 2940 CALL_INTERFACE_IF_OK_AND_REACHABLE(Select, cond, fval, tval, &result); 2941 Drop(3); 2942 Push(result); 2943 return 1; 2944 } 2945 2946 DECODE(SelectWithType) { 2947 this->detected_->Add(kFeature_reftypes); 2948 SelectTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 2949 this->module_); 2950 if (this->failed()) return 0; 2951 Value cond = Peek(0, 2, kWasmI32); 2952 Value fval = Peek(1, 1, imm.type); 2953 Value tval = Peek(2, 0, imm.type); 2954 Value result = CreateValue(imm.type); 2955 CALL_INTERFACE_IF_OK_AND_REACHABLE(Select, cond, fval, tval, &result); 2956 Drop(3); 2957 Push(result); 2958 return 1 + imm.length; 2959 } 2960 2961 DECODE(Br) { 2962 BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 2963 if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 2964 Control* c = control_at(imm.depth); 2965 if (!VALIDATE(TypeCheckBranch<false>(c, 0))) return 0; 2966 if (V8_LIKELY(current_code_reachable_and_ok_)) { 2967 CALL_INTERFACE(BrOrRet, imm.depth, 0); 2968 c->br_merge()->reached = true; 2969 } 2970 EndControl(); 2971 return 1 + imm.length; 2972 } 2973 2974 DECODE(BrIf) { 2975 BranchDepthImmediate<validate> imm(this, this->pc_ + 1); 2976 if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 2977 Value cond = Peek(0, 0, kWasmI32); 2978 Control* c = control_at(imm.depth); 2979 if (!VALIDATE(TypeCheckBranch<true>(c, 1))) return 0; 2980 if (V8_LIKELY(current_code_reachable_and_ok_)) { 2981 CALL_INTERFACE(BrIf, cond, imm.depth); 2982 c->br_merge()->reached = true; 2983 } 2984 Drop(cond); 2985 return 1 + imm.length; 2986 } 2987 2988 DECODE(BrTable) { 2989 BranchTableImmediate<validate> imm(this, this->pc_ + 1); 2990 BranchTableIterator<validate> iterator(this, imm); 2991 Value key = Peek(0, 0, kWasmI32); 2992 if (this->failed()) return 0; 2993 if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0; 2994 2995 // Cache the branch targets during the iteration, so that we can set 2996 // all branch targets as reachable after the {CALL_INTERFACE} call. 2997 std::vector<bool> br_targets(control_.size()); 2998 2999 uint32_t arity = 0; 3000 3001 while (iterator.has_next()) { 3002 const uint32_t index = iterator.cur_index(); 3003 const byte* pos = iterator.pc(); 3004 const uint32_t target = iterator.next(); 3005 if (!VALIDATE(target < control_depth())) { 3006 this->DecodeError(pos, "invalid branch depth: %u", target); 3007 return 0; 3008 } 3009 // Avoid redundant branch target checks. 3010 if (br_targets[target]) continue; 3011 br_targets[target] = true; 3012 3013 if (validate) { 3014 if (index == 0) { 3015 arity = control_at(target)->br_merge()->arity; 3016 } else if (!VALIDATE(control_at(target)->br_merge()->arity == arity)) { 3017 this->DecodeError( 3018 pos, "br_table: label arity inconsistent with previous arity %d", 3019 arity); 3020 return 0; 3021 } 3022 if (!VALIDATE(TypeCheckBranch<false>(control_at(target), 1))) return 0; 3023 } 3024 } 3025 3026 if (V8_LIKELY(current_code_reachable_and_ok_)) { 3027 CALL_INTERFACE(BrTable, imm, key); 3028 3029 for (uint32_t i = 0; i < control_depth(); ++i) { 3030 control_at(i)->br_merge()->reached |= br_targets[i]; 3031 } 3032 } 3033 Drop(key); 3034 EndControl(); 3035 return 1 + iterator.length(); 3036 } 3037 3038 DECODE(Return) { 3039 return DoReturn<kNonStrictCounting, kReturnMerge>() ? 1 : 0; 3040 } 3041 3042 DECODE(Unreachable) { 3043 CALL_INTERFACE_IF_OK_AND_REACHABLE(Trap, TrapReason::kTrapUnreachable); 3044 EndControl(); 3045 return 1; 3046 } 3047 3048 DECODE(I32Const) { 3049 ImmI32Immediate<validate> imm(this, this->pc_ + 1); 3050 Value value = CreateValue(kWasmI32); 3051 CALL_INTERFACE_IF_OK_AND_REACHABLE(I32Const, &value, imm.value); 3052 Push(value); 3053 return 1 + imm.length; 3054 } 3055 3056 DECODE(I64Const) { 3057 ImmI64Immediate<validate> imm(this, this->pc_ + 1); 3058 Value value = CreateValue(kWasmI64); 3059 CALL_INTERFACE_IF_OK_AND_REACHABLE(I64Const, &value, imm.value); 3060 Push(value); 3061 return 1 + imm.length; 3062 } 3063 3064 DECODE(F32Const) { 3065 ImmF32Immediate<validate> imm(this, this->pc_ + 1); 3066 Value value = CreateValue(kWasmF32); 3067 CALL_INTERFACE_IF_OK_AND_REACHABLE(F32Const, &value, imm.value); 3068 Push(value); 3069 return 1 + imm.length; 3070 } 3071 3072 DECODE(F64Const) { 3073 ImmF64Immediate<validate> imm(this, this->pc_ + 1); 3074 Value value = CreateValue(kWasmF64); 3075 CALL_INTERFACE_IF_OK_AND_REACHABLE(F64Const, &value, imm.value); 3076 Push(value); 3077 return 1 + imm.length; 3078 } 3079 3080 DECODE(RefNull) { 3081 this->detected_->Add(kFeature_reftypes); 3082 HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1, 3083 this->module_); 3084 if (!VALIDATE(this->ok())) return 0; 3085 ValueType type = ValueType::Ref(imm.type, kNullable); 3086 Value value = CreateValue(type); 3087 CALL_INTERFACE_IF_OK_AND_REACHABLE(RefNull, type, &value); 3088 Push(value); 3089 return 1 + imm.length; 3090 } 3091 3092 DECODE(RefIsNull) { 3093 this->detected_->Add(kFeature_reftypes); 3094 Value value = Peek(0); 3095 Value result = CreateValue(kWasmI32); 3096 switch (value.type.kind()) { 3097 case kOptRef: 3098 CALL_INTERFACE_IF_OK_AND_REACHABLE(UnOp, kExprRefIsNull, value, 3099 &result); 3100 Drop(value); 3101 Push(result); 3102 return 1; 3103 case kBottom: 3104 // We are in unreachable code, the return value does not matter. 3105 case kRef: 3106 // For non-nullable references, the result is always false. 3107 CALL_INTERFACE_IF_OK_AND_REACHABLE(Drop); 3108 Drop(value); 3109 CALL_INTERFACE_IF_OK_AND_REACHABLE(I32Const, &result, 0); 3110 Push(result); 3111 return 1; 3112 default: 3113 if (validate) { 3114 PopTypeError(0, value, "reference type"); 3115 return 0; 3116 } 3117 UNREACHABLE(); 3118 } 3119 } 3120 3121 DECODE(RefFunc) { 3122 this->detected_->Add(kFeature_reftypes); 3123 IndexImmediate<validate> imm(this, this->pc_ + 1, "function index"); 3124 if (!this->ValidateFunction(this->pc_ + 1, imm)) return 0; 3125 HeapType heap_type(this->enabled_.has_typed_funcref() 3126 ? this->module_->functions[imm.index].sig_index 3127 : HeapType::kFunc); 3128 Value value = CreateValue(ValueType::Ref(heap_type, kNonNullable)); 3129 CALL_INTERFACE_IF_OK_AND_REACHABLE(RefFunc, imm.index, &value); 3130 Push(value); 3131 return 1 + imm.length; 3132 } 3133 3134 DECODE(RefAsNonNull) { 3135 CHECK_PROTOTYPE_OPCODE(typed_funcref); 3136 Value value = Peek(0); 3137 switch (value.type.kind()) { 3138 case kBottom: 3139 // We are in unreachable code. Forward the bottom value. 3140 case kRef: 3141 // A non-nullable value can remain as-is. 3142 return 1; 3143 case kOptRef: { 3144 Value result = 3145 CreateValue(ValueType::Ref(value.type.heap_type(), kNonNullable)); 3146 CALL_INTERFACE_IF_OK_AND_REACHABLE(RefAsNonNull, value, &result); 3147 Drop(value); 3148 Push(result); 3149 return 1; 3150 } 3151 default: 3152 if (validate) { 3153 PopTypeError(0, value, "reference type"); 3154 } 3155 return 0; 3156 } 3157 } 3158 3159 V8_INLINE DECODE(LocalGet) { 3160 IndexImmediate<validate> imm(this, this->pc_ + 1, "local index"); 3161 if (!this->ValidateLocal(this->pc_ + 1, imm)) return 0; 3162 if (!VALIDATE(!this->enabled_.has_nn_locals() || 3163 this->is_local_initialized(imm.index))) { 3164 this->DecodeError(this->pc_, "uninitialized non-defaultable local: %u", 3165 imm.index); 3166 return 0; 3167 } 3168 Value value = CreateValue(this->local_type(imm.index)); 3169 CALL_INTERFACE_IF_OK_AND_REACHABLE(LocalGet, &value, imm); 3170 Push(value); 3171 return 1 + imm.length; 3172 } 3173 3174 DECODE(LocalSet) { 3175 IndexImmediate<validate> imm(this, this->pc_ + 1, "local index"); 3176 if (!this->ValidateLocal(this->pc_ + 1, imm)) return 0; 3177 Value value = Peek(0, 0, this->local_type(imm.index)); 3178 CALL_INTERFACE_IF_OK_AND_REACHABLE(LocalSet, value, imm); 3179 Drop(value); 3180 this->set_local_initialized(imm.index); 3181 return 1 + imm.length; 3182 } 3183 3184 DECODE(LocalTee) { 3185 IndexImmediate<validate> imm(this, this->pc_ + 1, "local index"); 3186 if (!this->ValidateLocal(this->pc_ + 1, imm)) return 0; 3187 ValueType local_type = this->local_type(imm.index); 3188 Value value = Peek(0, 0, local_type); 3189 Value result = CreateValue(local_type); 3190 CALL_INTERFACE_IF_OK_AND_REACHABLE(LocalTee, value, &result, imm); 3191 Drop(value); 3192 Push(result); 3193 this->set_local_initialized(imm.index); 3194 return 1 + imm.length; 3195 } 3196 3197 DECODE(Drop) { 3198 Peek(0); 3199 CALL_INTERFACE_IF_OK_AND_REACHABLE(Drop); 3200 Drop(1); 3201 return 1; 3202 } 3203 3204 DECODE(GlobalGet) { 3205 GlobalIndexImmediate<validate> imm(this, this->pc_ + 1); 3206 if (!this->Validate(this->pc_ + 1, imm)) return 0; 3207 Value result = CreateValue(imm.global->type); 3208 CALL_INTERFACE_IF_OK_AND_REACHABLE(GlobalGet, &result, imm); 3209 Push(result); 3210 return 1 + imm.length; 3211 } 3212 3213 DECODE(GlobalSet) { 3214 GlobalIndexImmediate<validate> imm(this, this->pc_ + 1); 3215 if (!this->Validate(this->pc_ + 1, imm)) return 0; 3216 if (!VALIDATE(imm.global->mutability)) { 3217 this->DecodeError("immutable global #%u cannot be assigned", imm.index); 3218 return 0; 3219 } 3220 Value value = Peek(0, 0, imm.global->type); 3221 CALL_INTERFACE_IF_OK_AND_REACHABLE(GlobalSet, value, imm); 3222 Drop(value); 3223 return 1 + imm.length; 3224 } 3225 3226 DECODE(TableGet) { 3227 this->detected_->Add(kFeature_reftypes); 3228 IndexImmediate<validate> imm(this, this->pc_ + 1, "table index"); 3229 if (!this->ValidateTable(this->pc_ + 1, imm)) return 0; 3230 Value index = Peek(0, 0, kWasmI32); 3231 Value result = CreateValue(this->module_->tables[imm.index].type); 3232 CALL_INTERFACE_IF_OK_AND_REACHABLE(TableGet, index, &result, imm); 3233 Drop(index); 3234 Push(result); 3235 return 1 + imm.length; 3236 } 3237 3238 DECODE(TableSet) { 3239 this->detected_->Add(kFeature_reftypes); 3240 IndexImmediate<validate> imm(this, this->pc_ + 1, "table index"); 3241 if (!this->ValidateTable(this->pc_ + 1, imm)) return 0; 3242 Value value = Peek(0, 1, this->module_->tables[imm.index].type); 3243 Value index = Peek(1, 0, kWasmI32); 3244 CALL_INTERFACE_IF_OK_AND_REACHABLE(TableSet, index, value, imm); 3245 Drop(2); 3246 return 1 + imm.length; 3247 } 3248 3249 DECODE(LoadMem) { 3250 // Hard-code the list of load types. The opcodes are highly unlikely to 3251 // ever change, and we have some checks here to guard against that. 3252 static_assert(sizeof(LoadType) == sizeof(uint8_t), "LoadType is compact"); 3253 static constexpr uint8_t kMinOpcode = kExprI32LoadMem; 3254 static constexpr uint8_t kMaxOpcode = kExprI64LoadMem32U; 3255 static constexpr LoadType kLoadTypes[] = { 3256 LoadType::kI32Load, LoadType::kI64Load, LoadType::kF32Load, 3257 LoadType::kF64Load, LoadType::kI32Load8S, LoadType::kI32Load8U, 3258 LoadType::kI32Load16S, LoadType::kI32Load16U, LoadType::kI64Load8S, 3259 LoadType::kI64Load8U, LoadType::kI64Load16S, LoadType::kI64Load16U, 3260 LoadType::kI64Load32S, LoadType::kI64Load32U}; 3261 STATIC_ASSERT(arraysize(kLoadTypes) == kMaxOpcode - kMinOpcode + 1); 3262 DCHECK_LE(kMinOpcode, opcode); 3263 DCHECK_GE(kMaxOpcode, opcode); 3264 return DecodeLoadMem(kLoadTypes[opcode - kMinOpcode]); 3265 } 3266 3267 DECODE(StoreMem) { 3268 // Hard-code the list of store types. The opcodes are highly unlikely to 3269 // ever change, and we have some checks here to guard against that. 3270 static_assert(sizeof(StoreType) == sizeof(uint8_t), "StoreType is compact"); 3271 static constexpr uint8_t kMinOpcode = kExprI32StoreMem; 3272 static constexpr uint8_t kMaxOpcode = kExprI64StoreMem32; 3273 static constexpr StoreType kStoreTypes[] = { 3274 StoreType::kI32Store, StoreType::kI64Store, StoreType::kF32Store, 3275 StoreType::kF64Store, StoreType::kI32Store8, StoreType::kI32Store16, 3276 StoreType::kI64Store8, StoreType::kI64Store16, StoreType::kI64Store32}; 3277 STATIC_ASSERT(arraysize(kStoreTypes) == kMaxOpcode - kMinOpcode + 1); 3278 DCHECK_LE(kMinOpcode, opcode); 3279 DCHECK_GE(kMaxOpcode, opcode); 3280 return DecodeStoreMem(kStoreTypes[opcode - kMinOpcode]); 3281 } 3282 3283 DECODE(MemoryGrow) { 3284 MemoryIndexImmediate<validate> imm(this, this->pc_ + 1); 3285 if (!this->Validate(this->pc_ + 1, imm)) return 0; 3286 // This opcode will not be emitted by the asm translator. 3287 DCHECK_EQ(kWasmOrigin, this->module_->origin); 3288 ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 3289 Value value = Peek(0, 0, mem_type); 3290 Value result = CreateValue(mem_type); 3291 CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryGrow, value, &result); 3292 Drop(value); 3293 Push(result); 3294 return 1 + imm.length; 3295 } 3296 3297 DECODE(MemorySize) { 3298 MemoryIndexImmediate<validate> imm(this, this->pc_ + 1); 3299 if (!this->Validate(this->pc_ + 1, imm)) return 0; 3300 ValueType result_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 3301 Value result = CreateValue(result_type); 3302 CALL_INTERFACE_IF_OK_AND_REACHABLE(CurrentMemoryPages, &result); 3303 Push(result); 3304 return 1 + imm.length; 3305 } 3306 3307 DECODE(CallFunction) { 3308 CallFunctionImmediate<validate> imm(this, this->pc_ + 1); 3309 if (!this->Validate(this->pc_ + 1, imm)) return 0; 3310 ArgVector args = PeekArgs(imm.sig); 3311 ReturnVector returns = CreateReturnValues(imm.sig); 3312 CALL_INTERFACE_IF_OK_AND_REACHABLE(CallDirect, imm, args.begin(), 3313 returns.begin()); 3314 DropArgs(imm.sig); 3315 PushReturns(returns); 3316 return 1 + imm.length; 3317 } 3318 3319 DECODE(CallIndirect) { 3320 CallIndirectImmediate<validate> imm(this, this->pc_ + 1); 3321 if (!this->Validate(this->pc_ + 1, imm)) return 0; 3322 Value index = 3323 Peek(0, static_cast<int>(imm.sig->parameter_count()), kWasmI32); 3324 ArgVector args = PeekArgs(imm.sig, 1); 3325 ReturnVector returns = CreateReturnValues(imm.sig); 3326 CALL_INTERFACE_IF_OK_AND_REACHABLE(CallIndirect, index, imm, args.begin(), 3327 returns.begin()); 3328 Drop(index); 3329 DropArgs(imm.sig); 3330 PushReturns(returns); 3331 return 1 + imm.length; 3332 } 3333 3334 DECODE(ReturnCall) { 3335 CHECK_PROTOTYPE_OPCODE(return_call); 3336 CallFunctionImmediate<validate> imm(this, this->pc_ + 1); 3337 if (!this->Validate(this->pc_ + 1, imm)) return 0; 3338 if (!VALIDATE(this->CanReturnCall(imm.sig))) { 3339 this->DecodeError("%s: %s", WasmOpcodes::OpcodeName(kExprReturnCall), 3340 "tail call type error"); 3341 return 0; 3342 } 3343 ArgVector args = PeekArgs(imm.sig); 3344 CALL_INTERFACE_IF_OK_AND_REACHABLE(ReturnCall, imm, args.begin()); 3345 DropArgs(imm.sig); 3346 EndControl(); 3347 return 1 + imm.length; 3348 } 3349 3350 DECODE(ReturnCallIndirect) { 3351 CHECK_PROTOTYPE_OPCODE(return_call); 3352 CallIndirectImmediate<validate> imm(this, this->pc_ + 1); 3353 if (!this->Validate(this->pc_ + 1, imm)) return 0; 3354 if (!VALIDATE(this->CanReturnCall(imm.sig))) { 3355 this->DecodeError("%s: %s", 3356 WasmOpcodes::OpcodeName(kExprReturnCallIndirect), 3357 "tail call return types mismatch"); 3358 return 0; 3359 } 3360 Value index = Peek(0, 0, kWasmI32); 3361 ArgVector args = PeekArgs(imm.sig, 1); 3362 CALL_INTERFACE_IF_OK_AND_REACHABLE(ReturnCallIndirect, index, imm, 3363 args.begin()); 3364 Drop(index); 3365 DropArgs(imm.sig); 3366 EndControl(); 3367 return 1 + imm.length; 3368 } 3369 3370 DECODE(CallRef) { 3371 CHECK_PROTOTYPE_OPCODE(typed_funcref); 3372 Value func_ref = Peek(0); 3373 ValueType func_type = func_ref.type; 3374 if (func_type == kWasmBottom) { 3375 // We are in unreachable code, maintain the polymorphic stack. 3376 return 1; 3377 } 3378 if (!VALIDATE(func_type.is_object_reference() && func_type.has_index() && 3379 this->module_->has_signature(func_type.ref_index()))) { 3380 PopTypeError(0, func_ref, "function reference"); 3381 return 0; 3382 } 3383 const FunctionSig* sig = this->module_->signature(func_type.ref_index()); 3384 ArgVector args = PeekArgs(sig, 1); 3385 ReturnVector returns = CreateReturnValues(sig); 3386 CALL_INTERFACE_IF_OK_AND_REACHABLE(CallRef, func_ref, sig, 3387 func_type.ref_index(), args.begin(), 3388 returns.begin()); 3389 Drop(func_ref); 3390 DropArgs(sig); 3391 PushReturns(returns); 3392 return 1; 3393 } 3394 3395 DECODE(ReturnCallRef) { 3396 CHECK_PROTOTYPE_OPCODE(typed_funcref); 3397 CHECK_PROTOTYPE_OPCODE(return_call); 3398 Value func_ref = Peek(0); 3399 ValueType func_type = func_ref.type; 3400 if (func_type == kWasmBottom) { 3401 // We are in unreachable code, maintain the polymorphic stack. 3402 return 1; 3403 } 3404 if (!VALIDATE(func_type.is_object_reference() && func_type.has_index() && 3405 this->module_->has_signature(func_type.ref_index()))) { 3406 PopTypeError(0, func_ref, "function reference"); 3407 return 0; 3408 } 3409 const FunctionSig* sig = this->module_->signature(func_type.ref_index()); 3410 ArgVector args = PeekArgs(sig, 1); 3411 CALL_INTERFACE_IF_OK_AND_REACHABLE(ReturnCallRef, func_ref, sig, 3412 func_type.ref_index(), args.begin()); 3413 Drop(func_ref); 3414 DropArgs(sig); 3415 EndControl(); 3416 return 1; 3417 } 3418 3419 DECODE(Numeric) { 3420 uint32_t opcode_length = 0; 3421 WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>( 3422 this->pc_, &opcode_length, "numeric index"); 3423 if (full_opcode == kExprTableGrow || full_opcode == kExprTableSize || 3424 full_opcode == kExprTableFill) { 3425 this->detected_->Add(kFeature_reftypes); 3426 } 3427 trace_msg->AppendOpcode(full_opcode); 3428 return DecodeNumericOpcode(full_opcode, opcode_length); 3429 } 3430 3431 DECODE(Simd) { 3432 CHECK_PROTOTYPE_OPCODE(simd); 3433 if (!CheckHardwareSupportsSimd()) { 3434 if (FLAG_correctness_fuzzer_suppressions) { 3435 FATAL("Aborting on missing Wasm SIMD support"); 3436 } 3437 this->DecodeError("Wasm SIMD unsupported"); 3438 return 0; 3439 } 3440 uint32_t opcode_length = 0; 3441 WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>( 3442 this->pc_, &opcode_length); 3443 if (!VALIDATE(this->ok())) return 0; 3444 trace_msg->AppendOpcode(full_opcode); 3445 if (!CheckSimdFeatureFlagOpcode(full_opcode)) { 3446 return 0; 3447 } 3448 return DecodeSimdOpcode(full_opcode, opcode_length); 3449 } 3450 3451 DECODE(Atomic) { 3452 CHECK_PROTOTYPE_OPCODE(threads); 3453 uint32_t opcode_length = 0; 3454 WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>( 3455 this->pc_, &opcode_length, "atomic index"); 3456 trace_msg->AppendOpcode(full_opcode); 3457 return DecodeAtomicOpcode(full_opcode, opcode_length); 3458 } 3459 3460 DECODE(GC) { 3461 CHECK_PROTOTYPE_OPCODE(gc); 3462 uint32_t opcode_length = 0; 3463 WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>( 3464 this->pc_, &opcode_length, "gc index"); 3465 trace_msg->AppendOpcode(full_opcode); 3466 return DecodeGCOpcode(full_opcode, opcode_length); 3467 } 3468 3469#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \ 3470 DECODE(name) { return BuildSimplePrototypeOperator(opcode); } 3471 FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE) 3472#undef SIMPLE_PROTOTYPE_CASE 3473 3474 DECODE(UnknownOrAsmJs) { 3475 // Deal with special asmjs opcodes. 3476 if (!VALIDATE(is_asmjs_module(this->module_))) { 3477 this->DecodeError("Invalid opcode 0x%x", opcode); 3478 return 0; 3479 } 3480 const FunctionSig* sig = WasmOpcodes::AsmjsSignature(opcode); 3481 DCHECK_NOT_NULL(sig); 3482 return BuildSimpleOperator(opcode, sig); 3483 } 3484 3485#undef DECODE 3486 3487 static int NonConstError(WasmFullDecoder* decoder, WasmOpcode opcode) { 3488 decoder->DecodeError("opcode %s is not allowed in init. expressions", 3489 WasmOpcodes::OpcodeName(opcode)); 3490 return 0; 3491 } 3492 3493 using OpcodeHandler = int (*)(WasmFullDecoder*, WasmOpcode); 3494 3495 // Ideally we would use template specialization for the different opcodes, but 3496 // GCC does not allow to specialize templates in class scope 3497 // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282), and specializing 3498 // outside the class is not allowed for non-specialized classes. 3499 // Hence just list all implementations explicitly here, which also gives more 3500 // freedom to use the same implementation for different opcodes. 3501#define DECODE_IMPL(opcode) DECODE_IMPL2(kExpr##opcode, opcode) 3502#define DECODE_IMPL2(opcode, name) \ 3503 if (idx == opcode) { \ 3504 if (decoding_mode == kInitExpression) { \ 3505 return &WasmFullDecoder::NonConstError; \ 3506 } else { \ 3507 return &WasmFullDecoder::Decode##name; \ 3508 } \ 3509 } 3510#define DECODE_IMPL_CONST(opcode) DECODE_IMPL_CONST2(kExpr##opcode, opcode) 3511#define DECODE_IMPL_CONST2(opcode, name) \ 3512 if (idx == opcode) return &WasmFullDecoder::Decode##name 3513 3514 static constexpr OpcodeHandler GetOpcodeHandlerTableEntry(size_t idx) { 3515 DECODE_IMPL(Nop); 3516#define BUILD_SIMPLE_OPCODE(op, _, sig) DECODE_IMPL(op); 3517 FOREACH_SIMPLE_NON_CONST_OPCODE(BUILD_SIMPLE_OPCODE) 3518#undef BUILD_SIMPLE_OPCODE 3519#define BUILD_SIMPLE_EXTENDED_CONST_OPCODE(op, _, sig) DECODE_IMPL_CONST(op); 3520 FOREACH_SIMPLE_EXTENDED_CONST_OPCODE(BUILD_SIMPLE_EXTENDED_CONST_OPCODE) 3521#undef BUILD_SIMPLE_EXTENDED_CONST_OPCODE 3522 DECODE_IMPL(Block); 3523 DECODE_IMPL(Rethrow); 3524 DECODE_IMPL(Throw); 3525 DECODE_IMPL(Try); 3526 DECODE_IMPL(Catch); 3527 DECODE_IMPL(Delegate); 3528 DECODE_IMPL(CatchAll); 3529 DECODE_IMPL(BrOnNull); 3530 DECODE_IMPL(BrOnNonNull); 3531 DECODE_IMPL(Let); 3532 DECODE_IMPL(Loop); 3533 DECODE_IMPL(If); 3534 DECODE_IMPL(Else); 3535 DECODE_IMPL_CONST(End); 3536 DECODE_IMPL(Select); 3537 DECODE_IMPL(SelectWithType); 3538 DECODE_IMPL(Br); 3539 DECODE_IMPL(BrIf); 3540 DECODE_IMPL(BrTable); 3541 DECODE_IMPL(Return); 3542 DECODE_IMPL(Unreachable); 3543 DECODE_IMPL(NopForTestingUnsupportedInLiftoff); 3544 DECODE_IMPL_CONST(I32Const); 3545 DECODE_IMPL_CONST(I64Const); 3546 DECODE_IMPL_CONST(F32Const); 3547 DECODE_IMPL_CONST(F64Const); 3548 DECODE_IMPL_CONST(RefNull); 3549 DECODE_IMPL(RefIsNull); 3550 DECODE_IMPL_CONST(RefFunc); 3551 DECODE_IMPL(RefAsNonNull); 3552 DECODE_IMPL(LocalGet); 3553 DECODE_IMPL(LocalSet); 3554 DECODE_IMPL(LocalTee); 3555 DECODE_IMPL(Drop); 3556 DECODE_IMPL_CONST(GlobalGet); 3557 DECODE_IMPL(GlobalSet); 3558 DECODE_IMPL(TableGet); 3559 DECODE_IMPL(TableSet); 3560#define DECODE_LOAD_MEM(op, ...) DECODE_IMPL2(kExpr##op, LoadMem); 3561 FOREACH_LOAD_MEM_OPCODE(DECODE_LOAD_MEM) 3562#undef DECODE_LOAD_MEM 3563#define DECODE_STORE_MEM(op, ...) DECODE_IMPL2(kExpr##op, StoreMem); 3564 FOREACH_STORE_MEM_OPCODE(DECODE_STORE_MEM) 3565#undef DECODE_LOAD_MEM 3566 DECODE_IMPL(MemoryGrow); 3567 DECODE_IMPL(MemorySize); 3568 DECODE_IMPL(CallFunction); 3569 DECODE_IMPL(CallIndirect); 3570 DECODE_IMPL(ReturnCall); 3571 DECODE_IMPL(ReturnCallIndirect); 3572 DECODE_IMPL(CallRef); 3573 DECODE_IMPL(ReturnCallRef); 3574 DECODE_IMPL2(kNumericPrefix, Numeric); 3575 DECODE_IMPL_CONST2(kSimdPrefix, Simd); 3576 DECODE_IMPL2(kAtomicPrefix, Atomic); 3577 DECODE_IMPL_CONST2(kGCPrefix, GC); 3578#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) DECODE_IMPL(name); 3579 FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE) 3580#undef SIMPLE_PROTOTYPE_CASE 3581 return &WasmFullDecoder::DecodeUnknownOrAsmJs; 3582 } 3583 3584#undef DECODE_IMPL 3585#undef DECODE_IMPL2 3586 3587 OpcodeHandler GetOpcodeHandler(uint8_t opcode) { 3588 static constexpr std::array<OpcodeHandler, 256> kOpcodeHandlers = 3589 base::make_array<256>(GetOpcodeHandlerTableEntry); 3590 return kOpcodeHandlers[opcode]; 3591 } 3592 3593 void EndControl() { 3594 DCHECK(!control_.empty()); 3595 Control* current = &control_.back(); 3596 DCHECK_LE(stack_ + current->stack_depth, stack_end_); 3597 stack_end_ = stack_ + current->stack_depth; 3598 current->reachability = kUnreachable; 3599 current_code_reachable_and_ok_ = false; 3600 } 3601 3602 template <typename func> 3603 void InitMerge(Merge<Value>* merge, uint32_t arity, func get_val) { 3604 merge->arity = arity; 3605 if (arity == 1) { 3606 merge->vals.first = get_val(0); 3607 } else if (arity > 1) { 3608 merge->vals.array = this->zone()->template NewArray<Value>(arity); 3609 for (uint32_t i = 0; i < arity; i++) { 3610 merge->vals.array[i] = get_val(i); 3611 } 3612 } 3613 } 3614 3615 // Initializes start- and end-merges of {c} with values according to the 3616 // in- and out-types of {c} respectively. 3617 void SetBlockType(Control* c, BlockTypeImmediate<validate>& imm, 3618 Value* args) { 3619 const byte* pc = this->pc_; 3620 InitMerge(&c->end_merge, imm.out_arity(), [pc, &imm](uint32_t i) { 3621 return Value{pc, imm.out_type(i)}; 3622 }); 3623 InitMerge(&c->start_merge, imm.in_arity(), [&imm, args](uint32_t i) { 3624 // The merge needs to be instantiated with Values of the correct 3625 // type, even if the actual Value is bottom/unreachable or has 3626 // a subtype of the static type. 3627 // So we copy-construct a new Value, and update its type. 3628 Value value = args[i]; 3629 value.type = imm.in_type(i); 3630 return value; 3631 }); 3632 } 3633 3634 // In reachable code, check if there are at least {count} values on the stack. 3635 // In unreachable code, if there are less than {count} values on the stack, 3636 // insert a number of unreachable values underneath the current values equal 3637 // to the difference, and return that number. 3638 V8_INLINE int EnsureStackArguments(int count) { 3639 uint32_t limit = control_.back().stack_depth; 3640 if (V8_LIKELY(stack_size() >= count + limit)) return 0; 3641 return EnsureStackArguments_Slow(count, limit); 3642 } 3643 3644 V8_NOINLINE int EnsureStackArguments_Slow(int count, uint32_t limit) { 3645 if (!VALIDATE(control_.back().unreachable())) { 3646 NotEnoughArgumentsError(count, stack_size() - limit); 3647 } 3648 // Silently create unreachable values out of thin air underneath the 3649 // existing stack values. To do so, we have to move existing stack values 3650 // upwards in the stack, then instantiate the new Values as 3651 // {UnreachableValue}. 3652 int current_values = stack_size() - limit; 3653 int additional_values = count - current_values; 3654 DCHECK_GT(additional_values, 0); 3655 EnsureStackSpace(additional_values); 3656 stack_end_ += additional_values; 3657 Value* stack_base = stack_value(current_values + additional_values); 3658 for (int i = current_values - 1; i >= 0; i--) { 3659 stack_base[additional_values + i] = stack_base[i]; 3660 } 3661 for (int i = 0; i < additional_values; i++) { 3662 stack_base[i] = UnreachableValue(this->pc_); 3663 } 3664 return additional_values; 3665 } 3666 3667 // Peeks arguments as required by signature. 3668 V8_INLINE ArgVector PeekArgs(const FunctionSig* sig, int depth = 0) { 3669 int count = sig ? static_cast<int>(sig->parameter_count()) : 0; 3670 if (count == 0) return {}; 3671 EnsureStackArguments(depth + count); 3672 ArgVector args(stack_value(depth + count), count); 3673 for (int i = 0; i < count; i++) { 3674 ValidateArgType(args, i, sig->GetParam(i)); 3675 } 3676 return args; 3677 } 3678 // Drops a number of stack elements equal to the {sig}'s parameter count (0 if 3679 // {sig} is null), or all of them if less are present. 3680 V8_INLINE void DropArgs(const FunctionSig* sig) { 3681 int count = sig ? static_cast<int>(sig->parameter_count()) : 0; 3682 Drop(count); 3683 } 3684 3685 V8_INLINE ArgVector PeekArgs(const StructType* type, int depth = 0) { 3686 int count = static_cast<int>(type->field_count()); 3687 if (count == 0) return {}; 3688 EnsureStackArguments(depth + count); 3689 ArgVector args(stack_value(depth + count), count); 3690 for (int i = 0; i < count; i++) { 3691 ValidateArgType(args, i, type->field(i).Unpacked()); 3692 } 3693 return args; 3694 } 3695 // Drops a number of stack elements equal to the struct's field count, or all 3696 // of them if less are present. 3697 V8_INLINE void DropArgs(const StructType* type) { 3698 Drop(static_cast<int>(type->field_count())); 3699 } 3700 3701 V8_INLINE ArgVector PeekArgs(base::Vector<ValueType> arg_types) { 3702 int size = static_cast<int>(arg_types.size()); 3703 EnsureStackArguments(size); 3704 ArgVector args(stack_value(size), arg_types.size()); 3705 for (int i = 0; i < size; i++) { 3706 ValidateArgType(args, i, arg_types[i]); 3707 } 3708 return args; 3709 } 3710 3711 ValueType GetReturnType(const FunctionSig* sig) { 3712 DCHECK_GE(1, sig->return_count()); 3713 return sig->return_count() == 0 ? kWasmVoid : sig->GetReturn(); 3714 } 3715 3716 // TODO(jkummerow): Consider refactoring control stack management so 3717 // that {drop_values} is never needed. That would require decoupling 3718 // creation of the Control object from setting of its stack depth. 3719 Control* PushControl(ControlKind kind, uint32_t locals_count = 0, 3720 uint32_t drop_values = 0) { 3721 DCHECK(!control_.empty()); 3722 Reachability reachability = control_.back().innerReachability(); 3723 // In unreachable code, we may run out of stack. 3724 uint32_t stack_depth = 3725 stack_size() >= drop_values ? stack_size() - drop_values : 0; 3726 stack_depth = std::max(stack_depth, control_.back().stack_depth); 3727 uint32_t init_stack_depth = this->locals_initialization_stack_depth(); 3728 control_.emplace_back(kind, locals_count, stack_depth, init_stack_depth, 3729 this->pc_, reachability); 3730 current_code_reachable_and_ok_ = this->ok() && reachability == kReachable; 3731 return &control_.back(); 3732 } 3733 3734 void PopControl() { 3735 // This cannot be the outermost control block. 3736 DCHECK_LT(1, control_.size()); 3737 Control* c = &control_.back(); 3738 DCHECK_LE(stack_ + c->stack_depth, stack_end_); 3739 3740 CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(PopControl, c); 3741 3742 // - In non-unreachable code, a loop just leaves the values on the stack. 3743 // - In unreachable code, it is not guaranteed that we have Values of the 3744 // correct types on the stack, so we have to make sure we do. Their values 3745 // do not matter, so we might as well push the (uninitialized) values of 3746 // the loop's end merge. 3747 if (!c->is_loop() || c->unreachable()) { 3748 PushMergeValues(c, &c->end_merge); 3749 } 3750 this->RollbackLocalsInitialization(c->init_stack_depth); 3751 3752 bool parent_reached = 3753 c->reachable() || c->end_merge.reached || c->is_onearmed_if(); 3754 control_.pop_back(); 3755 // If the parent block was reachable before, but the popped control does not 3756 // return to here, this block becomes "spec only reachable". 3757 if (!parent_reached) SetSucceedingCodeDynamicallyUnreachable(); 3758 current_code_reachable_and_ok_ = this->ok() && control_.back().reachable(); 3759 } 3760 3761 int DecodeLoadMem(LoadType type, int prefix_len = 1) { 3762 MemoryAccessImmediate<validate> imm = 3763 MakeMemoryAccessImmediate(prefix_len, type.size_log_2()); 3764 if (!this->Validate(this->pc_ + prefix_len, imm)) return 0; 3765 ValueType index_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 3766 Value index = Peek(0, 0, index_type); 3767 Value result = CreateValue(type.value_type()); 3768 CALL_INTERFACE_IF_OK_AND_REACHABLE(LoadMem, type, imm, index, &result); 3769 Drop(index); 3770 Push(result); 3771 return prefix_len + imm.length; 3772 } 3773 3774 int DecodeLoadTransformMem(LoadType type, LoadTransformationKind transform, 3775 uint32_t opcode_length) { 3776 // Load extends always load 64-bits. 3777 uint32_t max_alignment = 3778 transform == LoadTransformationKind::kExtend ? 3 : type.size_log_2(); 3779 MemoryAccessImmediate<validate> imm = 3780 MakeMemoryAccessImmediate(opcode_length, max_alignment); 3781 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 3782 ValueType index_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 3783 Value index = Peek(0, 0, index_type); 3784 Value result = CreateValue(kWasmS128); 3785 CALL_INTERFACE_IF_OK_AND_REACHABLE(LoadTransform, type, transform, imm, 3786 index, &result); 3787 Drop(index); 3788 Push(result); 3789 return opcode_length + imm.length; 3790 } 3791 3792 int DecodeLoadLane(WasmOpcode opcode, LoadType type, uint32_t opcode_length) { 3793 MemoryAccessImmediate<validate> mem_imm = 3794 MakeMemoryAccessImmediate(opcode_length, type.size_log_2()); 3795 if (!this->Validate(this->pc_ + opcode_length, mem_imm)) return 0; 3796 SimdLaneImmediate<validate> lane_imm( 3797 this, this->pc_ + opcode_length + mem_imm.length); 3798 if (!this->Validate(this->pc_ + opcode_length, opcode, lane_imm)) return 0; 3799 Value v128 = Peek(0, 1, kWasmS128); 3800 Value index = Peek(1, 0, kWasmI32); 3801 3802 Value result = CreateValue(kWasmS128); 3803 CALL_INTERFACE_IF_OK_AND_REACHABLE(LoadLane, type, v128, index, mem_imm, 3804 lane_imm.lane, &result); 3805 Drop(2); 3806 Push(result); 3807 return opcode_length + mem_imm.length + lane_imm.length; 3808 } 3809 3810 int DecodeStoreLane(WasmOpcode opcode, StoreType type, 3811 uint32_t opcode_length) { 3812 MemoryAccessImmediate<validate> mem_imm = 3813 MakeMemoryAccessImmediate(opcode_length, type.size_log_2()); 3814 if (!this->Validate(this->pc_ + opcode_length, mem_imm)) return 0; 3815 SimdLaneImmediate<validate> lane_imm( 3816 this, this->pc_ + opcode_length + mem_imm.length); 3817 if (!this->Validate(this->pc_ + opcode_length, opcode, lane_imm)) return 0; 3818 Value v128 = Peek(0, 1, kWasmS128); 3819 Value index = Peek(1, 0, kWasmI32); 3820 3821 CALL_INTERFACE_IF_OK_AND_REACHABLE(StoreLane, type, mem_imm, index, v128, 3822 lane_imm.lane); 3823 Drop(2); 3824 return opcode_length + mem_imm.length + lane_imm.length; 3825 } 3826 3827 int DecodeStoreMem(StoreType store, int prefix_len = 1) { 3828 MemoryAccessImmediate<validate> imm = 3829 MakeMemoryAccessImmediate(prefix_len, store.size_log_2()); 3830 if (!this->Validate(this->pc_ + prefix_len, imm)) return 0; 3831 Value value = Peek(0, 1, store.value_type()); 3832 ValueType index_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 3833 Value index = Peek(1, 0, index_type); 3834 CALL_INTERFACE_IF_OK_AND_REACHABLE(StoreMem, store, imm, index, value); 3835 Drop(2); 3836 return prefix_len + imm.length; 3837 } 3838 3839 uint32_t SimdConstOp(uint32_t opcode_length) { 3840 Simd128Immediate<validate> imm(this, this->pc_ + opcode_length); 3841 Value result = CreateValue(kWasmS128); 3842 CALL_INTERFACE_IF_OK_AND_REACHABLE(S128Const, imm, &result); 3843 Push(result); 3844 return opcode_length + kSimd128Size; 3845 } 3846 3847 uint32_t SimdExtractLane(WasmOpcode opcode, ValueType type, 3848 uint32_t opcode_length) { 3849 SimdLaneImmediate<validate> imm(this, this->pc_ + opcode_length); 3850 if (this->Validate(this->pc_ + opcode_length, opcode, imm)) { 3851 Value inputs[] = {Peek(0, 0, kWasmS128)}; 3852 Value result = CreateValue(type); 3853 CALL_INTERFACE_IF_OK_AND_REACHABLE(SimdLaneOp, opcode, imm, 3854 base::ArrayVector(inputs), &result); 3855 Drop(1); 3856 Push(result); 3857 } 3858 return opcode_length + imm.length; 3859 } 3860 3861 uint32_t SimdReplaceLane(WasmOpcode opcode, ValueType type, 3862 uint32_t opcode_length) { 3863 SimdLaneImmediate<validate> imm(this, this->pc_ + opcode_length); 3864 if (this->Validate(this->pc_ + opcode_length, opcode, imm)) { 3865 Value inputs[2] = {Peek(1, 0, kWasmS128), Peek(0, 1, type)}; 3866 Value result = CreateValue(kWasmS128); 3867 CALL_INTERFACE_IF_OK_AND_REACHABLE(SimdLaneOp, opcode, imm, 3868 base::ArrayVector(inputs), &result); 3869 Drop(2); 3870 Push(result); 3871 } 3872 return opcode_length + imm.length; 3873 } 3874 3875 uint32_t Simd8x16ShuffleOp(uint32_t opcode_length) { 3876 Simd128Immediate<validate> imm(this, this->pc_ + opcode_length); 3877 if (this->Validate(this->pc_ + opcode_length, imm)) { 3878 Value input1 = Peek(0, 1, kWasmS128); 3879 Value input0 = Peek(1, 0, kWasmS128); 3880 Value result = CreateValue(kWasmS128); 3881 CALL_INTERFACE_IF_OK_AND_REACHABLE(Simd8x16ShuffleOp, imm, input0, input1, 3882 &result); 3883 Drop(2); 3884 Push(result); 3885 } 3886 return opcode_length + 16; 3887 } 3888 3889 uint32_t DecodeSimdOpcode(WasmOpcode opcode, uint32_t opcode_length) { 3890 if (decoding_mode == kInitExpression) { 3891 // Currently, only s128.const is allowed in initializer expressions. 3892 if (opcode != kExprS128Const) { 3893 this->DecodeError("opcode %s is not allowed in init. expressions", 3894 this->SafeOpcodeNameAt(this->pc())); 3895 return 0; 3896 } 3897 return SimdConstOp(opcode_length); 3898 } 3899 // opcode_length is the number of bytes that this SIMD-specific opcode takes 3900 // up in the LEB128 encoded form. 3901 switch (opcode) { 3902 case kExprF64x2ExtractLane: 3903 return SimdExtractLane(opcode, kWasmF64, opcode_length); 3904 case kExprF32x4ExtractLane: 3905 return SimdExtractLane(opcode, kWasmF32, opcode_length); 3906 case kExprI64x2ExtractLane: 3907 return SimdExtractLane(opcode, kWasmI64, opcode_length); 3908 case kExprI32x4ExtractLane: 3909 case kExprI16x8ExtractLaneS: 3910 case kExprI16x8ExtractLaneU: 3911 case kExprI8x16ExtractLaneS: 3912 case kExprI8x16ExtractLaneU: 3913 return SimdExtractLane(opcode, kWasmI32, opcode_length); 3914 case kExprF64x2ReplaceLane: 3915 return SimdReplaceLane(opcode, kWasmF64, opcode_length); 3916 case kExprF32x4ReplaceLane: 3917 return SimdReplaceLane(opcode, kWasmF32, opcode_length); 3918 case kExprI64x2ReplaceLane: 3919 return SimdReplaceLane(opcode, kWasmI64, opcode_length); 3920 case kExprI32x4ReplaceLane: 3921 case kExprI16x8ReplaceLane: 3922 case kExprI8x16ReplaceLane: 3923 return SimdReplaceLane(opcode, kWasmI32, opcode_length); 3924 case kExprI8x16Shuffle: 3925 return Simd8x16ShuffleOp(opcode_length); 3926 case kExprS128LoadMem: 3927 return DecodeLoadMem(LoadType::kS128Load, opcode_length); 3928 case kExprS128StoreMem: 3929 return DecodeStoreMem(StoreType::kS128Store, opcode_length); 3930 case kExprS128Load32Zero: 3931 return DecodeLoadTransformMem(LoadType::kI32Load, 3932 LoadTransformationKind::kZeroExtend, 3933 opcode_length); 3934 case kExprS128Load64Zero: 3935 return DecodeLoadTransformMem(LoadType::kI64Load, 3936 LoadTransformationKind::kZeroExtend, 3937 opcode_length); 3938 case kExprS128Load8Splat: 3939 return DecodeLoadTransformMem(LoadType::kI32Load8S, 3940 LoadTransformationKind::kSplat, 3941 opcode_length); 3942 case kExprS128Load16Splat: 3943 return DecodeLoadTransformMem(LoadType::kI32Load16S, 3944 LoadTransformationKind::kSplat, 3945 opcode_length); 3946 case kExprS128Load32Splat: 3947 return DecodeLoadTransformMem( 3948 LoadType::kI32Load, LoadTransformationKind::kSplat, opcode_length); 3949 case kExprS128Load64Splat: 3950 return DecodeLoadTransformMem( 3951 LoadType::kI64Load, LoadTransformationKind::kSplat, opcode_length); 3952 case kExprS128Load8x8S: 3953 return DecodeLoadTransformMem(LoadType::kI32Load8S, 3954 LoadTransformationKind::kExtend, 3955 opcode_length); 3956 case kExprS128Load8x8U: 3957 return DecodeLoadTransformMem(LoadType::kI32Load8U, 3958 LoadTransformationKind::kExtend, 3959 opcode_length); 3960 case kExprS128Load16x4S: 3961 return DecodeLoadTransformMem(LoadType::kI32Load16S, 3962 LoadTransformationKind::kExtend, 3963 opcode_length); 3964 case kExprS128Load16x4U: 3965 return DecodeLoadTransformMem(LoadType::kI32Load16U, 3966 LoadTransformationKind::kExtend, 3967 opcode_length); 3968 case kExprS128Load32x2S: 3969 return DecodeLoadTransformMem(LoadType::kI64Load32S, 3970 LoadTransformationKind::kExtend, 3971 opcode_length); 3972 case kExprS128Load32x2U: 3973 return DecodeLoadTransformMem(LoadType::kI64Load32U, 3974 LoadTransformationKind::kExtend, 3975 opcode_length); 3976 case kExprS128Load8Lane: { 3977 return DecodeLoadLane(opcode, LoadType::kI32Load8S, opcode_length); 3978 } 3979 case kExprS128Load16Lane: { 3980 return DecodeLoadLane(opcode, LoadType::kI32Load16S, opcode_length); 3981 } 3982 case kExprS128Load32Lane: { 3983 return DecodeLoadLane(opcode, LoadType::kI32Load, opcode_length); 3984 } 3985 case kExprS128Load64Lane: { 3986 return DecodeLoadLane(opcode, LoadType::kI64Load, opcode_length); 3987 } 3988 case kExprS128Store8Lane: { 3989 return DecodeStoreLane(opcode, StoreType::kI32Store8, opcode_length); 3990 } 3991 case kExprS128Store16Lane: { 3992 return DecodeStoreLane(opcode, StoreType::kI32Store16, opcode_length); 3993 } 3994 case kExprS128Store32Lane: { 3995 return DecodeStoreLane(opcode, StoreType::kI32Store, opcode_length); 3996 } 3997 case kExprS128Store64Lane: { 3998 return DecodeStoreLane(opcode, StoreType::kI64Store, opcode_length); 3999 } 4000 case kExprS128Const: 4001 return SimdConstOp(opcode_length); 4002 default: { 4003 const FunctionSig* sig = WasmOpcodes::Signature(opcode); 4004 if (!VALIDATE(sig != nullptr)) { 4005 this->DecodeError("invalid simd opcode"); 4006 return 0; 4007 } 4008 ArgVector args = PeekArgs(sig); 4009 if (sig->return_count() == 0) { 4010 CALL_INTERFACE_IF_OK_AND_REACHABLE(SimdOp, opcode, 4011 base::VectorOf(args), nullptr); 4012 DropArgs(sig); 4013 } else { 4014 ReturnVector results = CreateReturnValues(sig); 4015 CALL_INTERFACE_IF_OK_AND_REACHABLE( 4016 SimdOp, opcode, base::VectorOf(args), results.begin()); 4017 DropArgs(sig); 4018 PushReturns(results); 4019 } 4020 return opcode_length; 4021 } 4022 } 4023 } 4024 4025 // Checks if types are unrelated, thus type checking will always fail. Does 4026 // not account for nullability. 4027 bool TypeCheckAlwaysFails(Value obj, Value rtt) { 4028 return !IsSubtypeOf(ValueType::Ref(rtt.type.ref_index(), kNonNullable), 4029 obj.type, this->module_) && 4030 !IsSubtypeOf(obj.type, 4031 ValueType::Ref(rtt.type.ref_index(), kNullable), 4032 this->module_); 4033 } 4034 4035 // Checks it {obj} is a nominal type which is a subtype of {rtt}'s index, thus 4036 // checking will always succeed. Does not account for nullability. 4037 bool TypeCheckAlwaysSucceeds(Value obj, Value rtt) { 4038 return obj.type.has_index() && 4039 this->module_->has_supertype(obj.type.ref_index()) && 4040 IsSubtypeOf(obj.type, 4041 ValueType::Ref(rtt.type.ref_index(), kNullable), 4042 this->module_); 4043 } 4044 4045#define NON_CONST_ONLY \ 4046 if (decoding_mode == kInitExpression) { \ 4047 this->DecodeError("opcode %s is not allowed in init. expressions", \ 4048 this->SafeOpcodeNameAt(this->pc())); \ 4049 return 0; \ 4050 } 4051 4052 int DecodeGCOpcode(WasmOpcode opcode, uint32_t opcode_length) { 4053 switch (opcode) { 4054 case kExprStructNew: 4055 case kExprStructNewWithRtt: { 4056 StructIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 4057 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 4058 ValueType rtt_type = ValueType::Rtt(imm.index); 4059 Value rtt = opcode == kExprStructNew 4060 ? CreateValue(rtt_type) 4061 : Peek(0, imm.struct_type->field_count(), rtt_type); 4062 if (opcode == kExprStructNew) { 4063 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 4064 Push(rtt); 4065 } 4066 ArgVector args = PeekArgs(imm.struct_type, 1); 4067 Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable)); 4068 CALL_INTERFACE_IF_OK_AND_REACHABLE(StructNewWithRtt, imm, rtt, 4069 args.begin(), &value); 4070 Drop(rtt); 4071 DropArgs(imm.struct_type); 4072 Push(value); 4073 return opcode_length + imm.length; 4074 } 4075 case kExprStructNewDefault: 4076 case kExprStructNewDefaultWithRtt: { 4077 StructIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 4078 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 4079 if (validate) { 4080 for (uint32_t i = 0; i < imm.struct_type->field_count(); i++) { 4081 ValueType ftype = imm.struct_type->field(i); 4082 if (!VALIDATE(ftype.is_defaultable())) { 4083 this->DecodeError( 4084 "%s: struct type %d has field %d of non-defaultable type %s", 4085 WasmOpcodes::OpcodeName(opcode), imm.index, i, 4086 ftype.name().c_str()); 4087 return 0; 4088 } 4089 } 4090 } 4091 ValueType rtt_type = ValueType::Rtt(imm.index); 4092 Value rtt = opcode == kExprStructNewDefault ? CreateValue(rtt_type) 4093 : Peek(0, 0, rtt_type); 4094 if (opcode == kExprStructNewDefault) { 4095 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 4096 Push(rtt); 4097 } 4098 Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable)); 4099 CALL_INTERFACE_IF_OK_AND_REACHABLE(StructNewDefault, imm, rtt, &value); 4100 Drop(rtt); 4101 Push(value); 4102 return opcode_length + imm.length; 4103 } 4104 case kExprStructGet: { 4105 NON_CONST_ONLY 4106 FieldImmediate<validate> field(this, this->pc_ + opcode_length); 4107 if (!this->Validate(this->pc_ + opcode_length, field)) return 0; 4108 ValueType field_type = 4109 field.struct_imm.struct_type->field(field.field_imm.index); 4110 if (!VALIDATE(!field_type.is_packed())) { 4111 this->DecodeError( 4112 "struct.get: Immediate field %d of type %d has packed type %s. " 4113 "Use struct.get_s or struct.get_u instead.", 4114 field.field_imm.index, field.struct_imm.index, 4115 field_type.name().c_str()); 4116 return 0; 4117 } 4118 Value struct_obj = 4119 Peek(0, 0, ValueType::Ref(field.struct_imm.index, kNullable)); 4120 Value value = CreateValue(field_type); 4121 CALL_INTERFACE_IF_OK_AND_REACHABLE(StructGet, struct_obj, field, true, 4122 &value); 4123 Drop(struct_obj); 4124 Push(value); 4125 return opcode_length + field.length; 4126 } 4127 case kExprStructGetU: 4128 case kExprStructGetS: { 4129 NON_CONST_ONLY 4130 FieldImmediate<validate> field(this, this->pc_ + opcode_length); 4131 if (!this->Validate(this->pc_ + opcode_length, field)) return 0; 4132 ValueType field_type = 4133 field.struct_imm.struct_type->field(field.field_imm.index); 4134 if (!VALIDATE(field_type.is_packed())) { 4135 this->DecodeError( 4136 "%s: Immediate field %d of type %d has non-packed type %s. Use " 4137 "struct.get instead.", 4138 WasmOpcodes::OpcodeName(opcode), field.field_imm.index, 4139 field.struct_imm.index, field_type.name().c_str()); 4140 return 0; 4141 } 4142 Value struct_obj = 4143 Peek(0, 0, ValueType::Ref(field.struct_imm.index, kNullable)); 4144 Value value = CreateValue(field_type.Unpacked()); 4145 CALL_INTERFACE_IF_OK_AND_REACHABLE(StructGet, struct_obj, field, 4146 opcode == kExprStructGetS, &value); 4147 Drop(struct_obj); 4148 Push(value); 4149 return opcode_length + field.length; 4150 } 4151 case kExprStructSet: { 4152 NON_CONST_ONLY 4153 FieldImmediate<validate> field(this, this->pc_ + opcode_length); 4154 if (!this->Validate(this->pc_ + opcode_length, field)) return 0; 4155 const StructType* struct_type = field.struct_imm.struct_type; 4156 if (!VALIDATE(struct_type->mutability(field.field_imm.index))) { 4157 this->DecodeError("struct.set: Field %d of type %d is immutable.", 4158 field.field_imm.index, field.struct_imm.index); 4159 return 0; 4160 } 4161 Value field_value = 4162 Peek(0, 1, struct_type->field(field.field_imm.index).Unpacked()); 4163 Value struct_obj = 4164 Peek(1, 0, ValueType::Ref(field.struct_imm.index, kNullable)); 4165 CALL_INTERFACE_IF_OK_AND_REACHABLE(StructSet, struct_obj, field, 4166 field_value); 4167 Drop(2); 4168 return opcode_length + field.length; 4169 } 4170 case kExprArrayNew: 4171 case kExprArrayNewWithRtt: { 4172 NON_CONST_ONLY 4173 ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 4174 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 4175 ValueType rtt_type = ValueType::Rtt(imm.index); 4176 Value rtt = opcode == kExprArrayNew ? CreateValue(rtt_type) 4177 : Peek(0, 2, rtt_type); 4178 if (opcode == kExprArrayNew) { 4179 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 4180 Push(rtt); 4181 } 4182 Value length = Peek(1, 1, kWasmI32); 4183 Value initial_value = 4184 Peek(2, 0, imm.array_type->element_type().Unpacked()); 4185 Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable)); 4186 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayNewWithRtt, imm, length, 4187 initial_value, rtt, &value); 4188 Drop(3); // rtt, length, initial_value. 4189 Push(value); 4190 return opcode_length + imm.length; 4191 } 4192 case kExprArrayNewDefault: 4193 case kExprArrayNewDefaultWithRtt: { 4194 NON_CONST_ONLY 4195 ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 4196 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 4197 if (!VALIDATE(imm.array_type->element_type().is_defaultable())) { 4198 this->DecodeError( 4199 "%s: array type %d has non-defaultable element type %s", 4200 WasmOpcodes::OpcodeName(opcode), imm.index, 4201 imm.array_type->element_type().name().c_str()); 4202 return 0; 4203 } 4204 ValueType rtt_type = ValueType::Rtt(imm.index); 4205 Value rtt = opcode == kExprArrayNewDefault ? CreateValue(rtt_type) 4206 : Peek(0, 1, rtt_type); 4207 if (opcode == kExprArrayNewDefault) { 4208 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 4209 Push(rtt); 4210 } 4211 Value length = Peek(1, 0, kWasmI32); 4212 Value value = CreateValue(ValueType::Ref(imm.index, kNonNullable)); 4213 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayNewDefault, imm, length, rtt, 4214 &value); 4215 Drop(2); // rtt, length 4216 Push(value); 4217 return opcode_length + imm.length; 4218 } 4219 case kExprArrayInitFromData: 4220 case kExprArrayInitFromDataStatic: { 4221 ArrayIndexImmediate<validate> array_imm(this, 4222 this->pc_ + opcode_length); 4223 if (!this->Validate(this->pc_ + opcode_length, array_imm)) return 0; 4224 ValueType element_type = array_imm.array_type->element_type(); 4225 if (element_type.is_reference()) { 4226 this->DecodeError( 4227 "array.init_from_data can only be used with value-type arrays, " 4228 "found array type #%d instead", 4229 array_imm.index); 4230 return 0; 4231 } 4232#if V8_TARGET_BIG_ENDIAN 4233 // Byte sequences in data segments are interpreted as little endian for 4234 // the purposes of this instruction. This means that those will have to 4235 // be transformed in big endian architectures. TODO(7748): Implement. 4236 if (element_type.value_kind_size() > 1) { 4237 UNIMPLEMENTED(); 4238 } 4239#endif 4240 const byte* data_index_pc = 4241 this->pc_ + opcode_length + array_imm.length; 4242 IndexImmediate<validate> data_segment(this, data_index_pc, 4243 "data segment"); 4244 if (!this->ValidateDataSegment(data_index_pc, data_segment)) return 0; 4245 4246 ValueType rtt_type = ValueType::Rtt(array_imm.index); 4247 Value rtt = opcode == kExprArrayInitFromDataStatic 4248 ? CreateValue(rtt_type) 4249 : Peek(0, 2, rtt_type); 4250 if (opcode == kExprArrayInitFromDataStatic) { 4251 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, array_imm.index, &rtt); 4252 Push(rtt); 4253 } 4254 4255 Value length = Peek(1, 1, kWasmI32); 4256 Value offset = Peek(2, 0, kWasmI32); 4257 4258 Value array = 4259 CreateValue(ValueType::Ref(array_imm.index, kNonNullable)); 4260 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayInitFromData, array_imm, 4261 data_segment, offset, length, rtt, 4262 &array); 4263 Drop(3); // rtt, length, offset 4264 Push(array); 4265 return opcode_length + array_imm.length + data_segment.length; 4266 } 4267 case kExprArrayGetS: 4268 case kExprArrayGetU: { 4269 NON_CONST_ONLY 4270 ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 4271 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 4272 if (!VALIDATE(imm.array_type->element_type().is_packed())) { 4273 this->DecodeError( 4274 "%s: Immediate array type %d has non-packed type %s. Use " 4275 "array.get instead.", 4276 WasmOpcodes::OpcodeName(opcode), imm.index, 4277 imm.array_type->element_type().name().c_str()); 4278 return 0; 4279 } 4280 Value index = Peek(0, 1, kWasmI32); 4281 Value array_obj = Peek(1, 0, ValueType::Ref(imm.index, kNullable)); 4282 Value value = CreateValue(imm.array_type->element_type().Unpacked()); 4283 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayGet, array_obj, imm, index, 4284 opcode == kExprArrayGetS, &value); 4285 Drop(2); // index, array_obj 4286 Push(value); 4287 return opcode_length + imm.length; 4288 } 4289 case kExprArrayGet: { 4290 NON_CONST_ONLY 4291 ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 4292 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 4293 if (!VALIDATE(!imm.array_type->element_type().is_packed())) { 4294 this->DecodeError( 4295 "array.get: Immediate array type %d has packed type %s. Use " 4296 "array.get_s or array.get_u instead.", 4297 imm.index, imm.array_type->element_type().name().c_str()); 4298 return 0; 4299 } 4300 Value index = Peek(0, 1, kWasmI32); 4301 Value array_obj = Peek(1, 0, ValueType::Ref(imm.index, kNullable)); 4302 Value value = CreateValue(imm.array_type->element_type()); 4303 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayGet, array_obj, imm, index, 4304 true, &value); 4305 Drop(2); // index, array_obj 4306 Push(value); 4307 return opcode_length + imm.length; 4308 } 4309 case kExprArraySet: { 4310 NON_CONST_ONLY 4311 ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 4312 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 4313 if (!VALIDATE(imm.array_type->mutability())) { 4314 this->DecodeError("array.set: immediate array type %d is immutable", 4315 imm.index); 4316 return 0; 4317 } 4318 Value value = Peek(0, 2, imm.array_type->element_type().Unpacked()); 4319 Value index = Peek(1, 1, kWasmI32); 4320 Value array_obj = Peek(2, 0, ValueType::Ref(imm.index, kNullable)); 4321 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArraySet, array_obj, imm, index, 4322 value); 4323 Drop(3); 4324 return opcode_length + imm.length; 4325 } 4326 case kExprArrayLen: { 4327 NON_CONST_ONLY 4328 // Read but ignore an immediate array type index. 4329 // TODO(7748): Remove this once we are ready to make breaking changes. 4330 ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 4331 Value array_obj = 4332 Peek(0, 0, ValueType::Ref(HeapType::kArray, kNullable)); 4333 Value value = CreateValue(kWasmI32); 4334 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayLen, array_obj, &value); 4335 Drop(array_obj); 4336 Push(value); 4337 return opcode_length + imm.length; 4338 } 4339 case kExprArrayCopy: { 4340 NON_CONST_ONLY 4341 ArrayIndexImmediate<validate> dst_imm(this, this->pc_ + opcode_length); 4342 if (!this->Validate(this->pc_ + opcode_length, dst_imm)) return 0; 4343 if (!VALIDATE(dst_imm.array_type->mutability())) { 4344 this->DecodeError( 4345 "array.copy: immediate destination array type #%d is immutable", 4346 dst_imm.index); 4347 return 0; 4348 } 4349 ArrayIndexImmediate<validate> src_imm( 4350 this, this->pc_ + opcode_length + dst_imm.length); 4351 if (!this->Validate(this->pc_ + opcode_length + dst_imm.length, 4352 src_imm)) { 4353 return 0; 4354 } 4355 if (!IsSubtypeOf(src_imm.array_type->element_type(), 4356 dst_imm.array_type->element_type(), this->module_)) { 4357 this->DecodeError( 4358 "array.copy: source array's #%d element type is not a subtype of " 4359 "destination array's #%d element type", 4360 src_imm.index, dst_imm.index); 4361 return 0; 4362 } 4363 // [dst, dst_index, src, src_index, length] 4364 Value dst = Peek(4, 0, ValueType::Ref(dst_imm.index, kNullable)); 4365 Value dst_index = Peek(3, 1, kWasmI32); 4366 Value src = Peek(2, 2, ValueType::Ref(src_imm.index, kNullable)); 4367 Value src_index = Peek(1, 3, kWasmI32); 4368 Value length = Peek(0, 4, kWasmI32); 4369 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayCopy, dst, dst_index, src, 4370 src_index, length); 4371 Drop(5); 4372 return opcode_length + dst_imm.length + src_imm.length; 4373 } 4374 case kExprArrayInit: 4375 case kExprArrayInitStatic: { 4376 ArrayIndexImmediate<validate> array_imm(this, 4377 this->pc_ + opcode_length); 4378 if (!this->Validate(this->pc_ + opcode_length, array_imm)) return 0; 4379 IndexImmediate<validate> length_imm( 4380 this, this->pc_ + opcode_length + array_imm.length, 4381 "array.init length"); 4382 uint32_t elem_count = length_imm.index; 4383 if (!VALIDATE(elem_count <= kV8MaxWasmArrayInitLength)) { 4384 this->DecodeError( 4385 "Requested length %u for array.init too large, maximum is %zu", 4386 length_imm.index, kV8MaxWasmArrayInitLength); 4387 return 0; 4388 } 4389 Value rtt = opcode == kExprArrayInit 4390 ? Peek(0, elem_count, ValueType::Rtt(array_imm.index)) 4391 : CreateValue(ValueType::Rtt(array_imm.index)); 4392 if (opcode == kExprArrayInitStatic) { 4393 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, array_imm.index, &rtt); 4394 Push(rtt); 4395 } 4396 ValueType element_type = array_imm.array_type->element_type(); 4397 std::vector<ValueType> element_types(elem_count, 4398 element_type.Unpacked()); 4399 FunctionSig element_sig(0, elem_count, element_types.data()); 4400 ArgVector elements = PeekArgs(&element_sig, 1); 4401 Value result = 4402 CreateValue(ValueType::Ref(array_imm.index, kNonNullable)); 4403 CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayInit, array_imm, elements, rtt, 4404 &result); 4405 Drop(elem_count + 1); 4406 Push(result); 4407 return opcode_length + array_imm.length + length_imm.length; 4408 } 4409 case kExprI31New: { 4410 NON_CONST_ONLY 4411 Value input = Peek(0, 0, kWasmI32); 4412 Value value = CreateValue(kWasmI31Ref); 4413 CALL_INTERFACE_IF_OK_AND_REACHABLE(I31New, input, &value); 4414 Drop(input); 4415 Push(value); 4416 return opcode_length; 4417 } 4418 case kExprI31GetS: { 4419 NON_CONST_ONLY 4420 Value i31 = Peek(0, 0, kWasmI31Ref); 4421 Value value = CreateValue(kWasmI32); 4422 CALL_INTERFACE_IF_OK_AND_REACHABLE(I31GetS, i31, &value); 4423 Drop(i31); 4424 Push(value); 4425 return opcode_length; 4426 } 4427 case kExprI31GetU: { 4428 NON_CONST_ONLY 4429 Value i31 = Peek(0, 0, kWasmI31Ref); 4430 Value value = CreateValue(kWasmI32); 4431 CALL_INTERFACE_IF_OK_AND_REACHABLE(I31GetU, i31, &value); 4432 Drop(i31); 4433 Push(value); 4434 return opcode_length; 4435 } 4436 case kExprRttCanon: { 4437 IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 4438 "type index"); 4439 if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 4440 Value value = CreateValue(ValueType::Rtt(imm.index)); 4441 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &value); 4442 Push(value); 4443 return opcode_length + imm.length; 4444 } 4445 case kExprRefTest: 4446 case kExprRefTestStatic: { 4447 NON_CONST_ONLY 4448 // "Tests whether {obj}'s runtime type is a runtime subtype of {rtt}." 4449 Value rtt = Peek(0); // This is safe for the ...Static instruction. 4450 if (opcode == kExprRefTestStatic) { 4451 IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 4452 "type index"); 4453 if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 4454 opcode_length += imm.length; 4455 rtt = CreateValue(ValueType::Rtt(imm.index)); 4456 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 4457 Push(rtt); 4458 } else { 4459 DCHECK_EQ(opcode, kExprRefTest); 4460 if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) { 4461 PopTypeError(1, rtt, "rtt"); 4462 return 0; 4463 } 4464 } 4465 Value obj = Peek(1); 4466 Value value = CreateValue(kWasmI32); 4467 if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) || 4468 IsSubtypeOf(obj.type, 4469 ValueType::Ref(HeapType::kData, kNullable), 4470 this->module_) || 4471 obj.type.is_bottom())) { 4472 PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)"); 4473 return 0; 4474 } 4475 if (current_code_reachable_and_ok_) { 4476 // This logic ensures that code generation can assume that functions 4477 // can only be cast to function types, and data objects to data types. 4478 if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) { 4479 // Drop rtt. 4480 CALL_INTERFACE(Drop); 4481 // Type checking can still fail for null. 4482 if (obj.type.is_nullable()) { 4483 // We abuse ref.as_non_null, which isn't otherwise used as a unary 4484 // operator, as a sentinel for the negation of ref.is_null. 4485 CALL_INTERFACE(UnOp, kExprRefAsNonNull, obj, &value); 4486 } else { 4487 CALL_INTERFACE(Drop); 4488 CALL_INTERFACE(I32Const, &value, 1); 4489 } 4490 } else if (V8_UNLIKELY(TypeCheckAlwaysFails(obj, rtt))) { 4491 CALL_INTERFACE(Drop); 4492 CALL_INTERFACE(Drop); 4493 CALL_INTERFACE(I32Const, &value, 0); 4494 } else { 4495 CALL_INTERFACE(RefTest, obj, rtt, &value); 4496 } 4497 } 4498 Drop(2); 4499 Push(value); 4500 return opcode_length; 4501 } 4502 case kExprRefCast: 4503 case kExprRefCastStatic: { 4504 NON_CONST_ONLY 4505 Value rtt = Peek(0); // This is safe for the ...Static instruction. 4506 if (opcode == kExprRefCastStatic) { 4507 IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 4508 "type index"); 4509 if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 4510 opcode_length += imm.length; 4511 rtt = CreateValue(ValueType::Rtt(imm.index)); 4512 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 4513 Push(rtt); 4514 } else { 4515 DCHECK_EQ(opcode, kExprRefCast); 4516 if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) { 4517 PopTypeError(1, rtt, "rtt"); 4518 return 0; 4519 } 4520 } 4521 Value obj = Peek(1); 4522 if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) || 4523 IsSubtypeOf(obj.type, 4524 ValueType::Ref(HeapType::kData, kNullable), 4525 this->module_) || 4526 obj.type.is_bottom())) { 4527 PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)"); 4528 return 0; 4529 } 4530 // If either value is bottom, we emit the most specific type possible. 4531 Value value = 4532 CreateValue(rtt.type.is_bottom() 4533 ? kWasmBottom 4534 : ValueType::Ref(rtt.type.ref_index(), 4535 obj.type.is_bottom() 4536 ? kNonNullable 4537 : obj.type.nullability())); 4538 if (current_code_reachable_and_ok_) { 4539 // This logic ensures that code generation can assume that functions 4540 // can only be cast to function types, and data objects to data types. 4541 if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) { 4542 // Drop the rtt from the stack, then forward the object value to the 4543 // result. 4544 CALL_INTERFACE(Drop); 4545 CALL_INTERFACE(Forward, obj, &value); 4546 } else if (V8_UNLIKELY(TypeCheckAlwaysFails(obj, rtt))) { 4547 // Unrelated types. The only way this will not trap is if the object 4548 // is null. 4549 if (obj.type.is_nullable()) { 4550 // Drop rtt from the stack, then assert that obj is null. 4551 CALL_INTERFACE(Drop); 4552 CALL_INTERFACE(AssertNull, obj, &value); 4553 } else { 4554 CALL_INTERFACE(Trap, TrapReason::kTrapIllegalCast); 4555 // We know that the following code is not reachable, but according 4556 // to the spec it technically is. Set it to spec-only reachable. 4557 SetSucceedingCodeDynamicallyUnreachable(); 4558 } 4559 } else { 4560 CALL_INTERFACE(RefCast, obj, rtt, &value); 4561 } 4562 } 4563 Drop(2); 4564 Push(value); 4565 return opcode_length; 4566 } 4567 case kExprBrOnCast: 4568 case kExprBrOnCastStatic: { 4569 NON_CONST_ONLY 4570 BranchDepthImmediate<validate> branch_depth(this, 4571 this->pc_ + opcode_length); 4572 if (!this->Validate(this->pc_ + opcode_length, branch_depth, 4573 control_.size())) { 4574 return 0; 4575 } 4576 uint32_t pc_offset = opcode_length + branch_depth.length; 4577 Value rtt = Peek(0); // This is safe for the ...Static instruction. 4578 if (opcode == kExprBrOnCastStatic) { 4579 IndexImmediate<validate> imm(this, this->pc_ + pc_offset, 4580 "type index"); 4581 if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 4582 pc_offset += imm.length; 4583 rtt = CreateValue(ValueType::Rtt(imm.index)); 4584 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 4585 Push(rtt); 4586 } else { 4587 DCHECK_EQ(opcode, kExprBrOnCast); 4588 if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) { 4589 PopTypeError(1, rtt, "rtt"); 4590 return 0; 4591 } 4592 } 4593 Value obj = Peek(1); 4594 if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) || 4595 IsSubtypeOf(obj.type, 4596 ValueType::Ref(HeapType::kData, kNullable), 4597 this->module_) || 4598 obj.type.is_bottom())) { 4599 PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)"); 4600 return 0; 4601 } 4602 Control* c = control_at(branch_depth.depth); 4603 if (c->br_merge()->arity == 0) { 4604 this->DecodeError( 4605 "br_on_cast must target a branch of arity at least 1"); 4606 return 0; 4607 } 4608 // Attention: contrary to most other instructions, we modify the 4609 // stack before calling the interface function. This makes it 4610 // significantly more convenient to pass around the values that 4611 // will be on the stack when the branch is taken. 4612 // TODO(jkummerow): Reconsider this choice. 4613 Drop(2); // {obj} and {rtt}. 4614 Value result_on_branch = CreateValue( 4615 rtt.type.is_bottom() 4616 ? kWasmBottom 4617 : ValueType::Ref(rtt.type.ref_index(), kNonNullable)); 4618 Push(result_on_branch); 4619 // The {value_on_branch} parameter we pass to the interface must 4620 // be pointer-identical to the object on the stack, so we can't 4621 // reuse {result_on_branch} which was passed-by-value to {Push}. 4622 Value* value_on_branch = stack_value(1); 4623 if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 4624 if (V8_LIKELY(current_code_reachable_and_ok_)) { 4625 // This logic ensures that code generation can assume that functions 4626 // can only be cast to function types, and data objects to data types. 4627 if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) { 4628 CALL_INTERFACE(Drop); // rtt 4629 CALL_INTERFACE(Forward, obj, value_on_branch); 4630 // The branch will still not be taken on null. 4631 if (obj.type.is_nullable()) { 4632 CALL_INTERFACE(BrOnNonNull, obj, branch_depth.depth); 4633 } else { 4634 CALL_INTERFACE(BrOrRet, branch_depth.depth, 0); 4635 // We know that the following code is not reachable, but according 4636 // to the spec it technically is. Set it to spec-only reachable. 4637 SetSucceedingCodeDynamicallyUnreachable(); 4638 } 4639 c->br_merge()->reached = true; 4640 } else if (V8_LIKELY(!TypeCheckAlwaysFails(obj, rtt))) { 4641 CALL_INTERFACE(BrOnCast, obj, rtt, value_on_branch, 4642 branch_depth.depth); 4643 c->br_merge()->reached = true; 4644 } 4645 // Otherwise the types are unrelated. Do not branch. 4646 } 4647 4648 Drop(result_on_branch); 4649 Push(obj); // Restore stack state on fallthrough. 4650 return pc_offset; 4651 } 4652 case kExprBrOnCastFail: 4653 case kExprBrOnCastStaticFail: { 4654 NON_CONST_ONLY 4655 BranchDepthImmediate<validate> branch_depth(this, 4656 this->pc_ + opcode_length); 4657 if (!this->Validate(this->pc_ + opcode_length, branch_depth, 4658 control_.size())) { 4659 return 0; 4660 } 4661 uint32_t pc_offset = opcode_length + branch_depth.length; 4662 Value rtt = Peek(0); // This is safe for the ...Static instruction. 4663 if (opcode == kExprBrOnCastStaticFail) { 4664 IndexImmediate<validate> imm(this, this->pc_ + pc_offset, 4665 "type index"); 4666 if (!this->ValidateType(this->pc_ + opcode_length, imm)) return 0; 4667 pc_offset += imm.length; 4668 rtt = CreateValue(ValueType::Rtt(imm.index)); 4669 CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt); 4670 Push(rtt); 4671 } else { 4672 DCHECK_EQ(opcode, kExprBrOnCastFail); 4673 if (!VALIDATE(rtt.type.is_rtt() || rtt.type.is_bottom())) { 4674 PopTypeError(1, rtt, "rtt"); 4675 return 0; 4676 } 4677 } 4678 Value obj = Peek(1); 4679 if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) || 4680 IsSubtypeOf(obj.type, 4681 ValueType::Ref(HeapType::kData, kNullable), 4682 this->module_) || 4683 obj.type.is_bottom())) { 4684 PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)"); 4685 return 0; 4686 } 4687 Control* c = control_at(branch_depth.depth); 4688 if (c->br_merge()->arity == 0) { 4689 this->DecodeError( 4690 "br_on_cast_fail must target a branch of arity at least 1"); 4691 return 0; 4692 } 4693 // Attention: contrary to most other instructions, we modify the stack 4694 // before calling the interface function. This makes it significantly 4695 // more convenient to pass around the values that will be on the stack 4696 // when the branch is taken. In this case, we leave {obj} on the stack 4697 // to type check the branch. 4698 // TODO(jkummerow): Reconsider this choice. 4699 Drop(rtt); 4700 if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 4701 Value result_on_fallthrough = CreateValue( 4702 rtt.type.is_bottom() 4703 ? kWasmBottom 4704 : ValueType::Ref(rtt.type.ref_index(), kNonNullable)); 4705 if (V8_LIKELY(current_code_reachable_and_ok_)) { 4706 // This logic ensures that code generation can assume that functions 4707 // can only be cast to function types, and data objects to data types. 4708 if (V8_UNLIKELY(TypeCheckAlwaysFails(obj, rtt))) { 4709 // Drop {rtt} in the interface. 4710 CALL_INTERFACE(Drop); 4711 // Otherwise the types are unrelated. Always branch. 4712 CALL_INTERFACE(BrOrRet, branch_depth.depth, 0); 4713 // We know that the following code is not reachable, but according 4714 // to the spec it technically is. Set it to spec-only reachable. 4715 SetSucceedingCodeDynamicallyUnreachable(); 4716 c->br_merge()->reached = true; 4717 } else if (V8_UNLIKELY(TypeCheckAlwaysSucceeds(obj, rtt))) { 4718 // Drop {rtt} in the interface. 4719 CALL_INTERFACE(Drop); 4720 // The branch can still be taken on null. 4721 if (obj.type.is_nullable()) { 4722 CALL_INTERFACE(BrOnNull, obj, branch_depth.depth, true, 4723 &result_on_fallthrough); 4724 c->br_merge()->reached = true; 4725 } else { 4726 // Drop {obj} in the interface. 4727 CALL_INTERFACE(Drop); 4728 } 4729 } else { 4730 CALL_INTERFACE(BrOnCastFail, obj, rtt, &result_on_fallthrough, 4731 branch_depth.depth); 4732 c->br_merge()->reached = true; 4733 } 4734 // Otherwise, the type check always succeeds. Do not branch. 4735 } 4736 // Make sure the correct value is on the stack state on fallthrough. 4737 Drop(obj); 4738 Push(result_on_fallthrough); 4739 return pc_offset; 4740 } 4741#define ABSTRACT_TYPE_CHECK(h_type) \ 4742 case kExprRefIs##h_type: { \ 4743 NON_CONST_ONLY \ 4744 Value arg = Peek(0, 0, kWasmAnyRef); \ 4745 if (this->failed()) return 0; \ 4746 Value result = CreateValue(kWasmI32); \ 4747 if (V8_LIKELY(current_code_reachable_and_ok_)) { \ 4748 if (IsHeapSubtypeOf(arg.type.heap_representation(), HeapType::k##h_type, \ 4749 this->module_)) { \ 4750 if (arg.type.is_nullable()) { \ 4751 /* We abuse ref.as_non_null, which isn't otherwise used as a unary \ 4752 * operator, as a sentinel for the negation of ref.is_null. */ \ 4753 CALL_INTERFACE(UnOp, kExprRefAsNonNull, arg, &result); \ 4754 } else { \ 4755 CALL_INTERFACE(Drop); \ 4756 CALL_INTERFACE(I32Const, &result, 1); \ 4757 } \ 4758 } else if (!IsHeapSubtypeOf(HeapType::k##h_type, \ 4759 arg.type.heap_representation(), \ 4760 this->module_)) { \ 4761 CALL_INTERFACE(Drop); \ 4762 CALL_INTERFACE(I32Const, &result, 0); \ 4763 } else { \ 4764 CALL_INTERFACE(RefIs##h_type, arg, &result); \ 4765 } \ 4766 } \ 4767 Drop(arg); \ 4768 Push(result); \ 4769 return opcode_length; \ 4770 } 4771 ABSTRACT_TYPE_CHECK(Data) 4772 ABSTRACT_TYPE_CHECK(Func) 4773 ABSTRACT_TYPE_CHECK(I31) 4774 ABSTRACT_TYPE_CHECK(Array) 4775#undef ABSTRACT_TYPE_CHECK 4776 4777#define ABSTRACT_TYPE_CAST(h_type) \ 4778 case kExprRefAs##h_type: { \ 4779 NON_CONST_ONLY \ 4780 Value arg = Peek(0, 0, kWasmAnyRef); \ 4781 ValueType non_nullable_abstract_type = \ 4782 ValueType::Ref(HeapType::k##h_type, kNonNullable); \ 4783 Value result = CreateValue(non_nullable_abstract_type); \ 4784 if (V8_LIKELY(current_code_reachable_and_ok_)) { \ 4785 if (IsHeapSubtypeOf(arg.type.heap_representation(), HeapType::k##h_type, \ 4786 this->module_)) { \ 4787 if (arg.type.is_nullable()) { \ 4788 CALL_INTERFACE(RefAsNonNull, arg, &result); \ 4789 } else { \ 4790 CALL_INTERFACE(Forward, arg, &result); \ 4791 } \ 4792 } else if (!IsHeapSubtypeOf(HeapType::k##h_type, \ 4793 arg.type.heap_representation(), \ 4794 this->module_)) { \ 4795 CALL_INTERFACE(Trap, TrapReason::kTrapIllegalCast); \ 4796 /* We know that the following code is not reachable, but according */ \ 4797 /* to the spec it technically is. Set it to spec-only reachable. */ \ 4798 SetSucceedingCodeDynamicallyUnreachable(); \ 4799 } else { \ 4800 CALL_INTERFACE(RefAs##h_type, arg, &result); \ 4801 } \ 4802 } \ 4803 Drop(arg); \ 4804 Push(result); \ 4805 return opcode_length; \ 4806 } 4807 ABSTRACT_TYPE_CAST(Data) 4808 ABSTRACT_TYPE_CAST(Func) 4809 ABSTRACT_TYPE_CAST(I31) 4810 ABSTRACT_TYPE_CAST(Array) 4811#undef ABSTRACT_TYPE_CAST 4812 4813 case kExprBrOnData: 4814 case kExprBrOnFunc: 4815 case kExprBrOnArray: 4816 case kExprBrOnI31: { 4817 NON_CONST_ONLY 4818 BranchDepthImmediate<validate> branch_depth(this, 4819 this->pc_ + opcode_length); 4820 if (!this->Validate(this->pc_ + opcode_length, branch_depth, 4821 control_.size())) { 4822 return 0; 4823 } 4824 4825 Control* c = control_at(branch_depth.depth); 4826 if (c->br_merge()->arity == 0) { 4827 this->DecodeError("%s must target a branch of arity at least 1", 4828 SafeOpcodeNameAt(this->pc_)); 4829 return 0; 4830 } 4831 4832 // Attention: contrary to most other instructions, we modify the 4833 // stack before calling the interface function. This makes it 4834 // significantly more convenient to pass around the values that 4835 // will be on the stack when the branch is taken. 4836 // TODO(jkummerow): Reconsider this choice. 4837 Value obj = Peek(0, 0, kWasmAnyRef); 4838 Drop(obj); 4839 HeapType::Representation heap_type = 4840 opcode == kExprBrOnFunc 4841 ? HeapType::kFunc 4842 : opcode == kExprBrOnData 4843 ? HeapType::kData 4844 : opcode == kExprBrOnArray ? HeapType::kArray 4845 : HeapType::kI31; 4846 Value result_on_branch = 4847 CreateValue(ValueType::Ref(heap_type, kNonNullable)); 4848 Push(result_on_branch); 4849 if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 4850 // The {value_on_branch} parameter we pass to the interface must be 4851 // pointer-identical to the object on the stack, so we can't reuse 4852 // {result_on_branch} which was passed-by-value to {Push}. 4853 Value* value_on_branch = stack_value(1); 4854 if (V8_LIKELY(current_code_reachable_and_ok_)) { 4855 if (opcode == kExprBrOnFunc) { 4856 CALL_INTERFACE(BrOnFunc, obj, value_on_branch, branch_depth.depth); 4857 } else if (opcode == kExprBrOnData) { 4858 CALL_INTERFACE(BrOnData, obj, value_on_branch, branch_depth.depth); 4859 } else if (opcode == kExprBrOnArray) { 4860 CALL_INTERFACE(BrOnArray, obj, value_on_branch, branch_depth.depth); 4861 } else { 4862 CALL_INTERFACE(BrOnI31, obj, value_on_branch, branch_depth.depth); 4863 } 4864 c->br_merge()->reached = true; 4865 } 4866 Drop(result_on_branch); 4867 Push(obj); // Restore stack state on fallthrough. 4868 return opcode_length + branch_depth.length; 4869 } 4870 case kExprBrOnNonData: 4871 case kExprBrOnNonFunc: 4872 case kExprBrOnNonArray: 4873 case kExprBrOnNonI31: { 4874 NON_CONST_ONLY 4875 BranchDepthImmediate<validate> branch_depth(this, 4876 this->pc_ + opcode_length); 4877 if (!this->Validate(this->pc_ + opcode_length, branch_depth, 4878 control_.size())) { 4879 return 0; 4880 } 4881 4882 Control* c = control_at(branch_depth.depth); 4883 if (c->br_merge()->arity == 0) { 4884 this->DecodeError("%s must target a branch of arity at least 1", 4885 SafeOpcodeNameAt(this->pc_)); 4886 return 0; 4887 } 4888 if (!VALIDATE(TypeCheckBranch<true>(c, 0))) return 0; 4889 4890 Value obj = Peek(0, 0, kWasmAnyRef); 4891 HeapType::Representation heap_type = 4892 opcode == kExprBrOnNonFunc 4893 ? HeapType::kFunc 4894 : opcode == kExprBrOnNonData 4895 ? HeapType::kData 4896 : opcode == kExprBrOnNonArray ? HeapType::kArray 4897 : HeapType::kI31; 4898 Value value_on_fallthrough = 4899 CreateValue(ValueType::Ref(heap_type, kNonNullable)); 4900 4901 if (V8_LIKELY(current_code_reachable_and_ok_)) { 4902 if (opcode == kExprBrOnNonFunc) { 4903 CALL_INTERFACE(BrOnNonFunc, obj, &value_on_fallthrough, 4904 branch_depth.depth); 4905 } else if (opcode == kExprBrOnNonData) { 4906 CALL_INTERFACE(BrOnNonData, obj, &value_on_fallthrough, 4907 branch_depth.depth); 4908 } else if (opcode == kExprBrOnNonArray) { 4909 CALL_INTERFACE(BrOnNonArray, obj, &value_on_fallthrough, 4910 branch_depth.depth); 4911 } else { 4912 CALL_INTERFACE(BrOnNonI31, obj, &value_on_fallthrough, 4913 branch_depth.depth); 4914 } 4915 c->br_merge()->reached = true; 4916 } 4917 Drop(obj); 4918 Push(value_on_fallthrough); 4919 return opcode_length + branch_depth.length; 4920 } 4921 default: 4922 this->DecodeError("invalid gc opcode: %x", opcode); 4923 return 0; 4924 } 4925 } 4926#undef NON_CONST_ONLY 4927 4928 uint32_t DecodeAtomicOpcode(WasmOpcode opcode, uint32_t opcode_length) { 4929 ValueType ret_type; 4930 const FunctionSig* sig = WasmOpcodes::Signature(opcode); 4931 if (!VALIDATE(sig != nullptr)) { 4932 this->DecodeError("invalid atomic opcode"); 4933 return 0; 4934 } 4935 MachineType memtype; 4936 switch (opcode) { 4937#define CASE_ATOMIC_STORE_OP(Name, Type) \ 4938 case kExpr##Name: { \ 4939 memtype = MachineType::Type(); \ 4940 ret_type = kWasmVoid; \ 4941 break; /* to generic mem access code below */ \ 4942 } 4943 ATOMIC_STORE_OP_LIST(CASE_ATOMIC_STORE_OP) 4944#undef CASE_ATOMIC_OP 4945#define CASE_ATOMIC_OP(Name, Type) \ 4946 case kExpr##Name: { \ 4947 memtype = MachineType::Type(); \ 4948 ret_type = GetReturnType(sig); \ 4949 break; /* to generic mem access code below */ \ 4950 } 4951 ATOMIC_OP_LIST(CASE_ATOMIC_OP) 4952#undef CASE_ATOMIC_OP 4953 case kExprAtomicFence: { 4954 byte zero = 4955 this->template read_u8<validate>(this->pc_ + opcode_length, "zero"); 4956 if (!VALIDATE(zero == 0)) { 4957 this->DecodeError(this->pc_ + opcode_length, 4958 "invalid atomic operand"); 4959 return 0; 4960 } 4961 CALL_INTERFACE_IF_OK_AND_REACHABLE(AtomicFence); 4962 return 1 + opcode_length; 4963 } 4964 default: 4965 this->DecodeError("invalid atomic opcode"); 4966 return 0; 4967 } 4968 4969 MemoryAccessImmediate<validate> imm = MakeMemoryAccessImmediate( 4970 opcode_length, ElementSizeLog2Of(memtype.representation())); 4971 if (!this->Validate(this->pc_ + opcode_length, imm)) return false; 4972 4973 // TODO(10949): Fix this for memory64 (index type should be kWasmI64 4974 // then). 4975 CHECK(!this->module_->is_memory64); 4976 ArgVector args = PeekArgs(sig); 4977 if (ret_type == kWasmVoid) { 4978 CALL_INTERFACE_IF_OK_AND_REACHABLE(AtomicOp, opcode, base::VectorOf(args), 4979 imm, nullptr); 4980 DropArgs(sig); 4981 } else { 4982 Value result = CreateValue(GetReturnType(sig)); 4983 CALL_INTERFACE_IF_OK_AND_REACHABLE(AtomicOp, opcode, base::VectorOf(args), 4984 imm, &result); 4985 DropArgs(sig); 4986 Push(result); 4987 } 4988 return opcode_length + imm.length; 4989 } 4990 4991 unsigned DecodeNumericOpcode(WasmOpcode opcode, uint32_t opcode_length) { 4992 const FunctionSig* sig = WasmOpcodes::Signature(opcode); 4993 switch (opcode) { 4994 case kExprI32SConvertSatF32: 4995 case kExprI32UConvertSatF32: 4996 case kExprI32SConvertSatF64: 4997 case kExprI32UConvertSatF64: 4998 case kExprI64SConvertSatF32: 4999 case kExprI64UConvertSatF32: 5000 case kExprI64SConvertSatF64: 5001 case kExprI64UConvertSatF64: { 5002 BuildSimpleOperator(opcode, sig); 5003 return opcode_length; 5004 } 5005 case kExprMemoryInit: { 5006 MemoryInitImmediate<validate> imm(this, this->pc_ + opcode_length); 5007 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 5008 ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 5009 Value size = Peek(0, 2, kWasmI32); 5010 Value offset = Peek(1, 1, kWasmI32); 5011 Value dst = Peek(2, 0, mem_type); 5012 CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryInit, imm, dst, offset, size); 5013 Drop(3); 5014 return opcode_length + imm.length; 5015 } 5016 case kExprDataDrop: { 5017 IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 5018 "data segment index"); 5019 if (!this->ValidateDataSegment(this->pc_ + opcode_length, imm)) { 5020 return 0; 5021 } 5022 CALL_INTERFACE_IF_OK_AND_REACHABLE(DataDrop, imm); 5023 return opcode_length + imm.length; 5024 } 5025 case kExprMemoryCopy: { 5026 MemoryCopyImmediate<validate> imm(this, this->pc_ + opcode_length); 5027 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 5028 ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 5029 Value size = Peek(0, 2, mem_type); 5030 Value src = Peek(1, 1, mem_type); 5031 Value dst = Peek(2, 0, mem_type); 5032 CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryCopy, imm, dst, src, size); 5033 Drop(3); 5034 return opcode_length + imm.length; 5035 } 5036 case kExprMemoryFill: { 5037 MemoryIndexImmediate<validate> imm(this, this->pc_ + opcode_length); 5038 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 5039 ValueType mem_type = this->module_->is_memory64 ? kWasmI64 : kWasmI32; 5040 Value size = Peek(0, 2, mem_type); 5041 Value value = Peek(1, 1, kWasmI32); 5042 Value dst = Peek(2, 0, mem_type); 5043 CALL_INTERFACE_IF_OK_AND_REACHABLE(MemoryFill, imm, dst, value, size); 5044 Drop(3); 5045 return opcode_length + imm.length; 5046 } 5047 case kExprTableInit: { 5048 TableInitImmediate<validate> imm(this, this->pc_ + opcode_length); 5049 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 5050 ArgVector args = PeekArgs(sig); 5051 CALL_INTERFACE_IF_OK_AND_REACHABLE(TableInit, imm, 5052 base::VectorOf(args)); 5053 DropArgs(sig); 5054 return opcode_length + imm.length; 5055 } 5056 case kExprElemDrop: { 5057 IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 5058 "element segment index"); 5059 if (!this->ValidateElementSegment(this->pc_ + opcode_length, imm)) { 5060 return 0; 5061 } 5062 CALL_INTERFACE_IF_OK_AND_REACHABLE(ElemDrop, imm); 5063 return opcode_length + imm.length; 5064 } 5065 case kExprTableCopy: { 5066 TableCopyImmediate<validate> imm(this, this->pc_ + opcode_length); 5067 if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; 5068 ArgVector args = PeekArgs(sig); 5069 CALL_INTERFACE_IF_OK_AND_REACHABLE(TableCopy, imm, 5070 base::VectorOf(args)); 5071 DropArgs(sig); 5072 return opcode_length + imm.length; 5073 } 5074 case kExprTableGrow: { 5075 IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 5076 "table index"); 5077 if (!this->ValidateTable(this->pc_ + opcode_length, imm)) return 0; 5078 Value delta = Peek(0, 1, kWasmI32); 5079 Value value = Peek(1, 0, this->module_->tables[imm.index].type); 5080 Value result = CreateValue(kWasmI32); 5081 CALL_INTERFACE_IF_OK_AND_REACHABLE(TableGrow, imm, value, delta, 5082 &result); 5083 Drop(2); 5084 Push(result); 5085 return opcode_length + imm.length; 5086 } 5087 case kExprTableSize: { 5088 IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 5089 "table index"); 5090 if (!this->ValidateTable(this->pc_ + opcode_length, imm)) return 0; 5091 Value result = CreateValue(kWasmI32); 5092 CALL_INTERFACE_IF_OK_AND_REACHABLE(TableSize, imm, &result); 5093 Push(result); 5094 return opcode_length + imm.length; 5095 } 5096 case kExprTableFill: { 5097 IndexImmediate<validate> imm(this, this->pc_ + opcode_length, 5098 "table index"); 5099 if (!this->ValidateTable(this->pc_ + opcode_length, imm)) return 0; 5100 Value count = Peek(0, 2, kWasmI32); 5101 Value value = Peek(1, 1, this->module_->tables[imm.index].type); 5102 Value start = Peek(2, 0, kWasmI32); 5103 CALL_INTERFACE_IF_OK_AND_REACHABLE(TableFill, imm, start, value, count); 5104 Drop(3); 5105 return opcode_length + imm.length; 5106 } 5107 default: 5108 this->DecodeError("invalid numeric opcode"); 5109 return 0; 5110 } 5111 } 5112 5113 V8_INLINE void EnsureStackSpace(int slots_needed) { 5114 if (V8_LIKELY(stack_capacity_end_ - stack_end_ >= slots_needed)) return; 5115 GrowStackSpace(slots_needed); 5116 } 5117 5118 V8_NOINLINE void GrowStackSpace(int slots_needed) { 5119 size_t new_stack_capacity = 5120 std::max(size_t{8}, 5121 base::bits::RoundUpToPowerOfTwo(stack_size() + slots_needed)); 5122 Value* new_stack = 5123 this->zone()->template NewArray<Value>(new_stack_capacity); 5124 if (stack_) { 5125 std::copy(stack_, stack_end_, new_stack); 5126 this->zone()->DeleteArray(stack_, stack_capacity_end_ - stack_); 5127 } 5128 stack_end_ = new_stack + (stack_end_ - stack_); 5129 stack_ = new_stack; 5130 stack_capacity_end_ = new_stack + new_stack_capacity; 5131 } 5132 5133 V8_INLINE Value CreateValue(ValueType type) { return Value{this->pc_, type}; } 5134 V8_INLINE void Push(Value value) { 5135 DCHECK_NE(kWasmVoid, value.type); 5136 // {EnsureStackSpace} should have been called before, either in the central 5137 // decoding loop, or individually if more than one element is pushed. 5138 DCHECK_GT(stack_capacity_end_, stack_end_); 5139 *stack_end_ = value; 5140 ++stack_end_; 5141 } 5142 5143 void PushMergeValues(Control* c, Merge<Value>* merge) { 5144 if (decoding_mode == kInitExpression) return; 5145 DCHECK_EQ(c, &control_.back()); 5146 DCHECK(merge == &c->start_merge || merge == &c->end_merge); 5147 DCHECK_LE(stack_ + c->stack_depth, stack_end_); 5148 stack_end_ = stack_ + c->stack_depth; 5149 if (merge->arity == 1) { 5150 // {EnsureStackSpace} should have been called before in the central 5151 // decoding loop. 5152 DCHECK_GT(stack_capacity_end_, stack_end_); 5153 *stack_end_++ = merge->vals.first; 5154 } else { 5155 EnsureStackSpace(merge->arity); 5156 for (uint32_t i = 0; i < merge->arity; i++) { 5157 *stack_end_++ = merge->vals.array[i]; 5158 } 5159 } 5160 DCHECK_EQ(c->stack_depth + merge->arity, stack_size()); 5161 } 5162 5163 V8_INLINE ReturnVector CreateReturnValues(const FunctionSig* sig) { 5164 size_t return_count = sig->return_count(); 5165 ReturnVector values(return_count); 5166 std::transform(sig->returns().begin(), sig->returns().end(), values.begin(), 5167 [this](ValueType type) { return CreateValue(type); }); 5168 return values; 5169 } 5170 V8_INLINE void PushReturns(ReturnVector values) { 5171 EnsureStackSpace(static_cast<int>(values.size())); 5172 for (Value& value : values) Push(value); 5173 } 5174 5175 // We do not inline these functions because doing so causes a large binary 5176 // size increase. Not inlining them should not create a performance 5177 // degradation, because their invocations are guarded by V8_LIKELY. 5178 V8_NOINLINE void PopTypeError(int index, Value val, const char* expected) { 5179 this->DecodeError(val.pc(), "%s[%d] expected %s, found %s of type %s", 5180 SafeOpcodeNameAt(this->pc_), index, expected, 5181 SafeOpcodeNameAt(val.pc()), val.type.name().c_str()); 5182 } 5183 5184 V8_NOINLINE void PopTypeError(int index, Value val, std::string expected) { 5185 PopTypeError(index, val, expected.c_str()); 5186 } 5187 5188 V8_NOINLINE void PopTypeError(int index, Value val, ValueType expected) { 5189 PopTypeError(index, val, ("type " + expected.name()).c_str()); 5190 } 5191 5192 V8_NOINLINE void NotEnoughArgumentsError(int needed, int actual) { 5193 DCHECK_LT(0, needed); 5194 DCHECK_LE(0, actual); 5195 DCHECK_LT(actual, needed); 5196 this->DecodeError( 5197 "not enough arguments on the stack for %s (need %d, got %d)", 5198 SafeOpcodeNameAt(this->pc_), needed, actual); 5199 } 5200 5201 V8_INLINE Value Peek(int depth, int index, ValueType expected) { 5202 Value val = Peek(depth); 5203 if (!VALIDATE(IsSubtypeOf(val.type, expected, this->module_) || 5204 val.type == kWasmBottom || expected == kWasmBottom)) { 5205 PopTypeError(index, val, expected); 5206 } 5207 return val; 5208 } 5209 5210 V8_INLINE Value Peek(int depth) { 5211 DCHECK(!control_.empty()); 5212 uint32_t limit = control_.back().stack_depth; 5213 if (V8_UNLIKELY(stack_size() <= limit + depth)) { 5214 // Peeking past the current control start in reachable code. 5215 if (!VALIDATE(decoding_mode == kFunctionBody && 5216 control_.back().unreachable())) { 5217 NotEnoughArgumentsError(depth + 1, stack_size() - limit); 5218 } 5219 return UnreachableValue(this->pc_); 5220 } 5221 DCHECK_LE(stack_, stack_end_ - depth - 1); 5222 return *(stack_end_ - depth - 1); 5223 } 5224 5225 V8_INLINE void ValidateArgType(ArgVector args, int index, 5226 ValueType expected) { 5227 Value val = args[index]; 5228 if (!VALIDATE(IsSubtypeOf(val.type, expected, this->module_) || 5229 val.type == kWasmBottom || expected == kWasmBottom)) { 5230 PopTypeError(index, val, expected); 5231 } 5232 } 5233 5234 // Drop the top {count} stack elements, or all of them if less than {count} 5235 // are present. 5236 V8_INLINE void Drop(int count = 1) { 5237 DCHECK(!control_.empty()); 5238 uint32_t limit = control_.back().stack_depth; 5239 if (V8_UNLIKELY(stack_size() < limit + count)) { 5240 // Pop what we can. 5241 count = std::min(count, static_cast<int>(stack_size() - limit)); 5242 } 5243 DCHECK_LE(stack_, stack_end_ - count); 5244 stack_end_ -= count; 5245 } 5246 // Drop the top stack element if present. Takes a Value input for more 5247 // descriptive call sites. 5248 V8_INLINE void Drop(const Value& /* unused */) { Drop(1); } 5249 5250 enum StackElementsCountMode : bool { 5251 kNonStrictCounting = false, 5252 kStrictCounting = true 5253 }; 5254 5255 enum MergeType { 5256 kBranchMerge, 5257 kReturnMerge, 5258 kFallthroughMerge, 5259 kInitExprMerge 5260 }; 5261 5262 // - If the current code is reachable, check if the current stack values are 5263 // compatible with {merge} based on their number and types. Disregard the 5264 // first {drop_values} on the stack. If {strict_count}, check that 5265 // #(stack elements) == {merge->arity}, otherwise 5266 // #(stack elements) >= {merge->arity}. 5267 // - If the current code is unreachable, check if any values that may exist on 5268 // top of the stack are compatible with {merge}. If {push_branch_values}, 5269 // push back to the stack values based on the type of {merge} (this is 5270 // needed for conditional branches due to their typing rules, and 5271 // fallthroughs so that the outer control finds the expected values on the 5272 // stack). TODO(manoskouk): We expect the unreachable-code behavior to 5273 // change, either due to relaxation of dead code verification, or the 5274 // introduction of subtyping. 5275 template <StackElementsCountMode strict_count, bool push_branch_values, 5276 MergeType merge_type> 5277 bool TypeCheckStackAgainstMerge(uint32_t drop_values, Merge<Value>* merge) { 5278 static_assert(validate, "Call this function only within VALIDATE"); 5279 constexpr const char* merge_description = 5280 merge_type == kBranchMerge 5281 ? "branch" 5282 : merge_type == kReturnMerge 5283 ? "return" 5284 : merge_type == kInitExprMerge ? "init. expression" 5285 : "fallthru"; 5286 uint32_t arity = merge->arity; 5287 uint32_t actual = stack_size() - control_.back().stack_depth; 5288 // Here we have to check for !unreachable(), because we need to typecheck as 5289 // if the current code is reachable even if it is spec-only reachable. 5290 if (V8_LIKELY(decoding_mode == kInitExpression || 5291 !control_.back().unreachable())) { 5292 if (V8_UNLIKELY(strict_count ? actual != drop_values + arity 5293 : actual < drop_values + arity)) { 5294 this->DecodeError("expected %u elements on the stack for %s, found %u", 5295 arity, merge_description, 5296 actual >= drop_values ? actual - drop_values : 0); 5297 return false; 5298 } 5299 // Typecheck the topmost {merge->arity} values on the stack. 5300 Value* stack_values = stack_end_ - (arity + drop_values); 5301 for (uint32_t i = 0; i < arity; ++i) { 5302 Value& val = stack_values[i]; 5303 Value& old = (*merge)[i]; 5304 if (!IsSubtypeOf(val.type, old.type, this->module_)) { 5305 this->DecodeError("type error in %s[%u] (expected %s, got %s)", 5306 merge_description, i, old.type.name().c_str(), 5307 val.type.name().c_str()); 5308 return false; 5309 } 5310 } 5311 return true; 5312 } 5313 // Unreachable code validation starts here. 5314 if (V8_UNLIKELY(strict_count && actual > drop_values + arity)) { 5315 this->DecodeError("expected %u elements on the stack for %s, found %u", 5316 arity, merge_description, 5317 actual >= drop_values ? actual - drop_values : 0); 5318 return false; 5319 } 5320 // TODO(manoskouk): Use similar code as above if we keep unreachable checks. 5321 for (int i = arity - 1, depth = drop_values; i >= 0; --i, ++depth) { 5322 Peek(depth, i, (*merge)[i].type); 5323 } 5324 if (push_branch_values) { 5325 uint32_t inserted_value_count = 5326 static_cast<uint32_t>(EnsureStackArguments(drop_values + arity)); 5327 if (inserted_value_count > 0) { 5328 // EnsureStackSpace may have inserted unreachable values into the bottom 5329 // of the stack. If so, mark them with the correct type. If drop values 5330 // were also inserted, disregard them, as they will be dropped anyway. 5331 Value* stack_base = stack_value(drop_values + arity); 5332 for (uint32_t i = 0; i < std::min(arity, inserted_value_count); i++) { 5333 if (stack_base[i].type == kWasmBottom) { 5334 stack_base[i].type = (*merge)[i].type; 5335 } 5336 } 5337 } 5338 } 5339 return this->ok(); 5340 } 5341 5342 template <StackElementsCountMode strict_count, MergeType merge_type> 5343 bool DoReturn() { 5344 if (!VALIDATE((TypeCheckStackAgainstMerge<strict_count, false, merge_type>( 5345 0, &control_.front().end_merge)))) { 5346 return false; 5347 } 5348 DCHECK_IMPLIES(current_code_reachable_and_ok_, 5349 stack_size() >= this->sig_->return_count()); 5350 CALL_INTERFACE_IF_OK_AND_REACHABLE(DoReturn, 0); 5351 EndControl(); 5352 return true; 5353 } 5354 5355 int startrel(const byte* ptr) { return static_cast<int>(ptr - this->start_); } 5356 5357 void FallThrough() { 5358 Control* c = &control_.back(); 5359 DCHECK_NE(c->kind, kControlLoop); 5360 if (!VALIDATE(TypeCheckFallThru())) return; 5361 CALL_INTERFACE_IF_OK_AND_REACHABLE(FallThruTo, c); 5362 if (c->reachable()) c->end_merge.reached = true; 5363 } 5364 5365 bool TypeCheckOneArmedIf(Control* c) { 5366 static_assert(validate, "Call this function only within VALIDATE"); 5367 DCHECK(c->is_onearmed_if()); 5368 if (c->end_merge.arity != c->start_merge.arity) { 5369 this->DecodeError(c->pc(), 5370 "start-arity and end-arity of one-armed if must match"); 5371 return false; 5372 } 5373 for (uint32_t i = 0; i < c->start_merge.arity; ++i) { 5374 Value& start = c->start_merge[i]; 5375 Value& end = c->end_merge[i]; 5376 if (!IsSubtypeOf(start.type, end.type, this->module_)) { 5377 this->DecodeError("type error in merge[%u] (expected %s, got %s)", i, 5378 end.type.name().c_str(), start.type.name().c_str()); 5379 return false; 5380 } 5381 } 5382 return true; 5383 } 5384 5385 bool TypeCheckFallThru() { 5386 static_assert(validate, "Call this function only within VALIDATE"); 5387 return TypeCheckStackAgainstMerge<kStrictCounting, true, kFallthroughMerge>( 5388 0, &control_.back().end_merge); 5389 } 5390 5391 // If the current code is reachable, check if the current stack values are 5392 // compatible with a jump to {c}, based on their number and types. 5393 // Otherwise, we have a polymorphic stack: check if any values that may exist 5394 // on top of the stack are compatible with {c}. If {push_branch_values}, 5395 // push back to the stack values based on the type of {c} (this is needed for 5396 // conditional branches due to their typing rules, and fallthroughs so that 5397 // the outer control finds enough values on the stack). 5398 // {drop_values} is the number of stack values that will be dropped before the 5399 // branch is taken. This is currently 1 for for br (condition), br_table 5400 // (index) and br_on_null (reference), and 0 for all other branches. 5401 template <bool push_branch_values> 5402 bool TypeCheckBranch(Control* c, uint32_t drop_values) { 5403 static_assert(validate, "Call this function only within VALIDATE"); 5404 return TypeCheckStackAgainstMerge<kNonStrictCounting, push_branch_values, 5405 kBranchMerge>(drop_values, c->br_merge()); 5406 } 5407 5408 void onFirstError() override { 5409 this->end_ = this->pc_; // Terminate decoding loop. 5410 this->current_code_reachable_and_ok_ = false; 5411 TRACE(" !%s\n", this->error_.message().c_str()); 5412 // Cannot use CALL_INTERFACE_* macros because we emitted an error. 5413 interface().OnFirstError(this); 5414 } 5415 5416 int BuildSimplePrototypeOperator(WasmOpcode opcode) { 5417 if (opcode == kExprRefEq) { 5418 CHECK_PROTOTYPE_OPCODE(gc); 5419 } 5420 const FunctionSig* sig = WasmOpcodes::Signature(opcode); 5421 return BuildSimpleOperator(opcode, sig); 5422 } 5423 5424 int BuildSimpleOperator(WasmOpcode opcode, const FunctionSig* sig) { 5425 DCHECK_GE(1, sig->return_count()); 5426 if (sig->parameter_count() == 1) { 5427 // All current simple unary operators have exactly 1 return value. 5428 DCHECK_EQ(1, sig->return_count()); 5429 return BuildSimpleOperator(opcode, sig->GetReturn(0), sig->GetParam(0)); 5430 } else { 5431 DCHECK_EQ(2, sig->parameter_count()); 5432 ValueType ret = sig->return_count() == 0 ? kWasmVoid : sig->GetReturn(0); 5433 return BuildSimpleOperator(opcode, ret, sig->GetParam(0), 5434 sig->GetParam(1)); 5435 } 5436 } 5437 5438 int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type, 5439 ValueType arg_type) { 5440 DCHECK_NE(kWasmVoid, return_type); 5441 Value val = Peek(0, 0, arg_type); 5442 Value ret = CreateValue(return_type); 5443 CALL_INTERFACE_IF_OK_AND_REACHABLE(UnOp, opcode, val, &ret); 5444 Drop(val); 5445 Push(ret); 5446 return 1; 5447 } 5448 5449 int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type, 5450 ValueType lhs_type, ValueType rhs_type) { 5451 Value rval = Peek(0, 1, rhs_type); 5452 Value lval = Peek(1, 0, lhs_type); 5453 if (return_type == kWasmVoid) { 5454 CALL_INTERFACE_IF_OK_AND_REACHABLE(BinOp, opcode, lval, rval, nullptr); 5455 Drop(2); 5456 } else { 5457 Value ret = CreateValue(return_type); 5458 CALL_INTERFACE_IF_OK_AND_REACHABLE(BinOp, opcode, lval, rval, &ret); 5459 Drop(2); 5460 Push(ret); 5461 } 5462 return 1; 5463 } 5464 5465#define DEFINE_SIMPLE_SIG_OPERATOR(sig, ...) \ 5466 int BuildSimpleOperator_##sig(WasmOpcode opcode) { \ 5467 return BuildSimpleOperator(opcode, __VA_ARGS__); \ 5468 } 5469 FOREACH_SIGNATURE(DEFINE_SIMPLE_SIG_OPERATOR) 5470#undef DEFINE_SIMPLE_SIG_OPERATOR 5471}; 5472 5473class EmptyInterface { 5474 public: 5475 static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation; 5476 static constexpr DecodingMode decoding_mode = kFunctionBody; 5477 using Value = ValueBase<validate>; 5478 using Control = ControlBase<Value, validate>; 5479 using FullDecoder = WasmFullDecoder<validate, EmptyInterface>; 5480 5481#define DEFINE_EMPTY_CALLBACK(name, ...) \ 5482 void name(FullDecoder* decoder, ##__VA_ARGS__) {} 5483 INTERFACE_FUNCTIONS(DEFINE_EMPTY_CALLBACK) 5484#undef DEFINE_EMPTY_CALLBACK 5485}; 5486 5487#undef CALL_INTERFACE_IF_OK_AND_REACHABLE 5488#undef CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE 5489#undef TRACE 5490#undef TRACE_INST_FORMAT 5491#undef VALIDATE 5492#undef CHECK_PROTOTYPE_OPCODE 5493 5494} // namespace wasm 5495} // namespace internal 5496} // namespace v8 5497 5498#endif // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_ 5499