Coverage Report

Created: 2026-08-14 06:41

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
432
                   uint32_t Bound) {
22
432
  spdlog::error(Code);
23
432
  spdlog::error(ErrInfo::InfoForbidIndex(Cate, Idx, Bound));
24
432
  return Unexpect(Code);
25
432
}
26
27
// Helper function for extracting address type to TypeCode.
28
2.91k
TypeCode convAddrTypeToTypeCode(const AddressType AT) noexcept {
29
2.91k
  switch (AT) {
30
2.64k
  case AddressType::I32:
31
2.64k
    return TypeCode::I32;
32
276
  case AddressType::I64:
33
276
    return TypeCode::I64;
34
0
  default:
35
0
    assumingUnreachable();
36
2.91k
  }
37
2.91k
};
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
161
  case TypeCode::I64:
45
161
    return AddressType::I64;
46
0
  default:
47
0
    assumingUnreachable();
48
50.8k
  }
49
50.8k
};
50
51
} // namespace
52
53
22.0k
void FormChecker::reset(bool CleanGlobal) {
54
22.0k
  ValStack.clear();
55
22.0k
  CtrlStack.clear();
56
22.0k
  Locals.clear();
57
22.0k
  Returns.clear();
58
59
22.0k
  if (CleanGlobal) {
60
6.72k
    Types.clear();
61
6.72k
    Funcs.clear();
62
6.72k
    Tables.clear();
63
6.72k
    Mems.clear();
64
6.72k
    Globals.clear();
65
6.72k
    Datas.clear();
66
6.72k
    Elems.clear();
67
6.72k
    Refs.clear();
68
6.72k
    Tags.clear();
69
6.72k
    NumImportFuncs = 0;
70
6.72k
    NumImportGlobals = 0;
71
6.72k
  }
72
22.0k
}
73
74
Expect<void> FormChecker::validate(AST::InstrView Instrs,
75
15.2k
                                   Span<const ValType> RetVals) {
76
15.2k
  for (const ValType &Val : RetVals) {
77
12.7k
    Returns.push_back(Val);
78
12.7k
  }
79
15.2k
  return checkExpr(Instrs);
80
15.2k
}
81
82
132M
Expect<void> FormChecker::validate(const ValType &VT) const noexcept {
83
  // The value type should be validated for the type index case.
84
132M
  if (VT.isRefType() && VT.getHeapTypeCode() == TypeCode::TypeIndex) {
85
106M
    if (VT.getTypeIndex() >= Types.size()) {
86
91
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
87
91
      spdlog::error(ErrInfo::InfoForbidIndex(
88
91
          ErrInfo::IndexCategory::FunctionType, VT.getTypeIndex(),
89
91
          static_cast<uint32_t>(Types.size())));
90
91
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
91
91
    }
92
106M
  }
93
132M
  return {};
94
132M
}
95
96
8.62k
void FormChecker::addType(const AST::SubType &Type) { Types.push_back(&Type); }
97
98
19.5k
void FormChecker::addFunc(const uint32_t TypeIdx, const bool IsImport) {
99
19.5k
  if (Types.size() > TypeIdx) {
100
19.5k
    Funcs.emplace_back(TypeIdx);
101
19.5k
  }
102
19.5k
  if (IsImport) {
103
717
    NumImportFuncs++;
104
717
  }
105
19.5k
}
106
107
909
void FormChecker::addTable(const AST::TableType &Tab) {
108
909
  Tables.emplace_back(convAddrTypeToTypeCode(Tab.getLimit().getAddrType()),
109
909
                      Tab.getRefType());
110
909
}
111
112
2.00k
void FormChecker::addMemory(const AST::MemoryType &Mem) {
113
2.00k
  Mems.push_back(convAddrTypeToTypeCode(Mem.getLimit().getAddrType()));
114
2.00k
}
115
116
401
void FormChecker::addGlobal(const AST::GlobalType &Glob, const bool IsImport) {
117
  // The global type is confirmed in the loading phase.
118
401
  Globals.emplace_back(Glob.getValType(), Glob.getValMut());
119
401
  if (IsImport) {
120
86
    NumImportGlobals++;
121
86
  }
122
401
}
123
124
1.07k
void FormChecker::addData(const AST::DataSegment &) {
125
1.07k
  Datas.emplace_back(static_cast<uint32_t>(Datas.size()));
126
1.07k
}
127
128
498
void FormChecker::addElem(const AST::ElementSegment &Elem) {
129
498
  Elems.emplace_back(Elem.getRefType());
130
498
}
131
132
12.8k
void FormChecker::addRef(const uint32_t FuncIdx) { Refs.emplace(FuncIdx); }
133
134
132M
void FormChecker::addLocal(const ValType &V, bool Initialized) {
135
132M
  Locals.emplace_back(V);
136
132M
  if (Initialized || V.isDefaultable()) {
137
132M
    LocalInits.push_back(static_cast<uint32_t>(Locals.size() - 1));
138
132M
    Locals.back().IsInit = true;
139
132M
  }
140
132M
}
141
142
289
void FormChecker::addTag(const uint32_t TypeIdx) { Tags.push_back(TypeIdx); }
143
144
1.37k
ValType FormChecker::VTypeToAST(const VType &V) {
145
1.37k
  if (!V) {
146
1
    return TypeCode::I32;
147
1
  }
148
1.37k
  return *V;
149
1.37k
}
150
151
15.2k
Expect<void> FormChecker::checkExpr(AST::InstrView Instrs) {
152
15.2k
  if (Instrs.size() > 0) {
153
    // Push ctrl frame ([] -> [Returns])
154
15.2k
    pushCtrl({}, Returns, &*Instrs.rbegin());
155
15.2k
    return checkInstrs(Instrs);
156
15.2k
  }
157
0
  return {};
158
15.2k
}
159
160
15.2k
Expect<void> FormChecker::checkInstrs(AST::InstrView Instrs) {
161
  // Validate instructions
162
2.06M
  for (auto &Instr : Instrs) {
163
2.06M
    EXPECTED_TRY(checkInstr(Instr).map_error([&Instr](auto E) {
164
2.06M
      spdlog::error(
165
2.06M
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
166
2.06M
      return E;
167
2.06M
    }));
168
2.06M
  }
169
13.5k
  return {};
170
15.2k
}
171
172
2.06M
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.06M
  auto checkTableIdx = [this](const uint32_t Idx) -> Expect<void> {
178
2.45k
    if (unlikely(Idx >= Tables.size())) {
179
52
      return logOutOfRange(ErrCode::Value::InvalidTableIdx,
180
52
                           ErrInfo::IndexCategory::Table, Idx,
181
52
                           static_cast<uint32_t>(Tables.size()));
182
52
    }
183
2.40k
    return {};
184
2.45k
  };
185
186
  // Helper lambda for checking whether the memory index is valid.
187
2.06M
  auto checkMemIdx = [this](const uint32_t Idx) -> Expect<void> {
188
56.4k
    if (unlikely(Idx >= Mems.size())) {
189
74
      return logOutOfRange(ErrCode::Value::InvalidMemoryIdx,
190
74
                           ErrInfo::IndexCategory::Memory, Idx,
191
74
                           static_cast<uint32_t>(Mems.size()));
192
74
    }
193
56.3k
    return {};
194
56.4k
  };
195
196
  // Helper lambda for checking whether the data index is valid.
197
2.06M
  auto checkDataIdx = [this](const uint32_t Idx) -> Expect<void> {
198
124
    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
115
    return {};
204
124
  };
205
206
  // Helper lambda for checking whether the element index is valid.
207
2.06M
  auto checkElemIdx = [this](const uint32_t Idx) -> Expect<void> {
208
95
    if (unlikely(Idx >= Elems.size())) {
209
13
      return logOutOfRange(ErrCode::Value::InvalidElemIdx,
210
13
                           ErrInfo::IndexCategory::Element, Idx,
211
13
                           static_cast<uint32_t>(Elems.size()));
212
13
    }
213
82
    return {};
214
95
  };
215
216
  // Helper lambda for checking whether the tag index is valid.
217
2.06M
  auto checkTagIdx = [this](const uint32_t Idx) -> Expect<void> {
218
34
    if (unlikely(Idx >= Tags.size())) {
219
16
      return logOutOfRange(ErrCode::Value::InvalidTagIdx,
220
16
                           ErrInfo::IndexCategory::Tag, Idx,
221
16
                           static_cast<uint32_t>(Tags.size()));
222
16
    }
223
18
    return {};
224
34
  };
225
226
  // Helper lambda for checking the defined type.
227
2.06M
  auto checkDefinedType =
228
2.06M
      [this](uint32_t TIdx, TypeCode TC) -> Expect<const AST::CompositeType *> {
229
8.05k
    if (TIdx >= Types.size()) {
230
88
      return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx,
231
88
                           ErrInfo::IndexCategory::FunctionType, TIdx,
232
88
                           static_cast<uint32_t>(Types.size()));
233
88
    }
234
7.97k
    const auto &CType = Types[TIdx]->getCompositeType();
235
7.97k
    if (CType.getContentTypeCode() == TC) {
236
7.96k
      return &CType;
237
7.96k
    } else {
238
9
      spdlog::error(ErrCode::Value::TypeCheckFailed);
239
9
      return Unexpect(ErrCode::Value::TypeCheckFailed);
240
9
    }
241
7.97k
  };
242
243
  // Helper lambda for checking and resolving the block type.
244
2.06M
  auto checkBlockType = [this, checkDefinedType](std::vector<ValType> &Buffer,
245
2.06M
                                                 const BlockType &BType)
246
2.06M
      -> Expect<std::pair<Span<const ValType>, Span<const ValType>>> {
247
10.3k
    using ReturnType = std::pair<Span<const ValType>, Span<const ValType>>;
248
10.3k
    if (BType.isEmpty()) {
249
      // Empty case. t2* = none
250
2.84k
      return ReturnType{{}, {}};
251
7.46k
    } else if (BType.isValType()) {
252
      // ValType case. t2* = valtype
253
2.81k
      EXPECTED_TRY(validate(BType.getValType()));
254
2.81k
      Buffer[0] = BType.getValType();
255
2.81k
      return ReturnType{{}, Buffer};
256
4.65k
    } else {
257
      // Type index case. t2* = functype.returns.
258
4.65k
      EXPECTED_TRY(auto CompType,
259
4.63k
                   checkDefinedType(BType.getTypeIndex(), TypeCode::Func));
260
4.63k
      const auto &FType = CompType->getFuncType();
261
4.63k
      return ReturnType{FType.getParamTypes(), FType.getReturnTypes()};
262
4.65k
    }
263
10.3k
  };
264
265
  // Helper lambda for checking control stack depth and return index.
266
2.06M
  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
