Coverage Report

Created: 2026-11-12 06:35

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