function-body-decoder-impl.h 158 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
#define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_

8 9 10
// Do only include this header for implementing new Interface of the
// WasmFullDecoder.

11 12
#include <inttypes.h>

13
#include "src/base/platform/elapsed-timer.h"
14
#include "src/base/small-vector.h"
15
#include "src/utils/bit-vector.h"
16
#include "src/wasm/decoder.h"
17
#include "src/wasm/function-body-decoder.h"
18
#include "src/wasm/value-type.h"
19
#include "src/wasm/wasm-features.h"
20 21
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-module.h"
22
#include "src/wasm/wasm-opcodes.h"
23
#include "src/wasm/wasm-subtyping.h"
24 25 26 27 28 29

namespace v8 {
namespace internal {
namespace wasm {

struct WasmGlobal;
30
struct WasmException;
31

32 33 34 35 36
#define TRACE(...)                                    \
  do {                                                \
    if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
  } while (false)

37 38
#define TRACE_INST_FORMAT "  @%-8d #%-20s|"

39 40
// Return the evaluation of `condition` if validate==true, DCHECK that it's
// true and always return true otherwise.
41 42 43 44
#define VALIDATE(condition)                \
  (validate ? V8_LIKELY(condition) : [&] { \
    DCHECK(condition);                     \
    return true;                           \
45 46
  }())

47
#define CHECK_PROTOTYPE_OPCODE(feat)                                           \
48
  DCHECK(this->module_->origin == kWasmOrigin);                                \
49
  if (!VALIDATE(this->enabled_.has_##feat())) {                                \
50
    this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
51 52 53
    return 0;                                                                  \
  }                                                                            \
  this->detected_->Add(kFeature_##feat);
54

55
#define ATOMIC_OP_LIST(V)                \
56
  V(AtomicNotify, Uint32)                \
57
  V(I32AtomicWait, Uint32)               \
58
  V(I64AtomicWait, Uint64)               \
59
  V(I32AtomicLoad, Uint32)               \
60
  V(I64AtomicLoad, Uint64)               \
61 62
  V(I32AtomicLoad8U, Uint8)              \
  V(I32AtomicLoad16U, Uint16)            \
63 64 65
  V(I64AtomicLoad8U, Uint8)              \
  V(I64AtomicLoad16U, Uint16)            \
  V(I64AtomicLoad32U, Uint32)            \
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
  V(I32AtomicAdd, Uint32)                \
  V(I32AtomicAdd8U, Uint8)               \
  V(I32AtomicAdd16U, Uint16)             \
  V(I64AtomicAdd, Uint64)                \
  V(I64AtomicAdd8U, Uint8)               \
  V(I64AtomicAdd16U, Uint16)             \
  V(I64AtomicAdd32U, Uint32)             \
  V(I32AtomicSub, Uint32)                \
  V(I64AtomicSub, Uint64)                \
  V(I32AtomicSub8U, Uint8)               \
  V(I32AtomicSub16U, Uint16)             \
  V(I64AtomicSub8U, Uint8)               \
  V(I64AtomicSub16U, Uint16)             \
  V(I64AtomicSub32U, Uint32)             \
  V(I32AtomicAnd, Uint32)                \
  V(I64AtomicAnd, Uint64)                \
  V(I32AtomicAnd8U, Uint8)               \
  V(I32AtomicAnd16U, Uint16)             \
  V(I64AtomicAnd8U, Uint8)               \
  V(I64AtomicAnd16U, Uint16)             \
  V(I64AtomicAnd32U, Uint32)             \
  V(I32AtomicOr, Uint32)                 \
  V(I64AtomicOr, Uint64)                 \
  V(I32AtomicOr8U, Uint8)                \
  V(I32AtomicOr16U, Uint16)              \
  V(I64AtomicOr8U, Uint8)                \
  V(I64AtomicOr16U, Uint16)              \
  V(I64AtomicOr32U, Uint32)              \
  V(I32AtomicXor, Uint32)                \
  V(I64AtomicXor, Uint64)                \
  V(I32AtomicXor8U, Uint8)               \
  V(I32AtomicXor16U, Uint16)             \
  V(I64AtomicXor8U, Uint8)               \
  V(I64AtomicXor16U, Uint16)             \
  V(I64AtomicXor32U, Uint32)             \
  V(I32AtomicExchange, Uint32)           \
  V(I64AtomicExchange, Uint64)           \
  V(I32AtomicExchange8U, Uint8)          \
  V(I32AtomicExchange16U, Uint16)        \
  V(I64AtomicExchange8U, Uint8)          \
  V(I64AtomicExchange16U, Uint16)        \
  V(I64AtomicExchange32U, Uint32)        \
  V(I32AtomicCompareExchange, Uint32)    \
  V(I64AtomicCompareExchange, Uint64)    \
  V(I32AtomicCompareExchange8U, Uint8)   \
  V(I32AtomicCompareExchange16U, Uint16) \
  V(I64AtomicCompareExchange8U, Uint8)   \
  V(I64AtomicCompareExchange16U, Uint16) \
  V(I64AtomicCompareExchange32U, Uint32)
115

116 117
#define ATOMIC_STORE_OP_LIST(V) \
  V(I32AtomicStore, Uint32)     \
118
  V(I64AtomicStore, Uint64)     \
119
  V(I32AtomicStore8U, Uint8)    \
120 121 122 123
  V(I32AtomicStore16U, Uint16)  \
  V(I64AtomicStore8U, Uint8)    \
  V(I64AtomicStore16U, Uint16)  \
  V(I64AtomicStore32U, Uint32)
124

125 126
namespace value_type_reader {

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
V8_INLINE WasmFeature feature_for_heap_type(HeapType heap_type) {
  switch (heap_type.representation()) {
    case HeapType::kFunc:
    case HeapType::kExtern:
      return WasmFeature::kFeature_reftypes;
    case HeapType::kExn:
      return WasmFeature::kFeature_eh;
    case HeapType::kEq:
    case HeapType::kI31:
      return WasmFeature::kFeature_gc;
    default:
      UNREACHABLE();
  }
}

template <Decoder::ValidateFlag validate>
HeapType read_heap_type(Decoder* decoder, const byte* pc,
                        uint32_t* const length, const WasmFeatures& enabled) {
  int64_t heap_index = decoder->read_i33v<validate>(pc, length, "heap type");
  if (heap_index < 0) {
    uint8_t uint_7_mask = 0x7F;
    uint8_t code = static_cast<ValueTypeCode>(heap_index) & uint_7_mask;
    switch (code) {
      case kLocalFuncRef:
      case kLocalExnRef:
      case kLocalEqRef:
      case kLocalExternRef:
      case kLocalI31Ref: {
        HeapType result = HeapType::from_code(code);
        if (!VALIDATE(enabled.contains(feature_for_heap_type(result)))) {
          decoder->errorf(
              pc, "invalid heap type '%s', enable with --experimental-wasm-%s",
              result.name().c_str(),
              WasmFeatures::name_for_feature(feature_for_heap_type(result)));
          return HeapType(HeapType::kBottom);
        }
        return result;
      }
      default:
166
        if (validate) {
167
          decoder->errorf(pc, "Unknown heap type %" PRId64, heap_index);
168
        }
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
        return HeapType(HeapType::kBottom);
    }
    UNREACHABLE();
  } else {
    if (!VALIDATE(enabled.has_typed_funcref())) {
      decoder->error(pc,
                     "Invalid indexed heap type, enable with "
                     "--experimental-wasm-typed-funcref");
      return HeapType(HeapType::kBottom);
    }
    uint32_t type_index = static_cast<uint32_t>(heap_index);
    if (!VALIDATE(type_index < kV8MaxWasmTypes)) {
      decoder->errorf(pc,
                      "Type index %u is greater than the maximum number %zu "
                      "of type definitions supported by V8",
                      type_index, kV8MaxWasmTypes);
      return HeapType(HeapType::kBottom);
    }
    return HeapType(type_index);
  }
}

191 192 193 194 195
// Read a value type starting at address 'pc' in 'decoder'.
// No bytes are consumed. The result is written into the 'result' parameter.
// Returns the amount of bytes read, or 0 if decoding failed.
// Registers an error if the type opcode is invalid iff validate is set.
template <Decoder::ValidateFlag validate>
196 197 198
ValueType read_value_type(Decoder* decoder, const byte* pc,
                          uint32_t* const length, const WasmFeatures& enabled) {
  *length = 1;
199
  byte val = decoder->read_u8<validate>(pc, "value type opcode");
200 201 202
  if (decoder->failed()) {
    return kWasmBottom;
  }
203
  ValueTypeCode code = static_cast<ValueTypeCode>(val);
204
  switch (code) {
205 206 207 208 209 210 211 212 213 214
    case kLocalFuncRef:
    case kLocalExnRef:
    case kLocalEqRef:
    case kLocalExternRef:
    case kLocalI31Ref: {
      HeapType heap_type = HeapType::from_code(code);
      ValueType result = ValueType::Ref(heap_type, kNullable);
      if (!VALIDATE(enabled.contains(feature_for_heap_type(heap_type)))) {
        decoder->errorf(
            pc, "invalid value type '%s', enable with --experimental-wasm-%s",
215
            result.name().c_str(),
216 217 218 219 220
            WasmFeatures::name_for_feature(feature_for_heap_type(heap_type)));
        return kWasmBottom;
      }
      return result;
    }
221 222 223 224 225 226 227 228 229 230 231
    case kLocalI32:
      return kWasmI32;
    case kLocalI64:
      return kWasmI64;
    case kLocalF32:
      return kWasmF32;
    case kLocalF64:
      return kWasmF64;
    case kLocalRef:
    case kLocalOptRef: {
      Nullability nullability = code == kLocalOptRef ? kNullable : kNonNullable;
232 233 234 235 236 237
      if (!VALIDATE(enabled.has_typed_funcref())) {
        decoder->errorf(pc,
                        "Invalid type 'ref%s', enable with "
                        "--experimental-wasm-typed-funcref",
                        nullability == kNullable ? " null" : "");
        return kWasmBottom;
238
      }
239 240 241 242 243
      HeapType heap_type =
          read_heap_type<validate>(decoder, pc + 1, length, enabled);
      *length += 1;
      return heap_type.is_bottom() ? kWasmBottom
                                   : ValueType::Ref(heap_type, nullability);
244
    }
245 246 247 248 249 250 251 252 253 254 255 256 257
    case kLocalRtt: {
      if (!VALIDATE(enabled.has_gc())) {
        decoder->error(
            pc, "invalid value type 'rtt', enable with --experimental-wasm-gc");
        return kWasmBottom;
      }
      uint32_t depth_length;
      uint32_t depth =
          decoder->read_u32v<validate>(pc + 1, &depth_length, "depth");
      // TODO(7748): Introduce a proper limit.
      const uint32_t kMaxRttSubtypingDepth = 7;
      if (!VALIDATE(depth <= kMaxRttSubtypingDepth)) {
        decoder->errorf(pc,
258 259
                        "subtyping depth %u is greater than the maximum depth "
                        "%u supported by V8",
260 261 262
                        depth, kMaxRttSubtypingDepth);
        return kWasmBottom;
      }
263 264 265 266 267
      HeapType heap_type = read_heap_type<validate>(
          decoder, pc + depth_length + 1, length, enabled);
      *length += depth_length + 1;
      return heap_type.is_bottom() ? kWasmBottom
                                   : ValueType::Rtt(heap_type, depth);
268
    }
269
    case kLocalS128:
270 271 272 273 274
      if (!VALIDATE(enabled.has_simd())) {
        decoder->error(pc,
                       "invalid value type 'Simd128', enable with "
                       "--experimental-wasm-simd");
        return kWasmBottom;
275
      }
276
      return kWasmS128;
277
    case kLocalVoid:
278 279 280 281 282
    case kLocalI8:
    case kLocalI16:
      // Although these types are included in ValueType, they are technically
      // not value types and are only used in specific contexts. The caller of
      // this function is responsible to check for them separately.
283
      break;
284
  }
285 286
  // Malformed modules specifying invalid types can get here.
  return kWasmBottom;
287
}
288
}  // namespace value_type_reader
289

290 291 292 293 294 295 296
// Helpers for decoding different kinds of immediates which follow bytecodes.
template <Decoder::ValidateFlag validate>
struct LocalIndexImmediate {
  uint32_t index;
  uint32_t length;

  inline LocalIndexImmediate(Decoder* decoder, const byte* pc) {
297
    index = decoder->read_u32v<validate>(pc, &length, "local index");
298 299 300 301 302 303 304 305 306 307
  }
};

template <Decoder::ValidateFlag validate>
struct ExceptionIndexImmediate {
  uint32_t index;
  const WasmException* exception = nullptr;
  uint32_t length;

  inline ExceptionIndexImmediate(Decoder* decoder, const byte* pc) {
308
    index = decoder->read_u32v<validate>(pc, &length, "exception index");
309 310 311 312 313 314 315 316
  }
};

template <Decoder::ValidateFlag validate>
struct ImmI32Immediate {
  int32_t value;
  uint32_t length;
  inline ImmI32Immediate(Decoder* decoder, const byte* pc) {
317
    value = decoder->read_i32v<validate>(pc, &length, "immi32");
318 319 320 321 322 323 324 325
  }
};

template <Decoder::ValidateFlag validate>
struct ImmI64Immediate {
  int64_t value;
  uint32_t length;
  inline ImmI64Immediate(Decoder* decoder, const byte* pc) {
326
    value = decoder->read_i64v<validate>(pc, &length, "immi64");
327 328 329 330 331 332 333 334 335 336 337
  }
};

template <Decoder::ValidateFlag validate>
struct ImmF32Immediate {
  float value;
  uint32_t length = 4;
  inline ImmF32Immediate(Decoder* decoder, const byte* pc) {
    // We can't use bit_cast here because calling any helper function that
    // returns a float would potentially flip NaN bits per C++ semantics, so we
    // have to inline the memcpy call directly.
338
    uint32_t tmp = decoder->read_u32<validate>(pc, "immf32");
339 340 341 342 343 344 345 346 347 348
    memcpy(&value, &tmp, sizeof(value));
  }
};

template <Decoder::ValidateFlag validate>
struct ImmF64Immediate {
  double value;
  uint32_t length = 8;
  inline ImmF64Immediate(Decoder* decoder, const byte* pc) {
    // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
349
    uint64_t tmp = decoder->read_u64<validate>(pc, "immf64");
350 351 352 353 354 355 356 357 358 359 360 361
    memcpy(&value, &tmp, sizeof(value));
  }
};

template <Decoder::ValidateFlag validate>
struct GlobalIndexImmediate {
  uint32_t index;
  ValueType type = kWasmStmt;
  const WasmGlobal* global = nullptr;
  uint32_t length;

  inline GlobalIndexImmediate(Decoder* decoder, const byte* pc) {
362
    index = decoder->read_u32v<validate>(pc, &length, "global index");
363 364 365
  }
};

366 367 368 369 370
template <Decoder::ValidateFlag validate>
struct SelectTypeImmediate {
  uint32_t length;
  ValueType type;

371 372
  inline SelectTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
                             const byte* pc) {
373
    uint8_t num_types =
374
        decoder->read_u32v<validate>(pc, &length, "number of select types");
375 376 377 378 379
    if (!VALIDATE(num_types == 1)) {
      decoder->error(
          pc + 1, "Invalid number of types. Select accepts exactly one type");
      return;
    }
380
    uint32_t type_length;
381 382
    type = value_type_reader::read_value_type<validate>(decoder, pc + length,
                                                        &type_length, enabled);
383
    length += type_length;
384
    if (!VALIDATE(type != kWasmBottom)) {
385 386 387 388 389
      decoder->error(pc + 1, "invalid select type");
    }
  }
};

390
template <Decoder::ValidateFlag validate>
391
struct BlockTypeImmediate {
392
  uint32_t length = 1;
393 394
  ValueType type = kWasmStmt;
  uint32_t sig_index = 0;
395
  const FunctionSig* sig = nullptr;
396

397 398
  inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
                            const byte* pc) {
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
    int64_t block_type =
        decoder->read_i33v<validate>(pc, &length, "block type");
    if (block_type < 0) {
      if ((static_cast<uint8_t>(block_type) & byte{0x7f}) == kLocalVoid) return;
      type = value_type_reader::read_value_type<validate>(decoder, pc, &length,
                                                          enabled);
      if (!VALIDATE(type != kWasmBottom)) {
        decoder->errorf(pc, "Invalid block type %" PRId64, block_type);
      }
    } else {
      if (!VALIDATE(enabled.has_mv())) {
        decoder->errorf(pc,
                        "invalid block type %" PRId64
                        ", enable with --experimental-wasm-mv",
                        block_type);
        return;
      }
      type = kWasmBottom;
      sig_index = static_cast<uint32_t>(block_type);
418
    }
419
  }
420

421
  uint32_t in_arity() const {
422
    if (type != kWasmBottom) return 0;
423 424 425 426
    return static_cast<uint32_t>(sig->parameter_count());
  }
  uint32_t out_arity() const {
    if (type == kWasmStmt) return 0;
427
    if (type != kWasmBottom) return 1;
428 429 430
    return static_cast<uint32_t>(sig->return_count());
  }
  ValueType in_type(uint32_t index) {
431
    DCHECK_EQ(kWasmBottom, type);
432 433 434
    return sig->GetParam(index);
  }
  ValueType out_type(uint32_t index) {
435
    if (type == kWasmBottom) return sig->GetReturn(index);
436 437 438
    DCHECK_NE(kWasmStmt, type);
    DCHECK_EQ(0, index);
    return type;
439 440 441
  }
};

442
template <Decoder::ValidateFlag validate>
443
struct BranchDepthImmediate {
444
  uint32_t depth;
445
  uint32_t length;
446
  inline BranchDepthImmediate(Decoder* decoder, const byte* pc) {
447
    depth = decoder->read_u32v<validate>(pc, &length, "branch depth");
448 449 450
  }
};

451 452 453 454 455 456 457 458 459 460 461 462
template <Decoder::ValidateFlag validate>
struct BranchOnExceptionImmediate {
  BranchDepthImmediate<validate> depth;
  ExceptionIndexImmediate<validate> index;
  uint32_t length = 0;
  inline BranchOnExceptionImmediate(Decoder* decoder, const byte* pc)
      : depth(BranchDepthImmediate<validate>(decoder, pc)),
        index(ExceptionIndexImmediate<validate>(decoder, pc + depth.length)) {
    length = depth.length + index.length;
  }
};

463 464 465 466 467
template <Decoder::ValidateFlag validate>
struct FunctionIndexImmediate {
  uint32_t index = 0;
  uint32_t length = 1;
  inline FunctionIndexImmediate(Decoder* decoder, const byte* pc) {
468
    index = decoder->read_u32v<validate>(pc, &length, "function index");
469 470 471
  }
};

472
template <Decoder::ValidateFlag validate>
473
struct MemoryIndexImmediate {
474
  uint32_t index = 0;
475
  uint32_t length = 1;
476
  inline MemoryIndexImmediate() = default;
477
  inline MemoryIndexImmediate(Decoder* decoder, const byte* pc) {
478
    index = decoder->read_u8<validate>(pc, "memory index");
479
    if (!VALIDATE(index == 0)) {
480
      decoder->errorf(pc, "expected memory index 0, found %u", index);
481 482 483 484
    }
  }
};

485 486
template <Decoder::ValidateFlag validate>
struct TableIndexImmediate {
487
  uint32_t index = 0;
488
  unsigned length = 1;
489
  inline TableIndexImmediate() = default;
490
  inline TableIndexImmediate(Decoder* decoder, const byte* pc) {
491
    index = decoder->read_u32v<validate>(pc, &length, "table index");
492 493 494
  }
};

495 496
// TODO(jkummerow): Introduce a common superclass for StructIndexImmediate and
// ArrayIndexImmediate? Maybe even FunctionIndexImmediate too?
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
template <Decoder::ValidateFlag validate>
struct StructIndexImmediate {
  uint32_t index = 0;
  uint32_t length = 0;
  const StructType* struct_type = nullptr;
  inline StructIndexImmediate(Decoder* decoder, const byte* pc) {
    index = decoder->read_u32v<validate>(pc, &length, "struct index");
  }
};

template <Decoder::ValidateFlag validate>
struct FieldIndexImmediate {
  StructIndexImmediate<validate> struct_index;
  uint32_t index = 0;
  uint32_t length = 0;
  inline FieldIndexImmediate(Decoder* decoder, const byte* pc)
      : struct_index(decoder, pc) {
    index = decoder->read_u32v<validate>(pc + struct_index.length, &length,
                                         "field index");
    length += struct_index.length;
  }
};

520 521 522 523 524 525 526 527 528 529
template <Decoder::ValidateFlag validate>
struct ArrayIndexImmediate {
  uint32_t index = 0;
  uint32_t length = 0;
  const ArrayType* array_type = nullptr;
  inline ArrayIndexImmediate(Decoder* decoder, const byte* pc) {
    index = decoder->read_u32v<validate>(pc, &length, "array index");
  }
};

530 531 532 533
template <Decoder::ValidateFlag validate>
struct CallIndirectImmediate {
  uint32_t table_index;
  uint32_t sig_index;
534
  const FunctionSig* sig = nullptr;
535 536 537 538
  uint32_t length = 0;
  inline CallIndirectImmediate(const WasmFeatures enabled, Decoder* decoder,
                               const byte* pc) {
    uint32_t len = 0;
539
    sig_index = decoder->read_u32v<validate>(pc, &len, "signature index");
540
    TableIndexImmediate<validate> table(decoder, pc + len);
541
    if (!VALIDATE((table.index == 0 && table.length == 1) ||
542
                  enabled.has_reftypes())) {
543
      decoder->errorf(pc + len, "expected table index 0, found %u",
544 545 546 547 548 549 550 551 552 553
                      table.index);
    }
    table_index = table.index;
    length = len + table.length;
  }
};

template <Decoder::ValidateFlag validate>
struct CallFunctionImmediate {
  uint32_t index;
554
  const FunctionSig* sig = nullptr;
555 556
  uint32_t length;
  inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
557
    index = decoder->read_u32v<validate>(pc, &length, "function index");
558 559 560
  }
};

561
template <Decoder::ValidateFlag validate>
562
struct BranchTableImmediate {
563 564 565
  uint32_t table_count;
  const byte* start;
  const byte* table;
566
  inline BranchTableImmediate(Decoder* decoder, const byte* pc) {
567
    start = pc;
568
    uint32_t len = 0;
569 570
    table_count = decoder->read_u32v<validate>(pc, &len, "table count");
    table = pc + len;
571 572 573 574
  }
};

// A helper to iterate over a branch table.
575
template <Decoder::ValidateFlag validate>
576 577
class BranchTableIterator {
 public:
578
  uint32_t cur_index() { return index_; }
579
  bool has_next() { return VALIDATE(decoder_->ok()) && index_ <= table_count_; }
580 581 582
  uint32_t next() {
    DCHECK(has_next());
    index_++;
583
    uint32_t length;
584
    uint32_t result =
585
        decoder_->read_u32v<validate>(pc_, &length, "branch table entry");
586 587 588
    pc_ += length;
    return result;
  }
589
  // length, including the length of the {BranchTableImmediate}, but not the
590
  // opcode.
591
  uint32_t length() {
592
    while (has_next()) next();
593
    return static_cast<uint32_t>(pc_ - start_);
594 595 596
  }
  const byte* pc() { return pc_; }

597
  BranchTableIterator(Decoder* decoder,
598
                      const BranchTableImmediate<validate>& imm)
599
      : decoder_(decoder),
600 601 602
        start_(imm.start),
        pc_(imm.table),
        table_count_(imm.table_count) {}
603 604