52
      return logOutOfRange(ErrCode::Value::InvalidLabelIdx,
271
52
                           ErrInfo::IndexCategory::Label, N,
272
52
                           static_cast<uint32_t>(CtrlStack.size()));
273
52
    }
274
    // Return the index of the N-th element from the end.
275
27.5k
    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.06M
  auto checkLaneAndTrans = [this,
280
2.06M
                            &Instr](uint32_t N, Span<const ValType> Take,
281
2.06M
                                    Span<const ValType> Put) -> Expect<void> {
282
8.44k
    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.43k
    return StackTrans(Take, Put);
288
8.44k
  };
289
290
  // Helper lambda for checking memory alignment and performing transformation.
291
2.06M
  auto checkMemArgAndTrans = [this, checkMemIdx,
292
2.06M
                              &Instr](uint32_t N, Span<const ValType> Take,
293
2.06M
                                      Span<const ValType> Put,
294
2.06M
                                      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
185
                    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
18
      spdlog::error(ErrCode::Value::InvalidAlignment);
315
18
      spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3),
316
18
                                          Instr.getMemoryAlign()));
317
18
      return Unexpect(ErrCode::Value::InvalidAlignment);
318
18
    }
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
1
      spdlog::error(ErrCode::Value::InvalidOffset);
324
1
      return Unexpect(ErrCode::Value::InvalidOffset);
325
1
    }
326
    // Check the memory lane if needed.
327
49.6k
    if (CheckLane && Instr.getMemoryLane() >= 128 / N) {
328
15
      return logOutOfRange(ErrCode::Value::InvalidLaneIdx,
329
15
                           ErrInfo::IndexCategory::Lane, Instr.getMemoryLane(),
330
15
                           128 / N);
331
15
    }
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.06M
  auto checkTypesMatching = [this](Span<const ValType> Exp,
341
2.06M
                                   Span<const ValType> Got) -> Expect<void> {
342
1.93k
    if (!AST::TypeMatcher::matchTypes(Types, Exp, Got)) {
343
19
      std::vector<ValType> ExpV(Exp.begin(), Exp.end()),
344
19
          GotV(Got.begin(), Got.end());
345
19
      spdlog::error(ErrCode::Value::TypeCheckFailed);
346
19
      spdlog::error(ErrInfo::InfoMismatch(ExpV, GotV));
347
19
      return Unexpect(ErrCode::Value::TypeCheckFailed);
348
19
    }
349
1.91k
    return {};
350
1.93k
  };
351
352
  // Helper lambda for recording jump data.
353
2.06M
  auto recordJump = [this, &Instr](AST::Instruction::JumpDescriptor &Jump,
354
2.06M
                                   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.06M
  auto unpackType = [](const ValType &T) -> ValType {
364
971
    if (T.isPackType()) {
365
380
      return ValType(TypeCode::I32);
366
380
    }
367
591
    return T;
368
971
  };
369
370
  // Helper lambda for downcasting into the top heap type.
371
2.06M
  auto toTopHeapType = [this](const ValType &T) -> ValType {
372
561
    assuming(T.isRefType());
373
561
    if (T.isAbsHeapType()) {
374
412
      switch (T.getHeapTypeCode()) {
375
11
      case TypeCode::NullFuncRef:
376
32
      case TypeCode::FuncRef:
377
32
        return TypeCode::FuncRef;
378
21
      case TypeCode::NullExternRef:
379
31
      case TypeCode::ExternRef:
380
31
        return TypeCode::ExternRef;
381
29
      case TypeCode::NullExnRef:
382
52
      case TypeCode::ExnRef:
383
52
        return TypeCode::ExnRef;
384
104
      case TypeCode::NullRef:
385
162
      case TypeCode::AnyRef:
386
176
      case TypeCode::EqRef:
387
226
      case TypeCode::I31Ref:
388
276
      case TypeCode::StructRef:
389
297
      case TypeCode::ArrayRef:
390
297
        return TypeCode::AnyRef;
391
0
      default:
392
0
        assumingUnreachable();
393
412
      }
394
412
    } 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
561
  };
403
404
2.06M
  switch (Instr.getOpCode()) {
405
  // Control instructions.
406
221k
  case OpCode::Unreachable:
407
221k
    return unreachable();
408
112k
  case OpCode::Nop:
409
112k
    return {};
410
411
4.10k
  case OpCode::Block:
412
6.47k
  case OpCode::Loop:
413
9.80k
  case OpCode::If:
414
10.3k
  case OpCode::Try_table: {
415
    // Get blocktype [t1*] -> [t2*] and check valtype first.
416
10.3k
    std::vector<ValType> Buffer(1);
417
10.3k
    const auto &BType = (Instr.getOpCode() == OpCode::Try_table)
418
10.3k
                            ? Instr.getTryCatch().ResType
419
10.3k
                            : Instr.getBlockType();
420
10.3k
    EXPECTED_TRY(auto T1T2, checkBlockType(Buffer, BType));
421
10.2k
    auto [T1, T2] = T1T2;
422
    // For the if instruction, pop I32 first.
423
10.2k
    if (Instr.getOpCode() == OpCode::If) {
424
3.33k
      EXPECTED_TRY(popType(TypeCode::I32));
425
3.33k
    }
426
    // Pop and check [t1*]
427
10.2k
    EXPECTED_TRY(popTypes(T1));
428
    // For the try_table instruction, validate the handlers.
429
10.2k
    if (Instr.getOpCode() == OpCode::Try_table) {
430
501
      const auto &TryDesc = Instr.getTryCatch();
431
501
      const_cast<AST::Instruction::TryDescriptor &>(TryDesc).BlockParamNum =
432
501
          static_cast<uint32_t>(T1.size());
433
      // Validate catch clause.
434
501
      for (const auto &C : TryDesc.Catch) {
435
72
        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
133
        EXPECTED_TRY(auto D, checkCtrlStackDepth(C.LabelIndex));
441
133
        pushCtrl({}, getLabelTypes(CtrlStack[D]), &Instr + TryDesc.JumpEnd,
442
133
                 Instr.getOpCode());
443
133
        std::vector<ValType> NTypes;
444
133
        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
133
        if (C.IsRef) {
452
27
          NTypes.emplace_back(ValType(TypeCode::Ref, TypeCode::ExnRef));
453
27
        }
454
133
        pushTypes(NTypes);
455
133
        EXPECTED_TRY(popCtrl());
456
61
        recordJump(const_cast<AST::Instruction::JumpDescriptor &>(C.Jump),
457
61
                   static_cast<uint32_t>(NTypes.size()), D);
458
61
      }
459
501
    }
460
    // Push ctrl frame ([t1*], [t2*])
461
10.2k
    const AST::Instruction *From = nullptr;
462
10.2k
    if (Instr.getOpCode() == OpCode::Loop) {
463
2.35k
      From = &Instr;
464
7.91k
    } else if (Instr.getOpCode() == OpCode::Try_table) {
465
490
      From = &Instr + Instr.getTryCatch().JumpEnd;
466
7.42k
    } else {
467
7.42k
      From = &Instr + Instr.getJumpEnd();
468
7.42k
    }
469
10.2k
    pushCtrl(T1, T2, From, Instr.getOpCode());
470
10.2k
    if (Instr.getOpCode() == OpCode::If &&
471
3.32k
        Instr.getJumpElse() == Instr.getJumpEnd()) {
472
      // No else case in if-else statement.
473
1.54k
      EXPECTED_TRY(checkTypesMatching(T2, T1));
474
1.54k
    }
475
10.2k
    return {};
476
10.2k
  }
477
478
1.77k
  case OpCode::Else: {
479
1.77k
    EXPECTED_TRY(auto Ctrl, popCtrl());
480
1.77k
    pushCtrl(Ctrl.StartTypes, Ctrl.EndTypes, Ctrl.Jump, Instr.getOpCode());
481
1.77k
    return {};
482
1.77k
  }
483
484
30
  case OpCode::Throw: {
485
30
    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
15
    return unreachable();
491
36
  }
492
493
420
  case OpCode::Throw_ref:
494
420
    EXPECTED_TRY(popType(TypeCode::ExnRef));
495
417
    return unreachable();
496
497
23.7k
  case OpCode::End: {
498
23.7k
    EXPECTED_TRY(auto Ctrl, popCtrl());
499
23.4k
    pushTypes(Ctrl.EndTypes);
500
23.4k
    return {};
501
23.7k
  }
502
503
2.39k
  case OpCode::Br: {
504
2.39k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
505
    // D is the last D element of control stack.
506
2.38k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
507
2.38k
    EXPECTED_TRY(popTypes(NTypes));
508
2.38k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
509
2.38k
               static_cast<uint32_t>(NTypes.size()), D);
510
2.38k
    return unreachable();
511
2.38k
  }
512
1.66k
  case OpCode::Br_if: {
513
1.66k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
514
    // D is the last D element of control stack.
515
1.65k
    EXPECTED_TRY(popType(TypeCode::I32));
516
1.64k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
517
1.64k
    EXPECTED_TRY(popTypes(NTypes));
518
1.64k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
519
1.64k
               static_cast<uint32_t>(NTypes.size()), D);
520
1.64k
    pushTypes(NTypes);
521
1.64k
    return {};
522
1.64k
  }
523
1.62k
  case OpCode::Br_table: {
524
1.62k
    EXPECTED_TRY(popType(TypeCode::I32));
525
1.61k
    auto LabelTable = const_cast<AST::Instruction &>(Instr).getLabelList();
526
1.61k
    const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
527
1.61k
    EXPECTED_TRY(auto M,
528
1.60k
                 checkCtrlStackDepth(LabelTable[LabelTableSize].TargetIndex));
529
    // M is the M-th element from the end of the control stack.
530
1.60k
    auto MTypes = getLabelTypes(CtrlStack[M]);
531
23.0k
    for (uint32_t LabelIdx = 0; LabelIdx < LabelTableSize; ++LabelIdx) {
532
21.4k
      const uint32_t L = LabelTable[LabelIdx].TargetIndex;
533
21.4k
      EXPECTED_TRY(auto N, checkCtrlStackDepth(L));
534
      // N is the N-th element from the end of the control stack.
535
21.4k
      const auto NTypes = getLabelTypes(CtrlStack[N]);
536
21.4k
      if (MTypes.size() != NTypes.size()) {
537
5
        return checkTypesMatching(MTypes, NTypes);
538
5
      }
539
      // Push the popped types.
540
21.4k
      std::vector<VType> TypeBuf(NTypes.size());
541
26.2k
      for (uint32_t IdxN = static_cast<uint32_t>(NTypes.size()); IdxN >= 1;
542
21.4k
           --IdxN) {
543
4.81k
        const uint32_t Idx = IdxN - 1;
544
        // Cannot use popTypes() here because we need the popped value.
545
4.81k
        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.80k
        if (CtrlStack.back().IsUnreachable) {
549
750
          TypeBuf[Idx] = unreachableVType();
550
4.05k
        } else {
551
4.05k
          TypeBuf[Idx] = Type;
552
4.05k
        }
553
4.80k
      }
554
21.4k
      recordJump(LabelTable[LabelIdx], static_cast<uint32_t>(NTypes.size()), N);
555
21.4k
      pushTypes(TypeBuf);
556
21.4k
    }
557
1.58k
    const auto NTypes = getLabelTypes(CtrlStack[M]);
558
1.58k
    EXPECTED_TRY(popTypes(NTypes));
559
1.58k
    recordJump(LabelTable[LabelTableSize], static_cast<uint32_t>(NTypes.size()),
560
1.58k
               M);
561
1.58k
    return unreachable();
562
1.58k
  }
