function-body-decoder-impl.h 112 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
#include "src/base/platform/elapsed-timer.h"
12
#include "src/base/small-vector.h"
13
#include "src/utils/bit-vector.h"
14
#include "src/wasm/decoder.h"
15
#include "src/wasm/function-body-decoder.h"
16
#include "src/wasm/value-type.h"
17
#include "src/wasm/wasm-features.h"
18 19
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-module.h"
20 21 22 23 24 25 26
#include "src/wasm/wasm-opcodes.h"

namespace v8 {
namespace internal {
namespace wasm {

struct WasmGlobal;
27
struct WasmException;
28

29 30 31 32 33
#define TRACE(...)                                    \
  do {                                                \
    if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
  } while (false)

34 35
#define TRACE_INST_FORMAT "  @%-8d #%-20s|"

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

44
#define RET_ON_PROTOTYPE_OPCODE(feat)                                          \
45
  DCHECK(!this->module_ || this->module_->origin == kWasmOrigin);              \
46 47 48 49
  if (!this->enabled_.feat) {                                                  \
    this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
  } else {                                                                     \
    this->detected_->feat = true;                                              \
50 51
  }

52
#define CHECK_PROTOTYPE_OPCODE(feat)                                           \
53
  DCHECK(!this->module_ || this->module_->origin == kWasmOrigin);              \
54 55
  if (!this->enabled_.feat) {                                                  \
    this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
56
    break;                                                                     \
57 58
  } else {                                                                     \
    this->detected_->feat = true;                                              \
59 60 61 62 63 64
  }

#define OPCODE_ERROR(opcode, message)                                 \
  (this->errorf(this->pc_, "%s: %s", WasmOpcodes::OpcodeName(opcode), \
                (message)))

65
#define ATOMIC_OP_LIST(V)                \
66
  V(AtomicNotify, Uint32)                \
67
  V(I32AtomicWait, Uint32)               \
68
  V(I64AtomicWait, Uint64)               \
69
  V(I32AtomicLoad, Uint32)               \
70
  V(I64AtomicLoad, Uint64)               \
71 72
  V(I32AtomicLoad8U, Uint8)              \
  V(I32AtomicLoad16U, Uint16)            \
73 74 75
  V(I64AtomicLoad8U, Uint8)              \
  V(I64AtomicLoad16U, Uint16)            \
  V(I64AtomicLoad32U, Uint32)            \
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 115 116 117 118 119 120 121 122 123 124
  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)
125

126 127
#define ATOMIC_STORE_OP_LIST(V) \
  V(I32AtomicStore, Uint32)     \
128
  V(I64AtomicStore, Uint64)     \
129
  V(I32AtomicStore8U, Uint8)    \
130 131 132 133
  V(I32AtomicStore16U, Uint16)  \
  V(I64AtomicStore8U, Uint8)    \
  V(I64AtomicStore16U, Uint16)  \
  V(I64AtomicStore32U, Uint32)
134

135
// Helpers for decoding different kinds of immediates which follow bytecodes.
136
template <Decoder::ValidateFlag validate>
137
struct LocalIndexImmediate {
138
  uint32_t index;
139
  ValueType type = kWasmStmt;
140
  uint32_t length;
141

142
  inline LocalIndexImmediate(Decoder* decoder, const byte* pc) {
143
    index = decoder->read_u32v<validate>(pc + 1, &length, "local index");
144 145 146
  }
};

147
template <Decoder::ValidateFlag validate>
148
struct ExceptionIndexImmediate {
149 150
  uint32_t index;
  const WasmException* exception = nullptr;
151
  uint32_t length;
152

153
  inline ExceptionIndexImmediate(Decoder* decoder, const byte* pc) {
154
    index = decoder->read_u32v<validate>(pc + 1, &length, "exception index");
155 156 157
  }
};

158
template <Decoder::ValidateFlag validate>
159
struct ImmI32Immediate {
160
  int32_t value;
161
  uint32_t length;
162
  inline ImmI32Immediate(Decoder* decoder, const byte* pc) {
163
    value = decoder->read_i32v<validate>(pc + 1, &length, "immi32");
164 165 166
  }
};

167
template <Decoder::ValidateFlag validate>
168
struct ImmI64Immediate {
169
  int64_t value;
170
  uint32_t length;
171
  inline ImmI64Immediate(Decoder* decoder, const byte* pc) {
172
    value = decoder->read_i64v<validate>(pc + 1, &length, "immi64");
173 174 175
  }
};

176
template <Decoder::ValidateFlag validate>
177
struct ImmF32Immediate {
178
  float value;
179
  uint32_t length = 4;
180
  inline ImmF32Immediate(Decoder* decoder, const byte* pc) {
181
    // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
182
    uint32_t tmp = decoder->read_u32<validate>(pc + 1, "immf32");
183 184 185 186
    memcpy(&value, &tmp, sizeof(value));
  }
};

187
template <Decoder::ValidateFlag validate>
188
struct ImmF64Immediate {
189
  double value;
190
  uint32_t length = 8;
191
  inline ImmF64Immediate(Decoder* decoder, const byte* pc) {
192
    // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
193
    uint64_t tmp = decoder->read_u64<validate>(pc + 1, "immf64");
194 195 196 197
    memcpy(&value, &tmp, sizeof(value));
  }
};

198
template <Decoder::ValidateFlag validate>
199
struct GlobalIndexImmediate {
200
  uint32_t index;
201 202
  ValueType type = kWasmStmt;
  const WasmGlobal* global = nullptr;
203
  uint32_t length;
204

205
  inline GlobalIndexImmediate(Decoder* decoder, const byte* pc) {
206
    index = decoder->read_u32v<validate>(pc + 1, &length, "global index");
207 208 209
  }
};

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
namespace function_body_decoder {
// Decode a byte representing a local type. Return {false} if the encoded
// byte was invalid or the start of a type index.
inline bool decode_local_type(uint8_t val, ValueType* result) {
  switch (static_cast<ValueTypeCode>(val)) {
    case kLocalVoid:
      *result = kWasmStmt;
      return true;
    case kLocalI32:
      *result = kWasmI32;
      return true;
    case kLocalI64:
      *result = kWasmI64;
      return true;
    case kLocalF32:
      *result = kWasmF32;
      return true;
    case kLocalF64:
      *result = kWasmF64;
      return true;
    case kLocalS128:
      *result = kWasmS128;
      return true;
233 234
    case kLocalFuncRef:
      *result = kWasmFuncRef;
235 236 237 238
      return true;
    case kLocalAnyRef:
      *result = kWasmAnyRef;
      return true;
239 240
    case kLocalExnRef:
      *result = kWasmExnRef;
241 242
      return true;
    default:
243
      *result = kWasmBottom;
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
      return false;
  }
}
}  // namespace function_body_decoder

template <Decoder::ValidateFlag validate>
struct SelectTypeImmediate {
  uint32_t length;
  ValueType type;

  inline SelectTypeImmediate(Decoder* decoder, const byte* pc) {
    uint8_t num_types =
        decoder->read_u32v<validate>(pc + 1, &length, "number of select types");
    if (!VALIDATE(num_types == 1)) {
      decoder->error(
          pc + 1, "Invalid number of types. Select accepts exactly one type");
      return;
    }
    uint8_t val = decoder->read_u8<validate>(pc + length + 1, "select type");
    length++;
    if (!function_body_decoder::decode_local_type(val, &type) ||
        type == kWasmStmt) {
      decoder->error(pc + 1, "invalid select type");
      return;
    }
  }
};

272
template <Decoder::ValidateFlag validate>
273
struct BlockTypeImmediate {
274
  uint32_t length = 1;
275 276 277
  ValueType type = kWasmStmt;
  uint32_t sig_index = 0;
  FunctionSig* sig = nullptr;
278

279 280
  inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
                            const byte* pc) {
281
    uint8_t val = decoder->read_u8<validate>(pc + 1, "block type");
282
    if (!function_body_decoder::decode_local_type(val, &type)) {
283
      // Handle multi-value blocks.
284
      if (!VALIDATE(enabled.mv)) {
285
        decoder->error(pc + 1, "invalid block type");
286
        return;
287
      }
288
      if (!VALIDATE(decoder->ok())) return;
289 290 291 292 293
      int32_t index =
          decoder->read_i32v<validate>(pc + 1, &length, "block arity");
      if (!VALIDATE(length > 0 && index >= 0)) {
        decoder->error(pc + 1, "invalid block type index");
        return;
294
      }
295
      sig_index = static_cast<uint32_t>(index);
296 297
    }
  }
298

299
  uint32_t in_arity() const {
300
    if (type != kWasmBottom) return 0;
301 302 303 304
    return static_cast<uint32_t>(sig->parameter_count());
  }
  uint32_t out_arity() const {
    if (type == kWasmStmt) return 0;
305
    if (type != kWasmBottom) return 1;
306 307 308
    return static_cast<uint32_t>(sig->return_count());
  }
  ValueType in_type(uint32_t index) {
309
    DCHECK_EQ(kWasmBottom, type);
310 311 312
    return sig->GetParam(index);
  }
  ValueType out_type(uint32_t index) {
313
    if (type == kWasmBottom) return sig->GetReturn(index);
314 315 316
    DCHECK_NE(kWasmStmt, type);
    DCHECK_EQ(0, index);
    return type;
317 318 319
  }
};

320
template <Decoder::ValidateFlag validate>
321
struct BranchDepthImmediate {
322
  uint32_t depth;
323
  uint32_t length;
324 325
  inline BranchDepthImmediate(Decoder* decoder, const byte* pc) {
    depth = decoder->read_u32v<validate>(pc + 1, &length, "branch depth");
326 327 328
  }
};

329 330 331 332 333 334 335 336 337 338 339 340
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;
  }
};

341
template <Decoder::ValidateFlag validate>
342
struct CallIndirectImmediate {
343
  uint32_t table_index;
344
  uint32_t sig_index;
345
  FunctionSig* sig = nullptr;
346
  uint32_t length = 0;
347 348
  inline CallIndirectImmediate(const WasmFeatures enabled, Decoder* decoder,
                               const byte* pc) {
349
    uint32_t len = 0;
350
    sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index");
351
    table_index = decoder->read_u8<validate>(pc + 1 + len, "table index");
352
    if (!VALIDATE(table_index == 0 || enabled.anyref)) {
353 354
      decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
                      table_index);
355 356 357 358 359
    }
    length = 1 + len;
  }
};

360
template <Decoder::ValidateFlag validate>
361
struct CallFunctionImmediate {
362
  uint32_t index;
363
  FunctionSig* sig = nullptr;
364
  uint32_t length;
365
  inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
366
    index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
367 368 369
  }
};

370 371 372 373 374 375 376 377 378
template <Decoder::ValidateFlag validate>
struct FunctionIndexImmediate {
  uint32_t index = 0;
  uint32_t length = 1;
  inline FunctionIndexImmediate(Decoder* decoder, const byte* pc) {
    index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
  }
};

379
template <Decoder::ValidateFlag validate>
380
struct MemoryIndexImmediate {
381
  uint32_t index = 0;
382
  uint32_t length = 1;
383
  inline MemoryIndexImmediate() = default;
384
  inline MemoryIndexImmediate(Decoder* decoder, const byte* pc) {
385
    index = decoder->read_u8<validate>(pc + 1, "memory index");
386
    if (!VALIDATE(index == 0)) {
387
      decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
388 389 390 391
    }
  }
};

392 393
template <Decoder::ValidateFlag validate>
struct TableIndexImmediate {
394
  uint32_t index = 0;
395
  unsigned length = 1;
396
  inline TableIndexImmediate() = default;
397 398 399 400 401
  inline TableIndexImmediate(Decoder* decoder, const byte* pc) {
    index = decoder->read_u8<validate>(pc + 1, "table index");
  }
};

402
template <Decoder::ValidateFlag validate>
403
struct BranchTableImmediate {
404 405 406
  uint32_t table_count;
  const byte* start;
  const byte* table;
407
  inline BranchTableImmediate(Decoder* decoder, const byte* pc) {
408
    DCHECK_EQ(kExprBrTable, decoder->read_u8<validate>(pc, "opcode"));
409
    start = pc + 1;
410
    uint32_t len = 0;
411
    table_count = decoder->read_u32v<validate>(pc + 1, &len, "table count");
412
    table = pc + 1 + len;
413 414 415 416
  }
};

// A helper to iterate over a branch table.
417
template <Decoder::ValidateFlag validate>
418 419
class BranchTableIterator {
 public:
420
  uint32_t cur_index() { return index_; }
421
  bool has_next() { return VALIDATE(decoder_->ok()) && index_ <= table_count_; }
422 423 424
  uint32_t next() {
    DCHECK(has_next());
    index_++;
425
    uint32_t length;
426
    uint32_t result =
427
        decoder_->read_u32v<validate>(pc_, &length, "branch table entry");
428 429 430
    pc_ += length;
    return result;
  }
431
  // length, including the length of the {BranchTableImmediate}, but not the
432
  // opcode.
433
  uint32_t length() {
434
    while (has_next()) next();
435
    return static_cast<uint32_t>(pc_ - start_);
436 437 438
  }
  const byte* pc() { return pc_; }

439
  BranchTableIterator(Decoder* decoder,
440
                      const BranchTableImmediate<validate>& imm)
441
      : decoder_(decoder),
442 443 444
        start_(imm.start),
        pc_(imm.table),
        table_count_(imm.table_count) {}
445 446 447 448 449

 private:
  Decoder* decoder_;
  const byte* start_;
  const byte* pc_;
450
  uint32_t index_ = 0;    // the current index.
451 452 453
  uint32_t table_count_;  // the count of entries, not including default.
};