 private:
605
  Decoder* const decoder_;
606 607
  const byte* start_;
  const byte* pc_;
608 609
  uint32_t index_ = 0;          // the current index.
  const uint32_t table_count_;  // the count of entries, not including default.
610 611
};

612
template <Decoder::ValidateFlag validate>
613
struct MemoryAccessImmediate {
614 615
  uint32_t alignment;
  uint32_t offset;
616
  uint32_t length = 0;
617 618
  inline MemoryAccessImmediate(Decoder* decoder, const byte* pc,
                               uint32_t max_alignment) {
619
    uint32_t alignment_length;
620
    alignment =
621
        decoder->read_u32v<validate>(pc, &alignment_length, "alignment");
622
    if (!VALIDATE(alignment <= max_alignment)) {
623
      decoder->errorf(pc,
624 625 626
                      "invalid alignment; expected maximum alignment is %u, "
                      "actual alignment is %u",
                      max_alignment, alignment);
627
    }
628
    uint32_t offset_length;
629 630
    offset = decoder->read_u32v<validate>(pc + alignment_length, &offset_length,
                                          "offset");
631 632 633 634
    length = alignment_length + offset_length;
  }
};

635
// Immediate for SIMD lane operations.
636
template <Decoder::ValidateFlag validate>
637
struct SimdLaneImmediate {
638
  uint8_t lane;
639
  uint32_t length = 1;
640

641 642
  inline SimdLaneImmediate(Decoder* decoder, const byte* pc) {
    lane = decoder->read_u8<validate>(pc, "lane");
643 644 645
  }
};

646
// Immediate for SIMD S8x16 shuffle operations.
647
template <Decoder::ValidateFlag validate>
648 649
struct Simd128Immediate {
  uint8_t value[kSimd128Size] = {0};
650

651
  inline Simd128Immediate(Decoder* decoder, const byte* pc) {
652
    for (uint32_t i = 0; i < kSimd128Size; ++i) {
653
      value[i] = decoder->read_u8<validate>(pc + i, "value");
654
    }
655 656 657
  }
};

658 659
template <Decoder::ValidateFlag validate>
struct MemoryInitImmediate {
660
  uint32_t data_segment_index = 0;
661
  MemoryIndexImmediate<validate> memory;
662
  unsigned length = 0;
663

664
  inline MemoryInitImmediate(Decoder* decoder, const byte* pc) {
665
    uint32_t len = 0;
666
    data_segment_index =
667 668
        decoder->read_u32v<validate>(pc, &len, "data segment index");
    memory = MemoryIndexImmediate<validate>(decoder, pc + len);
669
    length = len + memory.length;
670 671 672 673
  }
};

template <Decoder::ValidateFlag validate>
674
struct DataDropImmediate {
675 676 677
  uint32_t index;
  unsigned length;

678
  inline DataDropImmediate(Decoder* decoder, const byte* pc) {
679
    index = decoder->read_u32v<validate>(pc, &length, "data segment index");
680 681 682
  }
};

683 684 685 686 687 688 689
template <Decoder::ValidateFlag validate>
struct MemoryCopyImmediate {
  MemoryIndexImmediate<validate> memory_src;
  MemoryIndexImmediate<validate> memory_dst;
  unsigned length = 0;

  inline MemoryCopyImmediate(Decoder* decoder, const byte* pc) {
690
    memory_src = MemoryIndexImmediate<validate>(decoder, pc);
691
    memory_dst =
692
        MemoryIndexImmediate<validate>(decoder, pc + memory_src.length);
693 694 695 696
    length = memory_src.length + memory_dst.length;
  }
};

697 698
template <Decoder::ValidateFlag validate>
struct TableInitImmediate {
699
  uint32_t elem_segment_index = 0;
700
  TableIndexImmediate<validate> table;
701
  unsigned length = 0;
702

703
  inline TableInitImmediate(Decoder* decoder, const byte* pc) {
704
    uint32_t len = 0;
705
    elem_segment_index =
706 707
        decoder->read_u32v<validate>(pc, &len, "elem segment index");
    table = TableIndexImmediate<validate>(decoder, pc + len);
708
    length = len + table.length;
709 710 711 712
  }
};

template <Decoder::ValidateFlag validate>
713
struct ElemDropImmediate {
714 715 716
  uint32_t index;
  unsigned length;

717
  inline ElemDropImmediate(Decoder* decoder, const byte* pc) {
718
    index = decoder->read_u32v<validate>(pc, &length, "elem segment index");
719 720 721
  }
};

722 723 724
template <Decoder::ValidateFlag validate>
struct TableCopyImmediate {
  TableIndexImmediate<validate> table_dst;
725
  TableIndexImmediate<validate> table_src;
726 727 728
  unsigned length = 0;

  inline TableCopyImmediate(Decoder* decoder, const byte* pc) {
729 730
    table_dst = TableIndexImmediate<validate>(decoder, pc);
    table_src = TableIndexImmediate<validate>(decoder, pc + table_dst.length);
731 732 733 734
    length = table_src.length + table_dst.length;
  }
};

735 736 737
template <Decoder::ValidateFlag validate>
struct HeapTypeImmediate {
  uint32_t length = 1;
738
  HeapType type = HeapType(HeapType::kBottom);
739 740
  inline HeapTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
                           const byte* pc) {
741 742
    type = value_type_reader::read_heap_type<validate>(decoder, pc, &length,
                                                       enabled);
743 744 745
  }
};

746
// An entry on the value stack.
747
struct ValueBase {
748 749
  const byte* pc = nullptr;
  ValueType type = kWasmStmt;
750

751
  ValueBase(const byte* pc, ValueType type) : pc(pc), type(type) {}
752 753
};

754 755
template <typename Value>
struct Merge {
756 757
  uint32_t arity = 0;
  union {  // Either multiple values or a single value.
758 759
    Value* array;
    Value first;
760
  } vals = {nullptr};  // Initialize {array} with {nullptr}.
761

762 763 764 765
  // Tracks whether this merge was ever reached. Uses precise reachability, like
  // Reachability::kReachable.
  bool reached;

766
  explicit Merge(bool reached = false) : reached(reached) {}
767

768
  Value& operator[](uint32_t i) {
769 770 771 772 773
    DCHECK_GT(arity, i);
    return arity == 1 ? vals.first : vals.array[i];
  }
};

774
enum ControlKind : uint8_t {
775 776 777 778
  kControlIf,
  kControlIfElse,
  kControlBlock,
  kControlLoop,
779
  kControlLet,
780
  kControlTry,
781
  kControlTryCatch
782 783
};

784 785 786 787 788 789 790 791 792
enum Reachability : uint8_t {
  // reachable code.
  kReachable,
  // reachable code in unreachable block (implies normal validation).
  kSpecOnlyReachable,
  // code unreachable in its own block (implies polymorphic validation).
  kUnreachable
};

793
// An entry on the control stack (i.e. if, block, loop, or try).
794 795
template <typename Value>
struct ControlBase {
796
  ControlKind kind = kControlBlock;
797
  uint32_t locals_count = 0;
798 799
  uint32_t stack_depth = 0;  // stack height at the beginning of the construct.
  const uint8_t* pc = nullptr;
800
  Reachability reachability = kReachable;
801

802 803 804
  // Values merged into the start or end of this control construct.
  Merge<Value> start_merge;
  Merge<Value> end_merge;
805

806 807
  MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ControlBase);

808 809
  ControlBase(ControlKind kind, uint32_t locals_count, uint32_t stack_depth,
              const uint8_t* pc, Reachability reachability)
810
      : kind(kind),
811
        locals_count(locals_count),
812 813 814
        stack_depth(stack_depth),
        pc(pc),
        reachability(reachability),
815 816 817
        start_merge(reachability == kReachable) {
    DCHECK(kind == kControlLet || locals_count == 0);
  }
818

819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
  // Check whether the current block is reachable.
  bool reachable() const { return reachability == kReachable; }

  // Check whether the rest of the block is unreachable.
  // Note that this is different from {!reachable()}, as there is also the
  // "indirect unreachable state", for which both {reachable()} and
  // {unreachable()} return false.
  bool unreachable() const { return reachability == kUnreachable; }

  // Return the reachability of new control structs started in this block.
  Reachability innerReachability() const {
    return reachability == kReachable ? kReachable : kSpecOnlyReachable;
  }

  bool is_if() const { return is_onearmed_if() || is_if_else(); }
  bool is_onearmed_if() const { return kind == kControlIf; }
  bool is_if_else() const { return kind == kControlIfElse; }
  bool is_block() const { return kind == kControlBlock; }
837
  bool is_let() const { return kind == kControlLet; }
838 839 840
  bool is_loop() const { return kind == kControlLoop; }
  bool is_incomplete_try() const { return kind == kControlTry; }
  bool is_try_catch() const { return kind == kControlTryCatch; }
841
  bool is_try() const { return is_incomplete_try() || is_try_catch(); }
842

843 844 845
  inline Merge<Value>* br_merge() {
    return is_loop() ? &this->start_merge : &this->end_merge;
  }
846 847
};

848 849 850
// This is the list of callback functions that an interface for the
// WasmFullDecoder should implement.
// F(Name, args...)
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
#define INTERFACE_FUNCTIONS(F)                                                 \
  /* General: */                                                               \
  F(StartFunction)                                                             \
  F(StartFunctionBody, Control* block)                                         \
  F(FinishFunction)                                                            \
  F(OnFirstError)                                                              \
  F(NextInstruction, WasmOpcode)                                               \
  /* Control: */                                                               \
  F(Block, Control* block)                                                     \
  F(Loop, Control* block)                                                      \
  F(Try, Control* block)                                                       \
  F(Catch, Control* block, Value* exception)                                   \
  F(If, const Value& cond, Control* if_block)                                  \
  F(FallThruTo, Control* c)                                                    \
  F(PopControl, Control* block)                                                \
  F(EndControl, Control* block)                                                \
  /* Instructions: */                                                          \
  F(UnOp, WasmOpcode opcode, const Value& value, Value* result)                \
  F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs,              \
    Value* result)                                                             \
  F(I32Const, Value* result, int32_t value)                                    \
  F(I64Const, Value* result, int64_t value)                                    \
  F(F32Const, Value* result, float value)                                      \
  F(F64Const, Value* result, double value)                                     \
  F(RefNull, Value* result)                                                    \
  F(RefFunc, uint32_t function_index, Value* result)                           \
  F(RefAsNonNull, const Value& arg, Value* result)                             \
  F(Drop, const Value& value)                                                  \
  F(DoReturn, Vector<Value> values)                                            \
  F(LocalGet, Value* result, const LocalIndexImmediate<validate>& imm)         \
  F(LocalSet, const Value& value, const LocalIndexImmediate<validate>& imm)    \
  F(LocalTee, const Value& value, Value* result,                               \
    const LocalIndexImmediate<validate>& imm)                                  \
  F(AllocateLocals, Vector<Value> local_values)                                \
  F(DeallocateLocals, uint32_t count)                                          \
  F(GlobalGet, Value* result, const GlobalIndexImmediate<validate>& imm)       \
  F(GlobalSet, const Value& value, const GlobalIndexImmediate<validate>& imm)  \
  F(TableGet, const Value& index, Value* result,                               \
    const TableIndexImmediate<validate>& imm)                                  \
  F(TableSet, const Value& index, const Value& value,                          \
    const TableIndexImmediate<validate>& imm)                                  \
  F(Unreachable)                                                               \
  F(Select, const Value& cond, const Value& fval, const Value& tval,           \
    Value* result)                                                             \
  F(Br, Control* target)                                                       \
  F(BrIf, const Value& cond, uint32_t depth)                                   \
  F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key)      \
  F(Else, Control* if_block)                                                   \
  F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm,        \
    const Value& index, Value* result)                                         \
  F(LoadTransform, LoadType type, LoadTransformationKind transform,            \
902 903
    const MemoryAccessImmediate<validate>& imm, const Value& index,            \
    Value* result)                                                             \
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
  F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm,      \
    const Value& index, const Value& value)                                    \
  F(CurrentMemoryPages, Value* result)                                         \
  F(MemoryGrow, const Value& value, Value* result)                             \
  F(CallDirect, const CallFunctionImmediate<validate>& imm,                    \
    const Value args[], Value returns[])                                       \
  F(CallIndirect, const Value& index,                                          \
    const CallIndirectImmediate<validate>& imm, const Value args[],            \
    Value returns[])                                                           \
  F(ReturnCall, const CallFunctionImmediate<validate>& imm,                    \
    const Value args[])                                                        \
  F(ReturnCallIndirect, const Value& index,                                    \
    const CallIndirectImmediate<validate>& imm, const Value args[])            \
  F(BrOnNull, const Value& ref_object, uint32_t depth)                         \
  F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result)              \
  F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm,     \
    const Vector<Value> inputs, Value* result)                                 \
921 922
  F(S128Const, const Simd128Immediate<validate>& imm, Value* result)           \
  F(Simd8x16ShuffleOp, const Simd128Immediate<validate>& imm,                  \
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
    const Value& input0, const Value& input1, Value* result)                   \
  F(Throw, const ExceptionIndexImmediate<validate>& imm,                       \
    const Vector<Value>& args)                                                 \
  F(Rethrow, const Value& exception)                                           \
  F(BrOnException, const Value& exception,                                     \
    const ExceptionIndexImmediate<validate>& imm, uint32_t depth,              \
    Vector<Value> values)                                                      \
  F(AtomicOp, WasmOpcode opcode, Vector<Value> args,                           \
    const MemoryAccessImmediate<validate>& imm, Value* result)                 \
  F(AtomicFence)                                                               \
  F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst,    \
    const Value& src, const Value& size)                                       \
  F(DataDrop, const DataDropImmediate<validate>& imm)                          \
  F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst,    \
    const Value& src, const Value& size)                                       \
  F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst,   \
    const Value& value, const Value& size)                                     \
  F(TableInit, const TableInitImmediate<validate>& imm, Vector<Value> args)    \
  F(ElemDrop, const ElemDropImmediate<validate>& imm)                          \
  F(TableCopy, const TableCopyImmediate<validate>& imm, Vector<Value> args)    \
  F(TableGrow, const TableIndexImmediate<validate>& imm, const Value& value,   \
    const Value& delta, Value* result)                                         \
  F(TableSize, const TableIndexImmediate<validate>& imm, Value* result)        \
  F(TableFill, const TableIndexImmediate<validate>& imm, const Value& start,   \
    const Value& value, const Value& count)                                    \
948 949
  F(StructNewWithRtt, const StructIndexImmediate<validate>& imm,               \
    const Value& rtt, const Value args[], Value* result)                       \
950 951
  F(StructNewDefault, const StructIndexImmediate<validate>& imm,               \
    const Value& rtt, Value* result)                                           \
952 953 954 955
  F(StructGet, const Value& struct_object,                                     \
    const FieldIndexImmediate<validate>& field, bool is_signed, Value* result) \
  F(StructSet, const Value& struct_object,                                     \
    const FieldIndexImmediate<validate>& field, const Value& field_value)      \
956 957 958
  F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm,                 \
    const Value& length, const Value& initial_value, const Value& rtt,         \
    Value* result)                                                             \
959 960
  F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm,                 \
    const Value& length, const Value& rtt, Value* result)                      \
961 962 963 964 965 966 967
  F(ArrayGet, const Value& array_obj,                                          \
    const ArrayIndexImmediate<validate>& imm, const Value& index,              \
    bool is_signed, Value* result)                                             \
  F(ArraySet, const Value& array_obj,                                          \
    const ArrayIndexImmediate<validate>& imm, const Value& index,              \
    const Value& value)                                                        \
  F(ArrayLen, const Value& array_obj, Value* result)                           \
968 969 970
  F(I31New, const Value& input, Value* result)                                 \
  F(I31GetS, const Value& input, Value* result)                                \
  F(I31GetU, const Value& input, Value* result)                                \
971
  F(RttCanon, const HeapTypeImmediate<validate>& imm, Value* result)           \
972 973
  F(RttSub, const HeapTypeImmediate<validate>& imm, const Value& parent,       \
    Value* result)                                                             \
974 975
  F(RefTest, const Value& obj, const Value& rtt, Value* result)                \
  F(RefCast, const Value& obj, const Value& rtt, Value* result)                \
976 977
  F(BrOnCast, const Value& obj, const Value& rtt, Value* result_on_branch,     \
    uint32_t depth)                                                            \
978
  F(PassThrough, const Value& from, Value* to)
979 980

// Generic Wasm bytecode decoder with utilities for decoding immediates,
981
// lengths, etc.
982
template <Decoder::ValidateFlag validate>
983 984
class WasmDecoder : public Decoder {
 public:
985
  WasmDecoder(Zone* zone, const WasmModule* module, const WasmFeatures& enabled,
986
              WasmFeatures* detected, const FunctionSig* sig, const byte* start,
987 988
              const byte* end, uint32_t buffer_offset = 0)
      : Decoder(start, end, buffer_offset),
989
        local_types_(zone),
990
        module_(module),
991 992
        enabled_(enabled),
        detected_(detected),
993
        sig_(sig) {}
994

995
  Zone* zone() const { return local_types_.get_allocator().zone(); }
996

997 998
  uint32_t num_locals() const {
    return static_cast<uint32_t>(local_types_.size());
999 1000
  }

1001 1002
  ValueType local_type(uint32_t index) const { return local_types_[index]; }

1003
  void InitializeLocalsFromSig() {
1004 1005 1006
    DCHECK_NOT_NULL(sig_);
    DCHECK_EQ(0, this->local_types_.size());
    local_types_.assign(sig_->parameters().begin(), sig_->parameters().end());
1007 1008 1009 1010
  }

  // Decodes local definitions in the current decoder.
  // Returns true iff locals are found.
1011 1012 1013 1014 1015 1016 1017
  // Writes the total length of decoded locals in 'total_length'.
  // If insert_postion is present, the decoded locals will be inserted into the
  // 'local_types_' of this decoder. Otherwise, this function is used just to
  // check validity and determine the encoding length of the locals in bytes.
  // The decoder's pc is not advanced. If no locals are found (i.e., no
  // compressed uint32 is found at pc), this will exit as 'false' and without an
  // error.
1018
  bool DecodeLocals(const byte* pc, uint32_t* total_length,
1019
                    const base::Optional<uint32_t> insert_position) {
1020 1021 1022
    uint32_t length;
    *total_length = 0;

1023
    // The 'else' value is useless, we pass it for convenience.
1024 1025 1026
    auto insert_iterator = insert_position.has_value()
                               ? local_types_.begin() + insert_position.value()
                               : local_types_.begin();
1027

1028
    // Decode local declarations, if any.
1029
    uint32_t entries = read_u32v<kValidate>(pc, &length, "local decls count");
1030
    if (!VALIDATE(ok())) {
1031 1032 1033
      error(pc + *total_length, "invalid local decls count");
      return false;
    }
1034

1035
    *total_length += length;
1036 1037
    TRACE("local decls count: %u\n", entries);

1038
    while (entries-- > 0) {
1039
      if (!VALIDATE(more())) {
1040 1041 1042 1043 1044
        error(end(), "expected more local decls but reached end of input");
        return false;
      }
      uint32_t count =
          read_u32v<kValidate>(pc + *total_length, &length, "local count");
1045
      if (!VALIDATE(ok())) {
1046
        error(pc + *total_length, "invalid local count");
1047 1048
        return false;
      }
1049 1050
      DCHECK_LE(local_types_.size(), kV8MaxWasmFunctionLocals);
      if (!VALIDATE(count <= kV8MaxWasmFunctionLocals - local_types_.size())) {
1051
        error(pc + *total_length, "local count too large");
1052
        return false;
1053
      }
1054 1055 1056 1057
      *total_length += length;

      ValueType type = value_type_reader::read_value_type<kValidate>(
          this, pc + *total_length, &length, enabled_);
1058
      if (!VALIDATE(type != kWasmBottom)) {
1059 1060 1061 1062
        error(pc + *total_length, "invalid local type");
        return false;
      }
      *total_length += length;
1063

1064
      if (insert_position.has_value()) {
1065
        // Move the insertion iterator to the end of the newly inserted locals.
1066
        insert_iterator =
1067
            local_types_.insert(insert_iterator, count, type) + count;
1068
      }
1069
    }
1070
    DCHECK(ok());
1071 1072 1073
    return true;
  }

1074
  static BitVector* AnalyzeLoopAssignment(WasmDecoder* decoder, const byte* pc,
1075
                                          uint32_t locals_count, Zone* zone) {
1076 1077 1078
    if (pc >= decoder->end()) return nullptr;
    if (*pc != kExprLoop) return nullptr;

1079 1080
    // The number of locals_count is augmented by 2 so that 'locals_count - 2'
    // can be used to track mem_size, and 'locals_count - 1' to track mem_start.
1081
    BitVector* assigned = zone->New<BitVector>(locals_count, zone);
1082 1083
    int depth = 0;
    // Iteratively process all AST nodes nested inside the loop.
1084
    while (pc < decoder->end() && VALIDATE(decoder->ok())) {
1085
      WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
1086
      uint32_t length = 1;
1087 1088 1089 1090 1091 1092 1093 1094
      switch (opcode) {
        case kExprLoop:
        case kExprIf:
        case kExprBlock:
        case kExprTry:
          length = OpcodeLength(decoder, pc);
          depth++;
          break;
1095 1096
        case kExprLocalSet:  // fallthru
        case kExprLocalTee: {
1097
          LocalIndexImmediate<validate> imm(decoder, pc + 1);
1098
          if (assigned->length() > 0 &&
1099
              imm.index < static_cast<uint32_t>(assigned->length())) {
1100
            // Unverified code might have an out-of-bounds index.
1101
            assigned->Add(imm.index);
1102
          }
1103
          length = 1 + imm.length;
1104 1105
          break;
        }
1106
        case kExprMemoryGrow:
1107 1108
        case kExprCallFunction:
        case kExprCallIndirect:
1109 1110
        case kExprReturnCall:
        case kExprReturnCallIndirect:
1111
          // Add instance cache nodes to the assigned set.
1112 1113
          // TODO(titzer): make this more clear.
          assigned->Add(locals_count - 1);
1114 1115
          length = OpcodeLength(decoder, pc);
          break;
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
        case kExprEnd:
          depth--;
          break;
        default:
          length = OpcodeLength(decoder, pc);
          break;
      }
      if (depth <= 0) break;
      pc += length;
    }
1126
    return VALIDATE(decoder->ok()) ? assigned : nullptr;
1127 1128
  }

1129
  inline bool Validate(const byte* pc, LocalIndexImmediate<validate>& imm) {
1130
    if (!VALIDATE(imm.index < num_locals())) {
1131
      errorf(pc, "invalid local index: %u", imm.index);
1132
      return false;
1133
    }
1134
    return true;
1135 1136
  }

1137
  inline bool Complete(ExceptionIndexImmediate<validate>& imm) {
1138
    if (!VALIDATE(imm.index < module_->exceptions.size())) return false;
1139
    imm.exception = &module_->exceptions[imm.index];
1140
    return true;
1141 1142
  }

1143
  inline bool Validate(const byte* pc, ExceptionIndexImmediate<validate>& imm) {
1144 1145
    if (!Complete(imm)) {
      errorf(pc, "Invalid exception index: %u", imm.index);
1146 1147 1148 1149 1150
      return false;
    }
    return true;
  }

1151
  inline bool Validate(const byte* pc, GlobalIndexImmediate<validate>& imm) {
1152
    if (!VALIDATE(imm.index < module_->globals.size())) {
1153
      errorf(pc, "invalid global index: %u", imm.index);
1154
      return false;
1155
    }
1156 1157
    imm.global = &module_->globals[imm.index];
    imm.type = imm.global->type;
1158
    return true;
1159 1160
  }

1161
  inline bool Complete(StructIndexImmediate<validate>& imm) {
1162
    if (!VALIDATE(module_->has_struct(imm.index))) return false;
1163 1164 1165 1166 1167
    imm.struct_type = module_->struct_type(imm.index);
    return true;
  }

