Coverage Report

Created: 2025-11-11 06:39

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