454
template <Decoder::ValidateFlag validate>
455
struct MemoryAccessImmediate {
456 457
  uint32_t alignment;
  uint32_t offset;
458
  uint32_t length = 0;
459 460
  inline MemoryAccessImmediate(Decoder* decoder, const byte* pc,
                               uint32_t max_alignment) {
461
    uint32_t alignment_length;
462
    alignment =
463
        decoder->read_u32v<validate>(pc + 1, &alignment_length, "alignment");
464
    if (!VALIDATE(alignment <= max_alignment)) {
465 466 467 468
      decoder->errorf(pc + 1,
                      "invalid alignment; expected maximum alignment is %u, "
                      "actual alignment is %u",
                      max_alignment, alignment);
469
    }
470
    uint32_t offset_length;
471 472
    offset = decoder->read_u32v<validate>(pc + 1 + alignment_length,
                                          &offset_length, "offset");
473 474 475 476
    length = alignment_length + offset_length;
  }
};

477
// Immediate for SIMD lane operations.
478
template <Decoder::ValidateFlag validate>
479
struct SimdLaneImmediate {
480
  uint8_t lane;
481
  uint32_t length = 1;
482

483
  inline SimdLaneImmediate(Decoder* decoder, const byte* pc) {
484
    lane = decoder->read_u8<validate>(pc + 2, "lane");
485 486 487
  }
};

488
// Immediate for SIMD shift operations.
489
template <Decoder::ValidateFlag validate>
490
struct SimdShiftImmediate {
491
  uint8_t shift;
492
  uint32_t length = 1;
493

494
  inline SimdShiftImmediate(Decoder* decoder, const byte* pc) {
495
    shift = decoder->read_u8<validate>(pc + 2, "shift");
496 497 498
  }
};

499
// Immediate for SIMD S8x16 shuffle operations.
500
template <Decoder::ValidateFlag validate>
501
struct Simd8x16ShuffleImmediate {
502
  uint8_t shuffle[kSimd128Size] = {0};
503

504
  inline Simd8x16ShuffleImmediate(Decoder* decoder, const byte* pc) {
505
    for (uint32_t i = 0; i < kSimd128Size; ++i) {
506
      shuffle[i] = decoder->read_u8<validate>(pc + 2 + i, "shuffle");
507
    }
508 509 510
  }
};

511 512
template <Decoder::ValidateFlag validate>
struct MemoryInitImmediate {
513
  uint32_t data_segment_index = 0;
514
  MemoryIndexImmediate<validate> memory;
515
  unsigned length = 0;
516

517
  inline MemoryInitImmediate(Decoder* decoder, const byte* pc) {
518
    uint32_t len = 0;
519 520 521 522
    data_segment_index =
        decoder->read_i32v<validate>(pc + 2, &len, "data segment index");
    memory = MemoryIndexImmediate<validate>(decoder, pc + 1 + len);
    length = len + memory.length;
523 524 525 526
  }
};

template <Decoder::ValidateFlag validate>
527
struct DataDropImmediate {
528 529 530
  uint32_t index;
  unsigned length;

531
  inline DataDropImmediate(Decoder* decoder, const byte* pc) {
532 533 534 535
    index = decoder->read_i32v<validate>(pc + 2, &length, "data segment index");
  }
};

536 537 538 539 540 541 542 543 544 545 546 547 548 549
template <Decoder::ValidateFlag validate>
struct MemoryCopyImmediate {
  MemoryIndexImmediate<validate> memory_src;
  MemoryIndexImmediate<validate> memory_dst;
  unsigned length = 0;

  inline MemoryCopyImmediate(Decoder* decoder, const byte* pc) {
    memory_src = MemoryIndexImmediate<validate>(decoder, pc + 1);
    memory_dst =
        MemoryIndexImmediate<validate>(decoder, pc + 1 + memory_src.length);
    length = memory_src.length + memory_dst.length;
  }
};

550 551
template <Decoder::ValidateFlag validate>
struct TableInitImmediate {
552
  uint32_t elem_segment_index = 0;
553
  TableIndexImmediate<validate> table;
554
  unsigned length = 0;
555

556
  inline TableInitImmediate(Decoder* decoder, const byte* pc) {
557
    uint32_t len = 0;
558 559 560 561
    elem_segment_index =
        decoder->read_i32v<validate>(pc + 2, &len, "elem segment index");
    table = TableIndexImmediate<validate>(decoder, pc + 1 + len);
    length = len + table.length;
562 563 564 565
  }
};

template <Decoder::ValidateFlag validate>
566
struct ElemDropImmediate {
567 568 569
  uint32_t index;
  unsigned length;

570
  inline ElemDropImmediate(Decoder* decoder, const byte* pc) {
571 572 573 574
    index = decoder->read_i32v<validate>(pc + 2, &length, "elem segment index");
  }
};

575 576 577
template <Decoder::ValidateFlag validate>
struct TableCopyImmediate {
  TableIndexImmediate<validate> table_dst;
578
  TableIndexImmediate<validate> table_src;
579 580 581
  unsigned length = 0;

  inline TableCopyImmediate(Decoder* decoder, const byte* pc) {
582 583 584
    table_dst = TableIndexImmediate<validate>(decoder, pc + 1);
    table_src =
        TableIndexImmediate<validate>(decoder, pc + 1 + table_dst.length);
585 586 587 588
    length = table_src.length + table_dst.length;
  }
};

589
// An entry on the value stack.
590
struct ValueBase {
591 592
  const byte* pc = nullptr;
  ValueType type = kWasmStmt;
593

594
  ValueBase(const byte* pc, ValueType type) : pc(pc), type(type) {}
595 596
};

597 598
template <typename Value>
struct Merge {
599 600
  uint32_t arity = 0;
  union {  // Either multiple values or a single value.
601 602
    Value* array;
    Value first;
603
  } vals = {nullptr};  // Initialize {array} with {nullptr}.
604

605 606 607 608 609 610
  // Tracks whether this merge was ever reached. Uses precise reachability, like
  // Reachability::kReachable.
  bool reached;

  Merge(bool reached = false) : reached(reached) {}

611
  Value& operator[](uint32_t i) {
612 613 614 615 616
    DCHECK_GT(arity, i);
    return arity == 1 ? vals.first : vals.array[i];
  }
};

617
enum ControlKind : uint8_t {
618 619 620 621 622
  kControlIf,
  kControlIfElse,
  kControlBlock,
  kControlLoop,
  kControlTry,
623
  kControlTryCatch
624 625
};

626 627 628 629 630 631 632 633 634
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
};

635
// An entry on the control stack (i.e. if, block, loop, or try).
636 637
template <typename Value>
struct ControlBase {
638 639 640
  ControlKind kind = kControlBlock;
  uint32_t stack_depth = 0;  // stack height at the beginning of the construct.
  const uint8_t* pc = nullptr;
641
  Reachability reachability = kReachable;
642

643 644 645
  // Values merged into the start or end of this control construct.
  Merge<Value> start_merge;
  Merge<Value> end_merge;
646

647 648 649 650 651 652 653 654 655
  MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ControlBase);

  ControlBase(ControlKind kind, uint32_t stack_depth, const uint8_t* pc,
              Reachability reachability)
      : kind(kind),
        stack_depth(stack_depth),
        pc(pc),
        reachability(reachability),
        start_merge(reachability == kReachable) {}
656

657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
  // 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; }
  bool is_loop() const { return kind == kControlLoop; }
  bool is_incomplete_try() const { return kind == kControlTry; }
  bool is_try_catch() const { return kind == kControlTryCatch; }
678
  bool is_try() const { return is_incomplete_try() || is_try_catch(); }
679

680 681 682
  inline Merge<Value>* br_merge() {
    return is_loop() ? &this->start_merge : &this->end_merge;
  }
683 684
};

685 686 687
// This is the list of callback functions that an interface for the
// WasmFullDecoder should implement.
// F(Name, args...)
688 689 690 691 692 693 694 695 696 697 698
#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)                                                      \
699
  F(Catch, Control* block, Value* exception)                                  \
700 701 702 703 704
  F(If, const Value& cond, Control* if_block)                                 \
  F(FallThruTo, Control* c)                                                   \
  F(PopControl, Control* block)                                               \
  F(EndControl, Control* block)                                               \
  /* Instructions: */                                                         \
705 706 707
  F(UnOp, WasmOpcode opcode, const Value& value, Value* result)               \
  F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs,             \
    Value* result)                                                            \
708 709 710 711 712
  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)                                                   \
713
  F(RefFunc, uint32_t function_index, Value* result)                          \
714
  F(Drop, const Value& value)                                                 \
715
  F(DoReturn, Vector<Value> values)                                           \
716 717 718 719 720 721
  F(GetLocal, Value* result, const LocalIndexImmediate<validate>& imm)        \
  F(SetLocal, const Value& value, const LocalIndexImmediate<validate>& imm)   \
  F(TeeLocal, const Value& value, Value* result,                              \
    const LocalIndexImmediate<validate>& imm)                                 \
  F(GetGlobal, Value* result, const GlobalIndexImmediate<validate>& imm)      \
  F(SetGlobal, const Value& value, const GlobalIndexImmediate<validate>& imm) \
722
  F(TableGet, const Value& index, Value* result,                              \
723
    const TableIndexImmediate<validate>& imm)                                 \
724
  F(TableSet, const Value& index, const Value& value,                         \
725
    const TableIndexImmediate<validate>& imm)                                 \
726 727 728 729
  F(Unreachable)                                                              \
  F(Select, const Value& cond, const Value& fval, const Value& tval,          \
    Value* result)                                                            \
  F(Br, Control* target)                                                      \
730
  F(BrIf, const Value& cond, uint32_t depth)                                  \
731 732 733 734 735 736 737 738 739 740 741 742 743
  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(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[])                                                          \
744 745 746 747
  F(ReturnCall, const CallFunctionImmediate<validate>& imm,                   \
    const Value args[])                                                       \
  F(ReturnCallIndirect, const Value& index,                                   \
    const CallIndirectImmediate<validate>& imm, const Value args[])           \
748 749 750 751 752 753 754
  F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result)             \
  F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm,    \
    const Vector<Value> inputs, Value* result)                                \
  F(Simd8x16ShuffleOp, const Simd8x16ShuffleImmediate<validate>& imm,         \
    const Value& input0, const Value& input1, Value* result)                  \
  F(Throw, const ExceptionIndexImmediate<validate>& imm,                      \
    const Vector<Value>& args)                                                \
755 756 757 758
  F(Rethrow, const Value& exception)                                          \
  F(BrOnException, const Value& exception,                                    \
    const ExceptionIndexImmediate<validate>& imm, uint32_t depth,             \
    Vector<Value> values)                                                     \
759 760
  F(AtomicOp, WasmOpcode opcode, Vector<Value> args,                          \
    const MemoryAccessImmediate<validate>& imm, Value* result)                \
761
  F(AtomicFence)                                                              \
762 763
  F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst,   \
    const Value& src, const Value& size)                                      \
764
  F(DataDrop, const DataDropImmediate<validate>& imm)                         \
765
  F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst,   \
766 767 768 769
    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)   \
770
  F(ElemDrop, const ElemDropImmediate<validate>& imm)                         \
771 772
  F(TableCopy, const TableCopyImmediate<validate>& imm, Vector<Value> args)   \
  F(TableGrow, const TableIndexImmediate<validate>& imm, const Value& value,  \
773
    const Value& delta, Value* result)                                        \
774 775 776
  F(TableSize, const TableIndexImmediate<validate>& imm, Value* result)       \
  F(TableFill, const TableIndexImmediate<validate>& imm, const Value& start,  \
    const Value& value, const Value& count)
777 778

// Generic Wasm bytecode decoder with utilities for decoding immediates,
779
// lengths, etc.
780
template <Decoder::ValidateFlag validate>
781 782
class WasmDecoder : public Decoder {
 public:
783 784
  WasmDecoder(const WasmModule* module, const WasmFeatures& enabled,
              WasmFeatures* detected, FunctionSig* sig, const byte* start,
785 786 787
              const byte* end, uint32_t buffer_offset = 0)
      : Decoder(start, end, buffer_offset),
        module_(module),
788 789
        enabled_(enabled),
        detected_(detected),
790 791 792
        sig_(sig),
        local_types_(nullptr) {}
  const WasmModule* module_;
793 794
  const WasmFeatures enabled_;
  WasmFeatures* detected_;
795 796 797 798
  FunctionSig* sig_;

  ZoneVector<ValueType>* local_types_;

799 800 801 802
  uint32_t total_locals() const {
    return local_types_ == nullptr
               ? 0
               : static_cast<uint32_t>(local_types_->size());
803 804
  }

805 806
  static bool DecodeLocals(const WasmFeatures& enabled, Decoder* decoder,
                           const FunctionSig* sig,
807 808 809 810 811 812 813 814 815 816 817 818
                           ZoneVector<ValueType>* type_list) {
    DCHECK_NOT_NULL(type_list);
    DCHECK_EQ(0, type_list->size());
    // Initialize from signature.
    if (sig != nullptr) {
      type_list->assign(sig->parameters().begin(), sig->parameters().end());
    }
    // Decode local declarations, if any.
    uint32_t entries = decoder->consume_u32v("local decls count");
    if (decoder->failed()) return false;

    TRACE("local decls count: %u\n", entries);
819
    while (entries-- > 0 && decoder->more()) {
820 821 822
      uint32_t count = decoder->consume_u32v("local count");
      if (decoder->failed()) return false;

823 824
      DCHECK_LE(type_list->size(), kV8MaxWasmFunctionLocals);
      if (count > kV8MaxWasmFunctionLocals - type_list->size()) {
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
        decoder->error(decoder->pc() - 1, "local count too large");
        return false;
      }
      byte code = decoder->consume_u8("local type");
      if (decoder->failed()) return false;

      ValueType type;
      switch (code) {
        case kLocalI32:
          type = kWasmI32;
          break;
        case kLocalI64:
          type = kWasmI64;
          break;
        case kLocalF32:
          type = kWasmF32;
          break;
        case kLocalF64:
          type = kWasmF64;
          break;
845
        case kLocalAnyRef:
846
          if (enabled.anyref) {
847 848 849 850 851
            type = kWasmAnyRef;
            break;
          }
          decoder->error(decoder->pc() - 1, "invalid local type");
          return false;
852
        case kLocalFuncRef:
853
          if (enabled.anyref) {
854
            type = kWasmFuncRef;
855 856 857
            break;
          }
          decoder->error(decoder->pc() - 1,
858
                         "local type 'funcref' is not enabled with "
859 860
                         "--experimental-wasm-anyref");
          return false;
861
        case kLocalExnRef:
862
          if (enabled.eh) {
863
            type = kWasmExnRef;
864 865 866 867
            break;
          }
          decoder->error(decoder->pc() - 1, "invalid local type");
          return false;
868
        case kLocalS128:
869
          if (enabled.simd) {
870 871 872
            type = kWasmS128;
            break;
          }
873
          V8_FALLTHROUGH;
874 875 876 877 878 879 880 881 882 883 884
        default:
          decoder->error(decoder->pc() - 1, "invalid local type");
          return false;
      }
      type_list->insert(type_list->end(), count, type);
    }
    DCHECK(decoder->ok());
    return true;
  }