  inline bool Validate(const byte* pc, StructIndexImmediate<validate>& imm) {
1168
    if (Complete(imm)) return true;
1169 1170 1171 1172 1173 1174
    errorf(pc, "invalid struct index: %u", imm.index);
    return false;
  }

  inline bool Validate(const byte* pc, FieldIndexImmediate<validate>& imm) {
    if (!Validate(pc, imm.struct_index)) return false;
1175 1176 1177 1178 1179 1180
    if (!VALIDATE(imm.index < imm.struct_index.struct_type->field_count())) {
      errorf(pc + imm.struct_index.length, "invalid field index: %u",
             imm.index);
      return false;
    }
    return true;
1181 1182
  }

1183
  inline bool Complete(ArrayIndexImmediate<validate>& imm) {
1184
    if (!VALIDATE(module_->has_array(imm.index))) return false;
1185 1186 1187 1188 1189
    imm.array_type = module_->array_type(imm.index);
    return true;
  }

  inline bool Validate(const byte* pc, ArrayIndexImmediate<validate>& imm) {
1190
    if (!Complete(imm)) {
1191 1192 1193 1194
      errorf(pc, "invalid array index: %u", imm.index);
      return false;
    }
    return true;
1195 1196
  }

1197
  inline bool CanReturnCall(const FunctionSig* target_sig) {
1198
    if (target_sig == nullptr) return false;
1199
    size_t num_returns = sig_->return_count();
1200
    if (num_returns != target_sig->return_count()) return false;
1201
    for (size_t i = 0; i < num_returns; ++i) {
1202
      if (sig_->GetReturn(i) != target_sig->GetReturn(i)) return false;
1203 1204 1205 1206
    }
    return true;
  }

1207
  inline bool Complete(CallFunctionImmediate<validate>& imm) {
1208
    if (!VALIDATE(imm.index < module_->functions.size())) return false;
1209
    imm.sig = module_->functions[imm.index].sig;
1210 1211 1212
    if (imm.sig->return_count() > 1) {
      this->detected_->Add(kFeature_mv);
    }
1213
    return true;
1214 1215
  }

1216
  inline bool Validate(const byte* pc, CallFunctionImmediate<validate>& imm) {
1217 1218
    if (!Complete(imm)) {
      errorf(pc, "invalid function index: %u", imm.index);
1219
      return false;
1220
    }
1221
    return true;
1222 1223
  }

1224
  inline bool Complete(CallIndirectImmediate<validate>& imm) {
1225
    if (!VALIDATE(module_->has_signature(imm.sig_index))) return false;
1226
    imm.sig = module_->signature(imm.sig_index);
1227 1228 1229
    if (imm.sig->return_count() > 1) {
      this->detected_->Add(kFeature_mv);
    }
1230
    return true;
1231 1232
  }

1233
  inline bool Validate(const byte* pc, CallIndirectImmediate<validate>& imm) {
1234
    if (!VALIDATE(imm.table_index < module_->tables.size())) {
1235 1236 1237
      error("function table has to exist to execute call_indirect");
      return false;
    }
1238 1239 1240
    if (!VALIDATE(IsSubtypeOf(module_->tables[imm.table_index].type,
                              kWasmFuncRef, module_))) {
      error("table of call_indirect must be of a function type");
1241 1242
      return false;
    }
1243 1244
    if (!Complete(imm)) {
      errorf(pc, "invalid signature index: #%u", imm.sig_index);
1245
      return false;
1246
    }
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
    // Check that the dynamic signature for this call is a subtype of the static
    // type of the table the function is defined in.
    if (!VALIDATE(IsSubtypeOf(ValueType::Ref(imm.sig_index, kNonNullable),
                              module_->tables[imm.table_index].type,
                              module_))) {
      errorf(pc,
             "call_indirect: Signature of function %u is not a subtype of "
             "table %u",
             imm.sig_index, imm.table_index);
    }
1257
    return true;
1258 1259
  }

1260
  inline bool Validate(const byte* pc, BranchDepthImmediate<validate>& imm,
1261
                       size_t control_depth) {
1262
    if (!VALIDATE(imm.depth < control_depth)) {
1263
      errorf(pc, "invalid branch depth: %u", imm.depth);
1264
      return false;
1265
    }
1266
    return true;
1267 1268
  }

1269 1270
  inline bool Validate(const byte* pc, BranchTableImmediate<validate>& imm,
                       size_t block_depth) {
1271
    if (!VALIDATE(imm.table_count <= kV8MaxWasmFunctionBrTableSize)) {
1272
      errorf(pc, "invalid table count (> max br_table size): %u",
1273
             imm.table_count);
1274 1275
      return false;
    }
1276
    return checkAvailable(imm.table_count);
1277 1278
  }

1279 1280 1281 1282 1283 1284 1285
  inline bool Validate(const byte* pc,
                       BranchOnExceptionImmediate<validate>& imm,
                       size_t control_size) {
    return Validate(pc, imm.depth, control_size) &&
           Validate(pc + imm.depth.length, imm.index);
  }

1286
  inline bool Validate(const byte* pc, WasmOpcode opcode,
1287
                       SimdLaneImmediate<validate>& imm) {
1288 1289
    uint8_t num_lanes = 0;
    switch (opcode) {
1290 1291
      case kExprF64x2ExtractLane:
      case kExprF64x2ReplaceLane:
1292 1293 1294 1295
      case kExprI64x2ExtractLane:
      case kExprI64x2ReplaceLane:
        num_lanes = 2;
        break;
1296 1297 1298 1299 1300 1301
      case kExprF32x4ExtractLane:
      case kExprF32x4ReplaceLane:
      case kExprI32x4ExtractLane:
      case kExprI32x4ReplaceLane:
        num_lanes = 4;
        break;
1302 1303
      case kExprI16x8ExtractLaneS:
      case kExprI16x8ExtractLaneU:
1304 1305 1306
      case kExprI16x8ReplaceLane:
        num_lanes = 8;
        break;
1307 1308
      case kExprI8x16ExtractLaneS:
      case kExprI8x16ExtractLaneU:
1309 1310 1311 1312 1313 1314 1315
      case kExprI8x16ReplaceLane:
        num_lanes = 16;
        break;
      default:
        UNREACHABLE();
        break;
    }
1316
    if (!VALIDATE(imm.lane >= 0 && imm.lane < num_lanes)) {
1317
      error(pc, "invalid lane index");
1318 1319 1320 1321 1322 1323
      return false;
    } else {
      return true;
    }
  }

1324
  inline bool Validate(const byte* pc, Simd128Immediate<validate>& imm) {
1325
    uint8_t max_lane = 0;
1326
    for (uint32_t i = 0; i < kSimd128Size; ++i) {
1327
      max_lane = std::max(max_lane, imm.value[i]);
1328
    }
1329
    // Shuffle indices must be in [0..31] for a 16 lane shuffle.
1330
    if (!VALIDATE(max_lane < 2 * kSimd128Size)) {
1331
      error(pc, "invalid shuffle mask");
1332 1333
      return false;
    }
1334
    return true;
1335 1336
  }

1337
  inline bool Complete(BlockTypeImmediate<validate>& imm) {
1338
    if (imm.type != kWasmBottom) return true;
1339
    if (!VALIDATE(module_->has_signature(imm.sig_index))) return false;
1340
    imm.sig = module_->signature(imm.sig_index);
1341 1342 1343
    if (imm.sig->return_count() > 1) {
      this->detected_->Add(kFeature_mv);
    }
1344 1345 1346
    return true;
  }

1347
  inline bool Validate(const byte* pc, BlockTypeImmediate<validate>& imm) {
1348
    if (!Complete(imm)) {
1349 1350
      errorf(pc, "block type index %u out of bounds (%zu types)", imm.sig_index,
             module_->types.size());
1351 1352 1353 1354 1355
      return false;
    }
    return true;
  }

1356
  inline bool Validate(const byte* pc, FunctionIndexImmediate<validate>& imm) {
1357
    if (!VALIDATE(imm.index < module_->functions.size())) {
1358 1359 1360
      errorf(pc, "invalid function index: %u", imm.index);
      return false;
    }
1361
    if (!VALIDATE(module_->functions[imm.index].declared)) {
1362 1363 1364
      this->errorf(pc, "undeclared reference to function #%u", imm.index);
      return false;
    }
1365 1366 1367
    return true;
  }

1368
  inline bool Validate(const byte* pc, MemoryIndexImmediate<validate>& imm) {
1369
    if (!VALIDATE(module_->has_memory)) {
1370
      errorf(pc, "memory instruction with no memory");
1371 1372 1373 1374 1375
      return false;
    }
    return true;
  }

1376
  inline bool Validate(const byte* pc, MemoryInitImmediate<validate>& imm) {
1377 1378
    if (!VALIDATE(imm.data_segment_index <
                  module_->num_declared_data_segments)) {
1379
      errorf(pc, "invalid data segment index: %u", imm.data_segment_index);
1380 1381
      return false;
    }
1382
    if (!Validate(pc + imm.length - imm.memory.length, imm.memory))
1383
      return false;
1384 1385 1386
    return true;
  }

1387
  inline bool Validate(const byte* pc, DataDropImmediate<validate>& imm) {
1388
    if (!VALIDATE(imm.index < module_->num_declared_data_segments)) {
1389
      errorf(pc, "invalid data segment index: %u", imm.index);
1390 1391
      return false;
    }
1392 1393 1394
    return true;
  }

1395 1396 1397
  inline bool Validate(const byte* pc, MemoryCopyImmediate<validate>& imm) {
    return Validate(pc, imm.memory_src) &&
           Validate(pc + imm.memory_src.length, imm.memory_dst);
1398 1399
  }

1400
  inline bool Validate(const byte* pc, TableIndexImmediate<validate>& imm) {
1401
    if (!VALIDATE(imm.index < module_->tables.size())) {
1402
      errorf(pc, "invalid table index: %u", imm.index);
1403 1404 1405 1406 1407
      return false;
    }
    return true;
  }

1408
  inline bool Validate(const byte* pc, TableInitImmediate<validate>& imm) {
1409
    if (!VALIDATE(imm.elem_segment_index < module_->elem_segments.size())) {
1410
      errorf(pc, "invalid element segment index: %u", imm.elem_segment_index);
1411 1412
      return false;
    }
1413
    if (!Validate(pc + imm.length - imm.table.length, imm.table)) {
1414
      return false;
1415 1416
    }
    ValueType elem_type = module_->elem_segments[imm.elem_segment_index].type;
1417 1418
    if (!VALIDATE(IsSubtypeOf(elem_type, module_->tables[imm.table.index].type,
                              module_))) {
1419
      errorf(pc, "table %u is not a super-type of %s", imm.table.index,
1420
             elem_type.name().c_str());
1421 1422
      return false;
    }
1423 1424 1425
    return true;
  }

1426
  inline bool Validate(const byte* pc, ElemDropImmediate<validate>& imm) {
1427
    if (!VALIDATE(imm.index < module_->elem_segments.size())) {
1428
      errorf(pc, "invalid element segment index: %u", imm.index);
1429 1430 1431 1432 1433
      return false;
    }
    return true;
  }

1434 1435 1436
  inline bool Validate(const byte* pc, TableCopyImmediate<validate>& imm) {
    if (!Validate(pc, imm.table_src)) return false;
    if (!Validate(pc + imm.table_src.length, imm.table_dst)) return false;
1437
    ValueType src_type = module_->tables[imm.table_src.index].type;
1438 1439
    if (!VALIDATE(IsSubtypeOf(
            src_type, module_->tables[imm.table_dst.index].type, module_))) {
1440
      errorf(pc, "table %u is not a super-type of %s", imm.table_dst.index,
1441
             src_type.name().c_str());
1442 1443
      return false;
    }
1444 1445 1446
    return true;
  }

1447
  inline bool Validate(const byte* pc, HeapTypeImmediate<validate>& imm) {
1448 1449 1450 1451
    if (!VALIDATE(!imm.type.is_bottom())) {
      error(pc, "invalid heap type");
      return false;
    }
1452
    if (!VALIDATE(imm.type.is_generic() ||
1453 1454
                  module_->has_type(imm.type.ref_index()))) {
      errorf(pc, "Type index %u is out of bounds", imm.type.ref_index());
1455 1456 1457 1458 1459
      return false;
    }
    return true;
  }

1460
  static uint32_t OpcodeLength(WasmDecoder* decoder, const byte* pc) {
1461 1462 1463 1464 1465 1466 1467
    WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
    switch (opcode) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
      FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
      FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
      {
1468
        MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
1469
        return 1 + imm.length;
1470 1471 1472
      }
      case kExprBr:
      case kExprBrIf: {
1473
        BranchDepthImmediate<validate> imm(decoder, pc + 1);
1474
        return 1 + imm.length;
1475
      }
1476 1477
      case kExprGlobalGet:
      case kExprGlobalSet: {
1478
        GlobalIndexImmediate<validate> imm(decoder, pc + 1);
1479
        return 1 + imm.length;
1480
      }
1481 1482
      case kExprTableGet:
      case kExprTableSet: {
1483
        TableIndexImmediate<validate> imm(decoder, pc + 1);
1484 1485
        return 1 + imm.length;
      }
1486 1487
      case kExprCallFunction:
      case kExprReturnCall: {
1488
        CallFunctionImmediate<validate> imm(decoder, pc + 1);
1489
        return 1 + imm.length;
1490
      }
1491 1492
      case kExprCallIndirect:
      case kExprReturnCallIndirect: {
1493 1494
        CallIndirectImmediate<validate> imm(WasmFeatures::All(), decoder,
                                            pc + 1);
1495
        return 1 + imm.length;
1496 1497 1498 1499 1500 1501
      }

      case kExprTry:
      case kExprIf:  // fall through
      case kExprLoop:
      case kExprBlock: {
1502
        BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
1503
        return 1 + imm.length;
1504 1505
      }

1506
      case kExprLet: {
1507
        BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
1508 1509 1510 1511 1512 1513 1514
        uint32_t locals_length;
        bool locals_result =
            decoder->DecodeLocals(decoder->pc() + 1 + imm.length,
                                  &locals_length, base::Optional<uint32_t>());
        return 1 + imm.length + (locals_result ? locals_length : 0);
      }

1515
      case kExprThrow: {
1516
        ExceptionIndexImmediate<validate> imm(decoder, pc + 1);
1517
        return 1 + imm.length;
1518 1519
      }

1520
      case kExprBrOnExn: {
1521
        BranchOnExceptionImmediate<validate> imm(decoder, pc + 1);
1522
        return 1 + imm.length;
1523 1524
      }

1525
      case kExprBrOnNull: {
1526
        BranchDepthImmediate<validate> imm(decoder, pc + 1);
1527 1528 1529
        return 1 + imm.length;
      }

1530 1531 1532
      case kExprLocalGet:
      case kExprLocalSet:
      case kExprLocalTee: {
1533
        LocalIndexImmediate<validate> imm(decoder, pc + 1);
1534
        return 1 + imm.length;
1535
      }
1536
      case kExprSelectWithType: {
1537
        SelectTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
1538 1539
        return 1 + imm.length;
      }
1540
      case kExprBrTable: {
1541
        BranchTableImmediate<validate> imm(decoder, pc + 1);
1542
        BranchTableIterator<validate> iterator(decoder, imm);
1543 1544 1545
        return 1 + iterator.length();
      }
      case kExprI32Const: {
1546
        ImmI32Immediate<validate> imm(decoder, pc + 1);
1547
        return 1 + imm.length;
1548 1549
      }
      case kExprI64Const: {
1550
        ImmI64Immediate<validate> imm(decoder, pc + 1);
1551
        return 1 + imm.length;
1552
      }
1553
      case kExprRefNull: {
1554
        HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
1555 1556 1557
        return 1 + imm.length;
      }
      case kExprRefIsNull: {
1558
        return 1;
1559
      }
1560
      case kExprRefFunc: {
1561
        FunctionIndexImmediate<validate> imm(decoder, pc + 1);
1562 1563
        return 1 + imm.length;
      }
1564
      case kExprMemoryGrow:
1565
      case kExprMemorySize: {
1566
        MemoryIndexImmediate<validate> imm(decoder, pc + 1);
1567
        return 1 + imm.length;
1568 1569 1570 1571 1572
      }
      case kExprF32Const:
        return 5;
      case kExprF64Const:
        return 9;
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
      case kNumericPrefix: {
        byte numeric_index =
            decoder->read_u8<validate>(pc + 1, "numeric_index");
        WasmOpcode opcode =
            static_cast<WasmOpcode>(kNumericPrefix << 8 | numeric_index);
        switch (opcode) {
          case kExprI32SConvertSatF32:
          case kExprI32UConvertSatF32:
          case kExprI32SConvertSatF64:
          case kExprI32UConvertSatF64:
          case kExprI64SConvertSatF32:
          case kExprI64UConvertSatF32:
          case kExprI64SConvertSatF64:
          case kExprI64UConvertSatF64:
            return 2;
          case kExprMemoryInit: {
1589
            MemoryInitImmediate<validate> imm(decoder, pc + 2);
1590 1591
            return 2 + imm.length;
          }
1592
          case kExprDataDrop: {
1593
            DataDropImmediate<validate> imm(decoder, pc + 2);
1594 1595
            return 2 + imm.length;
          }
1596
          case kExprMemoryCopy: {
1597
            MemoryCopyImmediate<validate> imm(decoder, pc + 2);
1598 1599
            return 2 + imm.length;
          }
1600
          case kExprMemoryFill: {
1601
            MemoryIndexImmediate<validate> imm(decoder, pc + 2);
1602 1603 1604
            return 2 + imm.length;
          }
          case kExprTableInit: {
1605
            TableInitImmediate<validate> imm(decoder, pc + 2);
1606 1607
            return 2 + imm.length;
          }
1608
          case kExprElemDrop: {
1609
            ElemDropImmediate<validate> imm(decoder, pc + 2);
1610 1611 1612
            return 2 + imm.length;
          }
          case kExprTableCopy: {
1613
            TableCopyImmediate<validate> imm(decoder, pc + 2);
1614 1615
            return 2 + imm.length;
          }
1616
          case kExprTableGrow:
1617 1618
          case kExprTableSize:
          case kExprTableFill: {
1619
            TableIndexImmediate<validate> imm(decoder, pc + 2);
1620 1621
            return 2 + imm.length;
          }
1622 1623 1624 1625 1626
          default:
            decoder->error(pc, "invalid numeric opcode");
            return 2;
        }
      }
1627
      case kSimdPrefix: {
1628 1629
        uint32_t length = 0;
        opcode = decoder->read_prefixed_opcode<validate>(pc, &length);
1630 1631 1632 1633
        switch (opcode) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
          FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
1634
          return 1 + length;
1635 1636 1637
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
          FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
1638
          return 2 + length;
1639 1640
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
          FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1641
          FOREACH_SIMD_POST_MVP_MEM_OPCODE(DECLARE_OPCODE_CASE)
1642 1643
#undef DECLARE_OPCODE_CASE
          {
1644
            MemoryAccessImmediate<validate> imm(decoder, pc + length + 1,
1645
                                                UINT32_MAX);
1646
            return 1 + length + imm.length;
1647 1648
          }
          // Shuffles require a byte per lane, or 16 immediate bytes.
1649
          case kExprS128Const:
1650
          case kExprS8x16Shuffle:
1651
            return 1 + length + kSimd128Size;
1652 1653
          default:
            decoder->error(pc, "invalid SIMD opcode");
1654
            return 1 + length;
1655 1656
        }
      }
1657 1658 1659 1660 1661 1662 1663 1664 1665
      case kAtomicPrefix: {
        byte atomic_index = decoder->read_u8<validate>(pc + 1, "atomic_index");
        WasmOpcode opcode =
            static_cast<WasmOpcode>(kAtomicPrefix << 8 | atomic_index);
        switch (opcode) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
          FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
          {
1666
            MemoryAccessImmediate<validate> imm(decoder, pc + 2, UINT32_MAX);
1667
            return 2 + imm.length;
1668
          }
1669 1670 1671 1672 1673 1674
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
          FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
          {
            return 2 + 1;
          }
1675 1676 1677 1678 1679
          default:
            decoder->error(pc, "invalid Atomics opcode");
            return 2;
        }
      }
