Coverage Report

Created: 2026-06-30 06:10

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
412
                   uint32_t Bound) {
22
412
  spdlog::error(Code);
23
412
  spdlog::error(ErrInfo::InfoForbidIndex(Cate, Idx, Bound));
24
412
  return Unexpect(Code);
25
412
}
26
27
// Helper function for extracting address type to TypeCode.
28
2.97k
TypeCode convAddrTypeToTypeCode(const AddressType AT) noexcept {
29
2.97k
  switch (AT) {
30
2.57k
  case AddressType::I32:
31
2.57k
    return TypeCode::I32;
32
406
  case AddressType::I64:
33
406
    return TypeCode::I64;
34
0
  default:
35
0
    assumingUnreachable();
36
2.97k
  }
37
2.97k
};
38
39
// Helper function for packing TypeCode to address type.
40
52.1k
AddressType convTypeCodeToAddrType(const TypeCode TC) noexcept {
41
52.1k
  switch (TC) {
42
51.7k
  case TypeCode::I32:
43
51.7k
    return AddressType::I32;
44
383
  case TypeCode::I64:
45
383
    return AddressType::I64;
46
0
  default:
47
0
    assumingUnreachable();
48
52.1k
  }
49
52.1k
};
50
51
} // namespace
52
53
20.1k
void FormChecker::reset(bool CleanGlobal) {
54
20.1k
  ValStack.clear();
55
20.1k
  CtrlStack.clear();
56
20.1k
  Locals.clear();
57
20.1k
  Returns.clear();
58
59
20.1k
  if (CleanGlobal) {
60
4.29k
    Types.clear();
61
4.29k
    Funcs.clear();
62
4.29k
    Tables.clear();
63
4.29k
    Mems.clear();
64
4.29k
    Globals.clear();
65
4.29k
    Datas.clear();
66
4.29k
    Elems.clear();
67
4.29k
    Refs.clear();
68
4.29k
    Tags.clear();
69
4.29k
    NumImportFuncs = 0;
70
4.29k
    NumImportGlobals = 0;
71
4.29k
  }
72
20.1k
}
73
74
Expect<void> FormChecker::validate(AST::InstrView Instrs,
75
15.8k
                                   Span<const ValType> RetVals) {
76
15.8k
  for (const ValType &Val : RetVals) {
77
13.2k
    Returns.push_back(Val);
78
13.2k
  }
79
15.8k
  return checkExpr(Instrs);
80
15.8k
}
81
82
138M
Expect<void> FormChecker::validate(const ValType &VT) const noexcept {
83
  // The value type should be validated for the type index case.
84
138M
  if (VT.isRefType() && VT.getHeapTypeCode() == TypeCode::TypeIndex) {
85
100M
    if (VT.getTypeIndex() >= Types.size()) {
86
45
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
87
45
      spdlog::error(ErrInfo::InfoForbidIndex(
88
45
          ErrInfo::IndexCategory::FunctionType, VT.getTypeIndex(),
89
45
          static_cast<uint32_t>(Types.size())));
90
45
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
91
45
    }
92
100M
  }
93
138M
  return {};
94
138M
}
95
96
8.05k
void FormChecker::addType(const AST::SubType &Type) { Types.push_back(&Type); }
97
98
18.3k
void FormChecker::addFunc(const uint32_t TypeIdx, const bool IsImport) {
99
18.3k
  if (Types.size() > TypeIdx) {
100
18.3k
    Funcs.emplace_back(TypeIdx);
101
18.3k
  }
102
18.3k
  if (IsImport) {
103
389
    NumImportFuncs++;
104
389
  }
105
18.3k
}
106
107
608
void FormChecker::addTable(const AST::TableType &Tab) {
108
608
  Tables.emplace_back(convAddrTypeToTypeCode(Tab.getLimit().getAddrType()),
109
608
                      Tab.getRefType());
110
608
}
111
112
2.36k
void FormChecker::addMemory(const AST::MemoryType &Mem) {
113
2.36k
  Mems.push_back(convAddrTypeToTypeCode(Mem.getLimit().getAddrType()));
114
2.36k
}
115
116
349
void FormChecker::addGlobal(const AST::GlobalType &Glob, const bool IsImport) {
117
  // The global type is confirmed in the loading phase.
118
349
  Globals.emplace_back(Glob.getValType(), Glob.getValMut());
119
349
  if (IsImport) {
120
56
    NumImportGlobals++;
121
56
  }
122
349
}
123
124
348
void FormChecker::addData(const AST::DataSegment &) {
125
348
  Datas.emplace_back(static_cast<uint32_t>(Datas.size()));
126
348
}
127
128
501
void FormChecker::addElem(const AST::ElementSegment &Elem) {
129
501
  Elems.emplace_back(Elem.getRefType());
130
501
}
131
132
11.8k
void FormChecker::addRef(const uint32_t FuncIdx) { Refs.emplace(FuncIdx); }
133
134
138M
void FormChecker::addLocal(const ValType &V, bool Initialized) {
135
138M
  Locals.emplace_back(V);
136
138M
  if (Initialized || V.isDefaultable()) {
137
138M
    LocalInits.push_back(static_cast<uint32_t>(Locals.size() - 1));
138
138M
    Locals.back().IsInit = true;
139
138M
  }
140
138M
}
141
142
91
void FormChecker::addTag(const uint32_t TypeIdx) { Tags.push_back(TypeIdx); }
143
144
1.21k
ValType FormChecker::VTypeToAST(const VType &V) {
145
1.21k
  if (!V) {
146
1
    return TypeCode::I32;
147
1
  }
148
1.21k
  return *V;
149
1.21k
}
150
151
15.8k
Expect<void> FormChecker::checkExpr(AST::InstrView Instrs) {
152
15.8k
  if (Instrs.size() > 0) {
153
    // Push ctrl frame ([] -> [Returns])
154
15.8k
    pushCtrl({}, Returns, &*Instrs.rbegin());
155
15.8k
    return checkInstrs(Instrs);
156
15.8k
  }
157
0
  return {};
158
15.8k
}
159
160
15.8k
Expect<void> FormChecker::checkInstrs(AST::InstrView Instrs) {
161
  // Validate instructions
162
2.14M
  for (auto &Instr : Instrs) {
163
2.14M
    EXPECTED_TRY(checkInstr(Instr).map_error([&Instr](auto E) {
164
2.14M
      spdlog::error(
165
2.14M
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
166
2.14M
      return E;
167
2.14M
    }));
168
2.14M
  }
169
14.1k
  return {};
170
15.8k
}
171
172
2.14M
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.14M
  auto checkTableIdx = [this](const uint32_t Idx) -> Expect<void> {
178
2.98k
    if (unlikely(Idx >= Tables.size())) {
179
53
      return logOutOfRange(ErrCode::Value::InvalidTableIdx,
180
53
                           ErrInfo::IndexCategory::Table, Idx,
181
53
                           static_cast<uint32_t>(Tables.size()));
182
53
    }
183
2.92k
    return {};
184
2.98k
  };
185
186
  // Helper lambda for checking whether the memory index is valid.
187
2.14M
  auto checkMemIdx = [this](const uint32_t Idx) -> Expect<void> {
188
57.8k
    if (unlikely(Idx >= Mems.size())) {
189
77
      return logOutOfRange(ErrCode::Value::InvalidMemoryIdx,
190
77
                           ErrInfo::IndexCategory::Memory, Idx,
191
77
                           static_cast<uint32_t>(Mems.size()));
192
77
    }
193
57.7k
    return {};
194
57.8k
  };
195
196
  // Helper lambda for checking whether the data index is valid.
197
2.14M
  auto checkDataIdx = [this](const uint32_t Idx) -> Expect<void> {
198
135
    if (unlikely(Idx >= Datas.size())) {
199
11
      return logOutOfRange(ErrCode::Value::InvalidDataIdx,
200
11
                           ErrInfo::IndexCategory::Data, Idx,
201
11
                           static_cast<uint32_t>(Datas.size()));
202
11
    }
203
124
    return {};
204
135
  };
205
206
  // Helper lambda for checking whether the element index is valid.
207
2.14M
  auto checkElemIdx = [this](const uint32_t Idx) -> Expect<void> {
208
83
    if (unlikely(Idx >= Elems.size())) {
209
8
      return logOutOfRange(ErrCode::Value::InvalidElemIdx,
210
8
                           ErrInfo::IndexCategory::Element, Idx,
211
8
                           static_cast<uint32_t>(Elems.size()));
212
8
    }
213
75
    return {};
214
83
  };
215
216
  // Helper lambda for checking whether the tag index is valid.
217
2.14M
  auto checkTagIdx = [this](const uint32_t Idx) -> Expect<void> {
218
31
    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
15
    return {};
224
31
  };
225
226
  // Helper lambda for checking the defined type.
227
2.14M
  auto checkDefinedType =
228
2.14M
      [this](uint32_t TIdx, TypeCode TC) -> Expect<const AST::CompositeType *> {
229
7.82k
    if (TIdx >= Types.size()) {
230
54
      return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx,
231
54
                           ErrInfo::IndexCategory::FunctionType, TIdx,
232
54
                           static_cast<uint32_t>(Types.size()));
233
54
    }
234
7.77k
    const auto &CType = Types[TIdx]->getCompositeType();
235
7.77k
    if (CType.getContentTypeCode() == TC) {
236
7.76k
      return &CType;
237
7.76k
    } else {
238
11
      spdlog::error(ErrCode::Value::TypeCheckFailed);
239
11
      return Unexpect(ErrCode::Value::TypeCheckFailed);
240
11
    }
241
7.77k
  };
242
243
  // Helper lambda for checking and resolving the block type.
244
2.14M
  auto checkBlockType = [this, checkDefinedType](std::vector<ValType> &Buffer,
245
2.14M
                                                 const BlockType &BType)
246
2.14M
      -> Expect<std::pair<Span<const ValType>, Span<const ValType>>> {
247
10.0k
    using ReturnType = std::pair<Span<const ValType>, Span<const ValType>>;
248
10.0k
    if (BType.isEmpty()) {
249
      // Empty case. t2* = none
250
2.91k
      return ReturnType{{}, {}};
251
7.15k
    } else if (BType.isValType()) {
252
      // ValType case. t2* = valtype
253
2.98k
      EXPECTED_TRY(validate(BType.getValType()));
254
2.98k
      Buffer[0] = BType.getValType();
255
2.98k
      return ReturnType{{}, Buffer};
256
4.17k
    } else {
257
      // Type index case. t2* = functype.returns.
258
4.17k
      EXPECTED_TRY(auto CompType,
259
4.15k
                   checkDefinedType(BType.getTypeIndex(), TypeCode::Func));
260
4.15k
      const auto &FType = CompType->getFuncType();
261
4.15k
      return ReturnType{FType.getParamTypes(), FType.getReturnTypes()};
262
4.17k
    }
263
10.0k
  };
264
265
  // Helper lambda for checking control stack depth and return index.
266
2.14M
  auto checkCtrlStackDepth = [this](uint32_t N) -> Expect<uint32_t> {
267
    // Check the control stack for at least N + 1 frames.
268
27.7k
    if (N >= CtrlStack.size()) {
269
      // Branch out of the stack.
270
57
      return logOutOfRange(ErrCode::Value::InvalidLabelIdx,
271
57
                           ErrInfo::IndexCategory::Label, N,
272
57
                           static_cast<uint32_t>(CtrlStack.size()));
273
57
    }
274
    // Return the index of the N-th element from the end.
275
27.7k
    return static_cast<uint32_t>(CtrlStack.size()) - UINT32_C(1) - N;
276
27.7k
  };
277
278
  // Helper lambda for checking lane index and performing transformation.