  static BitVector* AnalyzeLoopAssignment(Decoder* decoder, const byte* pc,
885
                                          uint32_t locals_count, Zone* zone) {
886 887 888
    if (pc >= decoder->end()) return nullptr;
    if (*pc != kExprLoop) return nullptr;

889 890
    // 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.
891 892 893
    BitVector* assigned = new (zone) BitVector(locals_count, zone);
    int depth = 0;
    // Iteratively process all AST nodes nested inside the loop.
894
    while (pc < decoder->end() && VALIDATE(decoder->ok())) {
895
      WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
896
      uint32_t length = 1;
897 898 899 900 901 902 903 904 905 906
      switch (opcode) {
        case kExprLoop:
        case kExprIf:
        case kExprBlock:
        case kExprTry:
          length = OpcodeLength(decoder, pc);
          depth++;
          break;
        case kExprSetLocal:  // fallthru
        case kExprTeeLocal: {
907
          LocalIndexImmediate<validate> imm(decoder, pc);
908
          if (assigned->length() > 0 &&
909
              imm.index < static_cast<uint32_t>(assigned->length())) {
910
            // Unverified code might have an out-of-bounds index.
911
            assigned->Add(imm.index);
912
          }
913
          length = 1 + imm.length;
914 915
          break;
        }
916
        case kExprMemoryGrow:
917 918
        case kExprCallFunction:
        case kExprCallIndirect:
919 920
        case kExprReturnCall:
        case kExprReturnCallIndirect:
921
          // Add instance cache nodes to the assigned set.
922 923
          // TODO(titzer): make this more clear.
          assigned->Add(locals_count - 1);
924 925
          length = OpcodeLength(decoder, pc);
          break;
926 927 928 929 930 931 932 933 934 935
        case kExprEnd:
          depth--;
          break;
        default:
          length = OpcodeLength(decoder, pc);
          break;
      }
      if (depth <= 0) break;
      pc += length;
    }
936
    return VALIDATE(decoder->ok()) ? assigned : nullptr;
937 938
  }

939
  inline bool Validate(const byte* pc, LocalIndexImmediate<validate>& imm) {
940 941
    if (!VALIDATE(imm.index < total_locals())) {
      errorf(pc + 1, "invalid local index: %u", imm.index);
942
      return false;
943
    }
944
    imm.type = local_types_ ? local_types_->at(imm.index) : kWasmStmt;
945
    return true;
946 947
  }

948
  inline bool Complete(const byte* pc, ExceptionIndexImmediate<validate>& imm) {
949
    if (!VALIDATE(module_ != nullptr &&
950
                  imm.index < module_->exceptions.size())) {
951
      return false;
952
    }
953
    imm.exception = &module_->exceptions[imm.index];
954
    return true;
955 956
  }

957 958 959 960 961 962 963 964
  inline bool Validate(const byte* pc, ExceptionIndexImmediate<validate>& imm) {
    if (!Complete(pc, imm)) {
      errorf(pc + 1, "Invalid exception index: %u", imm.index);
      return false;
    }
    return true;
  }

965 966 967
  inline bool Validate(const byte* pc, GlobalIndexImmediate<validate>& imm) {
    if (!VALIDATE(module_ != nullptr && imm.index < module_->globals.size())) {
      errorf(pc + 1, "invalid global index: %u", imm.index);
968
      return false;
969
    }
970 971
    imm.global = &module_->globals[imm.index];
    imm.type = imm.global->type;
972
    return true;
973 974
  }

975 976
  inline bool CanReturnCall(FunctionSig* target_sig) {
    if (target_sig == nullptr) return false;
977
    size_t num_returns = sig_->return_count();
978
    if (num_returns != target_sig->return_count()) return false;
979
    for (size_t i = 0; i < num_returns; ++i) {
980
      if (sig_->GetReturn(i) != target_sig->GetReturn(i)) return false;
981 982 983 984
    }
    return true;
  }

985
  inline bool Complete(const byte* pc, CallFunctionImmediate<validate>& imm) {
986
    if (!VALIDATE(module_ != nullptr &&
987
                  imm.index < module_->functions.size())) {
988
      return false;
989
    }
990
    imm.sig = module_->functions[imm.index].sig;
991
    return true;
992 993
  }

994 995
  inline bool Validate(const byte* pc, CallFunctionImmediate<validate>& imm) {
    if (Complete(pc, imm)) {
996 997
      return true;
    }
998
    errorf(pc + 1, "invalid function index: %u", imm.index);
999 1000 1001
    return false;
  }

1002
  inline bool Complete(const byte* pc, CallIndirectImmediate<validate>& imm) {
1003
    if (!VALIDATE(module_ != nullptr &&
1004
                  imm.sig_index < module_->signatures.size())) {
1005
      return false;
1006
    }
1007
    imm.sig = module_->signatures[imm.sig_index];
1008
    return true;
1009 1010
  }

1011
  inline bool Validate(const byte* pc, CallIndirectImmediate<validate>& imm) {
1012 1013
    if (!VALIDATE(module_ != nullptr &&
                  imm.table_index < module_->tables.size())) {
1014 1015 1016
      error("function table has to exist to execute call_indirect");
      return false;
    }
1017
    if (!VALIDATE(module_ != nullptr &&
1018 1019
                  module_->tables[imm.table_index].type == kWasmFuncRef)) {
      error("table of call_indirect must be of type funcref");
1020 1021
      return false;
    }
1022 1023
    if (!Complete(pc, imm)) {
      errorf(pc + 1, "invalid signature index: #%u", imm.sig_index);
1024
      return false;
1025
    }
1026
    return true;
1027 1028
  }

1029
  inline bool Validate(const byte* pc, BranchDepthImmediate<validate>& imm,
1030
                       size_t control_depth) {
1031
    if (!VALIDATE(imm.depth < control_depth)) {
1032
      errorf(pc + 1, "invalid branch depth: %u", imm.depth);
1033
      return false;
1034
    }
1035
    return true;
1036 1037
  }

1038
  bool Validate(const byte* pc, BranchTableImmediate<validate>& imm,
1039
                size_t block_depth) {
1040
    if (!VALIDATE(imm.table_count < kV8MaxWasmFunctionSize)) {
1041
      errorf(pc + 1, "invalid table count (> max function size): %u",
1042
             imm.table_count);
1043 1044
      return false;
    }
1045
    return checkAvailable(imm.table_count);
1046 1047 1048
  }

  inline bool Validate(const byte* pc, WasmOpcode opcode,
1049
                       SimdLaneImmediate<validate>& imm) {
1050 1051
    uint8_t num_lanes = 0;
    switch (opcode) {
1052 1053
      case kExprF64x2ExtractLane:
      case kExprF64x2ReplaceLane:
1054 1055 1056 1057
      case kExprI64x2ExtractLane:
      case kExprI64x2ReplaceLane:
        num_lanes = 2;
        break;
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
      case kExprF32x4ExtractLane:
      case kExprF32x4ReplaceLane:
      case kExprI32x4ExtractLane:
      case kExprI32x4ReplaceLane:
        num_lanes = 4;
        break;
      case kExprI16x8ExtractLane:
      case kExprI16x8ReplaceLane:
        num_lanes = 8;
        break;
      case kExprI8x16ExtractLane:
      case kExprI8x16ReplaceLane:
        num_lanes = 16;
        break;
      default:
        UNREACHABLE();
        break;
    }
1076
    if (!VALIDATE(imm.lane >= 0 && imm.lane < num_lanes)) {
1077 1078 1079 1080 1081 1082 1083 1084
      error(pc_ + 2, "invalid lane index");
      return false;
    } else {
      return true;
    }
  }

  inline bool Validate(const byte* pc, WasmOpcode opcode,
1085
                       SimdShiftImmediate<validate>& imm) {
1086 1087
    uint8_t max_shift = 0;
    switch (opcode) {
1088 1089 1090 1091 1092
      case kExprI64x2Shl:
      case kExprI64x2ShrS:
      case kExprI64x2ShrU:
        max_shift = 64;
        break;
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
      case kExprI32x4Shl:
      case kExprI32x4ShrS:
      case kExprI32x4ShrU:
        max_shift = 32;
        break;
      case kExprI16x8Shl:
      case kExprI16x8ShrS:
      case kExprI16x8ShrU:
        max_shift = 16;
        break;
      case kExprI8x16Shl:
      case kExprI8x16ShrS:
      case kExprI8x16ShrU:
        max_shift = 8;
        break;
      default:
        UNREACHABLE();
        break;
    }
1112
    if (!VALIDATE(imm.shift >= 0 && imm.shift < max_shift)) {
1113 1114 1115 1116 1117 1118 1119 1120
      error(pc_ + 2, "invalid shift amount");
      return false;
    } else {
      return true;
    }
  }

  inline bool Validate(const byte* pc,
1121
                       Simd8x16ShuffleImmediate<validate>& imm) {
1122
    uint8_t max_lane = 0;
1123
    for (uint32_t i = 0; i < kSimd128Size; ++i) {
1124
      max_lane = std::max(max_lane, imm.shuffle[i]);
1125
    }
1126
    // Shuffle indices must be in [0..31] for a 16 lane shuffle.
1127
    if (!VALIDATE(max_lane <= 2 * kSimd128Size)) {
1128 1129 1130
      error(pc_ + 2, "invalid shuffle mask");
      return false;
    }
1131
    return true;
1132 1133
  }

1134
  inline bool Complete(BlockTypeImmediate<validate>& imm) {
1135
    if (imm.type != kWasmBottom) return true;
1136
    if (!VALIDATE(module_ && imm.sig_index < module_->signatures.size())) {
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
      return false;
    }
    imm.sig = module_->signatures[imm.sig_index];
    return true;
  }

  inline bool Validate(BlockTypeImmediate<validate>& imm) {
    if (!Complete(imm)) {
      errorf(pc_, "block type index %u out of bounds (%zu signatures)",
             imm.sig_index, module_ ? module_->signatures.size() : 0);
      return false;
    }
    return true;
  }

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

1161
  inline bool Validate(const byte* pc, MemoryIndexImmediate<validate>& imm) {
1162
    if (!VALIDATE(module_ != nullptr && module_->has_memory)) {
1163
      errorf(pc + 1, "memory instruction with no memory");
1164 1165 1166 1167 1168 1169
      return false;
    }
    return true;
  }

  inline bool Validate(MemoryInitImmediate<validate>& imm) {
1170 1171 1172 1173 1174 1175
    if (!VALIDATE(module_ != nullptr &&
                  imm.data_segment_index <
                      module_->num_declared_data_segments)) {
      errorf(pc_ + 2, "invalid data segment index: %u", imm.data_segment_index);
      return false;
    }
1176 1177
    if (!Validate(pc_ + imm.length - imm.memory.length - 1, imm.memory))
      return false;
1178 1179 1180
    return true;
  }

1181
  inline bool Validate(DataDropImmediate<validate>& imm) {
1182 1183 1184 1185 1186
    if (!VALIDATE(module_ != nullptr &&
                  imm.index < module_->num_declared_data_segments)) {
      errorf(pc_ + 2, "invalid data segment index: %u", imm.index);
      return false;
    }
1187 1188 1189
    return true;
  }

1190 1191 1192 1193 1194 1195
  inline bool Validate(MemoryCopyImmediate<validate>& imm) {
    if (!Validate(pc_ + 1, imm.memory_src)) return false;
    if (!Validate(pc_ + 2, imm.memory_dst)) return false;
    return true;
  }

1196 1197
  inline bool Validate(const byte* pc, TableIndexImmediate<validate>& imm) {
    if (!VALIDATE(module_ != nullptr && imm.index < module_->tables.size())) {
1198
      errorf(pc, "invalid table index: %u", imm.index);
1199 1200 1201 1202 1203 1204 1205
      return false;
    }
    return true;
  }

