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