Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/validator/formchecker.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "validator/formchecker.h"
5
6
#include "common/errinfo.h"
7
8
#include <array>
9
#include <cstdint>
10
#include <tuple>
11
12
using namespace std::literals;
13
14
namespace WasmEdge {
15
namespace Validator {
16
17
namespace {
18
19
// Helper function for printing an error log for an index out of range.
20
auto logOutOfRange(ErrCode Code, ErrInfo::IndexCategory Cate, uint32_t Idx,
21
1.18k
                   uint32_t Bound) {
22
1.18k
  spdlog::error(Code);
23
1.18k
  spdlog::error(ErrInfo::InfoForbidIndex(Cate, Idx, Bound));
24
1.18k
  return Unexpect(Code);
25
1.18k
}
26
27
// Helper function for extracting address type to TypeCode.
28
9.53k
TypeCode convAddrTypeToTypeCode(const AddressType AT) noexcept {
29
9.53k
  switch (AT) {
30
7.51k
  case AddressType::I32:
31
7.51k
    return TypeCode::I32;
32
2.01k
  case AddressType::I64:
33
2.01k
    return TypeCode::I64;
34
0
  default:
35
0
    assumingUnreachable();
36
9.53k
  }
37
9.53k
};
38
39
// Helper function for packing TypeCode to address type.
40
61.7k
AddressType convTypeCodeToAddrType(const TypeCode TC) noexcept {
41
61.7k
  switch (TC) {
42
61.4k
  case TypeCode::I32:
43
61.4k
    return AddressType::I32;
44
286
  case TypeCode::I64:
45
286
    return AddressType::I64;
46
0
  default:
47
0
    assumingUnreachable();
48
61.7k
  }
49
61.7k
};
50
51
} // namespace
52
53
47.9k
void FormChecker::reset(bool CleanGlobal) {
54
47.9k
  ValStack.clear();
55
47.9k
  CtrlStack.clear();
56
47.9k
  Locals.clear();
57
47.9k
  Returns.clear();
58
59
47.9k
  if (CleanGlobal) {
60
11.5k
    Types.clear();
61
11.5k
    Funcs.clear();
62
11.5k
    Tables.clear();
63
11.5k
    Mems.clear();
64
11.5k
    Globals.clear();
65
11.5k
    Datas.clear();
66
11.5k
    Elems.clear();
67
11.5k
    Refs.clear();
68
11.5k
    Tags.clear();
69
11.5k
    NumImportFuncs = 0;
70
11.5k
    NumImportGlobals = 0;
71
11.5k
  }
72
47.9k
}
73
74
Expect<void> FormChecker::validate(AST::InstrView Instrs,
75
36.3k
                                   Span<const ValType> RetVals) {
76
83.1k
  for (const ValType &Val : RetVals) {
77
83.1k
    Returns.push_back(Val);
78
83.1k
  }
79
36.3k
  return checkExpr(Instrs);
80
36.3k
}
81
82
338M
Expect<void> FormChecker::validate(const ValType &VT) const noexcept {
83
  // The value type should be validated for the type index case.
84
338M
  if (VT.isRefType() && VT.getHeapTypeCode() == TypeCode::TypeIndex) {
85
293M
    if (VT.getTypeIndex() >= Types.size()) {
86
109
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
87
109
      spdlog::error(ErrInfo::InfoForbidIndex(
88
109
          ErrInfo::IndexCategory::FunctionType, VT.getTypeIndex(),
89
109
          static_cast<uint32_t>(Types.size())));
90
109
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
91
109
    }
92
293M
  }
93
338M
  return {};
94
338M
}
95
96
64.4k
void FormChecker::addType(const AST::SubType &Type) { Types.push_back(&Type); }
97
98
41.5k
void FormChecker::addFunc(const uint32_t TypeIdx, const bool IsImport) {
99
41.5k
  if (Types.size() > TypeIdx) {
100
41.5k
    Funcs.emplace_back(TypeIdx);
101
41.5k
  }
102
41.5k
  if (IsImport) {
103
1.36k
    NumImportFuncs++;
104
1.36k
  }
105
41.5k
}
106
107
6.68k
void FormChecker::addTable(const AST::TableType &Tab) {
108
6.68k
  Tables.emplace_back(convAddrTypeToTypeCode(Tab.getLimit().getAddrType()),
109
6.68k
                      Tab.getRefType());
110
6.68k
}
111
112
2.84k
void FormChecker::addMemory(const AST::MemoryType &Mem) {
113
2.84k
  Mems.push_back(convAddrTypeToTypeCode(Mem.getLimit().getAddrType()));
114
2.84k
}
115
116
4.74k
void FormChecker::addGlobal(const AST::GlobalType &Glob, const bool IsImport) {
117
  // The global type is confirmed in the loading phase.
118
4.74k
  Globals.emplace_back(Glob.getValType(), Glob.getValMut());
119
4.74k
  if (IsImport) {
120
1.27k
    NumImportGlobals++;
121
1.27k
  }
122
4.74k
}
123
124
4.62k
void FormChecker::addData(const AST::DataSegment &) {
125
4.62k
  Datas.emplace_back(static_cast<uint32_t>(Datas.size()));
126
4.62k
}
127
128
3.22k
void FormChecker::addElem(const AST::ElementSegment &Elem) {
129
3.22k
  Elems.emplace_back(Elem.getRefType());
130
3.22k
}
131
132
15.1k
void FormChecker::addRef(const uint32_t FuncIdx) { Refs.emplace(FuncIdx); }
133
134
338M
void FormChecker::addLocal(const ValType &V, bool Initialized) {
135
338M
  Locals.emplace_back(V);
136
338M
  if (Initialized || V.isDefaultable()) {
137
336M
    LocalInits.push_back(static_cast<uint32_t>(Locals.size() - 1));
138
336M
    Locals.back().IsInit = true;
139
336M
  }
140
338M
}
141
142
5.26k
void FormChecker::addTag(const uint32_t TypeIdx) { Tags.push_back(TypeIdx); }
143
144
3.18k
ValType FormChecker::VTypeToAST(const VType &V) {
145
3.18k
  if (!V) {
146
1
    return TypeCode::I32;
147
1
  }
148
3.18k
  return *V;
149
3.18k
}
150
151
36.3k
Expect<void> FormChecker::checkExpr(AST::InstrView Instrs) {
152
36.3k
  if (Instrs.size() > 0) {
153
    // Push ctrl frame ([] -> [Returns])
154
36.3k
    pushCtrl({}, Returns, &*Instrs.rbegin());
155
36.3k
    return checkInstrs(Instrs);
156
36.3k
  }
157
0
  return {};
158
36.3k
}
159
160
36.3k
Expect<void> FormChecker::checkInstrs(AST::InstrView Instrs) {
161
  // Validate instructions
162
2.50M
  for (auto &Instr : Instrs) {
163
2.50M
    EXPECTED_TRY(checkInstr(Instr).map_error([&Instr](auto E) {
164
2.50M
      spdlog::error(
165
2.50M
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
166
2.50M
      return E;
167
2.50M
    }));
168
2.50M
  }
169
32.6k
  return {};
170
36.3k
}
171
172
2.50M
Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) {
173
  // Note: The instructions and their immediates have passed proposal
174
  // configuration checking in the loader phase.
175
176
  // Helper lambda for checking whether the table index is valid.
177
2.50M
  auto checkTableIdx = [this](const uint32_t Idx) -> Expect<void> {
178
6.11k
    if (unlikely(Idx >= Tables.size())) {
179
103
      return logOutOfRange(ErrCode::Value::InvalidTableIdx,
180
103
                           ErrInfo::IndexCategory::Table, Idx,
181
103
                           static_cast<uint32_t>(Tables.size()));
182
103
    }
183
6.01k
    return {};
184
6.11k
  };
185
186
  // Helper lambda for checking whether the memory index is valid.
187
2.50M
  auto checkMemIdx = [this](const uint32_t Idx) -> Expect<void> {
188
78.3k
    if (unlikely(Idx >= Mems.size())) {
189
484
      return logOutOfRange(ErrCode::Value::InvalidMemoryIdx,
190
484
                           ErrInfo::IndexCategory::Memory, Idx,
191
484
                           static_cast<uint32_t>(Mems.size()));
192
484
    }
193
77.8k
    return {};
194
78.3k
  };
195
196
  // Helper lambda for checking whether the data index is valid.
197
2.50M
  auto checkDataIdx = [this](const uint32_t Idx) -> Expect<void> {
198
1.21k
    if (unlikely(Idx >= Datas.size())) {
199
18
      return logOutOfRange(ErrCode::Value::InvalidDataIdx,
200
18
                           ErrInfo::IndexCategory::Data, Idx,
201
18
                           static_cast<uint32_t>(Datas.size()));
202
18
    }
203
1.19k
    return {};
204
1.21k
  };
205
206
  // Helper lambda for checking whether the element index is valid.
207
2.50M
  auto checkElemIdx = [this](const uint32_t Idx) -> Expect<void> {
208
4.79k
    if (unlikely(Idx >= Elems.size())) {
209
21
      return logOutOfRange(ErrCode::Value::InvalidElemIdx,
210
21
                           ErrInfo::IndexCategory::Element, Idx,
211
21
                           static_cast<uint32_t>(Elems.size()));
212
21
    }
213
4.77k
    return {};
214
4.79k
  };
215
216
  // Helper lambda for checking whether the tag index is valid.
217
2.50M
  auto checkTagIdx = [this](const uint32_t Idx) -> Expect<void> {
218
2.48k
    if (unlikely(Idx >= Tags.size())) {
219
53
      return logOutOfRange(ErrCode::Value::InvalidTagIdx,
220
53
                           ErrInfo::IndexCategory::Tag, Idx,
221
53
                           static_cast<uint32_t>(Tags.size()));
222
53
    }
223
2.42k
    return {};
224
2.48k
  };
225
226
  // Helper lambda for checking the defined type.
227
2.50M
  auto checkDefinedType =
228
2.50M
      [this](uint32_t TIdx, TypeCode TC) -> Expect<const AST::CompositeType *> {
229
13.3k
    if (TIdx >= Types.size()) {
230
123
      return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx,
231
123
                           ErrInfo::IndexCategory::FunctionType, TIdx,
232
123
                           static_cast<uint32_t>(Types.size()));
233
123
    }
234
13.1k
    const auto &CType = Types[TIdx]->getCompositeType();
235
13.1k
    if (CType.getContentTypeCode() == TC) {
236
13.1k
      return &CType;
237
13.1k
    } else {
238
33
      spdlog::error(ErrCode::Value::TypeCheckFailed);
239
33
      return Unexpect(ErrCode::Value::TypeCheckFailed);
240
33
    }
241
13.1k
  };
242
243
  // Helper lambda for checking and resolving the block type.
244
2.50M
  auto checkBlockType = [this, checkDefinedType](std::vector<ValType> &Buffer,
245
2.50M
                                                 const BlockType &BType)
246
2.50M
      -> Expect<std::pair<Span<const ValType>, Span<const ValType>>> {
247
27.8k
    using ReturnType = std::pair<Span<const ValType>, Span<const ValType>>;
248
27.8k
    if (BType.isEmpty()) {
249
      // Empty case. t2* = none
250
10.5k
      return ReturnType{{}, {}};
251
17.2k
    } else if (BType.isValType()) {
252
      // ValType case. t2* = valtype
253
10.4k
      EXPECTED_TRY(validate(BType.getValType()));
254
10.4k
      Buffer[0] = BType.getValType();
255
10.4k
      return ReturnType{{}, Buffer};
256
10.4k
    } else {
257
      // Type index case. t2* = functype.returns.
258
6.83k
      EXPECTED_TRY(auto CompType,
259
6.81k
                   checkDefinedType(BType.getTypeIndex(), TypeCode::Func));
260
6.81k
      const auto &FType = CompType->getFuncType();
261
6.81k
      return ReturnType{FType.getParamTypes(), FType.getReturnTypes()};
262
6.83k
    }
263
27.8k
  };
264
265
  // Helper lambda for checking control stack depth and return index.
266
2.50M
  auto checkCtrlStackDepth = [this](uint32_t N) -> Expect<uint32_t> {
267
    // Check the control stack for at least N + 1 frames.
268
56.0k
    if (N >= CtrlStack.size()) {
269
      // Branch out of the stack.
270
144
      return logOutOfRange(ErrCode::Value::InvalidLabelIdx,
271
144
                           ErrInfo::IndexCategory::Label, N,
272
144
                           static_cast<uint32_t>(CtrlStack.size()));
273
144
    }
274
    // Return the index of the N-th element from the end.
275
55.8k
    return static_cast<uint32_t>(CtrlStack.size()) - UINT32_C(1) - N;
276
56.0k
  };
277
278
  // Helper lambda for checking lane index and performing transformation.
279
2.50M
  auto checkLaneAndTrans = [this,
280
2.50M
                            &Instr](uint32_t N, Span<const ValType> Take,
281
2.50M
                                    Span<const ValType> Put) -> Expect<void> {
282
10.1k
    if (Instr.getMemoryLane() >= N) {
283
26
      return logOutOfRange(ErrCode::Value::InvalidLaneIdx,
284
26
                           ErrInfo::IndexCategory::Lane, Instr.getMemoryLane(),
285
26
                           N);
286
26
    }
287
10.1k
    return StackTrans(Take, Put);
288
10.1k
  };
289
290
  // Helper lambda for checking memory alignment and performing transformation.
291
2.50M
  auto checkMemArgAndTrans = [this, checkMemIdx,
292
2.50M
                              &Instr](uint32_t N, Span<const ValType> Take,
293
2.50M
                                      Span<const ValType> Put,
294
2.50M
                                      bool CheckLane = false) -> Expect<void> {
295
    // The first arg is always `addr_type`, representing the memory offset.
296
    // This helper will automatically add the first arg, therefore the caller
297
    // should set the input type list without the memory offset arg.
298
299
    // Check the memory index and get the address type.
300
60.9k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
301
    // Check the alignment.
302
60.5k
    auto IsAtomic = Instr.getOpCode() >= OpCode::Memory__atomic__notify &&
303
308
                    Instr.getOpCode() <= OpCode::I64__atomic__rmw32__cmpxchg_u;
304
60.5k
    if (Instr.getMemoryAlign() > 31 ||
305
60.5k
        (!IsAtomic && (1UL << Instr.getMemoryAlign()) > (N >> 3UL))) {
306
      // 2 ^ align must be <= N / 8.
307
43
      spdlog::error(ErrCode::Value::AlignmentTooLarge);
308
43
      spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3),
309
43
                                          Instr.getMemoryAlign()));
310
43
      return Unexpect(ErrCode::Value::AlignmentTooLarge);
311
43
    }