1680 1681 1682 1683
      case kGCPrefix: {
        byte gc_index = decoder->read_u8<validate>(pc + 1, "gc_index");
        WasmOpcode opcode = static_cast<WasmOpcode>(kGCPrefix << 8 | gc_index);
        switch (opcode) {
1684
          case kExprStructNewWithRtt:
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695
          case kExprStructNewDefault: {
            StructIndexImmediate<validate> imm(decoder, pc + 2);
            return 2 + imm.length;
          }
          case kExprStructGet:
          case kExprStructGetS:
          case kExprStructGetU:
          case kExprStructSet: {
            FieldIndexImmediate<validate> imm(decoder, pc + 2);
            return 2 + imm.length;
          }
1696
          case kExprArrayNewWithRtt:
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709
          case kExprArrayNewDefault:
          case kExprArrayGet:
          case kExprArrayGetS:
          case kExprArrayGetU:
          case kExprArraySet:
          case kExprArrayLen: {
            ArrayIndexImmediate<validate> imm(decoder, pc + 2);
            return 2 + imm.length;
          }
          case kExprBrOnCast: {
            BranchDepthImmediate<validate> imm(decoder, pc + 2);
            return 2 + imm.length;
          }
1710 1711 1712 1713
          case kExprRttCanon:
          case kExprRttSub: {
            // TODO(7748): Account for rtt.sub's additional immediates if
            // they stick.
1714 1715 1716
            HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder,
                                            pc + 2);
            return 2 + imm.length;
1717
          }
1718

1719 1720 1721
          case kExprI31New:
          case kExprI31GetS:
          case kExprI31GetU:
1722
            return 2;
1723 1724 1725 1726 1727 1728 1729 1730
          case kExprRefTest:
          case kExprRefCast: {
            HeapTypeImmediate<validate> ht1(WasmFeatures::All(), decoder,
                                            pc + 2);
            HeapTypeImmediate<validate> ht2(WasmFeatures::All(), decoder,
                                            pc + 2 + ht1.length);
            return 2 + ht1.length + ht2.length;
          }
1731 1732

          default:
1733 1734 1735
            // This is unreachable except for malformed modules.
            decoder->error(pc, "invalid gc opcode");
            return 2;
1736 1737
        }
      }
1738 1739 1740 1741 1742
      default:
        return 1;
    }
  }

1743 1744
  // TODO(clemensb): This is only used by the interpreter; move there.
  V8_EXPORT_PRIVATE std::pair<uint32_t, uint32_t> StackEffect(const byte* pc) {
1745 1746
    WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
    // Handle "simple" opcodes with a fixed signature first.
1747
    const FunctionSig* sig = WasmOpcodes::Signature(opcode);
1748 1749 1750 1751 1752 1753 1754
    if (!sig) sig = WasmOpcodes::AsmjsSignature(opcode);
    if (sig) return {sig->parameter_count(), sig->return_count()};

#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
    // clang-format off
    switch (opcode) {
      case kExprSelect:
1755
      case kExprSelectWithType:
1756
        return {3, 1};
1757
      case kExprTableSet:
1758 1759 1760
      FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
        return {2, 0};
      FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1761
      case kExprTableGet:
1762
      case kExprLocalTee:
1763
      case kExprMemoryGrow:
1764
      case kExprRefAsNonNull:
1765
      case kExprBrOnNull:
1766
      case kExprRefIsNull:
1767
        return {1, 1};
1768
      case kExprLocalSet:
1769
      case kExprGlobalSet:
1770 1771 1772 1773
      case kExprDrop:
      case kExprBrIf:
      case kExprBrTable:
      case kExprIf:
1774
      case kExprRethrow:
1775
        return {1, 0};
1776
      case kExprLocalGet:
1777
      case kExprGlobalGet:
1778 1779 1780 1781
      case kExprI32Const:
      case kExprI64Const:
      case kExprF32Const:
      case kExprF64Const:
1782
      case kExprRefNull:
1783
      case kExprRefFunc:
1784 1785 1786
      case kExprMemorySize:
        return {0, 1};
      case kExprCallFunction: {
1787 1788
        CallFunctionImmediate<validate> imm(this, pc + 1);
        CHECK(Complete(imm));
1789
        return {imm.sig->parameter_count(), imm.sig->return_count()};
1790 1791
      }
      case kExprCallIndirect: {
1792 1793
        CallIndirectImmediate<validate> imm(this->enabled_, this, pc + 1);
        CHECK(Complete(imm));
1794
        // Indirect calls pop an additional argument for the table index.
1795 1796
        return {imm.sig->parameter_count() + 1,
                imm.sig->return_count()};
1797
      }
1798
      case kExprThrow: {
1799 1800
        ExceptionIndexImmediate<validate> imm(this, pc + 1);
        CHECK(Complete(imm));
1801 1802 1803
        DCHECK_EQ(0, imm.exception->sig->return_count());
        return {imm.exception->sig->parameter_count(), 0};
      }
1804 1805 1806 1807 1808
      case kExprBr:
      case kExprBlock:
      case kExprLoop:
      case kExprEnd:
      case kExprElse:
1809
      case kExprTry:
1810
      case kExprCatch:
1811
      case kExprBrOnExn:
1812 1813
      case kExprNop:
      case kExprReturn:
1814 1815
      case kExprReturnCall:
      case kExprReturnCallIndirect:
1816 1817
      case kExprUnreachable:
        return {0, 0};
1818 1819 1820
      case kExprLet:
        // TODO(7748): Implement
        return {0, 0};
1821
      case kNumericPrefix:
1822 1823
      case kAtomicPrefix:
      case kSimdPrefix: {
1824
        opcode = this->read_prefixed_opcode<validate>(pc);
1825
        switch (opcode) {
1826
          FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1827
            return {1, 1};
1828
          FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1829
          FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1830
            return {2, 1};
1831 1832
          FOREACH_SIMD_CONST_OPCODE(DECLARE_OPCODE_CASE)
            return {0, 1};
1833 1834 1835 1836
          default: {
            sig = WasmOpcodes::Signature(opcode);
            if (sig) {
              return {sig->parameter_count(), sig->return_count()};
1837 1838
            } else {
              UNREACHABLE();
1839 1840 1841
            }
          }
        }
1842 1843 1844 1845
      }
      case kGCPrefix: {
        opcode = this->read_prefixed_opcode<validate>(pc);
        switch (opcode) {
1846
          case kExprStructNewDefault:
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857
          case kExprStructGet:
          case kExprStructGetS:
          case kExprStructGetU:
          case kExprI31New:
          case kExprI31GetS:
          case kExprI31GetU:
          case kExprArrayLen:
          case kExprRttSub:
            return {1, 1};
          case kExprStructSet:
            return {2, 0};
1858
          case kExprArrayNewDefault:
1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869
          case kExprArrayGet:
          case kExprArrayGetS:
          case kExprArrayGetU:
          case kExprRefTest:
          case kExprRefCast:
          case kExprBrOnCast:
            return {2, 1};
          case kExprArraySet:
            return {3, 0};
          case kExprRttCanon:
            return {0, 1};
1870
          case kExprArrayNewWithRtt:
1871 1872 1873 1874 1875 1876 1877 1878 1879
            return {3, 1};
          case kExprStructNewWithRtt: {
            StructIndexImmediate<validate> imm(this, this->pc_ + 2);
            this->Complete(imm);
            return {imm.struct_type->field_count() + 1, 1};
          }
          default:
            UNREACHABLE();
        }
1880
      }
1881
      default:
1882 1883
        FATAL("unimplemented opcode: %x (%s)", opcode,
              WasmOpcodes::OpcodeName(opcode));
1884 1885 1886 1887 1888
        return {0, 0};
    }
#undef DECLARE_OPCODE_CASE
    // clang-format on
  }
1889 1890 1891 1892 1893 1894 1895 1896 1897 1898

  // The {Zone} is implicitly stored in the {ZoneAllocator} which is part of
  // this {ZoneVector}. Hence save one field and just get it from there if
  // needed (see {zone()} accessor below).
  ZoneVector<ValueType> local_types_;

  const WasmModule* module_;
  const WasmFeatures enabled_;
  WasmFeatures* detected_;
  const FunctionSig* sig_;
1899 1900
};

1901
#define CALL_INTERFACE(name, ...) interface_.name(this, ##__VA_ARGS__)
1902 1903 1904 1905 1906 1907 1908 1909
#define CALL_INTERFACE_IF_REACHABLE(name, ...)            \
  do {                                                    \
    DCHECK(!control_.empty());                            \
    DCHECK_EQ(current_code_reachable_,                    \
              this->ok() && control_.back().reachable()); \
    if (current_code_reachable_) {                        \
      interface_.name(this, ##__VA_ARGS__);               \
    }                                                     \
1910
  } while (false)
1911 1912 1913 1914 1915 1916 1917
#define CALL_INTERFACE_IF_PARENT_REACHABLE(name, ...)           \
  do {                                                          \
    DCHECK(!control_.empty());                                  \
    if (VALIDATE(this->ok()) &&                                 \
        (control_.size() == 1 || control_at(1)->reachable())) { \
      interface_.name(this, ##__VA_ARGS__);                     \
    }                                                           \
1918 1919
  } while (false)

1920
template <Decoder::ValidateFlag validate, typename Interface>
1921
class WasmFullDecoder : public WasmDecoder<validate> {
1922 1923
  using Value = typename Interface::Value;
  using Control = typename Interface::Control;
1924
  using ArgVector = base::SmallVector<Value, 8>;
1925

1926 1927
  // All Value types should be trivially copyable for performance. We push, pop,
  // and store them in local variables.
1928
  ASSERT_TRIVIALLY_COPYABLE(Value);
1929 1930 1931

 public:
  template <typename... InterfaceArgs>
1932
  WasmFullDecoder(Zone* zone, const WasmModule* module,
1933
                  const WasmFeatures& enabled, WasmFeatures* detected,
1934
                  const FunctionBody& body, InterfaceArgs&&... interface_args)
1935 1936
      : WasmDecoder<validate>(zone, module, enabled, detected, body.sig,
                              body.start, body.end, body.offset),
1937 1938
        interface_(std::forward<InterfaceArgs>(interface_args)...),
        stack_(zone),
1939
        control_(zone) {}
1940 1941 1942 1943 1944 1945

  Interface& interface() { return interface_; }

  bool Decode() {
    DCHECK(stack_.empty());
    DCHECK(control_.empty());
1946
    DCHECK_LE(this->pc_, this->end_);
1947
    DCHECK_EQ(this->num_locals(), 0);
1948

1949
    this->InitializeLocalsFromSig();
1950
    uint32_t params_count = static_cast<uint32_t>(this->num_locals());
1951
    uint32_t locals_length;
1952 1953 1954 1955 1956 1957
    this->DecodeLocals(this->pc(), &locals_length, params_count);
    for (uint32_t index = params_count; index < this->num_locals(); index++) {
      if (!VALIDATE(this->local_type(index).is_defaultable())) {
        this->errorf(
            this->pc(),
            "Cannot define function-level local of non-defaultable type %s",
1958
            this->local_type(index).name().c_str());
1959 1960
      }
    }
1961 1962
    this->consume_bytes(locals_length);

1963
    CALL_INTERFACE(StartFunction);
1964
    DecodeFunctionBody();
1965
    if (!this->failed()) CALL_INTERFACE(FinishFunction);
1966

1967 1968
    // Generate a better error message whether the unterminated control
    // structure is the function body block or an innner structure.
1969 1970 1971 1972 1973 1974
    if (!VALIDATE(control_.empty())) {
      if (control_.size() > 1) {
        this->error(control_.back().pc, "unterminated control structure");
      } else if (control_.size() == 1) {
        this->error("function body must end with \"end\" opcode");
      }
1975 1976
    }

1977
    if (!VALIDATE(this->ok())) return this->TraceFailed();
1978

1979
    TRACE("wasm-decode %s\n\n", VALIDATE(this->ok()) ? "ok" : "failed");
1980 1981 1982 1983 1984

    return true;
  }

  bool TraceFailed() {
1985 1986 1987
    TRACE("wasm-error module+%-6d func+%d: %s\n\n", this->error_.offset(),
          this->GetBufferRelativeOffset(this->error_.offset()),
          this->error_.message().c_str());
1988 1989 1990 1991 1992
    return false;
  }

  const char* SafeOpcodeNameAt(const byte* pc) {
    if (pc >= this->end_) return "<end>";
1993 1994 1995 1996
    WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
    if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
      return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(opcode));
    }
1997 1998
    opcode = this->template read_prefixed_opcode<Decoder::kValidate>(pc);
    return WasmOpcodes::OpcodeName(opcode);
1999 2000
  }

2001
  inline WasmCodePosition position() {
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
    int offset = static_cast<int>(this->pc_ - this->start_);
    DCHECK_EQ(this->pc_ - this->start_, offset);  // overflows cannot happen
    return offset;
  }

  inline uint32_t control_depth() const {
    return static_cast<uint32_t>(control_.size());
  }

  inline Control* control_at(uint32_t depth) {
    DCHECK_GT(control_.size(), depth);
2013
    return &control_.back() - depth;
2014 2015 2016
  }

  inline uint32_t stack_size() const {
2017
    DCHECK_GE(kMaxUInt32, stack_.size());
2018 2019 2020
    return static_cast<uint32_t>(stack_.size());
  }

2021 2022 2023 2024
  inline Value* stack_value(uint32_t depth) {
    DCHECK_LT(0, depth);
    DCHECK_GE(stack_.size(), depth);
    return &*(stack_.end() - depth);
2025 2026
  }

2027 2028 2029 2030 2031 2032 2033 2034
  void SetSucceedingCodeDynamicallyUnreachable() {
    Control* current = &control_.back();
    if (current->reachable()) {
      current->reachability = kSpecOnlyReachable;
      current_code_reachable_ = false;
    }
  }

2035 2036 2037
 private:
  Interface interface_;

2038 2039
  ZoneVector<Value> stack_;      // stack of values.
  ZoneVector<Control> control_;  // stack of blocks, loops, and ifs.
2040 2041 2042
  // Controls whether code should be generated for the current block (basically
  // a cache for {ok() && control_.back().reachable()}).
  bool current_code_reachable_ = true;
2043

2044
  static Value UnreachableValue(const uint8_t* pc) {
2045
    return Value{pc, kWasmBottom};
2046 2047
  }

2048
  bool CheckHasMemory() {
2049 2050 2051 2052 2053
    if (!VALIDATE(this->module_->has_memory)) {
      this->error(this->pc_ - 1, "memory instruction with no memory");
      return false;
    }
    return true;
2054 2055
  }

2056 2057
  bool CheckHasMemoryForAtomics() {
    if (FLAG_wasm_atomics_on_non_shared_memory && CheckHasMemory()) return true;
2058 2059 2060 2061 2062 2063 2064
    if (!VALIDATE(this->module_->has_shared_memory)) {
      this->error(this->pc_ - 1, "Atomic opcodes used without shared memory");
      return false;
    }
    return true;
  }

2065 2066 2067 2068 2069 2070 2071 2072 2073
  bool CheckSimdPostMvp(WasmOpcode opcode) {
    if (!FLAG_wasm_simd_post_mvp && WasmOpcodes::IsSimdPostMvpOpcode(opcode)) {
      this->error(
          "simd opcode not available, enable with --wasm-simd-post-mvp");
      return false;
    }
    return true;
  }

2074
#ifdef DEBUG
2075 2076
  class TraceLine {
   public:
2077 2078 2079 2080 2081 2082 2083 2084 2085 2086
    explicit TraceLine(WasmFullDecoder* decoder) : decoder_(decoder) {
      WasmOpcode opcode = static_cast<WasmOpcode>(*decoder->pc());
      if (!WasmOpcodes::IsPrefixOpcode(opcode)) AppendOpcode(opcode);
    }

    void AppendOpcode(WasmOpcode opcode) {
      DCHECK(!WasmOpcodes::IsPrefixOpcode(opcode));
      Append(TRACE_INST_FORMAT, decoder_->startrel(decoder_->pc_),
             WasmOpcodes::OpcodeName(opcode));
    }
2087

2088 2089
    ~TraceLine() {
      if (!FLAG_trace_wasm_decoder) return;
2090
      AppendStackState();
2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107
      PrintF("%.*s\n", len_, buffer_);
    }

    // Appends a formatted string.
    PRINTF_FORMAT(2, 3)
    void Append(const char* format, ...) {
      if (!FLAG_trace_wasm_decoder) return;
      va_list va_args;
      va_start(va_args, format);
      size_t remaining_len = kMaxLen - len_;
      Vector<char> remaining_msg_space(buffer_ + len_, remaining_len);
      int len = VSNPrintF(remaining_msg_space, format, va_args);
      va_end(va_args);
      len_ += len < 0 ? remaining_len : len;
    }

   private:
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150
    void AppendStackState() {
      DCHECK(FLAG_trace_wasm_decoder);
      Append(" ");
      for (Control& c : decoder_->control_) {
        switch (c.kind) {
          case kControlIf:
            Append("I");
            break;
          case kControlBlock:
            Append("B");
            break;
          case kControlLoop:
            Append("L");
            break;
          case kControlTry:
            Append("T");
            break;
          case kControlIfElse:
          case kControlTryCatch:
          case kControlLet:  // TODO(7748): Implement
            break;
        }
        if (c.start_merge.arity) Append("%u-", c.start_merge.arity);
        Append("%u", c.end_merge.arity);
        if (!c.reachable()) Append("%c", c.unreachable() ? '*' : '#');
      }
      Append(" | ");
      for (size_t i = 0; i < decoder_->stack_.size(); ++i) {
        Value& val = decoder_->stack_[i];
        WasmOpcode val_opcode = static_cast<WasmOpcode>(*val.pc);
        if (WasmOpcodes::IsPrefixOpcode(val_opcode)) {
          val_opcode =
              decoder_->template read_prefixed_opcode<Decoder::kNoValidate>(
                  val.pc);
        }
        Append(" %c@%d:%s", val.type.short_name(),
               static_cast<int>(val.pc - decoder_->start_),
               WasmOpcodes::OpcodeName(val_opcode));
        // If the decoder failed, don't try to decode the immediates, as this
        // can trigger a DCHECK failure.
        if (decoder_->failed()) continue;
        switch (val_opcode) {
          case kExprI32Const: {
2151
            ImmI32Immediate<Decoder::kNoValidate> imm(decoder_, val.pc + 1);
2152 2153 2154 2155 2156 2157
            Append("[%d]", imm.value);
            break;
          }
          case kExprLocalGet:
          case kExprLocalSet:
          case kExprLocalTee: {
2158
            LocalIndexImmediate<Decoder::kNoValidate> imm(decoder_, val.pc + 1);
2159 2160 2161 2162 2163
            Append("[%u]", imm.index);
            break;
          }
          case kExprGlobalGet:
          case kExprGlobalSet: {
2164 2165
            GlobalIndexImmediate<Decoder::kNoValidate> imm(decoder_,
                                                           val.pc + 1);
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
            Append("[%u]", imm.index);
            break;
          }
          default:
            break;
        }
      }
    }

    static constexpr int kMaxLen = 512;

2177 2178
    char buffer_[kMaxLen];
    int len_ = 0;
2179
    WasmFullDecoder* const decoder_;
2180
  };
2181 2182 2183 2184 2185
#else
  class TraceLine {
   public:
    explicit TraceLine(WasmFullDecoder*) {}

2186 2187
    void AppendOpcode(WasmOpcode) {}

2188 2189 2190 2191
    PRINTF_FORMAT(2, 3)
    void Append(const char* format, ...) {}
  };
#endif
2192

2193 2194 2195 2196 2197 2198
#define DECODE(name)                                                     \
  static int Decode##name(WasmFullDecoder* decoder, WasmOpcode opcode) { \
    TraceLine trace_msg(decoder);                                        \
    return decoder->Decode##name##Impl(&trace_msg, opcode);              \
  }                                                                      \
  V8_INLINE int Decode##name##Impl(TraceLine* trace_msg, WasmOpcode opcode)
2199

2200
  DECODE(Nop) { return 1; }
2201

