Coverage Report

Created: 2025-07-23 06:30

/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
248
                   uint32_t Bound) {
22
248
  spdlog::error(Code);
23
248
  spdlog::error(ErrInfo::InfoForbidIndex(Cate, Idx, Bound));
24
248
  return Unexpect(Code);
25
248
}
26
27
} // namespace
28
29
17.9k
void FormChecker::reset(bool CleanGlobal) {
30
17.9k
  ValStack.clear();
31
17.9k
  CtrlStack.clear();
32
17.9k
  Locals.clear();
33
17.9k
  Returns.clear();
34
35
17.9k
  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.9k
}
49
50
Expect<void> FormChecker::validate(AST::InstrView Instrs,
51
14.4k
                                   Span<const ValType> RetVals) {
52
14.4k
  for (const ValType &Val : RetVals) {
53
12.2k
    Returns.push_back(Val);
54
12.2k
  }
55
14.4k
  return checkExpr(Instrs);
56
14.4k
}
57
58
12.1M
Expect<void> FormChecker::validate(const ValType &VT) const noexcept {
59
  // The value type should be validated for the type index case.
60
12.1M
  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
12.1M
  return {};
70
12.1M
}
71
72
5.78k
void FormChecker::addType(const AST::SubType &Type) { Types.push_back(&Type); }
73
74
17.5k
void FormChecker::addFunc(const uint32_t TypeIdx, const bool IsImport) {
75
17.5k
  if (Types.size() > TypeIdx) {
76
17.5k
    Funcs.emplace_back(TypeIdx);
77
17.5k
  }
78
17.5k
  if (IsImport) {
79
321
    NumImportFuncs++;
80
321
  }
81
17.5k
}
82
83
329
void FormChecker::addTable(const AST::TableType &Tab) {
84
329
  Tables.push_back(Tab.getRefType());
85
329
}
86
87
1.34k
void FormChecker::addMemory(const AST::MemoryType &) { Mems++; }
88
89
248
void FormChecker::addGlobal(const AST::GlobalType &Glob, const bool IsImport) {
90
  // Type in global is confirmed in loading phase.
91
248
  Globals.emplace_back(Glob.getValType(), Glob.getValMut());
92
248
  if (IsImport) {
93
54
    NumImportGlobals++;
94
54
  }
95
248
}
96
97
306
void FormChecker::addData(const AST::DataSegment &) {
98
306
  Datas.emplace_back(static_cast<uint32_t>(Datas.size()));
99
306
}
100
101
515
void FormChecker::addElem(const AST::ElementSegment &Elem) {
102
515
  Elems.emplace_back(Elem.getRefType());
103
515
}
104
105
12.7k
void FormChecker::addRef(const uint32_t FuncIdx) { Refs.emplace(FuncIdx); }
106
107
12.1M
void FormChecker::addLocal(const ValType &V, bool Initialized) {
108
12.1M
  Locals.emplace_back(V);
109
12.1M
  if (Initialized || V.isDefaultable()) {
110
12.1M
    LocalInits.push_back(static_cast<uint32_t>(Locals.size() - 1));
111
12.1M
    Locals.back().IsInit = true;
112
12.1M
  }
113
12.1M
}
114
115
0
void FormChecker::addTag(const uint32_t TypeIdx) { Tags.push_back(TypeIdx); }
116
117
1.00k
ValType FormChecker::VTypeToAST(const VType &V) {
118
1.00k
  if (!V) {
119
0
    return TypeCode::I32;
120
0
  }
121
1.00k
  return *V;
122
1.00k
}
123
124
14.4k
Expect<void> FormChecker::checkExpr(AST::InstrView Instrs) {
125
14.4k
  if (Instrs.size() > 0) {
126
    // Push ctrl frame ([] -> [Returns])
127
14.4k
    pushCtrl({}, Returns, &*Instrs.rbegin());
128
14.4k
    return checkInstrs(Instrs);
129
14.4k
  }
130
0
  return {};
131
14.4k
}
132
133
14.4k
Expect<void> FormChecker::checkInstrs(AST::InstrView Instrs) {
134
  // Validate instructions
135
1.85M
  for (auto &Instr : Instrs) {
136
1.85M
    EXPECTED_TRY(checkInstr(Instr).map_error([&Instr](auto E) {
137
1.85M
      spdlog::error(
138
1.85M
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
139
1.85M
      return E;
140
1.85M
    }));
141
1.85M
  }
142
13.2k
  return {};
143
14.4k
}
144
145
1.85M
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.85M
  auto checkDefinedType =
151
1.85M
      [this](uint32_t TIdx, TypeCode TC) -> Expect<const AST::CompositeType *> {
152
4.03k
    if (TIdx >= Types.size()) {
153
13
      return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx,
154
13
                           ErrInfo::IndexCategory::FunctionType, TIdx,
155
13
                           static_cast<uint32_t>(Types.size()));
156
13
    }
157
4.02k
    const auto &CType = Types[TIdx]->getCompositeType();
158
4.02k
    if (CType.getContentTypeCode() == TC) {
159
4.02k
      return &CType;
160
4.02k
    } else {
161
0
      spdlog::error(ErrCode::Value::TypeCheckFailed);
162
0
      return Unexpect(ErrCode::Value::TypeCheckFailed);
163
0
    }
164
4.02k
  };
165
166
  // Helper lambda for checking and resolve the block type.
167
1.85M
  auto checkBlockType = [this, checkDefinedType](std::vector<ValType> &Buffer,
168
1.85M
                                                 const BlockType &BType)
169
1.85M
      -> Expect<std::pair<Span<const ValType>, Span<const ValType>>> {
170
8.58k
    using ReturnType = std::pair<Span<const ValType>, Span<const ValType>>;
171
8.58k
    if (BType.isEmpty()) {
172
      // Empty case. t2* = none
173
2.33k
      return ReturnType{{}, {}};
174
6.24k
    } else if (BType.isValType()) {
175
      // ValType case. t2* = valtype
176
3.01k
      EXPECTED_TRY(validate(BType.getValType()));
177
3.01k
      Buffer[0] = BType.getValType();
178
3.01k
      return ReturnType{{}, Buffer};
179
3.23k
    } else {
180
      // Type index case. t2* = functype.returns.
181
3.23k
      EXPECTED_TRY(auto CompType,
182
3.22k
                   checkDefinedType(BType.getTypeIndex(), TypeCode::Func));
183
3.22k
      const auto &FType = CompType->getFuncType();
184
3.22k
      return ReturnType{FType.getParamTypes(), FType.getReturnTypes()};
185
3.23k
    }
186
8.58k
  };
187
188
  // Helper lambda for checking control stack depth and return index.
189
1.85M
  auto checkCtrlStackDepth = [this](uint32_t N) -> Expect<uint32_t> {
190
    // Check the control stack for at least N + 1 frames.
191
42.2k
    if (N >= CtrlStack.size()) {
192
      // Branch out of stack.
193
43
      return logOutOfRange(ErrCode::Value::InvalidLabelIdx,
194
43
                           ErrInfo::IndexCategory::Label, N,
195
43
                           static_cast<uint32_t>(CtrlStack.size()));
196
43
    }
197
    // Return the index of the last N element.
198
42.1k
    return static_cast<uint32_t>(CtrlStack.size()) - UINT32_C(1) - N;
199
42.2k
  };
200
201
  // Helper lambda for checking memory index and perform transformation.
202
1.85M
  auto checkMemAndTrans = [this,
203
1.85M
                           &Instr](Span<const ValType> Take,
204
1.85M
                                   Span<const ValType> Put) -> Expect<void> {
205
5.14k
    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.13k
    return StackTrans(Take, Put);
211
5.14k
  };
212
213
  // Helper lambda for checking lane index and perform transformation.
214
1.85M
  auto checkLaneAndTrans = [this,
215
1.85M
                            &Instr](uint32_t N, Span<const ValType> Take,
216
1.85M
                                    Span<const ValType> Put) -> Expect<void> {
217
11.5k
    if (Instr.getMemoryLane() >= N) {
218
25
      return logOutOfRange(ErrCode::Value::InvalidLaneIdx,
219
25
                           ErrInfo::IndexCategory::Lane, Instr.getMemoryLane(),
220
25
                           N);
221
25
    }
222
11.5k
    return StackTrans(Take, Put);
223
11.5k
  };
224
225
  // Helper lambda for checking memory alignment and perform transformation.