312
60.5k
    if (IsAtomic && (1UL << Instr.getMemoryAlign()) != (N >> 3UL)) {
313
      // 2 ^ align must be == N / 8.
314
24
      spdlog::error(ErrCode::Value::InvalidAlignment);
315
24
      spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3),
316
24
                                          Instr.getMemoryAlign()));
317
24
      return Unexpect(ErrCode::Value::InvalidAlignment);
318
24
    }
319
    // Check the memory offset validation.
320
60.4k
    auto ATCode = Mems[Instr.getTargetIndex()];
321
60.4k
    if (Instr.getMemoryOffset() >
322
60.4k
        getMaxAddress(convTypeCodeToAddrType(ATCode))) {
323
3
      spdlog::error(ErrCode::Value::InvalidOffset);
324
3
      return Unexpect(ErrCode::Value::InvalidOffset);
325
3
    }
326
    // Check the memory lane if needed.
327
60.4k
    if (CheckLane && Instr.getMemoryLane() >= 128 / N) {
328
14
      return logOutOfRange(ErrCode::Value::InvalidLaneIdx,
329
14
                           ErrInfo::IndexCategory::Lane, Instr.getMemoryLane(),
330
14
                           128 / N);
331
14
    }
332
    // Perform the stack change. Additionally pop the first arg (address type).
333
60.4k
    EXPECTED_TRY(popTypes(Take));
334
60.4k
    EXPECTED_TRY(popType(ATCode));
335
60.4k
    pushTypes(Put);
336
60.4k
    return {};
337
60.4k
  };
338
339
  // Helper lambda for checking value type matching.
340
2.50M
  auto checkTypesMatching = [this](Span<const ValType> Exp,
341
2.50M
                                   Span<const ValType> Got) -> Expect<void> {
342
6.65k
    if (!AST::TypeMatcher::matchTypes(Types, Exp, Got)) {
343
81
      std::vector<ValType> ExpV(Exp.begin(), Exp.end()),
344
81
          GotV(Got.begin(), Got.end());
345
81
      spdlog::error(ErrCode::Value::TypeCheckFailed);
346
81
      spdlog::error(ErrInfo::InfoMismatch(ExpV, GotV));
347
81
      return Unexpect(ErrCode::Value::TypeCheckFailed);
348
81
    }
349
6.56k
    return {};
350
6.65k
  };
351
352
  // Helper lambda for recording jump data.
353
2.50M
  auto recordJump = [this, &Instr](AST::Instruction::JumpDescriptor &Jump,
354
2.50M
                                   uint32_t Arity, uint32_t D) -> void {
355
55.7k
    const uint32_t Remain =
356
55.7k
        static_cast<uint32_t>(ValStack.size() - CtrlStack[D].Height);
357
55.7k
    Jump.StackEraseBegin = Remain + Arity;
358
55.7k
    Jump.StackEraseEnd = Arity;
359
55.7k
    Jump.PCOffset = static_cast<int32_t>(CtrlStack[D].Jump - &Instr);
360
55.7k
  };
361
362
  // Helper lambda for unpacking a value type.
363
2.50M
  auto unpackType = [](const ValType &T) -> ValType {
364
1.42k
    if (T.isPackType()) {
365
614
      return ValType(TypeCode::I32);
366
614
    }
367
813
    return T;
368
1.42k
  };
369
370
  // Helper lambda for downcasting into the top heap type.
371
2.50M
  auto toTopHeapType = [this](const ValType &T) -> ValType {
372
1.07k
    assuming(T.isRefType());
373
1.07k
    if (T.isAbsHeapType()) {
374
491
      switch (T.getHeapTypeCode()) {
375
27
      case TypeCode::NullFuncRef:
376
55
      case TypeCode::FuncRef:
377
55
        return TypeCode::FuncRef;
378
27
      case TypeCode::NullExternRef:
379
38
      case TypeCode::ExternRef:
380
38
        return TypeCode::ExternRef;
381
49
      case TypeCode::NullExnRef:
382
86
      case TypeCode::ExnRef:
383
86
        return TypeCode::ExnRef;
384
88
      case TypeCode::NullRef:
385
144
      case TypeCode::AnyRef:
386
172
      case TypeCode::EqRef:
387
231
      case TypeCode::I31Ref:
388
278
      case TypeCode::StructRef:
389
312
      case TypeCode::ArrayRef:
390
312
        return TypeCode::AnyRef;
391
0
      default:
392
0
        assumingUnreachable();
393
491
      }
394
579
    } else {
395
579
      const auto &CompType = Types[T.getTypeIndex()]->getCompositeType();
396
579
      if (CompType.isFunc()) {
397
118
        return TypeCode::FuncRef;
398
461
      } else {
399
461
        return TypeCode::AnyRef;
400
461
      }
401
579
    }
402
1.07k
  };
403
404
2.50M
  switch (Instr.getOpCode()) {
405
  // Control instructions.
406
289k
  case OpCode::Unreachable:
407
289k
    return unreachable();
408
113k
  case OpCode::Nop:
409
113k
    return {};
410
411
9.65k
  case OpCode::Block:
412
12.8k
  case OpCode::Loop:
413
21.1k
  case OpCode::If:
414
27.8k
  case OpCode::Try_table: {
415
    // Get blocktype [t1*] -> [t2*] and check valtype first.
416
27.8k
    std::vector<ValType> Buffer(1);
417
27.8k
    const auto &BType = (Instr.getOpCode() == OpCode::Try_table)
418
27.8k
                            ? Instr.getTryCatch().ResType
419
27.8k
                            : Instr.getBlockType();
420
27.8k
    EXPECTED_TRY(auto T1T2, checkBlockType(Buffer, BType));
421
27.7k
    auto [T1, T2] = T1T2;
422
    // For the if instruction, pop I32 first.
423
27.7k
    if (Instr.getOpCode() == OpCode::If) {
424
8.23k
      EXPECTED_TRY(popType(TypeCode::I32));
425
8.23k
    }
426
    // Pop and check [t1*]
427
27.7k
    EXPECTED_TRY(popTypes(T1));
428
    // For the try_table instruction, validate the handlers.
429
27.7k
    if (Instr.getOpCode() == OpCode::Try_table) {
430
6.68k
      const auto &TryDesc = Instr.getTryCatch();
431
6.68k
      const_cast<AST::Instruction::TryDescriptor &>(TryDesc).BlockParamNum =
432
6.68k
          static_cast<uint32_t>(T1.size());
433
      // Validate catch clause.
434
18.4k
      for (const auto &C : TryDesc.Catch) {
435
18.4k
        if (!C.IsAll) {
436
          // Check tag index.
437
2.37k
          EXPECTED_TRY(checkTagIdx(C.TagIndex));
438
          // Result types of tag indices are checked in the tag section.
439
2.37k
        }
440
36.8k
        EXPECTED_TRY(auto D, checkCtrlStackDepth(C.LabelIndex));
441
36.8k
        pushCtrl({}, getLabelTypes(CtrlStack[D]), &Instr + TryDesc.JumpEnd,
442
36.8k
                 Instr.getOpCode());
443
36.8k
        std::vector<ValType> NTypes;
444
36.8k
        if (!C.IsAll) {
445
          // The type is checked as a function type.
446
2.36k
          NTypes = Types[Tags[C.TagIndex]]
447
2.36k
                       ->getCompositeType()
448
2.36k
                       .getFuncType()
449
2.36k
                       .getParamTypes();
450
2.36k
        }
451
36.8k
        if (C.IsRef) {
452
23
          NTypes.emplace_back(ValType(TypeCode::Ref, TypeCode::ExnRef));
453
23
        }
454
36.8k
        pushTypes(NTypes);
455
36.8k
        EXPECTED_TRY(popCtrl());
456
18.3k
        recordJump(const_cast<AST::Instruction::JumpDescriptor &>(C.Jump),
457
18.3k
                   static_cast<uint32_t>(NTypes.size()), D);
458
18.3k
      }
459
6.68k
    }
460
    // Push ctrl frame ([t1*], [t2*])
461
27.7k
    const AST::Instruction *From = nullptr;
462
27.7k
    if (Instr.getOpCode() == OpCode::Loop) {
463
3.23k
      From = &Instr;
464
24.5k
    } else if (Instr.getOpCode() == OpCode::Try_table) {
465
6.64k
      From = &Instr + Instr.getTryCatch().JumpEnd;
466
17.8k
    } else {
467
17.8k
      From = &Instr + Instr.getJumpEnd();
468
17.8k
    }
469
27.7k
    pushCtrl(T1, T2, From, Instr.getOpCode());
470
27.7k
    if (Instr.getOpCode() == OpCode::If &&
471
8.22k
        Instr.getJumpElse() == Instr.getJumpEnd()) {
472
      // No else case in if-else statement.
473
5.13k
      EXPECTED_TRY(checkTypesMatching(T2, T1));
474
5.13k
    }
475
27.6k
    return {};
476
27.7k
  }
477
478
2.97k
  case OpCode::Else: {
479
2.97k
    EXPECTED_TRY(auto Ctrl, popCtrl());
480
2.97k
    pushCtrl(Ctrl.StartTypes, Ctrl.EndTypes, Ctrl.Jump, Instr.getOpCode());
481
2.97k
    return {};
482
2.97k
  }
483
484
105
  case OpCode::Throw: {
485
105
    EXPECTED_TRY(checkTagIdx(Instr.getTargetIndex()));
486
120
    EXPECTED_TRY(auto CompType, checkDefinedType(Tags[Instr.getTargetIndex()],
487
120
                                                 TypeCode::Func));
488
120
    std::vector<ValType> Input = CompType->getFuncType().getParamTypes();
489
120
    EXPECTED_TRY(popTypes(Input));
490
55
    return unreachable();
491
120
  }
492
493
1.17k
  case OpCode::Throw_ref:
494
1.17k
    EXPECTED_TRY(popType(TypeCode::ExnRef));
495
1.16k
    return unreachable();
496
497
58.5k
  case OpCode::End: {
498
58.5k
    EXPECTED_TRY(auto Ctrl, popCtrl());
499
58.1k
    pushTypes(Ctrl.EndTypes);
500
58.1k
    return {};
501
58.5k
  }
502
503
6.63k
  case OpCode::Br: {
504
6.63k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
505
    // D is the last D element of control stack.
506
6.61k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
507
6.61k
    EXPECTED_TRY(popTypes(NTypes));
508
6.59k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
509
6.59k
               static_cast<uint32_t>(NTypes.size()), D);
510
6.59k
    return unreachable();
511
6.61k
  }
512
4.23k
  case OpCode::Br_if: {
513
4.23k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
514
    // D is the last D element of control stack.
515
4.20k
    EXPECTED_TRY(popType(TypeCode::I32));
516
4.19k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
517
4.19k
    EXPECTED_TRY(popTypes(NTypes));
518
4.19k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
519
4.19k
               static_cast<uint32_t>(NTypes.size()), D);
520
4.19k
    pushTypes(NTypes);
521
4.19k
    return {};
522
4.19k
  }
523
2.06k
  case OpCode::Br_table: {
524
2.06k
    EXPECTED_TRY(popType(TypeCode::I32));
525
2.05k
    auto LabelTable = const_cast<AST::Instruction &>(Instr).getLabelList();
526
2.05k
    const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
527
2.05k
    EXPECTED_TRY(auto M,
528
2.04k
                 checkCtrlStackDepth(LabelTable[LabelTableSize].TargetIndex));
529
    // M is the M-th element from the end of the control stack.
530
2.04k
    auto MTypes = getLabelTypes(CtrlStack[M]);
531
24.6k
    for (uint32_t LabelIdx = 0; LabelIdx < LabelTableSize; ++LabelIdx) {
532
22.6k
      const uint32_t L = LabelTable[LabelIdx].TargetIndex;
533
22.6k
      EXPECTED_TRY(auto N, checkCtrlStackDepth(L));
534
      // N is the N-th element from the end of the control stack.
535
22.5k
      const auto NTypes = getLabelTypes(CtrlStack[N]);
536
22.5k
      if (MTypes.size() != NTypes.size()) {
537
5
        return checkTypesMatching(MTypes, NTypes);
538
5
      }
539
      // Push the popped types.
540
22.5k
      std::vector<VType> TypeBuf(NTypes.size());
541
32.5k
      for (uint32_t IdxN = static_cast<uint32_t>(NTypes.size()); IdxN >= 1;
542
22.5k
           --IdxN) {
543
10.0k
        const uint32_t Idx = IdxN - 1;
544
        // Cannot use popTypes() here because we need the popped value.
545
10.0k
        EXPECTED_TRY(auto Type, popType(NTypes[Idx]));
546
        // Check whether `unreachableVType` occurred when an `unreachable`
547
        // instruction appeared before the `br_table` instruction.
548
10.0k
        if (CtrlStack.back().IsUnreachable) {
549
5.99k
          TypeBuf[Idx] = unreachableVType();
550
5.99k
        } else {
551
4.01k
          TypeBuf[Idx] = Type;
552
4.01k
        }
553
10.0k
      }
554
22.5k
      recordJump(LabelTable[LabelIdx], static_cast<uint32_t>(NTypes.size()), N);
555
22.5k
      pushTypes(TypeBuf);
556
22.5k
    }
557
1.99k
    const auto NTypes = getLabelTypes(CtrlStack[M]);
558
1.99k
    EXPECTED_TRY(popTypes(NTypes));
559
1.99k
    recordJump(LabelTable[LabelTableSize], static_cast<uint32_t>(NTypes.size()),
560
1.99k
               M);
561
1.99k
    return unreachable();
562
1.99k
  }