  inline bool Validate(TableInitImmediate<validate>& imm) {
    if (!VALIDATE(module_ != nullptr &&
1206
                  imm.elem_segment_index < module_->elem_segments.size())) {
1207 1208 1209 1210
      errorf(pc_ + 2, "invalid element segment index: %u",
             imm.elem_segment_index);
      return false;
    }
1211 1212
    if (!Validate(pc_ + imm.length - imm.table.length - 1, imm.table))
      return false;
1213 1214 1215
    return true;
  }

1216
  inline bool Validate(ElemDropImmediate<validate>& imm) {
1217
    if (!VALIDATE(module_ != nullptr &&
1218
                  imm.index < module_->elem_segments.size())) {
1219 1220 1221 1222 1223 1224
      errorf(pc_ + 2, "invalid element segment index: %u", imm.index);
      return false;
    }
    return true;
  }

1225 1226 1227 1228 1229 1230
  inline bool Validate(TableCopyImmediate<validate>& imm) {
    if (!Validate(pc_ + 1, imm.table_src)) return false;
    if (!Validate(pc_ + 2, imm.table_dst)) return false;
    return true;
  }

1231
  static uint32_t OpcodeLength(Decoder* decoder, const byte* pc) {
1232 1233 1234 1235 1236 1237 1238
    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
      {
1239 1240
        MemoryAccessImmediate<validate> imm(decoder, pc, UINT32_MAX);
        return 1 + imm.length;
1241 1242 1243
      }
      case kExprBr:
      case kExprBrIf: {
1244
        BranchDepthImmediate<validate> imm(decoder, pc);
1245
        return 1 + imm.length;
1246
      }
1247 1248
      case kExprGetGlobal:
      case kExprSetGlobal: {
1249 1250
        GlobalIndexImmediate<validate> imm(decoder, pc);
        return 1 + imm.length;
1251
      }
1252 1253
      case kExprTableGet:
      case kExprTableSet: {
1254 1255 1256
        TableIndexImmediate<validate> imm(decoder, pc);
        return 1 + imm.length;
      }
1257 1258
      case kExprCallFunction:
      case kExprReturnCall: {
1259 1260
        CallFunctionImmediate<validate> imm(decoder, pc);
        return 1 + imm.length;
1261
      }
1262 1263
      case kExprCallIndirect:
      case kExprReturnCallIndirect: {
1264
        CallIndirectImmediate<validate> imm(kAllWasmFeatures, decoder, pc);
1265
        return 1 + imm.length;
1266 1267 1268 1269 1270 1271
      }

      case kExprTry:
      case kExprIf:  // fall through
      case kExprLoop:
      case kExprBlock: {
1272
        BlockTypeImmediate<validate> imm(kAllWasmFeatures, decoder, pc);
1273
        return 1 + imm.length;
1274 1275
      }

1276
      case kExprThrow: {
1277 1278
        ExceptionIndexImmediate<validate> imm(decoder, pc);
        return 1 + imm.length;
1279 1280
      }

1281
      case kExprBrOnExn: {
1282 1283
        BranchOnExceptionImmediate<validate> imm(decoder, pc);
        return 1 + imm.length;
1284 1285
      }

1286 1287 1288
      case kExprSetLocal:
      case kExprTeeLocal:
      case kExprGetLocal: {
1289
        LocalIndexImmediate<validate> imm(decoder, pc);
1290
        return 1 + imm.length;
1291
      }
1292 1293 1294 1295
      case kExprSelectWithType: {
        SelectTypeImmediate<validate> imm(decoder, pc);
        return 1 + imm.length;
      }
1296
      case kExprBrTable: {
1297 1298
        BranchTableImmediate<validate> imm(decoder, pc);
        BranchTableIterator<validate> iterator(decoder, imm);
1299 1300 1301
        return 1 + iterator.length();
      }
      case kExprI32Const: {
1302 1303
        ImmI32Immediate<validate> imm(decoder, pc);
        return 1 + imm.length;
1304 1305
      }
      case kExprI64Const: {
1306 1307
        ImmI64Immediate<validate> imm(decoder, pc);
        return 1 + imm.length;
1308
      }
1309 1310 1311
      case kExprRefNull: {
        return 1;
      }
1312 1313 1314 1315
      case kExprRefFunc: {
        FunctionIndexImmediate<validate> imm(decoder, pc);
        return 1 + imm.length;
      }
1316
      case kExprMemoryGrow:
1317
      case kExprMemorySize: {
1318 1319
        MemoryIndexImmediate<validate> imm(decoder, pc);
        return 1 + imm.length;
1320 1321 1322 1323 1324
      }
      case kExprF32Const:
        return 5;
      case kExprF64Const:
        return 9;
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
      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: {
            MemoryInitImmediate<validate> imm(decoder, pc);
            return 2 + imm.length;
          }
1344 1345
          case kExprDataDrop: {
            DataDropImmediate<validate> imm(decoder, pc);
1346 1347
            return 2 + imm.length;
          }
1348 1349 1350 1351
          case kExprMemoryCopy: {
            MemoryCopyImmediate<validate> imm(decoder, pc);
            return 2 + imm.length;
          }
1352 1353 1354 1355 1356 1357 1358 1359
          case kExprMemoryFill: {
            MemoryIndexImmediate<validate> imm(decoder, pc + 1);
            return 2 + imm.length;
          }
          case kExprTableInit: {
            TableInitImmediate<validate> imm(decoder, pc);
            return 2 + imm.length;
          }
1360 1361
          case kExprElemDrop: {
            ElemDropImmediate<validate> imm(decoder, pc);
1362 1363 1364
            return 2 + imm.length;
          }
          case kExprTableCopy: {
1365
            TableCopyImmediate<validate> imm(decoder, pc);
1366 1367
            return 2 + imm.length;
          }
1368
          case kExprTableGrow:
1369 1370
          case kExprTableSize:
          case kExprTableFill: {
1371 1372 1373
            TableIndexImmediate<validate> imm(decoder, pc);
            return 2 + imm.length;
          }
1374 1375 1376 1377 1378
          default:
            decoder->error(pc, "invalid numeric opcode");
            return 2;
        }
      }
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
      case kSimdPrefix: {
        byte simd_index = decoder->read_u8<validate>(pc + 1, "simd_index");
        WasmOpcode opcode =
            static_cast<WasmOpcode>(kSimdPrefix << 8 | simd_index);
        switch (opcode) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
          FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
          return 2;
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
          FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
          return 3;
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
          FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
          {
1396 1397
            MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
            return 2 + imm.length;
1398 1399 1400 1401 1402 1403 1404 1405 1406
          }
          // Shuffles require a byte per lane, or 16 immediate bytes.
          case kExprS8x16Shuffle:
            return 2 + kSimd128Size;
          default:
            decoder->error(pc, "invalid SIMD opcode");
            return 2;
        }
      }
1407 1408 1409 1410 1411 1412 1413 1414 1415
      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
          {
1416 1417
            MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
            return 2 + imm.length;
1418
          }
1419 1420 1421 1422 1423 1424
#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;
          }
1425 1426 1427 1428 1429
          default:
            decoder->error(pc, "invalid Atomics opcode");
            return 2;
        }
      }
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
      default:
        return 1;
    }
  }

  std::pair<uint32_t, uint32_t> StackEffect(const byte* pc) {
    WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
    // Handle "simple" opcodes with a fixed signature first.
    FunctionSig* sig = WasmOpcodes::Signature(opcode);
    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:
1446
      case kExprSelectWithType:
1447
        return {3, 1};
1448
      case kExprTableSet:
1449 1450 1451
      FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
        return {2, 0};
      FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1452
      case kExprTableGet:
1453
      case kExprTeeLocal:
1454
      case kExprMemoryGrow:
1455 1456 1457 1458 1459 1460 1461
        return {1, 1};
      case kExprSetLocal:
      case kExprSetGlobal:
      case kExprDrop:
      case kExprBrIf:
      case kExprBrTable:
      case kExprIf:
1462
      case kExprRethrow:
1463 1464 1465 1466 1467 1468 1469
        return {1, 0};
      case kExprGetLocal:
      case kExprGetGlobal:
      case kExprI32Const:
      case kExprI64Const:
      case kExprF32Const:
      case kExprF64Const:
1470
      case kExprRefNull:
1471
      case kExprRefFunc:
1472 1473 1474
      case kExprMemorySize:
        return {0, 1};
      case kExprCallFunction: {
1475 1476 1477
        CallFunctionImmediate<validate> imm(this, pc);
        CHECK(Complete(pc, imm));
        return {imm.sig->parameter_count(), imm.sig->return_count()};
1478 1479
      }
      case kExprCallIndirect: {
1480
        CallIndirectImmediate<validate> imm(this->enabled_, this, pc);
1481
        CHECK(Complete(pc, imm));
1482
        // Indirect calls pop an additional argument for the table index.
1483 1484
        return {imm.sig->parameter_count() + 1,
                imm.sig->return_count()};
1485
      }
1486 1487 1488 1489 1490 1491
      case kExprThrow: {
        ExceptionIndexImmediate<validate> imm(this, pc);
        CHECK(Complete(pc, imm));
        DCHECK_EQ(0, imm.exception->sig->return_count());
        return {imm.exception->sig->parameter_count(), 0};
      }
1492 1493 1494 1495 1496
      case kExprBr:
      case kExprBlock:
      case kExprLoop:
      case kExprEnd:
      case kExprElse:
1497
      case kExprTry:
1498
      case kExprCatch:
1499
      case kExprBrOnExn:
1500 1501
      case kExprNop:
      case kExprReturn:
1502 1503
      case kExprReturnCall:
      case kExprReturnCallIndirect:
1504 1505
      case kExprUnreachable:
        return {0, 0};
1506
      case kNumericPrefix:
1507 1508 1509 1510
      case kAtomicPrefix:
      case kSimdPrefix: {
        opcode = static_cast<WasmOpcode>(opcode << 8 | *(pc + 1));
        switch (opcode) {
1511
          FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1512
            return {1, 1};
1513
          FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1514
          FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1515
            return {2, 1};
1516 1517 1518 1519 1520 1521 1522
          default: {
            sig = WasmOpcodes::Signature(opcode);
            if (sig) {
              return {sig->parameter_count(), sig->return_count()};
            }
          }
        }
1523
        V8_FALLTHROUGH;
1524
      }
1525
      default:
1526 1527
        FATAL("unimplemented opcode: %x (%s)", opcode,
              WasmOpcodes::OpcodeName(opcode));
1528 1529 1530 1531 1532 1533 1534
        return {0, 0};
    }
#undef DECLARE_OPCODE_CASE
    // clang-format on
  }
};

1535
#define CALL_INTERFACE(name, ...) interface_.name(this, ##__VA_ARGS__)
1536 1537 1538 1539 1540 1541
#define CALL_INTERFACE_IF_REACHABLE(name, ...)                 \
  do {                                                         \
    DCHECK(!control_.empty());                                 \
    if (VALIDATE(this->ok()) && control_.back().reachable()) { \
      interface_.name(this, ##__VA_ARGS__);                    \
    }                                                          \
1542
  } while (false)
1543 1544 1545 1546 1547 1548 1549
#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__);                     \
    }                                                           \
1550 1551
  } while (false)

1552
template <Decoder::ValidateFlag validate, typename Interface>
1553
class WasmFullDecoder : public WasmDecoder<validate> {
1554 1555
  using Value = typename Interface::Value;
  using Control = typename Interface::Control;
1556
  using ArgVector = base::SmallVector<Value, 8>;
1557

1558 1559
  // All Value types should be trivially copyable for performance. We push, pop,
  // and store them in local variables.
1560
  ASSERT_TRIVIALLY_COPYABLE(Value);
1561 1562 1563

 public:
  template <typename... InterfaceArgs>
1564
  WasmFullDecoder(Zone* zone, const WasmModule* module,
1565
                  const WasmFeatures& enabled, WasmFeatures* detected,
1566
                  const FunctionBody& body, InterfaceArgs&&... interface_args)
1567 1568
      : WasmDecoder<validate>(module, enabled, detected, body.sig, body.start,
                              body.end, body.offset),
1569 1570 1571 1572
        zone_(zone),
        interface_(std::forward<InterfaceArgs>(interface_args)...),
        local_type_vec_(zone),
        stack_(zone),
1573
        control_(zone) {
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
    this->local_types_ = &local_type_vec_;
  }

  Interface& interface() { return interface_; }

  bool Decode() {
    DCHECK(stack_.empty());
    DCHECK(control_.empty());

    if (this->end_ < this->pc_) {
      this->error("function body end < start");
      return false;
    }

    DCHECK_EQ(0, this->local_types_->size());
1589 1590
    WasmDecoder<validate>::DecodeLocals(this->enabled_, this, this->sig_,
                                        this->local_types_);
1591
    CALL_INTERFACE(StartFunction);
1592
    DecodeFunctionBody();
1593
    if (!this->failed()) CALL_INTERFACE(FinishFunction);
1594

1595 1596 1597 1598 1599
    // Generate a better error message whether the unterminated control
    // structure is the function body block or an innner structure.
    if (control_.size() > 1) {
      this->error(control_.back().pc, "unterminated control structure");
    } else if (control_.size() == 1) {
1600 1601 1602
      this->error("function body must end with \"end\" opcode");
    }

1603 1604
    if (this->failed()) return this->TraceFailed();

1605
    TRACE("wasm-decode %s\n\n", VALIDATE(this->ok()) ? "ok" : "failed");
1606 1607 1608 1609 1610

    return true;
  }

  bool TraceFailed() {
1611 1612 1613
    TRACE("wasm-error module+%-6d func+%d: %s\n\n", this->error_.offset(),
          this->GetBufferRelativeOffset(this->error_.offset()),
          this->error_.message().c_str());
1614 1615 1616 1617 1618
    return false;
  }

  const char* SafeOpcodeNameAt(const byte* pc) {
    if (pc >= this->end_) return "<end>";
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628
    WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
    if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
      return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(opcode));
    }
    // We need one more byte.
    ++pc;
    if (pc >= this->end_) return "<end>";
    byte sub_opcode = *pc;
    opcode = static_cast<WasmOpcode>(opcode << 8 | sub_opcode);
    return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(opcode));
1629 1630 1631 1632
  }

  inline Zone* zone() const { return zone_; }

1633
  inline uint32_t num_locals() const {
1634 1635 1636 1637 1638 1639 1640
    return static_cast<uint32_t>(local_type_vec_.size());
  }

  inline ValueType GetLocalType(uint32_t index) {
    return local_type_vec_[index];
  }

1641
  inline WasmCodePosition position() {
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
    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);
1653
    return &control_.back() - depth;