226
1.85M
  auto checkAlignAndTrans = [this, checkLaneAndTrans,
227
1.85M
                             &Instr](uint32_t N, Span<const ValType> Take,
228
1.85M
                                     Span<const ValType> Put,
229
1.85M
                                     bool CheckLane = false) -> Expect<void> {
230
44.9k
    if (Instr.getTargetIndex() >= Mems) {
231
33
      return logOutOfRange(ErrCode::Value::InvalidMemoryIdx,
232
33
                           ErrInfo::IndexCategory::Memory,
233
33
                           Instr.getTargetIndex(), Mems);
234
33
    }
235
44.9k
    auto IsAtomic = Instr.getOpCode() >= OpCode::Memory__atomic__notify &&
236
44.9k
                    Instr.getOpCode() <= OpCode::I64__atomic__rmw32__cmpxchg_u;
237
44.9k
    if (Instr.getMemoryAlign() > 31 ||
238
44.9k
        (!IsAtomic && (1UL << Instr.getMemoryAlign()) > (N >> 3UL))) {
239
      // 2 ^ align needs to <= N / 8
240
14
      spdlog::error(ErrCode::Value::AlignmentTooLarge);
241
14
      spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3),
242
14
                                          Instr.getMemoryAlign()));
243
14
      return Unexpect(ErrCode::Value::AlignmentTooLarge);
244
14
    }
245
44.9k
    if (IsAtomic && (1UL << Instr.getMemoryAlign()) != (N >> 3UL)) {
246
      // 2 ^ align needs to == N / 8
247
36
      spdlog::error(ErrCode::Value::InvalidAlignment);
248
36
      spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3),
249
36
                                          Instr.getMemoryAlign()));
250
36
      return Unexpect(ErrCode::Value::InvalidAlignment);
251
36
    }
252
44.8k
    if (CheckLane) {
253
3.77k
      return checkLaneAndTrans(128 / N, Take, Put);
254
3.77k
    }
255
41.1k
    return StackTrans(Take, Put);
256
44.8k
  };
257
258
  // Helper lambda for checking value types matching.
259
1.85M
  auto checkTypesMatching = [this](Span<const ValType> Exp,
260
1.85M
                                   Span<const ValType> Got) -> Expect<void> {
261
1.02k
    if (!AST::TypeMatcher::matchTypes(Types, Exp, Got)) {
262
8
      std::vector<ValType> ExpV(Exp.begin(), Exp.end()),
263
8
          GotV(Got.begin(), Got.end());
264
8
      spdlog::error(ErrCode::Value::TypeCheckFailed);
265
8
      spdlog::error(ErrInfo::InfoMismatch(ExpV, GotV));
266
8
      return Unexpect(ErrCode::Value::TypeCheckFailed);
267
8
    }
268
1.01k
    return {};
269
1.02k
  };
270
271
  // Helper lambda for recording jump data.
272
1.85M
  auto recordJump = [this, &Instr](AST::Instruction::JumpDescriptor &Jump,
273
1.85M
                                   uint32_t Arity, uint32_t D) -> void {
274
42.1k
    const uint32_t Remain =
275
42.1k
        static_cast<uint32_t>(ValStack.size() - CtrlStack[D].Height);
276
42.1k
    Jump.StackEraseBegin = Remain + Arity;
277
42.1k
    Jump.StackEraseEnd = Arity;
278
42.1k
    Jump.PCOffset = static_cast<int32_t>(CtrlStack[D].Jump - &Instr);
279
42.1k
  };
280
281
  // Helper lambda for unpacking a value type.
282
1.85M
  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.85M
  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.85M
  switch (Instr.getOpCode()) {
321
  // Control instructions.
322
205k
  case OpCode::Unreachable:
323
205k
    return unreachable();
324
99.0k
  case OpCode::Nop:
325
99.0k
    return {};
326
327
4.29k
  case OpCode::Block:
328
5.97k
  case OpCode::Loop:
329
8.58k
  case OpCode::If:
330
  // LEGACY-EH: remove the `Try` case after deprecating legacy EH.
331
8.58k
  case OpCode::Try:
332
8.58k
  case OpCode::Try_table: {
333
    // Get blocktype [t1*] -> [t2*] and check valtype first.
334
8.58k
    std::vector<ValType> Buffer(1);
335
    // LEGACY-EH: remove the `Try` case after deprecating legacy EH.
336
8.58k
    const auto &BType = (Instr.getOpCode() == OpCode::Try ||
337
8.58k
                         Instr.getOpCode() == OpCode::Try_table)
338
8.58k
                            ? Instr.getTryCatch().ResType
339
8.58k
                            : Instr.getBlockType();
340
8.58k
    EXPECTED_TRY(auto T1T2, checkBlockType(Buffer, BType));
341
8.57k
    auto [T1, T2] = T1T2;
342
    // For the if instruction, pop I32 first.
343
8.57k
    if (Instr.getOpCode() == OpCode::If) {
344
2.60k
      EXPECTED_TRY(popType(TypeCode::I32));
345
2.60k
    }
346
    // Pop and check [t1*]
347
8.56k
    EXPECTED_TRY(popTypes(T1));
348
    // For the try_table instruction, validate the handlers.
349
8.56k
    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
8.56k
    } 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
8.56k
    const AST::Instruction *From = Instr.getOpCode() == OpCode::Loop
391
8.56k
                                       ? &Instr
392
8.56k
                                       : &Instr + Instr.getJumpEnd();
393
8.56k
    pushCtrl(T1, T2, From, Instr.getOpCode());
394
8.56k
    if (Instr.getOpCode() == OpCode::If &&
395
8.56k
        Instr.getJumpElse() == Instr.getJumpEnd()) {
396
      // No else case in if-else statement.
397
1.02k
      EXPECTED_TRY(checkTypesMatching(T2, T1));
398
1.02k
    }
399
8.56k
    return {};
400
8.56k
  }
401
402
1.57k
  case OpCode::Else: {
403
1.57k
    EXPECTED_TRY(auto Ctrl, popCtrl());
404
1.57k
    pushCtrl(Ctrl.StartTypes, Ctrl.EndTypes, Ctrl.Jump, Instr.getOpCode());
405
1.57k
    return {};
406
1.57k
  }
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
21.7k
  case OpCode::End: {
459
21.7k
    EXPECTED_TRY(auto Ctrl, popCtrl());
460
21.6k
    pushTypes(Ctrl.EndTypes);
461
21.6k
    return {};
462
21.7k
  }
463
464
2.21k
  case OpCode::Br: {
465
2.21k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
466
    // D is the last D element of control stack.
467
2.20k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
468
2.20k
    EXPECTED_TRY(popTypes(NTypes));
469
2.20k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
470
2.20k
               static_cast<uint32_t>(NTypes.size()), D);
471
2.20k
    return unreachable();
472
2.20k
  }
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.00k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
478
1.00k
    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.00k
  }
484
1.61k
  case OpCode::Br_table: {
485
1.61k
    EXPECTED_TRY(popType(TypeCode::I32));
486
1.60k
    auto LabelTable = const_cast<AST::Instruction &>(Instr).getLabelList();
487
1.60k
    const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
488
1.60k
    EXPECTED_TRY(auto M,
489
1.59k
                 checkCtrlStackDepth(LabelTable[LabelTableSize].TargetIndex));
490
    // M is the last M element of control stack.
491
1.59k
    auto MTypes = getLabelTypes(CtrlStack[M]);
492
38.9k
    for (uint32_t LabelIdx = 0; LabelIdx < LabelTableSize; ++LabelIdx) {
493
37.3k
      const uint32_t L = LabelTable[LabelIdx].TargetIndex;
494
37.3k
      EXPECTED_TRY(auto N, checkCtrlStackDepth(L));
495
      // N is the last N element of control stack.
496
37.3k
      const auto NTypes = getLabelTypes(CtrlStack[N]);
497
37.3k
      if (MTypes.size() != NTypes.size()) {
498
2
        return checkTypesMatching(MTypes, NTypes);
499
2
      }
500
      // Push the popped types.
501
37.3k
      std::vector<VType> TypeBuf(NTypes.size());
502
41.5k
      for (uint32_t IdxN = static_cast<uint32_t>(NTypes.size()); IdxN >= 1;
503
37.3k
           --IdxN) {
504
4.16k
        const uint32_t Idx = IdxN - 1;
505
        // Cannot use popTypes() here because we need the popped value.
506
4.16k
        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.16k
        if (CtrlStack.back().IsUnreachable) {
511
575
          TypeBuf[Idx] = unreachableVType();
512
3.59k
        } else {
513
3.59k
          TypeBuf[Idx] = Type;
514
3.59k
        }
515
4.16k
      }
516
37.3k
      recordJump(LabelTable[LabelIdx], static_cast<uint32_t>(NTypes.size()), N);
517
37.3k
      pushTypes(TypeBuf);
518
37.3k
    }
519
1.57k
    const auto NTypes = getLabelTypes(CtrlStack[M]);
520
1.57k
    EXPECTED_TRY(popTypes(NTypes));
521
1.57k
    recordJump(LabelTable[LabelTableSize], static_cast<uint32_t>(NTypes.size()),
522
1.57k
               M);
523
1.57k
    return unreachable();
524
1.57k
  }
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.28k
  case OpCode::Return:
573
2.28k
    EXPECTED_TRY(popTypes(Returns));
574
2.28k
    return unreachable();
575
576
4.76k
  case OpCode::Call: {
577
4.76k
    auto N = Instr.getTargetIndex();
578
4.76k
    if (unlikely(N >= Funcs.size())) {
579
23
      return logOutOfRange(ErrCode::Value::InvalidFuncIdx,
580
23
                           ErrInfo::IndexCategory::Function, N,
581
23
                           static_cast<uint32_t>(Funcs.size()));
582
23
    }
583
    // Due to validation when adding functions, Type[Funcs[N]] must be a
584
    // function type.
585
4.74k
    auto &FuncType = Types[Funcs[N]]->getCompositeType().getFuncType();
586
4.74k
    return StackTrans(FuncType.getParamTypes(), FuncType.getReturnTypes());
587
4.76k
  }
588
820
  case OpCode::Call_indirect: {
589
820
    auto N = Instr.getTargetIndex();
590
820
    auto T = Instr.getSourceIndex();
591
    // Check source table index.
592
820
    if (unlikely(T >= Tables.size())) {
593
17
      return logOutOfRange(ErrCode::Value::InvalidTableIdx,
594
17
                           ErrInfo::IndexCategory::Table, T,
595
17
                           static_cast<uint32_t>(Tables.size()));
596
17
    }
597
803
    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.60k
    EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func));
604
1.60k
    EXPECTED_TRY(popType(TypeCode::I32));
605
799
    const auto &FType = CompType->getFuncType();
606
799
    return StackTrans(FType.getParamTypes(), FType.getReturnTypes());
607
1.60k
  }
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.88k
  case OpCode::Ref__null: {
687
1.88k
    EXPECTED_TRY(validate(Instr.getValType()));
688
1.88k
    return StackTrans({}, {Instr.getValType()});
689
1.88k
  }
690
923
  case OpCode::Ref__is_null: {
691
923
    EXPECTED_TRY(auto Type, popType());
692
921
    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
918
    return StackTrans({}, {ValType(TypeCode::I32)});
698
921
  }
699
1.13k
  case OpCode::Ref__func: {
700
1.13k
    auto FuncIdx = Instr.getTargetIndex();
701
1.13k
    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.10k
    assuming(FuncIdx < Funcs.size());
707
1.10k
    auto TypeIdx = Funcs[FuncIdx];
708
1.10k
    assuming(TypeIdx < Types.size());
709
1.10k
    return StackTrans({}, {ValType(TypeCode::Ref, TypeIdx)});
710
1.10k
  }
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.24k
  case OpCode::Drop:
1034
7.24k
    return StackPopAny();
1035
3.33k
  case OpCode::Select: {
1036
    // Pop I32.
1037
3.33k
    EXPECTED_TRY(popType(TypeCode::I32));
1038
    // Pop T1 and T2.
1039
6.66k
    EXPECTED_TRY(VType T1, popType());
1040
6.66k
    EXPECTED_TRY(VType T2, popType());
1041
    // T1 and T2 should be number type.
1042
3.32k
    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.32k
    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.32k
    if (T1 != T2 && T1 != unreachableVType() && T2 != unreachableVType()) {
1054
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1055
3
      spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(T1), VTypeToAST(T2)));
1056
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1057
3
    }
1058
    // Push value.
1059
3.32k
    if (T1 == unreachableVType()) {
1060
1.80k
      pushType(T2);
1061
1.80k
    } else {
1062
1.51k
      pushType(T1);
1063
1.51k
    }
1064
3.32k
    return {};
1065
3.32k
  }
1066
603
  case OpCode::Select_t: {
1067
    // Note: There may be multiple values choice in the future.
1068
603
    if (Instr.getValTypeList().size() != 1) {
1069
5
      spdlog::error(ErrCode::Value::InvalidResultArity);
1070
5
      return Unexpect(ErrCode::Value::InvalidResultArity);
1071
5
    }
1072
598
    ValType ExpT = Instr.getValTypeList()[0];
1073
598
    EXPECTED_TRY(validate(ExpT));
1074
598
    EXPECTED_TRY(popTypes({ExpT, ExpT, ValType(TypeCode::I32)}));
1075
596
    pushType(ExpT);
1076
596
    return {};
1077
598
  }
1078
1079
  // Variable Instructions.
1080
12.8k
  case OpCode::Local__get:
1081
18.0k
  case OpCode::Local__set:
1082
24.8k
  case OpCode::Local__tee: {
1083
24.8k
    if (Instr.getTargetIndex() >= Locals.size()) {
1084
26
      return logOutOfRange(
1085
26
          ErrCode::Value::InvalidLocalIdx, ErrInfo::IndexCategory::Local,
1086
26
          Instr.getTargetIndex(), static_cast<uint32_t>(Locals.size()));
1087
26
    }
1088
24.8k
    auto &TExpect = Locals[Instr.getTargetIndex()];
1089
24.8k
    const_cast<AST::Instruction &>(Instr).getStackOffset() =
1090
24.8k
        static_cast<uint32_t>(ValStack.size() +
1091
24.8k
                              (Locals.size() - Instr.getTargetIndex()));
1092
24.8k
    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.14k
      if (!TExpect.IsInit) {
1100
0
        TExpect.IsInit = true;
1101
0
        LocalInits.push_back(Instr.getTargetIndex());
1102
0
      }
1103
5.14k
      return StackTrans({TExpect.VType}, {});
1104
6.84k
    } else if (Instr.getOpCode() == OpCode::Local__tee) {
1105
6.84k
      if (!TExpect.IsInit) {
1106
0
        TExpect.IsInit = true;
1107
0
        LocalInits.push_back(Instr.getTargetIndex());
1108
0
      }
1109
6.84k
      return StackTrans({TExpect.VType}, {TExpect.VType});
1110
6.84k
    } else {
1111
0
      assumingUnreachable();
1112
0
    }
1113
24.8k
  }
1114
75
  case OpCode::Global__set:
1115
    // Global case, check mutation.
1116
75
    if (Instr.getTargetIndex() < Globals.size() &&
1117
75
        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
74
    [[fallthrough]];
1123
405
  case OpCode::Global__get: {
1124
405
    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
384
    ValType ExpT = Globals[Instr.getTargetIndex()].first;
1130
384
    if (Instr.getOpCode() == OpCode::Global__set) {
1131
60
      return StackTrans({ExpT}, {});
1132
324
    } else {
1133
324
      return StackTrans({}, {ExpT});
1134
324
    }
1135
384
  }
1136
1137
  // Table Instructions.
1138
99
  case OpCode::Table__get:
1139
336
  case OpCode::Table__set:
1140
403
  case OpCode::Table__grow:
1141
451
  case OpCode::Table__size:
1142
490
  case OpCode::Table__fill:
1143
534
  case OpCode::Table__init:
1144
705
  case OpCode::Table__copy: {
1145
    // Check target table index to perform.
1146
705
    if (Instr.getTargetIndex() >= Tables.size()) {
1147
16
      return logOutOfRange(
1148
16
          ErrCode::Value::InvalidTableIdx, ErrInfo::IndexCategory::Table,
1149
16
          Instr.getTargetIndex(), static_cast<uint32_t>(Tables.size()));
1150
16
    }
1151
689
    ValType ExpT = Tables[Instr.getTargetIndex()];
1152
689
    if (Instr.getOpCode() == OpCode::Table__get) {
1153
92
      return StackTrans({ValType(TypeCode::I32)}, {ExpT});
1154
597
    } else if (Instr.getOpCode() == OpCode::Table__set) {
1155
234
      return StackTrans({ValType(TypeCode::I32), ExpT}, {});
1156
363
    } else if (Instr.getOpCode() == OpCode::Table__grow) {
1157
64
      return StackTrans({ExpT, ValType(TypeCode::I32)},
1158
64
                        {ValType(TypeCode::I32)});
1159
299
    } else if (Instr.getOpCode() == OpCode::Table__size) {
1160
48
      return StackTrans({}, {ValType(TypeCode::I32)});
1161
251
    } else if (Instr.getOpCode() == OpCode::Table__fill) {
1162
39
      return StackTrans({ValType(TypeCode::I32), ExpT, ValType(TypeCode::I32)},
1163
39
                        {});
1164
212
    } else if (Instr.getOpCode() == OpCode::Table__init) {
1165
      // Check source element index for initialization.
1166
43
      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
40
      if (!AST::TypeMatcher::matchType(Types, Tables[Instr.getTargetIndex()],
1173
40
                                       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
38
      return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32),
1180
38
                         ValType(TypeCode::I32)},
1181
38
                        {});
1182
169
    } else if (Instr.getOpCode() == OpCode::Table__copy) {
1183
      // Check source table index for copying.
1184
169
      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
165
      if (!AST::TypeMatcher::matchType(Types, Tables[Instr.getTargetIndex()],
1191
165
                                       Tables[Instr.getSourceIndex()])) {
1192
1
        spdlog::error(ErrCode::Value::TypeCheckFailed);
1193
1
        spdlog::error(ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()],
1194
1
                                            Tables[Instr.getSourceIndex()]));
1195
1
        return Unexpect(ErrCode::Value::TypeCheckFailed);
1196
1
      }