563
564
1.85k
  case OpCode::Br_on_null: {
565
    // D is the last D element of control stack.
566
1.85k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
567
1.83k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
568
1.83k
    EXPECTED_TRY(auto ResT, popType());
569
1.83k
    if (ResT.has_value() && !ResT->isRefType()) {
570
5
      spdlog::error(ErrCode::Value::InvalidBrRefType);
571
5
      return Unexpect(ErrCode::ErrCode::Value::InvalidBrRefType);
572
5
    }
573
1.83k
    EXPECTED_TRY(popTypes(NTypes));
574
1.82k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
575
1.82k
               static_cast<uint32_t>(NTypes.size()), D);
576
1.82k
    pushTypes(NTypes);
577
1.82k
    if (ResT.has_value()) {
578
1.40k
      pushType(ResT->toNonNullableRef());
579
1.40k
    } else {
580
425
      pushType(unreachableVType());
581
425
    }
582
1.82k
    return {};
583
1.83k
  }
584
585
159
  case OpCode::Br_on_non_null: {
586
159
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
587
    // Get the result type of the label. (Should be [t* rt].)
588
152
    auto LabelTypes = getLabelTypes(CtrlStack[D]);
589
152
    std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end());
590
152
    if (unlikely(NTypes.empty())) {
591
6
      spdlog::error(ErrCode::Value::InvalidBrRefType);
592
6
      return Unexpect(ErrCode::Value::InvalidBrRefType);
593
6
    }
594
    // Pop types [t* (ref.null rt)].
595
146
    ValType &RT = NTypes.back();
596
146
    if (!RT.isRefType()) {
597
5
      spdlog::error(ErrCode::Value::InvalidBrRefType);
598
5
      return Unexpect(ErrCode::Value::InvalidBrRefType);
599
5
    }
600
141
    RT.toNullableRef();
601
141
    EXPECTED_TRY(popTypes(NTypes));
602
134
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
603
134
               static_cast<uint32_t>(NTypes.size()), D);
604
    // Push types [t*].
605
134
    NTypes.pop_back();
606
134
    pushTypes(NTypes);
607
134
    return {};
608
141
  }
609
610
3.74k
  case OpCode::Return:
611
3.74k
    EXPECTED_TRY(popTypes(Returns));
612
3.73k
    return unreachable();
613
614
5.39k
  case OpCode::Call: {
615
5.39k
    auto N = Instr.getTargetIndex();
616
5.39k
    if (unlikely(N >= Funcs.size())) {
617
44
      return logOutOfRange(ErrCode::Value::InvalidFuncIdx,
618
44
                           ErrInfo::IndexCategory::Function, N,
619
44
                           static_cast<uint32_t>(Funcs.size()));
620
44
    }
621
    // Because functions were validated when added, Type[Funcs[N]] must be a
622
    // function type.
623
5.35k
    auto &FuncType = Types[Funcs[N]]->getCompositeType().getFuncType();
624
5.35k
    return StackTrans(FuncType.getParamTypes(), FuncType.getReturnTypes());
625
5.39k
  }
626
1.51k
  case OpCode::Call_indirect: {
627
1.51k
    auto N = Instr.getTargetIndex();
628
1.51k
    auto T = Instr.getSourceIndex();
629
    // Check source table index.
630
1.51k
    EXPECTED_TRY(checkTableIdx(T));
631
1.48k
    if (!AST::TypeMatcher::matchType(Types, TypeCode::FuncRef,
632
1.48k
                                     Tables[T].second)) {
633
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
634
3
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, Tables[T].second));
635
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
636
3
    }
637
    // Check target function type index.
638
2.96k
    EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func));
639
2.96k
    EXPECTED_TRY(popType(Tables[T].first));
640
1.47k
    const auto &FType = CompType->getFuncType();
641
1.47k
    return StackTrans(FType.getParamTypes(), FType.getReturnTypes());
642
2.96k
  }
643
667
  case OpCode::Return_call: {
644
667
    auto N = Instr.getTargetIndex();
645
667
    if (unlikely(N >= Funcs.size())) {
646
      // Call function index out of range
647
8
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
648
8
      spdlog::error(
649
8
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Function, N,
650
8
                                   static_cast<uint32_t>(Funcs.size())));
651
8
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
652
8
    }
653
    // Because functions were validated when added, Type[Funcs[N]] must be a
654
    // function type.
655
659
    auto &FType = Types[Funcs[N]]->getCompositeType().getFuncType();
656
659
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
657
645
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
658
642
    return unreachable();
659
645
  }
660
672
  case OpCode::Return_call_indirect: {
661
672
    auto N = Instr.getTargetIndex();
662
672
    auto T = Instr.getSourceIndex();
663
    // Check source table index.
664
672
    EXPECTED_TRY(checkTableIdx(T));
665
658
    if (!AST::TypeMatcher::matchType(Types, TypeCode::FuncRef,
666
658
                                     Tables[T].second)) {
667
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
668
3
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, Tables[T].second));
669
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
670
3
    }
671
    // Check target function type index.
672
1.30k
    EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func));
673
1.30k
    const auto &FType = CompType->getFuncType();
674
1.30k
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
675
646
    EXPECTED_TRY(popType(Tables[T].first));
676
641
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
677
638
    return unreachable();
678
641
  }
679
452
  case OpCode::Call_ref: {
680
452
    EXPECTED_TRY(auto CompType,
681
444
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Func));
682
444
    const auto &FType = CompType->getFuncType();
683
444
    std::vector<ValType> Input = FType.getParamTypes();
684
444
    Input.push_back(ValType(TypeCode::RefNull, Instr.getTargetIndex()));
685
444
    return StackTrans(Input, FType.getReturnTypes());
686
452
  }
687
220
  case OpCode::Return_call_ref: {
688
220
    EXPECTED_TRY(auto CompType,
689
205
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Func));
690
205
    const auto &FType = CompType->getFuncType();
691
205
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
692
188
    EXPECTED_TRY(popType(ValType(TypeCode::RefNull, Instr.getTargetIndex())));
693
183
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
694
181
    return unreachable();
695
183
  }
696
697
  // Reference Instructions.
698
19.4k
  case OpCode::Ref__null: {
699
19.4k
    EXPECTED_TRY(validate(Instr.getValType()));
700
19.4k
    return StackTrans({}, {Instr.getValType()});
701
19.4k
  }
702
4.12k
  case OpCode::Ref__is_null: {
703
4.12k
    EXPECTED_TRY(auto Type, popType());
704
4.12k
    if (Type.has_value() && !Type->isRefType()) {
705
4
      spdlog::error(ErrCode::Value::TypeCheckFailed);
706
4
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, VTypeToAST(Type)));
707
4
      return Unexpect(ErrCode::Value::TypeCheckFailed);
708
4
    }
709
4.12k
    return StackTrans({}, {ValType(TypeCode::I32)});
710
4.12k
  }
711
2.77k
  case OpCode::Ref__func: {
712
2.77k
    auto FuncIdx = Instr.getTargetIndex();
713
2.77k
    if (Refs.find(FuncIdx) == Refs.cend()) {
714
      // Undeclared function reference.
715
36
      spdlog::error(ErrCode::Value::InvalidRefIdx);
716
36
      return Unexpect(ErrCode::Value::InvalidRefIdx);
717
36
    }
718
2.73k
    assuming(FuncIdx < Funcs.size());
719
2.73k
    auto TypeIdx = Funcs[FuncIdx];
720
2.73k
    assuming(TypeIdx < Types.size());
721
2.73k
    return StackTrans({}, {ValType(TypeCode::Ref, TypeIdx)});
722
2.73k
  }
723
136
  case OpCode::Ref__eq:
724
136
    return StackTrans({ValType(TypeCode::RefNull, TypeCode::EqRef),
725
136
                       ValType(TypeCode::RefNull, TypeCode::EqRef)},
726
136
                      {ValType(TypeCode::I32)});
727
3.97k
  case OpCode::Ref__as_non_null: {
728
3.97k
    EXPECTED_TRY(auto Type, popType());
729
3.96k
    if (Type == unreachableVType()) {
730
1.92k
      pushType(unreachableVType());
731
1.92k
      return {};
732
1.92k
    }
733
2.04k
    if (!Type->isRefType()) {
734
13
      spdlog::error(ErrCode::Value::TypeCheckFailed);
735
13
      spdlog::error(ErrInfo::InfoMismatch(
736
13
          ValType(TypeCode::RefNull, TypeCode::FuncRef), VTypeToAST(Type)));
737
13
      return Unexpect(ErrCode::Value::TypeCheckFailed);
738
13
    }
739
2.03k
    return StackTrans({}, {Type->toNonNullableRef()});
740
2.04k
  }
741
742
633
  case OpCode::Struct__new:
743
1.70k
  case OpCode::Struct__new_default: {
744
1.70k
    EXPECTED_TRY(auto CompType,
745
1.67k
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct));
746
1.67k
    std::vector<ValType> Fields;
747
1.67k
    if (Instr.getOpCode() == OpCode::Struct__new) {
748
617
      Fields.reserve(CompType->getFieldTypes().size());
749
617
    }
750
9.47k
    for (auto &FType : CompType->getFieldTypes()) {
751
9.47k
      if (Instr.getOpCode() == OpCode::Struct__new) {
752
156
        Fields.emplace_back(unpackType(FType.getStorageType()));
753
9.31k
      } else if (!FType.getStorageType().isDefaultable()) {
754
1
        spdlog::error(ErrCode::Value::TypeCheckFailed);
755
1
        spdlog::error("    Value type should be defaultable."sv);
756
1
        return Unexpect(ErrCode::Value::TypeCheckFailed);
757
1
      }
758
9.47k
    }
759
1.67k
    return StackTrans(Fields, {ValType(TypeCode::Ref, Instr.getTargetIndex())});
760
1.67k
  }
761
10
  case OpCode::Struct__get:
762
16
  case OpCode::Struct__get_s:
763
31
  case OpCode::Struct__get_u: {
764
31
    EXPECTED_TRY(auto CompType,
765
21
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct));
766
21
    if (Instr.getSourceIndex() >= CompType->getFieldTypes().size()) {
767
4
      return logOutOfRange(
768
4
          ErrCode::Value::InvalidFieldIdx, ErrInfo::IndexCategory::Field,
769
4
          Instr.getSourceIndex(),
770
4
          static_cast<uint32_t>(CompType->getFieldTypes().size()));
771
4
    }
772
17
    const auto &FType = CompType->getFieldTypes()[Instr.getSourceIndex()];
773
17
    if (unlikely(Instr.getOpCode() == OpCode::Struct__get &&
774
4
                 FType.getStorageType().isPackType())) {
775
      // For a packed type, the `_s` or `_u` in the instruction is required.
776
2
      spdlog::error(ErrCode::Value::InvalidPackedField);
777
2
      return Unexpect(ErrCode::Value::InvalidPackedField);
778
15
    } else if (unlikely(Instr.getOpCode() != OpCode::Struct__get &&
779
13
                        !FType.getStorageType().isPackType())) {
780
      // The `_s` or `_u` in instruction only accepts packed field.
781
2
      spdlog::error(ErrCode::Value::InvalidUnpackedField);
782
2
      return Unexpect(ErrCode::Value::InvalidUnpackedField);
783
2
    }
784
13
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex())},
785
13
                      {unpackType(FType.getStorageType())});
786
17
  }
787
32
  case OpCode::Struct__set: {
788
32
    EXPECTED_TRY(auto CompType,
789
29
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct));
790
29
    if (Instr.getSourceIndex() >= CompType->getFieldTypes().size()) {
791
4
      return logOutOfRange(
792
4
          ErrCode::Value::InvalidFieldIdx, ErrInfo::IndexCategory::Field,
793
4
          Instr.getSourceIndex(),
794
4
          static_cast<uint32_t>(CompType->getFieldTypes().size()));
795
4
    }
796
25
    const auto &FType = CompType->getFieldTypes()[Instr.getSourceIndex()];
797
25
    if (FType.getValMut() != ValMut::Var) {
798
2
      spdlog::error(ErrCode::Value::ImmutableField);
799
2
      return Unexpect(ErrCode::Value::ImmutableField);
800
2
    }
801
23
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
802
23
                       unpackType(FType.getStorageType())},
803
23
                      {});
804
25
  }
805
317
  case OpCode::Array__new:
806
721
  case OpCode::Array__new_default:
807
1.06k
  case OpCode::Array__new_fixed: {
808
1.06k
    EXPECTED_TRY(auto CompType,
809
1.04k
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
810
1.04k
    const auto &SType = CompType->getFieldTypes()[0].getStorageType();
811
1.04k
    if (Instr.getOpCode() == OpCode::Array__new) {
812
309
      return StackTrans({unpackType(SType), ValType(TypeCode::I32)},
813
309
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
814
740
    } else if (Instr.getOpCode() == OpCode::Array__new_default) {
815
398
      if (!SType.isDefaultable()) {
816
1
        spdlog::error(ErrCode::Value::TypeCheckFailed);
817
1
        spdlog::error("    Value type should be defaultable."sv);
818
1
        return Unexpect(ErrCode::Value::TypeCheckFailed);
819
1
      }
820
397
      return StackTrans({ValType(TypeCode::I32)},
821
397
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
822
398
    } else {
823
342
      std::vector<ValType> Fields(Instr.getSourceIndex(), unpackType(SType));
824
342
      return StackTrans(Fields,
825
342
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
826
342
    }
827
1.04k
  }
828
9
  case OpCode::Array__new_data:
829
18
  case OpCode::Array__init_data: {
830
18
    EXPECTED_TRY(auto CompType,
831
12
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
832
12
    const auto &FType = CompType->getFieldTypes()[0];
833
12
    if (Instr.getOpCode() == OpCode::Array__init_data &&
834
6
        FType.getValMut() != ValMut::Var) {
835
3
      spdlog::error(ErrCode::Value::ImmutableArray);
836
3
      return Unexpect(ErrCode::Value::ImmutableArray);
837
3
    }
838
9
    if (!unpackType(FType.getStorageType()).isNumType()) {
839
3
      spdlog::error(ErrCode::Value::ArrayTypesNumtypeRequired);
840
3
      return Unexpect(ErrCode::Value::ArrayTypesNumtypeRequired);
841
3
    }
842
6
    EXPECTED_TRY(checkDataIdx(Instr.getSourceIndex()));
843
2
    if (Instr.getOpCode() == OpCode::Array__new_data) {
844
1
      return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
845
1
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
846
1
    } else {
847
1
      return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
848
1
                         ValType(TypeCode::I32), ValType(TypeCode::I32),
849
1
                         ValType(TypeCode::I32)},
850
1
                        {});
851
1
    }
852
2
  }
853
7
  case OpCode::Array__new_elem:
854
18
  case OpCode::Array__init_elem: {
855
18
    EXPECTED_TRY(auto CompType,
856
12
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
857
12
    const auto &FType = CompType->getFieldTypes()[0];
858
12
    if (Instr.getOpCode() == OpCode::Array__init_elem &&
859
9
        FType.getValMut() != ValMut::Var) {
860
4
      spdlog::error(ErrCode::Value::ImmutableArray);
861
4
      return Unexpect(ErrCode::Value::ImmutableArray);
862
4
    }
863
8
    if (!FType.getStorageType().isRefType()) {
864
4
      spdlog::error(ErrCode::Value::TypeCheckFailed);
865
4
      return Unexpect(ErrCode::Value::TypeCheckFailed);
866
4
    }
867
4
    EXPECTED_TRY(checkElemIdx(Instr.getSourceIndex()));
868
1
    if (!AST::TypeMatcher::matchType(Types, FType.getStorageType(),
869
1
                                     Elems[Instr.getSourceIndex()])) {
870
1
      spdlog::error(ErrCode::Value::TypeCheckFailed);
871
1
      spdlog::error(ErrInfo::InfoMismatch(FType.getStorageType(),
872
1
                                          Elems[Instr.getSourceIndex()]));
873
1
      return Unexpect(ErrCode::Value::TypeCheckFailed);
874
1
    }
875
0
    if (Instr.getOpCode() == OpCode::Array__new_elem) {
876
0
      return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
877
0
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
878
0
    } else {
879
0
      return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
880
0
                         ValType(TypeCode::I32), ValType(TypeCode::I32),
881
0
                         ValType(TypeCode::I32)},
882
0
                        {});
883
0
    }
884
0
  }
885
247
  case OpCode::Array__get:
886
417
  case OpCode::Array__get_s:
887
489
  case OpCode::Array__get_u: {
888
489
    EXPECTED_TRY(auto CompType,
889
472
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
890
472
    const auto &FType = CompType->getFieldTypes()[0];
891
472
    if (unlikely(Instr.getOpCode() == OpCode::Array__get &&
892
241
                 FType.getStorageType().isPackType())) {
893
      // For a packed type, the `_s` or `_u` in the instruction is required.
894
2
      spdlog::error(ErrCode::Value::InvalidPackedArray);
895
2
      return Unexpect(ErrCode::Value::InvalidPackedArray);
896
470
    } else if (unlikely(Instr.getOpCode() != OpCode::Array__get &&
897
231
                        !FType.getStorageType().isPackType())) {
898
      // The `_s` or `_u` in instruction only accepts packed array.
899
3
      spdlog::error(ErrCode::Value::InvalidUnpackedArray);
900
3
      return Unexpect(ErrCode::Value::InvalidUnpackedArray);
901
3
    }
902
467
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
903
467
                       ValType(TypeCode::I32)},
904
467
                      {unpackType(FType.getStorageType())});
905
472
  }
906
79
  case OpCode::Array__set:
907
122
  case OpCode::Array__fill: {
908
122
    EXPECTED_TRY(auto CompType,
909
112
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
910
112
    const auto &FType = CompType->getFieldTypes()[0];
911
112
    if (FType.getValMut() != ValMut::Var) {
912
4
      spdlog::error(ErrCode::Value::ImmutableArray);
913
4
      return Unexpect(ErrCode::Value::ImmutableArray);
914
4
    }
915
108
    std::vector<ValType> Fields = {
916
108
        ValType(TypeCode::RefNull, Instr.getTargetIndex()),
917
108
        ValType(TypeCode::I32), unpackType(FType.getStorageType())};
918
108
    if (Instr.getOpCode() == OpCode::Array__fill) {
919
36
      Fields.emplace_back(ValType(TypeCode::I32));
920
36
    }
921
108
    return StackTrans(Fields, {});
922
112
  }
923
141
  case OpCode::Array__len:
924
141
    return StackTrans({ValType(TypeCode::ArrayRef)}, {ValType(TypeCode::I32)});
925
61
  case OpCode::Array__copy: {
926
61
    EXPECTED_TRY(auto CompType,
927
58
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
928
58
    const auto &DstFType = CompType->getFieldTypes()[0];
929
58
    if (DstFType.getValMut() != ValMut::Var) {
930
2
      spdlog::error(ErrCode::Value::ImmutableArray);
931
2
      return Unexpect(ErrCode::Value::ImmutableArray);
932
2
    }
933
110
    EXPECTED_TRY(auto Src,
934
110
                 checkDefinedType(Instr.getSourceIndex(), TypeCode::Array));
935
110
    const auto &SrcFType = Src->getFieldTypes()[0];
936
110
    if (!AST::TypeMatcher::matchType(Types, DstFType.getStorageType(),
937
54
                                     SrcFType.getStorageType())) {
938
1
      spdlog::error(ErrCode::Value::ArrayTypesMismatch);
939
1
      spdlog::error(ErrInfo::InfoMismatch(DstFType.getStorageType(),
940
1
                                          SrcFType.getStorageType()));
941
1
      return Unexpect(ErrCode::Value::ArrayTypesMismatch);
942
1
    }
943
53
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
944
53
                       ValType(TypeCode::I32),
945
53
                       ValType(TypeCode::RefNull, Instr.getSourceIndex()),
946
53
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
947
53
                      {});
948
110
  }
949
950
270
  case OpCode::Ref__test:
951
394
  case OpCode::Ref__test_null:
952
795
  case OpCode::Ref__cast:
953
1.16k
  case OpCode::Ref__cast_null: {
954
1.16k
    EXPECTED_TRY(validate(Instr.getValType()));
955
2.30k
    EXPECTED_TRY(auto Type, popType());
956
2.30k
    if (Type.has_value() && !Type->isRefType()) {
957
      // The trap occurs when the actual type is not a reference type.
958
7
      spdlog::error(ErrCode::Value::TypeCheckFailed);
959
7
      spdlog::error(
960
7
          ErrInfo::InfoMismatch(Instr.getValType(), VTypeToAST(Type)));
961
7
      return Unexpect(ErrCode::Value::TypeCheckFailed);
962
7
    }
963
    // When Type is nullopt (unreachable/bottom type), the bottom type matches
964
    // any target type, so skip the type matching check.
965
1.14k
    if (Type.has_value() &&
966
1.07k
        !AST::TypeMatcher::matchType(Types, toTopHeapType(*Type),
967
1.07k
                                     Instr.getValType())) {
968
14
      spdlog::error(ErrCode::Value::TypeCheckFailed);
969
14
      spdlog::error(ErrInfo::InfoMismatch(*Type, Instr.getValType()));
970
14
      return Unexpect(ErrCode::Value::TypeCheckFailed);
971
14
    }
972
1.12k
    if (Instr.getOpCode() == OpCode::Ref__test ||
973
860
        Instr.getOpCode() == OpCode::Ref__test_null) {
974
383
      return StackTrans({}, {ValType(TypeCode::I32)});
975
745
    } else {
976
745
      return StackTrans({}, {Instr.getValType()});
977
745
    }
978
1.12k
  }
979
45
  case OpCode::Br_on_cast:
980
105
  case OpCode::Br_on_cast_fail: {
981
    // The reference types should be valid.
982
105
    auto &RT1 = Instr.getBrCast().RType1;
983
105
    auto &RT2 = Instr.getBrCast().RType2;
984
105
    EXPECTED_TRY(validate(RT1));
985
99
    EXPECTED_TRY(validate(RT2));
986
    // The reference type RT2 should match RT1.
987
94
    if (unlikely(!AST::TypeMatcher::matchType(Types, RT1, RT2))) {
988
15
      spdlog::error(ErrCode::Value::TypeCheckFailed);
989
15
      spdlog::error(ErrInfo::InfoMismatch(RT1, RT2));
990
15
      return Unexpect(ErrCode::Value::TypeCheckFailed);
991
15
    }
992
155
    EXPECTED_TRY(auto D,
993
155
                 checkCtrlStackDepth(Instr.getBrCast().Jump.TargetIndex));
994
    // Get the result type of the label. (Should be [t* rt'].)
995
155
    auto LabelTypes = getLabelTypes(CtrlStack[D]);
996
155
    std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end());
997
155
    if (unlikely(NTypes.empty())) {
998
4
      spdlog::error(ErrCode::Value::InvalidBrRefType);
999
4
      return Unexpect(ErrCode::Value::InvalidBrRefType);
1000
4
    }
1001
    // Get the type difference between rt1 \ rt2. (rt1' = rt1 \ rt2)
1002
72
    ValType RT1P = RT2.isNullableRefType() ? RT1.getNonNullableRef() : RT1;
1003
    // For br_on_cast, rt2 must match rt'.
1004
    // For Br_on_cast_fail, rt1' must match rt'.
1005
72
    ValType &RTP = NTypes.back();
1006
72
    const ValType &RTRHS = Instr.getOpCode() == OpCode::Br_on_cast ? RT2 : RT1P;
1007
72
    if (unlikely(!AST::TypeMatcher::matchType(Types, RTP, RTRHS))) {
1008
4
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1009
4
      spdlog::error(ErrInfo::InfoMismatch(RTP, RTRHS));
1010
4
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1011
4
    }
1012
    // Pop types [t* rt1].
1013
68
    RTP = RT1;
1014
68
    EXPECTED_TRY(popTypes(NTypes));
1015
65
    recordJump(const_cast<AST::Instruction &>(Instr).getBrCast().Jump,
1016
65
               static_cast<uint32_t>(NTypes.size()), D);
1017
    // For br_on_cast, push types [t* rt1'].
1018
    // For Br_on_cast_fail, push types [t* rt2].
1019
65
    RTP = Instr.getOpCode() == OpCode::Br_on_cast ? RT1P : RT2;
1020
65
    pushTypes(NTypes);
1021
65
    return {};
1022
68
  }
1023
121
  case OpCode::Any__convert_extern: {
1024
121
    EXPECTED_TRY(auto Type, popType(TypeCode::ExternRef));
1025
112
    return StackTrans({}, {ValType(Type->getCode(), TypeCode::AnyRef)});
1026
121
  }
1027
208
  case OpCode::Extern__convert_any: {
1028
208
    EXPECTED_TRY(auto Type, popType(TypeCode::AnyRef));
1029
206
    return StackTrans({}, {ValType(Type->getCode(), TypeCode::ExternRef)});
1030
208
  }
1031
388
  case OpCode::Ref__i31:
1032
388
    return StackTrans({ValType(TypeCode::I32)},
1033
388
                      {ValType(TypeCode::Ref, TypeCode::I31Ref)});
1034
84
  case OpCode::I31__get_s:
1035
172
  case OpCode::I31__get_u:
1036
172
    return StackTrans({ValType(TypeCode::RefNull, TypeCode::I31Ref)},
1037
172
                      {ValType(TypeCode::I32)});
1038
1039
  // Parametric Instructions.
1040
12.6k
  case OpCode::Drop:
1041
12.6k
    return StackPopAny();
1042
4.49k
  case OpCode::Select: {
1043
    // Pop I32.
1044
4.49k
    EXPECTED_TRY(popType(TypeCode::I32));
1045
    // Pop T1 and T2.
1046
8.96k
    EXPECTED_TRY(VType T1, popType());
1047
8.96k
    EXPECTED_TRY(VType T2, popType());
1048
    // T1 and T2 should be number type.
1049
4.47k
    if (T1.has_value() && !T1->isNumType()) {
1050
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1051
3
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::I32, VTypeToAST(T1)));
1052
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1053
3
    }
1054
4.47k
    if (T2.has_value() && !T2->isNumType()) {
1055
4
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1056
4
      spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(T1), VTypeToAST(T2)));
1057
4
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1058
4
    }
1059
    // Error if t1 != t2 && t1 =/= Unknown && t2 =/= Unknown
1060
4.46k
    if (T1 != T2 && T1 != unreachableVType() && T2 != unreachableVType()) {
1061
6
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1062
6
      spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(T1), VTypeToAST(T2)));
1063
6
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1064
6
    }
1065
    // Push value.
1066
4.46k
    if (T1 == unreachableVType()) {
1067
2.10k
      pushType(T2);
1068
2.36k
    } else {
1069
2.36k
      pushType(T1);
1070
2.36k
    }
1071
4.46k
    return {};
1072
4.46k
  }
1073
590
  case OpCode::Select_t: {
1074
    // Note: There may be multiple values choice in the future.
1075
590
    if (Instr.getValTypeList().size() != 1) {
1076
10
      spdlog::error(ErrCode::Value::InvalidResultArity);
1077
10
      return Unexpect(ErrCode::Value::InvalidResultArity);
1078
10
    }
1079
580
    ValType ExpT = Instr.getValTypeList()[0];
1080
580
    EXPECTED_TRY(validate(ExpT));
1081
577
    EXPECTED_TRY(popTypes({ExpT, ExpT, ValType(TypeCode::I32)}));
1082
572
    pushType(ExpT);
1083
572
    return {};
1084
577
  }
1085
1086
  // Variable Instructions.
1087
31.1k
  case OpCode::Local__get:
1088
44.2k
  case OpCode::Local__set:
1089
50.9k
  case OpCode::Local__tee: {
1090
50.9k
    if (Instr.getTargetIndex() >= Locals.size()) {
1091
75
      return logOutOfRange(
1092
75
          ErrCode::Value::InvalidLocalIdx, ErrInfo::IndexCategory::Local,
1093
75
          Instr.getTargetIndex(), static_cast<uint32_t>(Locals.size()));
1094
75
    }
1095
50.8k
    auto &TExpect = Locals[Instr.getTargetIndex()];
1096
50.8k
    const_cast<AST::Instruction &>(Instr).getStackOffset() =
1097
50.8k
        static_cast<uint32_t>(ValStack.size() +
1098
50.8k
                              (Locals.size() - Instr.getTargetIndex()));
1099
50.8k
    if (Instr.getOpCode() == OpCode::Local__get) {
1100
31.1k
      if (!TExpect.IsInit) {
1101
3
        spdlog::error(ErrCode::Value::InvalidUninitLocal);
1102
3
        return Unexpect(ErrCode::Value::InvalidUninitLocal);
1103
3
      }
1104
31.1k
      return StackTrans({}, {TExpect.VType});
1105
31.1k
    } else if (Instr.getOpCode() == OpCode::Local__set) {
1106
13.0k
      if (!TExpect.IsInit) {
1107
46
        TExpect.IsInit = true;
1108
46
        LocalInits.push_back(Instr.getTargetIndex());
1109
46
      }
1110
13.0k
      return StackTrans({TExpect.VType}, {});
1111
13.0k
    } else if (Instr.getOpCode() == OpCode::Local__tee) {
1112
6.72k
      if (!TExpect.IsInit) {
1113
78
        TExpect.IsInit = true;
1114
78
        LocalInits.push_back(Instr.getTargetIndex());
1115
78
      }
1116
6.72k
      return StackTrans({TExpect.VType}, {TExpect.VType});
1117
6.72k
    } else {
1118
0
      assumingUnreachable();
1119
0
    }
1120
50.8k
  }
1121
17.2k
  case OpCode::Global__set:
1122
    // Global case, check mutation.
1123
17.2k
    if (Instr.getTargetIndex() < Globals.size() &&
1124
17.2k
        Globals[Instr.getTargetIndex()].second != ValMut::Var) {
1125
      // Global is immutable
1126
3
      spdlog::error(ErrCode::Value::ImmutableGlobal);
1127
3
      return Unexpect(ErrCode::Value::ImmutableGlobal);
1128
3
    }
1129
17.2k
    [[fallthrough]];
1130
37.1k
  case OpCode::Global__get: {
1131
37.1k
    if (Instr.getTargetIndex() >= Globals.size()) {
1132
75
      return logOutOfRange(
1133
75
          ErrCode::Value::InvalidGlobalIdx, ErrInfo::IndexCategory::Global,
1134
75
          Instr.getTargetIndex(), static_cast<uint32_t>(Globals.size()));
1135
75
    }
1136
37.0k
    ValType ExpT = Globals[Instr.getTargetIndex()].first;
1137
37.0k
    if (Instr.getOpCode() == OpCode::Global__set) {
1138
17.2k
      return StackTrans({ExpT}, {});
1139
19.8k
    } else {
1140
19.8k
      return StackTrans({}, {ExpT});
1141
19.8k
    }
1142
37.0k
  }
1143
1144
  // Table Instructions.
1145
261
  case OpCode::Table__get:
1146
261
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1147
246
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first)},
1148
246
                      {Tables[Instr.getTargetIndex()].second});
1149
450
  case OpCode::Table__set:
1150
450
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1151
434
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1152
434
                       Tables[Instr.getTargetIndex()].second},
1153
434
                      {});
1154
82
  case OpCode::Table__init:
1155
82
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1156
79
    EXPECTED_TRY(checkElemIdx(Instr.getSourceIndex()));
1157
    // Check whether the reference types match.
1158
72
    if (!AST::TypeMatcher::matchType(Types,
1159
72
                                     Tables[Instr.getTargetIndex()].second,
1160
72
                                     Elems[Instr.getSourceIndex()])) {
1161
2
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1162
2
      spdlog::error(ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()].second,
1163
2
                                          Elems[Instr.getSourceIndex()]));
1164
2
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1165
2
    }
1166
70
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1167
70
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
1168
70
                      {});
1169
4.71k
  case OpCode::Elem__drop:
1170
4.71k
    EXPECTED_TRY(checkElemIdx(Instr.getTargetIndex()));
1171
4.70k
    return {};
1172
297
  case OpCode::Table__copy: {
1173
297
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1174
288
    EXPECTED_TRY(checkTableIdx(Instr.getSourceIndex()));
1175
    // Check whether the reference types match.
1176
281
    if (!AST::TypeMatcher::matchType(Types,
1177
281
                                     Tables[Instr.getTargetIndex()].second,
1178
281
                                     Tables[Instr.getSourceIndex()].second)) {
1179
8
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1180
8
      spdlog::error(
1181
8
          ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()].second,
1182
8
                                Tables[Instr.getSourceIndex()].second));
1183
8
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1184
8
    }
1185
273
    auto ATDst = Tables[Instr.getTargetIndex()].first;
1186
273
    auto ATSrc = Tables[Instr.getSourceIndex()].first;
1187
273
    auto ATMin = convTypeCodeToAddrType(ATDst) <= convTypeCodeToAddrType(ATSrc)
1188
273
                     ? ATDst
1189
273
                     : ATSrc;
1190
273
    return StackTrans({ValType(ATDst), ValType(ATSrc), ValType(ATMin)}, {});
1191
281
  }
1192
170
  case OpCode::Table__grow:
1193
170
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1194
165
    return StackTrans({Tables[Instr.getTargetIndex()].second,
1195
165
                       ValType(Tables[Instr.getTargetIndex()].first)},
1196
165
                      {ValType(Tables[Instr.getTargetIndex()].first)});
1197
2.31k
  case OpCode::Table__size:
1198
2.31k
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1199
2.31k
    return StackTrans({}, {ValType(Tables[Instr.getTargetIndex()].first)});
1200
66
  case OpCode::Table__fill:
1201
66
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1202
64
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1203
64
                       Tables[Instr.getTargetIndex()].second,
1204
64
                       ValType(Tables[Instr.getTargetIndex()].first)},
1205
64
                      {});
1206
1207
  // Memory Instructions.
1208
6.38k
  case OpCode::I32__load:
1209
6.38k
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I32)});
1210
4.09k
  case OpCode::I64__load:
1211
4.09k
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::I64)});
1212
1.21k
  case OpCode::F32__load:
1213
1.21k
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::F32)});
1214
1.16k
  case OpCode::F64__load:
1215
1.16k
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::F64)});
1216
2.34k
  case OpCode::I32__load8_s:
1217
4.42k
  case OpCode::I32__load8_u:
1218
4.42k
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I32)});
1219
1.53k
  case OpCode::I32__load16_s:
1220
4.05k
  case OpCode::I32__load16_u:
1221
4.05k
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I32)});
1222
2.13k
  case OpCode::I64__load8_s:
1223
3.31k
  case OpCode::I64__load8_u:
1224
3.31k
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I64)});
1225
1.33k
  case OpCode::I64__load16_s:
1226
3.36k
  case OpCode::I64__load16_u:
1227
3.36k
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I64)});
1228
1.24k
  case OpCode::I64__load32_s:
1229
2.69k
  case OpCode::I64__load32_u:
1230
2.69k
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I64)});
1231
662
  case OpCode::I32__store:
1232
662
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, {});
1233
2.46k
  case OpCode::I64__store:
1234
2.46k
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, {});
1235
731
  case OpCode::F32__store:
1236
731
    return checkMemArgAndTrans(32, {ValType(TypeCode::F32)}, {});
1237
208
  case OpCode::F64__store:
1238
208
    return checkMemArgAndTrans(64, {ValType(TypeCode::F64)}, {});
1239
1.09k
  case OpCode::I32__store8:
1240
1.09k
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, {});
1241
802
  case OpCode::I32__store16:
1242
802
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, {});
1243
807
  case OpCode::I64__store8:
1244
807
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, {});
1245
864
  case OpCode::I64__store16:
1246
864
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, {});
1247
201
  case OpCode::I64__store32:
1248
201
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, {});
1249
6.05k
  case OpCode::Memory__size:
1250
6.05k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1251
6.03k
    return StackTrans({}, {ValType(Mems[Instr.getTargetIndex()])});
1252
9.26k
  case OpCode::Memory__grow:
1253
9.26k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1254
9.22k
    return StackTrans({ValType(Mems[Instr.getTargetIndex()])},
1255
9.22k
                      {ValType(Mems[Instr.getTargetIndex()])});
1256
39
  case OpCode::Memory__init:
1257
39
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1258
35
    EXPECTED_TRY(checkDataIdx(Instr.getSourceIndex()));
1259
31
    return StackTrans({ValType(Mems[Instr.getTargetIndex()]),
1260
31
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
1261
31
                      {});
1262
1.17k
  case OpCode::Data__drop:
1263
1.17k
    EXPECTED_TRY(checkDataIdx(Instr.getTargetIndex()));
1264
1.16k
    return {};
1265
380
  case OpCode::Memory__copy: {
1266
380
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1267
374
    EXPECTED_TRY(checkMemIdx(Instr.getSourceIndex()));
1268
370
    auto ATDst = Mems[Instr.getTargetIndex()];
1269
370
    auto ATSrc = Mems[Instr.getSourceIndex()];
1270
370
    auto ATMin = convTypeCodeToAddrType(ATDst) <= convTypeCodeToAddrType(ATSrc)
1271
370
                     ? ATDst
1272
370
                     : ATSrc;
1273
370
    return StackTrans({ValType(ATDst), ValType(ATSrc), ValType(ATMin)}, {});
1274
374
  }
1275
1.25k
  case OpCode::Memory__fill:
1276
1.25k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1277
1.24k
    return StackTrans({ValType(Mems[Instr.getTargetIndex()]),
1278
1.24k
                       ValType(TypeCode::I32),
1279
1.24k
                       ValType(Mems[Instr.getTargetIndex()])},
1280
1.24k
                      {});
1281
1282
  // Const Instructions.
1283
847k
  case OpCode::I32__const:
1284
847k
    return StackTrans({}, {ValType(TypeCode::I32)});
1285
129k
  case OpCode::I64__const:
1286
129k
    return StackTrans({}, {ValType(TypeCode::I64)});
1287
37.3k
  case OpCode::F32__const:
1288
37.3k
    return StackTrans({}, {ValType(TypeCode::F32)});
1289
24.9k
  case OpCode::F64__const:
1290
24.9k
    return StackTrans({}, {ValType(TypeCode::F64)});
1291
1292
  // Unary Numeric Instructions.
1293
14.4k
  case OpCode::I32__eqz:
1294
14.4k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1295
4.99k
  case OpCode::I64__eqz:
1296
4.99k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1297
5.56k
  case OpCode::I32__clz:
1298
9.97k
  case OpCode::I32__ctz:
1299
38.7k
  case OpCode::I32__popcnt:
1300
38.7k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1301
3.61k
  case OpCode::I64__clz:
1302
6.73k
  case OpCode::I64__ctz:
1303
14.3k
  case OpCode::I64__popcnt:
1304
14.3k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1305
2.44k
  case OpCode::F32__abs:
1306
5.22k
  case OpCode::F32__neg:
1307
12.0k
  case OpCode::F32__ceil:
1308
16.2k
  case OpCode::F32__floor:
1309
21.6k
  case OpCode::F32__trunc:
1310
24.0k
  case OpCode::F32__nearest:
1311
28.1k
  case OpCode::F32__sqrt:
1312
28.1k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F32)});
1313
2.35k
  case OpCode::F64__abs:
1314
4.73k
  case OpCode::F64__neg:
1315
10.0k
  case OpCode::F64__ceil:
1316
11.3k
  case OpCode::F64__floor:
1317
12.7k
  case OpCode::F64__trunc:
1318
13.9k
  case OpCode::F64__nearest:
1319
19.4k
  case OpCode::F64__sqrt:
1320
19.4k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F64)});
1321
1.21k
  case OpCode::I32__wrap_i64:
1322
1.21k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1323
2.44k
  case OpCode::I32__trunc_f32_s:
1324
3.74k
  case OpCode::I32__trunc_f32_u:
1325
3.74k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1326
2.00k
  case OpCode::I32__trunc_f64_s:
1327
3.98k
  case OpCode::I32__trunc_f64_u:
1328
3.98k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1329
3.75k
  case OpCode::I64__extend_i32_s:
1330
7.38k
  case OpCode::I64__extend_i32_u:
1331
7.38k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I64)});
1332
1.36k
  case OpCode::I64__trunc_f32_s:
1333
4.88k
  case OpCode::I64__trunc_f32_u:
1334
4.88k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1335
1.46k
  case OpCode::I64__trunc_f64_s:
1336
4.64k
  case OpCode::I64__trunc_f64_u:
1337
4.64k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1338
2.92k
  case OpCode::F32__convert_i32_s:
1339
4.77k
  case OpCode::F32__convert_i32_u:
1340
4.77k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1341
3.84k
  case OpCode::F32__convert_i64_s:
1342
7.30k
  case OpCode::F32__convert_i64_u:
1343
7.30k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F32)});
1344
1.15k
  case OpCode::F32__demote_f64:
1345
1.15k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F32)});
1346
3.47k
  case OpCode::F64__convert_i32_s:
1347
7.40k
  case OpCode::F64__convert_i32_u:
1348
7.40k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F64)});
1349
11.3k
  case OpCode::F64__convert_i64_s:
1350
12.3k
  case OpCode::F64__convert_i64_u:
1351
12.3k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)});
1352
832
  case OpCode::F64__promote_f32:
1353
832
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F64)});
1354
3.98k
  case OpCode::I32__reinterpret_f32:
1355
3.98k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1356
7.32k
  case OpCode::I64__reinterpret_f64:
1357
7.32k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1358
6.98k
  case OpCode::F32__reinterpret_i32:
1359
6.98k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1360
2.73k
  case OpCode::F64__reinterpret_i64:
1361
2.73k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)});
1362
4.93k
  case OpCode::I32__extend8_s:
1363
11.3k
  case OpCode::I32__extend16_s:
1364
11.3k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1365
4.12k
  case OpCode::I64__extend8_s:
1366
9.88k
  case OpCode::I64__extend16_s:
1367
12.8k
  case OpCode::I64__extend32_s:
1368
12.8k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1369
924
  case OpCode::I32__trunc_sat_f32_s:
1370
1.47k
  case OpCode::I32__trunc_sat_f32_u:
1371
1.47k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1372
1.62k
  case OpCode::I32__trunc_sat_f64_s:
1373
4.36k
  case OpCode::I32__trunc_sat_f64_u:
1374
4.36k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1375
1.36k
  case OpCode::I64__trunc_sat_f32_s:
1376
2.11k
  case OpCode::I64__trunc_sat_f32_u:
1377
2.11k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1378
719
  case OpCode::I64__trunc_sat_f64_s:
1379
1.84k
  case OpCode::I64__trunc_sat_f64_u:
1380
1.84k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1381
1382
  // Binary Numeric Instructions.
1383
2.05k
  case OpCode::I32__eq:
1384
4.18k
  case OpCode::I32__ne:
1385
8.64k
  case OpCode::I32__lt_s:
1386
17.9k
  case OpCode::I32__lt_u:
1387
21.0k
  case OpCode::I32__gt_s:
1388
31.0k
  case OpCode::I32__gt_u:
1389
35.4k
  case OpCode::I32__le_s:
1390
38.0k
  case OpCode::I32__le_u:
1391
41.0k
  case OpCode::I32__ge_s:
1392
43.4k
  case OpCode::I32__ge_u:
1393
43.4k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1394
43.4k
                      {ValType(TypeCode::I32)});
1395
559
  case OpCode::I64__eq:
1396
1.40k
  case OpCode::I64__ne:
1397
2.87k
  case OpCode::I64__lt_s:
1398
3.66k
  case OpCode::I64__lt_u:
1399
5.25k
  case OpCode::I64__gt_s:
1400
5.61k
  case OpCode::I64__gt_u:
1401
7.22k
  case OpCode::I64__le_s:
1402
9.68k
  case OpCode::I64__le_u:
1403
10.3k
  case OpCode::I64__ge_s:
1404
11.8k
  case OpCode::I64__ge_u:
1405
11.8k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1406
11.8k
                      {ValType(TypeCode::I32)});
1407
1.02k
  case OpCode::F32__eq:
1408
1.69k
  case OpCode::F32__ne:
1409
2.74k
  case OpCode::F32__lt:
1410
3.35k
  case OpCode::F32__gt:
1411
3.98k
  case OpCode::F32__le:
1412
4.93k
  case OpCode::F32__ge:
1413
4.93k
    return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)},
1414
4.93k
                      {ValType(TypeCode::I32)});
1415
2.25k
  case OpCode::F64__eq:
1416
3.27k
  case OpCode::F64__ne:
1417
4.50k
  case OpCode::F64__lt:
1418
6.19k
  case OpCode::F64__gt:
1419
6.57k
  case OpCode::F64__le:
1420
7.43k
  case OpCode::F64__ge:
1421
7.43k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1422
7.43k
                      {ValType(TypeCode::I32)});
1423
3.18k
  case OpCode::I32__add:
1424
9.27k
  case OpCode::I32__sub:
1425
11.8k
  case OpCode::I32__mul:
1426
15.1k
  case OpCode::I32__div_s:
1427
21.5k
  case OpCode::I32__div_u:
1428
24.3k
  case OpCode::I32__rem_s:
1429
27.2k
  case OpCode::I32__rem_u:
1430
28.9k
  case OpCode::I32__and:
1431
33.4k
  case OpCode::I32__or:
1432
42.8k
  case OpCode::I32__xor:
1433
47.1k
  case OpCode::I32__shl:
1434
50.8k
  case OpCode::I32__shr_s:
1435
57.3k
  case OpCode::I32__shr_u:
1436
62.0k
  case OpCode::I32__rotl:
1437
64.7k
  case OpCode::I32__rotr:
1438
64.7k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1439
64.7k
                      {ValType(TypeCode::I32)});
1440
3.44k
  case OpCode::I64__add:
1441
6.18k
  case OpCode::I64__sub:
1442
8.10k
  case OpCode::I64__mul:
1443
9.27k
  case OpCode::I64__div_s:
1444
13.2k
  case OpCode::I64__div_u:
1445
14.4k
  case OpCode::I64__rem_s:
1446
16.2k
  case OpCode::I64__rem_u:
1447
18.3k
  case OpCode::I64__and:
1448
19.8k
  case OpCode::I64__or:
1449
28.8k
  case OpCode::I64__xor:
1450
29.9k
  case OpCode::I64__shl:
1451
31.5k
  case OpCode::I64__shr_s:
1452
32.7k
  case OpCode::I64__shr_u:
1453
35.9k
  case OpCode::I64__rotl:
1454
39.6k
  case OpCode::I64__rotr:
1455
39.6k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1456
39.6k
                      {ValType(TypeCode::I64)});
1457
1.19k
  case OpCode::F32__add:
1458
3.66k
  case OpCode::F32__sub:
1459
6.86k
  case OpCode::F32__mul:
1460
7.82k
  case OpCode::F32__div:
1461
8.76k
  case OpCode::F32__min:
1462
10.4k
  case OpCode::F32__max:
1463
11.9k
  case OpCode::F32__copysign:
1464
11.9k
    return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)},
1465
11.9k
                      {ValType(TypeCode::F32)});
1466
1.00k
  case OpCode::F64__add:
1467
3.45k
  case OpCode::F64__sub:
1468
4.54k
  case OpCode::F64__mul:
1469
5.68k
  case OpCode::F64__div:
1470
7.14k
  case OpCode::F64__min:
1471
9.18k
  case OpCode::F64__max:
1472
11.0k
  case OpCode::F64__copysign:
1473
11.0k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1474
11.0k
                      {ValType(TypeCode::F64)});
1475
1476
  // SIMD Memory Instruction.
1477
9.30k
  case OpCode::V128__load:
1478
9.30k
    return checkMemArgAndTrans(128, {}, {ValType(TypeCode::V128)});
1479
1.00k
  case OpCode::V128__load8x8_s:
1480
1.29k
  case OpCode::V128__load8x8_u:
1481
2.01k
  case OpCode::V128__load16x4_s:
1482
3.83k
  case OpCode::V128__load16x4_u:
1483
4.46k
  case OpCode::V128__load32x2_s:
1484
4.85k
  case OpCode::V128__load32x2_u:
1485
5.49k
  case OpCode::V128__load64_splat:
1486
5.74k
  case OpCode::V128__load64_zero:
1487
5.74k
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::V128)});
1488
618
  case OpCode::V128__load8_splat:
1489
618
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::V128)});
1490
817
  case OpCode::V128__load16_splat:
1491
817
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::V128)});
1492
526
  case OpCode::V128__load32_splat:
1493
879
  case OpCode::V128__load32_zero:
1494
879
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::V128)});
1495
646
  case OpCode::V128__store:
1496
646
    return checkMemArgAndTrans(128, {ValType(TypeCode::V128)}, {});
1497
351
  case OpCode::V128__load8_lane:
1498
351
    return checkMemArgAndTrans(8, {ValType(TypeCode::V128)},
1499
351
                               {ValType(TypeCode::V128)}, true);
1500
1.24k
  case OpCode::V128__load16_lane:
1501
1.24k
    return checkMemArgAndTrans(16, {ValType(TypeCode::V128)},
1502
1.24k
                               {ValType(TypeCode::V128)}, true);
1503
236
  case OpCode::V128__load32_lane:
1504
236
    return checkMemArgAndTrans(32, {ValType(TypeCode::V128)},
1505
236
                               {ValType(TypeCode::V128)}, true);
1506
434
  case OpCode::V128__load64_lane:
1507
434
    return checkMemArgAndTrans(64, {ValType(TypeCode::V128)},
1508
434
                               {ValType(TypeCode::V128)}, true);
1509
558
  case OpCode::V128__store8_lane:
1510
558
    return checkMemArgAndTrans(8, {ValType(TypeCode::V128)}, {}, true);
1511
137
  case OpCode::V128__store16_lane:
1512
137
    return checkMemArgAndTrans(16, {ValType(TypeCode::V128)}, {}, true);
1513
822
  case OpCode::V128__store32_lane:
1514
822
    return checkMemArgAndTrans(32, {ValType(TypeCode::V128)}, {}, true);
1515
285
  case OpCode::V128__store64_lane:
1516
285
    return checkMemArgAndTrans(64, {ValType(TypeCode::V128)}, {}, true);
1517
1518
  // SIMD Const Instruction.
1519
7.39k
  case OpCode::V128__const:
1520
7.39k
    return StackTrans({}, {ValType(TypeCode::V128)});
1521
1522
  // SIMD Shuffle Instruction.
1523
370
  case OpCode::I8x16__shuffle: {
1524
    // Check that all lane indices are less than 32 by masking.
1525
370
    const uint128_t Mask = (uint128_t(0xe0e0e0e0e0e0e0e0U) << 64U) |
1526
370
                           uint128_t(0xe0e0e0e0e0e0e0e0U);
1527
370
    const uint128_t Result = Instr.getNum().get<uint128_t>() & Mask;
1528
370
    if (Result) {
1529
13
      spdlog::error(ErrCode::Value::InvalidLaneIdx);
1530
13
      return Unexpect(ErrCode::Value::InvalidLaneIdx);
1531
13
    }
1532
357
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1533
357
                      {ValType(TypeCode::V128)});
1534
370
  }
1535
1536
  // SIMD Lane Instructions.
1537
1.09k
  case OpCode::I8x16__extract_lane_s:
1538
1.34k
  case OpCode::I8x16__extract_lane_u:
1539
1.34k
    return checkLaneAndTrans(16, {ValType(TypeCode::V128)},
1540
1.34k
                             {ValType(TypeCode::I32)});
1541
1.16k
  case OpCode::I8x16__replace_lane:
1542
1.16k
    return checkLaneAndTrans(16,
1543
1.16k
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1544
1.16k
                             {ValType(TypeCode::V128)});
1545
1.05k
  case OpCode::I16x8__extract_lane_s:
1546
1.95k
  case OpCode::I16x8__extract_lane_u:
1547
1.95k
    return checkLaneAndTrans(8, {ValType(TypeCode::V128)},
1548
1.95k
                             {ValType(TypeCode::I32)});
1549
561
  case OpCode::I16x8__replace_lane:
1550
561
    return checkLaneAndTrans(8,
1551
561
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1552
561
                             {ValType(TypeCode::V128)});
1553
1.62k
  case OpCode::I32x4__extract_lane:
1554
1.62k
    return checkLaneAndTrans(4, {ValType(TypeCode::V128)},
1555
1.62k
                             {ValType(TypeCode::I32)});
1556
682
  case OpCode::I32x4__replace_lane:
1557
682
    return checkLaneAndTrans(4,
1558
682
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1559
682
                             {ValType(TypeCode::V128)});
1560
376
  case OpCode::I64x2__extract_lane:
1561
376
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1562
376
                             {ValType(TypeCode::I64)});
1563
778
  case OpCode::I64x2__replace_lane:
1564
778
    return checkLaneAndTrans(2,
1565
778
                             {ValType(TypeCode::V128), ValType(TypeCode::I64)},
1566
778
                             {ValType(TypeCode::V128)});
1567
659
  case OpCode::F32x4__extract_lane:
1568
659
    return checkLaneAndTrans(4, {ValType(TypeCode::V128)},
1569
659
                             {ValType(TypeCode::F32)});
1570
184
  case OpCode::F32x4__replace_lane:
1571
184
    return checkLaneAndTrans(4,
1572
184
                             {ValType(TypeCode::V128), ValType(TypeCode::F32)},
1573
184
                             {ValType(TypeCode::V128)});
1574
617
  case OpCode::F64x2__extract_lane:
1575
617
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1576
617
                             {ValType(TypeCode::F64)});
1577
202
  case OpCode::F64x2__replace_lane:
1578
202
    return checkLaneAndTrans(2,
1579
202
                             {ValType(TypeCode::V128), ValType(TypeCode::F64)},
1580
202
                             {ValType(TypeCode::V128)});
1581
1582
  // SIMD Numeric Instructions.
1583
57.3k
  case OpCode::I8x16__splat:
1584
70.4k
  case OpCode::I16x8__splat:
1585
73.0k
  case OpCode::I32x4__splat:
1586
73.0k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::V128)});
1587
1.43k
  case OpCode::I64x2__splat:
1588
1.43k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::V128)});
1589
885
  case OpCode::F32x4__splat:
1590
885
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::V128)});
1591
889
  case OpCode::F64x2__splat:
1592
889
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::V128)});
1593
1.16k
  case OpCode::V128__not:
1594
3.98k
  case OpCode::I8x16__abs:
1595
8.00k
  case OpCode::I8x16__neg:
1596
9.20k
  case OpCode::I8x16__popcnt:
1597
10.6k
  case OpCode::I16x8__abs:
1598
12.2k
  case OpCode::I16x8__neg:
1599
14.5k
  case OpCode::I16x8__extend_low_i8x16_s:
1600
15.1k
  case OpCode::I16x8__extend_high_i8x16_s:
1601
16.1k
  case OpCode::I16x8__extend_low_i8x16_u:
1602
16.5k
  case OpCode::I16x8__extend_high_i8x16_u:
1603
17.6k
  case OpCode::I16x8__extadd_pairwise_i8x16_s:
1604
19.4k
  case OpCode::I16x8__extadd_pairwise_i8x16_u:
1605
20.2k
  case OpCode::I32x4__abs:
1606
20.9k
  case OpCode::I32x4__neg:
1607
23.0k
  case OpCode::I32x4__extend_low_i16x8_s:
1608
24.2k
  case OpCode::I32x4__extend_high_i16x8_s:
1609
27.6k
  case OpCode::I32x4__extend_low_i16x8_u:
1610
28.2k
  case OpCode::I32x4__extend_high_i16x8_u:
1611
30.4k
  case OpCode::I32x4__extadd_pairwise_i16x8_s:
1612
33.1k
  case OpCode::I32x4__extadd_pairwise_i16x8_u:
1613
34.7k
  case OpCode::I64x2__abs:
1614
36.0k
  case OpCode::I64x2__neg:
1615
37.6k
  case OpCode::I64x2__extend_low_i32x4_s:
1616
39.2k
  case OpCode::I64x2__extend_high_i32x4_s:
1617
39.8k
  case OpCode::I64x2__extend_low_i32x4_u:
1618
41.3k
  case OpCode::I64x2__extend_high_i32x4_u:
1619
41.6k
  case OpCode::F32x4__abs:
1620
44.8k
  case OpCode::F32x4__neg:
1621
45.4k
  case OpCode::F32x4__sqrt:
1622
46.1k
  case OpCode::F64x2__abs:
1623
47.5k
  case OpCode::F64x2__neg:
1624
47.9k
  case OpCode::F64x2__sqrt:
1625
49.2k
  case OpCode::I32x4__trunc_sat_f32x4_s:
1626
55.3k
  case OpCode::I32x4__trunc_sat_f32x4_u:
1627
56.0k
  case OpCode::F32x4__convert_i32x4_s:
1628
57.3k
  case OpCode::F32x4__convert_i32x4_u:
1629
58.6k
  case OpCode::I32x4__trunc_sat_f64x2_s_zero:
1630
62.2k
  case OpCode::I32x4__trunc_sat_f64x2_u_zero:
1631
63.7k
  case OpCode::F64x2__convert_low_i32x4_s:
1632
65.7k
  case OpCode::F64x2__convert_low_i32x4_u:
1633
67.3k
  case OpCode::F32x4__demote_f64x2_zero:
1634
69.5k
  case OpCode::F64x2__promote_low_f32x4:
1635
71.4k
  case OpCode::F32x4__ceil:
1636
75.0k
  case OpCode::F32x4__floor:
1637
78.2k
  case OpCode::F32x4__trunc:
1638
79.3k
  case OpCode::F32x4__nearest:
1639
80.7k
  case OpCode::F64x2__ceil:
1640
82.8k
  case OpCode::F64x2__floor:
1641
83.9k
  case OpCode::F64x2__trunc:
1642
84.5k
  case OpCode::F64x2__nearest:
1643
84.5k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)});
1644
917
  case OpCode::I8x16__swizzle:
1645
1.62k
  case OpCode::I8x16__eq:
1646
2.33k
  case OpCode::I8x16__ne:
1647
2.83k
  case OpCode::I8x16__lt_s:
1648
3.20k
  case OpCode::I8x16__lt_u:
1649
4.65k
  case OpCode::I8x16__gt_s:
1650
5.05k
  case OpCode::I8x16__gt_u:
1651
5.47k
  case OpCode::I8x16__le_s:
1652
5.91k
  case OpCode::I8x16__le_u:
1653
7.32k
  case OpCode::I8x16__ge_s:
1654
7.71k
  case OpCode::I8x16__ge_u:
1655
8.41k
  case OpCode::I16x8__eq:
1656
9.25k
  case OpCode::I16x8__ne:
1657
9.87k
  case OpCode::I16x8__lt_s:
1658
11.3k
  case OpCode::I16x8__lt_u:
1659
12.4k
  case OpCode::I16x8__gt_s:
1660
13.7k
  case OpCode::I16x8__gt_u:
1661
14.2k
  case OpCode::I16x8__le_s:
1662
14.6k
  case OpCode::I16x8__le_u:
1663
15.3k
  case OpCode::I16x8__ge_s:
1664
16.1k
  case OpCode::I16x8__ge_u:
1665
16.5k
  case OpCode::I32x4__eq:
1666
16.8k
  case OpCode::I32x4__ne:
1667
17.8k
  case OpCode::I32x4__lt_s:
1668
18.1k
  case OpCode::I32x4__lt_u:
1669
18.5k
  case OpCode::I32x4__gt_s:
1670
19.5k
  case OpCode::I32x4__gt_u:
1671
21.1k
  case OpCode::I32x4__le_s:
1672
21.6k
  case OpCode::I32x4__le_u:
1673
21.7k
  case OpCode::I32x4__ge_s:
1674
22.4k
  case OpCode::I32x4__ge_u:
1675
22.8k
  case OpCode::I64x2__eq:
1676
23.3k
  case OpCode::I64x2__ne:
1677
23.9k
  case OpCode::I64x2__lt_s:
1678
24.2k
  case OpCode::I64x2__gt_s:
1679
24.5k
  case OpCode::I64x2__le_s:
1680
25.4k
  case OpCode::I64x2__ge_s:
1681
28.3k
  case OpCode::F32x4__eq:
1682
28.6k
  case OpCode::F32x4__ne:
1683
29.4k
  case OpCode::F32x4__lt:
1684
29.8k
  case OpCode::F32x4__gt:
1685
30.7k
  case OpCode::F32x4__le:
1686
31.0k
  case OpCode::F32x4__ge:
1687
32.7k
  case OpCode::F64x2__eq:
1688
33.0k
  case OpCode::F64x2__ne:
1689
34.7k
  case OpCode::F64x2__lt:
1690
36.4k
  case OpCode::F64x2__gt:
1691
36.8k
  case OpCode::F64x2__le:
1692
37.6k
  case OpCode::F64x2__ge:
1693
37.9k
  case OpCode::V128__and:
1694
38.3k
  case OpCode::V128__andnot:
1695
38.8k
  case OpCode::V128__or:
1696
40.8k
  case OpCode::V128__xor:
1697
41.6k
  case OpCode::I8x16__narrow_i16x8_s:
1698
42.2k
  case OpCode::I8x16__narrow_i16x8_u:
1699
42.7k
  case OpCode::I8x16__add:
1700
43.7k
  case OpCode::I8x16__add_sat_s:
1701
44.1k
  case OpCode::I8x16__add_sat_u:
1702
45.0k
  case OpCode::I8x16__sub:
1703
46.1k
  case OpCode::I8x16__sub_sat_s:
1704
46.3k
  case OpCode::I8x16__sub_sat_u:
1705
46.7k
  case OpCode::I8x16__min_s:
1706
48.1k
  case OpCode::I8x16__min_u:
1707
48.8k
  case OpCode::I8x16__max_s:
1708
49.5k
  case OpCode::I8x16__max_u:
1709
50.2k
  case OpCode::I8x16__avgr_u:
1710
50.6k
  case OpCode::I16x8__narrow_i32x4_s:
1711
51.4k
  case OpCode::I16x8__narrow_i32x4_u:
1712
52.1k
  case OpCode::I16x8__add:
1713
52.3k
  case OpCode::I16x8__add_sat_s:
1714
53.3k
  case OpCode::I16x8__add_sat_u:
1715
54.1k
  case OpCode::I16x8__sub:
1716
55.0k
  case OpCode::I16x8__sub_sat_s:
1717
56.3k
  case OpCode::I16x8__sub_sat_u:
1718
57.0k
  case OpCode::I16x8__mul:
1719
57.6k
  case OpCode::I16x8__min_s:
1720
58.1k
  case OpCode::I16x8__min_u:
1721
58.6k
  case OpCode::I16x8__max_s:
1722
59.9k
  case OpCode::I16x8__max_u:
1723
60.2k
  case OpCode::I16x8__avgr_u:
1724
60.6k
  case OpCode::I16x8__extmul_low_i8x16_s:
1725
61.3k
  case OpCode::I16x8__extmul_high_i8x16_s:
1726
61.6k
  case OpCode::I16x8__extmul_low_i8x16_u:
1727
62.4k
  case OpCode::I16x8__extmul_high_i8x16_u:
1728
62.9k
  case OpCode::I16x8__q15mulr_sat_s:
1729
63.4k
  case OpCode::I32x4__add:
1730
63.5k
  case OpCode::I32x4__sub:
1731
63.9k
  case OpCode::I32x4__mul:
1732
64.2k
  case OpCode::I32x4__min_s:
1733
64.6k
  case OpCode::I32x4__min_u:
1734
64.9k
  case OpCode::I32x4__max_s:
1735
65.2k
  case OpCode::I32x4__max_u:
1736
65.6k
  case OpCode::I32x4__extmul_low_i16x8_s:
1737
66.0k
  case OpCode::I32x4__extmul_high_i16x8_s:
1738
66.4k
  case OpCode::I32x4__extmul_low_i16x8_u:
1739
66.8k
  case OpCode::I32x4__extmul_high_i16x8_u:
1740
67.4k
  case OpCode::I64x2__add:
1741
67.9k
  case OpCode::I64x2__sub:
1742
68.5k
  case OpCode::I64x2__mul:
1743
68.8k
  case OpCode::I64x2__extmul_low_i32x4_s:
1744
69.7k
  case OpCode::I64x2__extmul_high_i32x4_s:
1745
70.3k
  case OpCode::I64x2__extmul_low_i32x4_u:
1746
71.3k
  case OpCode::I64x2__extmul_high_i32x4_u:
1747
73.1k
  case OpCode::F32x4__add:
1748
73.9k
  case OpCode::F32x4__sub:
1749
74.7k
  case OpCode::F32x4__mul:
1750
75.1k
  case OpCode::F32x4__div:
1751
75.6k
  case OpCode::F32x4__min:
1752
76.2k
  case OpCode::F32x4__max:
1753
78.9k
  case OpCode::F32x4__pmin:
1754
79.4k
  case OpCode::F32x4__pmax:
1755
79.5k
  case OpCode::F64x2__add:
1756
80.8k
  case OpCode::F64x2__sub:
1757
81.2k
  case OpCode::F64x2__mul:
1758
81.5k
  case OpCode::F64x2__div:
1759
81.9k
  case OpCode::F64x2__min:
1760
82.2k
  case OpCode::F64x2__max:
1761
82.9k
  case OpCode::F64x2__pmin:
1762
83.5k
  case OpCode::F64x2__pmax:
1763
83.9k
  case OpCode::I32x4__dot_i16x8_s:
1764
83.9k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1765
83.9k
                      {ValType(TypeCode::V128)});
1766
339
  case OpCode::V128__bitselect:
1767
339
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1768
339
                       ValType(TypeCode::V128)},
1769
339
                      {ValType(TypeCode::V128)});
1770
258
  case OpCode::V128__any_true:
1771
854
  case OpCode::I8x16__all_true:
1772
2.01k
  case OpCode::I8x16__bitmask:
1773
2.63k
  case OpCode::I16x8__all_true:
1774
3.16k
  case OpCode::I16x8__bitmask:
1775
4.09k
  case OpCode::I32x4__all_true:
1776
5.79k
  case OpCode::I32x4__bitmask:
1777
6.80k
  case OpCode::I64x2__all_true:
1778
7.37k
  case OpCode::I64x2__bitmask:
1779
7.37k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::I32)});
1780
617
  case OpCode::I8x16__shl:
1781
2.38k
  case OpCode::I8x16__shr_s:
1782
3.08k
  case OpCode::I8x16__shr_u:
1783
3.26k
  case OpCode::I16x8__shl:
1784
3.80k
  case OpCode::I16x8__shr_s:
1785
4.04k
  case OpCode::I16x8__shr_u:
1786
5.66k
  case OpCode::I32x4__shl:
1787
6.02k
  case OpCode::I32x4__shr_s:
1788
6.85k
  case OpCode::I32x4__shr_u:
1789
7.10k
  case OpCode::I64x2__shl:
1790
8.31k
  case OpCode::I64x2__shr_s:
1791
8.45k
  case OpCode::I64x2__shr_u:
1792
8.45k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::I32)},
1793
8.45k
                      {ValType(TypeCode::V128)});
1794
1795
114
  case OpCode::I8x16__relaxed_swizzle:
1796
114
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1797
114
                      {ValType(TypeCode::V128)});
1798
84
  case OpCode::I32x4__relaxed_trunc_f32x4_s:
1799
466
  case OpCode::I32x4__relaxed_trunc_f32x4_u:
1800
707
  case OpCode::I32x4__relaxed_trunc_f64x2_s_zero:
1801
818
  case OpCode::I32x4__relaxed_trunc_f64x2_u_zero:
1802
818
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)});
1803
102
  case OpCode::F32x4__relaxed_madd:
1804
288
  case OpCode::F32x4__relaxed_nmadd:
1805
342
  case OpCode::F64x2__relaxed_madd:
1806
418
  case OpCode::F64x2__relaxed_nmadd:
1807
496
  case OpCode::I8x16__relaxed_laneselect:
1808
605
  case OpCode::I16x8__relaxed_laneselect:
1809
756
  case OpCode::I32x4__relaxed_laneselect:
1810
962
  case OpCode::I64x2__relaxed_laneselect:
1811
962
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1812
962
                       ValType(TypeCode::V128)},
1813
962
                      {ValType(TypeCode::V128)});
1814
273
  case OpCode::F32x4__relaxed_min:
1815
377
  case OpCode::F32x4__relaxed_max:
1816
425
  case OpCode::F64x2__relaxed_min:
1817
530
  case OpCode::F64x2__relaxed_max:
1818
614
  case OpCode::I16x8__relaxed_q15mulr_s:
1819
878
  case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s:
1820
878
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1821
878
                      {ValType(TypeCode::V128)});
1822
58
  case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s:
1823
58
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1824
58
                       ValType(TypeCode::V128)},
1825
58
                      {ValType(TypeCode::V128)});
1826
1827
512
  case OpCode::Atomic__fence:
1828
512
    return {};
1829
1830
154
  case OpCode::Memory__atomic__notify:
1831
154
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1832
154
                               {ValType(TypeCode::I32)});
1833
86
  case OpCode::Memory__atomic__wait32:
1834
86
    return checkMemArgAndTrans(32,
1835
86
                               {ValType(TypeCode::I32), ValType(TypeCode::I64)},
1836
86
                               {ValType(TypeCode::I32)});
1837
85
  case OpCode::Memory__atomic__wait64:
1838
85
    return checkMemArgAndTrans(64,
1839
85
                               {ValType(TypeCode::I64), ValType(TypeCode::I64)},
1840
85
                               {ValType(TypeCode::I32)});
1841
1842
0
  case OpCode::I32__atomic__load:
1843
0
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I32)});
1844
0
  case OpCode::I64__atomic__load:
1845
0
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::I64)});
1846
0
  case OpCode::I32__atomic__load8_u:
1847
0
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I32)});
1848
0
  case OpCode::I32__atomic__load16_u:
1849
0
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I32)});
1850
0
  case OpCode::I64__atomic__load8_u:
1851
0
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I64)});
1852
0
  case OpCode::I64__atomic__load16_u:
1853
0
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I64)});
1854
0
  case OpCode::I64__atomic__load32_u:
1855
0
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I64)});
1856
0
  case OpCode::I32__atomic__store:
1857
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, {});
1858
0
  case OpCode::I64__atomic__store:
1859
0
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, {});
1860
0
  case OpCode::I32__atomic__store8:
1861
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, {});
1862
0
  case OpCode::I32__atomic__store16:
1863
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, {});
1864
0
  case OpCode::I64__atomic__store8:
1865
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, {});
1866
0
  case OpCode::I64__atomic__store16:
1867
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, {});
1868
0
  case OpCode::I64__atomic__store32:
1869
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, {});
1870
0
  case OpCode::I32__atomic__rmw__add:
1871
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1872
0
                               {ValType(TypeCode::I32)});
1873
0
  case OpCode::I64__atomic__rmw__add:
1874
0
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)},
1875
0
                               {ValType(TypeCode::I64)});
1876
0
  case OpCode::I32__atomic__rmw8__add_u:
1877
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)},
1878
0
                               {ValType(TypeCode::I32)});
1879
0
  case OpCode::I32__atomic__rmw16__add_u:
1880
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)},
1881
0
                               {ValType(TypeCode::I32)});
1882
0
  case OpCode::I64__atomic__rmw8__add_u:
1883
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)},
1884
0
                               {ValType(TypeCode::I64)});
1885
0
  case OpCode::I64__atomic__rmw16__add_u:
1886
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)},
1887
0
                               {ValType(TypeCode::I64)});
1888
0
  case OpCode::I64__atomic__rmw32__add_u:
1889
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)},
1890
0
                               {ValType(TypeCode::I64)});
1891
0
  case OpCode::I32__atomic__rmw__sub:
1892
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1893
0
                               {ValType(TypeCode::I32)});
1894
0
  case OpCode::I64__atomic__rmw__sub:
1895
0
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)},
1896
0
                               {ValType(TypeCode::I64)});
1897
0
  case OpCode::I32__atomic__rmw8__sub_u:
1898
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)},
1899
0
                               {ValType(TypeCode::I32)});
1900
0
  case OpCode::I32__atomic__rmw16__sub_u:
1901
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)},
1902
0
                               {ValType(TypeCode::I32)});
1903
0
  case OpCode::I64__atomic__rmw8__sub_u:
1904
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)},
1905
0
                               {ValType(TypeCode::I64)});
1906
0
  case OpCode::I64__atomic__rmw16__sub_u:
1907
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)},
1908
0
                               {ValType(TypeCode::I64)});
1909
0
  case OpCode::I64__atomic__rmw32__sub_u:
1910
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)},
1911
0
                               {ValType(TypeCode::I64)});
1912
0
  case OpCode::I32__atomic__rmw__and:
1913
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1914
0
                               {ValType(TypeCode::I32)});
1915
0
  case OpCode::I64__atomic__rmw__and:
1916
0
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)},
1917
0
                               {ValType(TypeCode::I64)});
1918
0
  case OpCode::I32__atomic__rmw8__and_u:
1919
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)},
1920
0
                               {ValType(TypeCode::I32)});
1921
0
  case OpCode::I32__atomic__rmw16__and_u:
1922
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)},
1923
0
                               {ValType(TypeCode::I32)});
1924
0
  case OpCode::I64__atomic__rmw8__and_u:
1925
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)},
1926
0
                               {ValType(TypeCode::I64)});
1927
0
  case OpCode::I64__atomic__rmw16__and_u:
1928
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)},
1929
0
                               {ValType(TypeCode::I64)});
1930
0
  case OpCode::I64__atomic__rmw32__and_u:
1931
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)},
1932
0
                               {ValType(TypeCode::I64)});
1933
0
  case OpCode::I32__atomic__rmw__or:
1934
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1935
0
                               {ValType(TypeCode::I32)});
1936
0
  case OpCode::I64__atomic__rmw__or:
1937
0
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)},
1938
0
                               {ValType(TypeCode::I64)});
1939
0
  case OpCode::I32__atomic__rmw8__or_u:
1940
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)},
1941
0
                               {ValType(TypeCode::I32)});
1942
0
  case OpCode::I32__atomic__rmw16__or_u:
1943
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)},
1944
0
                               {ValType(TypeCode::I32)});
1945
0
  case OpCode::I64__atomic__rmw8__or_u:
1946
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)},
1947
0
                               {ValType(TypeCode::I64)});
1948
0
  case OpCode::I64__atomic__rmw16__or_u:
1949
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)},
1950
0
                               {ValType(TypeCode::I64)});
1951
0
  case OpCode::I64__atomic__rmw32__or_u:
1952
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)},
1953
0
                               {ValType(TypeCode::I64)});
1954
0
  case OpCode::I32__atomic__rmw__xor:
1955
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1956
0
                               {ValType(TypeCode::I32)});
1957
0
  case OpCode::I64__atomic__rmw__xor:
1958
0
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)},
1959
0
                               {ValType(TypeCode::I64)});
1960
0
  case OpCode::I32__atomic__rmw8__xor_u:
1961
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)},
1962
0
                               {ValType(TypeCode::I32)});
1963
0
  case OpCode::I32__atomic__rmw16__xor_u:
1964
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)},
1965
0
                               {ValType(TypeCode::I32)});
1966
0
  case OpCode::I64__atomic__rmw8__xor_u:
1967
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)},
1968
0
                               {ValType(TypeCode::I64)});
1969
0
  case OpCode::I64__atomic__rmw16__xor_u:
1970
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)},
1971
0
                               {ValType(TypeCode::I64)});
1972
0
  case OpCode::I64__atomic__rmw32__xor_u:
1973
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)},
1974
0
                               {ValType(TypeCode::I64)});
1975
0
  case OpCode::I32__atomic__rmw__xchg:
1976
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1977
0
                               {ValType(TypeCode::I32)});
1978
0
  case OpCode::I64__atomic__rmw__xchg:
1979
0
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)},
1980
0
                               {ValType(TypeCode::I64)});
1981
0
  case OpCode::I32__atomic__rmw8__xchg_u:
1982
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)},
1983
0
                               {ValType(TypeCode::I32)});
1984
0
  case OpCode::I32__atomic__rmw16__xchg_u:
1985
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)},
1986
0
                               {ValType(TypeCode::I32)});
1987
0
  case OpCode::I64__atomic__rmw8__xchg_u:
1988
0
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)},
1989
0
                               {ValType(TypeCode::I64)});
1990
0
  case OpCode::I64__atomic__rmw16__xchg_u:
1991
0
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)},
1992
0
                               {ValType(TypeCode::I64)});
1993
0
  case OpCode::I64__atomic__rmw32__xchg_u:
1994
0
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)},
1995
0
                               {ValType(TypeCode::I64)});
1996
0
  case OpCode::I32__atomic__rmw__cmpxchg:
1997
0
    return checkMemArgAndTrans(32,
1998
0
                               {ValType(TypeCode::I32), ValType(TypeCode::I32)},
1999
0
                               {ValType(TypeCode::I32)});
2000
0
  case OpCode::I64__atomic__rmw__cmpxchg:
2001
0
    return checkMemArgAndTrans(64,
2002
0
                               {ValType(TypeCode::I64), ValType(TypeCode::I64)},
2003
0
                               {ValType(TypeCode::I64)});
2004
0
  case OpCode::I32__atomic__rmw8__cmpxchg_u:
2005
0
    return checkMemArgAndTrans(8,
2006
0
                               {ValType(TypeCode::I32), ValType(TypeCode::I32)},
2007
0
                               {ValType(TypeCode::I32)});
2008
0
  case OpCode::I32__atomic__rmw16__cmpxchg_u:
2009
0
    return checkMemArgAndTrans(16,
2010
0
                               {ValType(TypeCode::I32), ValType(TypeCode::I32)},
2011
0
                               {ValType(TypeCode::I32)});
2012
0
  case OpCode::I64__atomic__rmw8__cmpxchg_u:
2013
0
    return checkMemArgAndTrans(8,
2014
0
                               {ValType(TypeCode::I64), ValType(TypeCode::I64)},
2015
0
                               {ValType(TypeCode::I64)});
2016
0
  case OpCode::I64__atomic__rmw16__cmpxchg_u:
2017
0
    return checkMemArgAndTrans(16,
2018
0
                               {ValType(TypeCode::I64), ValType(TypeCode::I64)},
2019
0
                               {ValType(TypeCode::I64)});
2020
0
  case OpCode::I64__atomic__rmw32__cmpxchg_u:
2021
0
    return checkMemArgAndTrans(32,
2022
0
                               {ValType(TypeCode::I64), ValType(TypeCode::I64)},
2023
0
                               {ValType(TypeCode::I64)});
2024
2025
0
  default:
2026
0
    assumingUnreachable();
2027
2.50M
  }
2028
2.50M
}
2029
2030
2.02M
void FormChecker::pushType(VType V) { ValStack.emplace_back(V); }
2031
2032
22.5k
void FormChecker::pushTypes(Span<const VType> Input) {
2033
22.5k
  for (auto Val : Input) {
2034
10.0k
    pushType(Val);
2035
10.0k
  }
2036
22.5k
}
2037
2038
2.12M
void FormChecker::pushTypes(Span<const ValType> Input) {
2039
2.12M
  for (auto Val : Input) {
2040
2.00M
    pushType(Val);
2041
2.00M
  }
2042
2.12M
}
2043
2044
2.22M
Expect<VType> FormChecker::popType() {
2045
2.22M
  if (ValStack.size() == CtrlStack.back().Height) {
2046
299k
    if (CtrlStack.back().IsUnreachable) {
2047
299k
      return unreachableVType();
2048
299k
    }
2049
    // Value stack underflow
2050
442
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2051
442
    spdlog::error("    Value stack underflow."sv);
2052
442
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2053
299k
  }
2054
1.93M
  auto T = std::move(ValStack.back());
2055
1.93M
  ValStack.pop_back();
2056
1.93M
  return T;
2057
2.22M
}
2058
2059
1.29M
Expect<VType> FormChecker::popType(ValType E) {
2060
1.29M
  EXPECTED_TRY(auto Type, popType());
2061
1.29M
  if (Type == unreachableVType()) {
2062
299k
    return E;
2063
299k
  }
2064
2065
994k
  if (!AST::TypeMatcher::matchType(Types, E, *Type)) {
2066
    // The expected value on the value stack does not match.
2067
1.57k
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2068
1.57k
    spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(E), VTypeToAST(Type)));
2069
1.57k
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2070
1.57k
  }
2071
993k
  return Type;
2072
994k
}
2073
2074
2.08M
Expect<void> FormChecker::popTypes(Span<const ValType> Input) {
2075
3.28M
  for (auto Val = Input.rbegin(); Val != Input.rend(); ++Val) {
2076
1.20M
    EXPECTED_TRY(popType(*Val));
2077
1.20M
  }
2078
2.08M
  return {};
2079
2.08M
}
2080
2081
void FormChecker::pushCtrl(Span<const ValType> In, Span<const ValType> Out,
2082
85.4k
                           const AST::Instruction *Jump, OpCode Code) {
2083
85.4k
  CtrlStack.emplace_back(In, Out, Jump, ValStack.size(), LocalInits.size(),
2084
85.4k
                         Code);
2085
85.4k
  pushTypes(In);
2086
85.4k
}
2087
2088
79.9k
Expect<FormChecker::CtrlFrame> FormChecker::popCtrl() {
2089
79.9k
  if (CtrlStack.empty()) {
2090
    // Ctrl stack is empty when popping.
2091
0
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2092
0
    spdlog::error("    Control stack underflow."sv);
2093
0
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2094
0
  }
2095
79.9k
  EXPECTED_TRY(popTypes(CtrlStack.back().EndTypes));
2096
79.6k
  if (ValStack.size() != CtrlStack.back().Height) {
2097
    // Value stack size does not match.
2098
110
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2099
110
    spdlog::error("    Value stack underflow."sv);
2100
110
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2101
110
  }
2102
  // When popping a frame, reset the locals initialized during this frame.
2103
79.6k
  for (size_t I = CtrlStack.back().InitedLocal; I < LocalInits.size(); I++) {
2104
106
    Locals[LocalInits[I]].IsInit = false;
2105
106
  }
2106
79.5k
  LocalInits.erase(LocalInits.begin() +
2107
79.5k
                       static_cast<uint32_t>(CtrlStack.back().InitedLocal),
2108
79.5k
                   LocalInits.end());
2109
79.5k
  auto Head = std::move(CtrlStack.back());
2110
79.5k
  CtrlStack.pop_back();
2111
79.5k
  return Head;
2112
79.6k
}
2113
2114
Span<const ValType>
2115
57.8k
FormChecker::getLabelTypes(const FormChecker::CtrlFrame &F) {
2116
57.8k
  if (F.Code == OpCode::Loop) {
2117
15.0k
    return F.StartTypes;
2118
15.0k
  }
2119
42.8k
  return F.EndTypes;
2120
57.8k
}
2121
2122
304k
Expect<void> FormChecker::unreachable() {
2123
1.20M
  while (ValStack.size() > CtrlStack.back().Height) {
2124
902k
    EXPECTED_TRY(popType());
2125
902k
  }
2126
304k
  CtrlStack.back().IsUnreachable = true;
2127
304k
  return {};
2128
304k
}
2129
2130
Expect<void> FormChecker::StackTrans(Span<const ValType> Take,
2131
1.90M
                                     Span<const ValType> Put) {
2132
1.90M
  EXPECTED_TRY(popTypes(Take));
2133
1.89M
  pushTypes(Put);
2134
1.89M
  return {};
2135
1.90M
}
2136
2137
12.6k
Expect<void> FormChecker::StackPopAny() {
2138
12.6k
  EXPECTED_TRY(popType());
2139
12.6k
  return {};
2140
12.6k
}
2141
2142
} // namespace Validator
2143
} // namespace WasmEdge