1654 1655 1656
  }

  inline uint32_t stack_size() const {
1657
    DCHECK_GE(kMaxUInt32, stack_.size());
1658 1659 1660
    return static_cast<uint32_t>(stack_.size());
  }

1661 1662 1663 1664
  inline Value* stack_value(uint32_t depth) {
    DCHECK_LT(0, depth);
    DCHECK_GE(stack_.size(), depth);
    return &*(stack_.end() - depth);
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675
  }

 private:
  Zone* zone_;

  Interface interface_;

  ZoneVector<ValueType> local_type_vec_;  // types of local variables.
  ZoneVector<Value> stack_;               // stack of values.
  ZoneVector<Control> control_;           // stack of blocks, loops, and ifs.

1676
  static Value UnreachableValue(const uint8_t* pc) {
1677
    return Value{pc, kWasmBottom};
1678 1679
  }

1680
  bool CheckHasMemory() {
1681 1682 1683 1684 1685
    if (!VALIDATE(this->module_->has_memory)) {
      this->error(this->pc_ - 1, "memory instruction with no memory");
      return false;
    }
    return true;
1686 1687
  }

1688 1689 1690 1691 1692 1693 1694 1695
  bool CheckHasSharedMemory() {
    if (!VALIDATE(this->module_->has_shared_memory)) {
      this->error(this->pc_ - 1, "Atomic opcodes used without shared memory");
      return false;
    }
    return true;
  }

1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
  class TraceLine {
   public:
    static constexpr int kMaxLen = 512;
    ~TraceLine() {
      if (!FLAG_trace_wasm_decoder) return;
      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:
    char buffer_[kMaxLen];
    int len_ = 0;
  };

1722 1723
  // Decodes the body of a function.
  void DecodeFunctionBody() {
1724 1725
    TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n", this->start(),
          this->end(), this->pc_offset(),
1726 1727 1728 1729
          static_cast<int>(this->end() - this->start()));

    // Set up initial function block.
    {
1730
      auto* c = PushControl(kControlBlock);
1731
      InitMerge(&c->start_merge, 0, [](uint32_t) -> Value { UNREACHABLE(); });
1732 1733
      InitMerge(&c->end_merge,
                static_cast<uint32_t>(this->sig_->return_count()),
1734 1735 1736
                [&](uint32_t i) {
                  return Value{this->pc_, this->sig_->GetReturn(i)};
                });
1737
      CALL_INTERFACE(StartFunctionBody, c);
1738 1739 1740
    }

    while (this->pc_ < this->end_) {  // decoding loop.
1741
      uint32_t len = 1;
1742
      WasmOpcode opcode = static_cast<WasmOpcode>(*this->pc_);
1743 1744 1745

      CALL_INTERFACE_IF_REACHABLE(NextInstruction, opcode);

1746
#if DEBUG
1747 1748 1749
      TraceLine trace_msg;
#define TRACE_PART(...) trace_msg.Append(__VA_ARGS__)
      if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
1750
        TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
1751
                   WasmOpcodes::OpcodeName(opcode));
1752
      }
1753 1754
#else
#define TRACE_PART(...)
1755 1756
#endif

1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
      switch (opcode) {
#define BUILD_SIMPLE_OPCODE(op, _, sig) \
  case kExpr##op:                       \
    BuildSimpleOperator_##sig(opcode);  \
    break;
        FOREACH_SIMPLE_OPCODE(BUILD_SIMPLE_OPCODE)
#undef BUILD_SIMPLE_OPCODE
        case kExprNop:
          break;
        case kExprBlock: {
          BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
          if (!this->Validate(imm)) break;
1769
          auto args = PopArgs(imm.sig);
1770
          auto* block = PushControl(kControlBlock);
1771
          SetBlockType(block, imm, args.begin());
1772 1773 1774 1775 1776 1777 1778
          CALL_INTERFACE_IF_REACHABLE(Block, block);
          PushMergeValues(block, &block->start_merge);
          len = 1 + imm.length;
          break;
        }
        case kExprRethrow: {
          CHECK_PROTOTYPE_OPCODE(eh);
1779
          auto exception = Pop(0, kWasmExnRef);
1780
          CALL_INTERFACE_IF_REACHABLE(Rethrow, exception);
1781 1782 1783 1784 1785 1786 1787 1788
          EndControl();
          break;
        }
        case kExprThrow: {
          CHECK_PROTOTYPE_OPCODE(eh);
          ExceptionIndexImmediate<validate> imm(this, this->pc_);
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
1789 1790
          auto args = PopArgs(imm.exception->ToFunctionSig());
          CALL_INTERFACE_IF_REACHABLE(Throw, imm, VectorOf(args));
1791 1792 1793 1794 1795 1796 1797
          EndControl();
          break;
        }
        case kExprTry: {
          CHECK_PROTOTYPE_OPCODE(eh);
          BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
          if (!this->Validate(imm)) break;
1798
          auto args = PopArgs(imm.sig);
1799
          auto* try_block = PushControl(kControlTry);
1800
          SetBlockType(try_block, imm, args.begin());
1801 1802 1803 1804 1805 1806 1807 1808 1809
          len = 1 + imm.length;
          CALL_INTERFACE_IF_REACHABLE(Try, try_block);
          PushMergeValues(try_block, &try_block->start_merge);
          break;
        }
        case kExprCatch: {
          CHECK_PROTOTYPE_OPCODE(eh);
          if (!VALIDATE(!control_.empty())) {
            this->error("catch does not match any try");
1810 1811
            break;
          }
1812 1813 1814
          Control* c = &control_.back();
          if (!VALIDATE(c->is_try())) {
            this->error("catch does not match any try");
1815 1816
            break;
          }
1817 1818
          if (!VALIDATE(c->is_incomplete_try())) {
            this->error("catch already present for try");
1819 1820
            break;
          }
1821 1822
          c->kind = kControlTryCatch;
          FallThruTo(c);
1823
          stack_.erase(stack_.begin() + c->stack_depth, stack_.end());
1824
          c->reachability = control_at(1)->innerReachability();
1825
          auto* exception = Push(kWasmExnRef);
1826
          CALL_INTERFACE_IF_PARENT_REACHABLE(Catch, c, exception);
1827 1828
          break;
        }
1829
        case kExprBrOnExn: {
1830
          CHECK_PROTOTYPE_OPCODE(eh);
1831 1832 1833 1834
          BranchOnExceptionImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(this->pc_, imm.depth, control_.size())) break;
          if (!this->Validate(this->pc_ + imm.depth.length, imm.index)) break;
          Control* c = control_at(imm.depth.depth);
1835
          auto exception = Pop(0, kWasmExnRef);
1836
          const WasmExceptionSig* sig = imm.index.exception->sig;
1837 1838 1839 1840 1841 1842 1843
          size_t value_count = sig->parameter_count();
          // TODO(mstarzinger): 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);
1844 1845
          TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
          if (V8_LIKELY(check_result == kReachableBranch)) {
1846
            CALL_INTERFACE(BrOnException, exception, imm.index, imm.depth.depth,
1847 1848
                           values);
            c->br_merge()->reached = true;
1849 1850
          } else if (check_result == kInvalidStack) {
            break;
1851
          }
1852
          len = 1 + imm.length;
1853
          for (size_t i = 0; i < value_count; ++i) Pop();
1854
          auto* pexception = Push(kWasmExnRef);
1855
          *pexception = exception;
1856 1857 1858 1859 1860
          break;
        }
        case kExprLoop: {
          BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
          if (!this->Validate(imm)) break;
1861
          auto args = PopArgs(imm.sig);
1862
          auto* block = PushControl(kControlLoop);
1863
          SetBlockType(&control_.back(), imm, args.begin());
1864 1865 1866 1867 1868 1869 1870 1871 1872
          len = 1 + imm.length;
          CALL_INTERFACE_IF_REACHABLE(Loop, block);
          PushMergeValues(block, &block->start_merge);
          break;
        }
        case kExprIf: {
          BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
          if (!this->Validate(imm)) break;
          auto cond = Pop(0, kWasmI32);
1873
          auto args = PopArgs(imm.sig);
1874
          if (!VALIDATE(this->ok())) break;
1875
          auto* if_block = PushControl(kControlIf);
1876
          SetBlockType(if_block, imm, args.begin());
1877 1878 1879 1880 1881 1882 1883 1884
          CALL_INTERFACE_IF_REACHABLE(If, cond, if_block);
          len = 1 + imm.length;
          PushMergeValues(if_block, &if_block->start_merge);
          break;
        }
        case kExprElse: {
          if (!VALIDATE(!control_.empty())) {
            this->error("else does not match any if");
1885 1886
            break;
          }
1887 1888 1889
          Control* c = &control_.back();
          if (!VALIDATE(c->is_if())) {
            this->error(this->pc_, "else does not match an if");
1890 1891
            break;
          }
1892 1893
          if (c->is_if_else()) {
            this->error(this->pc_, "else already present for if");
1894 1895
            break;
          }
1896
          if (!TypeCheckFallThru()) break;
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906
          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();
          break;
        }
        case kExprEnd: {
          if (!VALIDATE(!control_.empty())) {
            this->error("end does not match any if, try, or block");
1907 1908
            break;
          }
1909 1910 1911
          Control* c = &control_.back();
          if (!VALIDATE(!c->is_incomplete_try())) {
            this->error(this->pc_, "missing catch or catch-all in try");
1912 1913
            break;
          }
1914 1915 1916 1917 1918 1919
          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");
              break;
1920
            }
1921
          }
1922

1923
          if (!TypeCheckFallThru()) break;
1924 1925

          if (control_.size() == 1) {
1926 1927 1928 1929 1930 1931 1932 1933 1934
            // 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");
              break;
            }
            // The result of the block is the return value.
            TRACE_PART("\n" TRACE_INST_FORMAT, startrel(this->pc_),
                       "(implicit) return");
            DoReturn();
1935 1936
            control_.clear();
            break;
1937
          }
1938 1939 1940 1941 1942 1943 1944
          PopControl(c);
          break;
        }
        case kExprSelect: {
          auto cond = Pop(2, kWasmI32);
          auto fval = Pop();
          auto tval = Pop(0, fval.type);
1945
          ValueType type = tval.type == kWasmBottom ? fval.type : tval.type;
1946
          if (ValueTypes::IsSubType(type, kWasmAnyRef)) {
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962
            this->error(
                "select without type is only valid for value type inputs");
            break;
          }
          auto* result = Push(type);
          CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
          break;
        }
        case kExprSelectWithType: {
          CHECK_PROTOTYPE_OPCODE(anyref);
          SelectTypeImmediate<validate> imm(this, this->pc_);
          if (this->failed()) break;
          auto cond = Pop(2, kWasmI32);
          auto fval = Pop(1, imm.type);
          auto tval = Pop(0, imm.type);
          auto* result = Push(imm.type);
1963
          CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
1964
          len = 1 + imm.length;
1965 1966 1967 1968 1969 1970
          break;
        }
        case kExprBr: {
          BranchDepthImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(this->pc_, imm, control_.size())) break;
          Control* c = control_at(imm.depth);
1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
          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) {
            break;
1981
          }
1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
          len = 1 + imm.length;
          EndControl();
          break;
        }
        case kExprBrIf: {
          BranchDepthImmediate<validate> imm(this, this->pc_);
          auto cond = Pop(0, kWasmI32);
          if (this->failed()) break;
          if (!this->Validate(this->pc_, imm, control_.size())) break;
          Control* c = control_at(imm.depth);
1992 1993
          TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
          if (V8_LIKELY(check_result == kReachableBranch)) {
1994 1995
            CALL_INTERFACE(BrIf, cond, imm.depth);
            c->br_merge()->reached = true;
1996 1997
          } else if (check_result == kInvalidStack) {
            break;
1998
          }
1999 2000 2001 2002 2003 2004 2005 2006 2007
          len = 1 + imm.length;
          break;
        }
        case kExprBrTable: {
          BranchTableImmediate<validate> imm(this, this->pc_);
          BranchTableIterator<validate> iterator(this, imm);
          auto key = Pop(0, kWasmI32);
          if (this->failed()) break;
          if (!this->Validate(this->pc_, imm, control_.size())) break;
2008 2009 2010

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

2013 2014 2015 2016
          // 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;

2017
          while (iterator.has_next()) {
2018
            const uint32_t index = iterator.cur_index();
2019 2020
            const byte* pos = iterator.pc();
            uint32_t target = iterator.next();
2021
            if (!VALIDATE(ValidateBrTableTarget(target, pos, index))) break;
2022 2023 2024
            // Avoid redundant branch target checks.
            if (br_targets[target]) continue;
            br_targets[target] = true;
2025 2026 2027 2028 2029 2030 2031 2032

            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)) {
                break;
2033
              }
2034 2035
            }
          }
2036 2037 2038 2039

          if (!VALIDATE(TypeCheckBrTable(result_types))) break;

          DCHECK(this->ok());
2040 2041 2042 2043

          if (control_.back().reachable()) {
            CALL_INTERFACE(BrTable, imm, key);

2044 2045 2046
            for (int i = 0, e = control_depth(); i < e; ++i) {
              if (!br_targets[i]) continue;
              control_at(i)->br_merge()->reached = true;
2047
            }
2048
          }
2049 2050 2051 2052 2053 2054

          len = 1 + iterator.length();
          EndControl();
          break;
        }
        case kExprReturn: {
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067
          if (V8_LIKELY(control_.back().reachable())) {
            if (!VALIDATE(TypeCheckReturn())) break;
            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 = 0; i < num_returns; ++i) {
              Pop(i, this->sig_->GetReturn(i));
            }
          }

2068
          EndControl();