279
2.14M
  auto checkLaneAndTrans = [this,
280
2.14M
                            &Instr](uint32_t N, Span<const ValType> Take,
281
2.14M
                                    Span<const ValType> Put) -> Expect<void> {
282
8.51k
    if (Instr.getMemoryLane() >= N) {
283
13
      return logOutOfRange(ErrCode::Value::InvalidLaneIdx,
284
13
                           ErrInfo::IndexCategory::Lane, Instr.getMemoryLane(),
285
13
                           N);
286
13
    }
287
8.50k
    return StackTrans(Take, Put);
288
8.51k
  };
289
290
  // Helper lambda for checking memory alignment and performing transformation.
291
2.14M
  auto checkMemArgAndTrans = [this, checkMemIdx,
292
2.14M
                              &Instr](uint32_t N, Span<const ValType> Take,
293
2.14M
                                      Span<const ValType> Put,
294
2.14M
                                      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
50.8k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
301
    // Check the alignment.
302
50.8k
    auto IsAtomic = Instr.getOpCode() >= OpCode::Memory__atomic__notify &&
303
157
                    Instr.getOpCode() <= OpCode::I64__atomic__rmw32__cmpxchg_u;
304
50.8k
    if (Instr.getMemoryAlign() > 31 ||
305
50.8k
        (!IsAtomic && (1UL << Instr.getMemoryAlign()) > (N >> 3UL))) {
306
      // 2 ^ align must be <= N / 8.
307
23
      spdlog::error(ErrCode::Value::AlignmentTooLarge);
308
23
      spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3),
309
23
                                          Instr.getMemoryAlign()));
310
23
      return Unexpect(ErrCode::Value::AlignmentTooLarge);
311
23
    }
312
50.8k
    if (IsAtomic && (1UL << Instr.getMemoryAlign()) != (N >> 3UL)) {
313
      // 2 ^ align must be == N / 8.
314
20
      spdlog::error(ErrCode::Value::InvalidAlignment);
315
20
      spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3),
316
20
                                          Instr.getMemoryAlign()));
317
20
      return Unexpect(ErrCode::Value::InvalidAlignment);
318
20
    }
319
    // Check the memory offset validation.
320
50.7k
    auto ATCode = Mems[Instr.getTargetIndex()];
321
50.7k
    if (Instr.getMemoryOffset() >
322
50.7k
        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
50.7k
    if (CheckLane && Instr.getMemoryLane() >= 128 / N) {
328
13
      return logOutOfRange(ErrCode::Value::InvalidLaneIdx,
329
13
                           ErrInfo::IndexCategory::Lane, Instr.getMemoryLane(),
330
13
                           128 / N);
331
13
    }
332
    // Perform the stack change. Additionally pop the first arg (address type).
333
50.7k
    EXPECTED_TRY(popTypes(Take));
334
50.7k
    EXPECTED_TRY(popType(ATCode));
335
50.7k
    pushTypes(Put);
336
50.7k
    return {};
337
50.7k
  };
338
339
  // Helper lambda for checking value type matching.
340
2.14M
  auto checkTypesMatching = [this](Span<const ValType> Exp,
341
2.14M
                                   Span<const ValType> Got) -> Expect<void> {
342
1.94k
    if (!AST::TypeMatcher::matchTypes(Types, Exp, Got)) {
343
17
      std::vector<ValType> ExpV(Exp.begin(), Exp.end()),
344
17
          GotV(Got.begin(), Got.end());
345
17
      spdlog::error(ErrCode::Value::TypeCheckFailed);
346
17
      spdlog::error(ErrInfo::InfoMismatch(ExpV, GotV));
347
17
      return Unexpect(ErrCode::Value::TypeCheckFailed);
348
17
    }
349
1.92k
    return {};
350
1.94k
  };
351
352
  // Helper lambda for recording jump data.
353
2.14M
  auto recordJump = [this, &Instr](AST::Instruction::JumpDescriptor &Jump,
354
2.14M
                                   uint32_t Arity, uint32_t D) -> void {
355
27.6k
    const uint32_t Remain =
356
27.6k
        static_cast<uint32_t>(ValStack.size() - CtrlStack[D].Height);
357
27.6k
    Jump.StackEraseBegin = Remain + Arity;
358
27.6k
    Jump.StackEraseEnd = Arity;
359
27.6k
    Jump.PCOffset = static_cast<int32_t>(CtrlStack[D].Jump - &Instr);
360
27.6k
  };
361
362
  // Helper lambda for unpacking a value type.
363
2.14M
  auto unpackType = [](const ValType &T) -> ValType {
364
947
    if (T.isPackType()) {
365
408
      return ValType(TypeCode::I32);
366
408
    }
367
539
    return T;
368
947
  };
369
370
  // Helper lambda for downcasting into the top heap type.
371
2.14M
  auto toTopHeapType = [this](const ValType &T) -> ValType {
372
643
    assuming(T.isRefType());
373
643
    if (T.isAbsHeapType()) {
374
475
      switch (T.getHeapTypeCode()) {
375
23
      case TypeCode::NullFuncRef:
376
40
      case TypeCode::FuncRef:
377
40
        return TypeCode::FuncRef;
378
19
      case TypeCode::NullExternRef:
379
37
      case TypeCode::ExternRef:
380
37
        return TypeCode::ExternRef;
381
60
      case TypeCode::NullExnRef:
382
88
      case TypeCode::ExnRef:
383
88
        return TypeCode::ExnRef;
384
115
      case TypeCode::NullRef:
385
162
      case TypeCode::AnyRef:
386
190
      case TypeCode::EqRef:
387
233
      case TypeCode::I31Ref:
388
289
      case TypeCode::StructRef:
389
310
      case TypeCode::ArrayRef:
390
310
        return TypeCode::AnyRef;
391
0
      default:
392
0
        assumingUnreachable();
393
475
      }
394
475
    } else {
395
168
      const auto &CompType = Types[T.getTypeIndex()]->getCompositeType();
396
168
      if (CompType.isFunc()) {
397
19
        return TypeCode::FuncRef;
398
149
      } else {
399
149
        return TypeCode::AnyRef;
400
149
      }
401
168
    }
402
643
  };
403
404
2.14M
  switch (Instr.getOpCode()) {
405
  // Control instructions.
406
226k
  case OpCode::Unreachable:
407
226k
    return unreachable();
408
120k
  case OpCode::Nop:
409
120k
    return {};
410
411
4.24k
  case OpCode::Block:
412
6.57k
  case OpCode::Loop:
413
9.96k
  case OpCode::If:
414
10.0k
  case OpCode::Try_table: {
415
    // Get blocktype [t1*] -> [t2*] and check valtype first.
416
10.0k
    std::vector<ValType> Buffer(1);
417
10.0k
    const auto &BType = (Instr.getOpCode() == OpCode::Try_table)
418
10.0k
                            ? Instr.getTryCatch().ResType
419
10.0k
                            : Instr.getBlockType();
420
10.0k
    EXPECTED_TRY(auto T1T2, checkBlockType(Buffer, BType));
421
10.0k
    auto [T1, T2] = T1T2;
422
    // For the if instruction, pop I32 first.
423
10.0k
    if (Instr.getOpCode() == OpCode::If) {
424
3.37k
      EXPECTED_TRY(popType(TypeCode::I32));
425
3.37k
    }
426
    // Pop and check [t1*]
427
10.0k
    EXPECTED_TRY(popTypes(T1));
428
    // For the try_table instruction, validate the handlers.
429
10.0k
    if (Instr.getOpCode() == OpCode::Try_table) {
430
104
      const auto &TryDesc = Instr.getTryCatch();
431
104
      const_cast<AST::Instruction::TryDescriptor &>(TryDesc).BlockParamNum =
432
104
          static_cast<uint32_t>(T1.size());
433
      // Validate catch clause.
434
104
      for (const auto &C : TryDesc.Catch) {
435
88
        if (!C.IsAll) {
436
          // Check tag index.
437
6
          EXPECTED_TRY(checkTagIdx(C.TagIndex));
438
          // Result types of tag indices are checked in the tag section.
439
6
        }
440
158
        EXPECTED_TRY(auto D, checkCtrlStackDepth(C.LabelIndex));
441
158
        pushCtrl({}, getLabelTypes(CtrlStack[D]), &Instr + TryDesc.JumpEnd,
442
158
                 Instr.getOpCode());
443
158
        std::vector<ValType> NTypes;
444
158
        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
158
        if (C.IsRef) {
452
29
          NTypes.emplace_back(ValType(TypeCode::Ref, TypeCode::ExnRef));
453
29
        }
454
158
        pushTypes(NTypes);
455
158
        EXPECTED_TRY(popCtrl());
456
73
        recordJump(const_cast<AST::Instruction::JumpDescriptor &>(C.Jump),
457
73
                   static_cast<uint32_t>(NTypes.size()), D);
458
73
      }
459
104
    }
460
    // Push ctrl frame ([t1*], [t2*])
461
10.0k
    const AST::Instruction *From = nullptr;
462
10.0k
    if (Instr.getOpCode() == OpCode::Loop) {
463
2.32k
      From = &Instr;
464
7.69k
    } else if (Instr.getOpCode() == OpCode::Try_table) {
465
89
      From = &Instr + Instr.getTryCatch().JumpEnd;
466
7.60k
    } else {
467
7.60k
      From = &Instr + Instr.getJumpEnd();
468
7.60k
    }
469
10.0k
    pushCtrl(T1, T2, From, Instr.getOpCode());
470
10.0k
    if (Instr.getOpCode() == OpCode::If &&
471
3.36k
        Instr.getJumpElse() == Instr.getJumpEnd()) {
472
      // No else case in if-else statement.
473
1.52k
      EXPECTED_TRY(checkTypesMatching(T2, T1));
474
1.52k
    }
475
10.0k
    return {};
476
10.0k
  }
477
478
1.84k
  case OpCode::Else: {
479
1.84k
    EXPECTED_TRY(auto Ctrl, popCtrl());
480
1.83k
    pushCtrl(Ctrl.StartTypes, Ctrl.EndTypes, Ctrl.Jump, Instr.getOpCode());
481
1.83k
    return {};
482
1.84k
  }
483
484
25
  case OpCode::Throw: {
485
25
    EXPECTED_TRY(checkTagIdx(Instr.getTargetIndex()));
486
30
    EXPECTED_TRY(auto CompType, checkDefinedType(Tags[Instr.getTargetIndex()],
487
30
                                                 TypeCode::Func));
488
30
    std::vector<ValType> Input = CompType->getFuncType().getParamTypes();
489
30
    EXPECTED_TRY(popTypes(Input));
490
13
    return unreachable();
491
30
  }
492
493
391
  case OpCode::Throw_ref:
494
391
    EXPECTED_TRY(popType(TypeCode::ExnRef));
495
386
    return unreachable();
496
497
24.0k
  case OpCode::End: {
498
24.0k
    EXPECTED_TRY(auto Ctrl, popCtrl());
499
23.8k
    pushTypes(Ctrl.EndTypes);
500
23.8k
    return {};
501
24.0k
  }
502
503
2.43k
  case OpCode::Br: {
504
2.43k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
505
    // D is the last D element of control stack.
506
2.42k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
507
2.42k
    EXPECTED_TRY(popTypes(NTypes));
508
2.41k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
509
2.41k
               static_cast<uint32_t>(NTypes.size()), D);
510
2.41k
    return unreachable();
511
2.42k
  }
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.63k
  case OpCode::Br_table: {
524
1.63k
    EXPECTED_TRY(popType(TypeCode::I32));
525
1.62k
    auto LabelTable = const_cast<AST::Instruction &>(Instr).getLabelList();
526
1.62k
    const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
527
1.62k
    EXPECTED_TRY(auto M,
528
1.61k
                 checkCtrlStackDepth(LabelTable[LabelTableSize].TargetIndex));
529
    // M is the M-th element from the end of the control stack.
530
1.61k
    auto MTypes = getLabelTypes(CtrlStack[M]);
531
23.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
25.9k
      for (uint32_t IdxN = static_cast<uint32_t>(NTypes.size()); IdxN >= 1;
542
21.4k
           --IdxN) {
543
4.45k
        const uint32_t Idx = IdxN - 1;
544
        // Cannot use popTypes() here because we need the popped value.
545
4.45k
        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.45k
        if (CtrlStack.back().IsUnreachable) {
549
689
          TypeBuf[Idx] = unreachableVType();
550
3.76k
        } else {
551
3.76k
          TypeBuf[Idx] = Type;
552
3.76k
        }
553
4.45k
      }
554
21.4k
      recordJump(LabelTable[LabelIdx], static_cast<uint32_t>(NTypes.size()), N);
555
21.4k
      pushTypes(TypeBuf);
556
21.4k
    }