563
564
311
  case OpCode::Br_on_null: {
565
    // D is the last D element of control stack.
566
311
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
567
304
    const auto NTypes = getLabelTypes(CtrlStack[D]);
568
304
    EXPECTED_TRY(auto ResT, popType());
569
303
    if (ResT.has_value() && !ResT->isRefType()) {
570
4
      spdlog::error(ErrCode::Value::InvalidBrRefType);
571
4
      return Unexpect(ErrCode::ErrCode::Value::InvalidBrRefType);
572
4
    }
573
299
    EXPECTED_TRY(popTypes(NTypes));
574
297
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
575
297
               static_cast<uint32_t>(NTypes.size()), D);
576
297
    pushTypes(NTypes);
577
297
    if (ResT.has_value()) {
578
54
      pushType(ResT->toNonNullableRef());
579
243
    } else {
580
243
      pushType(unreachableVType());
581
243
    }
582
297
    return {};
583
299
  }
584
585
123
  case OpCode::Br_on_non_null: {
586
123
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
587
    // Get the result type of the label. (Should be [t* rt].)
588
119
    auto LabelTypes = getLabelTypes(CtrlStack[D]);
589
119
    std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end());
590
119
    if (unlikely(NTypes.empty())) {
591
2
      spdlog::error(ErrCode::Value::InvalidBrRefType);
592
2
      return Unexpect(ErrCode::Value::InvalidBrRefType);
593
2
    }
594
    // Pop types [t* (ref.null rt)].
595
117
    ValType &RT = NTypes.back();
596
117
    if (!RT.isRefType()) {
597
1
      spdlog::error(ErrCode::Value::InvalidBrRefType);
598
1
      return Unexpect(ErrCode::Value::InvalidBrRefType);
599
1
    }
600
116
    RT.toNullableRef();
601
116
    EXPECTED_TRY(popTypes(NTypes));
602
112
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
603
112
               static_cast<uint32_t>(NTypes.size()), D);
604
    // Push types [t*].
605
112
    NTypes.pop_back();
606
112
    pushTypes(NTypes);
607
112
    return {};
608
116
  }
609
610
2.47k
  case OpCode::Return:
611
2.47k
    EXPECTED_TRY(popTypes(Returns));
612
2.46k
    return unreachable();
613
614
4.36k
  case OpCode::Call: {
615
4.36k
    auto N = Instr.getTargetIndex();
616
4.36k
    if (unlikely(N >= Funcs.size())) {
617
29
      return logOutOfRange(ErrCode::Value::InvalidFuncIdx,
618
29
                           ErrInfo::IndexCategory::Function, N,
619
29
                           static_cast<uint32_t>(Funcs.size()));
620
29
    }
621
    // Because functions were validated when added, Type[Funcs[N]] must be a
622
    // function type.
623
4.33k
    auto &FuncType = Types[Funcs[N]]->getCompositeType().getFuncType();
624
4.33k
    return StackTrans(FuncType.getParamTypes(), FuncType.getReturnTypes());
625
4.36k
  }
626
1.17k
  case OpCode::Call_indirect: {
627
1.17k
    auto N = Instr.getTargetIndex();
628
1.17k
    auto T = Instr.getSourceIndex();
629
    // Check source table index.
630
1.17k
    EXPECTED_TRY(checkTableIdx(T));
631
1.15k
    if (!AST::TypeMatcher::matchType(Types, TypeCode::FuncRef,
632
1.15k
                                     Tables[T].second)) {
633
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
634
3
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, Tables[T].second));
635
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
636
3
    }
637
    // Check target function type index.
638
2.29k
    EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func));
639
2.29k
    EXPECTED_TRY(popType(Tables[T].first));
640
1.14k
    const auto &FType = CompType->getFuncType();
641
1.14k
    return StackTrans(FType.getParamTypes(), FType.getReturnTypes());
642
2.29k
  }
643
91
  case OpCode::Return_call: {
644
91
    auto N = Instr.getTargetIndex();
645
91
    if (unlikely(N >= Funcs.size())) {
646
      // Call function index out of range
647
4
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
648
4
      spdlog::error(
649
4
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Function, N,
650
4
                                   static_cast<uint32_t>(Funcs.size())));
651
4
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
652
4
    }
653
    // Because functions were validated when added, Type[Funcs[N]] must be a
654
    // function type.
655
87
    auto &FType = Types[Funcs[N]]->getCompositeType().getFuncType();
656
87
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
657
85
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
658
84
    return unreachable();
659
85
  }
660
201
  case OpCode::Return_call_indirect: {
661
201
    auto N = Instr.getTargetIndex();
662
201
    auto T = Instr.getSourceIndex();
663
    // Check source table index.
664
201
    EXPECTED_TRY(checkTableIdx(T));
665
196
    if (!AST::TypeMatcher::matchType(Types, TypeCode::FuncRef,
666
196
                                     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
388
    EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func));
673
388
    const auto &FType = CompType->getFuncType();
674
388
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
675
191
    EXPECTED_TRY(popType(Tables[T].first));
676
190
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
677
188
    return unreachable();
678
190
  }
679
500
  case OpCode::Call_ref: {
680
500
    EXPECTED_TRY(auto CompType,
681
494
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Func));
682
494
    const auto &FType = CompType->getFuncType();
683
494
    std::vector<ValType> Input = FType.getParamTypes();
684
494
    Input.push_back(ValType(TypeCode::RefNull, Instr.getTargetIndex()));
685
494
    return StackTrans(Input, FType.getReturnTypes());
686
500
  }
687
110
  case OpCode::Return_call_ref: {
688
110
    EXPECTED_TRY(auto CompType,
689
107
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Func));
690
107
    const auto &FType = CompType->getFuncType();
691
107
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
692
106
    EXPECTED_TRY(popType(ValType(TypeCode::RefNull, Instr.getTargetIndex())));
693
104
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
694
103
    return unreachable();
695
104
  }
696
697
  // Reference Instructions.
698
13.6k
  case OpCode::Ref__null: {
699
13.6k
    EXPECTED_TRY(validate(Instr.getValType()));
700
13.6k
    return StackTrans({}, {Instr.getValType()});
701
13.6k
  }
702
5.67k
  case OpCode::Ref__is_null: {
703
5.67k
    EXPECTED_TRY(auto Type, popType());
704
5.67k
    if (Type.has_value() && !Type->isRefType()) {
705
4
      spdlog::error(ErrCode::Value::TypeCheckFailed);
706
4
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, VTypeToAST(Type)));
707
4
      return Unexpect(ErrCode::Value::TypeCheckFailed);
708
4
    }
709
5.66k
    return StackTrans({}, {ValType(TypeCode::I32)});
710
5.67k
  }
711
1.39k
  case OpCode::Ref__func: {
712
1.39k
    auto FuncIdx = Instr.getTargetIndex();
713
1.39k
    if (Refs.find(FuncIdx) == Refs.cend()) {
714
      // Undeclared function reference.
715
25
      spdlog::error(ErrCode::Value::InvalidRefIdx);
716
25
      return Unexpect(ErrCode::Value::InvalidRefIdx);
717
25
    }
718
1.37k
    assuming(FuncIdx < Funcs.size());
719
1.37k
    auto TypeIdx = Funcs[FuncIdx];
720
1.37k
    assuming(TypeIdx < Types.size());
721
1.37k
    return StackTrans({}, {ValType(TypeCode::Ref, TypeIdx)});
722
1.37k
  }
723
71
  case OpCode::Ref__eq:
724
71
    return StackTrans({ValType(TypeCode::RefNull, TypeCode::EqRef),
725
71
                       ValType(TypeCode::RefNull, TypeCode::EqRef)},
726
71
                      {ValType(TypeCode::I32)});
727
1.07k
  case OpCode::Ref__as_non_null: {
728
1.07k
    EXPECTED_TRY(auto Type, popType());
729
1.06k
    if (Type == unreachableVType()) {
730
604
      pushType(unreachableVType());
731
604
      return {};
732
604
    }
733
463
    if (!Type->isRefType()) {
734
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
735
3
      spdlog::error(ErrInfo::InfoMismatch(
736
3
          ValType(TypeCode::RefNull, TypeCode::FuncRef), VTypeToAST(Type)));
737
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
738
3
    }
739
460
    return StackTrans({}, {Type->toNonNullableRef()});
740
463
  }
741
742
130
  case OpCode::Struct__new:
743
248
  case OpCode::Struct__new_default: {
744
248
    EXPECTED_TRY(auto CompType,
745
223
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct));
746
223
    std::vector<ValType> Fields;
747
223
    if (Instr.getOpCode() == OpCode::Struct__new) {
748
117
      Fields.reserve(CompType->getFieldTypes().size());
749
117
    }
750
223
    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
223
    return StackTrans(Fields, {ValType(TypeCode::Ref, Instr.getTargetIndex())});
760
223
  }
761
3
  case OpCode::Struct__get:
762
7
  case OpCode::Struct__get_s:
763
9
  case OpCode::Struct__get_u: {
764
9
    EXPECTED_TRY(auto CompType,
765
7
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct));
766
7
    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
5
    const auto &FType = CompType->getFieldTypes()[Instr.getSourceIndex()];
773
5
    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
4
    } else if (unlikely(Instr.getOpCode() != OpCode::Struct__get &&
779
2
                        !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
3
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex())},
785
3
                      {unpackType(FType.getStorageType())});
786
5
  }
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
278
  case OpCode::Array__new:
806
342
  case OpCode::Array__new_default:
807
486
  case OpCode::Array__new_fixed: {
808
486
    EXPECTED_TRY(auto CompType,
809
459
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
810
459
    const auto &SType = CompType->getFieldTypes()[0].getStorageType();
811
459
    if (Instr.getOpCode() == OpCode::Array__new) {
812
266
      return StackTrans({unpackType(SType), ValType(TypeCode::I32)},
813
266
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
814
266
    } else if (Instr.getOpCode() == OpCode::Array__new_default) {
815
53
      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
53
      return StackTrans({ValType(TypeCode::I32)},
821
53
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
822
140
    } else {
823
140
      std::vector<ValType> Fields(Instr.getSourceIndex(), unpackType(SType));
824
140
      return StackTrans(Fields,
825
140
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
826
140
    }
827
459
  }
828
6
  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
2
        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
5
  case OpCode::Array__new_elem:
854
9
  case OpCode::Array__init_elem: {
855
9
    EXPECTED_TRY(auto CompType,
856
5
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
857
5
    const auto &FType = CompType->getFieldTypes()[0];
858
5
    if (Instr.getOpCode() == OpCode::Array__init_elem &&
859
3
        FType.getValMut() != ValMut::Var) {
860
1
      spdlog::error(ErrCode::Value::ImmutableArray);
861
1
      return Unexpect(ErrCode::Value::ImmutableArray);
862
1
    }
863
4
    if (!FType.getStorageType().isRefType()) {
864
2
      spdlog::error(ErrCode::Value::TypeCheckFailed);
865
2
      return Unexpect(ErrCode::Value::TypeCheckFailed);
866
2
    }
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
238
  case OpCode::Array__get:
886
394
  case OpCode::Array__get_s:
887
458
  case OpCode::Array__get_u: {
888
458
    EXPECTED_TRY(auto CompType,
889
453
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
890
453
    const auto &FType = CompType->getFieldTypes()[0];
891
453
    if (unlikely(Instr.getOpCode() == OpCode::Array__get &&
892
236
                 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
452
    } 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
450
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
903
450
                       ValType(TypeCode::I32)},
904
450
                      {unpackType(FType.getStorageType())});
905
453
  }
906
64
  case OpCode::Array__set:
907
104
  case OpCode::Array__fill: {
908
104
    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
3
      spdlog::error(ErrCode::Value::ImmutableArray);
913
3
      return Unexpect(ErrCode::Value::ImmutableArray);
914
3
    }
915
99
    std::vector<ValType> Fields = {
916
99
        ValType(TypeCode::RefNull, Instr.getTargetIndex()),
917
99
        ValType(TypeCode::I32), unpackType(FType.getStorageType())};
918
99
    if (Instr.getOpCode() == OpCode::Array__fill) {
919
38
      Fields.emplace_back(ValType(TypeCode::I32));
920
38
    }
921
99
    return StackTrans(Fields, {});
922
102
  }
923
123
  case OpCode::Array__len:
924
123
    return StackTrans({ValType(TypeCode::ArrayRef)}, {ValType(TypeCode::I32)});
925
55
  case OpCode::Array__copy: {
926
55
    EXPECTED_TRY(auto CompType,
927
54
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
928
54
    const auto &DstFType = CompType->getFieldTypes()[0];
929
54
    if (DstFType.getValMut() != ValMut::Var) {
930
2
      spdlog::error(ErrCode::Value::ImmutableArray);
931
2
      return Unexpect(ErrCode::Value::ImmutableArray);
932
2
    }
933
103
    EXPECTED_TRY(auto Src,
934
103
                 checkDefinedType(Instr.getSourceIndex(), TypeCode::Array));
935
103
    const auto &SrcFType = Src->getFieldTypes()[0];
936
103
    if (!AST::TypeMatcher::matchType(Types, DstFType.getStorageType(),
937
51
                                     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
51
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
944
51
                       ValType(TypeCode::I32),
945
51
                       ValType(TypeCode::RefNull, Instr.getSourceIndex()),
946
51
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
947
51
                      {});
948
103
  }
949
950
40
  case OpCode::Ref__test:
951
126
  case OpCode::Ref__test_null:
952
402
  case OpCode::Ref__cast:
953
599
  case OpCode::Ref__cast_null: {
954
599
    EXPECTED_TRY(validate(Instr.getValType()));
955
1.18k
    EXPECTED_TRY(auto Type, popType());
956
1.18k
    if (Type.has_value() && !Type->isRefType()) {
957
      // The trap occurs when the actual type is not a reference type.
958
2
      spdlog::error(ErrCode::Value::TypeCheckFailed);
959
2
      spdlog::error(
960
2
          ErrInfo::InfoMismatch(Instr.getValType(), VTypeToAST(Type)));
961
2
      return Unexpect(ErrCode::Value::TypeCheckFailed);
962
2
    }
963
    // When Type is nullopt (unreachable/bottom type), the bottom type matches
964
    // any target type, so skip the type matching check.
965
588
    if (Type.has_value() &&
966
561
        !AST::TypeMatcher::matchType(Types, toTopHeapType(*Type),
967
561
                                     Instr.getValType())) {
968
10
      spdlog::error(ErrCode::Value::TypeCheckFailed);
969
10
      spdlog::error(ErrInfo::InfoMismatch(*Type, Instr.getValType()));
970
10
      return Unexpect(ErrCode::Value::TypeCheckFailed);
971
10
    }
972
578
    if (Instr.getOpCode() == OpCode::Ref__test ||
973
540
        Instr.getOpCode() == OpCode::Ref__test_null) {
974
122
      return StackTrans({}, {ValType(TypeCode::I32)});
975
456
    } else {
976
456
      return StackTrans({}, {Instr.getValType()});
977
456
    }
978
578
  }
979
2
  case OpCode::Br_on_cast:
980
5
  case OpCode::Br_on_cast_fail: {
981
    // The reference types should be valid.
982
5
    auto &RT1 = Instr.getBrCast().RType1;
983
5
    auto &RT2 = Instr.getBrCast().RType2;
984
5
    EXPECTED_TRY(validate(RT1));
985
4
    EXPECTED_TRY(validate(RT2));
986
    // The reference type RT2 should match RT1.
987
2
    if (unlikely(!AST::TypeMatcher::matchType(Types, RT1, RT2))) {
988
1
      spdlog::error(ErrCode::Value::TypeCheckFailed);
989
1
      spdlog::error(ErrInfo::InfoMismatch(RT1, RT2));
990
1
      return Unexpect(ErrCode::Value::TypeCheckFailed);
991
1
    }
992
2
    EXPECTED_TRY(auto D,
993
2
                 checkCtrlStackDepth(Instr.getBrCast().Jump.TargetIndex));
994
    // Get the result type of the label. (Should be [t* rt'].)
995
2
    auto LabelTypes = getLabelTypes(CtrlStack[D]);
996
2
    std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end());
997
2
    if (unlikely(NTypes.empty())) {
998
1
      spdlog::error(ErrCode::Value::InvalidBrRefType);
999
1
      return Unexpect(ErrCode::Value::InvalidBrRefType);
1000
1
    }
1001
    // Get the type difference between rt1 \ rt2. (rt1' = rt1 \ rt2)
1002
0
    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
0
    ValType &RTP = NTypes.back();
1006
0
    const ValType &RTRHS = Instr.getOpCode() == OpCode::Br_on_cast ? RT2 : RT1P;
1007
0
    if (unlikely(!AST::TypeMatcher::matchType(Types, RTP, RTRHS))) {
1008
0
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1009
0
      spdlog::error(ErrInfo::InfoMismatch(RTP, RTRHS));
1010
0
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1011
0
    }
1012
    // Pop types [t* rt1].
1013
0
    RTP = RT1;
1014
0
    EXPECTED_TRY(popTypes(NTypes));
1015
0
    recordJump(const_cast<AST::Instruction &>(Instr).getBrCast().Jump,
1016
0
               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
0
    RTP = Instr.getOpCode() == OpCode::Br_on_cast ? RT1P : RT2;
1020
0
    pushTypes(NTypes);
1021
0
    return {};
1022
0
  }
1023
112
  case OpCode::Any__convert_extern: {
1024
112
    EXPECTED_TRY(auto Type, popType(TypeCode::ExternRef));
1025
101
    return StackTrans({}, {ValType(Type->getCode(), TypeCode::AnyRef)});
1026
112
  }
1027
131
  case OpCode::Extern__convert_any: {
1028
131
    EXPECTED_TRY(auto Type, popType(TypeCode::AnyRef));
1029
126
    return StackTrans({}, {ValType(Type->getCode(), TypeCode::ExternRef)});
1030
131
  }
1031
157
  case OpCode::Ref__i31:
1032
157
    return StackTrans({ValType(TypeCode::I32)},
1033
157
                      {ValType(TypeCode::Ref, TypeCode::I31Ref)});
1034
66
  case OpCode::I31__get_s:
1035
132
  case OpCode::I31__get_u:
1036
132
    return StackTrans({ValType(TypeCode::RefNull, TypeCode::I31Ref)},
1037
132
                      {ValType(TypeCode::I32)});
1038
1039
  // Parametric Instructions.
1040
6.77k
  case OpCode::Drop:
1041
6.77k
    return StackPopAny();
1042
3.26k
  case OpCode::Select: {
1043
    // Pop I32.
1044
3.26k
    EXPECTED_TRY(popType(TypeCode::I32));
1045
    // Pop T1 and T2.
1046
6.52k
    EXPECTED_TRY(VType T1, popType());
1047
6.52k
    EXPECTED_TRY(VType T2, popType());
1048
    // T1 and T2 should be number type.
1049
3.25k
    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.25k
    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.25k
    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.24k
    if (T1 == unreachableVType()) {
1067
1.74k
      pushType(T2);
1068
1.74k
    } else {
1069
1.50k
      pushType(T1);
1070
1.50k
    }
1071
3.24k
    return {};
1072
3.25k
  }
1073
565
  case OpCode::Select_t: {
1074
    // Note: There may be multiple values choice in the future.
1075
565
    if (Instr.getValTypeList().size() != 1) {
1076
5
      spdlog::error(ErrCode::Value::InvalidResultArity);
1077
5
      return Unexpect(ErrCode::Value::InvalidResultArity);
1078
5
    }
1079
560
    ValType ExpT = Instr.getValTypeList()[0];
1080
560
    EXPECTED_TRY(validate(ExpT));
1081
558
    EXPECTED_TRY(popTypes({ExpT, ExpT, ValType(TypeCode::I32)}));
1082
557
    pushType(ExpT);
1083
557
    return {};
1084
558
  }
1085
1086
  // Variable Instructions.
1087
13.4k
  case OpCode::Local__get:
1088
18.6k
  case OpCode::Local__set:
1089
23.0k
  case OpCode::Local__tee: {
1090
23.0k
    if (Instr.getTargetIndex() >= Locals.size()) {
1091
35
      return logOutOfRange(
1092
35
          ErrCode::Value::InvalidLocalIdx, ErrInfo::IndexCategory::Local,
1093
35
          Instr.getTargetIndex(), static_cast<uint32_t>(Locals.size()));
1094
35
    }
1095
22.9k
    auto &TExpect = Locals[Instr.getTargetIndex()];
1096
22.9k
    const_cast<AST::Instruction &>(Instr).getStackOffset() =
1097
22.9k
        static_cast<uint32_t>(ValStack.size() +
1098
22.9k
                              (Locals.size() - Instr.getTargetIndex()));
1099
22.9k
    if (Instr.getOpCode() == OpCode::Local__get) {
1100
13.4k
      if (!TExpect.IsInit) {
1101
2
        spdlog::error(ErrCode::Value::InvalidUninitLocal);
1102
2
        return Unexpect(ErrCode::Value::InvalidUninitLocal);
1103
2
      }
1104
13.4k
      return StackTrans({}, {TExpect.VType});
1105
13.4k
    } else if (Instr.getOpCode() == OpCode::Local__set) {
1106
5.14k
      if (!TExpect.IsInit) {
1107
36
        TExpect.IsInit = true;
1108
36
        LocalInits.push_back(Instr.getTargetIndex());
1109
36
      }
1110
5.14k
      return StackTrans({TExpect.VType}, {});
1111
5.14k
    } else if (Instr.getOpCode() == OpCode::Local__tee) {
1112
4.38k
      if (!TExpect.IsInit) {
1113
118
        TExpect.IsInit = true;
1114
118
        LocalInits.push_back(Instr.getTargetIndex());
1115
118
      }
1116
4.38k
      return StackTrans({TExpect.VType}, {TExpect.VType});
1117
4.38k
    } else {
1118
0
      assumingUnreachable();
1119
0
    }
1120
22.9k
  }
1121
1.45k
  case OpCode::Global__set:
1122
    // Global case, check mutation.
1123
1.45k
    if (Instr.getTargetIndex() < Globals.size() &&
1124
1.43k
        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.45k
    [[fallthrough]];
1130
3.45k
  case OpCode::Global__get: {
1131
3.45k
    if (Instr.getTargetIndex() >= Globals.size()) {
1132
31
      return logOutOfRange(
1133
31
          ErrCode::Value::InvalidGlobalIdx, ErrInfo::IndexCategory::Global,
1134
31
          Instr.getTargetIndex(), static_cast<uint32_t>(Globals.size()));
1135
31
    }
1136
3.42k
    ValType ExpT = Globals[Instr.getTargetIndex()].first;
1137
3.42k
    if (Instr.getOpCode() == OpCode::Global__set) {
1138
1.43k
      return StackTrans({ExpT}, {});
1139
1.99k
    } else {
1140
1.99k
      return StackTrans({}, {ExpT});
1141
1.99k
    }
1142
3.42k
  }
1143
1144
  // Table Instructions.
1145
124
  case OpCode::Table__get:
1146
124
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1147
118
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first)},
1148
118
                      {Tables[Instr.getTargetIndex()].second});
1149
269
  case OpCode::Table__set:
1150
269
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1151
264
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1152
264
                       Tables[Instr.getTargetIndex()].second},
1153
264
                      {});
1154
42
  case OpCode::Table__init:
1155
42
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1156
40
    EXPECTED_TRY(checkElemIdx(Instr.getSourceIndex()));
1157
    // Check whether the reference types match.
1158
36
    if (!AST::TypeMatcher::matchType(Types,
1159
36
                                     Tables[Instr.getTargetIndex()].second,
1160
36
                                     Elems[Instr.getSourceIndex()])) {
1161
2
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1162
2
      spdlog::error(ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()].second,
1163
2
                                          Elems[Instr.getSourceIndex()]));
1164
2
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1165
2
    }
1166
34
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1167
34
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
1168
34
                      {});