2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105
          break;
        }
        case kExprUnreachable: {
          CALL_INTERFACE_IF_REACHABLE(Unreachable);
          EndControl();
          break;
        }
        case kExprI32Const: {
          ImmI32Immediate<validate> imm(this, this->pc_);
          auto* value = Push(kWasmI32);
          CALL_INTERFACE_IF_REACHABLE(I32Const, value, imm.value);
          len = 1 + imm.length;
          break;
        }
        case kExprI64Const: {
          ImmI64Immediate<validate> imm(this, this->pc_);
          auto* value = Push(kWasmI64);
          CALL_INTERFACE_IF_REACHABLE(I64Const, value, imm.value);
          len = 1 + imm.length;
          break;
        }
        case kExprF32Const: {
          ImmF32Immediate<validate> imm(this, this->pc_);
          auto* value = Push(kWasmF32);
          CALL_INTERFACE_IF_REACHABLE(F32Const, value, imm.value);
          len = 1 + imm.length;
          break;
        }
        case kExprF64Const: {
          ImmF64Immediate<validate> imm(this, this->pc_);
          auto* value = Push(kWasmF64);
          CALL_INTERFACE_IF_REACHABLE(F64Const, value, imm.value);
          len = 1 + imm.length;
          break;
        }
        case kExprRefNull: {
          CHECK_PROTOTYPE_OPCODE(anyref);
2106
          auto* value = Push(kWasmNullRef);
2107 2108 2109 2110
          CALL_INTERFACE_IF_REACHABLE(RefNull, value);
          len = 1;
          break;
        }
2111 2112 2113 2114
        case kExprRefFunc: {
          CHECK_PROTOTYPE_OPCODE(anyref);
          FunctionIndexImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(this->pc_, imm)) break;
2115
          auto* value = Push(kWasmFuncRef);
2116 2117 2118 2119
          CALL_INTERFACE_IF_REACHABLE(RefFunc, imm.index, value);
          len = 1 + imm.length;
          break;
        }
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 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164
        case kExprGetLocal: {
          LocalIndexImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(this->pc_, imm)) break;
          auto* value = Push(imm.type);
          CALL_INTERFACE_IF_REACHABLE(GetLocal, value, imm);
          len = 1 + imm.length;
          break;
        }
        case kExprSetLocal: {
          LocalIndexImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(this->pc_, imm)) break;
          auto value = Pop(0, local_type_vec_[imm.index]);
          CALL_INTERFACE_IF_REACHABLE(SetLocal, value, imm);
          len = 1 + imm.length;
          break;
        }
        case kExprTeeLocal: {
          LocalIndexImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(this->pc_, imm)) break;
          auto value = Pop(0, local_type_vec_[imm.index]);
          auto* result = Push(value.type);
          CALL_INTERFACE_IF_REACHABLE(TeeLocal, value, result, imm);
          len = 1 + imm.length;
          break;
        }
        case kExprDrop: {
          auto value = Pop();
          CALL_INTERFACE_IF_REACHABLE(Drop, value);
          break;
        }
        case kExprGetGlobal: {
          GlobalIndexImmediate<validate> imm(this, this->pc_);
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
          auto* result = Push(imm.type);
          CALL_INTERFACE_IF_REACHABLE(GetGlobal, result, imm);
          break;
        }
        case kExprSetGlobal: {
          GlobalIndexImmediate<validate> imm(this, this->pc_);
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
          if (!VALIDATE(imm.global->mutability)) {
            this->errorf(this->pc_, "immutable global #%u cannot be assigned",
                         imm.index);
2165 2166
            break;
          }
2167 2168 2169 2170
          auto value = Pop(0, imm.type);
          CALL_INTERFACE_IF_REACHABLE(SetGlobal, value, imm);
          break;
        }
2171
        case kExprTableGet: {
2172 2173 2174 2175 2176 2177 2178
          CHECK_PROTOTYPE_OPCODE(anyref);
          TableIndexImmediate<validate> imm(this, this->pc_);
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
          DCHECK_NOT_NULL(this->module_);
          auto index = Pop(0, kWasmI32);
          auto* result = Push(this->module_->tables[imm.index].type);
2179
          CALL_INTERFACE_IF_REACHABLE(TableGet, index, result, imm);
2180 2181
          break;
        }
2182
        case kExprTableSet: {
2183 2184 2185 2186
          CHECK_PROTOTYPE_OPCODE(anyref);
          TableIndexImmediate<validate> imm(this, this->pc_);
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
2187
          auto value = Pop(1, this->module_->tables[imm.index].type);
2188
          auto index = Pop(0, kWasmI32);
2189
          CALL_INTERFACE_IF_REACHABLE(TableSet, index, value, imm);
2190 2191 2192
          break;
        }

2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 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
        case kExprI32LoadMem8S:
          len = 1 + DecodeLoadMem(LoadType::kI32Load8S);
          break;
        case kExprI32LoadMem8U:
          len = 1 + DecodeLoadMem(LoadType::kI32Load8U);
          break;
        case kExprI32LoadMem16S:
          len = 1 + DecodeLoadMem(LoadType::kI32Load16S);
          break;
        case kExprI32LoadMem16U:
          len = 1 + DecodeLoadMem(LoadType::kI32Load16U);
          break;
        case kExprI32LoadMem:
          len = 1 + DecodeLoadMem(LoadType::kI32Load);
          break;
        case kExprI64LoadMem8S:
          len = 1 + DecodeLoadMem(LoadType::kI64Load8S);
          break;
        case kExprI64LoadMem8U:
          len = 1 + DecodeLoadMem(LoadType::kI64Load8U);
          break;
        case kExprI64LoadMem16S:
          len = 1 + DecodeLoadMem(LoadType::kI64Load16S);
          break;
        case kExprI64LoadMem16U:
          len = 1 + DecodeLoadMem(LoadType::kI64Load16U);
          break;
        case kExprI64LoadMem32S:
          len = 1 + DecodeLoadMem(LoadType::kI64Load32S);
          break;
        case kExprI64LoadMem32U:
          len = 1 + DecodeLoadMem(LoadType::kI64Load32U);
          break;
        case kExprI64LoadMem:
          len = 1 + DecodeLoadMem(LoadType::kI64Load);
          break;
        case kExprF32LoadMem:
          len = 1 + DecodeLoadMem(LoadType::kF32Load);
          break;
        case kExprF64LoadMem:
          len = 1 + DecodeLoadMem(LoadType::kF64Load);
          break;
        case kExprI32StoreMem8:
          len = 1 + DecodeStoreMem(StoreType::kI32Store8);
          break;
        case kExprI32StoreMem16:
          len = 1 + DecodeStoreMem(StoreType::kI32Store16);
          break;
        case kExprI32StoreMem:
          len = 1 + DecodeStoreMem(StoreType::kI32Store);
          break;
        case kExprI64StoreMem8:
          len = 1 + DecodeStoreMem(StoreType::kI64Store8);
          break;
        case kExprI64StoreMem16:
          len = 1 + DecodeStoreMem(StoreType::kI64Store16);
          break;
        case kExprI64StoreMem32:
          len = 1 + DecodeStoreMem(StoreType::kI64Store32);
          break;
        case kExprI64StoreMem:
          len = 1 + DecodeStoreMem(StoreType::kI64Store);
          break;
        case kExprF32StoreMem:
          len = 1 + DecodeStoreMem(StoreType::kF32Store);
          break;
        case kExprF64StoreMem:
          len = 1 + DecodeStoreMem(StoreType::kF64Store);
          break;
        case kExprMemoryGrow: {
          if (!CheckHasMemory()) break;
          MemoryIndexImmediate<validate> imm(this, this->pc_);
          len = 1 + imm.length;
          DCHECK_NOT_NULL(this->module_);
          if (!VALIDATE(this->module_->origin == kWasmOrigin)) {
            this->error("grow_memory is not supported for asmjs modules");
2269 2270
            break;
          }
2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
          auto value = Pop(0, kWasmI32);
          auto* result = Push(kWasmI32);
          CALL_INTERFACE_IF_REACHABLE(MemoryGrow, value, result);
          break;
        }
        case kExprMemorySize: {
          if (!CheckHasMemory()) break;
          MemoryIndexImmediate<validate> imm(this, this->pc_);
          auto* result = Push(kWasmI32);
          len = 1 + imm.length;
          CALL_INTERFACE_IF_REACHABLE(CurrentMemoryPages, result);
          break;
        }
        case kExprCallFunction: {
          CallFunctionImmediate<validate> imm(this, this->pc_);
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
2288
          auto args = PopArgs(imm.sig);
2289
          auto* returns = PushReturns(imm.sig);
2290
          CALL_INTERFACE_IF_REACHABLE(CallDirect, imm, args.begin(), returns);
2291 2292 2293
          break;
        }
        case kExprCallIndirect: {
2294
          CallIndirectImmediate<validate> imm(this->enabled_, this, this->pc_);
2295 2296 2297
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
          auto index = Pop(0, kWasmI32);
2298
          auto args = PopArgs(imm.sig);
2299
          auto* returns = PushReturns(imm.sig);
2300
          CALL_INTERFACE_IF_REACHABLE(CallIndirect, index, imm, args.begin(),
2301 2302 2303
                                      returns);
          break;
        }
2304 2305 2306 2307 2308 2309
        case kExprReturnCall: {
          CHECK_PROTOTYPE_OPCODE(return_call);

          CallFunctionImmediate<validate> imm(this, this->pc_);
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
2310
          if (!this->CanReturnCall(imm.sig)) {
2311 2312 2313 2314
            OPCODE_ERROR(opcode, "tail call return types mismatch");
            break;
          }

2315
          auto args = PopArgs(imm.sig);
2316

2317
          CALL_INTERFACE_IF_REACHABLE(ReturnCall, imm, args.begin());
2318 2319 2320 2321 2322
          EndControl();
          break;
        }
        case kExprReturnCallIndirect: {
          CHECK_PROTOTYPE_OPCODE(return_call);
2323
          CallIndirectImmediate<validate> imm(this->enabled_, this, this->pc_);
2324 2325
          len = 1 + imm.length;
          if (!this->Validate(this->pc_, imm)) break;
2326
          if (!this->CanReturnCall(imm.sig)) {
2327 2328 2329 2330
            OPCODE_ERROR(opcode, "tail call return types mismatch");
            break;
          }
          auto index = Pop(0, kWasmI32);
2331
          auto args = PopArgs(imm.sig);
2332
          CALL_INTERFACE_IF_REACHABLE(ReturnCallIndirect, index, imm,
2333
                                      args.begin());
2334 2335 2336
          EndControl();
          break;
        }
2337 2338 2339 2340 2341 2342 2343
        case kNumericPrefix: {
          ++len;
          byte numeric_index =
              this->template read_u8<validate>(this->pc_ + 1, "numeric index");
          opcode = static_cast<WasmOpcode>(opcode << 8 | numeric_index);
          if (opcode < kExprMemoryInit) {
            CHECK_PROTOTYPE_OPCODE(sat_f2i_conversions);
2344 2345
          } else if (opcode == kExprTableGrow || opcode == kExprTableSize ||
                     opcode == kExprTableFill) {
2346
            CHECK_PROTOTYPE_OPCODE(anyref);
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
          } else {
            CHECK_PROTOTYPE_OPCODE(bulk_memory);
          }
          TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
                     WasmOpcodes::OpcodeName(opcode));
          len += DecodeNumericOpcode(opcode);
          break;
        }
        case kSimdPrefix: {
          CHECK_PROTOTYPE_OPCODE(simd);
          len++;
          byte simd_index =
              this->template read_u8<validate>(this->pc_ + 1, "simd index");
          opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
          TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
                     WasmOpcodes::OpcodeName(opcode));
          len += DecodeSimdOpcode(opcode);
          break;
        }
        case kAtomicPrefix: {
          CHECK_PROTOTYPE_OPCODE(threads);
          len++;
          byte atomic_index =
              this->template read_u8<validate>(this->pc_ + 1, "atomic index");
          opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_index);
          TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
                     WasmOpcodes::OpcodeName(opcode));
          len += DecodeAtomicOpcode(opcode);
          break;
        }
2377 2378 2379 2380
// Note that prototype opcodes are not handled in the fastpath
// above this switch, to avoid checking a feature flag.
#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \
  case kExpr##name: /* fallthrough */
2381
          FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE)
2382
#undef SIMPLE_PROTOTYPE_CASE
2383 2384 2385 2386
          BuildSimplePrototypeOperator(opcode);
          break;
        default: {
          // Deal with special asmjs opcodes.
2387
          if (this->module_ != nullptr && is_asmjs_module(this->module_)) {
2388 2389 2390
            FunctionSig* sig = WasmOpcodes::AsmjsSignature(opcode);
            if (sig) {
              BuildSimpleOperator(opcode, sig);
2391
            }
2392 2393 2394
          } else {
            this->error("Invalid opcode");
            return;
2395 2396 2397 2398 2399 2400
          }
        }
      }

#if DEBUG
      if (FLAG_trace_wasm_decoder) {
2401
        TRACE_PART(" ");
2402 2403
        for (Control& c : control_) {
          switch (c.kind) {
2404
            case kControlIf:
2405
              TRACE_PART("I");
2406 2407
              break;
            case kControlBlock:
2408
              TRACE_PART("B");
2409 2410
              break;
            case kControlLoop:
2411
              TRACE_PART("L");
2412 2413
              break;
            case kControlTry:
2414
              TRACE_PART("T");
2415 2416 2417 2418
              break;
            default:
              break;
          }
2419 2420 2421
          if (c.start_merge.arity) TRACE_PART("%u-", c.start_merge.arity);
          TRACE_PART("%u", c.end_merge.arity);
          if (!c.reachable()) TRACE_PART("%c", c.unreachable() ? '*' : '#');
2422
        }
2423
        TRACE_PART(" | ");
2424 2425 2426 2427 2428 2429
        for (size_t i = 0; i < stack_.size(); ++i) {
          auto& val = stack_[i];
          WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc);
          if (WasmOpcodes::IsPrefixOpcode(opcode)) {
            opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1));
          }