557
1.59k
    const auto NTypes = getLabelTypes(CtrlStack[M]);
558
1.59k
    EXPECTED_TRY(popTypes(NTypes));
559
1.59k
    recordJump(LabelTable[LabelTableSize], static_cast<uint32_t>(NTypes.size()),
560
1.59k
               M);
561
1.59k
    return unreachable();
562
1.59k
  }
563
564
333
  case OpCode::Br_on_null: {
565
    // D is the last D element of control stack.
566
333
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
567
329
    const auto NTypes = getLabelTypes(CtrlStack[D]);
568
329
    EXPECTED_TRY(auto ResT, popType());
569
328
    if (ResT.has_value() && !ResT->isRefType()) {
570
2
      spdlog::error(ErrCode::Value::InvalidBrRefType);
571
2
      return Unexpect(ErrCode::ErrCode::Value::InvalidBrRefType);
572
2
    }
573
326
    EXPECTED_TRY(popTypes(NTypes));
574
324
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
575
324
               static_cast<uint32_t>(NTypes.size()), D);
576
324
    pushTypes(NTypes);
577
324
    if (ResT.has_value()) {
578
45
      pushType(ResT->toNonNullableRef());
579
279
    } else {
580
279
      pushType(unreachableVType());
581
279
    }
582
324
    return {};
583
326
  }
584
585
111
  case OpCode::Br_on_non_null: {
586
111
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
587
    // Get the result type of the label. (Should be [t* rt].)
588
109
    auto LabelTypes = getLabelTypes(CtrlStack[D]);
589
109
    std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end());
590
109
    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
107
    ValType &RT = NTypes.back();
596
107
    if (!RT.isRefType()) {
597
1
      spdlog::error(ErrCode::Value::InvalidBrRefType);
598
1
      return Unexpect(ErrCode::Value::InvalidBrRefType);
599
1
    }
600
106
    RT.toNullableRef();
601
106
    EXPECTED_TRY(popTypes(NTypes));
602
103
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
603
103
               static_cast<uint32_t>(NTypes.size()), D);
604
    // Push types [t*].
605
103
    NTypes.pop_back();
606
103
    pushTypes(NTypes);
607
103
    return {};
608
106
  }
609
610
2.30k
  case OpCode::Return:
611
2.30k
    EXPECTED_TRY(popTypes(Returns));
612
2.30k
    return unreachable();
613
614
4.83k
  case OpCode::Call: {
615
4.83k
    auto N = Instr.getTargetIndex();
616
4.83k
    if (unlikely(N >= Funcs.size())) {
617
32
      return logOutOfRange(ErrCode::Value::InvalidFuncIdx,
618
32
                           ErrInfo::IndexCategory::Function, N,
619
32
                           static_cast<uint32_t>(Funcs.size()));
620
32
    }
621
    // Because functions were validated when added, Type[Funcs[N]] must be a
622
    // function type.
623
4.80k
    auto &FuncType = Types[Funcs[N]]->getCompositeType().getFuncType();
624
4.80k
    return StackTrans(FuncType.getParamTypes(), FuncType.getReturnTypes());
625
4.83k
  }
626
1.46k
  case OpCode::Call_indirect: {
627
1.46k
    auto N = Instr.getTargetIndex();
628
1.46k
    auto T = Instr.getSourceIndex();
629
    // Check source table index.
630
1.46k
    EXPECTED_TRY(checkTableIdx(T));
631
1.44k
    if (!AST::TypeMatcher::matchType(Types, TypeCode::FuncRef,
632
1.44k
                                     Tables[T].second)) {
633
1
      spdlog::error(ErrCode::Value::TypeCheckFailed);
634
1
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, Tables[T].second));
635
1
      return Unexpect(ErrCode::Value::TypeCheckFailed);
636
1
    }
637
    // Check target function type index.
638
2.88k
    EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func));
639
2.88k
    EXPECTED_TRY(popType(Tables[T].first));
640
1.44k
    const auto &FType = CompType->getFuncType();
641
1.44k
    return StackTrans(FType.getParamTypes(), FType.getReturnTypes());
642
2.88k
  }
643
85
  case OpCode::Return_call: {
644
85
    auto N = Instr.getTargetIndex();
645
85
    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
81
    auto &FType = Types[Funcs[N]]->getCompositeType().getFuncType();
656
81
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
657
80
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
658
79
    return unreachable();
659
80
  }
660
258
  case OpCode::Return_call_indirect: {
661
258
    auto N = Instr.getTargetIndex();
662
258
    auto T = Instr.getSourceIndex();
663
    // Check source table index.
664
258
    EXPECTED_TRY(checkTableIdx(T));
665
253
    if (!AST::TypeMatcher::matchType(Types, TypeCode::FuncRef,
666
253
                                     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
503
    EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func));
673
503
    const auto &FType = CompType->getFuncType();
674
503
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
675
250
    EXPECTED_TRY(popType(Tables[T].first));
676
248
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
677
246
    return unreachable();
678
248
  }
679
481
  case OpCode::Call_ref: {
680
481
    EXPECTED_TRY(auto CompType,
681
476
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Func));
682
476
    const auto &FType = CompType->getFuncType();
683
476
    std::vector<ValType> Input = FType.getParamTypes();
684
476
    Input.push_back(ValType(TypeCode::RefNull, Instr.getTargetIndex()));
685
476
    return StackTrans(Input, FType.getReturnTypes());
686
481
  }
687
89
  case OpCode::Return_call_ref: {
688
89
    EXPECTED_TRY(auto CompType,
689
86
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Func));
690
86
    const auto &FType = CompType->getFuncType();
691
86
    EXPECTED_TRY(checkTypesMatching(Returns, FType.getReturnTypes()));
692
85
    EXPECTED_TRY(popType(ValType(TypeCode::RefNull, Instr.getTargetIndex())));
693
83
    EXPECTED_TRY(popTypes(FType.getParamTypes()));
694
82
    return unreachable();
695
83
  }
696
697
  // Reference Instructions.
698
14.6k
  case OpCode::Ref__null: {
699
14.6k
    EXPECTED_TRY(validate(Instr.getValType()));
700
14.6k
    return StackTrans({}, {Instr.getValType()});
701
14.6k
  }
702
6.37k
  case OpCode::Ref__is_null: {
703
6.37k
    EXPECTED_TRY(auto Type, popType());
704
6.37k
    if (Type.has_value() && !Type->isRefType()) {
705
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
706
3
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, VTypeToAST(Type)));
707
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
708
3
    }
709
6.37k
    return StackTrans({}, {ValType(TypeCode::I32)});
710
6.37k
  }
711
1.37k
  case OpCode::Ref__func: {
712
1.37k
    auto FuncIdx = Instr.getTargetIndex();
713
1.37k
    if (Refs.find(FuncIdx) == Refs.cend()) {
714
      // Undeclared function reference.
715
22
      spdlog::error(ErrCode::Value::InvalidRefIdx);
716
22
      return Unexpect(ErrCode::Value::InvalidRefIdx);
717
22
    }
718
1.34k
    assuming(FuncIdx < Funcs.size());
719
1.34k
    auto TypeIdx = Funcs[FuncIdx];
720
1.34k
    assuming(TypeIdx < Types.size());
721
1.34k
    return StackTrans({}, {ValType(TypeCode::Ref, TypeIdx)});
722
1.34k
  }
723
53
  case OpCode::Ref__eq:
724
53
    return StackTrans({ValType(TypeCode::RefNull, TypeCode::EqRef),
725
53
                       ValType(TypeCode::RefNull, TypeCode::EqRef)},
726
53
                      {ValType(TypeCode::I32)});
727
1.18k
  case OpCode::Ref__as_non_null: {
728
1.18k
    EXPECTED_TRY(auto Type, popType());
729
1.18k
    if (Type == unreachableVType()) {
730
541
      pushType(unreachableVType());
731
541
      return {};
732
541
    }
733
646
    if (!Type->isRefType()) {
734
4
      spdlog::error(ErrCode::Value::TypeCheckFailed);
735
4
      spdlog::error(ErrInfo::InfoMismatch(
736
4
          ValType(TypeCode::RefNull, TypeCode::FuncRef), VTypeToAST(Type)));
737
4
      return Unexpect(ErrCode::Value::TypeCheckFailed);
738
4
    }
739
642
    return StackTrans({}, {Type->toNonNullableRef()});
740
646
  }
741
742
109
  case OpCode::Struct__new:
743
204
  case OpCode::Struct__new_default: {
744
204
    EXPECTED_TRY(auto CompType,
745
191
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct));
746
191
    std::vector<ValType> Fields;
747
191
    if (Instr.getOpCode() == OpCode::Struct__new) {
748
99
      Fields.reserve(CompType->getFieldTypes().size());
749
99
    }
750
191
    for (auto &FType : CompType->getFieldTypes()) {
751
5
      if (Instr.getOpCode() == OpCode::Struct__new) {
752
3
        Fields.emplace_back(unpackType(FType.getStorageType()));
753
3
      } 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
5
    }
759
191
    return StackTrans(Fields, {ValType(TypeCode::Ref, Instr.getTargetIndex())});
760
191
  }
761
3
  case OpCode::Struct__get:
762
5
  case OpCode::Struct__get_s:
763
6
  case OpCode::Struct__get_u: {
764
6
    EXPECTED_TRY(auto CompType,
765
5
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct));
766
5
    if (Instr.getSourceIndex() >= CompType->getFieldTypes().size()) {
767
1
      return logOutOfRange(
768
1
          ErrCode::Value::InvalidFieldIdx, ErrInfo::IndexCategory::Field,
769
1
          Instr.getSourceIndex(),
770
1
          static_cast<uint32_t>(CompType->getFieldTypes().size()));
771
1
    }
772
4
    const auto &FType = CompType->getFieldTypes()[Instr.getSourceIndex()];
773
4
    if (unlikely(Instr.getOpCode() == OpCode::Struct__get &&
774
2
                 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
3
    } 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
2
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex())},
785
2
                      {unpackType(FType.getStorageType())});
786
4
  }
787
7
  case OpCode::Struct__set: {
788
7
    EXPECTED_TRY(auto CompType,
789
5
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct));
790
5
    if (Instr.getSourceIndex() >= CompType->getFieldTypes().size()) {
791
2
      return logOutOfRange(
792
2
          ErrCode::Value::InvalidFieldIdx, ErrInfo::IndexCategory::Field,
793
2
          Instr.getSourceIndex(),
794
2
          static_cast<uint32_t>(CompType->getFieldTypes().size()));
795
2
    }
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
346
  case OpCode::Array__new_default:
807
435
  case OpCode::Array__new_fixed: {
808
435
    EXPECTED_TRY(auto CompType,
809
426
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
810
426
    const auto &SType = CompType->getFieldTypes()[0].getStorageType();
811
426
    if (Instr.getOpCode() == OpCode::Array__new) {
812
271
      return StackTrans({unpackType(SType), ValType(TypeCode::I32)},
813
271
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
814
271
    } else if (Instr.getOpCode() == OpCode::Array__new_default) {
815
67
      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
67
      return StackTrans({ValType(TypeCode::I32)},
821
67
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
822
88
    } else {
823
88
      std::vector<ValType> Fields(Instr.getSourceIndex(), unpackType(SType));
824
88
      return StackTrans(Fields,
825
88
                        {ValType(TypeCode::Ref, Instr.getTargetIndex())});
826
88
    }
827
426
  }
828
3
  case OpCode::Array__new_data:
829
8
  case OpCode::Array__init_data: {
830
8
    EXPECTED_TRY(auto CompType,
831
5
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
832
5
    const auto &FType = CompType->getFieldTypes()[0];
833
5
    if (Instr.getOpCode() == OpCode::Array__init_data &&
834
3
        FType.getValMut() != ValMut::Var) {
835
1
      spdlog::error(ErrCode::Value::ImmutableArray);
836
1
      return Unexpect(ErrCode::Value::ImmutableArray);
837
1
    }
838
4
    if (!unpackType(FType.getStorageType()).isNumType()) {
839
1
      spdlog::error(ErrCode::Value::ArrayTypesNumtypeRequired);
840
1
      return Unexpect(ErrCode::Value::ArrayTypesNumtypeRequired);
841
1
    }
842
3
    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
2
  case OpCode::Array__new_elem:
854
5
  case OpCode::Array__init_elem: {
855
5
    EXPECTED_TRY(auto CompType,
856
3
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
857
3
    const auto &FType = CompType->getFieldTypes()[0];
858
3
    if (Instr.getOpCode() == OpCode::Array__init_elem &&
859
2
        FType.getValMut() != ValMut::Var) {
860
1
      spdlog::error(ErrCode::Value::ImmutableArray);
861
1
      return Unexpect(ErrCode::Value::ImmutableArray);
862
1
    }
863
2
    if (!FType.getStorageType().isRefType()) {
864
1
      spdlog::error(ErrCode::Value::TypeCheckFailed);
865
1
      return Unexpect(ErrCode::Value::TypeCheckFailed);
866
1
    }
867
1
    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
407
  case OpCode::Array__get_s:
887
474
  case OpCode::Array__get_u: {
888
474
    EXPECTED_TRY(auto CompType,
889
469
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
890
469
    const auto &FType = CompType->getFieldTypes()[0];
891
469
    if (unlikely(Instr.getOpCode() == OpCode::Array__get &&
892
235
                 FType.getStorageType().isPackType())) {
893
      // For a packed type, the `_s` or `_u` in the instruction is required.
894
2
      spdlog::error(ErrCode::Value::InvalidPackedArray);
895
2
      return Unexpect(ErrCode::Value::InvalidPackedArray);
896
467
    } else if (unlikely(Instr.getOpCode() != OpCode::Array__get &&
897
234
                        !FType.getStorageType().isPackType())) {
898
      // The `_s` or `_u` in instruction only accepts packed array.
899
1
      spdlog::error(ErrCode::Value::InvalidUnpackedArray);
900
1
      return Unexpect(ErrCode::Value::InvalidUnpackedArray);
901
1
    }
902
466
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
903
466
                       ValType(TypeCode::I32)},
904
466
                      {unpackType(FType.getStorageType())});
905
469
  }
906
67
  case OpCode::Array__set:
907
115
  case OpCode::Array__fill: {
908
115
    EXPECTED_TRY(auto CompType,
909
113
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
910
113
    const auto &FType = CompType->getFieldTypes()[0];
911
113
    if (FType.getValMut() != ValMut::Var) {
912
2
      spdlog::error(ErrCode::Value::ImmutableArray);
913
2
      return Unexpect(ErrCode::Value::ImmutableArray);
914
2
    }
915
111
    std::vector<ValType> Fields = {
916
111
        ValType(TypeCode::RefNull, Instr.getTargetIndex()),
917
111
        ValType(TypeCode::I32), unpackType(FType.getStorageType())};
918
111
    if (Instr.getOpCode() == OpCode::Array__fill) {
919
45
      Fields.emplace_back(ValType(TypeCode::I32));
920
45
    }
921
111
    return StackTrans(Fields, {});
922
113
  }
923
119
  case OpCode::Array__len:
924
119
    return StackTrans({ValType(TypeCode::ArrayRef)}, {ValType(TypeCode::I32)});
925
62
  case OpCode::Array__copy: {
926
62
    EXPECTED_TRY(auto CompType,
927
61
                 checkDefinedType(Instr.getTargetIndex(), TypeCode::Array));
928
61
    const auto &DstFType = CompType->getFieldTypes()[0];
929
61
    if (DstFType.getValMut() != ValMut::Var) {
930
1
      spdlog::error(ErrCode::Value::ImmutableArray);
931
1
      return Unexpect(ErrCode::Value::ImmutableArray);
932
1
    }
933
118
    EXPECTED_TRY(auto Src,
934
118
                 checkDefinedType(Instr.getSourceIndex(), TypeCode::Array));
935
118
    const auto &SrcFType = Src->getFieldTypes()[0];
936
118
    if (!AST::TypeMatcher::matchType(Types, DstFType.getStorageType(),
937
58
                                     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
58
    return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()),
944
58
                       ValType(TypeCode::I32),
945
58
                       ValType(TypeCode::RefNull, Instr.getSourceIndex()),
946
58
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
947
58
                      {});
948
118
  }
949
950
23
  case OpCode::Ref__test:
951
107
  case OpCode::Ref__test_null:
952
458
  case OpCode::Ref__cast:
953
682
  case OpCode::Ref__cast_null: {
954
682
    EXPECTED_TRY(validate(Instr.getValType()));
955
1.33k
    EXPECTED_TRY(auto Type, popType());
956
1.33k
    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
667
    if (Type.has_value() &&
966
643
        !AST::TypeMatcher::matchType(Types, toTopHeapType(*Type),
967
643
                                     Instr.getValType())) {
968
18
      spdlog::error(ErrCode::Value::TypeCheckFailed);
969
18
      spdlog::error(ErrInfo::InfoMismatch(*Type, Instr.getValType()));
970
18
      return Unexpect(ErrCode::Value::TypeCheckFailed);
971
18
    }
972
649
    if (Instr.getOpCode() == OpCode::Ref__test ||
973
629
        Instr.getOpCode() == OpCode::Ref__test_null) {
974
102
      return StackTrans({}, {ValType(TypeCode::I32)});
975
547
    } else {
976
547
      return StackTrans({}, {Instr.getValType()});
977
547
    }
978
649
  }
979
37
  case OpCode::Br_on_cast:
980
56
  case OpCode::Br_on_cast_fail: {
981
    // The reference types should be valid.
982
56
    auto &RT1 = Instr.getBrCast().RType1;
983
56
    auto &RT2 = Instr.getBrCast().RType2;
984
56
    EXPECTED_TRY(validate(RT1));
985
54
    EXPECTED_TRY(validate(RT2));
986
    // The reference type RT2 should match RT1.
987
51
    if (unlikely(!AST::TypeMatcher::matchType(Types, RT1, RT2))) {
988
6
      spdlog::error(ErrCode::Value::TypeCheckFailed);
989
6
      spdlog::error(ErrInfo::InfoMismatch(RT1, RT2));
990
6
      return Unexpect(ErrCode::Value::TypeCheckFailed);
991
6
    }
992
83
    EXPECTED_TRY(auto D,
993
83
                 checkCtrlStackDepth(Instr.getBrCast().Jump.TargetIndex));
994
    // Get the result type of the label. (Should be [t* rt'].)
995
83
    auto LabelTypes = getLabelTypes(CtrlStack[D]);
996
83
    std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end());
997
83
    if (unlikely(NTypes.empty())) {
998
2
      spdlog::error(ErrCode::Value::InvalidBrRefType);
999
2
      return Unexpect(ErrCode::Value::InvalidBrRefType);
1000
2
    }
1001
    // Get the type difference between rt1 \ rt2. (rt1' = rt1 \ rt2)
1002
36
    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
36
    ValType &RTP = NTypes.back();
1006
36
    const ValType &RTRHS = Instr.getOpCode() == OpCode::Br_on_cast ? RT2 : RT1P;
1007
36
    if (unlikely(!AST::TypeMatcher::matchType(Types, RTP, RTRHS))) {
1008
2
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1009
2
      spdlog::error(ErrInfo::InfoMismatch(RTP, RTRHS));
1010
2
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1011
2
    }
1012
    // Pop types [t* rt1].
1013
34
    RTP = RT1;
1014
34
    EXPECTED_TRY(popTypes(NTypes));
1015
31
    recordJump(const_cast<AST::Instruction &>(Instr).getBrCast().Jump,
1016
31
               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
31
    RTP = Instr.getOpCode() == OpCode::Br_on_cast ? RT1P : RT2;
1020
31
    pushTypes(NTypes);
1021
31
    return {};
1022
34
  }
1023
102
  case OpCode::Any__convert_extern: {
1024
102
    EXPECTED_TRY(auto Type, popType(TypeCode::ExternRef));
1025
97
    return StackTrans({}, {ValType(Type->getCode(), TypeCode::AnyRef)});
1026
102
  }
1027
57
  case OpCode::Extern__convert_any: {
1028
57
    EXPECTED_TRY(auto Type, popType(TypeCode::AnyRef));
1029
56
    return StackTrans({}, {ValType(Type->getCode(), TypeCode::ExternRef)});
1030
57
  }
1031
157
  case OpCode::Ref__i31:
1032
157
    return StackTrans({ValType(TypeCode::I32)},
1033
157
                      {ValType(TypeCode::Ref, TypeCode::I31Ref)});
1034
71
  case OpCode::I31__get_s:
1035
135
  case OpCode::I31__get_u:
1036
135
    return StackTrans({ValType(TypeCode::RefNull, TypeCode::I31Ref)},
1037
135
                      {ValType(TypeCode::I32)});
1038
1039
  // Parametric Instructions.
1040
6.69k
  case OpCode::Drop:
1041
6.69k
    return StackPopAny();
1042
3.89k
  case OpCode::Select: {
1043
    // Pop I32.
1044
3.89k
    EXPECTED_TRY(popType(TypeCode::I32));
1045
    // Pop T1 and T2.
1046
7.78k
    EXPECTED_TRY(VType T1, popType());
1047
7.78k
    EXPECTED_TRY(VType T2, popType());
1048
    // T1 and T2 should be number type.
1049
3.88k
    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.88k
    if (T2.has_value() && !T2->isNumType()) {
1055
2
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1056
2
      spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(T1), VTypeToAST(T2)));
1057
2
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1058
2
    }
1059
    // Error if t1 != t2 && t1 =/= Unknown && t2 =/= Unknown
1060
3.88k
    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.88k
    if (T1 == unreachableVType()) {
1067
2.10k
      pushType(T2);
1068
2.10k
    } else {
1069
1.77k
      pushType(T1);
1070
1.77k
    }
1071
3.88k
    return {};
1072
3.88k
  }
1073
567
  case OpCode::Select_t: {
1074
    // Note: There may be multiple values choice in the future.
1075
567
    if (Instr.getValTypeList().size() != 1) {
1076
9
      spdlog::error(ErrCode::Value::InvalidResultArity);
1077
9
      return Unexpect(ErrCode::Value::InvalidResultArity);
1078
9
    }
1079
558
    ValType ExpT = Instr.getValTypeList()[0];
1080
558
    EXPECTED_TRY(validate(ExpT));
1081
556
    EXPECTED_TRY(popTypes({ExpT, ExpT, ValType(TypeCode::I32)}));
1082
555
    pushType(ExpT);
1083
555
    return {};
1084
556
  }
1085
1086
  // Variable Instructions.
1087
13.7k
  case OpCode::Local__get:
1088
19.1k
  case OpCode::Local__set:
1089
23.5k
  case OpCode::Local__tee: {
1090
23.5k
    if (Instr.getTargetIndex() >= Locals.size()) {
1091
39
      return logOutOfRange(
1092
39
          ErrCode::Value::InvalidLocalIdx, ErrInfo::IndexCategory::Local,
1093
39
          Instr.getTargetIndex(), static_cast<uint32_t>(Locals.size()));
1094
39
    }
1095
23.5k
    auto &TExpect = Locals[Instr.getTargetIndex()];
1096
23.5k
    const_cast<AST::Instruction &>(Instr).getStackOffset() =
1097
23.5k
        static_cast<uint32_t>(ValStack.size() +
1098
23.5k
                              (Locals.size() - Instr.getTargetIndex()));
1099
23.5k
    if (Instr.getOpCode() == OpCode::Local__get) {
1100
13.7k
      if (!TExpect.IsInit) {
1101
2
        spdlog::error(ErrCode::Value::InvalidUninitLocal);
1102
2
        return Unexpect(ErrCode::Value::InvalidUninitLocal);
1103
2
      }
1104
13.7k
      return StackTrans({}, {TExpect.VType});
1105
13.7k
    } else if (Instr.getOpCode() == OpCode::Local__set) {
1106
5.38k
      if (!TExpect.IsInit) {
1107
49
        TExpect.IsInit = true;
1108
49
        LocalInits.push_back(Instr.getTargetIndex());
1109
49
      }
1110
5.38k
      return StackTrans({TExpect.VType}, {});
1111
5.38k
    } else if (Instr.getOpCode() == OpCode::Local__tee) {
1112
4.41k
      if (!TExpect.IsInit) {
1113
109
        TExpect.IsInit = true;
1114
109
        LocalInits.push_back(Instr.getTargetIndex());
1115
109
      }
1116
4.41k
      return StackTrans({TExpect.VType}, {TExpect.VType});
1117
4.41k
    } else {
1118
0
      assumingUnreachable();
1119
0
    }
1120
23.5k
  }
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.46k
  case OpCode::Global__get: {
1131
3.46k
    if (Instr.getTargetIndex() >= Globals.size()) {
1132
36
      return logOutOfRange(
1133
36
          ErrCode::Value::InvalidGlobalIdx, ErrInfo::IndexCategory::Global,
1134
36
          Instr.getTargetIndex(), static_cast<uint32_t>(Globals.size()));
1135
36
    }
1136
3.43k
    ValType ExpT = Globals[Instr.getTargetIndex()].first;
1137
3.43k
    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.43k
  }
1143
1144
  // Table Instructions.
1145
139
  case OpCode::Table__get:
1146
139
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1147
130
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first)},
1148
130
                      {Tables[Instr.getTargetIndex()].second});
1149
346
  case OpCode::Table__set:
1150
346
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1151
342
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1152
342
                       Tables[Instr.getTargetIndex()].second},
1153
342
                      {});