2202
#define BUILD_SIMPLE_OPCODE(op, _, sig) \
2203 2204
  DECODE(op) { return BuildSimpleOperator_##sig(kExpr##op); }
  FOREACH_SIMPLE_OPCODE(BUILD_SIMPLE_OPCODE)
2205
#undef BUILD_SIMPLE_OPCODE
2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315

  DECODE(Block) {
    BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    ArgVector args = PopArgs(imm.sig);
    Control* block = PushControl(kControlBlock);
    SetBlockType(block, imm, args.begin());
    CALL_INTERFACE_IF_REACHABLE(Block, block);
    PushMergeValues(block, &block->start_merge);
    return 1 + imm.length;
  }

  DECODE(Rethrow) {
    CHECK_PROTOTYPE_OPCODE(eh);
    Value exception = Pop(0, kWasmExnRef);
    CALL_INTERFACE_IF_REACHABLE(Rethrow, exception);
    EndControl();
    return 1;
  }

  DECODE(Throw) {
    CHECK_PROTOTYPE_OPCODE(eh);
    ExceptionIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    ArgVector args = PopArgs(imm.exception->ToFunctionSig());
    CALL_INTERFACE_IF_REACHABLE(Throw, imm, VectorOf(args));
    EndControl();
    return 1 + imm.length;
  }

  DECODE(Try) {
    CHECK_PROTOTYPE_OPCODE(eh);
    BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    ArgVector args = PopArgs(imm.sig);
    Control* try_block = PushControl(kControlTry);
    SetBlockType(try_block, imm, args.begin());
    CALL_INTERFACE_IF_REACHABLE(Try, try_block);
    PushMergeValues(try_block, &try_block->start_merge);
    return 1 + imm.length;
  }

  DECODE(Catch) {
    CHECK_PROTOTYPE_OPCODE(eh);
    if (!VALIDATE(!control_.empty())) {
      this->error("catch does not match any try");
      return 0;
    }
    Control* c = &control_.back();
    if (!VALIDATE(c->is_try())) {
      this->error("catch does not match any try");
      return 0;
    }
    if (!VALIDATE(c->is_incomplete_try())) {
      this->error("catch already present for try");
      return 0;
    }
    c->kind = kControlTryCatch;
    FallThruTo(c);
    stack_.erase(stack_.begin() + c->stack_depth, stack_.end());
    c->reachability = control_at(1)->innerReachability();
    current_code_reachable_ = this->ok() && c->reachable();
    Value* exception = Push(kWasmExnRef);
    CALL_INTERFACE_IF_PARENT_REACHABLE(Catch, c, exception);
    return 1;
  }

  DECODE(BrOnExn) {
    CHECK_PROTOTYPE_OPCODE(eh);
    BranchOnExceptionImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc() + 1, imm, control_.size())) return 0;
    Control* c = control_at(imm.depth.depth);
    Value exception = Pop(0, kWasmExnRef);
    const WasmExceptionSig* sig = imm.index.exception->sig;
    size_t value_count = sig->parameter_count();
    // TODO(wasm): This operand stack mutation is an ugly hack to make
    // both type checking here as well as environment merging in the
    // graph builder interface work out of the box. We should introduce
    // special handling for both and do minimal/no stack mutation here.
    for (size_t i = 0; i < value_count; ++i) Push(sig->GetParam(i));
    Vector<Value> values(stack_.data() + c->stack_depth, value_count);
    TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
    if (this->failed()) return 0;
    if (V8_LIKELY(check_result == kReachableBranch)) {
      CALL_INTERFACE(BrOnException, exception, imm.index, imm.depth.depth,
                     values);
      c->br_merge()->reached = true;
    } else if (check_result == kInvalidStack) {
      return 0;
    }
    for (int i = static_cast<int>(value_count) - 1; i >= 0; i--) Pop(i);
    Value* pexception = Push(kWasmExnRef);
    *pexception = exception;
    return 1 + imm.length;
  }

  DECODE(BrOnNull) {
    CHECK_PROTOTYPE_OPCODE(typed_funcref);
    BranchDepthImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0;
    Value ref_object = Pop(0);
    if (this->failed()) return 0;
    Control* c = control_at(imm.depth);
    TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
    if (V8_LIKELY(check_result == kReachableBranch)) {
      switch (ref_object.type.kind()) {
        case ValueType::kRef: {
          Value* result = Push(ref_object.type);
          CALL_INTERFACE(PassThrough, ref_object, result);
          break;
2316
        }
2317 2318 2319 2320 2321 2322 2323 2324
        case ValueType::kOptRef: {
          // We need to Push the result value after calling BrOnNull on
          // the interface. Therefore we must sync the ref_object and
          // result nodes afterwards (in PassThrough).
          CALL_INTERFACE(BrOnNull, ref_object, imm.depth);
          Value* result =
              Push(ValueType::Ref(ref_object.type.heap_type(), kNonNullable));
          CALL_INTERFACE(PassThrough, ref_object, result);
2325
          c->br_merge()->reached = true;
2326
          break;
2327
        }
2328
        default:
2329
          this->error(this->pc_, "invalid argument type to br_on_null");
2330
          return 0;
2331
      }
2332 2333
    } else if (check_result == kInvalidStack) {
      return 0;
2334 2335 2336
    }
    return 1 + imm.length;
  }
2337

2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542
  DECODE(Let) {
    CHECK_PROTOTYPE_OPCODE(typed_funcref);
    BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    uint32_t old_local_count = this->num_locals();
    // Temporarily add the let-defined values
    // to the beginning of the function locals.
    uint32_t locals_length;
    if (!this->DecodeLocals(this->pc() + 1 + imm.length, &locals_length, 0)) {
      return 0;
    }
    uint32_t num_added_locals = this->num_locals() - old_local_count;
    ArgVector let_local_values =
        PopArgs(static_cast<uint32_t>(imm.in_arity()),
                VectorOf(this->local_types_.data(), num_added_locals));
    ArgVector args = PopArgs(imm.sig);
    Control* let_block = PushControl(kControlLet, num_added_locals);
    SetBlockType(let_block, imm, args.begin());
    CALL_INTERFACE_IF_REACHABLE(Block, let_block);
    PushMergeValues(let_block, &let_block->start_merge);
    CALL_INTERFACE_IF_REACHABLE(AllocateLocals, VectorOf(let_local_values));
    return 1 + imm.length + locals_length;
  }

  DECODE(Loop) {
    BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    ArgVector args = PopArgs(imm.sig);
    Control* block = PushControl(kControlLoop);
    SetBlockType(&control_.back(), imm, args.begin());
    CALL_INTERFACE_IF_REACHABLE(Loop, block);
    PushMergeValues(block, &block->start_merge);
    return 1 + imm.length;
  }

  DECODE(If) {
    BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value cond = Pop(0, kWasmI32);
    ArgVector args = PopArgs(imm.sig);
    if (!VALIDATE(this->ok())) return 0;
    Control* if_block = PushControl(kControlIf);
    SetBlockType(if_block, imm, args.begin());
    CALL_INTERFACE_IF_REACHABLE(If, cond, if_block);
    PushMergeValues(if_block, &if_block->start_merge);
    return 1 + imm.length;
  }

  DECODE(Else) {
    if (!VALIDATE(!control_.empty())) {
      this->error("else does not match any if");
      return 0;
    }
    Control* c = &control_.back();
    if (!VALIDATE(c->is_if())) {
      this->error(this->pc_, "else does not match an if");
      return 0;
    }
    if (!VALIDATE(c->is_onearmed_if())) {
      this->error(this->pc_, "else already present for if");
      return 0;
    }
    if (!TypeCheckFallThru()) return 0;
    c->kind = kControlIfElse;
    CALL_INTERFACE_IF_PARENT_REACHABLE(Else, c);
    if (c->reachable()) c->end_merge.reached = true;
    PushMergeValues(c, &c->start_merge);
    c->reachability = control_at(1)->innerReachability();
    current_code_reachable_ = this->ok() && c->reachable();
    return 1;
  }

  DECODE(End) {
    if (!VALIDATE(!control_.empty())) {
      this->error("end does not match any if, try, or block");
      return 0;
    }
    Control* c = &control_.back();
    if (!VALIDATE(!c->is_incomplete_try())) {
      this->error(this->pc_, "missing catch or catch-all in try");
      return 0;
    }
    if (c->is_onearmed_if()) {
      if (!VALIDATE(c->end_merge.arity == c->start_merge.arity)) {
        this->error(c->pc,
                    "start-arity and end-arity of one-armed if must match");
        return 0;
      }
      if (!TypeCheckOneArmedIf(c)) return 0;
    }
    if (c->is_let()) {
      this->local_types_.erase(this->local_types_.begin(),
                               this->local_types_.begin() + c->locals_count);
      CALL_INTERFACE_IF_REACHABLE(DeallocateLocals, c->locals_count);
    }
    if (!TypeCheckFallThru()) return 0;

    if (control_.size() == 1) {
      // If at the last (implicit) control, check we are at end.
      if (!VALIDATE(this->pc_ + 1 == this->end_)) {
        this->error(this->pc_ + 1, "trailing code after function end");
        return 0;
      }
      // The result of the block is the return value.
      trace_msg->Append("\n" TRACE_INST_FORMAT, startrel(this->pc_),
                        "(implicit) return");
      DoReturn();
      control_.clear();
      return 1;
    }
    PopControl(c);
    return 1;
  }

  DECODE(Select) {
    Value cond = Pop(2, kWasmI32);
    Value fval = Pop(1);
    Value tval = Pop(0, fval.type);
    ValueType type = tval.type == kWasmBottom ? fval.type : tval.type;
    if (!VALIDATE(!type.is_reference_type())) {
      this->error("select without type is only valid for value type inputs");
      return 0;
    }
    Value* result = Push(type);
    CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
    return 1;
  }

  DECODE(SelectWithType) {
    CHECK_PROTOTYPE_OPCODE(reftypes);
    SelectTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (this->failed()) return 0;
    Value cond = Pop(2, kWasmI32);
    Value fval = Pop(1, imm.type);
    Value tval = Pop(0, imm.type);
    Value* result = Push(imm.type);
    CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
    return 1 + imm.length;
  }

  DECODE(Br) {
    BranchDepthImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0;
    Control* c = control_at(imm.depth);
    TypeCheckBranchResult check_result = TypeCheckBranch(c, false);
    if (V8_LIKELY(check_result == kReachableBranch)) {
      if (imm.depth == control_.size() - 1) {
        DoReturn();
      } else {
        CALL_INTERFACE(Br, c);
        c->br_merge()->reached = true;
      }
    } else if (check_result == kInvalidStack) {
      return 0;
    }
    EndControl();
    return 1 + imm.length;
  }

  DECODE(BrIf) {
    BranchDepthImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0;
    Value cond = Pop(0, kWasmI32);
    if (this->failed()) return 0;
    Control* c = control_at(imm.depth);
    TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
    if (V8_LIKELY(check_result == kReachableBranch)) {
      CALL_INTERFACE(BrIf, cond, imm.depth);
      c->br_merge()->reached = true;
    } else if (check_result == kInvalidStack) {
      return 0;
    }
    return 1 + imm.length;
  }

  DECODE(BrTable) {
    BranchTableImmediate<validate> imm(this, this->pc_ + 1);
    BranchTableIterator<validate> iterator(this, imm);
    Value key = Pop(0, kWasmI32);
    if (this->failed()) return 0;
    if (!this->Validate(this->pc_ + 1, imm, control_.size())) return 0;

    // Cache the branch targets during the iteration, so that we can set
    // all branch targets as reachable after the {CALL_INTERFACE} call.
    std::vector<bool> br_targets(control_.size());

    // The result types of the br_table instruction. We have to check the
    // stack against these types. Only needed during validation.
    std::vector<ValueType> result_types;

    while (iterator.has_next()) {
      const uint32_t index = iterator.cur_index();
      const byte* pos = iterator.pc();
      uint32_t target = iterator.next();
      if (!VALIDATE(ValidateBrTableTarget(target, pos, index))) return 0;
      // Avoid redundant branch target checks.
      if (br_targets[target]) continue;
      br_targets[target] = true;

      if (validate) {
        if (index == 0) {
          // With the first branch target, initialize the result types.
          result_types = InitializeBrTableResultTypes(target);
        } else if (!UpdateBrTableResultTypes(&result_types, target, pos,
                                             index)) {
2543
          return 0;
2544
        }
2545
      }
2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557
    }

    if (!VALIDATE(TypeCheckBrTable(result_types))) return 0;

    DCHECK(this->ok());

    if (current_code_reachable_) {
      CALL_INTERFACE(BrTable, imm, key);

      for (int i = 0, e = control_depth(); i < e; ++i) {
        if (!br_targets[i]) continue;
        control_at(i)->br_merge()->reached = true;
2558
      }
2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
    }

    EndControl();
    return 1 + iterator.length();
  }

  DECODE(Return) {
    if (V8_LIKELY(current_code_reachable_)) {
      if (!VALIDATE(TypeCheckReturn())) return 0;
      DoReturn();
    } else {
      // We pop all return values from the stack to check their type.
      // Since we deal with unreachable code, we do not have to keep the
      // values.
      int num_returns = static_cast<int>(this->sig_->return_count());
      for (int i = num_returns - 1; i >= 0; --i) {
        Pop(i, this->sig_->GetReturn(i));
2576
      }
2577
    }
2578

2579 2580 2581
    EndControl();
    return 1;
  }
2582

2583 2584 2585 2586 2587
  DECODE(Unreachable) {
    CALL_INTERFACE_IF_REACHABLE(Unreachable);
    EndControl();
    return 1;
  }
2588

2589 2590 2591 2592 2593 2594
  DECODE(I32Const) {
    ImmI32Immediate<validate> imm(this, this->pc_ + 1);
    Value* value = Push(kWasmI32);
    CALL_INTERFACE_IF_REACHABLE(I32Const, value, imm.value);
    return 1 + imm.length;
  }
2595

2596 2597 2598 2599 2600 2601
  DECODE(I64Const) {
    ImmI64Immediate<validate> imm(this, this->pc_ + 1);
    Value* value = Push(kWasmI64);
    CALL_INTERFACE_IF_REACHABLE(I64Const, value, imm.value);
    return 1 + imm.length;
  }
2602

2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624
  DECODE(F32Const) {
    ImmF32Immediate<validate> imm(this, this->pc_ + 1);
    Value* value = Push(kWasmF32);
    CALL_INTERFACE_IF_REACHABLE(F32Const, value, imm.value);
    return 1 + imm.length;
  }

  DECODE(F64Const) {
    ImmF64Immediate<validate> imm(this, this->pc_ + 1);
    Value* value = Push(kWasmF64);
    CALL_INTERFACE_IF_REACHABLE(F64Const, value, imm.value);
    return 1 + imm.length;
  }

  DECODE(RefNull) {
    CHECK_PROTOTYPE_OPCODE(reftypes);
    HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value* value = Push(ValueType::Ref(imm.type, kNullable));
    CALL_INTERFACE_IF_REACHABLE(RefNull, value);
    return 1 + imm.length;
  }
2625

2626 2627 2628 2629 2630 2631 2632
  DECODE(RefIsNull) {
    CHECK_PROTOTYPE_OPCODE(reftypes);
    Value value = Pop(0);
    Value* result = Push(kWasmI32);
    switch (value.type.kind()) {
      case ValueType::kOptRef:
        CALL_INTERFACE_IF_REACHABLE(UnOp, kExprRefIsNull, value, result);
2633
        return 1;
2634 2635 2636
      case ValueType::kRef:
        // For non-nullable references, the result is always false.
        CALL_INTERFACE_IF_REACHABLE(I32Const, result, 0);
2637
        return 1;
2638 2639 2640 2641 2642
      default:
        if (validate) {
          this->errorf(this->pc_,
                       "invalid argument type to ref.is_null. Expected "
                       "reference type, got %s",
2643
                       value.type.name().c_str());
2644
          return 0;
2645
        }
2646 2647 2648 2649 2650 2651 2652 2653
        UNREACHABLE();
    }
  }

  DECODE(RefFunc) {
    CHECK_PROTOTYPE_OPCODE(reftypes);
    FunctionIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
2654 2655 2656 2657
    HeapType heap_type(this->enabled_.has_typed_funcref()
                           ? this->module_->functions[imm.index].sig_index
                           : HeapType::kFunc);
    Value* value = Push(ValueType::Ref(heap_type, kNonNullable));
2658 2659 2660 2661 2662 2663 2664 2665 2666
    CALL_INTERFACE_IF_REACHABLE(RefFunc, imm.index, value);
    return 1 + imm.length;
  }

  DECODE(RefAsNonNull) {
    CHECK_PROTOTYPE_OPCODE(typed_funcref);
    Value value = Pop(0);
    switch (value.type.kind()) {
      case ValueType::kRef: {
2667
        Value* result = Push(value.type);
2668
        CALL_INTERFACE_IF_REACHABLE(PassThrough, value, result);
2669
        return 1;
2670
      }
2671 2672 2673 2674 2675
      case ValueType::kOptRef: {
        Value* result =
            Push(ValueType::Ref(value.type.heap_type(), kNonNullable));
        CALL_INTERFACE_IF_REACHABLE(RefAsNonNull, value, result);
        return 1;
2676
      }
2677 2678 2679 2680 2681
      default:
        if (validate) {
          this->errorf(this->pc_,
                       "invalid agrument type to ref.as_non_null: Expected "
                       "reference type, got %s",
2682
                       value.type.name().c_str());
2683
        }
2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759
        return 0;
    }
  }

  DECODE(LocalGet) {
    LocalIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value* value = Push(this->local_type(imm.index));
    CALL_INTERFACE_IF_REACHABLE(LocalGet, value, imm);
    return 1 + imm.length;
  }

  DECODE(LocalSet) {
    LocalIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value value = Pop(0, this->local_type(imm.index));
    CALL_INTERFACE_IF_REACHABLE(LocalSet, value, imm);
    return 1 + imm.length;
  }

  DECODE(LocalTee) {
    LocalIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value value = Pop(0, this->local_type(imm.index));
    Value* result = Push(value.type);
    CALL_INTERFACE_IF_REACHABLE(LocalTee, value, result, imm);
    return 1 + imm.length;
  }

  DECODE(Drop) {
    Value value = Pop(0);
    CALL_INTERFACE_IF_REACHABLE(Drop, value);
    return 1;
  }

  DECODE(GlobalGet) {
    GlobalIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value* result = Push(imm.type);
    CALL_INTERFACE_IF_REACHABLE(GlobalGet, result, imm);
    return 1 + imm.length;
  }

  DECODE(GlobalSet) {
    GlobalIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    if (!VALIDATE(imm.global->mutability)) {
      this->errorf(this->pc_, "immutable global #%u cannot be assigned",
                   imm.index);
      return 0;
    }
    Value value = Pop(0, imm.type);
    CALL_INTERFACE_IF_REACHABLE(GlobalSet, value, imm);
    return 1 + imm.length;
  }

  DECODE(TableGet) {
    CHECK_PROTOTYPE_OPCODE(reftypes);
    TableIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value index = Pop(0, kWasmI32);
    Value* result = Push(this->module_->tables[imm.index].type);
    CALL_INTERFACE_IF_REACHABLE(TableGet, index, result, imm);
    return 1 + imm.length;
  }

  DECODE(TableSet) {
    CHECK_PROTOTYPE_OPCODE(reftypes);
    TableIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value value = Pop(1, this->module_->tables[imm.index].type);
    Value index = Pop(0, kWasmI32);
    CALL_INTERFACE_IF_REACHABLE(TableSet, index, value, imm);
    return 1 + imm.length;
  }

2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792
  DECODE(LoadMem) {
    // Hard-code the list of load types. The opcodes are highly unlikely to
    // ever change, and we have some checks here to guard against that.
    static_assert(sizeof(LoadType) == sizeof(uint8_t), "LoadType is compact");
    static constexpr uint8_t kMinOpcode = kExprI32LoadMem;
    static constexpr uint8_t kMaxOpcode = kExprI64LoadMem32U;
    static constexpr LoadType kLoadTypes[] = {
        LoadType::kI32Load,    LoadType::kI64Load,    LoadType::kF32Load,
        LoadType::kF64Load,    LoadType::kI32Load8S,  LoadType::kI32Load8U,
        LoadType::kI32Load16S, LoadType::kI32Load16U, LoadType::kI64Load8S,
        LoadType::kI64Load8U,  LoadType::kI64Load16S, LoadType::kI64Load16U,
        LoadType::kI64Load32S, LoadType::kI64Load32U};
    STATIC_ASSERT(arraysize(kLoadTypes) == kMaxOpcode - kMinOpcode + 1);
    DCHECK_LE(kMinOpcode, opcode);
    DCHECK_GE(kMaxOpcode, opcode);
    return DecodeLoadMem(kLoadTypes[opcode - kMinOpcode]);
  }

  DECODE(StoreMem) {
    // Hard-code the list of store types. The opcodes are highly unlikely to
    // ever change, and we have some checks here to guard against that.
    static_assert(sizeof(StoreType) == sizeof(uint8_t), "StoreType is compact");
    static constexpr uint8_t kMinOpcode = kExprI32StoreMem;
    static constexpr uint8_t kMaxOpcode = kExprI64StoreMem32;
    static constexpr StoreType kStoreTypes[] = {
        StoreType::kI32Store,  StoreType::kI64Store,   StoreType::kF32Store,
        StoreType::kF64Store,  StoreType::kI32Store8,  StoreType::kI32Store16,
        StoreType::kI64Store8, StoreType::kI64Store16, StoreType::kI64Store32};
    STATIC_ASSERT(arraysize(kStoreTypes) == kMaxOpcode - kMinOpcode + 1);
    DCHECK_LE(kMinOpcode, opcode);
    DCHECK_GE(kMaxOpcode, opcode);
    return DecodeStoreMem(kStoreTypes[opcode - kMinOpcode]);
  }