2430
          TRACE_PART(" %c@%d:%s", ValueTypes::ShortNameOf(val.type),
2431 2432
                     static_cast<int>(val.pc - this->start_),
                     WasmOpcodes::OpcodeName(opcode));
2433
          // If the decoder failed, don't try to decode the immediates, as this
2434 2435
          // can trigger a DCHECK failure.
          if (this->failed()) continue;
2436 2437
          switch (opcode) {
            case kExprI32Const: {
2438 2439
              ImmI32Immediate<Decoder::kNoValidate> imm(this, val.pc);
              TRACE_PART("[%d]", imm.value);
2440 2441
              break;
            }
2442 2443 2444
            case kExprGetLocal:
            case kExprSetLocal:
            case kExprTeeLocal: {
2445 2446
              LocalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
              TRACE_PART("[%u]", imm.index);
2447 2448
              break;
            }
2449 2450
            case kExprGetGlobal:
            case kExprSetGlobal: {
2451 2452
              GlobalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
              TRACE_PART("[%u]", imm.index);
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462
              break;
            }
            default:
              break;
          }
        }
      }
#endif
      this->pc_ += len;
    }  // end decode loop
2463 2464 2465
    if (!VALIDATE(this->pc_ == this->end_) && this->ok()) {
      this->error("Beyond end of code");
    }
2466 2467 2468 2469 2470
  }

  void EndControl() {
    DCHECK(!control_.empty());
    auto* current = &control_.back();
2471
    stack_.erase(stack_.begin() + current->stack_depth, stack_.end());
2472
    CALL_INTERFACE_IF_REACHABLE(EndControl, current);
2473
    current->reachability = kUnreachable;
2474 2475
  }

2476 2477 2478 2479 2480 2481 2482
  template<typename func>
  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) {
      merge->vals.array = zone_->NewArray<Value>(arity);
2483
      for (uint32_t i = 0; i < arity; i++) {
2484
        merge->vals.array[i] = get_val(i);
2485 2486 2487 2488
      }
    }
  }

2489 2490
  void SetBlockType(Control* c, BlockTypeImmediate<validate>& imm,
                    Value* args) {
2491
    const byte* pc = this->pc_;
2492
    InitMerge(&c->end_merge, imm.out_arity(), [pc, &imm](uint32_t i) {
2493
      return Value{pc, imm.out_type(i)};
2494
    });
2495
    InitMerge(&c->start_merge, imm.in_arity(),
2496
              [args](uint32_t i) { return args[i]; });
2497 2498
  }

2499 2500
  // Pops arguments as required by signature.
  V8_INLINE ArgVector PopArgs(FunctionSig* sig) {
2501
    int count = sig ? static_cast<int>(sig->parameter_count()) : 0;
2502
    ArgVector args(count);
2503
    for (int i = count - 1; i >= 0; --i) {
2504
      args[i] = Pop(i, sig->GetParam(i));
2505
    }
2506
    return args;
2507 2508 2509 2510 2511 2512 2513
  }

  ValueType GetReturnType(FunctionSig* sig) {
    DCHECK_GE(1, sig->return_count());
    return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn();
  }

2514
  Control* PushControl(ControlKind kind) {
2515 2516
    Reachability reachability =
        control_.empty() ? kReachable : control_.back().innerReachability();
2517 2518
    control_.emplace_back(kind, stack_size(), this->pc_, reachability);
    return &control_.back();
2519 2520 2521 2522
  }

  void PopControl(Control* c) {
    DCHECK_EQ(c, &control_.back());
2523
    CALL_INTERFACE_IF_PARENT_REACHABLE(PopControl, c);
2524 2525 2526 2527 2528 2529

    // 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();
2530
    control_.pop_back();
2531
    // If the parent block was reachable before, but the popped control does not
2532 2533
    // return to here, this block becomes "spec only reachable".
    if (!parent_reached && control_.back().reachable()) {
2534 2535
      control_.back().reachability = kSpecOnlyReachable;
    }
2536 2537
  }

2538
  int DecodeLoadMem(LoadType type, int prefix_len = 0) {
2539
    if (!CheckHasMemory()) return 0;
2540 2541
    MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
                                        type.size_log_2());
2542
    auto index = Pop(0, kWasmI32);
2543
    auto* result = Push(type.value_type());
2544 2545
    CALL_INTERFACE_IF_REACHABLE(LoadMem, type, imm, index, result);
    return imm.length;
2546 2547
  }

2548
  int DecodeStoreMem(StoreType store, int prefix_len = 0) {
2549
    if (!CheckHasMemory()) return 0;
2550 2551
    MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
                                        store.size_log_2());
2552
    auto value = Pop(1, store.value_type());
2553
    auto index = Pop(0, kWasmI32);
2554 2555
    CALL_INTERFACE_IF_REACHABLE(StoreMem, store, imm, index, value);
    return imm.length;
2556 2557
  }

2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641
  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) {
    auto* merge = control_at(target)->br_merge();
    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) {
    auto* merge = control_at(target)->br_merge();
    int br_arity = merge->arity;
    // First we check if the arities match.
    if (br_arity != static_cast<int>(result_types->size())) {
      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) {
      if (this->enabled_.anyref) {
        // The expected type is the biggest common sub type of all targets.
        (*result_types)[i] =
            ValueTypes::CommonSubType((*result_types)[i], (*merge)[i].type);
      } else {
        // All target must have the same signature.
        if ((*result_types)[i] != (*merge)[i].type) {
          this->errorf(pos,
                       "inconsistent type in br_table target %u (previous "
                       "was %s, this one is %s)",
                       index, ValueTypes::TypeName((*result_types)[i]),
                       ValueTypes::TypeName((*merge)[i].type));
          return false;
        }
      }
    }
    return true;
  }

  bool TypeCheckBrTable(const std::vector<ValueType>& result_types) {
    int br_arity = static_cast<int>(result_types.size());
    if (V8_LIKELY(control_.back().reachable())) {
      int available =
          static_cast<int>(stack_.size()) - control_.back().stack_depth;
      // There have to be enough values on the stack.
      if (available < br_arity) {
        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];
        if (!ValueTypes::IsSubType(val.type, result_types[i])) {
          this->errorf(this->pc_,
                       "type error in merge[%u] (expected %s, got %s)", i,
                       ValueTypes::TypeName(result_types[i]),
                       ValueTypes::TypeName(val.type));
          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();
  }

2642
  uint32_t SimdExtractLane(WasmOpcode opcode, ValueType type) {
2643 2644
    SimdLaneImmediate<validate> imm(this, this->pc_);
    if (this->Validate(this->pc_, opcode, imm)) {
2645
      Value inputs[] = {Pop(0, kWasmS128)};
2646
      auto* result = Push(type);
2647 2648
      CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
                                  result);
2649
    }
2650
    return imm.length;
2651 2652
  }

2653
  uint32_t SimdReplaceLane(WasmOpcode opcode, ValueType type) {
2654 2655
    SimdLaneImmediate<validate> imm(this, this->pc_);
    if (this->Validate(this->pc_, opcode, imm)) {
2656 2657
      Value inputs[2] = {UnreachableValue(this->pc_),
                         UnreachableValue(this->pc_)};
2658
      inputs[1] = Pop(1, type);
2659 2660
      inputs[0] = Pop(0, kWasmS128);
      auto* result = Push(kWasmS128);
2661 2662
      CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
                                  result);
2663
    }
2664
    return imm.length;
2665 2666
  }

2667
  uint32_t Simd8x16ShuffleOp() {
2668 2669
    Simd8x16ShuffleImmediate<validate> imm(this, this->pc_);
    if (this->Validate(this->pc_, imm)) {
2670 2671 2672
      auto input1 = Pop(1, kWasmS128);
      auto input0 = Pop(0, kWasmS128);
      auto* result = Push(kWasmS128);
2673
      CALL_INTERFACE_IF_REACHABLE(Simd8x16ShuffleOp, imm, input0, input1,
2674
                                  result);
2675 2676 2677 2678
    }
    return 16;
  }

2679 2680
  uint32_t DecodeSimdOpcode(WasmOpcode opcode) {
    uint32_t len = 0;
2681
    switch (opcode) {
2682 2683 2684 2685
      case kExprF64x2ExtractLane: {
        len = SimdExtractLane(opcode, kWasmF64);
        break;
      }
2686
      case kExprF32x4ExtractLane: {
2687
        len = SimdExtractLane(opcode, kWasmF32);
2688 2689
        break;
      }
2690 2691 2692 2693
      case kExprI64x2ExtractLane: {
        len = SimdExtractLane(opcode, kWasmI64);
        break;
      }
2694 2695 2696
      case kExprI32x4ExtractLane:
      case kExprI16x8ExtractLane:
      case kExprI8x16ExtractLane: {
2697
        len = SimdExtractLane(opcode, kWasmI32);
2698 2699
        break;
      }
2700 2701 2702 2703
      case kExprF64x2ReplaceLane: {
        len = SimdReplaceLane(opcode, kWasmF64);
        break;
      }
2704
      case kExprF32x4ReplaceLane: {
2705
        len = SimdReplaceLane(opcode, kWasmF32);
2706 2707
        break;
      }
2708 2709 2710 2711
      case kExprI64x2ReplaceLane: {
        len = SimdReplaceLane(opcode, kWasmI64);
        break;
      }
2712 2713 2714
      case kExprI32x4ReplaceLane:
      case kExprI16x8ReplaceLane:
      case kExprI8x16ReplaceLane: {
2715
        len = SimdReplaceLane(opcode, kWasmI32);
2716 2717 2718 2719 2720 2721 2722
        break;
      }
      case kExprS8x16Shuffle: {
        len = Simd8x16ShuffleOp();
        break;
      }
      case kExprS128LoadMem:
2723
        len = DecodeLoadMem(LoadType::kS128Load, 1);
2724 2725
        break;
      case kExprS128StoreMem:
2726
        len = DecodeStoreMem(StoreType::kS128Store, 1);
2727 2728 2729
        break;
      default: {
        FunctionSig* sig = WasmOpcodes::Signature(opcode);
2730
        if (!VALIDATE(sig != nullptr)) {
2731 2732 2733
          this->error("invalid simd opcode");
          break;
        }
2734
        auto args = PopArgs(sig);
2735
        auto* results =
2736
            sig->return_count() == 0 ? nullptr : Push(GetReturnType(sig));
2737
        CALL_INTERFACE_IF_REACHABLE(SimdOp, opcode, VectorOf(args), results);
2738 2739 2740 2741 2742
      }
    }
    return len;
  }

2743 2744
  uint32_t DecodeAtomicOpcode(WasmOpcode opcode) {
    uint32_t len = 0;
2745
    ValueType ret_type;
2746
    FunctionSig* sig = WasmOpcodes::Signature(opcode);
2747 2748 2749 2750 2751 2752
    if (!VALIDATE(sig != nullptr)) {
      this->error("invalid atomic opcode");
      return 0;
    }
    MachineType memtype;
    switch (opcode) {
2753 2754 2755 2756 2757
#define CASE_ATOMIC_STORE_OP(Name, Type) \
  case kExpr##Name: {                    \
    memtype = MachineType::Type();       \
    ret_type = kWasmStmt;                \
    break;                               \
2758
  }
2759
      ATOMIC_STORE_OP_LIST(CASE_ATOMIC_STORE_OP)
2760 2761 2762 2763 2764 2765 2766
#undef CASE_ATOMIC_OP
#define CASE_ATOMIC_OP(Name, Type) \
  case kExpr##Name: {              \
    memtype = MachineType::Type(); \
    ret_type = GetReturnType(sig); \
    break;                         \
  }
2767
      ATOMIC_OP_LIST(CASE_ATOMIC_OP)
2768
#undef CASE_ATOMIC_OP
2769 2770 2771 2772
      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");
2773
          return 0;
2774 2775 2776
        }
        CALL_INTERFACE_IF_REACHABLE(AtomicFence);
        return 1;
2777
      }
2778 2779 2780
      default:
        this->error("invalid atomic opcode");
        return 0;
2781
    }
2782 2783 2784 2785 2786 2787 2788
    if (!CheckHasSharedMemory()) return 0;
    MemoryAccessImmediate<validate> imm(
        this, this->pc_ + 1, ElementSizeLog2Of(memtype.representation()));
    len += imm.length;
    auto args = PopArgs(sig);
    auto result = ret_type == kWasmStmt ? nullptr : Push(GetReturnType(sig));
    CALL_INTERFACE_IF_REACHABLE(AtomicOp, opcode, VectorOf(args), imm, result);
2789 2790 2791
    return len;
  }