1154
37
  case OpCode::Table__init:
1155
37
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1156
36
    EXPECTED_TRY(checkElemIdx(Instr.getSourceIndex()));
1157
    // Check whether the reference types match.
1158
33
    if (!AST::TypeMatcher::matchType(Types,
1159
33
                                     Tables[Instr.getTargetIndex()].second,
1160
33
                                     Elems[Instr.getSourceIndex()])) {
1161
1
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1162
1
      spdlog::error(ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()].second,
1163
1
                                          Elems[Instr.getSourceIndex()]));
1164
1
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1165
1
    }
1166
32
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1167
32
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
1168
32
                      {});
1169
46
  case OpCode::Elem__drop:
1170
46
    EXPECTED_TRY(checkElemIdx(Instr.getTargetIndex()));
1171
42
    return {};
1172
285
  case OpCode::Table__copy: {
1173
285
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1174
280
    EXPECTED_TRY(checkTableIdx(Instr.getSourceIndex()));
1175
    // Check whether the reference types match.
1176
278
    if (!AST::TypeMatcher::matchType(Types,
1177
278
                                     Tables[Instr.getTargetIndex()].second,
1178
278
                                     Tables[Instr.getSourceIndex()].second)) {
1179
11
      spdlog::error(ErrCode::Value::TypeCheckFailed);
1180
11
      spdlog::error(
1181
11
          ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()].second,
1182
11
                                Tables[Instr.getSourceIndex()].second));
1183
11
      return Unexpect(ErrCode::Value::TypeCheckFailed);
1184
11
    }
1185
267
    auto ATDst = Tables[Instr.getTargetIndex()].first;
1186
267
    auto ATSrc = Tables[Instr.getSourceIndex()].first;
1187
267
    auto ATMin = convTypeCodeToAddrType(ATDst) <= convTypeCodeToAddrType(ATSrc)
1188
267
                     ? ATDst
1189
267
                     : ATSrc;
1190
267
    return StackTrans({ValType(ATDst), ValType(ATSrc), ValType(ATMin)}, {});
1191
278
  }
1192
79
  case OpCode::Table__grow:
1193
79
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1194
74
    return StackTrans({Tables[Instr.getTargetIndex()].second,
1195
74
                       ValType(Tables[Instr.getTargetIndex()].first)},
1196
74
                      {ValType(Tables[Instr.getTargetIndex()].first)});
1197
50
  case OpCode::Table__size:
1198
50
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1199
48
    return StackTrans({}, {ValType(Tables[Instr.getTargetIndex()].first)});
1200
45
  case OpCode::Table__fill:
1201
45
    EXPECTED_TRY(checkTableIdx(Instr.getTargetIndex()));
1202
42
    return StackTrans({ValType(Tables[Instr.getTargetIndex()].first),
1203
42
                       Tables[Instr.getTargetIndex()].second,
1204
42
                       ValType(Tables[Instr.getTargetIndex()].first)},
1205
42
                      {});
1206
1207
  // Memory Instructions.
1208
1.79k
  case OpCode::I32__load:
1209
1.79k
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I32)});
1210
4.30k
  case OpCode::I64__load:
1211
4.30k
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::I64)});
1212
260
  case OpCode::F32__load:
1213
260
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::F32)});
1214
882
  case OpCode::F64__load:
1215
882
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::F64)});
1216
1.52k
  case OpCode::I32__load8_s:
1217
2.48k
  case OpCode::I32__load8_u:
1218
2.48k
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I32)});
1219
1.23k
  case OpCode::I32__load16_s:
1220
3.41k
  case OpCode::I32__load16_u:
1221
3.41k
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I32)});
1222
1.45k
  case OpCode::I64__load8_s:
1223
2.26k
  case OpCode::I64__load8_u:
1224
2.26k
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::I64)});
1225
1.21k
  case OpCode::I64__load16_s:
1226
3.25k
  case OpCode::I64__load16_u:
1227
3.25k
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::I64)});
1228
974
  case OpCode::I64__load32_s:
1229
2.27k
  case OpCode::I64__load32_u:
1230
2.27k
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::I64)});
1231
677
  case OpCode::I32__store:
1232
677
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)}, {});
1233
2.75k
  case OpCode::I64__store:
1234
2.75k
    return checkMemArgAndTrans(64, {ValType(TypeCode::I64)}, {});
1235
777
  case OpCode::F32__store:
1236
777
    return checkMemArgAndTrans(32, {ValType(TypeCode::F32)}, {});
1237
207
  case OpCode::F64__store:
1238
207
    return checkMemArgAndTrans(64, {ValType(TypeCode::F64)}, {});
1239
1.09k
  case OpCode::I32__store8:
1240
1.09k
    return checkMemArgAndTrans(8, {ValType(TypeCode::I32)}, {});
1241
781
  case OpCode::I32__store16:
1242
781
    return checkMemArgAndTrans(16, {ValType(TypeCode::I32)}, {});
1243
1.10k
  case OpCode::I64__store8:
1244
1.10k
    return checkMemArgAndTrans(8, {ValType(TypeCode::I64)}, {});
1245
929
  case OpCode::I64__store16:
1246
929
    return checkMemArgAndTrans(16, {ValType(TypeCode::I64)}, {});
1247
183
  case OpCode::I64__store32:
1248
183
    return checkMemArgAndTrans(32, {ValType(TypeCode::I64)}, {});
1249
1.81k
  case OpCode::Memory__size:
1250
1.81k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1251
1.81k
    return StackTrans({}, {ValType(Mems[Instr.getTargetIndex()])});
1252
2.95k
  case OpCode::Memory__grow:
1253
2.95k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1254
2.94k
    return StackTrans({ValType(Mems[Instr.getTargetIndex()])},
1255
2.94k
                      {ValType(Mems[Instr.getTargetIndex()])});
1256
34
  case OpCode::Memory__init:
1257
34
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1258
33
    EXPECTED_TRY(checkDataIdx(Instr.getSourceIndex()));
1259
29
    return StackTrans({ValType(Mems[Instr.getTargetIndex()]),
1260
29
                       ValType(TypeCode::I32), ValType(TypeCode::I32)},
1261
29
                      {});
1262
99
  case OpCode::Data__drop:
1263
99
    EXPECTED_TRY(checkDataIdx(Instr.getTargetIndex()));
1264
95
    return {};
1265
423
  case OpCode::Memory__copy: {
1266
423
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1267
419
    EXPECTED_TRY(checkMemIdx(Instr.getSourceIndex()));
1268
415
    auto ATDst = Mems[Instr.getTargetIndex()];
1269
415
    auto ATSrc = Mems[Instr.getSourceIndex()];
1270
415
    auto ATMin = convTypeCodeToAddrType(ATDst) <= convTypeCodeToAddrType(ATSrc)
1271
415
                     ? ATDst
1272
415
                     : ATSrc;
1273
415
    return StackTrans({ValType(ATDst), ValType(ATSrc), ValType(ATMin)}, {});
1274
419
  }
1275
1.28k
  case OpCode::Memory__fill:
1276
1.28k
    EXPECTED_TRY(checkMemIdx(Instr.getTargetIndex()));
1277
1.28k
    return StackTrans({ValType(Mems[Instr.getTargetIndex()]),
1278
1.28k
                       ValType(TypeCode::I32),
1279
1.28k
                       ValType(Mems[Instr.getTargetIndex()])},
1280
1.28k
                      {});
1281
1282
  // Const Instructions.
1283
925k
  case OpCode::I32__const:
1284
925k
    return StackTrans({}, {ValType(TypeCode::I32)});
1285
113k
  case OpCode::I64__const:
1286
113k
    return StackTrans({}, {ValType(TypeCode::I64)});
1287
24.5k
  case OpCode::F32__const:
1288
24.5k
    return StackTrans({}, {ValType(TypeCode::F32)});
1289
10.5k
  case OpCode::F64__const:
1290
10.5k
    return StackTrans({}, {ValType(TypeCode::F64)});
1291
1292
  // Unary Numeric Instructions.
1293
10.7k
  case OpCode::I32__eqz:
1294
10.7k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1295
2.01k
  case OpCode::I64__eqz:
1296
2.01k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1297
5.30k
  case OpCode::I32__clz:
1298
9.01k
  case OpCode::I32__ctz:
1299
41.4k
  case OpCode::I32__popcnt:
1300
41.4k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1301
572
  case OpCode::I64__clz:
1302
1.84k
  case OpCode::I64__ctz:
1303
4.58k
  case OpCode::I64__popcnt:
1304
4.58k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1305
946
  case OpCode::F32__abs:
1306
2.82k
  case OpCode::F32__neg:
1307
4.96k
  case OpCode::F32__ceil:
1308
5.92k
  case OpCode::F32__floor:
1309
7.25k
  case OpCode::F32__trunc:
1310
8.62k
  case OpCode::F32__nearest:
1311
12.0k
  case OpCode::F32__sqrt:
1312
12.0k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F32)});
1313
1.28k
  case OpCode::F64__abs:
1314
2.25k
  case OpCode::F64__neg:
1315
6.65k
  case OpCode::F64__ceil:
1316
7.21k
  case OpCode::F64__floor:
1317
7.85k
  case OpCode::F64__trunc:
1318
8.39k
  case OpCode::F64__nearest:
1319
10.5k
  case OpCode::F64__sqrt:
1320
10.5k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F64)});
1321
774
  case OpCode::I32__wrap_i64:
1322
774
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1323
1.94k
  case OpCode::I32__trunc_f32_s:
1324
2.99k
  case OpCode::I32__trunc_f32_u:
1325
2.99k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1326
933
  case OpCode::I32__trunc_f64_s:
1327
2.66k
  case OpCode::I32__trunc_f64_u:
1328
2.66k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1329
3.48k
  case OpCode::I64__extend_i32_s:
1330
4.19k
  case OpCode::I64__extend_i32_u:
1331
4.19k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I64)});
1332
432
  case OpCode::I64__trunc_f32_s:
1333
1.98k
  case OpCode::I64__trunc_f32_u:
1334
1.98k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1335
1.02k
  case OpCode::I64__trunc_f64_s:
1336
3.39k
  case OpCode::I64__trunc_f64_u:
1337
3.39k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1338
2.71k
  case OpCode::F32__convert_i32_s:
1339
4.38k
  case OpCode::F32__convert_i32_u:
1340
4.38k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1341
1.44k
  case OpCode::F32__convert_i64_s:
1342
3.39k
  case OpCode::F32__convert_i64_u:
1343
3.39k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F32)});
1344
384
  case OpCode::F32__demote_f64:
1345
384
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F32)});
1346
2.00k
  case OpCode::F64__convert_i32_s:
1347
5.22k
  case OpCode::F64__convert_i32_u:
1348
5.22k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F64)});
1349
8.89k
  case OpCode::F64__convert_i64_s:
1350
9.21k
  case OpCode::F64__convert_i64_u:
1351
9.21k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)});
1352
153
  case OpCode::F64__promote_f32:
1353
153
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F64)});
1354
1.94k
  case OpCode::I32__reinterpret_f32:
1355
1.94k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1356
1.51k
  case OpCode::I64__reinterpret_f64:
1357
1.51k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1358
6.97k
  case OpCode::F32__reinterpret_i32:
1359
6.97k
    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.39k
  case OpCode::I32__extend8_s:
1363
10.6k
  case OpCode::I32__extend16_s:
1364
10.6k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1365
963
  case OpCode::I64__extend8_s:
1366
2.00k
  case OpCode::I64__extend16_s:
1367
2.79k
  case OpCode::I64__extend32_s:
1368
2.79k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1369
589
  case OpCode::I32__trunc_sat_f32_s:
1370
910
  case OpCode::I32__trunc_sat_f32_u:
1371
910
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1372
940
  case OpCode::I32__trunc_sat_f64_s:
1373
1.64k
  case OpCode::I32__trunc_sat_f64_u:
1374
1.64k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1375
494
  case OpCode::I64__trunc_sat_f32_s:
1376
1.02k
  case OpCode::I64__trunc_sat_f32_u:
1377
1.02k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1378
571
  case OpCode::I64__trunc_sat_f64_s:
1379
1.36k
  case OpCode::I64__trunc_sat_f64_u:
1380
1.36k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1381
1382
  // Binary Numeric Instructions.
1383
1.90k
  case OpCode::I32__eq:
1384
3.43k
  case OpCode::I32__ne:
1385
7.53k
  case OpCode::I32__lt_s:
1386
17.0k
  case OpCode::I32__lt_u:
1387
20.0k
  case OpCode::I32__gt_s:
1388
31.1k
  case OpCode::I32__gt_u:
1389
34.4k
  case OpCode::I32__le_s:
1390
35.7k
  case OpCode::I32__le_u:
1391
38.6k
  case OpCode::I32__ge_s:
1392
41.2k
  case OpCode::I32__ge_u:
1393
41.2k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1394
41.2k
                      {ValType(TypeCode::I32)});
1395
423
  case OpCode::I64__eq:
1396
1.18k
  case OpCode::I64__ne:
1397
2.66k
  case OpCode::I64__lt_s:
1398
3.39k
  case OpCode::I64__lt_u:
1399
4.76k
  case OpCode::I64__gt_s:
1400
5.11k
  case OpCode::I64__gt_u:
1401
6.51k
  case OpCode::I64__le_s:
1402
8.90k
  case OpCode::I64__le_u:
1403
9.32k
  case OpCode::I64__ge_s:
1404
10.5k
  case OpCode::I64__ge_u:
1405
10.5k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1406
10.5k
                      {ValType(TypeCode::I32)});
1407
648
  case OpCode::F32__eq:
1408
1.05k
  case OpCode::F32__ne:
1409
1.83k
  case OpCode::F32__lt:
1410
2.04k
  case OpCode::F32__gt:
1411
2.60k
  case OpCode::F32__le:
1412
3.21k
  case OpCode::F32__ge:
1413
3.21k
    return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)},
1414
3.21k
                      {ValType(TypeCode::I32)});
1415
529
  case OpCode::F64__eq:
1416
726
  case OpCode::F64__ne:
1417
1.17k
  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.80k
  case OpCode::I32__add:
1424
5.37k
  case OpCode::I32__sub:
1425
6.47k
  case OpCode::I32__mul:
1426
9.31k
  case OpCode::I32__div_s:
1427
15.7k
  case OpCode::I32__div_u:
1428
18.1k
  case OpCode::I32__rem_s:
1429
21.2k
  case OpCode::I32__rem_u:
1430
22.4k
  case OpCode::I32__and:
1431
24.9k
  case OpCode::I32__or:
1432
27.8k
  case OpCode::I32__xor:
1433
32.0k
  case OpCode::I32__shl:
1434
36.3k
  case OpCode::I32__shr_s:
1435
42.8k
  case OpCode::I32__shr_u:
1436
47.0k
  case OpCode::I32__rotl:
1437
49.4k
  case OpCode::I32__rotr:
1438
49.4k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1439
49.4k
                      {ValType(TypeCode::I32)});
1440
1.03k
  case OpCode::I64__add:
1441
1.90k
  case OpCode::I64__sub:
1442
3.26k
  case OpCode::I64__mul:
1443
4.00k
  case OpCode::I64__div_s:
1444
6.75k
  case OpCode::I64__div_u:
1445
7.56k
  case OpCode::I64__rem_s:
1446
8.84k
  case OpCode::I64__rem_u:
1447
10.5k
  case OpCode::I64__and:
1448
11.5k
  case OpCode::I64__or:
1449
12.9k
  case OpCode::I64__xor:
1450
13.5k
  case OpCode::I64__shl:
1451
14.7k
  case OpCode::I64__shr_s:
1452
15.4k
  case OpCode::I64__shr_u:
1453
18.1k
  case OpCode::I64__rotl:
1454
21.3k
  case OpCode::I64__rotr:
1455
21.3k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1456
21.3k
                      {ValType(TypeCode::I64)});
1457
623
  case OpCode::F32__add:
1458
2.50k
  case OpCode::F32__sub:
1459
3.55k
  case OpCode::F32__mul:
1460
4.05k
  case OpCode::F32__div:
1461
4.71k
  case OpCode::F32__min:
1462
5.71k
  case OpCode::F32__max:
1463
6.58k
  case OpCode::F32__copysign:
1464
6.58k
    return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)},
1465
6.58k
                      {ValType(TypeCode::F32)});
1466
656
  case OpCode::F64__add:
1467
2.85k
  case OpCode::F64__sub:
1468
3.27k
  case OpCode::F64__mul:
1469
4.07k
  case OpCode::F64__div:
1470
5.02k
  case OpCode::F64__min:
1471
6.70k
  case OpCode::F64__max:
1472
8.02k
  case OpCode::F64__copysign:
1473
8.02k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1474
8.02k
                      {ValType(TypeCode::F64)});
1475
1476
  // SIMD Memory Instruction.
1477
9.45k
  case OpCode::V128__load:
1478
9.45k
    return checkMemArgAndTrans(128, {}, {ValType(TypeCode::V128)});
1479
972
  case OpCode::V128__load8x8_s:
1480
1.06k
  case OpCode::V128__load8x8_u:
1481
1.72k
  case OpCode::V128__load16x4_s:
1482
3.49k
  case OpCode::V128__load16x4_u:
1483
4.01k
  case OpCode::V128__load32x2_s:
1484
4.31k
  case OpCode::V128__load32x2_u:
1485
4.92k
  case OpCode::V128__load64_splat:
1486
5.11k
  case OpCode::V128__load64_zero:
1487
5.11k
    return checkMemArgAndTrans(64, {}, {ValType(TypeCode::V128)});
1488
396
  case OpCode::V128__load8_splat:
1489
396
    return checkMemArgAndTrans(8, {}, {ValType(TypeCode::V128)});
1490
771
  case OpCode::V128__load16_splat:
1491
771
    return checkMemArgAndTrans(16, {}, {ValType(TypeCode::V128)});
1492
569
  case OpCode::V128__load32_splat:
1493
855
  case OpCode::V128__load32_zero:
1494
855
    return checkMemArgAndTrans(32, {}, {ValType(TypeCode::V128)});
1495
649
  case OpCode::V128__store:
1496
649
    return checkMemArgAndTrans(128, {ValType(TypeCode::V128)}, {});
1497
346
  case OpCode::V128__load8_lane:
1498
346
    return checkMemArgAndTrans(8, {ValType(TypeCode::V128)},
1499
346
                               {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
233
  case OpCode::V128__load32_lane:
1504
233
    return checkMemArgAndTrans(32, {ValType(TypeCode::V128)},
1505
233
                               {ValType(TypeCode::V128)}, true);
1506
407
  case OpCode::V128__load64_lane:
1507
407
    return checkMemArgAndTrans(64, {ValType(TypeCode::V128)},
1508
407
                               {ValType(TypeCode::V128)}, true);
1509
525
  case OpCode::V128__store8_lane:
1510
525
    return checkMemArgAndTrans(8, {ValType(TypeCode::V128)}, {}, true);
1511
134
  case OpCode::V128__store16_lane:
1512
134
    return checkMemArgAndTrans(16, {ValType(TypeCode::V128)}, {}, true);
1513
822
  case OpCode::V128__store32_lane:
1514
822
    return checkMemArgAndTrans(32, {ValType(TypeCode::V128)}, {}, true);
1515
290
  case OpCode::V128__store64_lane:
1516
290
    return checkMemArgAndTrans(64, {ValType(TypeCode::V128)}, {}, true);
1517
1518
  // SIMD Const Instruction.
1519
532
  case OpCode::V128__const:
1520
532
    return StackTrans({}, {ValType(TypeCode::V128)});
1521
1522
  // SIMD Shuffle Instruction.
1523
324
  case OpCode::I8x16__shuffle: {
1524
    // Check that all lane indices are less than 32 by masking.
1525
324
    const uint128_t Mask = (uint128_t(0xe0e0e0e0e0e0e0e0U) << 64U) |
1526
324
                           uint128_t(0xe0e0e0e0e0e0e0e0U);
1527
324
    const uint128_t Result = Instr.getNum().get<uint128_t>() & Mask;
1528
324
    if (Result) {
1529
5
      spdlog::error(ErrCode::Value::InvalidLaneIdx);
1530
5
      return Unexpect(ErrCode::Value::InvalidLaneIdx);
1531
5
    }
1532
319
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1533
319
                      {ValType(TypeCode::V128)});
1534
324
  }
1535
1536
  // SIMD Lane Instructions.
1537
974
  case OpCode::I8x16__extract_lane_s:
1538
1.08k
  case OpCode::I8x16__extract_lane_u:
1539
1.08k
    return checkLaneAndTrans(16, {ValType(TypeCode::V128)},
1540
1.08k
                             {ValType(TypeCode::I32)});
1541
1.03k
  case OpCode::I8x16__replace_lane:
1542
1.03k
    return checkLaneAndTrans(16,
1543
1.03k
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1544
1.03k
                             {ValType(TypeCode::V128)});
1545
956
  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
794
  case OpCode::I16x8__replace_lane:
1550
794
    return checkLaneAndTrans(8,
1551
794
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1552
794
                             {ValType(TypeCode::V128)});
1553
1.38k
  case OpCode::I32x4__extract_lane:
1554
1.38k
    return checkLaneAndTrans(4, {ValType(TypeCode::V128)},
1555
1.38k
                             {ValType(TypeCode::I32)});
1556
671
  case OpCode::I32x4__replace_lane:
1557
671
    return checkLaneAndTrans(4,
1558
671
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1559
671
                             {ValType(TypeCode::V128)});
1560
256
  case OpCode::I64x2__extract_lane:
1561
256
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1562
256
                             {ValType(TypeCode::I64)});
