Coverage Report

Created: 2025-11-16 06:42

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