2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909

  DECODE(MemoryGrow) {
    if (!CheckHasMemory()) return 0;
    MemoryIndexImmediate<validate> imm(this, this->pc_ + 1);
    if (!VALIDATE(this->module_->origin == kWasmOrigin)) {
      this->error("grow_memory is not supported for asmjs modules");
      return 0;
    }
    Value value = Pop(0, kWasmI32);
    Value* result = Push(kWasmI32);
    CALL_INTERFACE_IF_REACHABLE(MemoryGrow, value, result);
    return 1 + imm.length;
  }

  DECODE(MemorySize) {
    if (!CheckHasMemory()) return 0;
    MemoryIndexImmediate<validate> imm(this, this->pc_ + 1);
    Value* result = Push(kWasmI32);
    CALL_INTERFACE_IF_REACHABLE(CurrentMemoryPages, result);
    return 1 + imm.length;
  }

  DECODE(CallFunction) {
    CallFunctionImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    ArgVector args = PopArgs(imm.sig);
    Value* returns = PushReturns(imm.sig);
    CALL_INTERFACE_IF_REACHABLE(CallDirect, imm, args.begin(), returns);
    return 1 + imm.length;
  }

  DECODE(CallIndirect) {
    CallIndirectImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    Value index = Pop(0, kWasmI32);
    ArgVector args = PopArgs(imm.sig);
    Value* returns = PushReturns(imm.sig);
    CALL_INTERFACE_IF_REACHABLE(CallIndirect, index, imm, args.begin(),
                                returns);
    return 1 + imm.length;
  }

  DECODE(ReturnCall) {
    CHECK_PROTOTYPE_OPCODE(return_call);
    CallFunctionImmediate<validate> imm(this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    if (!VALIDATE(this->CanReturnCall(imm.sig))) {
      this->errorf(this->pc_, "%s: %s",
                   WasmOpcodes::OpcodeName(kExprReturnCall),
                   "tail call return types mismatch");
      return 0;
    }
    ArgVector args = PopArgs(imm.sig);
    CALL_INTERFACE_IF_REACHABLE(ReturnCall, imm, args.begin());
    EndControl();
    return 1 + imm.length;
  }

  DECODE(ReturnCallIndirect) {
    CHECK_PROTOTYPE_OPCODE(return_call);
    CallIndirectImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
    if (!this->Validate(this->pc_ + 1, imm)) return 0;
    if (!VALIDATE(this->CanReturnCall(imm.sig))) {
      this->errorf(this->pc_, "%s: %s",
                   WasmOpcodes::OpcodeName(kExprReturnCallIndirect),
                   "tail call return types mismatch");
      return 0;
    }
    Value index = Pop(0, kWasmI32);
    ArgVector args = PopArgs(imm.sig);
    CALL_INTERFACE_IF_REACHABLE(ReturnCallIndirect, index, imm, args.begin());
    EndControl();
    return 1 + imm.length;
  }

  DECODE(Numeric) {
    byte numeric_index =
        this->template read_u8<validate>(this->pc_ + 1, "numeric index");
    WasmOpcode full_opcode =
        static_cast<WasmOpcode>(kNumericPrefix << 8 | numeric_index);
    if (full_opcode == kExprTableGrow || full_opcode == kExprTableSize ||
        full_opcode == kExprTableFill) {
      CHECK_PROTOTYPE_OPCODE(reftypes);
    } else if (full_opcode >= kExprMemoryInit) {
      CHECK_PROTOTYPE_OPCODE(bulk_memory);
    }
    trace_msg->AppendOpcode(full_opcode);
    return DecodeNumericOpcode(full_opcode);
  }

  DECODE(Simd) {
    CHECK_PROTOTYPE_OPCODE(simd);
    uint32_t opcode_length = 0;
    WasmOpcode full_opcode = this->template read_prefixed_opcode<validate>(
        this->pc_, &opcode_length);
    if (!VALIDATE(this->ok())) return 0;
    trace_msg->AppendOpcode(full_opcode);
    return DecodeSimdOpcode(full_opcode, 1 + opcode_length);
  }

  DECODE(Atomic) {
    CHECK_PROTOTYPE_OPCODE(threads);
    byte atomic_index =
        this->template read_u8<validate>(this->pc_ + 1, "atomic index");
    WasmOpcode full_opcode =
        static_cast<WasmOpcode>(kAtomicPrefix << 8 | atomic_index);
    trace_msg->AppendOpcode(full_opcode);
    return DecodeAtomicOpcode(full_opcode);
  }

  DECODE(GC) {
    CHECK_PROTOTYPE_OPCODE(gc);
    byte gc_index = this->template read_u8<validate>(this->pc_ + 1, "gc index");
    WasmOpcode full_opcode = static_cast<WasmOpcode>(kGCPrefix << 8 | gc_index);
    trace_msg->AppendOpcode(full_opcode);
    return DecodeGCOpcode(full_opcode);
  }
2910

2911
#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \
2912 2913
  DECODE(name) { return BuildSimplePrototypeOperator(opcode); }
  FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE)
2914
#undef SIMPLE_PROTOTYPE_CASE
2915 2916 2917 2918 2919 2920

  DECODE(UnknownOrAsmJs) {
    // Deal with special asmjs opcodes.
    if (!VALIDATE(is_asmjs_module(this->module_))) {
      this->error("Invalid opcode");
      return 0;
2921
    }
2922 2923 2924
    const FunctionSig* sig = WasmOpcodes::AsmjsSignature(opcode);
    DCHECK_NOT_NULL(sig);
    return BuildSimpleOperator(opcode, sig);
2925 2926
  }

2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980
#undef DECODE

  using OpcodeHandler = int (*)(WasmFullDecoder*, WasmOpcode);

  // Ideally we would use template specialization for the different opcodes, but
  // GCC does not allow to specialize templates in class scope
  // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282), and specializing
  // outside the class is not allowed for non-specialized classes.
  // Hence just list all implementations explicitly here, which also gives more
  // freedom to use the same implementation for different opcodes.
#define DECODE_IMPL(opcode) DECODE_IMPL2(kExpr##opcode, opcode)
#define DECODE_IMPL2(opcode, name) \
  if (idx == opcode) return &WasmFullDecoder::Decode##name

  static constexpr OpcodeHandler GetOpcodeHandlerTableEntry(size_t idx) {
    DECODE_IMPL(Nop);
#define BUILD_SIMPLE_OPCODE(op, _, sig) DECODE_IMPL(op);
    FOREACH_SIMPLE_OPCODE(BUILD_SIMPLE_OPCODE)
#undef BUILD_SIMPLE_OPCODE
    DECODE_IMPL(Block);
    DECODE_IMPL(Rethrow);
    DECODE_IMPL(Throw);
    DECODE_IMPL(Try);
    DECODE_IMPL(Catch);
    DECODE_IMPL(BrOnExn);
    DECODE_IMPL(BrOnNull);
    DECODE_IMPL(Let);
    DECODE_IMPL(Loop);
    DECODE_IMPL(If);
    DECODE_IMPL(Else);
    DECODE_IMPL(End);
    DECODE_IMPL(Select);
    DECODE_IMPL(SelectWithType);
    DECODE_IMPL(Br);
    DECODE_IMPL(BrIf);
    DECODE_IMPL(BrTable);
    DECODE_IMPL(Return);
    DECODE_IMPL(Unreachable);
    DECODE_IMPL(I32Const);
    DECODE_IMPL(I64Const);
    DECODE_IMPL(F32Const);
    DECODE_IMPL(F64Const);
    DECODE_IMPL(RefNull);
    DECODE_IMPL(RefIsNull);
    DECODE_IMPL(RefFunc);
    DECODE_IMPL(RefAsNonNull);
    DECODE_IMPL(LocalGet);
    DECODE_IMPL(LocalSet);
    DECODE_IMPL(LocalTee);
    DECODE_IMPL(Drop);
    DECODE_IMPL(GlobalGet);
    DECODE_IMPL(GlobalSet);
    DECODE_IMPL(TableGet);
    DECODE_IMPL(TableSet);
2981 2982 2983 2984 2985 2986
#define DECODE_LOAD_MEM(op, ...) DECODE_IMPL2(kExpr##op, LoadMem);
    FOREACH_LOAD_MEM_OPCODE(DECODE_LOAD_MEM)
#undef DECODE_LOAD_MEM
#define DECODE_STORE_MEM(op, ...) DECODE_IMPL2(kExpr##op, StoreMem);
    FOREACH_STORE_MEM_OPCODE(DECODE_STORE_MEM)
#undef DECODE_LOAD_MEM
2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001
    DECODE_IMPL(MemoryGrow);
    DECODE_IMPL(MemorySize);
    DECODE_IMPL(CallFunction);
    DECODE_IMPL(CallIndirect);
    DECODE_IMPL(ReturnCall);
    DECODE_IMPL(ReturnCallIndirect);
    DECODE_IMPL2(kNumericPrefix, Numeric);
    DECODE_IMPL2(kSimdPrefix, Simd);
    DECODE_IMPL2(kAtomicPrefix, Atomic);
    DECODE_IMPL2(kGCPrefix, GC);
#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) DECODE_IMPL(name);
    FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE)
#undef SIMPLE_PROTOTYPE_CASE
    return &WasmFullDecoder::DecodeUnknownOrAsmJs;
  }
3002

3003 3004
#undef DECODE_IMPL
#undef DECODE_IMPL2
3005 3006 3007

  OpcodeHandler GetOpcodeHandler(uint8_t opcode) {
    static constexpr std::array<OpcodeHandler, 256> kOpcodeHandlers =
3008
        base::make_array<256>(GetOpcodeHandlerTableEntry);
3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031
    return kOpcodeHandlers[opcode];
  }

  void DecodeFunctionBody() {
    TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n", this->start(),
          this->end(), this->pc_offset(),
          static_cast<int>(this->end() - this->start()));

    // Set up initial function block.
    {
      Control* c = PushControl(kControlBlock);
      InitMerge(&c->start_merge, 0, [](uint32_t) -> Value { UNREACHABLE(); });
      InitMerge(&c->end_merge,
                static_cast<uint32_t>(this->sig_->return_count()),
                [&](uint32_t i) {
                  return Value{this->pc_, this->sig_->GetReturn(i)};
                });
      CALL_INTERFACE(StartFunctionBody, c);
    }

    // Decode the function body.
    while (this->pc_ < this->end_) {
      uint8_t first_byte = *this->pc_;
3032 3033
      WasmOpcode opcode = static_cast<WasmOpcode>(first_byte);
      CALL_INTERFACE_IF_REACHABLE(NextInstruction, opcode);
3034
      OpcodeHandler handler = GetOpcodeHandler(first_byte);
3035
      int len = (*handler)(this, opcode);
3036
      this->pc_ += len;
3037 3038
    }

3039
    if (!VALIDATE(this->pc_ == this->end_)) {
3040 3041
      this->error("Beyond end of code");
    }
3042 3043 3044 3045
  }

  void EndControl() {
    DCHECK(!control_.empty());
3046
    Control* current = &control_.back();
3047
    stack_.erase(stack_.begin() + current->stack_depth, stack_.end());
3048
    CALL_INTERFACE_IF_REACHABLE(EndControl, current);
3049
    current->reachability = kUnreachable;
3050
    current_code_reachable_ = false;
3051 3052
  }

3053
  template <typename func>
3054 3055 3056 3057 3058
  void InitMerge(Merge<Value>* merge, uint32_t arity, func get_val) {
    merge->arity = arity;
    if (arity == 1) {
      merge->vals.first = get_val(0);
    } else if (arity > 1) {
3059
      merge->vals.array = this->zone()->template NewArray<Value>(arity);
3060
      for (uint32_t i = 0; i < arity; i++) {
3061
        merge->vals.array[i] = get_val(i);
3062 3063 3064 3065
      }
    }
  }

3066 3067
  void SetBlockType(Control* c, BlockTypeImmediate<validate>& imm,
                    Value* args) {
3068
    const byte* pc = this->pc_;
3069
    InitMerge(&c->end_merge, imm.out_arity(), [pc, &imm](uint32_t i) {
3070
      return Value{pc, imm.out_type(i)};
3071
    });
3072
    InitMerge(&c->start_merge, imm.in_arity(),
3073
              [args](uint32_t i) { return args[i]; });
3074 3075
  }

3076
  // Pops arguments as required by signature.
3077
  V8_INLINE ArgVector PopArgs(const FunctionSig* sig) {
3078
    int count = sig ? static_cast<int>(sig->parameter_count()) : 0;
3079
    ArgVector args(count);
3080
    for (int i = count - 1; i >= 0; --i) {
3081
      args[i] = Pop(i, sig->GetParam(i));
3082
    }
3083
    return args;
3084 3085
  }

3086 3087 3088 3089
  V8_INLINE ArgVector PopArgs(const StructType* type) {
    int count = static_cast<int>(type->field_count());
    ArgVector args(count);
    for (int i = count - 1; i >= 0; i--) {
3090
      args[i] = Pop(i, type->field(i).Unpacked());
3091 3092 3093 3094
    }
    return args;
  }

3095 3096
  V8_INLINE ArgVector PopArgs(uint32_t base_index,
                              Vector<ValueType> arg_types) {
3097 3098
    ArgVector args(arg_types.size());
    for (int i = static_cast<int>(arg_types.size()) - 1; i >= 0; i--) {
3099
      args[i] = Pop(base_index + i, arg_types[i]);
3100 3101 3102 3103
    }
    return args;
  }

3104
  ValueType GetReturnType(const FunctionSig* sig) {
3105 3106 3107 3108
    DCHECK_GE(1, sig->return_count());
    return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn();
  }

3109
  Control* PushControl(ControlKind kind, uint32_t locals_count = 0) {
3110 3111
    Reachability reachability =
        control_.empty() ? kReachable : control_.back().innerReachability();
3112 3113
    control_.emplace_back(kind, locals_count, stack_size(), this->pc_,
                          reachability);
3114
    current_code_reachable_ = this->ok() && reachability == kReachable;
3115
    return &control_.back();
3116 3117 3118 3119
  }

  void PopControl(Control* c) {
    DCHECK_EQ(c, &control_.back());
3120
    CALL_INTERFACE_IF_PARENT_REACHABLE(PopControl, c);
3121 3122 3123 3124 3125 3126

    // A loop just leaves the values on the stack.
    if (!c->is_loop()) PushMergeValues(c, &c->end_merge);

    bool parent_reached =
        c->reachable() || c->end_merge.reached || c->is_onearmed_if();
3127
    control_.pop_back();
3128
    // If the parent block was reachable before, but the popped control does not
3129
    // return to here, this block becomes "spec only reachable".
3130 3131
    if (!parent_reached) SetSucceedingCodeDynamicallyUnreachable();
    current_code_reachable_ = control_.back().reachable();
3132 3133
  }

3134
  int DecodeLoadMem(LoadType type, int prefix_len = 1) {
3135
    if (!CheckHasMemory()) return 0;
3136 3137
    MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
                                        type.size_log_2());
3138 3139
    Value index = Pop(0, kWasmI32);
    Value* result = Push(type.value_type());
3140
    CALL_INTERFACE_IF_REACHABLE(LoadMem, type, imm, index, result);
3141
    return prefix_len + imm.length;
3142 3143
  }

3144 3145
  int DecodeLoadTransformMem(LoadType type, LoadTransformationKind transform,
                             uint32_t opcode_length) {
3146
    if (!CheckHasMemory()) return 0;
3147 3148 3149
    // Load extends always load 64-bits.
    uint32_t max_alignment =
        transform == LoadTransformationKind::kExtend ? 3 : type.size_log_2();
3150
    MemoryAccessImmediate<validate> imm(this, this->pc_ + opcode_length,
3151
                                        max_alignment);
3152 3153
    Value index = Pop(0, kWasmI32);
    Value* result = Push(kWasmS128);
3154 3155
    CALL_INTERFACE_IF_REACHABLE(LoadTransform, type, transform, imm, index,
                                result);
3156
    return opcode_length + imm.length;
3157 3158
  }

3159
  int DecodeStoreMem(StoreType store, int prefix_len = 1) {
3160
    if (!CheckHasMemory()) return 0;
3161 3162
    MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
                                        store.size_log_2());
3163 3164
    Value value = Pop(1, store.value_type());
    Value index = Pop(0, kWasmI32);
3165
    CALL_INTERFACE_IF_REACHABLE(StoreMem, store, imm, index, value);
3166
    return prefix_len + imm.length;
3167 3168
  }

3169 3170 3171 3172 3173 3174 3175 3176 3177 3178
  bool ValidateBrTableTarget(uint32_t target, const byte* pos, int index) {
    if (!VALIDATE(target < this->control_.size())) {
      this->errorf(pos, "improper branch in br_table target %u (depth %u)",
                   index, target);
      return false;
    }
    return true;
  }

  std::vector<ValueType> InitializeBrTableResultTypes(uint32_t target) {
3179
    Merge<Value>* merge = control_at(target)->br_merge();
3180 3181 3182 3183 3184 3185 3186 3187 3188 3189
    int br_arity = merge->arity;
    std::vector<ValueType> result(br_arity);
    for (int i = 0; i < br_arity; ++i) {
      result[i] = (*merge)[i].type;
    }
    return result;
  }

  bool UpdateBrTableResultTypes(std::vector<ValueType>* result_types,
                                uint32_t target, const byte* pos, int index) {
3190
    Merge<Value>* merge = control_at(target)->br_merge();
3191 3192
    int br_arity = merge->arity;
    // First we check if the arities match.
3193
    if (!VALIDATE(br_arity == static_cast<int>(result_types->size()))) {
3194 3195 3196 3197 3198 3199 3200 3201
      this->errorf(pos,
                   "inconsistent arity in br_table target %u (previous was "
                   "%zu, this one is %u)",
                   index, result_types->size(), br_arity);
      return false;
    }

    for (int i = 0; i < br_arity; ++i) {
3202
      if (this->enabled_.has_reftypes()) {
3203
        // The expected type is the biggest common sub type of all targets.
3204
        ValueType type = (*result_types)[i];
3205
        (*result_types)[i] =
3206
            CommonSubtype((*result_types)[i], (*merge)[i].type, this->module_);
3207
        if (!VALIDATE((*result_types)[i] != kWasmBottom)) {
3208 3209 3210
          this->errorf(pos,
                       "inconsistent type in br_table target %u (previous "
                       "was %s, this one is %s)",
3211 3212
                       index, type.name().c_str(),
                       (*merge)[i].type.name().c_str());
3213 3214
          return false;
        }
3215 3216
      } else {
        // All target must have the same signature.
3217
        if (!VALIDATE((*result_types)[i] == (*merge)[i].type)) {
3218 3219 3220
          this->errorf(pos,
                       "inconsistent type in br_table target %u (previous "
                       "was %s, this one is %s)",
3221 3222
                       index, (*result_types)[i].name().c_str(),
                       (*merge)[i].type.name().c_str());
3223 3224 3225 3226 3227 3228 3229 3230 3231
          return false;
        }
      }
    }
    return true;
  }

  bool TypeCheckBrTable(const std::vector<ValueType>& result_types) {
    int br_arity = static_cast<int>(result_types.size());
3232
    if (V8_LIKELY(!control_.back().unreachable())) {
3233 3234 3235
      int available =
          static_cast<int>(stack_.size()) - control_.back().stack_depth;
      // There have to be enough values on the stack.
3236
      if (!VALIDATE(available >= br_arity)) {
3237 3238 3239 3240 3241 3242 3243 3244 3245 3246
        this->errorf(this->pc_,
                     "expected %u elements on the stack for branch to "
                     "@%d, found %u",
                     br_arity, startrel(control_.back().pc), available);
        return false;
      }
      Value* stack_values = &*(stack_.end() - br_arity);
      // Type-check the topmost br_arity values on the stack.
      for (int i = 0; i < br_arity; ++i) {
        Value& val = stack_values[i];
3247
        if (!VALIDATE(IsSubtypeOf(val.type, result_types[i], this->module_))) {
3248 3249
          this->errorf(this->pc_,
                       "type error in merge[%u] (expected %s, got %s)", i,
3250
                       result_types[i].name().c_str(), val.type.name().c_str());
3251 3252 3253 3254 3255 3256 3257 3258 3259 3260
          return false;
        }
      }
    } else {  // !control_.back().reachable()
      // Pop values from the stack, accoring to the expected signature.
      for (int i = 0; i < br_arity; ++i) Pop(i + 1, result_types[i]);
    }
    return this->ok();
  }

3261 3262 3263 3264 3265 3266 3267
  uint32_t SimdConstOp(uint32_t opcode_length) {
    Simd128Immediate<validate> imm(this, this->pc_ + opcode_length);
    auto* result = Push(kWasmS128);
    CALL_INTERFACE_IF_REACHABLE(S128Const, imm, result);
    return opcode_length + kSimd128Size;
  }

3268 3269
  uint32_t SimdExtractLane(WasmOpcode opcode, ValueType type,
                           uint32_t opcode_length) {
3270 3271
    SimdLaneImmediate<validate> imm(this, this->pc_ + opcode_length);
    if (this->Validate(this->pc_ + opcode_length, opcode, imm)) {
3272
      Value inputs[] = {Pop(0, kWasmS128)};
3273
      Value* result = Push(type);
3274 3275
      CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
                                  result);
3276
    }
3277
    return opcode_length + imm.length;
3278 3279
  }

3280 3281
  uint32_t SimdReplaceLane(WasmOpcode opcode, ValueType type,
                           uint32_t opcode_length) {
3282 3283
    SimdLaneImmediate<validate> imm(this, this->pc_ + opcode_length);
    if (this->Validate(this->pc_ + opcode_length, opcode, imm)) {
3284 3285
      Value inputs[2] = {UnreachableValue(this->pc_),
                         UnreachableValue(this->pc_)};
3286
      inputs[1] = Pop(1, type);
3287
      inputs[0] = Pop(0, kWasmS128);
3288
      Value* result = Push(kWasmS128);
3289 3290
      CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
                                  result);
3291
    }
3292
    return opcode_length + imm.length;
3293 3294
  }

3295
  uint32_t Simd8x16ShuffleOp(uint32_t opcode_length) {
3296
    Simd128Immediate<validate> imm(this, this->pc_ + opcode_length);
3297
    if (this->Validate(this->pc_ + opcode_length, imm)) {
3298 3299 3300
      Value input1 = Pop(1, kWasmS128);
      Value input0 = Pop(0, kWasmS128);
      Value* result = Push(kWasmS128);
3301
      CALL_INTERFACE_IF_REACHABLE(Simd8x16ShuffleOp, imm, input0, input1,
3302
                                  result);
3303
    }
3304
    return opcode_length + 16;
3305 3306
  }