1563
747
  case OpCode::I64x2__replace_lane:
1564
747
    return checkLaneAndTrans(2,
1565
747
                             {ValType(TypeCode::V128), ValType(TypeCode::I64)},
1566
747
                             {ValType(TypeCode::V128)});
1567
137
  case OpCode::F32x4__extract_lane:
1568
137
    return checkLaneAndTrans(4, {ValType(TypeCode::V128)},
1569
137
                             {ValType(TypeCode::F32)});
1570
183
  case OpCode::F32x4__replace_lane:
1571
183
    return checkLaneAndTrans(4,
1572
183
                             {ValType(TypeCode::V128), ValType(TypeCode::F32)},
1573
183
                             {ValType(TypeCode::V128)});
1574
393
  case OpCode::F64x2__extract_lane:
1575
393
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1576
393
                             {ValType(TypeCode::F64)});
1577
161
  case OpCode::F64x2__replace_lane:
1578
161
    return checkLaneAndTrans(2,
1579
161
                             {ValType(TypeCode::V128), ValType(TypeCode::F64)},
1580
161
                             {ValType(TypeCode::V128)});
1581
1582
  // SIMD Numeric Instructions.
1583
63.2k
  case OpCode::I8x16__splat:
1584
77.0k
  case OpCode::I16x8__splat:
1585
79.5k
  case OpCode::I32x4__splat:
1586
79.5k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::V128)});
1587
1.38k
  case OpCode::I64x2__splat:
1588
1.38k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::V128)});
1589
558
  case OpCode::F32x4__splat:
1590
558
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::V128)});
1591
712
  case OpCode::F64x2__splat:
1592
712
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::V128)});
1593
596
  case OpCode::V128__not:
1594
2.97k
  case OpCode::I8x16__abs:
1595
6.48k
  case OpCode::I8x16__neg:
1596
7.42k
  case OpCode::I8x16__popcnt:
1597
8.22k
  case OpCode::I16x8__abs:
1598
8.74k
  case OpCode::I16x8__neg:
1599
10.2k
  case OpCode::I16x8__extend_low_i8x16_s:
1600
10.4k
  case OpCode::I16x8__extend_high_i8x16_s:
1601
11.1k
  case OpCode::I16x8__extend_low_i8x16_u:
1602
11.2k
  case OpCode::I16x8__extend_high_i8x16_u:
1603
12.3k
  case OpCode::I16x8__extadd_pairwise_i8x16_s:
1604
13.9k
  case OpCode::I16x8__extadd_pairwise_i8x16_u:
1605
14.4k
  case OpCode::I32x4__abs:
1606
14.8k
  case OpCode::I32x4__neg:
1607
15.3k
  case OpCode::I32x4__extend_low_i16x8_s:
1608
16.2k
  case OpCode::I32x4__extend_high_i16x8_s:
1609
19.6k
  case OpCode::I32x4__extend_low_i16x8_u:
1610
20.2k
  case OpCode::I32x4__extend_high_i16x8_u:
1611
22.3k
  case OpCode::I32x4__extadd_pairwise_i16x8_s:
1612
24.0k
  case OpCode::I32x4__extadd_pairwise_i16x8_u:
1613
25.2k
  case OpCode::I64x2__abs:
1614
26.1k
  case OpCode::I64x2__neg:
1615
27.0k
  case OpCode::I64x2__extend_low_i32x4_s:
1616
28.1k
  case OpCode::I64x2__extend_high_i32x4_s:
1617
28.6k
  case OpCode::I64x2__extend_low_i32x4_u:
1618
30.2k
  case OpCode::I64x2__extend_high_i32x4_u:
1619
30.4k
  case OpCode::F32x4__abs:
1620
31.1k
  case OpCode::F32x4__neg:
1621
31.3k
  case OpCode::F32x4__sqrt:
1622
32.1k
  case OpCode::F64x2__abs:
1623
33.3k
  case OpCode::F64x2__neg:
1624
33.5k
  case OpCode::F64x2__sqrt:
1625
33.9k
  case OpCode::I32x4__trunc_sat_f32x4_s:
1626
40.7k
  case OpCode::I32x4__trunc_sat_f32x4_u:
1627
41.1k
  case OpCode::F32x4__convert_i32x4_s:
1628
42.4k
  case OpCode::F32x4__convert_i32x4_u:
1629
43.8k
  case OpCode::I32x4__trunc_sat_f64x2_s_zero:
1630
47.5k
  case OpCode::I32x4__trunc_sat_f64x2_u_zero:
1631
48.6k
  case OpCode::F64x2__convert_low_i32x4_s:
1632
50.7k
  case OpCode::F64x2__convert_low_i32x4_u:
1633
51.9k
  case OpCode::F32x4__demote_f64x2_zero:
1634
53.3k
  case OpCode::F64x2__promote_low_f32x4:
1635
54.9k
  case OpCode::F32x4__ceil:
1636
58.4k
  case OpCode::F32x4__floor:
1637
61.7k
  case OpCode::F32x4__trunc:
1638
62.3k
  case OpCode::F32x4__nearest:
1639
63.4k
  case OpCode::F64x2__ceil:
1640
64.7k
  case OpCode::F64x2__floor:
1641
65.6k
  case OpCode::F64x2__trunc:
1642
66.0k
  case OpCode::F64x2__nearest:
1643
66.0k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)});
1644
765
  case OpCode::I8x16__swizzle:
1645
1.37k
  case OpCode::I8x16__eq:
1646
2.01k
  case OpCode::I8x16__ne:
1647
2.44k
  case OpCode::I8x16__lt_s:
1648
2.77k
  case OpCode::I8x16__lt_u:
1649
4.03k
  case OpCode::I8x16__gt_s:
1650
4.41k
  case OpCode::I8x16__gt_u:
1651
4.67k
  case OpCode::I8x16__le_s:
1652
5.05k
  case OpCode::I8x16__le_u:
1653
6.91k
  case OpCode::I8x16__ge_s:
1654
7.24k
  case OpCode::I8x16__ge_u:
1655
7.59k
  case OpCode::I16x8__eq:
1656
8.32k
  case OpCode::I16x8__ne:
1657
8.85k
  case OpCode::I16x8__lt_s:
1658
10.3k
  case OpCode::I16x8__lt_u:
1659
11.2k
  case OpCode::I16x8__gt_s:
1660
12.5k
  case OpCode::I16x8__gt_u:
1661
12.9k
  case OpCode::I16x8__le_s:
1662
13.2k
  case OpCode::I16x8__le_u:
1663
13.9k
  case OpCode::I16x8__ge_s:
1664
14.5k
  case OpCode::I16x8__ge_u:
1665
14.8k
  case OpCode::I32x4__eq:
1666
15.1k
  case OpCode::I32x4__ne:
1667
16.2k
  case OpCode::I32x4__lt_s:
1668
16.4k
  case OpCode::I32x4__lt_u:
1669
16.8k
  case OpCode::I32x4__gt_s:
1670
17.7k
  case OpCode::I32x4__gt_u:
1671
19.7k
  case OpCode::I32x4__le_s:
1672
20.2k
  case OpCode::I32x4__le_u:
1673
20.3k
  case OpCode::I32x4__ge_s:
1674
20.9k
  case OpCode::I32x4__ge_u:
1675
21.2k
  case OpCode::I64x2__eq:
1676
21.6k
  case OpCode::I64x2__ne:
1677
22.2k
  case OpCode::I64x2__lt_s:
1678
22.5k
  case OpCode::I64x2__gt_s:
1679
22.7k
  case OpCode::I64x2__le_s:
1680
23.5k
  case OpCode::I64x2__ge_s:
1681
26.1k
  case OpCode::F32x4__eq:
1682
26.3k
  case OpCode::F32x4__ne:
1683
27.1k
  case OpCode::F32x4__lt:
1684
27.4k
  case OpCode::F32x4__gt:
1685
28.3k
  case OpCode::F32x4__le:
1686
28.6k
  case OpCode::F32x4__ge:
1687
30.1k
  case OpCode::F64x2__eq:
1688
30.4k
  case OpCode::F64x2__ne:
1689
30.9k
  case OpCode::F64x2__lt:
1690
33.2k
  case OpCode::F64x2__gt:
1691
33.6k
  case OpCode::F64x2__le:
1692
34.3k
  case OpCode::F64x2__ge:
1693
34.5k
  case OpCode::V128__and:
1694
34.8k
  case OpCode::V128__andnot:
1695
35.3k
  case OpCode::V128__or:
1696
35.8k
  case OpCode::V128__xor:
1697
36.5k
  case OpCode::I8x16__narrow_i16x8_s:
1698
37.0k
  case OpCode::I8x16__narrow_i16x8_u:
1699
37.4k
  case OpCode::I8x16__add:
1700
38.5k
  case OpCode::I8x16__add_sat_s:
1701
38.9k
  case OpCode::I8x16__add_sat_u:
1702
39.9k
  case OpCode::I8x16__sub:
1703
40.8k
  case OpCode::I8x16__sub_sat_s:
1704
41.0k
  case OpCode::I8x16__sub_sat_u:
1705
41.4k
  case OpCode::I8x16__min_s:
1706
42.7k
  case OpCode::I8x16__min_u:
1707
43.5k
  case OpCode::I8x16__max_s:
1708
44.1k
  case OpCode::I8x16__max_u:
1709
44.6k
  case OpCode::I8x16__avgr_u:
1710
45.0k
  case OpCode::I16x8__narrow_i32x4_s:
1711
45.6k
  case OpCode::I16x8__narrow_i32x4_u:
1712
46.3k
  case OpCode::I16x8__add:
1713
46.4k
  case OpCode::I16x8__add_sat_s:
1714
47.5k
  case OpCode::I16x8__add_sat_u:
1715
48.2k
  case OpCode::I16x8__sub:
1716
48.8k
  case OpCode::I16x8__sub_sat_s:
1717
49.0k
  case OpCode::I16x8__sub_sat_u:
1718
49.4k
  case OpCode::I16x8__mul:
1719
49.9k
  case OpCode::I16x8__min_s:
1720
50.3k
  case OpCode::I16x8__min_u:
1721
50.8k
  case OpCode::I16x8__max_s:
1722
52.1k
  case OpCode::I16x8__max_u:
1723
52.4k
  case OpCode::I16x8__avgr_u:
1724
52.7k
  case OpCode::I16x8__extmul_low_i8x16_s:
1725
53.3k
  case OpCode::I16x8__extmul_high_i8x16_s:
1726
53.5k
  case OpCode::I16x8__extmul_low_i8x16_u:
1727
54.4k
  case OpCode::I16x8__extmul_high_i8x16_u:
1728
54.9k
  case OpCode::I16x8__q15mulr_sat_s:
1729
55.4k
  case OpCode::I32x4__add:
1730
55.6k
  case OpCode::I32x4__sub:
1731
56.0k
  case OpCode::I32x4__mul:
1732
56.4k
  case OpCode::I32x4__min_s:
1733
56.8k
  case OpCode::I32x4__min_u:
1734
56.9k
  case OpCode::I32x4__max_s:
1735
57.2k
  case OpCode::I32x4__max_u:
1736
57.5k
  case OpCode::I32x4__extmul_low_i16x8_s:
1737
57.8k
  case OpCode::I32x4__extmul_high_i16x8_s:
1738
58.2k
  case OpCode::I32x4__extmul_low_i16x8_u:
1739
58.6k
  case OpCode::I32x4__extmul_high_i16x8_u:
1740
59.1k
  case OpCode::I64x2__add:
1741
59.6k
  case OpCode::I64x2__sub:
1742
60.2k
  case OpCode::I64x2__mul:
1743
60.4k
  case OpCode::I64x2__extmul_low_i32x4_s:
1744
61.5k
  case OpCode::I64x2__extmul_high_i32x4_s:
1745
62.3k
  case OpCode::I64x2__extmul_low_i32x4_u:
1746
63.0k
  case OpCode::I64x2__extmul_high_i32x4_u:
1747
64.8k
  case OpCode::F32x4__add:
1748
65.5k
  case OpCode::F32x4__sub:
1749
66.3k
  case OpCode::F32x4__mul:
1750
66.6k
  case OpCode::F32x4__div:
1751
67.0k
  case OpCode::F32x4__min:
1752
67.6k
  case OpCode::F32x4__max:
1753
69.4k
  case OpCode::F32x4__pmin:
1754
69.8k
  case OpCode::F32x4__pmax:
1755
69.9k
  case OpCode::F64x2__add:
1756
70.9k
  case OpCode::F64x2__sub:
1757
71.2k
  case OpCode::F64x2__mul:
1758
71.7k
  case OpCode::F64x2__div:
1759
71.9k
  case OpCode::F64x2__min:
1760
72.1k
  case OpCode::F64x2__max:
1761
72.9k
  case OpCode::F64x2__pmin:
1762
73.3k
  case OpCode::F64x2__pmax:
1763
73.8k
  case OpCode::I32x4__dot_i16x8_s:
1764
73.8k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1765
73.8k
                      {ValType(TypeCode::V128)});
1766
268
  case OpCode::V128__bitselect:
1767
268
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1768
268
                       ValType(TypeCode::V128)},
1769
268
                      {ValType(TypeCode::V128)});
1770
222
  case OpCode::V128__any_true:
1771
637
  case OpCode::I8x16__all_true:
1772
1.91k
  case OpCode::I8x16__bitmask:
1773
2.35k
  case OpCode::I16x8__all_true:
1774
2.83k
  case OpCode::I16x8__bitmask:
1775
3.60k
  case OpCode::I32x4__all_true:
1776
4.99k
  case OpCode::I32x4__bitmask:
1777
5.85k
  case OpCode::I64x2__all_true:
1778
6.26k
  case OpCode::I64x2__bitmask:
1779
6.26k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::I32)});
1780
862
  case OpCode::I8x16__shl:
1781
2.32k
  case OpCode::I8x16__shr_s:
1782
3.01k
  case OpCode::I8x16__shr_u:
1783
3.17k
  case OpCode::I16x8__shl:
1784
3.83k
  case OpCode::I16x8__shr_s:
1785
4.10k
  case OpCode::I16x8__shr_u:
1786
5.96k
  case OpCode::I32x4__shl:
1787
6.46k
  case OpCode::I32x4__shr_s:
1788
7.54k
  case OpCode::I32x4__shr_u:
1789
7.84k
  case OpCode::I64x2__shl:
1790
9.04k
  case OpCode::I64x2__shr_s:
1791
9.20k
  case OpCode::I64x2__shr_u:
1792
9.20k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::I32)},
1793
9.20k
                      {ValType(TypeCode::V128)});
1794
1795
105
  case OpCode::I8x16__relaxed_swizzle:
1796
105
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1797
105
                      {ValType(TypeCode::V128)});
1798
20
  case OpCode::I32x4__relaxed_trunc_f32x4_s:
1799
48
  case OpCode::I32x4__relaxed_trunc_f32x4_u:
1800
131
  case OpCode::I32x4__relaxed_trunc_f64x2_s_zero:
1801
168
  case OpCode::I32x4__relaxed_trunc_f64x2_u_zero:
1802
168
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)});
1803
46
  case OpCode::F32x4__relaxed_madd:
1804
168
  case OpCode::F32x4__relaxed_nmadd:
1805
196
  case OpCode::F64x2__relaxed_madd:
1806
245
  case OpCode::F64x2__relaxed_nmadd:
1807
286
  case OpCode::I8x16__relaxed_laneselect:
1808
377
  case OpCode::I16x8__relaxed_laneselect:
1809
494
  case OpCode::I32x4__relaxed_laneselect:
1810
633
  case OpCode::I64x2__relaxed_laneselect:
1811
633
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1812
633
                       ValType(TypeCode::V128)},
1813
633
                      {ValType(TypeCode::V128)});
1814
193
  case OpCode::F32x4__relaxed_min:
1815
278
  case OpCode::F32x4__relaxed_max:
1816
330
  case OpCode::F64x2__relaxed_min:
1817
432
  case OpCode::F64x2__relaxed_max:
1818
462
  case OpCode::I16x8__relaxed_q15mulr_s:
1819
595
  case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s:
1820
595
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1821
595
                      {ValType(TypeCode::V128)});
1822
41
  case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s:
1823
41
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1824
41
                       ValType(TypeCode::V128)},
1825
41
                      {ValType(TypeCode::V128)});
1826
1827
434
  case OpCode::Atomic__fence:
1828
434
    return {};
1829
1830
66
  case OpCode::Memory__atomic__notify:
1831
66
    return checkMemArgAndTrans(32, {ValType(TypeCode::I32)},
1832
66
                               {ValType(TypeCode::I32)});
1833
20
  case OpCode::Memory__atomic__wait32:
1834
20
    return checkMemArgAndTrans(32,
1835
20
                               {ValType(TypeCode::I32), ValType(TypeCode::I64)},
1836
20
                               {ValType(TypeCode::I32)});
1837
74
  case OpCode::Memory__atomic__wait64:
1838
74
    return checkMemArgAndTrans(64,
1839
74
                               {ValType(TypeCode::I64), ValType(TypeCode::I64)},
1840
74
                               {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.14M
  }
2028
2.14M
}
2029
2030
1.74M
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.45k
    pushType(Val);
2035
4.45k
  }
2036
21.4k
}
2037
2038
1.78M
void FormChecker::pushTypes(Span<const ValType> Input) {
2039
1.78M
  for (auto Val : Input) {
2040
1.73M
    pushType(Val);
2041
1.73M
  }
2042
1.78M
}
2043
2044
1.90M
Expect<VType> FormChecker::popType() {
2045
1.90M
  if (ValStack.size() == CtrlStack.back().Height) {
2046
202k
    if (CtrlStack.back().IsUnreachable) {
2047
202k
      return unreachableVType();
2048
202k
    }
2049
    // Value stack underflow
2050
324
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2051
324
    spdlog::error("    Value stack underflow."sv);
2052
324
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2053
202k
  }
2054
1.69M
  auto T = std::move(ValStack.back());
2055
1.69M
  ValStack.pop_back();
2056
1.69M
  return T;
2057
1.90M
}
2058
2059
914k
Expect<VType> FormChecker::popType(ValType E) {
2060
914k
  EXPECTED_TRY(auto Type, popType());
2061
914k
  if (Type == unreachableVType()) {
2062
198k
    return E;
2063
198k
  }
2064
2065
715k
  if (!AST::TypeMatcher::matchType(Types, E, *Type)) {
2066
    // The expected value on the value stack does not match.
2067
594
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2068
594
    spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(E), VTypeToAST(Type)));
2069
594
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2070
594
  }
2071
715k
  return Type;
2072
715k
}
2073
2074
1.78M
Expect<void> FormChecker::popTypes(Span<const ValType> Input) {
2075
2.62M
  for (auto Val = Input.rbegin(); Val != Input.rend(); ++Val) {
2076
846k
    EXPECTED_TRY(popType(*Val));
2077
846k
  }
2078
1.78M
  return {};
2079
1.78M
}
2080
2081
void FormChecker::pushCtrl(Span<const ValType> In, Span<const ValType> Out,
2082
27.7k
                           const AST::Instruction *Jump, OpCode Code) {
2083
27.7k
  CtrlStack.emplace_back(In, Out, Jump, ValStack.size(), LocalInits.size(),
2084
27.7k
                         Code);
2085
27.7k
  pushTypes(In);
2086
27.7k
}
2087
2088
25.9k
Expect<FormChecker::CtrlFrame> FormChecker::popCtrl() {
2089
25.9k
  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.9k
  EXPECTED_TRY(popTypes(CtrlStack.back().EndTypes));
2096
25.8k
  if (ValStack.size() != CtrlStack.back().Height) {
2097
    // Value stack size does not match.
2098
96
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2099
96
    spdlog::error("    Value stack underflow."sv);
2100
96
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2101
96
  }
2102
  // When popping a frame, reset the locals initialized during this frame.
2103
25.8k
  for (size_t I = CtrlStack.back().InitedLocal; I < LocalInits.size(); I++) {
2104
123
    Locals[LocalInits[I]].IsInit = false;
2105
123
  }
2106
25.7k
  LocalInits.erase(LocalInits.begin() +
2107
25.7k
                       static_cast<uint32_t>(CtrlStack.back().InitedLocal),
2108
25.7k
                   LocalInits.end());
2109
25.7k
  auto Head = std::move(CtrlStack.back());
2110
25.7k
  CtrlStack.pop_back();
2111
25.7k
  return Head;
2112
25.8k
}
2113
2114
Span<const ValType>
2115
29.3k
FormChecker::getLabelTypes(const FormChecker::CtrlFrame &F) {
2116
29.3k
  if (F.Code == OpCode::Loop) {
2117
5.91k
    return F.StartTypes;
2118
5.91k
  }
2119
23.3k
  return F.EndTypes;
2120
29.3k
}
2121
2122
233k
Expect<void> FormChecker::unreachable() {
2123
1.19M
  while (ValStack.size() > CtrlStack.back().Height) {
2124
964k
    EXPECTED_TRY(popType());
2125
964k
  }
2126
233k
  CtrlStack.back().IsUnreachable = true;
2127
233k
  return {};
2128
233k
}
2129
2130
Expect<void> FormChecker::StackTrans(Span<const ValType> Take,
2131
1.68M
                                     Span<const ValType> Put) {
2132
1.68M
  EXPECTED_TRY(popTypes(Take));
2133
1.68M
  pushTypes(Put);
2134
1.68M
  return {};
2135
1.68M
}
2136
2137
6.69k
Expect<void> FormChecker::StackPopAny() {
2138
6.69k
  EXPECTED_TRY(popType());
2139
6.69k
  return {};
2140
6.69k
}
2141
2142
} // namespace Validator
2143
} // namespace WasmEdge