Coverage Report

Created: 2025-08-25 06:58

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