3307 3308 3309
  uint32_t DecodeSimdOpcode(WasmOpcode opcode, uint32_t opcode_length) {
    // opcode_length is the number of bytes that this SIMD-specific opcode takes
    // up in the LEB128 encoded form.
3310
    switch (opcode) {
3311 3312 3313 3314 3315 3316
      case kExprF64x2ExtractLane:
        return SimdExtractLane(opcode, kWasmF64, opcode_length);
      case kExprF32x4ExtractLane:
        return SimdExtractLane(opcode, kWasmF32, opcode_length);
      case kExprI64x2ExtractLane:
        return SimdExtractLane(opcode, kWasmI64, opcode_length);
3317
      case kExprI32x4ExtractLane:
3318 3319 3320
      case kExprI16x8ExtractLaneS:
      case kExprI16x8ExtractLaneU:
      case kExprI8x16ExtractLaneS:
3321 3322 3323 3324 3325 3326 3327 3328
      case kExprI8x16ExtractLaneU:
        return SimdExtractLane(opcode, kWasmI32, opcode_length);
      case kExprF64x2ReplaceLane:
        return SimdReplaceLane(opcode, kWasmF64, opcode_length);
      case kExprF32x4ReplaceLane:
        return SimdReplaceLane(opcode, kWasmF32, opcode_length);
      case kExprI64x2ReplaceLane:
        return SimdReplaceLane(opcode, kWasmI64, opcode_length);
3329 3330
      case kExprI32x4ReplaceLane:
      case kExprI16x8ReplaceLane:
3331 3332 3333 3334
      case kExprI8x16ReplaceLane:
        return SimdReplaceLane(opcode, kWasmI32, opcode_length);
      case kExprS8x16Shuffle:
        return Simd8x16ShuffleOp(opcode_length);
3335
      case kExprS128LoadMem:
3336
        return DecodeLoadMem(LoadType::kS128Load, opcode_length);
3337
      case kExprS128StoreMem:
3338
        return DecodeStoreMem(StoreType::kS128Store, opcode_length);
3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352
      case kExprS128LoadMem32Zero:
        if (!CheckSimdPostMvp(opcode)) {
          return 0;
        }
        return DecodeLoadTransformMem(LoadType::kI32Load,
                                      LoadTransformationKind::kZeroExtend,
                                      opcode_length);
      case kExprS128LoadMem64Zero:
        if (!CheckSimdPostMvp(opcode)) {
          return 0;
        }
        return DecodeLoadTransformMem(LoadType::kI64Load,
                                      LoadTransformationKind::kZeroExtend,
                                      opcode_length);
3353
      case kExprS8x16LoadSplat:
3354 3355 3356
        return DecodeLoadTransformMem(LoadType::kI32Load8S,
                                      LoadTransformationKind::kSplat,
                                      opcode_length);
3357
      case kExprS16x8LoadSplat:
3358 3359 3360
        return DecodeLoadTransformMem(LoadType::kI32Load16S,
                                      LoadTransformationKind::kSplat,
                                      opcode_length);
3361
      case kExprS32x4LoadSplat:
3362
        return DecodeLoadTransformMem(
3363
            LoadType::kI32Load, LoadTransformationKind::kSplat, opcode_length);
3364
      case kExprS64x2LoadSplat:
3365
        return DecodeLoadTransformMem(
3366
            LoadType::kI64Load, LoadTransformationKind::kSplat, opcode_length);
3367
      case kExprI16x8Load8x8S:
3368 3369 3370
        return DecodeLoadTransformMem(LoadType::kI32Load8S,
                                      LoadTransformationKind::kExtend,
                                      opcode_length);
3371
      case kExprI16x8Load8x8U:
3372 3373 3374
        return DecodeLoadTransformMem(LoadType::kI32Load8U,
                                      LoadTransformationKind::kExtend,
                                      opcode_length);
3375
      case kExprI32x4Load16x4S:
3376 3377 3378
        return DecodeLoadTransformMem(LoadType::kI32Load16S,
                                      LoadTransformationKind::kExtend,
                                      opcode_length);
3379
      case kExprI32x4Load16x4U:
3380 3381 3382
        return DecodeLoadTransformMem(LoadType::kI32Load16U,
                                      LoadTransformationKind::kExtend,
                                      opcode_length);
3383
      case kExprI64x2Load32x2S:
3384 3385 3386
        return DecodeLoadTransformMem(LoadType::kI64Load32S,
                                      LoadTransformationKind::kExtend,
                                      opcode_length);
3387
      case kExprI64x2Load32x2U:
3388 3389 3390
        return DecodeLoadTransformMem(LoadType::kI64Load32U,
                                      LoadTransformationKind::kExtend,
                                      opcode_length);
3391 3392
      case kExprS128Const:
        return SimdConstOp(opcode_length);
3393
      default: {
3394
        if (!CheckSimdPostMvp(opcode)) {
3395
          return 0;
3396
        }
3397
        const FunctionSig* sig = WasmOpcodes::Signature(opcode);
3398
        if (!VALIDATE(sig != nullptr)) {
3399
          this->error("invalid simd opcode");
3400
          return 0;
3401
        }
3402 3403
        ArgVector args = PopArgs(sig);
        Value* results =
3404
            sig->return_count() == 0 ? nullptr : Push(GetReturnType(sig));
3405
        CALL_INTERFACE_IF_REACHABLE(SimdOp, opcode, VectorOf(args), results);
3406
        return opcode_length;
3407 3408 3409 3410
      }
    }
  }

3411
  int DecodeGCOpcode(WasmOpcode opcode) {
3412
    switch (opcode) {
3413
      case kExprStructNewWithRtt: {
3414
        StructIndexImmediate<validate> imm(this, this->pc_ + 2);
3415
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3416
        Value rtt = Pop(imm.struct_type->field_count());
3417
        if (!VALIDATE(rtt.type.kind() == ValueType::kRtt)) {
3418 3419 3420
          this->errorf(this->pc_,
                       "struct.new_with_rtt expected rtt, found %s of type %s",
                       SafeOpcodeNameAt(rtt.pc), rtt.type.name().c_str());
3421
          return 0;
3422 3423 3424
        }
        // TODO(7748): Drop this check if {imm} is dropped from the proposal
        // à la https://github.com/WebAssembly/function-references/pull/31.
3425
        if (!VALIDATE(rtt.type.heap_representation() == imm.index)) {
3426
          this->errorf(this->pc_,
3427 3428 3429
                       "struct.new_with_rtt expected rtt for type %d, found "
                       "rtt for type %s",
                       imm.index, rtt.type.heap_type().name().c_str());
3430
          return 0;
3431 3432 3433 3434 3435
        }
        ArgVector args = PopArgs(imm.struct_type);
        Value* value = Push(ValueType::Ref(imm.index, kNonNullable));
        CALL_INTERFACE_IF_REACHABLE(StructNewWithRtt, imm, rtt, args.begin(),
                                    value);
3436
        return 2 + imm.length;
3437
      }
3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474
      case kExprStructNewDefault: {
        StructIndexImmediate<validate> imm(this, this->pc_ + 2);
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
        if (validate) {
          for (uint32_t i = 0; i < imm.struct_type->field_count(); i++) {
            ValueType ftype = imm.struct_type->field(i);
            if (!VALIDATE(ftype.is_defaultable())) {
              this->errorf(this->pc_,
                           "struct.new_default_with_rtt: struct type %d has "
                           "non-defaultable type %s for field %d",
                           imm.index, ftype.name().c_str(), i);
              return 0;
            }
          }
        }
        Value rtt = Pop(0);
        if (!VALIDATE(rtt.type.kind() == ValueType::kRtt)) {
          this->errorf(
              this->pc_,
              "struct.new_default_with_rtt expected rtt, found %s of type %s",
              SafeOpcodeNameAt(rtt.pc), rtt.type.name().c_str());
          return 0;
        }
        // TODO(7748): Drop this check if {imm} is dropped from the proposal
        // à la https://github.com/WebAssembly/function-references/pull/31.
        if (!VALIDATE(rtt.type.heap_representation() == imm.index)) {
          this->errorf(
              this->pc_,
              "struct.new_default_with_rtt expected rtt for type %d, found "
              "rtt for type %s",
              imm.index, rtt.type.heap_type().name().c_str());
          return 0;
        }
        Value* value = Push(ValueType::Ref(imm.index, kNonNullable));
        CALL_INTERFACE_IF_REACHABLE(StructNewDefault, imm, rtt, value);
        return 2 + imm.length;
      }
3475
      case kExprStructGet: {
3476
        FieldIndexImmediate<validate> field(this, this->pc_ + 2);
3477
        if (!this->Validate(this->pc_ + 2, field)) return 0;
3478 3479
        ValueType field_type =
            field.struct_index.struct_type->field(field.index);
3480
        if (!VALIDATE(!field_type.is_packed())) {
3481 3482 3483
          this->error(this->pc_,
                      "struct.get used with a field of packed type. "
                      "Use struct.get_s or struct.get_u instead.");
3484
          return 0;
3485
        }
3486 3487
        Value struct_obj =
            Pop(0, ValueType::Ref(field.struct_index.index, kNullable));
3488
        Value* value = Push(field_type);
3489
        CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field, true, value);
3490
        return 2 + field.length;
3491
      }
3492 3493
      case kExprStructGetU:
      case kExprStructGetS: {
3494
        FieldIndexImmediate<validate> field(this, this->pc_ + 2);
3495
        if (!this->Validate(this->pc_ + 2, field)) return 0;
3496 3497
        ValueType field_type =
            field.struct_index.struct_type->field(field.index);
3498
        if (!VALIDATE(field_type.is_packed())) {
3499 3500 3501 3502
          this->errorf(this->pc_,
                       "%s is only valid for packed struct fields. "
                       "Use struct.get instead.",
                       WasmOpcodes::OpcodeName(opcode));
3503
          return 0;
3504
        }
3505 3506
        Value struct_obj =
            Pop(0, ValueType::Ref(field.struct_index.index, kNullable));
3507
        Value* value = Push(field_type.Unpacked());
3508 3509
        CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field,
                                    opcode == kExprStructGetS, value);
3510
        return 2 + field.length;
3511
      }
3512
      case kExprStructSet: {
3513
        FieldIndexImmediate<validate> field(this, this->pc_ + 2);
3514
        if (!this->Validate(this->pc_ + 2, field)) return 0;
3515
        const StructType* struct_type = field.struct_index.struct_type;
3516
        if (!VALIDATE(struct_type->mutability(field.index))) {
3517
          this->error(this->pc_, "setting immutable struct field");
3518
          return 0;
3519
        }
3520
        Value field_value = Pop(1, struct_type->field(field.index).Unpacked());
3521 3522
        Value struct_obj =
            Pop(0, ValueType::Ref(field.struct_index.index, kNullable));
3523
        CALL_INTERFACE_IF_REACHABLE(StructSet, struct_obj, field, field_value);
3524
        return 2 + field.length;
3525
      }
3526 3527 3528 3529 3530
      case kExprArrayNewWithRtt: {
        ArrayIndexImmediate<validate> imm(this, this->pc_ + 2);
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
        Value rtt = Pop(2);
        if (!VALIDATE(rtt.type.kind() == ValueType::kRtt)) {
3531 3532 3533
          this->errorf(this->pc_ + 2,
                       "array.new_with_rtt expected rtt, found %s of type %s",
                       SafeOpcodeNameAt(rtt.pc), rtt.type.name().c_str());
3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551
          return 0;
        }
        // TODO(7748): Drop this check if {imm} is dropped from the proposal
        // à la https://github.com/WebAssembly/function-references/pull/31.
        if (!VALIDATE(rtt.type.heap_representation() == imm.index)) {
          this->errorf(this->pc_ + 2,
                       "array.new_with_rtt expected rtt for type %d, found "
                       "rtt for type %s",
                       imm.index, rtt.type.heap_type().name().c_str());
          return 0;
        }
        Value length = Pop(1, kWasmI32);
        Value initial_value = Pop(0, imm.array_type->element_type().Unpacked());
        Value* value = Push(ValueType::Ref(imm.index, kNonNullable));
        CALL_INTERFACE_IF_REACHABLE(ArrayNewWithRtt, imm, length, initial_value,
                                    rtt, value);
        return 2 + imm.length;
      }
3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584
      case kExprArrayNewDefault: {
        ArrayIndexImmediate<validate> imm(this, this->pc_ + 2);
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
        if (!VALIDATE(imm.array_type->element_type().is_defaultable())) {
          this->errorf(this->pc_,
                       "array.new_default_with_rtt: array type %d has "
                       "non-defaultable element type %s",
                       imm.index,
                       imm.array_type->element_type().name().c_str());
          return 0;
        }
        Value rtt = Pop(1);
        if (!VALIDATE(rtt.type.kind() == ValueType::kRtt)) {
          this->errorf(
              this->pc_ + 2,
              "array.new_default_with_rtt expected rtt, found %s of type %s",
              SafeOpcodeNameAt(rtt.pc), rtt.type.name().c_str());
          return 0;
        }
        // TODO(7748): Drop this check if {imm} is dropped from the proposal
        // à la https://github.com/WebAssembly/function-references/pull/31.
        if (!VALIDATE(rtt.type.heap_representation() == imm.index)) {
          this->errorf(this->pc_ + 2,
                       "array.new_default_with_rtt expected rtt for type %d, "
                       "found rtt for type %s",
                       imm.index, rtt.type.heap_type().name().c_str());
          return 0;
        }
        Value length = Pop(0, kWasmI32);
        Value* value = Push(ValueType::Ref(imm.index, kNonNullable));
        CALL_INTERFACE_IF_REACHABLE(ArrayNewDefault, imm, length, rtt, value);
        return 2 + imm.length;
      }
3585 3586
      case kExprArrayGetS:
      case kExprArrayGetU: {
3587
        ArrayIndexImmediate<validate> imm(this, this->pc_ + 2);
3588
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3589
        if (!VALIDATE(imm.array_type->element_type().is_packed())) {
3590 3591 3592 3593
          this->errorf(
              this->pc_,
              "%s is only valid for packed arrays. Use array.get instead.",
              WasmOpcodes::OpcodeName(opcode));
3594
          return 0;
3595 3596
        }
        Value index = Pop(1, kWasmI32);
3597
        Value array_obj = Pop(0, ValueType::Ref(imm.index, kNullable));
3598
        Value* value = Push(imm.array_type->element_type().Unpacked());
3599 3600
        CALL_INTERFACE_IF_REACHABLE(ArrayGet, array_obj, imm, index,
                                    opcode == kExprArrayGetS, value);
3601
        return 2 + imm.length;
3602
      }
3603
      case kExprArrayGet: {
3604
        ArrayIndexImmediate<validate> imm(this, this->pc_ + 2);
3605
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3606
        if (!VALIDATE(!imm.array_type->element_type().is_packed())) {
3607 3608 3609
          this->error(this->pc_,
                      "array.get used with a field of packed type. "
                      "Use array.get_s or array.get_u instead.");
3610
          return 0;
3611
        }
3612
        Value index = Pop(1, kWasmI32);
3613
        Value array_obj = Pop(0, ValueType::Ref(imm.index, kNullable));
3614
        Value* value = Push(imm.array_type->element_type());
3615 3616
        CALL_INTERFACE_IF_REACHABLE(ArrayGet, array_obj, imm, index, true,
                                    value);
3617
        return 2 + imm.length;
3618 3619
      }
      case kExprArraySet: {
3620
        ArrayIndexImmediate<validate> imm(this, this->pc_ + 2);
3621
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3622
        if (!VALIDATE(imm.array_type->mutability())) {
3623
          this->error(this->pc_, "setting element of immutable array");
3624
          return 0;
3625
        }
3626
        Value value = Pop(2, imm.array_type->element_type().Unpacked());
3627
        Value index = Pop(1, kWasmI32);
3628
        Value array_obj = Pop(0, ValueType::Ref(imm.index, kNullable));
3629
        CALL_INTERFACE_IF_REACHABLE(ArraySet, array_obj, imm, index, value);
3630
        return 2 + imm.length;
3631
      }
3632
      case kExprArrayLen: {
3633
        ArrayIndexImmediate<validate> imm(this, this->pc_ + 2);
3634
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3635
        Value array_obj = Pop(0, ValueType::Ref(imm.index, kNullable));
3636
        Value* value = Push(kWasmI32);
3637
        CALL_INTERFACE_IF_REACHABLE(ArrayLen, array_obj, value);
3638
        return 2 + imm.length;
3639
      }
3640 3641 3642 3643
      case kExprI31New: {
        Value input = Pop(0, kWasmI32);
        Value* value = Push(kWasmI31Ref);
        CALL_INTERFACE_IF_REACHABLE(I31New, input, value);
3644
        return 2;
3645 3646 3647 3648 3649
      }
      case kExprI31GetS: {
        Value i31 = Pop(0, kWasmI31Ref);
        Value* value = Push(kWasmI32);
        CALL_INTERFACE_IF_REACHABLE(I31GetS, i31, value);
3650
        return 2;
3651 3652 3653 3654 3655
      }
      case kExprI31GetU: {
        Value i31 = Pop(0, kWasmI31Ref);
        Value* value = Push(kWasmI32);
        CALL_INTERFACE_IF_REACHABLE(I31GetU, i31, value);
3656
        return 2;
3657
      }
3658
      case kExprRttCanon: {
3659
        HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 2);
3660
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3661
        Value* value = Push(ValueType::Rtt(imm.type, 1));
3662
        CALL_INTERFACE_IF_REACHABLE(RttCanon, imm, value);
3663
        return 2 + imm.length;
3664
      }
3665 3666 3667 3668 3669 3670 3671 3672
      case kExprRttSub: {
        // TODO(7748): The proposal currently includes additional immediates
        // here: the subtyping depth <n> and the "parent type", see:
        // https://github.com/WebAssembly/gc/commit/20a80e34 .
        // If these immediates don't get dropped (in the spirit of
        // https://github.com/WebAssembly/function-references/pull/31 ),
        // implement them here.
        HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 2);
3673
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3674
        Value parent = Pop(0);
3675 3676 3677 3678 3679 3680 3681 3682
        // TODO(7748): Consider exposing "IsSubtypeOfHeap(HeapType t1, t2)" so
        // we can avoid creating (ref heaptype) wrappers here.
        if (!VALIDATE(parent.type.kind() == ValueType::kRtt &&
                      IsSubtypeOf(
                          ValueType::Ref(imm.type, kNonNullable),
                          ValueType::Ref(parent.type.heap_type(), kNonNullable),
                          this->module_))) {
          this->error(this->pc_, "rtt.sub requires a supertype rtt on stack");
3683
          return 0;
3684 3685 3686
        }
        Value* value = Push(ValueType::Rtt(imm.type, parent.type.depth() + 1));
        CALL_INTERFACE_IF_REACHABLE(RttSub, imm, parent, value);
3687
        return 2 + imm.length;
3688
      }
3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706
      case kExprRefTest: {
        // "Tests whether {obj}'s runtime type is a runtime subtype of {rtt}."
        HeapTypeImmediate<validate> obj_type(this->enabled_, this,
                                             this->pc_ + 2);
        if (!this->Validate(this->pc_ + 2, obj_type)) return 0;
        int len = 2 + obj_type.length;
        HeapTypeImmediate<validate> rtt_type(this->enabled_, this,
                                             this->pc_ + len);
        if (!this->Validate(this->pc_ + len, rtt_type)) return 0;
        len += rtt_type.length;
        // The static type of {obj} must be a supertype of the {rtt}'s type.
        if (!VALIDATE(IsSubtypeOf(ValueType::Ref(rtt_type.type, kNonNullable),
                                  ValueType::Ref(obj_type.type, kNonNullable),
                                  this->module_))) {
          this->errorf(this->pc_,
                       "ref.test: rtt type must be subtype of object type");
          return 0;
        }
3707
        Value rtt = Pop(1);
3708 3709
        if (!VALIDATE(rtt.type.kind() == ValueType::kRtt &&
                      rtt.type.heap_type() == rtt_type.type)) {
3710 3711 3712
          this->errorf(this->pc_,
                       "ref.test: expected rtt for type %s but got %s",
                       rtt_type.type.name().c_str(), rtt.type.name().c_str());
3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732
          return 0;
        }
        Value obj = Pop(0, ValueType::Ref(obj_type.type, kNullable));
        Value* value = Push(kWasmI32);
        CALL_INTERFACE_IF_REACHABLE(RefTest, obj, rtt, value);
        return len;
      }
      case kExprRefCast: {
        HeapTypeImmediate<validate> obj_type(this->enabled_, this,
                                             this->pc_ + 2);
        if (!this->Validate(this->pc_ + 2, obj_type)) return 0;
        int len = 2 + obj_type.length;
        HeapTypeImmediate<validate> rtt_type(this->enabled_, this,
                                             this->pc_ + len);
        if (!this->Validate(this->pc_ + len, rtt_type)) return 0;
        len += rtt_type.length;
        if (!VALIDATE(IsSubtypeOf(ValueType::Ref(rtt_type.type, kNonNullable),
                                  ValueType::Ref(obj_type.type, kNonNullable),
                                  this->module_))) {
          this->errorf(this->pc_,
3733
                       "ref.cast: rtt type must be subtype of object type");
3734 3735
          return 0;
        }
3736
        Value rtt = Pop(1);
3737 3738
        if (!VALIDATE(rtt.type.kind() == ValueType::kRtt &&
                      rtt.type.heap_type() == rtt_type.type)) {
3739 3740 3741
          this->errorf(this->pc_,
                       "ref.cast: expected rtt for type %s but got %s",
                       rtt_type.type.name().c_str(), rtt.type.name().c_str());
3742 3743 3744 3745 3746 3747 3748
          return 0;
        }
        Value obj = Pop(0, ValueType::Ref(obj_type.type, kNullable));
        Value* value = Push(ValueType::Ref(rtt_type.type, kNonNullable));
        CALL_INTERFACE_IF_REACHABLE(RefCast, obj, rtt, value);
        return len;
      }
3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791
      case kExprBrOnCast: {
        BranchDepthImmediate<validate> branch_depth(this, this->pc_ + 2);
        if (!this->Validate(this->pc_ + 2, branch_depth, control_.size())) {
          return 0;
        }
        // TODO(7748): If the heap type immediates remain in the spec, read
        // them here.
        Value rtt = Pop(1);
        if (!VALIDATE(rtt.type.kind() == ValueType::kRtt)) {
          this->error(this->pc_, "br_on_cast[1]: expected rtt on stack");
          return 0;
        }
        Value obj = Pop(0);
        if (!VALIDATE(obj.type.kind() == ValueType::kRef ||
                      obj.type.kind() == ValueType::kOptRef)) {
          this->error(this->pc_, "br_on_cast[0]: expected reference on stack");
          return 0;
        }
        // The static type of {obj} must be a supertype of {rtt}'s type.
        if (!VALIDATE(
                IsSubtypeOf(ValueType::Ref(rtt.type.heap_type(), kNonNullable),
                            ValueType::Ref(obj.type.heap_type(), kNonNullable),
                            this->module_))) {
          this->error(this->pc_,
                      "br_on_cast: rtt type must be a subtype of object type");
          return 0;
        }
        Control* c = control_at(branch_depth.depth);
        Value* result_on_branch =
            Push(ValueType::Ref(rtt.type.heap_type(), kNonNullable));
        TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
        if (V8_LIKELY(check_result == kReachableBranch)) {
          CALL_INTERFACE(BrOnCast, obj, rtt, result_on_branch,
                         branch_depth.depth);
          c->br_merge()->reached = true;
        } else if (check_result == kInvalidStack) {
          return 0;
        }
        Pop(0);  // Drop {result_on_branch}, restore original value.
        Value* result_on_fallthrough = Push(obj.type);
        *result_on_fallthrough = obj;
        return 2 + branch_depth.length;
      }