1169
53
  case OpCode::Elem__drop:
1170
53
    EXPECTED_TRY(checkElemIdx(Instr.getTargetIndex()));
1171
46
    return {};
1172
220
  case OpCode::Table__copy: {
1173
220
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1174
215
    EXPECTED_TRY(checkTableIdx(Instr.getSourceIndex()));
1175
    // Check whether the reference types match.
1176
211
    if (!AST::TypeMatcher::matchType(Types,
1177
211
                                     Tables[Instr.getTargetIndex()].second,
1178
211
                                     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
203
    auto ATDst = Tables[Instr.getTargetIndex()].first;
1186
203
    auto ATSrc = Tables[Instr.getSourceIndex()].first;
1187
203
    auto ATMin = convTypeCodeToAddrType(ATDst) <= convTypeCodeToAddrType(ATSrc)
1188
203
                     ? ATDst
1189
203
                     : ATSrc;
1190
203
    return StackTrans({ValType(ATDst), ValType(ATSrc), ValType(ATMin)}, {});
1191
211
  }
1192
81
  case OpCode::Table__grow:
1193
81
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1194
77
    return StackTrans({Tables[Instr.getTargetIndex()].second,
1195
77
                       ValType(Tables[Instr.getTargetIndex()].first)},
1196
77
                      {ValType(Tables[Instr.getTargetIndex()].first)});
1197
57
  case OpCode::Table__size:
1198
57
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1199
56
    return StackTrans({}, {ValType(Tables[Instr.getTargetIndex()].first)});
1200
72
  case OpCode::Table__fill:
1201
72
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1202
70
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1203
70
                       Tables[Instr.getTargetIndex()].second,
1204
70
                       ValType(Tables[Instr.getTargetIndex()].first)},
1205
70
                      {});
1206
1207
  // Memory Instructions.
1208
1.72k
  case OpCode::I32__load:
1209
1.72k
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I32)});
1210
4.18k
  case OpCode::I64__load:
1211
4.18k
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::I64)});
1212
305
  case OpCode::F32__load:
1213
305
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::F32)});
1214
893
  case OpCode::F64__load:
1215
893
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::F64)});
1216
1.57k
  case OpCode::I32__load8_s:
1217
2.53k
  case OpCode::I32__load8_u:
1218
2.53k
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I32)});
1219
995
  case OpCode::I32__load16_s:
1220
3.21k
  case OpCode::I32__load16_u:
1221
3.21k
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I32)});
1222
1.45k
  case OpCode::I64__load8_s:
1223
2.28k
  case OpCode::I64__load8_u:
1224
2.28k
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I64)});
1225
1.17k
  case OpCode::I64__load16_s:
1226
3.15k
  case OpCode::I64__load16_u:
1227
3.15k
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I64)});
1228
940
  case OpCode::I64__load32_s:
1229
2.23k
  case OpCode::I64__load32_u:
1230
2.23k
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I64)});
1231
624
  case OpCode::I32__store:
1232
624
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, {});
1233
2.73k
  case OpCode::I64__store:
1234
2.73k
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, {});
1235
694
  case OpCode::F32__store:
1236
694
    return checkMemArgAndTrans(32, {ValType(TypeCode::F32)}, {});
1237
196
  case OpCode::F64__store:
1238
196
    return checkMemArgAndTrans(64, {ValType(TypeCode::F64)}, {});
1239
1.08k
  case OpCode::I32__store8:
1240
1.08k
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, {});
1241
771
  case OpCode::I32__store16:
1242
771
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, {});
1243
774
  case OpCode::I64__store8:
1244
774
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, {});
1245
700
  case OpCode::I64__store16:
1246
700
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, {});
1247
176
  case OpCode::I64__store32:
1248
176
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, {});
1249
1.65k
  case OpCode::Memory__size:
1250
1.65k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1251
1.64k
    return StackTrans({}, {ValType(Mems[Instr.getTargetIndex()])});
1252
2.96k
  case OpCode::Memory__grow:
1253
2.96k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1254
2.95k
    return StackTrans({ValType(Mems[Instr.getTargetIndex()])},
1255
2.95k
                      {ValType(Mems[Instr.getTargetIndex()])});
1256
32
  case OpCode::Memory__init:
1257
32
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1258
30
    EXPECTED_TRY(checkDataIdx(Instr.getSourceIndex()));
1259
28
    return StackTrans({ValType(Mems[Instr.getTargetIndex()]),
1260
28
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
1261
28
                      {});
1262
90
  case OpCode::Data__drop:
1263
90
    EXPECTED_TRY(checkDataIdx(Instr.getTargetIndex()));
1264
87
    return {};
1265
390
  case OpCode::Memory__copy: {
1266
390
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1267
387
    EXPECTED_TRY(checkMemIdx(Instr.getSourceIndex()));
1268
386
    auto ATDst = Mems[Instr.getTargetIndex()];
1269
386
    auto ATSrc = Mems[Instr.getSourceIndex()];
1270
386
    auto ATMin = convTypeCodeToAddrType(ATDst) <= convTypeCodeToAddrType(ATSrc)
1271
386
                     ? ATDst
1272
386
                     : ATSrc;
1273
386
    return StackTrans({ValType(ATDst), ValType(ATSrc), ValType(ATMin)}, {});
1274
387
  }
1275
1.31k
  case OpCode::Memory__fill:
1276
1.31k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1277
1.31k
    return StackTrans({ValType(Mems[Instr.getTargetIndex()]),
1278
1.31k
                       ValType(TypeCode::I32),
1279
1.31k
                       ValType(Mems[Instr.getTargetIndex()])},
1280
1.31k
                      {});
1281
1282
  // Const Instructions.
1283
875k
  case OpCode::I32__const:
1284
875k
    return StackTrans({}, {ValType(TypeCode::I32)});
1285
117k
  case OpCode::I64__const:
1286
117k
    return StackTrans({}, {ValType(TypeCode::I64)});
1287
21.1k
  case OpCode::F32__const:
1288
21.1k
    return StackTrans({}, {ValType(TypeCode::F32)});
1289
10.1k
  case OpCode::F64__const:
1290
10.1k
    return StackTrans({}, {ValType(TypeCode::F64)});
1291
1292
  // Unary Numeric Instructions.
1293
11.7k
  case OpCode::I32__eqz:
1294
11.7k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1295
2.62k
  case OpCode::I64__eqz:
1296
2.62k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1297
4.55k
  case OpCode::I32__clz:
1298
8.08k
  case OpCode::I32__ctz:
1299
38.6k
  case OpCode::I32__popcnt:
1300
38.6k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1301
566
  case OpCode::I64__clz:
1302
1.79k
  case OpCode::I64__ctz:
1303
4.51k
  case OpCode::I64__popcnt:
1304
4.51k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1305
948
  case OpCode::F32__abs:
1306
2.82k
  case OpCode::F32__neg:
1307
4.94k
  case OpCode::F32__ceil:
1308
5.90k
  case OpCode::F32__floor:
1309
7.26k
  case OpCode::F32__trunc:
1310
8.76k
  case OpCode::F32__nearest:
1311
12.0k
  case OpCode::F32__sqrt:
1312
12.0k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F32)});
1313
1.04k
  case OpCode::F64__abs:
1314
2.00k
  case OpCode::F64__neg:
1315
6.43k
  case OpCode::F64__ceil:
1316
7.02k
  case OpCode::F64__floor:
1317
7.79k
  case OpCode::F64__trunc:
1318
8.32k
  case OpCode::F64__nearest:
1319
10.4k
  case OpCode::F64__sqrt:
1320
10.4k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F64)});
1321
808
  case OpCode::I32__wrap_i64:
1322
808
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1323
1.98k
  case OpCode::I32__trunc_f32_s:
1324
3.05k
  case OpCode::I32__trunc_f32_u:
1325
3.05k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1326
944
  case OpCode::I32__trunc_f64_s:
1327
2.77k
  case OpCode::I32__trunc_f64_u:
1328
2.77k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1329
3.50k
  case OpCode::I64__extend_i32_s:
1330
4.18k
  case OpCode::I64__extend_i32_u:
1331
4.18k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I64)});
1332
445
  case OpCode::I64__trunc_f32_s:
1333
2.71k
  case OpCode::I64__trunc_f32_u:
1334
2.71k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1335
1.01k
  case OpCode::I64__trunc_f64_s:
1336
4.47k
  case OpCode::I64__trunc_f64_u:
1337
4.47k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1338
2.50k
  case OpCode::F32__convert_i32_s:
1339
3.98k
  case OpCode::F32__convert_i32_u:
1340
3.98k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1341
1.43k
  case OpCode::F32__convert_i64_s:
1342
4.16k
  case OpCode::F32__convert_i64_u:
1343
4.16k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F32)});
1344
339
  case OpCode::F32__demote_f64:
1345
339
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F32)});
1346
1.89k
  case OpCode::F64__convert_i32_s:
1347
4.83k
  case OpCode::F64__convert_i32_u:
1348
4.83k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F64)});
1349
10.1k
  case OpCode::F64__convert_i64_s:
1350
10.4k
  case OpCode::F64__convert_i64_u:
1351
10.4k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)});
1352
164
  case OpCode::F64__promote_f32:
1353
164
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F64)});
1354
1.07k
  case OpCode::I32__reinterpret_f32:
1355
1.07k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1356
1.50k
  case OpCode::I64__reinterpret_f64:
1357
1.50k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1358
6.93k
  case OpCode::F32__reinterpret_i32:
1359
6.93k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1360
2.31k
  case OpCode::F64__reinterpret_i64:
1361
2.31k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)});
1362
5.58k
  case OpCode::I32__extend8_s:
1363
10.5k
  case OpCode::I32__extend16_s:
1364
10.5k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1365
793
  case OpCode::I64__extend8_s:
1366
1.82k
  case OpCode::I64__extend16_s:
1367
2.60k
  case OpCode::I64__extend32_s:
1368
2.60k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1369
591
  case OpCode::I32__trunc_sat_f32_s:
1370
927
  case OpCode::I32__trunc_sat_f32_u:
1371
927
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1372
821
  case OpCode::I32__trunc_sat_f64_s:
1373
1.41k
  case OpCode::I32__trunc_sat_f64_u:
1374
1.41k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1375
540
  case OpCode::I64__trunc_sat_f32_s:
1376
1.08k
  case OpCode::I64__trunc_sat_f32_u:
1377
1.08k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1378
570
  case OpCode::I64__trunc_sat_f64_s:
1379
1.30k
  case OpCode::I64__trunc_sat_f64_u:
1380
1.30k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1381
1382
  // Binary Numeric Instructions.
1383
1.89k
  case OpCode::I32__eq:
1384
3.33k
  case OpCode::I32__ne:
1385
7.55k
  case OpCode::I32__lt_s:
1386
16.8k
  case OpCode::I32__lt_u:
1387
19.8k
  case OpCode::I32__gt_s:
1388
29.8k
  case OpCode::I32__gt_u:
1389
33.0k
  case OpCode::I32__le_s:
1390
34.3k
  case OpCode::I32__le_u:
1391
37.1k
  case OpCode::I32__ge_s:
1392
39.0k
  case OpCode::I32__ge_u:
1393
39.0k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1394
39.0k
                      {ValType(TypeCode::I32)});
1395
503
  case OpCode::I64__eq:
1396
1.26k
  case OpCode::I64__ne:
1397
2.74k
  case OpCode::I64__lt_s:
1398
3.47k
  case OpCode::I64__lt_u:
1399
5.23k
  case OpCode::I64__gt_s:
1400
5.52k
  case OpCode::I64__gt_u:
1401
7.33k
  case OpCode::I64__le_s:
1402
9.72k
  case OpCode::I64__le_u:
1403
10.1k
  case OpCode::I64__ge_s:
1404
11.8k
  case OpCode::I64__ge_u:
1405
11.8k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1406
11.8k
                      {ValType(TypeCode::I32)});
1407
588
  case OpCode::F32__eq:
1408
996
  case OpCode::F32__ne:
1409
1.75k
  case OpCode::F32__lt:
1410
1.96k
  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
525
  case OpCode::F64__eq:
1416
727
  case OpCode::F64__ne:
1417
1.18k
  case OpCode::F64__lt:
1418
2.06k
  case OpCode::F64__gt:
1419
2.43k
  case OpCode::F64__le:
1420
3.31k
  case OpCode::F64__ge:
1421
3.31k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1422
3.31k
                      {ValType(TypeCode::I32)});
1423
1.82k
  case OpCode::I32__add:
1424
5.36k
  case OpCode::I32__sub:
1425
6.47k
  case OpCode::I32__mul:
1426
9.16k
  case OpCode::I32__div_s:
1427
15.4k
  case OpCode::I32__div_u:
1428
17.7k
  case OpCode::I32__rem_s:
1429
20.6k
  case OpCode::I32__rem_u:
1430
21.8k
  case OpCode::I32__and:
1431
24.2k
  case OpCode::I32__or:
1432
27.0k
  case OpCode::I32__xor:
1433
31.4k
  case OpCode::I32__shl:
1434
35.7k
  case OpCode::I32__shr_s:
1435
41.8k
  case OpCode::I32__shr_u:
1436
46.0k
  case OpCode::I32__rotl:
1437
48.4k
  case OpCode::I32__rotr:
1438
48.4k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1439
48.4k
                      {ValType(TypeCode::I32)});
1440
1.05k
  case OpCode::I64__add:
1441
1.94k
  case OpCode::I64__sub:
1442
3.35k
  case OpCode::I64__mul:
1443
4.10k
  case OpCode::I64__div_s:
1444
6.85k
  case OpCode::I64__div_u:
1445
7.64k
  case OpCode::I64__rem_s:
1446
8.94k
  case OpCode::I64__rem_u:
1447
10.6k
  case OpCode::I64__and:
1448
11.5k
  case OpCode::I64__or:
1449
13.0k
  case OpCode::I64__xor:
1450
13.6k
  case OpCode::I64__shl:
1451
14.8k
  case OpCode::I64__shr_s:
1452
15.5k
  case OpCode::I64__shr_u:
1453
18.3k
  case OpCode::I64__rotl:
1454
21.5k
  case OpCode::I64__rotr:
1455
21.5k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1456
21.5k
                      {ValType(TypeCode::I64)});
1457
613
  case OpCode::F32__add:
1458
2.48k
  case OpCode::F32__sub:
1459
3.52k
  case OpCode::F32__mul:
1460
4.02k
  case OpCode::F32__div:
1461
4.67k
  case OpCode::F32__min:
1462
5.67k
  case OpCode::F32__max:
1463
6.54k
  case OpCode::F32__copysign:
1464
6.54k
    return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)},
1465
6.54k
                      {ValType(TypeCode::F32)});
1466
681
  case OpCode::F64__add:
1467
2.85k
  case OpCode::F64__sub:
1468
3.25k
  case OpCode::F64__mul:
1469
4.05k
  case OpCode::F64__div:
1470
5.03k
  case OpCode::F64__min:
1471
6.70k
  case OpCode::F64__max:
1472
8.14k
  case OpCode::F64__copysign:
1473
8.14k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1474
8.14k
                      {ValType(TypeCode::F64)});
1475
1476
  // SIMD Memory Instruction.
1477
9.44k
  case OpCode::V128__load:
1478
9.44k
    return checkMemArgAndTrans(128, {}, {ValType(TypeCode::V128)});
1479
967
  case OpCode::V128__load8x8_s:
1480
1.05k
  case OpCode::V128__load8x8_u:
1481
1.72k
  case OpCode::V128__load16x4_s:
1482
3.48k
  case OpCode::V128__load16x4_u:
1483
3.97k
  case OpCode::V128__load32x2_s:
1484
4.28k
  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
430
  case OpCode::V128__load8_splat:
1489
430
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::V128)});
1490
755
  case OpCode::V128__load16_splat:
1491
755
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::V128)});
1492
544
  case OpCode::V128__load32_splat:
1493
845
  case OpCode::V128__load32_zero:
1494
845
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::V128)});
1495
649
  case OpCode::V128__store:
1496
649
    return checkMemArgAndTrans(128, {ValType(TypeCode::V128)}, {});
1497
345
  case OpCode::V128__load8_lane:
1498
345
    return checkMemArgAndTrans(8, {ValType(TypeCode::V128)},
1499
345
                               {ValType(TypeCode::V128)}, true);
1500
1.28k
  case OpCode::V128__load16_lane:
1501
1.28k
    return checkMemArgAndTrans(16, {ValType(TypeCode::V128)},
1502
1.28k
                               {ValType(TypeCode::V128)}, true);
1503
225
  case OpCode::V128__load32_lane:
1504
225
    return checkMemArgAndTrans(32, {ValType(TypeCode::V128)},
1505
225
                               {ValType(TypeCode::V128)}, true);
1506
419
  case OpCode::V128__load64_lane:
1507
419
    return checkMemArgAndTrans(64, {ValType(TypeCode::V128)},
1508
419
                               {ValType(TypeCode::V128)}, true);
1509
521
  case OpCode::V128__store8_lane:
1510
521
    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
289
  case OpCode::V128__store64_lane:
1516
289
    return checkMemArgAndTrans(64, {ValType(TypeCode::V128)}, {}, true);
1517
1518
  // SIMD Const Instruction.
1519
511
  case OpCode::V128__const:
1520
511
    return StackTrans({}, {ValType(TypeCode::V128)});
1521
1522
  // SIMD Shuffle Instruction.
