Coverage Report

Created: 2025-11-24 06:51

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