3792 3793 3794 3795 3796 3797
      default:
        this->error("invalid gc opcode");
        return 0;
    }
  }

3798
  uint32_t DecodeAtomicOpcode(WasmOpcode opcode) {
3799
    ValueType ret_type;
3800
    const FunctionSig* sig = WasmOpcodes::Signature(opcode);
3801 3802 3803 3804 3805 3806
    if (!VALIDATE(sig != nullptr)) {
      this->error("invalid atomic opcode");
      return 0;
    }
    MachineType memtype;
    switch (opcode) {
3807 3808 3809 3810 3811
#define CASE_ATOMIC_STORE_OP(Name, Type)          \
  case kExpr##Name: {                             \
    memtype = MachineType::Type();                \
    ret_type = kWasmStmt;                         \
    break; /* to generic mem access code below */ \
3812
  }
3813
      ATOMIC_STORE_OP_LIST(CASE_ATOMIC_STORE_OP)
3814
#undef CASE_ATOMIC_OP
3815 3816 3817 3818 3819
#define CASE_ATOMIC_OP(Name, Type)                \
  case kExpr##Name: {                             \
    memtype = MachineType::Type();                \
    ret_type = GetReturnType(sig);                \
    break; /* to generic mem access code below */ \
3820
  }
3821
      ATOMIC_OP_LIST(CASE_ATOMIC_OP)
3822
#undef CASE_ATOMIC_OP
3823 3824 3825 3826
      case kExprAtomicFence: {
        byte zero = this->template read_u8<validate>(this->pc_ + 2, "zero");
        if (!VALIDATE(zero == 0)) {
          this->error(this->pc_ + 2, "invalid atomic operand");
3827
          return 0;
3828 3829
        }
        CALL_INTERFACE_IF_REACHABLE(AtomicFence);
3830
        return 3;
3831
      }
3832 3833 3834
      default:
        this->error("invalid atomic opcode");
        return 0;
3835
    }
3836
    if (!CheckHasMemoryForAtomics()) return 0;
3837
    MemoryAccessImmediate<validate> imm(
3838
        this, this->pc_ + 2, ElementSizeLog2Of(memtype.representation()));
3839 3840
    ArgVector args = PopArgs(sig);
    Value* result = ret_type == kWasmStmt ? nullptr : Push(GetReturnType(sig));
3841
    CALL_INTERFACE_IF_REACHABLE(AtomicOp, opcode, VectorOf(args), imm, result);
3842
    return 2 + imm.length;
3843 3844
  }

3845
  unsigned DecodeNumericOpcode(WasmOpcode opcode) {
3846
    const FunctionSig* sig = WasmOpcodes::Signature(opcode);
3847
    if (!VALIDATE(sig != nullptr)) {
3848
      this->error("invalid numeric opcode");
3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859
      return 0;
    }
    switch (opcode) {
      case kExprI32SConvertSatF32:
      case kExprI32UConvertSatF32:
      case kExprI32SConvertSatF64:
      case kExprI32UConvertSatF64:
      case kExprI64SConvertSatF32:
      case kExprI64UConvertSatF32:
      case kExprI64SConvertSatF64:
      case kExprI64UConvertSatF64:
3860
        return 1 + BuildSimpleOperator(opcode, sig);
3861
      case kExprMemoryInit: {
3862
        MemoryInitImmediate<validate> imm(this, this->pc_ + 2);
3863
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3864 3865 3866 3867
        Value size = Pop(2, sig->GetParam(2));
        Value src = Pop(1, sig->GetParam(1));
        Value dst = Pop(0, sig->GetParam(0));
        CALL_INTERFACE_IF_REACHABLE(MemoryInit, imm, dst, src, size);
3868
        return 2 + imm.length;
3869 3870
      }
      case kExprDataDrop: {
3871
        DataDropImmediate<validate> imm(this, this->pc_ + 2);
3872
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3873
        CALL_INTERFACE_IF_REACHABLE(DataDrop, imm);
3874
        return 2 + imm.length;
3875 3876
      }
      case kExprMemoryCopy: {
3877
        MemoryCopyImmediate<validate> imm(this, this->pc_ + 2);
3878
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3879 3880 3881 3882
        Value size = Pop(2, sig->GetParam(2));
        Value src = Pop(1, sig->GetParam(1));
        Value dst = Pop(0, sig->GetParam(0));
        CALL_INTERFACE_IF_REACHABLE(MemoryCopy, imm, dst, src, size);
3883
        return 2 + imm.length;
3884 3885
      }
      case kExprMemoryFill: {
3886
        MemoryIndexImmediate<validate> imm(this, this->pc_ + 2);
3887
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3888 3889 3890 3891
        Value size = Pop(2, sig->GetParam(2));
        Value value = Pop(1, sig->GetParam(1));
        Value dst = Pop(0, sig->GetParam(0));
        CALL_INTERFACE_IF_REACHABLE(MemoryFill, imm, dst, value, size);
3892
        return 2 + imm.length;
3893 3894
      }
      case kExprTableInit: {
3895
        TableInitImmediate<validate> imm(this, this->pc_ + 2);
3896
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3897 3898
        ArgVector args = PopArgs(sig);
        CALL_INTERFACE_IF_REACHABLE(TableInit, imm, VectorOf(args));
3899
        return 2 + imm.length;
3900 3901
      }
      case kExprElemDrop: {
3902
        ElemDropImmediate<validate> imm(this, this->pc_ + 2);
3903
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3904
        CALL_INTERFACE_IF_REACHABLE(ElemDrop, imm);
3905
        return 2 + imm.length;
3906 3907
      }
      case kExprTableCopy: {
3908
        TableCopyImmediate<validate> imm(this, this->pc_ + 2);
3909
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3910 3911
        ArgVector args = PopArgs(sig);
        CALL_INTERFACE_IF_REACHABLE(TableCopy, imm, VectorOf(args));
3912
        return 2 + imm.length;
3913 3914
      }
      case kExprTableGrow: {
3915
        TableIndexImmediate<validate> imm(this, this->pc_ + 2);
3916
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3917 3918 3919 3920
        Value delta = Pop(1, sig->GetParam(1));
        Value value = Pop(0, this->module_->tables[imm.index].type);
        Value* result = Push(kWasmI32);
        CALL_INTERFACE_IF_REACHABLE(TableGrow, imm, value, delta, result);
3921
        return 2 + imm.length;
3922 3923
      }
      case kExprTableSize: {
3924
        TableIndexImmediate<validate> imm(this, this->pc_ + 2);
3925
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3926 3927
        Value* result = Push(kWasmI32);
        CALL_INTERFACE_IF_REACHABLE(TableSize, imm, result);
3928
        return 2 + imm.length;
3929 3930
      }
      case kExprTableFill: {
3931
        TableIndexImmediate<validate> imm(this, this->pc_ + 2);
3932
        if (!this->Validate(this->pc_ + 2, imm)) return 0;
3933 3934 3935 3936
        Value count = Pop(2, sig->GetParam(2));
        Value value = Pop(1, this->module_->tables[imm.index].type);
        Value start = Pop(0, sig->GetParam(0));
        CALL_INTERFACE_IF_REACHABLE(TableFill, imm, start, value, count);
3937
        return 2 + imm.length;
3938 3939 3940
      }
      default:
        this->error("invalid numeric opcode");
3941
        return 0;
3942 3943 3944
    }
  }

3945
  void DoReturn() {
3946
    size_t return_count = this->sig_->return_count();
3947 3948 3949
    if (return_count > 1) {
      this->detected_->Add(kFeature_mv);
    }
3950
    DCHECK_GE(stack_.size(), return_count);
3951 3952 3953 3954
    Vector<Value> return_values =
        return_count == 0
            ? Vector<Value>{}
            : Vector<Value>{&*(stack_.end() - return_count), return_count};
3955

3956
    CALL_INTERFACE_IF_REACHABLE(DoReturn, return_values);
3957 3958
  }

3959
  V8_INLINE Value* Push(ValueType type) {
3960
    DCHECK_NE(kWasmStmt, type);
3961
    stack_.emplace_back(this->pc_, type);
3962 3963 3964
    return &stack_.back();
  }

3965
  void PushMergeValues(Control* c, Merge<Value>* merge) {
3966
    DCHECK_EQ(c, &control_.back());
3967
    DCHECK(merge == &c->start_merge || merge == &c->end_merge);
3968
    stack_.erase(stack_.begin() + c->stack_depth, stack_.end());
3969 3970
    if (merge->arity == 1) {
      stack_.push_back(merge->vals.first);
3971
    } else {
3972
      for (uint32_t i = 0; i < merge->arity; i++) {
3973
        stack_.push_back(merge->vals.array[i]);
3974 3975
      }
    }
3976
    DCHECK_EQ(c->stack_depth + merge->arity, stack_.size());
3977 3978
  }

3979
  Value* PushReturns(const FunctionSig* sig) {
3980 3981 3982 3983 3984 3985 3986 3987 3988
    size_t return_count = sig->return_count();
    if (return_count == 0) return nullptr;
    size_t old_size = stack_.size();
    for (size_t i = 0; i < return_count; ++i) {
      Push(sig->GetReturn(i));
    }
    return stack_.data() + old_size;
  }

3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003
  // We do not inline these functions because doing so causes a large binary
  // size increase. Not inlining them should not create a performance
  // degradation, because their invocations are guarded by V8_LIKELY.
  V8_NOINLINE void PopTypeError(int index, Value val, ValueType expected) {
    this->errorf(val.pc, "%s[%d] expected type %s, found %s of type %s",
                 SafeOpcodeNameAt(this->pc_), index, expected.name().c_str(),
                 SafeOpcodeNameAt(val.pc), val.type.name().c_str());
  }

  V8_NOINLINE void NotEnoughArgumentsError(int index) {
    this->errorf(this->pc_,
                 "not enough arguments on the stack for %s, expected %d more",
                 SafeOpcodeNameAt(this->pc_), index + 1);
  }

4004
  V8_INLINE Value Pop(int index, ValueType expected) {
4005
    Value val = Pop(index);
4006 4007
    if (!VALIDATE(IsSubtypeOf(val.type, expected, this->module_) ||
                  val.type == kWasmBottom || expected == kWasmBottom)) {
4008
      PopTypeError(index, val, expected);
4009 4010 4011 4012
    }
    return val;
  }

4013
  V8_INLINE Value Pop(int index) {
4014
    DCHECK(!control_.empty());
4015
    uint32_t limit = control_.back().stack_depth;
4016 4017
    if (stack_.size() <= limit) {
      // Popping past the current control start in reachable code.
4018
      if (!VALIDATE(control_.back().unreachable())) {
4019
        NotEnoughArgumentsError(index);
4020
      }
4021
      return UnreachableValue(this->pc_);
4022
    }
4023
    Value val = stack_.back();
4024 4025 4026 4027
    stack_.pop_back();
    return val;
  }

4028 4029 4030 4031 4032 4033 4034 4035 4036
  // Pops values from the stack, as defined by {merge}. Thereby we type-check
  // unreachable merges. Afterwards the values are pushed again on the stack
  // according to the signature in {merge}. This is done so follow-up validation
  // is possible.
  bool TypeCheckUnreachableMerge(Merge<Value>& merge, bool conditional_branch) {
    int arity = merge.arity;
    // For conditional branches, stack value '0' is the condition of the branch,
    // and the result values start at index '1'.
    int index_offset = conditional_branch ? 1 : 0;
4037
    for (int i = arity - 1; i >= 0; --i) Pop(index_offset + i, merge[i].type);
4038
    // Push values of the correct type back on the stack.
4039
    for (int i = 0; i < arity; ++i) Push(merge[i].type);
4040 4041 4042
    return this->ok();
  }

4043 4044 4045 4046
  int startrel(const byte* ptr) { return static_cast<int>(ptr - this->start_); }

  void FallThruTo(Control* c) {
    DCHECK_EQ(c, &control_.back());
4047
    if (!TypeCheckFallThru()) return;
4048
    if (!c->reachable()) return;
4049

4050 4051
    if (!c->is_loop()) CALL_INTERFACE(FallThruTo, c);
    c->end_merge.reached = true;
4052 4053
  }

4054
  bool TypeCheckMergeValues(Control* c, Merge<Value>* merge) {
4055 4056 4057
    // This is a CHECK instead of a DCHECK because {validate} is a constexpr,
    // and a CHECK makes the whole function unreachable.
    static_assert(validate, "Call this function only within VALIDATE");
4058 4059
    DCHECK(merge == &c->start_merge || merge == &c->end_merge);
    DCHECK_GE(stack_.size(), c->stack_depth + merge->arity);
4060 4061 4062
    // The computation of {stack_values} is only valid if {merge->arity} is >0.
    DCHECK_LT(0, merge->arity);
    Value* stack_values = &*(stack_.end() - merge->arity);
4063 4064
    // Typecheck the topmost {merge->arity} values on the stack.
    for (uint32_t i = 0; i < merge->arity; ++i) {
4065 4066
      Value& val = stack_values[i];
      Value& old = (*merge)[i];
4067
      if (!VALIDATE(IsSubtypeOf(val.type, old.type, this->module_))) {
4068
        this->errorf(this->pc_, "type error in merge[%u] (expected %s, got %s)",
4069
                     i, old.type.name().c_str(), val.type.name().c_str());
4070
        return false;
4071 4072 4073 4074 4075 4076
      }
    }

    return true;
  }

4077 4078 4079 4080 4081 4082 4083
  bool TypeCheckOneArmedIf(Control* c) {
    static_assert(validate, "Call this function only within VALIDATE");
    DCHECK(c->is_onearmed_if());
    DCHECK_EQ(c->start_merge.arity, c->end_merge.arity);
    for (uint32_t i = 0; i < c->start_merge.arity; ++i) {
      Value& start = c->start_merge[i];
      Value& end = c->end_merge[i];
4084
      if (!VALIDATE(IsSubtypeOf(start.type, end.type, this->module_))) {
4085
        this->errorf(this->pc_, "type error in merge[%u] (expected %s, got %s)",
4086
                     i, end.type.name().c_str(), start.type.name().c_str());
4087 4088 4089 4090 4091 4092 4093
        return false;
      }
    }

    return true;
  }

4094
  bool TypeCheckFallThru() {
4095
    static_assert(validate, "Call this function only within VALIDATE");
4096 4097 4098 4099 4100 4101
    Control& c = control_.back();
    if (V8_LIKELY(c.reachable())) {
      uint32_t expected = c.end_merge.arity;
      DCHECK_GE(stack_.size(), c.stack_depth);
      uint32_t actual = static_cast<uint32_t>(stack_.size()) - c.stack_depth;
      // Fallthrus must match the arity of the control exactly.
4102
      if (!VALIDATE(actual == expected)) {
4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120
        this->errorf(
            this->pc_,
            "expected %u elements on the stack for fallthru to @%d, found %u",
            expected, startrel(c.pc), actual);
        return false;
      }
      if (expected == 0) return true;  // Fast path.

      return TypeCheckMergeValues(&c, &c.end_merge);
    }

    // Type-check an unreachable fallthru. First we do an arity check, then a
    // type check. Note that type-checking may require an adjustment of the
    // stack, if some stack values are missing to match the block signature.
    Merge<Value>& merge = c.end_merge;
    int arity = static_cast<int>(merge.arity);
    int available = static_cast<int>(stack_.size()) - c.stack_depth;
    // For fallthrus, not more than the needed values should be available.
4121
    if (!VALIDATE(available <= arity)) {
4122 4123 4124
      this->errorf(
          this->pc_,
          "expected %u elements on the stack for fallthru to @%d, found %u",
4125
          arity, startrel(c.pc), available);
4126 4127
      return false;
    }
4128 4129 4130
    // Pop all values from the stack for type checking of existing stack
    // values.
    return TypeCheckUnreachableMerge(merge, false);
4131 4132
  }

4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150
  enum TypeCheckBranchResult {
    kReachableBranch,
    kUnreachableBranch,
    kInvalidStack,
  };

  TypeCheckBranchResult TypeCheckBranch(Control* c, bool conditional_branch) {
    if (V8_LIKELY(control_.back().reachable())) {
      // We only do type-checking here. This is only needed during validation.
      if (!validate) return kReachableBranch;

      // Branches must have at least the number of values expected; can have
      // more.
      uint32_t expected = c->br_merge()->arity;
      if (expected == 0) return kReachableBranch;  // Fast path.
      DCHECK_GE(stack_.size(), control_.back().stack_depth);
      uint32_t actual =
          static_cast<uint32_t>(stack_.size()) - control_.back().stack_depth;
4151
      if (!VALIDATE(actual >= expected)) {
4152 4153 4154 4155 4156 4157 4158 4159
        this->errorf(
            this->pc_,
            "expected %u elements on the stack for br to @%d, found %u",
            expected, startrel(c->pc), actual);
        return kInvalidStack;
      }
      return TypeCheckMergeValues(c, c->br_merge()) ? kReachableBranch
                                                    : kInvalidStack;
4160
    }
4161 4162 4163 4164

    return TypeCheckUnreachableMerge(*c->br_merge(), conditional_branch)
               ? kUnreachableBranch
               : kInvalidStack;
4165 4166
  }

4167
  bool TypeCheckReturn() {
4168 4169 4170 4171
    int num_returns = static_cast<int>(this->sig_->return_count());
    // No type checking is needed if there are no returns.
    if (num_returns == 0) return true;

4172
    // Returns must have at least the number of values expected; can have more.
4173 4174
    int num_available =
        static_cast<int>(stack_.size()) - control_.back().stack_depth;
4175
    if (!VALIDATE(num_available >= num_returns)) {
4176 4177
      this->errorf(this->pc_,
                   "expected %u elements on the stack for return, found %u",
4178
                   num_returns, num_available);
4179 4180 4181 4182
      return false;
    }

    // Typecheck the topmost {num_returns} values on the stack.
4183
    // This line requires num_returns > 0.
4184
    Value* stack_values = &*(stack_.end() - num_returns);
4185
    for (int i = 0; i < num_returns; ++i) {
4186
      Value& val = stack_values[i];
4187
      ValueType expected_type = this->sig_->GetReturn(i);
4188
      if (!VALIDATE(IsSubtypeOf(val.type, expected_type, this->module_))) {
4189 4190 4191
        this->errorf(this->pc_,
                     "type error in return[%u] (expected %s, got %s)", i,
                     expected_type.name().c_str(), val.type.name().c_str());
4192 4193
        return false;
      }
4194 4195
    }
    return true;
4196 4197
  }

4198
  void onFirstError() override {
4199
    this->end_ = this->pc_;  // Terminate decoding loop.
4200
    this->current_code_reachable_ = false;
4201
    TRACE(" !%s\n", this->error_.message().c_str());
4202
    CALL_INTERFACE(OnFirstError);
4203 4204
  }

4205
  int BuildSimplePrototypeOperator(WasmOpcode opcode) {
4206
    if (opcode == kExprRefEq) {
4207
      CHECK_PROTOTYPE_OPCODE(gc);
4208
    }
4209
    const FunctionSig* sig = WasmOpcodes::Signature(opcode);
4210
    return BuildSimpleOperator(opcode, sig);
4211
  }
4212

4213
  int BuildSimpleOperator(WasmOpcode opcode, const FunctionSig* sig) {
4214 4215 4216
    DCHECK_GE(1, sig->return_count());
    ValueType ret = sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0);
    if (sig->parameter_count() == 1) {
4217
      return BuildSimpleOperator(opcode, ret, sig->GetParam(0));
4218 4219
    } else {
      DCHECK_EQ(2, sig->parameter_count());
4220 4221
      return BuildSimpleOperator(opcode, ret, sig->GetParam(0),
                                 sig->GetParam(1));
4222 4223
    }
  }
4224

4225 4226
  int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
                          ValueType arg_type) {
4227 4228
    Value val = Pop(0, arg_type);
    Value* ret = return_type == kWasmStmt ? nullptr : Push(return_type);
4229
    CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, val, ret);
4230
    return 1;
4231 4232
  }

4233 4234
  int BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
                          ValueType lhs_type, ValueType rhs_type) {
4235 4236 4237
    Value rval = Pop(1, rhs_type);
    Value lval = Pop(0, lhs_type);
    Value* ret = return_type == kWasmStmt ? nullptr : Push(return_type);
4238
    CALL_INTERFACE_IF_REACHABLE(BinOp, opcode, lval, rval, ret);
4239
    return 1;
4240 4241
  }

4242 4243 4244
#define DEFINE_SIMPLE_SIG_OPERATOR(sig, ...)         \
  int BuildSimpleOperator_##sig(WasmOpcode opcode) { \
    return BuildSimpleOperator(opcode, __VA_ARGS__); \
4245 4246 4247
  }
  FOREACH_SIGNATURE(DEFINE_SIMPLE_SIG_OPERATOR)
#undef DEFINE_SIMPLE_SIG_OPERATOR
4248 4249
};

4250 4251 4252 4253
#undef CALL_INTERFACE
#undef CALL_INTERFACE_IF_REACHABLE
#undef CALL_INTERFACE_IF_PARENT_REACHABLE

4254
class EmptyInterface {
4255
 public:
4256
  static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
4257 4258
  using Value = ValueBase;
  using Control = ControlBase<Value>;
4259
  using FullDecoder = WasmFullDecoder<validate, EmptyInterface>;
4260 4261

#define DEFINE_EMPTY_CALLBACK(name, ...) \
4262
  void name(FullDecoder* decoder, ##__VA_ARGS__) {}
4263 4264 4265 4266
  INTERFACE_FUNCTIONS(DEFINE_EMPTY_CALLBACK)
#undef DEFINE_EMPTY_CALLBACK
};

4267
#undef TRACE
4268
#undef TRACE_INST_FORMAT
4269 4270
#undef VALIDATE
#undef CHECK_PROTOTYPE_OPCODE
4271

4272 4273 4274 4275 4276
}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_