1523
327
  case OpCode::I8x16__shuffle: {
1524
    // Check that all lane indices are less than 32 by masking.
1525
327
    const uint128_t Mask = (uint128_t(0xe0e0e0e0e0e0e0e0U) << 64U) |
1526
327
                           uint128_t(0xe0e0e0e0e0e0e0e0U);
1527
327
    const uint128_t Result = Instr.getNum().get<uint128_t>() & Mask;
1528
327
    if (Result) {
1529
5
      spdlog::error(ErrCode::Value::InvalidLaneIdx);
1530
5
      return Unexpect(ErrCode::Value::InvalidLaneIdx);
1531
5
    }
1532
322
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1533
322
                      {ValType(TypeCode::V128)});
1534
327
  }
1535
1536
  // SIMD Lane Instructions.
1537
980
  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.08k
  case OpCode::I8x16__replace_lane:
1542
1.08k
    return checkLaneAndTrans(16,
1543
1.08k
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1544
1.08k
                             {ValType(TypeCode::V128)});
1545
948
  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
678
  case OpCode::I16x8__replace_lane:
1550
678
    return checkLaneAndTrans(8,
1551
678
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1552
678
                             {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
617
  case OpCode::I32x4__replace_lane:
1557
617
    return checkLaneAndTrans(4,
1558
617
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1559
617
                             {ValType(TypeCode::V128)});
1560
265
  case OpCode::I64x2__extract_lane:
1561
265
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1562
265
                             {ValType(TypeCode::I64)});
1563
753
  case OpCode::I64x2__replace_lane:
1564
753
    return checkLaneAndTrans(2,
1565
753
                             {ValType(TypeCode::V128), ValType(TypeCode::I64)},
1566
753
                             {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
402
  case OpCode::F64x2__extract_lane:
1575
402
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1576
402
                             {ValType(TypeCode::F64)});
1577
168
  case OpCode::F64x2__replace_lane:
1578
168
    return checkLaneAndTrans(2,
1579
168
                             {ValType(TypeCode::V128), ValType(TypeCode::F64)},
1580
168
                             {ValType(TypeCode::V128)});
1581
1582
  // SIMD Numeric Instructions.
1583
59.1k
  case OpCode::I8x16__splat:
1584
72.4k
  case OpCode::I16x8__splat:
1585
74.8k
  case OpCode::I32x4__splat:
1586
74.8k
    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
561
  case OpCode::F32x4__splat:
1590
561
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::V128)});
1591
685
  case OpCode::F64x2__splat:
1592
685
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::V128)});
1593
910
  case OpCode::V128__not:
1594
3.69k
  case OpCode::I8x16__abs:
1595
7.76k
  case OpCode::I8x16__neg:
1596
8.70k
  case OpCode::I8x16__popcnt:
1597
9.48k
  case OpCode::I16x8__abs:
1598
9.98k
  case OpCode::I16x8__neg:
1599
11.4k
  case OpCode::I16x8__extend_low_i8x16_s:
1600
11.6k
  case OpCode::I16x8__extend_high_i8x16_s:
1601
12.2k
  case OpCode::I16x8__extend_low_i8x16_u:
1602
12.3k
  case OpCode::I16x8__extend_high_i8x16_u:
1603
13.4k
  case OpCode::I16x8__extadd_pairwise_i8x16_s:
1604
15.0k
  case OpCode::I16x8__extadd_pairwise_i8x16_u:
1605
15.5k
  case OpCode::I32x4__abs:
1606
15.9k
  case OpCode::I32x4__neg:
1607
16.4k
  case OpCode::I32x4__extend_low_i16x8_s:
1608
17.2k
  case OpCode::I32x4__extend_high_i16x8_s:
1609
20.2k
  case OpCode::I32x4__extend_low_i16x8_u:
1610
20.7k
  case OpCode::I32x4__extend_high_i16x8_u:
1611
22.7k
  case OpCode::I32x4__extadd_pairwise_i16x8_s:
1612
24.9k
  case OpCode::I32x4__extadd_pairwise_i16x8_u:
1613
26.4k
  case OpCode::I64x2__abs:
1614
27.5k
  case OpCode::I64x2__neg:
1615
28.3k
  case OpCode::I64x2__extend_low_i32x4_s:
1616
29.5k
  case OpCode::I64x2__extend_high_i32x4_s:
1617
30.1k
  case OpCode::I64x2__extend_low_i32x4_u:
1618
31.6k
  case OpCode::I64x2__extend_high_i32x4_u:
1619
31.8k
  case OpCode::F32x4__abs:
1620
32.4k
  case OpCode::F32x4__neg:
1621
32.7k
  case OpCode::F32x4__sqrt:
1622
33.3k
  case OpCode::F64x2__abs:
1623
34.5k
  case OpCode::F64x2__neg:
1624
34.7k
  case OpCode::F64x2__sqrt:
1625
35.1k
  case OpCode::I32x4__trunc_sat_f32x4_s:
1626
40.8k
  case OpCode::I32x4__trunc_sat_f32x4_u:
1627
41.2k
  case OpCode::F32x4__convert_i32x4_s:
1628
42.4k
  case OpCode::F32x4__convert_i32x4_u:
1629
43.6k
  case OpCode::I32x4__trunc_sat_f64x2_s_zero:
1630
46.8k
  case OpCode::I32x4__trunc_sat_f64x2_u_zero:
1631
47.9k
  case OpCode::F64x2__convert_low_i32x4_s:
1632
49.8k
  case OpCode::F64x2__convert_low_i32x4_u:
1633
50.9k
  case OpCode::F32x4__demote_f64x2_zero:
1634
52.3k
  case OpCode::F64x2__promote_low_f32x4:
1635
54.0k
  case OpCode::F32x4__ceil:
1636
57.5k
  case OpCode::F32x4__floor:
1637
60.6k
  case OpCode::F32x4__trunc:
1638
61.2k
  case OpCode::F32x4__nearest:
1639
62.2k
  case OpCode::F64x2__ceil:
1640
63.5k
  case OpCode::F64x2__floor:
1641
64.3k
  case OpCode::F64x2__trunc:
1642
64.7k
  case OpCode::F64x2__nearest:
1643
64.7k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)});
1644
852
  case OpCode::I8x16__swizzle:
1645
1.46k
  case OpCode::I8x16__eq:
1646
2.25k
  case OpCode::I8x16__ne:
1647
2.68k
  case OpCode::I8x16__lt_s:
1648
3.01k
  case OpCode::I8x16__lt_u:
1649
4.42k
  case OpCode::I8x16__gt_s:
1650
4.76k
  case OpCode::I8x16__gt_u:
1651
5.08k
  case OpCode::I8x16__le_s:
1652
5.44k
  case OpCode::I8x16__le_u:
1653
6.37k
  case OpCode::I8x16__ge_s:
1654
6.70k
  case OpCode::I8x16__ge_u:
1655
7.20k
  case OpCode::I16x8__eq:
1656
7.93k
  case OpCode::I16x8__ne:
1657
8.46k
  case OpCode::I16x8__lt_s:
1658
9.85k
  case OpCode::I16x8__lt_u:
1659
10.7k
  case OpCode::I16x8__gt_s:
1660
12.0k
  case OpCode::I16x8__gt_u:
1661
12.4k
  case OpCode::I16x8__le_s:
1662
12.7k
  case OpCode::I16x8__le_u:
1663
13.4k
  case OpCode::I16x8__ge_s:
1664
14.0k
  case OpCode::I16x8__ge_u:
1665
14.3k
  case OpCode::I32x4__eq:
1666
14.6k
  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.1k
  case OpCode::I32x4__le_u:
1673
19.2k
  case OpCode::I32x4__ge_s:
1674
19.7k
  case OpCode::I32x4__ge_u:
1675
20.0k
  case OpCode::I64x2__eq:
1676
20.5k
  case OpCode::I64x2__ne:
1677
21.0k
  case OpCode::I64x2__lt_s:
1678
21.3k
  case OpCode::I64x2__gt_s:
1679
21.6k
  case OpCode::I64x2__le_s:
1680
22.4k
  case OpCode::I64x2__ge_s:
1681
25.0k
  case OpCode::F32x4__eq:
1682
25.2k
  case OpCode::F32x4__ne:
1683
26.0k
  case OpCode::F32x4__lt:
1684
26.2k
  case OpCode::F32x4__gt:
1685
27.1k
  case OpCode::F32x4__le:
1686
27.3k
  case OpCode::F32x4__ge:
1687
28.9k
  case OpCode::F64x2__eq:
1688
29.2k
  case OpCode::F64x2__ne:
1689
29.6k
  case OpCode::F64x2__lt:
1690
31.3k
  case OpCode::F64x2__gt:
1691
31.7k
  case OpCode::F64x2__le:
1692
32.3k
  case OpCode::F64x2__ge:
1693
32.6k
  case OpCode::V128__and:
1694
32.9k
  case OpCode::V128__andnot:
1695
33.4k
  case OpCode::V128__or:
1696
33.9k
  case OpCode::V128__xor:
1697
34.6k
  case OpCode::I8x16__narrow_i16x8_s:
1698
35.2k
  case OpCode::I8x16__narrow_i16x8_u:
1699
35.6k
  case OpCode::I8x16__add:
1700
36.6k
  case OpCode::I8x16__add_sat_s:
1701
37.0k
  case OpCode::I8x16__add_sat_u:
1702
37.8k
  case OpCode::I8x16__sub:
1703
38.8k
  case OpCode::I8x16__sub_sat_s:
1704
39.0k
  case OpCode::I8x16__sub_sat_u:
1705
39.3k
  case OpCode::I8x16__min_s:
1706
40.7k
  case OpCode::I8x16__min_u:
1707
41.4k
  case OpCode::I8x16__max_s:
1708
42.0k
  case OpCode::I8x16__max_u:
1709
42.6k
  case OpCode::I8x16__avgr_u:
1710
42.9k
  case OpCode::I16x8__narrow_i32x4_s:
1711
43.6k
  case OpCode::I16x8__narrow_i32x4_u:
1712
44.3k
  case OpCode::I16x8__add:
1713
44.4k
  case OpCode::I16x8__add_sat_s:
1714
45.4k
  case OpCode::I16x8__add_sat_u:
1715
46.0k
  case OpCode::I16x8__sub:
1716
46.6k
  case OpCode::I16x8__sub_sat_s:
1717
46.8k
  case OpCode::I16x8__sub_sat_u:
1718
47.3k
  case OpCode::I16x8__mul:
1719
47.8k
  case OpCode::I16x8__min_s:
1720
48.2k
  case OpCode::I16x8__min_u:
1721
48.7k
  case OpCode::I16x8__max_s:
1722
50.0k
  case OpCode::I16x8__max_u:
1723
50.2k
  case OpCode::I16x8__avgr_u:
1724
50.5k
  case OpCode::I16x8__extmul_low_i8x16_s:
1725
51.1k
  case OpCode::I16x8__extmul_high_i8x16_s:
1726
51.4k
  case OpCode::I16x8__extmul_low_i8x16_u:
1727
52.2k
  case OpCode::I16x8__extmul_high_i8x16_u:
1728
52.8k
  case OpCode::I16x8__q15mulr_sat_s:
1729
53.2k
  case OpCode::I32x4__add:
1730
53.4k
  case OpCode::I32x4__sub:
1731
53.7k
  case OpCode::I32x4__mul:
1732
54.1k
  case OpCode::I32x4__min_s:
1733
54.3k
  case OpCode::I32x4__min_u:
1734
54.5k
  case OpCode::I32x4__max_s:
1735
54.8k
  case OpCode::I32x4__max_u:
1736
55.1k
  case OpCode::I32x4__extmul_low_i16x8_s:
1737
55.4k
  case OpCode::I32x4__extmul_high_i16x8_s:
1738
55.8k
  case OpCode::I32x4__extmul_low_i16x8_u:
1739
56.2k
  case OpCode::I32x4__extmul_high_i16x8_u:
1740
56.7k
  case OpCode::I64x2__add:
1741
57.1k
  case OpCode::I64x2__sub:
1742
57.8k
  case OpCode::I64x2__mul:
1743
57.9k
  case OpCode::I64x2__extmul_low_i32x4_s:
1744
58.8k
  case OpCode::I64x2__extmul_high_i32x4_s:
1745
59.4k
  case OpCode::I64x2__extmul_low_i32x4_u:
1746
60.2k
  case OpCode::I64x2__extmul_high_i32x4_u:
1747
61.9k
  case OpCode::F32x4__add:
1748
62.7k
  case OpCode::F32x4__sub:
1749
63.4k
  case OpCode::F32x4__mul:
1750
63.7k
  case OpCode::F32x4__div:
1751
64.2k
  case OpCode::F32x4__min:
1752
64.7k
  case OpCode::F32x4__max:
1753
66.5k
  case OpCode::F32x4__pmin:
1754
67.0k
  case OpCode::F32x4__pmax:
1755
67.1k
  case OpCode::F64x2__add:
1756
68.0k
  case OpCode::F64x2__sub:
1757
68.4k
  case OpCode::F64x2__mul:
1758
68.7k
  case OpCode::F64x2__div:
1759
68.9k
  case OpCode::F64x2__min:
1760
69.1k
  case OpCode::F64x2__max:
1761
69.8k
  case OpCode::F64x2__pmin:
1762
70.3k
  case OpCode::F64x2__pmax:
1763
70.7k
  case OpCode::I32x4__dot_i16x8_s:
1764
70.7k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1765
70.7k
                      {ValType(TypeCode::V128)});
1766
236
  case OpCode::V128__bitselect:
1767
236
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1768
236
                       ValType(TypeCode::V128)},
1769
236
                      {ValType(TypeCode::V128)});
1770
254
  case OpCode::V128__any_true:
1771
665
  case OpCode::I8x16__all_true:
1772
1.85k
  case OpCode::I8x16__bitmask:
1773
2.29k
  case OpCode::I16x8__all_true:
1774
2.74k
  case OpCode::I16x8__bitmask:
1775
3.50k
  case OpCode::I32x4__all_true:
1776
4.92k
  case OpCode::I32x4__bitmask:
1777
5.72k
  case OpCode::I64x2__all_true:
1778
6.18k
  case OpCode::I64x2__bitmask:
1779
6.18k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::I32)});
1780
555
  case OpCode::I8x16__shl:
1781
2.30k
  case OpCode::I8x16__shr_s:
1782
2.95k
  case OpCode::I8x16__shr_u:
1783
3.11k
  case OpCode::I16x8__shl:
1784
3.71k
  case OpCode::I16x8__shr_s:
1785
3.95k
  case OpCode::I16x8__shr_u:
1786
5.68k
  case OpCode::I32x4__shl:
1787
6.10k
  case OpCode::I32x4__shr_s:
1788
7.01k
  case OpCode::I32x4__shr_u:
1789
7.29k
  case OpCode::I64x2__shl:
1790
8.51k
  case OpCode::I64x2__shr_s:
1791
8.65k
  case OpCode::I64x2__shr_u:
1792
8.65k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::I32)},
1793
8.65k
                      {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
163
  case OpCode::I32x4__relaxed_trunc_f64x2_u_zero:
1802
163
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)});
1803
63
  case OpCode::F32x4__relaxed_madd:
1804
193
  case OpCode::F32x4__relaxed_nmadd:
1805
216
  case OpCode::F64x2__relaxed_madd:
1806
269
  case OpCode::F64x2__relaxed_nmadd:
1807
310
  case OpCode::I8x16__relaxed_laneselect:
1808
401
  case OpCode::I16x8__relaxed_laneselect:
1809
507
  case OpCode::I32x4__relaxed_laneselect:
1810
645
  case OpCode::I64x2__relaxed_laneselect:
1811
645
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1812
645
                       ValType(TypeCode::V128)},
1813
645
                      {ValType(TypeCode::V128)});
1814
192
  case OpCode::F32x4__relaxed_min:
1815
266
  case OpCode::F32x4__relaxed_max:
1816
332
  case OpCode::F64x2__relaxed_min:
1817
413
  case OpCode::F64x2__relaxed_max:
1818
436
  case OpCode::I16x8__relaxed_q15mulr_s:
1819
567
  case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s:
1820
567
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1821
567
                      {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
433
  case OpCode::Atomic__fence:
1828
433
    return {};
1829
1830
98
  case OpCode::Memory__atomic__notify:
1831
98
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1832
98
                               {ValType(TypeCode::I32)});
1833
18
  case OpCode::Memory__atomic__wait32:
1834
18
    return checkMemArgAndTrans(32,
1835
18
                               {ValType(TypeCode::I32), ValType(TypeCode::I64)},
1836
18
                               {ValType(TypeCode::I32)});
1837
73
  case OpCode::Memory__atomic__wait64:
1838
73
    return checkMemArgAndTrans(64,
1839
73
                               {ValType(TypeCode::I64), ValType(TypeCode::I64)},
1840
73
                               {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.06M
  }
2028
2.06M
}
2029
2030
1.67M
void FormChecker::pushType(VType V) { ValStack.emplace_back(V); }
2031
2032
21.4k
void FormChecker::pushTypes(Span<const VType> Input) {
2033
21.4k
  for (auto Val : Input) {
2034
4.80k
    pushType(Val);
2035
4.80k
  }
2036
21.4k
}
2037
2038
1.72M
void FormChecker::pushTypes(Span<const ValType> Input) {
2039
1.72M
  for (auto Val : Input) {
2040
1.66M
    pushType(Val);
2041
1.66M
  }
2042
1.72M
}
2043
2044
1.82M
Expect<VType> FormChecker::popType() {
2045
1.82M
  if (ValStack.size() == CtrlStack.back().Height) {
2046
196k
    if (CtrlStack.back().IsUnreachable) {
2047
196k
      return unreachableVType();
2048
196k
    }
2049
    // Value stack underflow
2050
352
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2051
352
    spdlog::error("    Value stack underflow."sv);
2052
352
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2053
196k
  }
2054
1.63M
  auto T = std::move(ValStack.back());
2055
1.63M
  ValStack.pop_back();
2056
1.63M
  return T;
2057
1.82M
}
2058
2059
893k
Expect<VType> FormChecker::popType(ValType E) {
2060
893k
  EXPECTED_TRY(auto Type, popType());
2061
893k
  if (Type == unreachableVType()) {
2062
193k
    return E;
2063
193k
  }
2064
2065
700k
  if (!AST::TypeMatcher::matchType(Types, E, *Type)) {
2066
    // The expected value on the value stack does not match.
2067
673
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2068
673
    spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(E), VTypeToAST(Type)));
2069
673
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2070
673
  }
2071
699k
  return Type;
2072
700k
}
2073
2074
1.71M
Expect<void> FormChecker::popTypes(Span<const ValType> Input) {
2075
2.54M
  for (auto Val = Input.rbegin(); Val != Input.rend(); ++Val) {
2076
827k
    EXPECTED_TRY(popType(*Val));
2077
827k
  }
2078
1.71M
  return {};
2079
1.71M
}
2080
2081
void FormChecker::pushCtrl(Span<const ValType> In, Span<const ValType> Out,
2082
27.3k
                           const AST::Instruction *Jump, OpCode Code) {
2083
27.3k
  CtrlStack.emplace_back(In, Out, Jump, ValStack.size(), LocalInits.size(),
2084
27.3k
                         Code);
2085
27.3k
  pushTypes(In);
2086
27.3k
}
2087
2088
25.5k
Expect<FormChecker::CtrlFrame> FormChecker::popCtrl() {
2089
25.5k
  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
25.5k
  EXPECTED_TRY(popTypes(CtrlStack.back().EndTypes));
2096
25.3k
  if (ValStack.size() != CtrlStack.back().Height) {
2097
    // Value stack size does not match.
2098
99
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2099
99
    spdlog::error("    Value stack underflow."sv);
2100
99
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2101
99
  }
2102
  // When popping a frame, reset the locals initialized during this frame.
2103
25.4k
  for (size_t I = CtrlStack.back().InitedLocal; I < LocalInits.size(); I++) {
2104
122
    Locals[LocalInits[I]].IsInit = false;
2105
122
  }
2106
25.2k
  LocalInits.erase(LocalInits.begin() +
2107
25.2k
                       static_cast<uint32_t>(CtrlStack.back().InitedLocal),
2108
25.2k
                   LocalInits.end());
2109
25.2k
  auto Head = std::move(CtrlStack.back());
2110
25.2k
  CtrlStack.pop_back();
2111
25.2k
  return Head;
2112
25.3k
}
2113
2114
Span<const ValType>
2115
29.1k
FormChecker::getLabelTypes(const FormChecker::CtrlFrame &F) {
2116
29.1k
  if (F.Code == OpCode::Loop) {
2117
6.05k
    return F.StartTypes;
2118
6.05k
  }
2119
23.1k
  return F.EndTypes;
2120
29.1k
}
2121
2122
229k
Expect<void> FormChecker::unreachable() {
2123
1.14M
  while (ValStack.size() > CtrlStack.back().Height) {
2124
912k
    EXPECTED_TRY(popType());
2125
912k
  }
2126
229k
  CtrlStack.back().IsUnreachable = true;
2127
229k
  return {};
2128
229k
}
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.61M
  pushTypes(Put);
2134
1.61M
  return {};
2135
1.61M
}
2136
2137
6.77k
Expect<void> FormChecker::StackPopAny() {
2138
6.77k
  EXPECTED_TRY(popType());
2139
6.77k
  return {};
2140
6.77k
}
2141
2142
} // namespace Validator
2143
} // namespace WasmEdge