Coverage Report

Created: 2025-07-11 06:21

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