2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
  unsigned DecodeNumericOpcode(WasmOpcode opcode) {
    unsigned len = 0;
    FunctionSig* sig = WasmOpcodes::Signature(opcode);
    if (sig != nullptr) {
      switch (opcode) {
        case kExprI32SConvertSatF32:
        case kExprI32UConvertSatF32:
        case kExprI32SConvertSatF64:
        case kExprI32UConvertSatF64:
        case kExprI64SConvertSatF32:
        case kExprI64UConvertSatF32:
        case kExprI64SConvertSatF64:
        case kExprI64UConvertSatF64:
          BuildSimpleOperator(opcode, sig);
          break;
        case kExprMemoryInit: {
          MemoryInitImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(imm)) break;
          len += imm.length;
2811 2812 2813 2814
          auto size = Pop(2, sig->GetParam(2));
          auto src = Pop(1, sig->GetParam(1));
          auto dst = Pop(0, sig->GetParam(0));
          CALL_INTERFACE_IF_REACHABLE(MemoryInit, imm, dst, src, size);
2815 2816
          break;
        }
2817 2818
        case kExprDataDrop: {
          DataDropImmediate<validate> imm(this, this->pc_);
2819 2820
          if (!this->Validate(imm)) break;
          len += imm.length;
2821
          CALL_INTERFACE_IF_REACHABLE(DataDrop, imm);
2822 2823 2824
          break;
        }
        case kExprMemoryCopy: {
2825
          MemoryCopyImmediate<validate> imm(this, this->pc_);
2826 2827
          if (!this->Validate(imm)) break;
          len += imm.length;
2828 2829 2830 2831
          auto size = Pop(2, sig->GetParam(2));
          auto src = Pop(1, sig->GetParam(1));
          auto dst = Pop(0, sig->GetParam(0));
          CALL_INTERFACE_IF_REACHABLE(MemoryCopy, imm, dst, src, size);
2832 2833 2834 2835
          break;
        }
        case kExprMemoryFill: {
          MemoryIndexImmediate<validate> imm(this, this->pc_ + 1);
2836
          if (!this->Validate(this->pc_ + 1, imm)) break;
2837
          len += imm.length;
2838 2839 2840 2841
          auto size = Pop(2, sig->GetParam(2));
          auto value = Pop(1, sig->GetParam(1));
          auto dst = Pop(0, sig->GetParam(0));
          CALL_INTERFACE_IF_REACHABLE(MemoryFill, imm, dst, value, size);
2842 2843 2844 2845 2846 2847
          break;
        }
        case kExprTableInit: {
          TableInitImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(imm)) break;
          len += imm.length;
2848 2849
          auto args = PopArgs(sig);
          CALL_INTERFACE_IF_REACHABLE(TableInit, imm, VectorOf(args));
2850 2851
          break;
        }
2852 2853
        case kExprElemDrop: {
          ElemDropImmediate<validate> imm(this, this->pc_);
2854 2855
          if (!this->Validate(imm)) break;
          len += imm.length;
2856
          CALL_INTERFACE_IF_REACHABLE(ElemDrop, imm);
2857 2858 2859
          break;
        }
        case kExprTableCopy: {
2860 2861
          TableCopyImmediate<validate> imm(this, this->pc_);
          if (!this->Validate(imm)) break;
2862
          len += imm.length;
2863 2864
          auto args = PopArgs(sig);
          CALL_INTERFACE_IF_REACHABLE(TableCopy, imm, VectorOf(args));
2865 2866
          break;
        }
2867 2868 2869 2870 2871 2872 2873 2874 2875 2876
        case kExprTableGrow: {
          TableIndexImmediate<validate> imm(this, this->pc_ + 1);
          if (!this->Validate(this->pc_, imm)) break;
          len += imm.length;
          auto delta = Pop(1, sig->GetParam(1));
          auto value = Pop(0, this->module_->tables[imm.index].type);
          auto* result = Push(kWasmI32);
          CALL_INTERFACE_IF_REACHABLE(TableGrow, imm, value, delta, result);
          break;
        }
2877 2878 2879 2880 2881 2882 2883 2884
        case kExprTableSize: {
          TableIndexImmediate<validate> imm(this, this->pc_ + 1);
          if (!this->Validate(this->pc_, imm)) break;
          len += imm.length;
          auto* result = Push(kWasmI32);
          CALL_INTERFACE_IF_REACHABLE(TableSize, imm, result);
          break;
        }
2885 2886 2887 2888 2889 2890 2891 2892 2893 2894
        case kExprTableFill: {
          TableIndexImmediate<validate> imm(this, this->pc_ + 1);
          if (!this->Validate(this->pc_, imm)) break;
          len += imm.length;
          auto count = Pop(2, sig->GetParam(2));
          auto value = Pop(1, this->module_->tables[imm.index].type);
          auto start = Pop(0, sig->GetParam(0));
          CALL_INTERFACE_IF_REACHABLE(TableFill, imm, start, value, count);
          break;
        }
2895 2896 2897 2898 2899 2900 2901 2902 2903 2904
        default:
          this->error("invalid numeric opcode");
          break;
      }
    } else {
      this->error("invalid numeric opcode");
    }
    return len;
  }

2905
  void DoReturn() {
2906
    size_t return_count = this->sig_->return_count();
2907
    DCHECK_GE(stack_.size(), return_count);
2908 2909 2910 2911
    Vector<Value> return_values =
        return_count == 0
            ? Vector<Value>{}
            : Vector<Value>{&*(stack_.end() - return_count), return_count};
2912

2913
    CALL_INTERFACE_IF_REACHABLE(DoReturn, return_values);
2914 2915 2916
  }

  inline Value* Push(ValueType type) {
2917
    DCHECK_NE(kWasmStmt, type);
2918
    stack_.emplace_back(this->pc_, type);
2919 2920 2921
    return &stack_.back();
  }

2922
  void PushMergeValues(Control* c, Merge<Value>* merge) {
2923
    DCHECK_EQ(c, &control_.back());
2924
    DCHECK(merge == &c->start_merge || merge == &c->end_merge);
2925
    stack_.erase(stack_.begin() + c->stack_depth, stack_.end());
2926 2927
    if (merge->arity == 1) {
      stack_.push_back(merge->vals.first);
2928
    } else {
2929
      for (uint32_t i = 0; i < merge->arity; i++) {
2930
        stack_.push_back(merge->vals.array[i]);
2931 2932
      }
    }
2933
    DCHECK_EQ(c->stack_depth + merge->arity, stack_.size());
2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945
  }

  Value* PushReturns(FunctionSig* sig) {
    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;
  }

2946
  V8_INLINE Value Pop(int index, ValueType expected) {
2947
    auto val = Pop();
2948
    if (!VALIDATE(ValueTypes::IsSubType(val.type, expected) ||
2949
                  val.type == kWasmBottom || expected == kWasmBottom)) {
2950 2951
      this->errorf(val.pc, "%s[%d] expected type %s, found %s of type %s",
                   SafeOpcodeNameAt(this->pc_), index,
2952 2953
                   ValueTypes::TypeName(expected), SafeOpcodeNameAt(val.pc),
                   ValueTypes::TypeName(val.type));
2954 2955 2956 2957
    }
    return val;
  }

2958
  V8_INLINE Value Pop() {
2959
    DCHECK(!control_.empty());
2960
    uint32_t limit = control_.back().stack_depth;
2961 2962
    if (stack_.size() <= limit) {
      // Popping past the current control start in reachable code.
2963
      if (!VALIDATE(control_.back().unreachable())) {
2964 2965 2966
        this->errorf(this->pc_, "%s found empty stack",
                     SafeOpcodeNameAt(this->pc_));
      }
2967
      return UnreachableValue(this->pc_);
2968 2969 2970 2971 2972 2973
    }
    auto val = stack_.back();
    stack_.pop_back();
    return val;
  }

2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988
  // 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;
    for (int i = 0; i < arity; ++i) Pop(index_offset + i, merge[i].type);
    // Push values of the correct type back on the stack.
    for (int i = arity - 1; i >= 0; --i) Push(merge[i].type);
    return this->ok();
  }

2989 2990 2991 2992
  int startrel(const byte* ptr) { return static_cast<int>(ptr - this->start_); }

  void FallThruTo(Control* c) {
    DCHECK_EQ(c, &control_.back());
2993
    if (!TypeCheckFallThru()) return;
2994
    if (!c->reachable()) return;
2995

2996 2997
    if (!c->is_loop()) CALL_INTERFACE(FallThruTo, c);
    c->end_merge.reached = true;
2998 2999
  }

3000
  bool TypeCheckMergeValues(Control* c, Merge<Value>* merge) {
3001 3002 3003
    // 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");
3004 3005
    DCHECK(merge == &c->start_merge || merge == &c->end_merge);
    DCHECK_GE(stack_.size(), c->stack_depth + merge->arity);
3006 3007 3008
    // 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);
3009 3010
    // Typecheck the topmost {merge->arity} values on the stack.
    for (uint32_t i = 0; i < merge->arity; ++i) {
3011 3012
      Value& val = stack_values[i];
      Value& old = (*merge)[i];
3013
      if (!ValueTypes::IsSubType(val.type, old.type)) {
3014 3015 3016 3017
        this->errorf(this->pc_, "type error in merge[%u] (expected %s, got %s)",
                     i, ValueTypes::TypeName(old.type),
                     ValueTypes::TypeName(val.type));
        return false;
3018 3019 3020 3021 3022 3023
      }
    }

    return true;
  }

3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053
  bool TypeCheckFallThru() {
    Control& c = control_.back();
    if (V8_LIKELY(c.reachable())) {
      // We only do type-checking here. This is only needed during validation.
      if (!validate) return true;

      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.
      if (actual != expected) {
        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.
    if (available > arity) {
3054 3055 3056
      this->errorf(
          this->pc_,
          "expected %u elements on the stack for fallthru to @%d, found %u",
3057
          arity, startrel(c.pc), available);
3058 3059
      return false;
    }
3060 3061 3062
    // Pop all values from the stack for type checking of existing stack
    // values.
    return TypeCheckUnreachableMerge(merge, false);
3063 3064
  }

3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091
  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;
      if (expected > actual) {
        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;
3092
    }
3093 3094 3095 3096

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

3099
  bool TypeCheckReturn() {
3100 3101 3102 3103
    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;

3104
    // Returns must have at least the number of values expected; can have more.
3105 3106 3107
    int num_available =
        static_cast<int>(stack_.size()) - control_.back().stack_depth;
    if (num_available < num_returns) {
3108 3109
      this->errorf(this->pc_,
                   "expected %u elements on the stack for return, found %u",
3110
                   num_returns, num_available);
3111 3112 3113 3114
      return false;
    }

    // Typecheck the topmost {num_returns} values on the stack.
3115
    // This line requires num_returns > 0.
3116
    Value* stack_values = &*(stack_.end() - num_returns);
3117
    for (int i = 0; i < num_returns; ++i) {
3118 3119
      auto& val = stack_values[i];
      ValueType expected_type = this->sig_->GetReturn(i);
3120
      if (!ValueTypes::IsSubType(val.type, expected_type)) {
3121 3122 3123 3124 3125 3126
        this->errorf(this->pc_,
                     "type error in return[%u] (expected %s, got %s)", i,
                     ValueTypes::TypeName(expected_type),
                     ValueTypes::TypeName(val.type));
        return false;
      }
3127 3128
    }
    return true;
3129 3130
  }

3131
  void onFirstError() override {
3132
    this->end_ = this->pc_;  // Terminate decoding loop.
3133
    TRACE(" !%s\n", this->error_.message().c_str());
3134
    CALL_INTERFACE(OnFirstError);
3135 3136
  }

3137
  void BuildSimplePrototypeOperator(WasmOpcode opcode) {
3138 3139 3140
    if (WasmOpcodes::IsSignExtensionOpcode(opcode)) {
      RET_ON_PROTOTYPE_OPCODE(se);
    }
3141 3142 3143
    if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
      RET_ON_PROTOTYPE_OPCODE(anyref);
    }
3144 3145 3146
    FunctionSig* sig = WasmOpcodes::Signature(opcode);
    BuildSimpleOperator(opcode, sig);
  }
3147

3148
  void BuildSimpleOperator(WasmOpcode opcode, FunctionSig* sig) {
3149 3150 3151 3152 3153
    switch (sig->parameter_count()) {
      case 1: {
        auto val = Pop(0, sig->GetParam(0));
        auto* ret =
            sig->return_count() == 0 ? nullptr : Push(sig->GetReturn(0));
3154
        CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, val, ret);
3155 3156 3157 3158 3159 3160 3161
        break;
      }
      case 2: {
        auto rval = Pop(1, sig->GetParam(1));
        auto lval = Pop(0, sig->GetParam(0));
        auto* ret =
            sig->return_count() == 0 ? nullptr : Push(sig->GetReturn(0));
3162
        CALL_INTERFACE_IF_REACHABLE(BinOp, opcode, lval, rval, ret);
3163 3164 3165 3166 3167 3168
        break;
      }
      default:
        UNREACHABLE();
    }
  }
3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190

  void BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
                           ValueType arg_type) {
    auto val = Pop(0, arg_type);
    auto* ret = return_type == kWasmStmt ? nullptr : Push(return_type);
    CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, val, ret);
  }

  void BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
                           ValueType lhs_type, ValueType rhs_type) {
    auto rval = Pop(1, rhs_type);
    auto lval = Pop(0, lhs_type);
    auto* ret = return_type == kWasmStmt ? nullptr : Push(return_type);
    CALL_INTERFACE_IF_REACHABLE(BinOp, opcode, lval, rval, ret);
  }

#define DEFINE_SIMPLE_SIG_OPERATOR(sig, ...)          \
  void BuildSimpleOperator_##sig(WasmOpcode opcode) { \
    BuildSimpleOperator(opcode, __VA_ARGS__);         \
  }
  FOREACH_SIGNATURE(DEFINE_SIMPLE_SIG_OPERATOR)
#undef DEFINE_SIMPLE_SIG_OPERATOR
3191 3192
};

3193 3194 3195 3196
#undef CALL_INTERFACE
#undef CALL_INTERFACE_IF_REACHABLE
#undef CALL_INTERFACE_IF_PARENT_REACHABLE

3197
class EmptyInterface {
3198
 public:
3199
  static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
3200 3201
  using Value = ValueBase;
  using Control = ControlBase<Value>;
3202
  using FullDecoder = WasmFullDecoder<validate, EmptyInterface>;
3203 3204

#define DEFINE_EMPTY_CALLBACK(name, ...) \
3205
  void name(FullDecoder* decoder, ##__VA_ARGS__) {}
3206 3207 3208 3209
  INTERFACE_FUNCTIONS(DEFINE_EMPTY_CALLBACK)
#undef DEFINE_EMPTY_CALLBACK
};

3210
#undef TRACE
3211
#undef TRACE_INST_FORMAT
3212 3213
#undef VALIDATE
#undef CHECK_PROTOTYPE_OPCODE
3214
#undef OPCODE_ERROR
3215

3216 3217 3218 3219 3220
}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_