1197
164
      return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32),
1198
164
                         ValType(TypeCode::I32)},
1199
164
                        {});
1200
165
    } else {
1201
0
      assumingUnreachable();
1202
0
    }
1203
689
  }
1204
52
  case OpCode::Elem__drop:
1205
    // Check target element index to drop.
1206
52
    if (Instr.getTargetIndex() >= Elems.size()) {
1207
6
      return logOutOfRange(
1208
6
          ErrCode::Value::InvalidElemIdx, ErrInfo::IndexCategory::Element,
1209
6
          Instr.getTargetIndex(), static_cast<uint32_t>(Elems.size()));
1210
6
    }
1211
46
    return {};
1212
1213
  // Memory Instructions.
1214
1.63k
  case OpCode::I32__load:
1215
1.63k
    return checkAlignAndTrans(32, {ValType(TypeCode::I32)},
1216
1.63k
                              {ValType(TypeCode::I32)});
1217
4.10k
  case OpCode::I64__load:
1218
4.10k
    return checkAlignAndTrans(64, {ValType(TypeCode::I32)},
1219
4.10k
                              {ValType(TypeCode::I64)});
1220
219
  case OpCode::F32__load:
1221
219
    return checkAlignAndTrans(32, {ValType(TypeCode::I32)},
1222
219
                              {ValType(TypeCode::F32)});
1223
847
  case OpCode::F64__load:
1224
847
    return checkAlignAndTrans(64, {ValType(TypeCode::I32)},
1225
847
                              {ValType(TypeCode::F64)});
1226
1.29k
  case OpCode::I32__load8_s:
1227
1.56k
  case OpCode::I32__load8_u:
1228
1.56k
    return checkAlignAndTrans(8, {ValType(TypeCode::I32)},
1229
1.56k
                              {ValType(TypeCode::I32)});
1230
977
  case OpCode::I32__load16_s:
1231
2.92k
  case OpCode::I32__load16_u:
1232
2.92k
    return checkAlignAndTrans(16, {ValType(TypeCode::I32)},
1233
2.92k
                              {ValType(TypeCode::I32)});
1234
1.22k
  case OpCode::I64__load8_s:
1235
1.96k
  case OpCode::I64__load8_u:
1236
1.96k
    return checkAlignAndTrans(8, {ValType(TypeCode::I32)},
1237
1.96k
                              {ValType(TypeCode::I64)});
1238
1.13k
  case OpCode::I64__load16_s:
1239
2.96k
  case OpCode::I64__load16_u:
1240
2.96k
    return checkAlignAndTrans(16, {ValType(TypeCode::I32)},
1241
2.96k
                              {ValType(TypeCode::I64)});
1242
900
  case OpCode::I64__load32_s:
1243
2.16k
  case OpCode::I64__load32_u:
1244
2.16k
    return checkAlignAndTrans(32, {ValType(TypeCode::I32)},
1245
2.16k
                              {ValType(TypeCode::I64)});
1246
683
  case OpCode::I32__store:
1247
683
    return checkAlignAndTrans(
1248
683
        32, {ValType(TypeCode::I32), ValType(TypeCode::I32)}, {});
1249
2.56k
  case OpCode::I64__store:
1250
2.56k
    return checkAlignAndTrans(
1251
2.56k
        64, {ValType(TypeCode::I32), ValType(TypeCode::I64)}, {});
1252
582
  case OpCode::F32__store:
1253
582
    return checkAlignAndTrans(
1254
582
        32, {ValType(TypeCode::I32), ValType(TypeCode::F32)}, {});
1255
322
  case OpCode::F64__store:
1256
322
    return checkAlignAndTrans(
1257
322
        64, {ValType(TypeCode::I32), ValType(TypeCode::F64)}, {});
1258
1.06k
  case OpCode::I32__store8:
1259
1.06k
    return checkAlignAndTrans(
1260
1.06k
        8, {ValType(TypeCode::I32), ValType(TypeCode::I32)}, {});
1261
381
  case OpCode::I32__store16:
1262
381
    return checkAlignAndTrans(
1263
381
        16, {ValType(TypeCode::I32), ValType(TypeCode::I32)}, {});
1264
170
  case OpCode::I64__store8:
1265
170
    return checkAlignAndTrans(
1266
170
        8, {ValType(TypeCode::I32), ValType(TypeCode::I64)}, {});
1267
367
  case OpCode::I64__store16:
1268
367
    return checkAlignAndTrans(
1269
367
        16, {ValType(TypeCode::I32), ValType(TypeCode::I64)}, {});
1270
180
  case OpCode::I64__store32:
1271
180
    return checkAlignAndTrans(
1272
180
        32, {ValType(TypeCode::I32), ValType(TypeCode::I64)}, {});
1273
1.41k
  case OpCode::Memory__size:
1274
1.41k
    return checkMemAndTrans({}, {ValType(TypeCode::I32)});
1275
2.05k
  case OpCode::Memory__grow:
1276
2.05k
    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
394
  case OpCode::Memory__copy:
1294
    /// Check the source memory index.
1295
394
    if (Instr.getSourceIndex() >= Mems) {
1296
3
      return logOutOfRange(ErrCode::Value::InvalidMemoryIdx,
1297
3
                           ErrInfo::IndexCategory::Memory,
1298
3
                           Instr.getSourceIndex(), Mems);
1299
3
    }
1300
391
    [[fallthrough]];
1301
1.66k
  case OpCode::Memory__fill:
1302
1.66k
    return checkMemAndTrans({ValType(TypeCode::I32), ValType(TypeCode::I32),
1303
1.66k
                             ValType(TypeCode::I32)},
1304
1.66k
                            {});
1305
90
  case OpCode::Data__drop:
1306
    // Check the target data index.
1307
90
    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
88
    return {};
1313
1314
  // Const Instructions.
1315
779k
  case OpCode::I32__const:
1316
779k
    return StackTrans({}, {ValType(TypeCode::I32)});
1317
130k
  case OpCode::I64__const:
1318
130k
    return StackTrans({}, {ValType(TypeCode::I64)});
1319
22.6k
  case OpCode::F32__const:
1320
22.6k
    return StackTrans({}, {ValType(TypeCode::F32)});
1321
9.86k
  case OpCode::F64__const:
1322
9.86k
    return StackTrans({}, {ValType(TypeCode::F64)});
1323
1324
  // Unary Numeric Instructions.
1325
9.17k
  case OpCode::I32__eqz:
1326
9.17k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1327
1.68k
  case OpCode::I64__eqz:
1328
1.68k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1329
4.23k
  case OpCode::I32__clz:
1330
7.97k
  case OpCode::I32__ctz:
1331
30.5k
  case OpCode::I32__popcnt:
1332
30.5k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1333
497
  case OpCode::I64__clz:
1334
1.60k
  case OpCode::I64__ctz:
1335
4.14k
  case OpCode::I64__popcnt:
1336
4.14k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1337
935
  case OpCode::F32__abs:
1338
3.05k
  case OpCode::F32__neg:
1339
5.76k
  case OpCode::F32__ceil:
1340
6.93k
  case OpCode::F32__floor:
1341
9.45k
  case OpCode::F32__trunc:
1342
10.6k
  case OpCode::F32__nearest:
1343
13.7k
  case OpCode::F32__sqrt:
1344
13.7k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F32)});
1345
1.06k
  case OpCode::F64__abs:
1346
2.32k
  case OpCode::F64__neg:
1347
6.35k
  case OpCode::F64__ceil:
1348
7.05k
  case OpCode::F64__floor:
1349
7.56k
  case OpCode::F64__trunc:
1350
8.03k
  case OpCode::F64__nearest:
1351
11.0k
  case OpCode::F64__sqrt:
1352
11.0k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F64)});
1353
521
  case OpCode::I32__wrap_i64:
1354
521
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1355
1.69k
  case OpCode::I32__trunc_f32_s:
1356
2.08k
  case OpCode::I32__trunc_f32_u:
1357
2.08k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1358
925
  case OpCode::I32__trunc_f64_s:
1359
2.75k
  case OpCode::I32__trunc_f64_u:
1360
2.75k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1361
2.97k
  case OpCode::I64__extend_i32_s:
1362
3.53k
  case OpCode::I64__extend_i32_u:
1363
3.53k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I64)});
1364
448
  case OpCode::I64__trunc_f32_s:
1365
1.53k
  case OpCode::I64__trunc_f32_u:
1366
1.53k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1367
1.00k
  case OpCode::I64__trunc_f64_s:
1368
2.62k
  case OpCode::I64__trunc_f64_u:
1369
2.62k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1370
2.54k
  case OpCode::F32__convert_i32_s:
1371
4.10k
  case OpCode::F32__convert_i32_u:
1372
4.10k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1373
1.63k
  case OpCode::F32__convert_i64_s:
1374
3.13k
  case OpCode::F32__convert_i64_u:
1375
3.13k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F32)});
1376
341
  case OpCode::F32__demote_f64:
1377
341
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F32)});
1378
2.15k
  case OpCode::F64__convert_i32_s:
1379
4.24k
  case OpCode::F64__convert_i32_u:
1380
4.24k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F64)});
1381
8.29k
  case OpCode::F64__convert_i64_s:
1382
8.65k
  case OpCode::F64__convert_i64_u:
1383
8.65k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)});
1384
127
  case OpCode::F64__promote_f32:
1385
127
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F64)});
1386
1.04k
  case OpCode::I32__reinterpret_f32:
1387
1.04k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1388
1.67k
  case OpCode::I64__reinterpret_f64:
1389
1.67k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1390
6.09k
  case OpCode::F32__reinterpret_i32:
1391
6.09k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1392
2.83k
  case OpCode::F64__reinterpret_i64:
1393
2.83k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)});
1394
3.53k
  case OpCode::I32__extend8_s:
1395
8.56k
  case OpCode::I32__extend16_s:
1396
8.56k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1397
703
  case OpCode::I64__extend8_s:
1398
1.76k
  case OpCode::I64__extend16_s:
1399
2.63k
  case OpCode::I64__extend32_s:
1400
2.63k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1401
402
  case OpCode::I32__trunc_sat_f32_s:
1402
782
  case OpCode::I32__trunc_sat_f32_u:
1403
782
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1404
550
  case OpCode::I32__trunc_sat_f64_s:
1405
827
  case OpCode::I32__trunc_sat_f64_u:
1406
827
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1407
512
  case OpCode::I64__trunc_sat_f32_s:
1408
1.02k
  case OpCode::I64__trunc_sat_f32_u:
1409
1.02k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1410
704
  case OpCode::I64__trunc_sat_f64_s:
1411
1.40k
  case OpCode::I64__trunc_sat_f64_u:
1412
1.40k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1413
1414
  // Binary Numeric Instructions.
1415
1.89k
  case OpCode::I32__eq:
1416
3.15k
  case OpCode::I32__ne:
1417
8.35k
  case OpCode::I32__lt_s:
1418
17.1k
  case OpCode::I32__lt_u:
1419
20.3k
  case OpCode::I32__gt_s:
1420
29.5k
  case OpCode::I32__gt_u:
1421
32.6k
  case OpCode::I32__le_s:
1422
33.7k
  case OpCode::I32__le_u:
1423
36.6k
  case OpCode::I32__ge_s:
1424
40.1k
  case OpCode::I32__ge_u:
1425
40.1k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1426
40.1k
                      {ValType(TypeCode::I32)});
1427
376
  case OpCode::I64__eq:
1428
1.18k
  case OpCode::I64__ne:
1429
2.62k
  case OpCode::I64__lt_s:
1430
3.54k
  case OpCode::I64__lt_u:
1431
4.69k
  case OpCode::I64__gt_s:
1432
5.04k
  case OpCode::I64__gt_u:
1433
6.23k
  case OpCode::I64__le_s:
1434
8.69k
  case OpCode::I64__le_u:
1435
9.10k
  case OpCode::I64__ge_s:
1436
10.1k
  case OpCode::I64__ge_u:
1437
10.1k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1438
10.1k
                      {ValType(TypeCode::I32)});
1439
722
  case OpCode::F32__eq:
1440
1.11k
  case OpCode::F32__ne:
1441
2.06k
  case OpCode::F32__lt:
1442
2.32k
  case OpCode::F32__gt:
1443
2.83k
  case OpCode::F32__le:
1444
3.41k
  case OpCode::F32__ge:
1445
3.41k
    return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)},
1446
3.41k
                      {ValType(TypeCode::I32)});
1447
496
  case OpCode::F64__eq:
1448
692
  case OpCode::F64__ne:
1449
1.12k
  case OpCode::F64__lt:
1450
2.00k
  case OpCode::F64__gt:
1451
2.38k
  case OpCode::F64__le:
1452
3.28k
  case OpCode::F64__ge:
1453
3.28k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1454
3.28k
                      {ValType(TypeCode::I32)});
1455
1.56k
  case OpCode::I32__add:
1456
4.26k
  case OpCode::I32__sub:
1457
5.40k
  case OpCode::I32__mul:
1458
8.27k
  case OpCode::I32__div_s:
1459
15.0k
  case OpCode::I32__div_u:
1460
17.0k
  case OpCode::I32__rem_s:
1461
18.7k
  case OpCode::I32__rem_u:
1462
20.2k
  case OpCode::I32__and:
1463
22.2k
  case OpCode::I32__or:
1464
24.1k
  case OpCode::I32__xor:
1465
27.9k
  case OpCode::I32__shl:
1466
31.8k
  case OpCode::I32__shr_s:
1467
37.6k
  case OpCode::I32__shr_u:
1468
41.6k
  case OpCode::I32__rotl:
1469
43.8k
  case OpCode::I32__rotr:
1470
43.8k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1471
43.8k
                      {ValType(TypeCode::I32)});
1472
1.05k
  case OpCode::I64__add:
1473
1.71k
  case OpCode::I64__sub:
1474
3.11k
  case OpCode::I64__mul:
1475
4.10k
  case OpCode::I64__div_s:
1476
6.84k
  case OpCode::I64__div_u:
1477
7.61k
  case OpCode::I64__rem_s:
1478
8.69k
  case OpCode::I64__rem_u:
1479
10.4k
  case OpCode::I64__and:
1480
12.6k
  case OpCode::I64__or:
1481
13.6k
  case OpCode::I64__xor:
1482
14.4k
  case OpCode::I64__shl:
1483
15.2k
  case OpCode::I64__shr_s:
1484
15.8k
  case OpCode::I64__shr_u:
1485
18.2k
  case OpCode::I64__rotl:
1486
21.7k
  case OpCode::I64__rotr:
1487
21.7k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1488
21.7k
                      {ValType(TypeCode::I64)});
1489
736
  case OpCode::F32__add:
1490
2.30k
  case OpCode::F32__sub:
1491
3.48k
  case OpCode::F32__mul:
1492
4.00k
  case OpCode::F32__div:
1493
4.86k
  case OpCode::F32__min:
1494
5.83k
  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
619
  case OpCode::F64__add:
1499
2.04k
  case OpCode::F64__sub:
1500
2.46k
  case OpCode::F64__mul:
1501
3.39k
  case OpCode::F64__div:
1502
4.38k
  case OpCode::F64__min:
1503
6.11k
  case OpCode::F64__max:
1504
7.06k
  case OpCode::F64__copysign:
1505
7.06k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1506
7.06k
                      {ValType(TypeCode::F64)});
1507
1508
  // SIMD Memory Instruction.
1509
9.54k
  case OpCode::V128__load:
1510
9.54k
    return checkAlignAndTrans(128, {ValType(TypeCode::I32)},
1511
9.54k
                              {ValType(TypeCode::V128)});
