Coverage Report

Created: 2026-08-08 06:32

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