1512
868
  case OpCode::V128__load8x8_s:
1513
942
  case OpCode::V128__load8x8_u:
1514
1.58k
  case OpCode::V128__load16x4_s:
1515
2.99k
  case OpCode::V128__load16x4_u:
1516
3.49k
  case OpCode::V128__load32x2_s:
1517
3.73k
  case OpCode::V128__load32x2_u:
1518
4.23k
  case OpCode::V128__load64_splat:
1519
4.43k
  case OpCode::V128__load64_zero:
1520
4.43k
    return checkAlignAndTrans(64, {ValType(TypeCode::I32)},
1521
4.43k
                              {ValType(TypeCode::V128)});
1522
384
  case OpCode::V128__load8_splat:
1523
384
    return checkAlignAndTrans(8, {ValType(TypeCode::I32)},
1524
384
                              {ValType(TypeCode::V128)});
1525
725
  case OpCode::V128__load16_splat:
1526
725
    return checkAlignAndTrans(16, {ValType(TypeCode::I32)},
1527
725
                              {ValType(TypeCode::V128)});
1528
564
  case OpCode::V128__load32_splat:
1529
740
  case OpCode::V128__load32_zero:
1530
740
    return checkAlignAndTrans(32, {ValType(TypeCode::I32)},
1531
740
                              {ValType(TypeCode::V128)});
1532
523
  case OpCode::V128__store:
1533
523
    return checkAlignAndTrans(
1534
523
        128, {ValType(TypeCode::I32), ValType(TypeCode::V128)}, {});
1535
341
  case OpCode::V128__load8_lane:
1536
341
    return checkAlignAndTrans(8,
1537
341
                              {ValType(TypeCode::I32), ValType(TypeCode::V128)},
1538
341
                              {ValType(TypeCode::V128)}, true);
1539
1.25k
  case OpCode::V128__load16_lane:
1540
1.25k
    return checkAlignAndTrans(16,
1541
1.25k
                              {ValType(TypeCode::I32), ValType(TypeCode::V128)},
1542
1.25k
                              {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
405
  case OpCode::V128__load64_lane:
1548
405
    return checkAlignAndTrans(64,
1549
405
                              {ValType(TypeCode::I32), ValType(TypeCode::V128)},
1550
405
                              {ValType(TypeCode::V128)}, true);
1551
350
  case OpCode::V128__store8_lane:
1552
350
    return checkAlignAndTrans(
1553
350
        8, {ValType(TypeCode::I32), ValType(TypeCode::V128)}, {}, true);
1554
122
  case OpCode::V128__store16_lane:
1555
122
    return checkAlignAndTrans(
1556
122
        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
274
  case OpCode::V128__store64_lane:
1561
274
    return checkAlignAndTrans(
1562
274
        64, {ValType(TypeCode::I32), ValType(TypeCode::V128)}, {}, true);
1563
1564
  // SIMD Const Instruction.
1565
445
  case OpCode::V128__const:
1566
445
    return StackTrans({}, {ValType(TypeCode::V128)});
1567
1568
  // SIMD Shuffle Instruction.
1569
234
  case OpCode::I8x16__shuffle: {
1570
    // Check all lane index < 32 by masking
1571
234
    const uint128_t Mask = (uint128_t(0xe0e0e0e0e0e0e0e0U) << 64U) |
1572
234
                           uint128_t(0xe0e0e0e0e0e0e0e0U);
1573
234
    const uint128_t Result = Instr.getNum().get<uint128_t>() & Mask;
1574
234
    if (Result) {
1575
5
      spdlog::error(ErrCode::Value::InvalidLaneIdx);
1576
5
      return Unexpect(ErrCode::Value::InvalidLaneIdx);
1577
5
    }
1578
229
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1579
229
                      {ValType(TypeCode::V128)});
1580
234
  }
1581
1582
  // SIMD Lane Instructions.
1583
914
  case OpCode::I8x16__extract_lane_s:
1584
1.04k
  case OpCode::I8x16__extract_lane_u:
1585
1.04k
    return checkLaneAndTrans(16, {ValType(TypeCode::V128)},
1586
1.04k
                             {ValType(TypeCode::I32)});
1587
918
  case OpCode::I8x16__replace_lane:
1588
918
    return checkLaneAndTrans(16,
1589
918
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1590
918
                             {ValType(TypeCode::V128)});
1591
905
  case OpCode::I16x8__extract_lane_s:
1592
1.60k
  case OpCode::I16x8__extract_lane_u:
1593
1.60k
    return checkLaneAndTrans(8, {ValType(TypeCode::V128)},
1594
1.60k
                             {ValType(TypeCode::I32)});
1595
554
  case OpCode::I16x8__replace_lane:
1596
554
    return checkLaneAndTrans(8,
1597
554
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1598
554
                             {ValType(TypeCode::V128)});
1599
1.29k
  case OpCode::I32x4__extract_lane:
1600
1.29k
    return checkLaneAndTrans(4, {ValType(TypeCode::V128)},
1601
1.29k
                             {ValType(TypeCode::I32)});
1602
689
  case OpCode::I32x4__replace_lane:
1603
689
    return checkLaneAndTrans(4,
1604
689
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1605
689
                             {ValType(TypeCode::V128)});
1606
231
  case OpCode::I64x2__extract_lane:
1607
231
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1608
231
                             {ValType(TypeCode::I64)});
1609
738
  case OpCode::I64x2__replace_lane:
1610
738
    return checkLaneAndTrans(2,
1611
738
                             {ValType(TypeCode::V128), ValType(TypeCode::I64)},
1612
738
                             {ValType(TypeCode::V128)});
1613
119
  case OpCode::F32x4__extract_lane:
1614
119
    return checkLaneAndTrans(4, {ValType(TypeCode::V128)},
1615
119
                             {ValType(TypeCode::F32)});
1616
110
  case OpCode::F32x4__replace_lane:
1617
110
    return checkLaneAndTrans(4,
1618
110
                             {ValType(TypeCode::V128), ValType(TypeCode::F32)},
1619
110
                             {ValType(TypeCode::V128)});
1620
316
  case OpCode::F64x2__extract_lane:
1621
316
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1622
316
                             {ValType(TypeCode::F64)});
1623
168
  case OpCode::F64x2__replace_lane:
1624
168
    return checkLaneAndTrans(2,
1625
168
                             {ValType(TypeCode::V128), ValType(TypeCode::F64)},
1626
168
                             {ValType(TypeCode::V128)});
1627
1628
  // SIMD Numeric Instructions.
1629
49.4k
  case OpCode::I8x16__splat:
1630
62.5k
  case OpCode::I16x8__splat:
1631
64.8k
  case OpCode::I32x4__splat:
1632
64.8k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::V128)});
1633
829
  case OpCode::I64x2__splat:
1634
829
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::V128)});
1635
604
  case OpCode::F32x4__splat:
1636
604
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::V128)});
1637
566
  case OpCode::F64x2__splat:
1638
566
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::V128)});
1639
276
  case OpCode::V128__not:
1640
1.48k
  case OpCode::I8x16__abs:
1641
3.21k
  case OpCode::I8x16__neg:
1642
4.13k
  case OpCode::I8x16__popcnt:
1643
4.70k
  case OpCode::I16x8__abs:
1644
5.22k
  case OpCode::I16x8__neg:
1645
6.53k
  case OpCode::I16x8__extend_low_i8x16_s:
1646
6.71k
  case OpCode::I16x8__extend_high_i8x16_s:
1647
7.42k
  case OpCode::I16x8__extend_low_i8x16_u:
1648
7.47k
  case OpCode::I16x8__extend_high_i8x16_u:
1649
8.30k
  case OpCode::I16x8__extadd_pairwise_i8x16_s:
1650
9.77k
  case OpCode::I16x8__extadd_pairwise_i8x16_u:
1651
10.1k
  case OpCode::I32x4__abs:
1652
10.5k
  case OpCode::I32x4__neg:
1653
11.0k
  case OpCode::I32x4__extend_low_i16x8_s:
1654
11.7k
  case OpCode::I32x4__extend_high_i16x8_s:
1655
14.5k
  case OpCode::I32x4__extend_low_i16x8_u:
1656
14.9k
  case OpCode::I32x4__extend_high_i16x8_u:
1657
16.4k
  case OpCode::I32x4__extadd_pairwise_i16x8_s:
1658
17.3k
  case OpCode::I32x4__extadd_pairwise_i16x8_u:
1659
18.9k
  case OpCode::I64x2__abs:
1660
20.0k
  case OpCode::I64x2__neg:
1661
20.4k
  case OpCode::I64x2__extend_low_i32x4_s:
1662
21.7k
  case OpCode::I64x2__extend_high_i32x4_s:
1663
22.1k
  case OpCode::I64x2__extend_low_i32x4_u:
1664
23.3k
  case OpCode::I64x2__extend_high_i32x4_u:
1665
23.6k
  case OpCode::F32x4__abs:
1666
24.2k
  case OpCode::F32x4__neg:
1667
24.5k
  case OpCode::F32x4__sqrt:
1668
25.1k
  case OpCode::F64x2__abs:
1669
26.6k
  case OpCode::F64x2__neg:
1670
26.8k
  case OpCode::F64x2__sqrt:
1671
27.2k
  case OpCode::I32x4__trunc_sat_f32x4_s:
1672
32.7k
  case OpCode::I32x4__trunc_sat_f32x4_u:
1673
33.1k
  case OpCode::F32x4__convert_i32x4_s:
1674
34.2k
  case OpCode::F32x4__convert_i32x4_u:
1675
35.4k
  case OpCode::I32x4__trunc_sat_f64x2_s_zero:
1676
38.5k
  case OpCode::I32x4__trunc_sat_f64x2_u_zero:
1677
39.4k
  case OpCode::F64x2__convert_low_i32x4_s:
1678
41.4k
  case OpCode::F64x2__convert_low_i32x4_u:
1679
42.0k
  case OpCode::F32x4__demote_f64x2_zero:
1680
42.8k
  case OpCode::F64x2__promote_low_f32x4:
1681
43.7k
  case OpCode::F32x4__ceil:
1682
45.7k
  case OpCode::F32x4__floor:
1683
47.6k
  case OpCode::F32x4__trunc:
1684
47.9k
  case OpCode::F32x4__nearest:
1685
48.5k
  case OpCode::F64x2__ceil:
1686
49.2k
  case OpCode::F64x2__floor:
1687
50.1k
  case OpCode::F64x2__trunc:
1688
50.5k
  case OpCode::F64x2__nearest:
1689
50.5k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)});
1690
1.33k
  case OpCode::I8x16__swizzle:
1691
1.58k
  case OpCode::I8x16__eq:
1692
2.20k
  case OpCode::I8x16__ne:
1693
2.40k
  case OpCode::I8x16__lt_s:
1694
2.72k
  case OpCode::I8x16__lt_u:
1695
3.79k
  case OpCode::I8x16__gt_s:
1696
4.17k
  case OpCode::I8x16__gt_u:
1697
4.44k
  case OpCode::I8x16__le_s:
1698
4.67k
  case OpCode::I8x16__le_u:
1699
5.71k
  case OpCode::I8x16__ge_s:
1700
6.08k
  case OpCode::I8x16__ge_u:
1701
6.33k
  case OpCode::I16x8__eq:
1702
7.07k
  case OpCode::I16x8__ne:
1703
7.53k
  case OpCode::I16x8__lt_s:
1704
8.73k
  case OpCode::I16x8__lt_u:
1705
9.48k
  case OpCode::I16x8__gt_s:
1706
10.5k
  case OpCode::I16x8__gt_u:
1707
10.8k
  case OpCode::I16x8__le_s:
1708
11.1k
  case OpCode::I16x8__le_u:
1709
11.7k
  case OpCode::I16x8__ge_s:
1710
12.3k
  case OpCode::I16x8__ge_u:
1711
12.6k
  case OpCode::I32x4__eq:
1712
12.9k
  case OpCode::I32x4__ne:
1713
13.4k
  case OpCode::I32x4__lt_s:
1714
13.6k
  case OpCode::I32x4__lt_u:
1715
13.8k
  case OpCode::I32x4__gt_s:
1716
14.3k
  case OpCode::I32x4__gt_u:
1717
15.1k
  case OpCode::I32x4__le_s:
1718
15.6k
  case OpCode::I32x4__le_u:
1719
15.7k
  case OpCode::I32x4__ge_s:
1720
16.2k
  case OpCode::I32x4__ge_u:
1721
16.5k
  case OpCode::I64x2__eq:
1722
17.0k
  case OpCode::I64x2__ne:
1723
17.4k
  case OpCode::I64x2__lt_s:
1724
17.6k
  case OpCode::I64x2__gt_s:
1725
17.9k
  case OpCode::I64x2__le_s:
1726
18.6k
  case OpCode::I64x2__ge_s:
1727
21.1k
  case OpCode::F32x4__eq:
1728
21.2k
  case OpCode::F32x4__ne:
1729
22.4k
  case OpCode::F32x4__lt:
1730
22.6k
  case OpCode::F32x4__gt:
1731
23.3k
  case OpCode::F32x4__le:
1732
23.4k
  case OpCode::F32x4__ge:
1733
23.9k
  case OpCode::F64x2__eq:
1734
24.2k
  case OpCode::F64x2__ne:
1735
24.7k
  case OpCode::F64x2__lt:
1736
25.0k
  case OpCode::F64x2__gt:
1737
25.4k
  case OpCode::F64x2__le:
1738
25.9k
  case OpCode::F64x2__ge:
1739
26.1k
  case OpCode::V128__and:
1740
26.4k
  case OpCode::V128__andnot:
1741
27.1k
  case OpCode::V128__or:
1742
27.6k
  case OpCode::V128__xor:
1743
28.3k
  case OpCode::I8x16__narrow_i16x8_s:
1744
28.8k
  case OpCode::I8x16__narrow_i16x8_u:
1745
29.2k
  case OpCode::I8x16__add:
1746
30.1k
  case OpCode::I8x16__add_sat_s:
1747
30.5k
  case OpCode::I8x16__add_sat_u:
1748
31.3k
  case OpCode::I8x16__sub:
1749
32.2k
  case OpCode::I8x16__sub_sat_s:
1750
32.4k
  case OpCode::I8x16__sub_sat_u:
1751
32.6k
  case OpCode::I8x16__min_s:
1752
33.9k
  case OpCode::I8x16__min_u:
1753
34.6k
  case OpCode::I8x16__max_s:
1754
35.2k
  case OpCode::I8x16__max_u:
1755
35.7k
  case OpCode::I8x16__avgr_u:
1756
36.1k
  case OpCode::I16x8__narrow_i32x4_s:
1757
36.7k
  case OpCode::I16x8__narrow_i32x4_u:
1758
37.4k
  case OpCode::I16x8__add:
1759
37.6k
  case OpCode::I16x8__add_sat_s:
1760
38.5k
  case OpCode::I16x8__add_sat_u:
1761
39.1k
  case OpCode::I16x8__sub:
1762
39.7k
  case OpCode::I16x8__sub_sat_s:
1763
39.9k
  case OpCode::I16x8__sub_sat_u:
1764
40.3k
  case OpCode::I16x8__mul:
1765
40.6k
  case OpCode::I16x8__min_s:
1766
41.0k
  case OpCode::I16x8__min_u:
1767
41.5k
  case OpCode::I16x8__max_s:
1768
42.6k
  case OpCode::I16x8__max_u:
1769
42.8k
  case OpCode::I16x8__avgr_u:
1770
43.0k
  case OpCode::I16x8__extmul_low_i8x16_s:
1771
43.6k
  case OpCode::I16x8__extmul_high_i8x16_s:
1772
43.8k
  case OpCode::I16x8__extmul_low_i8x16_u:
1773
44.7k
  case OpCode::I16x8__extmul_high_i8x16_u:
1774
45.0k
  case OpCode::I16x8__q15mulr_sat_s:
1775
45.3k
  case OpCode::I32x4__add:
1776
45.5k
  case OpCode::I32x4__sub:
1777
45.9k
  case OpCode::I32x4__mul:
1778
46.3k
  case OpCode::I32x4__min_s:
1779
46.8k
  case OpCode::I32x4__min_u:
1780
46.9k
  case OpCode::I32x4__max_s:
1781
47.2k
  case OpCode::I32x4__max_u:
1782
47.5k
  case OpCode::I32x4__extmul_low_i16x8_s:
1783
47.7k
  case OpCode::I32x4__extmul_high_i16x8_s:
1784
48.1k
  case OpCode::I32x4__extmul_low_i16x8_u:
1785
48.5k
  case OpCode::I32x4__extmul_high_i16x8_u:
1786
49.0k
  case OpCode::I64x2__add:
1787
49.4k
  case OpCode::I64x2__sub:
1788
50.0k
  case OpCode::I64x2__mul:
1789
50.1k
  case OpCode::I64x2__extmul_low_i32x4_s:
1790
50.8k
  case OpCode::I64x2__extmul_high_i32x4_s:
1791
51.2k
  case OpCode::I64x2__extmul_low_i32x4_u:
1792
51.9k
  case OpCode::I64x2__extmul_high_i32x4_u:
1793
53.7k
  case OpCode::F32x4__add:
1794
54.4k
  case OpCode::F32x4__sub:
1795
55.1k
  case OpCode::F32x4__mul:
1796
55.5k
  case OpCode::F32x4__div:
1797
55.9k
  case OpCode::F32x4__min:
1798
56.4k
  case OpCode::F32x4__max:
1799
58.0k
  case OpCode::F32x4__pmin:
1800
58.4k
  case OpCode::F32x4__pmax:
1801
58.5k
  case OpCode::F64x2__add:
1802
59.1k
  case OpCode::F64x2__sub:
1803
59.4k
  case OpCode::F64x2__mul:
1804
59.6k
  case OpCode::F64x2__div:
1805
59.8k
  case OpCode::F64x2__min:
1806
60.0k
  case OpCode::F64x2__max:
1807
60.7k
  case OpCode::F64x2__pmin:
1808
61.1k
  case OpCode::F64x2__pmax:
1809
61.3k
  case OpCode::I32x4__dot_i16x8_s:
1810
61.3k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1811
61.3k
                      {ValType(TypeCode::V128)});
1812
246
  case OpCode::V128__bitselect:
1813
246
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1814
246
                       ValType(TypeCode::V128)},
1815
246
                      {ValType(TypeCode::V128)});
1816
170
  case OpCode::V128__any_true:
1817
611
  case OpCode::I8x16__all_true:
1818
1.39k
  case OpCode::I8x16__bitmask:
1819
1.83k
  case OpCode::I16x8__all_true:
1820
2.25k
  case OpCode::I16x8__bitmask:
1821
2.88k
  case OpCode::I32x4__all_true:
1822
4.25k
  case OpCode::I32x4__bitmask:
1823
5.11k
  case OpCode::I64x2__all_true:
1824
5.47k
  case OpCode::I64x2__bitmask:
1825
5.47k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::I32)});
1826
342
  case OpCode::I8x16__shl:
1827
2.10k
  case OpCode::I8x16__shr_s:
1828
2.76k
  case OpCode::I8x16__shr_u:
1829
2.88k
  case OpCode::I16x8__shl:
1830
3.44k
  case OpCode::I16x8__shr_s:
1831
3.53k
  case OpCode::I16x8__shr_u:
1832
5.10k
  case OpCode::I32x4__shl:
1833
5.43k
  case OpCode::I32x4__shr_s:
1834
5.61k
  case OpCode::I32x4__shr_u:
1835
5.87k
  case OpCode::I64x2__shl:
1836
7.02k
  case OpCode::I64x2__shr_s:
1837
7.16k
  case OpCode::I64x2__shr_u:
1838
7.16k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::I32)},
1839
7.16k
                      {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
422
  case OpCode::Atomic__fence:
1874
422
    return {};
1875
1876
65
  case OpCode::Memory__atomic__notify:
1877
65
    return checkAlignAndTrans(
1878
65
        32, std::array{ValType(TypeCode::I32), ValType(TypeCode::I32)},
1879
65
        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
48
  case OpCode::Memory__atomic__wait64:
1887
48
    return checkAlignAndTrans(64,
1888
48
                              std::array{ValType(TypeCode::I32),
1889
48
                                         ValType(TypeCode::I64),
1890
48
                                         ValType(TypeCode::I64)},
1891
48
                              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.85M
  }
2149
1.85M
}
2150
2151
1.50M
void FormChecker::pushType(VType V) { ValStack.emplace_back(V); }
2152
2153
37.3k
void FormChecker::pushTypes(Span<const VType> Input) {
2154
37.3k
  for (auto Val : Input) {
2155
4.16k
    pushType(Val);
2156
4.16k
  }
2157
37.3k
}
2158
2159
1.54M
void FormChecker::pushTypes(Span<const ValType> Input) {
2160
1.54M
  for (auto Val : Input) {
2161
1.49M
    pushType(Val);
2162
1.49M
  }
2163
1.54M
}
2164
2165
1.63M
Expect<VType> FormChecker::popType() {
2166
1.63M
  if (ValStack.size() == CtrlStack.back().Height) {
2167
171k
    if (CtrlStack.back().IsUnreachable) {
2168
171k
      return unreachableVType();
2169
171k
    }
2170
    // Value stack underflow
2171
288
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2172
288
    spdlog::error("    Value stack underflow."sv);
2173
288
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2174
171k
  }
2175
1.45M
  auto T = std::move(ValStack.back());
2176
1.45M
  ValStack.pop_back();
2177
1.45M
  return T;
2178
1.63M
}
2179
2180
793k
Expect<VType> FormChecker::popType(ValType E) {
2181
793k
  EXPECTED_TRY(auto Type, popType());
2182
793k
  if (Type == unreachableVType()) {
2183
168k
    return E;
2184
168k
  }
2185
2186
625k
  if (!AST::TypeMatcher::matchType(Types, E, *Type)) {
2187
    // Expect value on value stack is not matched
2188
495
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2189
495
    spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(E), VTypeToAST(Type)));
2190
495
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2191
495
  }
2192
625k
  return Type;
2193
625k
}
2194
2195
1.53M
Expect<void> FormChecker::popTypes(Span<const ValType> Input) {
2196
2.31M
  for (auto Val = Input.rbegin(); Val != Input.rend(); ++Val) {
2197
780k
    EXPECTED_TRY(popType(*Val));
2198
780k
  }
2199
1.53M
  return {};
2200
1.53M
}
2201
2202
void FormChecker::pushCtrl(Span<const ValType> In, Span<const ValType> Out,
2203
24.6k
                           const AST::Instruction *Jump, OpCode Code) {
2204
24.6k
  CtrlStack.emplace_back(In, Out, Jump, ValStack.size(), LocalInits.size(),
2205
24.6k
                         Code);
2206
24.6k
  pushTypes(In);
2207
24.6k
}
2208
2209
23.3k
Expect<FormChecker::CtrlFrame> FormChecker::popCtrl() {
2210
23.3k
  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
23.3k
  EXPECTED_TRY(popTypes(CtrlStack.back().EndTypes));
2217
23.3k
  if (ValStack.size() != CtrlStack.back().Height) {
2218
    // Value stack size not matched.
2219
90
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2220
90
    spdlog::error("    Value stack underflow."sv);
2221
90
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2222
90
  }
2223
  // When popping a frame, reset the inited locals during this frame.
2224
23.2k
  for (size_t I = CtrlStack.back().InitedLocal; I < LocalInits.size(); I++) {
2225
0
    Locals[LocalInits[I]].IsInit = false;
2226
0
  }
2227
23.2k
  LocalInits.erase(LocalInits.begin() +
2228
23.2k
                       static_cast<uint32_t>(CtrlStack.back().InitedLocal),
2229
23.2k
                   LocalInits.end());
2230
23.2k
  auto Head = std::move(CtrlStack.back());
2231
23.2k
  CtrlStack.pop_back();
2232
23.2k
  return Head;
2233
23.3k
}
2234
2235
Span<const ValType>
2236
43.7k
FormChecker::getLabelTypes(const FormChecker::CtrlFrame &F) {
2237
43.7k
  if (F.Code == OpCode::Loop) {
2238
4.75k
    return F.StartTypes;
2239
4.75k
  }
2240
39.0k
  return F.EndTypes;
2241
43.7k
}
2242
2243
211k
Expect<void> FormChecker::unreachable() {
2244
1.03M
  while (ValStack.size() > CtrlStack.back().Height) {
2245
822k
    EXPECTED_TRY(popType());
2246
822k
  }
2247
211k
  CtrlStack.back().IsUnreachable = true;
2248
211k
  return {};
2249
211k
}
2250
2251
Expect<void> FormChecker::StackTrans(Span<const ValType> Take,
2252
1.49M
                                     Span<const ValType> Put) {
2253
1.49M
  EXPECTED_TRY(popTypes(Take));
2254
1.49M
  pushTypes(Put);
2255
1.49M
  return {};
2256
1.49M
}
2257
2258
7.24k
Expect<void> FormChecker::StackPopAny() {
2259
7.24k
  EXPECTED_TRY(popType());
2260
7.24k
  return {};
2261
7.24k
}
2262
2263
} // namespace Validator
2264
} // namespace WasmEdge