Coverage Report

Created: 2025-07-01 06:18

/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
287
                   uint32_t Bound) {
22
287
  spdlog::error(Code);
23
287
  spdlog::error(ErrInfo::InfoForbidIndex(Cate, Idx, Bound));
24
287
  return Unexpect(Code);
25
287
}
26
27
} // namespace
28
29
20.9k
void FormChecker::reset(bool CleanGlobal) {
30
20.9k
  ValStack.clear();
31
20.9k
  CtrlStack.clear();
32
20.9k
  Locals.clear();
33
20.9k
  Returns.clear();
34
35
20.9k
  if (CleanGlobal) {
36
3.80k
    Types.clear();
37
3.80k
    Funcs.clear();
38
3.80k
    Tables.clear();
39
3.80k
    Mems = 0;
40
3.80k
    Globals.clear();
41
3.80k
    Datas.clear();
42
3.80k
    Elems.clear();
43
3.80k
    Refs.clear();
44
3.80k
    Tags.clear();
45
3.80k
    NumImportFuncs = 0;
46
3.80k
    NumImportGlobals = 0;
47
3.80k
  }
48
20.9k
}
49
50
Expect<void> FormChecker::validate(AST::InstrView Instrs,
51
17.1k
                                   Span<const ValType> RetVals) {
52
17.1k
  for (const ValType &Val : RetVals) {
53
14.5k
    Returns.push_back(Val);
54
14.5k
  }
55
17.1k
  return checkExpr(Instrs);
56
17.1k
}
57
58
8.43M
Expect<void> FormChecker::validate(const ValType &VT) const noexcept {
59
  // The value type should be validated for the type index case.
60
8.43M
  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.43M
  return {};
70
8.43M
}
71
72
6.73k
void FormChecker::addType(const AST::SubType &Type) { Types.push_back(&Type); }
73
74
20.8k
void FormChecker::addFunc(const uint32_t TypeIdx, const bool IsImport) {
75
20.8k
  if (Types.size() > TypeIdx) {
76
20.8k
    Funcs.emplace_back(TypeIdx);
77
20.8k
  }
78
20.8k
  if (IsImport) {
79
266
    NumImportFuncs++;
80
266
  }
81
20.8k
}
82
83
330
void FormChecker::addTable(const AST::TableType &Tab) {
84
330
  Tables.push_back(Tab.getRefType());
85
330
}
86
87
1.42k
void FormChecker::addMemory(const AST::MemoryType &) { Mems++; }
88
89
234
void FormChecker::addGlobal(const AST::GlobalType &Glob, const bool IsImport) {
90
  // Type in global is confirmed in loading phase.
91
234
  Globals.emplace_back(Glob.getValType(), Glob.getValMut());
92
234
  if (IsImport) {
93
48
    NumImportGlobals++;
94
48
  }
95
234
}
96
97
339
void FormChecker::addData(const AST::DataSegment &) {
98
339
  Datas.emplace_back(static_cast<uint32_t>(Datas.size()));
99
339
}
100
101
558
void FormChecker::addElem(const AST::ElementSegment &Elem) {
102
558
  Elems.emplace_back(Elem.getRefType());
103
558
}
104
105
15.7k
void FormChecker::addRef(const uint32_t FuncIdx) { Refs.emplace(FuncIdx); }
106
107
8.43M
void FormChecker::addLocal(const ValType &V, bool Initialized) {
108
8.43M
  Locals.emplace_back(V);
109
8.43M
  if (Initialized || V.isDefaultable()) {
110
8.43M
    LocalInits.push_back(static_cast<uint32_t>(Locals.size() - 1));
111
8.43M
    Locals.back().IsInit = true;
112
8.43M
  }
113
8.43M
}
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
17.1k
Expect<void> FormChecker::checkExpr(AST::InstrView Instrs) {
125
17.1k
  if (Instrs.size() > 0) {
126
    // Push ctrl frame ([] -> [Returns])
127
17.1k
    pushCtrl({}, Returns, &*Instrs.rbegin());
128
17.1k
    return checkInstrs(Instrs);
129
17.1k
  }
130
0
  return {};
131
17.1k
}
132
133
17.1k
Expect<void> FormChecker::checkInstrs(AST::InstrView Instrs) {
134
  // Validate instructions
135
1.83M
  for (auto &Instr : Instrs) {
136
1.83M
    EXPECTED_TRY(checkInstr(Instr).map_error([&Instr](auto E) {
137
1.83M
      spdlog::error(
138
1.83M
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
139
1.83M
      return E;
140
1.83M
    }));
141
1.83M
  }
142
15.7k
  return {};
143
17.1k
}
144
145
1.83M
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.83M
  auto checkDefinedType =
151
1.83M
      [this](uint32_t TIdx, TypeCode TC) -> Expect<const AST::CompositeType *> {
152
3.97k
    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.96k
    const auto &CType = Types[TIdx]->getCompositeType();
158
3.96k
    if (CType.getContentTypeCode() == TC) {
159
3.96k
      return &CType;
160
3.96k
    } else {
161
0
      spdlog::error(ErrCode::Value::TypeCheckFailed);
162
0
      return Unexpect(ErrCode::Value::TypeCheckFailed);
163
0
    }
164
3.96k
  };
165
166
  // Helper lambda for checking and resolve the block type.
167
1.83M
  auto checkBlockType = [this, checkDefinedType](std::vector<ValType> &Buffer,
168
1.83M
                                                 const BlockType &BType)
169
1.83M
      -> Expect<std::pair<Span<const ValType>, Span<const ValType>>> {
170
9.83k
    using ReturnType = std::pair<Span<const ValType>, Span<const ValType>>;
171
9.83k
    if (BType.isEmpty()) {
172
      // Empty case. t2* = none
173
3.08k
      return ReturnType{{}, {}};
174
6.75k
    } else if (BType.isValType()) {
175
      // ValType case. t2* = valtype
176
3.62k
      EXPECTED_TRY(validate(BType.getValType()));
177
3.62k
      Buffer[0] = BType.getValType();
178
3.62k
      return ReturnType{{}, Buffer};
179
3.62k
    } else {
180
      // Type index case. t2* = functype.returns.
181
3.12k
      EXPECTED_TRY(auto CompType,
182
3.11k
                   checkDefinedType(BType.getTypeIndex(), TypeCode::Func));
183
3.11k
      const auto &FType = CompType->getFuncType();
184
3.11k
      return ReturnType{FType.getParamTypes(), FType.getReturnTypes()};
185
3.12k
    }
186
9.83k
  };
187
188
  // Helper lambda for checking control stack depth and return index.
189
1.83M
  auto checkCtrlStackDepth = [this](uint32_t N) -> Expect<uint32_t> {
190
    // Check the control stack for at least N + 1 frames.
191
43.0k
    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
43.0k
  };
200
201
  // Helper lambda for checking memory index and perform transformation.
202
1.83M
  auto checkMemAndTrans = [this,
203
1.83M
                           &Instr](Span<const ValType> Take,
204
1.83M
                                   Span<const ValType> Put) -> Expect<void> {
205
5.11k
    if (Instr.getTargetIndex() >= Mems) {
206
8
      return logOutOfRange(ErrCode::Value::InvalidMemoryIdx,
207
8
                           ErrInfo::IndexCategory::Memory,
208
8
                           Instr.getTargetIndex(), Mems);
209
8
    }
210
5.10k
    return StackTrans(Take, Put);
211
5.11k
  };
212
213
  // Helper lambda for checking lane index and perform transformation.
214
1.83M
  auto checkLaneAndTrans = [this,
215
1.83M
                            &Instr](uint32_t N, Span<const ValType> Take,
216
1.83M
                                    Span<const ValType> Put) -> Expect<void> {
217
11.4k
    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.4k
    return StackTrans(Take, Put);
223
11.4k
  };
224
225
  // Helper lambda for checking memory alignment and perform transformation.
226
1.83M
  auto checkAlignAndTrans = [this, checkLaneAndTrans,
227
1.83M
                             &Instr](uint32_t N, Span<const ValType> Take,
228
1.83M
                                     Span<const ValType> Put,
229
1.83M
                                     bool CheckLane = false) -> Expect<void> {
230
50.7k
    if (Instr.getTargetIndex() >= Mems) {
231
34
      return logOutOfRange(ErrCode::Value::InvalidMemoryIdx,
232
34
                           ErrInfo::IndexCategory::Memory,
233
34
                           Instr.getTargetIndex(), Mems);
234
34
    }
235
50.7k
    auto IsAtomic = Instr.getOpCode() >= OpCode::Memory__atomic__notify &&
236
50.7k
                    Instr.getOpCode() <= OpCode::I64__atomic__rmw32__cmpxchg_u;
237
50.7k
    if (Instr.getMemoryAlign() > 31 ||
238
50.7k
        (!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
50.7k
    if (IsAtomic && (1UL << Instr.getMemoryAlign()) != (N >> 3UL)) {
246
      // 2 ^ align needs to == N / 8
247
34
      spdlog::error(ErrCode::Value::InvalidAlignment);
248
34
      spdlog::error(ErrInfo::InfoMismatch(static_cast<uint8_t>(N >> 3),
249
34
                                          Instr.getMemoryAlign()));
250
34
      return Unexpect(ErrCode::Value::InvalidAlignment);
251
34
    }
252
50.6k
    if (CheckLane) {
253
3.94k
      return checkLaneAndTrans(128 / N, Take, Put);
254
3.94k
    }
255
46.7k
    return StackTrans(Take, Put);
256
50.6k
  };
257
258
  // Helper lambda for checking value types matching.
259
1.83M
  auto checkTypesMatching = [this](Span<const ValType> Exp,
260
1.83M
                                   Span<const ValType> Got) -> Expect<void> {
261
1.26k
    if (!AST::TypeMatcher::matchTypes(Types, Exp, Got)) {
262
11
      std::vector<ValType> ExpV(Exp.begin(), Exp.end()),
263
11
          GotV(Got.begin(), Got.end());
264
11
      spdlog::error(ErrCode::Value::TypeCheckFailed);
265
11
      spdlog::error(ErrInfo::InfoMismatch(ExpV, GotV));
266
11
      return Unexpect(ErrCode::Value::TypeCheckFailed);
267
11
    }
268
1.25k
    return {};
269
1.26k
  };
270
271
  // Helper lambda for recording jump data.
272
1.83M
  auto recordJump = [this, &Instr](AST::Instruction::JumpDescriptor &Jump,
273
1.83M
                                   uint32_t Arity, uint32_t D) -> void {
274
42.9k
    const uint32_t Remain =
275
42.9k
        static_cast<uint32_t>(ValStack.size() - CtrlStack[D].Height);
276
42.9k
    Jump.StackEraseBegin = Remain + Arity;
277
42.9k
    Jump.StackEraseEnd = Arity;
278
42.9k
    Jump.PCOffset = static_cast<int32_t>(CtrlStack[D].Jump - &Instr);
279
42.9k
  };
280
281
  // Helper lambda for unpacking a value type.
282
1.83M
  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.83M
  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.83M
  switch (Instr.getOpCode()) {
321
  // Control instructions.
322
212k
  case OpCode::Unreachable:
323
212k
    return unreachable();
324
103k
  case OpCode::Nop:
325
103k
    return {};
326
327
5.20k
  case OpCode::Block:
328
6.94k
  case OpCode::Loop:
329
9.83k
  case OpCode::If:
330
  // LEGACY-EH: remove the `Try` case after deprecating legacy EH.
331
9.83k
  case OpCode::Try:
332
9.83k
  case OpCode::Try_table: {
333
    // Get blocktype [t1*] -> [t2*] and check valtype first.
334
9.83k
    std::vector<ValType> Buffer(1);
335
    // LEGACY-EH: remove the `Try` case after deprecating legacy EH.
336
9.83k
    const auto &BType = (Instr.getOpCode() == OpCode::Try ||
337
9.83k
                         Instr.getOpCode() == OpCode::Try_table)
338
9.83k
                            ? Instr.getTryCatch().ResType
339
9.83k
                            : Instr.getBlockType();
340
9.83k
    EXPECTED_TRY(auto T1T2, checkBlockType(Buffer, BType));
341
9.82k
    auto [T1, T2] = T1T2;
342
    // For the if instruction, pop I32 first.
343
9.82k
    if (Instr.getOpCode() == OpCode::If) {
344
2.88k
      EXPECTED_TRY(popType(TypeCode::I32));
345
2.88k
    }
346
    // Pop and check [t1*]
347
9.82k
    EXPECTED_TRY(popTypes(T1));
348
    // For the try_table instruction, validate the handlers.
349
9.81k
    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.81k
    } 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.81k
    const AST::Instruction *From = Instr.getOpCode() == OpCode::Loop
391
9.81k
                                       ? &Instr
392
9.81k
                                       : &Instr + Instr.getJumpEnd();
393
9.81k
    pushCtrl(T1, T2, From, Instr.getOpCode());
394
9.81k
    if (Instr.getOpCode() == OpCode::If &&
395
9.81k
        Instr.getJumpElse() == Instr.getJumpEnd()) {
396
      // No else case in if-else statement.
397
1.26k
      EXPECTED_TRY(checkTypesMatching(T2, T1));
398
1.26k
    }
399
9.81k
    return {};
400
9.81k
  }
401
402
1.62k
  case OpCode::Else: {
403
1.62k
    EXPECTED_TRY(auto Ctrl, popCtrl());
404
1.62k
    pushCtrl(Ctrl.StartTypes, Ctrl.EndTypes, Ctrl.Jump, Instr.getOpCode());
405
1.62k
    return {};
406
1.62k
  }
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
25.5k
  case OpCode::End: {
459
25.5k
    EXPECTED_TRY(auto Ctrl, popCtrl());
460
25.3k
    pushTypes(Ctrl.EndTypes);
461
25.3k
    return {};
462
25.5k
  }
463
464
2.24k
  case OpCode::Br: {
465
2.24k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
466
    // D is the last D element of control stack.
467
2.23k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
468
2.23k
    EXPECTED_TRY(popTypes(NTypes));
469
2.23k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
470
2.23k
               static_cast<uint32_t>(NTypes.size()), D);
471
2.23k
    return unreachable();
472
2.23k
  }
473
1.21k
  case OpCode::Br_if: {
474
1.21k
    EXPECTED_TRY(auto D, checkCtrlStackDepth(Instr.getJump().TargetIndex));
475
    // D is the last D element of control stack.
476
1.20k
    EXPECTED_TRY(popType(TypeCode::I32));
477
1.19k
    const auto NTypes = getLabelTypes(CtrlStack[D]);
478
1.19k
    EXPECTED_TRY(popTypes(NTypes));
479
1.19k
    recordJump(const_cast<AST::Instruction &>(Instr).getJump(),
480
1.19k
               static_cast<uint32_t>(NTypes.size()), D);
481
1.19k
    pushTypes(NTypes);
482
1.19k
    return {};
483
1.19k
  }
484
1.78k
  case OpCode::Br_table: {
485
1.78k
    EXPECTED_TRY(popType(TypeCode::I32));
486
1.77k
    auto LabelTable = const_cast<AST::Instruction &>(Instr).getLabelList();
487
1.77k
    const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
488
1.77k
    EXPECTED_TRY(auto M,
489
1.76k
                 checkCtrlStackDepth(LabelTable[LabelTableSize].TargetIndex));
490
    // M is the last M element of control stack.
491
1.76k
    auto MTypes = getLabelTypes(CtrlStack[M]);
492
39.5k
    for (uint32_t LabelIdx = 0; LabelIdx < LabelTableSize; ++LabelIdx) {
493
37.7k
      const uint32_t L = LabelTable[LabelIdx].TargetIndex;
494
37.7k
      EXPECTED_TRY(auto N, checkCtrlStackDepth(L));
495
      // N is the last N element of control stack.
496
37.7k
      const auto NTypes = getLabelTypes(CtrlStack[N]);
497
37.7k
      if (MTypes.size() != NTypes.size()) {
498
5
        return checkTypesMatching(MTypes, NTypes);
499
5
      }
500
      // Push the popped types.
501
37.7k
      std::vector<VType> TypeBuf(NTypes.size());
502
42.2k
      for (uint32_t IdxN = static_cast<uint32_t>(NTypes.size()); IdxN >= 1;
503
37.7k
           --IdxN) {
504
4.41k
        const uint32_t Idx = IdxN - 1;
505
        // Cannot use popTypes() here because we need the popped value.
506
4.41k
        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
4.41k
        if (CtrlStack.back().IsUnreachable) {
511
588
          TypeBuf[Idx] = unreachableVType();
512
3.82k
        } else {
513
3.82k
          TypeBuf[Idx] = Type;
514
3.82k
        }
515
4.41k
      }
516
37.7k
      recordJump(LabelTable[LabelIdx], static_cast<uint32_t>(NTypes.size()), N);
517
37.7k
      pushTypes(TypeBuf);
518
37.7k
    }
519
1.74k
    const auto NTypes = getLabelTypes(CtrlStack[M]);
520
1.74k
    EXPECTED_TRY(popTypes(NTypes));
521
1.74k
    recordJump(LabelTable[LabelTableSize], static_cast<uint32_t>(NTypes.size()),
522
1.74k
               M);
523
1.74k
    return unreachable();
524
1.74k
  }
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.46k
  case OpCode::Return:
573
2.46k
    EXPECTED_TRY(popTypes(Returns));
574
2.46k
    return unreachable();
575
576
4.82k
  case OpCode::Call: {
577
4.82k
    auto N = Instr.getTargetIndex();
578
4.82k
    if (unlikely(N >= Funcs.size())) {
579
26
      return logOutOfRange(ErrCode::Value::InvalidFuncIdx,
580
26
                           ErrInfo::IndexCategory::Function, N,
581
26
                           static_cast<uint32_t>(Funcs.size()));
582
26
    }
583
    // Due to validation when adding functions, Type[Funcs[N]] must be a
584
    // function type.
585
4.80k
    auto &FuncType = Types[Funcs[N]]->getCompositeType().getFuncType();
586
4.80k
    return StackTrans(FuncType.getParamTypes(), FuncType.getReturnTypes());
587
4.82k
  }
588
873
  case OpCode::Call_indirect: {
589
873
    auto N = Instr.getTargetIndex();
590
873
    auto T = Instr.getSourceIndex();
591
    // Check source table index.
592
873
    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
855
    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.70k
    EXPECTED_TRY(auto CompType, checkDefinedType(N, TypeCode::Func));
604
1.70k
    EXPECTED_TRY(popType(TypeCode::I32));
605
850
    const auto &FType = CompType->getFuncType();
606
850
    return StackTrans(FType.getParamTypes(), FType.getReturnTypes());
607
1.70k
  }
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.57k
  case OpCode::Ref__null: {
687
1.57k
    EXPECTED_TRY(validate(Instr.getValType()));
688
1.57k
    return StackTrans({}, {Instr.getValType()});
689
1.57k
  }
690
752
  case OpCode::Ref__is_null: {
691
752
    EXPECTED_TRY(auto Type, popType());
692
751
    if (Type.has_value() && !Type->isRefType()) {
693
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
694
3
      spdlog::error(ErrInfo::InfoMismatch(TypeCode::FuncRef, VTypeToAST(Type)));
695
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
696
3
    }
697
748
    return StackTrans({}, {ValType(TypeCode::I32)});
698
751
  }
699
1.22k
  case OpCode::Ref__func: {
700
1.22k
    auto FuncIdx = Instr.getTargetIndex();
701
1.22k
    if (Refs.find(FuncIdx) == Refs.cend()) {
702
      // Undeclared function reference.
703
26
      spdlog::error(ErrCode::Value::InvalidRefIdx);
704
26
      return Unexpect(ErrCode::Value::InvalidRefIdx);
705
26
    }
706
1.19k
    assuming(FuncIdx < Funcs.size());
707
1.19k
    auto TypeIdx = Funcs[FuncIdx];
708
1.19k
    assuming(TypeIdx < Types.size());
709
1.19k
    return StackTrans({}, {ValType(TypeCode::Ref, TypeIdx)});
710
1.19k
  }
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.19k
  case OpCode::Drop:
1034
7.19k
    return StackPopAny();
1035
4.89k
  case OpCode::Select: {
1036
    // Pop I32.
1037
4.89k
    EXPECTED_TRY(popType(TypeCode::I32));
1038
    // Pop T1 and T2.
1039
9.79k
    EXPECTED_TRY(VType T1, popType());
1040
9.79k
    EXPECTED_TRY(VType T2, popType());
1041
    // T1 and T2 should be number type.
1042
4.89k
    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.89k
    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.88k
    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.88k
    if (T1 == unreachableVType()) {
1060
3.40k
      pushType(T2);
1061
3.40k
    } else {
1062
1.48k
      pushType(T1);
1063
1.48k
    }
1064
4.88k
    return {};
1065
4.88k
  }
1066
578
  case OpCode::Select_t: {
1067
    // Note: There may be multiple values choice in the future.
1068
578
    if (Instr.getValTypeList().size() != 1) {
1069
5
      spdlog::error(ErrCode::Value::InvalidResultArity);
1070
5
      return Unexpect(ErrCode::Value::InvalidResultArity);
1071
5
    }
1072
573
    ValType ExpT = Instr.getValTypeList()[0];
1073
573
    EXPECTED_TRY(validate(ExpT));
1074
573
    EXPECTED_TRY(popTypes({ExpT, ExpT, ValType(TypeCode::I32)}));
1075
572
    pushType(ExpT);
1076
572
    return {};
1077
573
  }
1078
1079
  // Variable Instructions.
1080
17.8k
  case OpCode::Local__get:
1081
25.5k
  case OpCode::Local__set:
1082
32.3k
  case OpCode::Local__tee: {
1083
32.3k
    if (Instr.getTargetIndex() >= Locals.size()) {
1084
48
      return logOutOfRange(
1085
48
          ErrCode::Value::InvalidLocalIdx, ErrInfo::IndexCategory::Local,
1086
48
          Instr.getTargetIndex(), static_cast<uint32_t>(Locals.size()));
1087
48
    }
1088
32.3k
    auto &TExpect = Locals[Instr.getTargetIndex()];
1089
32.3k
    const_cast<AST::Instruction &>(Instr).getStackOffset() =
1090
32.3k
        static_cast<uint32_t>(ValStack.size() +
1091
32.3k
                              (Locals.size() - Instr.getTargetIndex()));
1092
32.3k
    if (Instr.getOpCode() == OpCode::Local__get) {
1093
17.7k
      if (!TExpect.IsInit) {
1094
0
        spdlog::error(ErrCode::Value::InvalidUninitLocal);
1095
0
        return Unexpect(ErrCode::Value::InvalidUninitLocal);
1096
0
      }
1097
17.7k
      return StackTrans({}, {TExpect.VType});
1098
17.7k
    } else if (Instr.getOpCode() == OpCode::Local__set) {
1099
7.70k
      if (!TExpect.IsInit) {
1100
0
        TExpect.IsInit = true;
1101
0
        LocalInits.push_back(Instr.getTargetIndex());
1102
0
      }
1103
7.70k
      return StackTrans({TExpect.VType}, {});
1104
7.70k
    } else if (Instr.getOpCode() == OpCode::Local__tee) {
1105
6.84k
      if (!TExpect.IsInit) {
1106
0
        TExpect.IsInit = true;
1107
0
        LocalInits.push_back(Instr.getTargetIndex());
1108
0
      }
1109
6.84k
      return StackTrans({TExpect.VType}, {TExpect.VType});
1110
6.84k
    } else {
1111
0
      assumingUnreachable();
1112
0
    }
1113
32.3k
  }
1114
78
  case OpCode::Global__set:
1115
    // Global case, check mutation.
1116
78
    if (Instr.getTargetIndex() < Globals.size() &&
1117
78
        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
77
    [[fallthrough]];
1123
480
  case OpCode::Global__get: {
1124
480
    if (Instr.getTargetIndex() >= Globals.size()) {
1125
23
      return logOutOfRange(
1126
23
          ErrCode::Value::InvalidGlobalIdx, ErrInfo::IndexCategory::Global,
1127
23
          Instr.getTargetIndex(), static_cast<uint32_t>(Globals.size()));
1128
23
    }
1129
457
    ValType ExpT = Globals[Instr.getTargetIndex()].first;
1130
457
    if (Instr.getOpCode() == OpCode::Global__set) {
1131
62
      return StackTrans({ExpT}, {});
1132
395
    } else {
1133
395
      return StackTrans({}, {ExpT});
1134
395
    }
1135
457
  }
1136
1137
  // Table Instructions.
1138
90
  case OpCode::Table__get:
1139
308
  case OpCode::Table__set:
1140
383
  case OpCode::Table__grow:
1141
442
  case OpCode::Table__size:
1142
480
  case OpCode::Table__fill:
1143
517
  case OpCode::Table__init:
1144
669
  case OpCode::Table__copy: {
1145
    // Check target table index to perform.
1146
669
    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
651
    ValType ExpT = Tables[Instr.getTargetIndex()];
1152
651
    if (Instr.getOpCode() == OpCode::Table__get) {
1153
83
      return StackTrans({ValType(TypeCode::I32)}, {ExpT});
1154
568
    } else if (Instr.getOpCode() == OpCode::Table__set) {
1155
214
      return StackTrans({ValType(TypeCode::I32), ExpT}, {});
1156
354
    } else if (Instr.getOpCode() == OpCode::Table__grow) {
1157
72
      return StackTrans({ExpT, ValType(TypeCode::I32)},
1158
72
                        {ValType(TypeCode::I32)});
1159
282
    } else if (Instr.getOpCode() == OpCode::Table__size) {
1160
59
      return StackTrans({}, {ValType(TypeCode::I32)});
1161
223
    } else if (Instr.getOpCode() == OpCode::Table__fill) {
1162
38
      return StackTrans({ValType(TypeCode::I32), ExpT, ValType(TypeCode::I32)},
1163
38
                        {});
1164
185
    } else if (Instr.getOpCode() == OpCode::Table__init) {
1165
      // Check source element index for initialization.
1166
35
      if (Instr.getSourceIndex() >= Elems.size()) {
1167
5
        return logOutOfRange(
1168
5
            ErrCode::Value::InvalidElemIdx, ErrInfo::IndexCategory::Element,
1169
5
            Instr.getSourceIndex(), static_cast<uint32_t>(Elems.size()));
1170
5
      }
1171
      // Check is the reference types matched.
1172
30
      if (!AST::TypeMatcher::matchType(Types, Tables[Instr.getTargetIndex()],
1173
30
                                       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
29
      return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32),
1180
29
                         ValType(TypeCode::I32)},
1181
29
                        {});
1182
150
    } else if (Instr.getOpCode() == OpCode::Table__copy) {
1183
      // Check source table index for copying.
1184
150
      if (Instr.getSourceIndex() >= Tables.size()) {
1185
3
        return logOutOfRange(
1186
3
            ErrCode::Value::InvalidTableIdx, ErrInfo::IndexCategory::Table,
1187
3
            Instr.getSourceIndex(), static_cast<uint32_t>(Tables.size()));
1188
3
      }
1189
      // Check is the reference types matched.
1190
147
      if (!AST::TypeMatcher::matchType(Types, Tables[Instr.getTargetIndex()],
1191
147
                                       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
146
      return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32),
1198
146
                         ValType(TypeCode::I32)},
1199
146
                        {});
1200
147
    } else {
1201
0
      assumingUnreachable();
1202
0
    }
1203
651
  }
1204
40
  case OpCode::Elem__drop:
1205
    // Check target element index to drop.
1206
40
    if (Instr.getTargetIndex() >= Elems.size()) {
1207
6
      return logOutOfRange(
1208
6
          ErrCode::Value::InvalidElemIdx, ErrInfo::IndexCategory::Element,
1209
6
          Instr.getTargetIndex(), static_cast<uint32_t>(Elems.size()));
1210
6
    }
1211
34
    return {};
1212
1213
  // Memory Instructions.
1214
1.82k
  case OpCode::I32__load:
1215
1.82k
    return checkAlignAndTrans(32, {ValType(TypeCode::I32)},
1216
1.82k
                              {ValType(TypeCode::I32)});
1217
6.19k
  case OpCode::I64__load:
1218
6.19k
    return checkAlignAndTrans(64, {ValType(TypeCode::I32)},
1219
6.19k
                              {ValType(TypeCode::I64)});
1220
241
  case OpCode::F32__load:
1221
241
    return checkAlignAndTrans(32, {ValType(TypeCode::I32)},
1222
241
                              {ValType(TypeCode::F32)});
1223
891
  case OpCode::F64__load:
1224
891
    return checkAlignAndTrans(64, {ValType(TypeCode::I32)},
1225
891
                              {ValType(TypeCode::F64)});
1226
1.57k
  case OpCode::I32__load8_s:
1227
1.87k
  case OpCode::I32__load8_u:
1228
1.87k
    return checkAlignAndTrans(8, {ValType(TypeCode::I32)},
1229
1.87k
                              {ValType(TypeCode::I32)});
1230
999
  case OpCode::I32__load16_s:
1231
2.96k
  case OpCode::I32__load16_u:
1232
2.96k
    return checkAlignAndTrans(16, {ValType(TypeCode::I32)},
1233
2.96k
                              {ValType(TypeCode::I32)});
1234
1.21k
  case OpCode::I64__load8_s:
1235
1.97k
  case OpCode::I64__load8_u:
1236
1.97k
    return checkAlignAndTrans(8, {ValType(TypeCode::I32)},
1237
1.97k
                              {ValType(TypeCode::I64)});
1238
1.21k
  case OpCode::I64__load16_s:
1239
3.06k
  case OpCode::I64__load16_u:
1240
3.06k
    return checkAlignAndTrans(16, {ValType(TypeCode::I32)},
1241
3.06k
                              {ValType(TypeCode::I64)});
1242
952
  case OpCode::I64__load32_s:
1243
2.27k
  case OpCode::I64__load32_u:
1244
2.27k
    return checkAlignAndTrans(32, {ValType(TypeCode::I32)},
1245
2.27k
                              {ValType(TypeCode::I64)});
1246
698
  case OpCode::I32__store:
1247
698
    return checkAlignAndTrans(
1248
698
        32, {ValType(TypeCode::I32), ValType(TypeCode::I32)}, {});
1249
4.01k
  case OpCode::I64__store:
1250
4.01k
    return checkAlignAndTrans(
1251
4.01k
        64, {ValType(TypeCode::I32), ValType(TypeCode::I64)}, {});
1252
612
  case OpCode::F32__store:
1253
612
    return checkAlignAndTrans(
1254
612
        32, {ValType(TypeCode::I32), ValType(TypeCode::F32)}, {});
1255
317
  case OpCode::F64__store:
1256
317
    return checkAlignAndTrans(
1257
317
        64, {ValType(TypeCode::I32), ValType(TypeCode::F64)}, {});
1258
1.10k
  case OpCode::I32__store8:
1259
1.10k
    return checkAlignAndTrans(
1260
1.10k
        8, {ValType(TypeCode::I32), ValType(TypeCode::I32)}, {});
1261
428
  case OpCode::I32__store16:
1262
428
    return checkAlignAndTrans(
1263
428
        16, {ValType(TypeCode::I32), ValType(TypeCode::I32)}, {});
1264
199
  case OpCode::I64__store8:
1265
199
    return checkAlignAndTrans(
1266
199
        8, {ValType(TypeCode::I32), ValType(TypeCode::I64)}, {});
1267
395
  case OpCode::I64__store16:
1268
395
    return checkAlignAndTrans(
1269
395
        16, {ValType(TypeCode::I32), ValType(TypeCode::I64)}, {});
1270
228
  case OpCode::I64__store32:
1271
228
    return checkAlignAndTrans(
1272
228
        32, {ValType(TypeCode::I32), ValType(TypeCode::I64)}, {});
1273
1.25k
  case OpCode::Memory__size:
1274
1.25k
    return checkMemAndTrans({}, {ValType(TypeCode::I32)});
1275
2.10k
  case OpCode::Memory__grow:
1276
2.10k
    return checkMemAndTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1277
34
  case OpCode::Memory__init:
1278
    // Check the target memory index. Memory index should be checked first.
1279
34
    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
33
    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
29
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32),
1291
29
                       ValType(TypeCode::I32)},
1292
29
                      {});
1293
603
  case OpCode::Memory__copy:
1294
    /// Check the source memory index.
1295
603
    if (Instr.getSourceIndex() >= Mems) {
1296
3
      return logOutOfRange(ErrCode::Value::InvalidMemoryIdx,
1297
3
                           ErrInfo::IndexCategory::Memory,
1298
3
                           Instr.getSourceIndex(), Mems);
1299
3
    }
1300
600
    [[fallthrough]];
1301
1.75k
  case OpCode::Memory__fill:
1302
1.75k
    return checkMemAndTrans({ValType(TypeCode::I32), ValType(TypeCode::I32),
1303
1.75k
                             ValType(TypeCode::I32)},
1304
1.75k
                            {});
1305
81
  case OpCode::Data__drop:
1306
    // Check the target data index.
1307
81
    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
79
    return {};
1313
1314
  // Const Instructions.
1315
767k
  case OpCode::I32__const:
1316
767k
    return StackTrans({}, {ValType(TypeCode::I32)});
1317
107k
  case OpCode::I64__const:
1318
107k
    return StackTrans({}, {ValType(TypeCode::I64)});
1319
20.2k
  case OpCode::F32__const:
1320
20.2k
    return StackTrans({}, {ValType(TypeCode::F32)});
1321
9.74k
  case OpCode::F64__const:
1322
9.74k
    return StackTrans({}, {ValType(TypeCode::F64)});
1323
1324
  // Unary Numeric Instructions.
1325
9.30k
  case OpCode::I32__eqz:
1326
9.30k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1327
1.69k
  case OpCode::I64__eqz:
1328
1.69k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1329
5.16k
  case OpCode::I32__clz:
1330
8.62k
  case OpCode::I32__ctz:
1331
29.6k
  case OpCode::I32__popcnt:
1332
29.6k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1333
494
  case OpCode::I64__clz:
1334
1.60k
  case OpCode::I64__ctz:
1335
4.34k
  case OpCode::I64__popcnt:
1336
4.34k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1337
936
  case OpCode::F32__abs:
1338
2.99k
  case OpCode::F32__neg:
1339
5.09k
  case OpCode::F32__ceil:
1340
6.11k
  case OpCode::F32__floor:
1341
7.20k
  case OpCode::F32__trunc:
1342
8.28k
  case OpCode::F32__nearest:
1343
12.5k
  case OpCode::F32__sqrt:
1344
12.5k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::F32)});
1345
2.07k
  case OpCode::F64__abs:
1346
3.36k
  case OpCode::F64__neg:
1347
6.32k
  case OpCode::F64__ceil:
1348
6.86k
  case OpCode::F64__floor:
1349
7.38k
  case OpCode::F64__trunc:
1350
9.28k
  case OpCode::F64__nearest:
1351
11.4k
  case OpCode::F64__sqrt:
1352
11.4k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F64)});
1353
562
  case OpCode::I32__wrap_i64:
1354
562
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I32)});
1355
1.62k
  case OpCode::I32__trunc_f32_s:
1356
2.03k
  case OpCode::I32__trunc_f32_u:
1357
2.03k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1358
912
  case OpCode::I32__trunc_f64_s:
1359
2.54k
  case OpCode::I32__trunc_f64_u:
1360
2.54k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1361
2.78k
  case OpCode::I64__extend_i32_s:
1362
3.31k
  case OpCode::I64__extend_i32_u:
1363
3.31k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I64)});
1364
606
  case OpCode::I64__trunc_f32_s:
1365
1.68k
  case OpCode::I64__trunc_f32_u:
1366
1.68k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1367
947
  case OpCode::I64__trunc_f64_s:
1368
2.56k
  case OpCode::I64__trunc_f64_u:
1369
2.56k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1370
2.46k
  case OpCode::F32__convert_i32_s:
1371
4.06k
  case OpCode::F32__convert_i32_u:
1372
4.06k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1373
1.59k
  case OpCode::F32__convert_i64_s:
1374
3.05k
  case OpCode::F32__convert_i64_u:
1375
3.05k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F32)});
1376
346
  case OpCode::F32__demote_f64:
1377
346
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::F32)});
1378
1.94k
  case OpCode::F64__convert_i32_s:
1379
4.07k
  case OpCode::F64__convert_i32_u:
1380
4.07k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F64)});
1381
7.39k
  case OpCode::F64__convert_i64_s:
1382
7.74k
  case OpCode::F64__convert_i64_u:
1383
7.74k
    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
880
  case OpCode::I32__reinterpret_f32:
1387
880
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1388
1.66k
  case OpCode::I64__reinterpret_f64:
1389
1.66k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1390
5.75k
  case OpCode::F32__reinterpret_i32:
1391
5.75k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::F32)});
1392
2.72k
  case OpCode::F64__reinterpret_i64:
1393
2.72k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::F64)});
1394
2.11k
  case OpCode::I32__extend8_s:
1395
6.88k
  case OpCode::I32__extend16_s:
1396
6.88k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::I32)});
1397
687
  case OpCode::I64__extend8_s:
1398
1.84k
  case OpCode::I64__extend16_s:
1399
2.63k
  case OpCode::I64__extend32_s:
1400
2.63k
    return StackTrans({ValType(TypeCode::I64)}, {ValType(TypeCode::I64)});
1401
424
  case OpCode::I32__trunc_sat_f32_s:
1402
771
  case OpCode::I32__trunc_sat_f32_u:
1403
771
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I32)});
1404
559
  case OpCode::I32__trunc_sat_f64_s:
1405
846
  case OpCode::I32__trunc_sat_f64_u:
1406
846
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I32)});
1407
520
  case OpCode::I64__trunc_sat_f32_s:
1408
1.00k
  case OpCode::I64__trunc_sat_f32_u:
1409
1.00k
    return StackTrans({ValType(TypeCode::F32)}, {ValType(TypeCode::I64)});
1410
689
  case OpCode::I64__trunc_sat_f64_s:
1411
1.40k
  case OpCode::I64__trunc_sat_f64_u:
1412
1.40k
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::I64)});
1413
1414
  // Binary Numeric Instructions.
1415
2.11k
  case OpCode::I32__eq:
1416
3.35k
  case OpCode::I32__ne:
1417
8.54k
  case OpCode::I32__lt_s:
1418
16.9k
  case OpCode::I32__lt_u:
1419
18.9k
  case OpCode::I32__gt_s:
1420
27.5k
  case OpCode::I32__gt_u:
1421
30.8k
  case OpCode::I32__le_s:
1422
31.9k
  case OpCode::I32__le_u:
1423
34.7k
  case OpCode::I32__ge_s:
1424
37.0k
  case OpCode::I32__ge_u:
1425
37.0k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1426
37.0k
                      {ValType(TypeCode::I32)});
1427
322
  case OpCode::I64__eq:
1428
1.13k
  case OpCode::I64__ne:
1429
2.53k
  case OpCode::I64__lt_s:
1430
3.36k
  case OpCode::I64__lt_u:
1431
4.57k
  case OpCode::I64__gt_s:
1432
4.84k
  case OpCode::I64__gt_u:
1433
5.83k
  case OpCode::I64__le_s:
1434
7.67k
  case OpCode::I64__le_u:
1435
8.01k
  case OpCode::I64__ge_s:
1436
9.04k
  case OpCode::I64__ge_u:
1437
9.04k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1438
9.04k
                      {ValType(TypeCode::I32)});
1439
700
  case OpCode::F32__eq:
1440
1.20k
  case OpCode::F32__ne:
1441
2.07k
  case OpCode::F32__lt:
1442
2.32k
  case OpCode::F32__gt:
1443
2.94k
  case OpCode::F32__le:
1444
3.37k
  case OpCode::F32__ge:
1445
3.37k
    return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)},
1446
3.37k
                      {ValType(TypeCode::I32)});
1447
502
  case OpCode::F64__eq:
1448
696
  case OpCode::F64__ne:
1449
1.12k
  case OpCode::F64__lt:
1450
2.04k
  case OpCode::F64__gt:
1451
2.42k
  case OpCode::F64__le:
1452
3.31k
  case OpCode::F64__ge:
1453
3.31k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1454
3.31k
                      {ValType(TypeCode::I32)});
1455
1.56k
  case OpCode::I32__add:
1456
4.41k
  case OpCode::I32__sub:
1457
5.54k
  case OpCode::I32__mul:
1458
8.26k
  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.0k
  case OpCode::I32__and:
1463
22.1k
  case OpCode::I32__or:
1464
23.8k
  case OpCode::I32__xor:
1465
27.3k
  case OpCode::I32__shl:
1466
30.2k
  case OpCode::I32__shr_s:
1467
35.6k
  case OpCode::I32__shr_u:
1468
39.4k
  case OpCode::I32__rotl:
1469
41.5k
  case OpCode::I32__rotr:
1470
41.5k
    return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)},
1471
41.5k
                      {ValType(TypeCode::I32)});
1472
1.18k
  case OpCode::I64__add:
1473
2.02k
  case OpCode::I64__sub:
1474
3.28k
  case OpCode::I64__mul:
1475
4.05k
  case OpCode::I64__div_s:
1476
6.67k
  case OpCode::I64__div_u:
1477
7.52k
  case OpCode::I64__rem_s:
1478
8.54k
  case OpCode::I64__rem_u:
1479
10.2k
  case OpCode::I64__and:
1480
11.1k
  case OpCode::I64__or:
1481
12.1k
  case OpCode::I64__xor:
1482
12.7k
  case OpCode::I64__shl:
1483
13.5k
  case OpCode::I64__shr_s:
1484
14.2k
  case OpCode::I64__shr_u:
1485
16.5k
  case OpCode::I64__rotl:
1486
20.0k
  case OpCode::I64__rotr:
1487
20.0k
    return StackTrans({ValType(TypeCode::I64), ValType(TypeCode::I64)},
1488
20.0k
                      {ValType(TypeCode::I64)});
1489
717
  case OpCode::F32__add:
1490
2.31k
  case OpCode::F32__sub:
1491
3.37k
  case OpCode::F32__mul:
1492
3.89k
  case OpCode::F32__div:
1493
4.64k
  case OpCode::F32__min:
1494
5.52k
  case OpCode::F32__max:
1495
6.76k
  case OpCode::F32__copysign:
1496
6.76k
    return StackTrans({ValType(TypeCode::F32), ValType(TypeCode::F32)},
1497
6.76k
                      {ValType(TypeCode::F32)});
1498
808
  case OpCode::F64__add:
1499
2.23k
  case OpCode::F64__sub:
1500
3.45k
  case OpCode::F64__mul:
1501
4.37k
  case OpCode::F64__div:
1502
5.34k
  case OpCode::F64__min:
1503
7.03k
  case OpCode::F64__max:
1504
7.96k
  case OpCode::F64__copysign:
1505
7.96k
    return StackTrans({ValType(TypeCode::F64), ValType(TypeCode::F64)},
1506
7.96k
                      {ValType(TypeCode::F64)});
1507
1508
  // SIMD Memory Instruction.
1509
10.3k
  case OpCode::V128__load:
1510
10.3k
    return checkAlignAndTrans(128, {ValType(TypeCode::I32)},
1511
10.3k
                              {ValType(TypeCode::V128)});
1512
934
  case OpCode::V128__load8x8_s:
1513
1.02k
  case OpCode::V128__load8x8_u:
1514
1.67k
  case OpCode::V128__load16x4_s:
1515
3.08k
  case OpCode::V128__load16x4_u:
1516
3.59k
  case OpCode::V128__load32x2_s:
1517
3.80k
  case OpCode::V128__load32x2_u:
1518
4.27k
  case OpCode::V128__load64_splat:
1519
4.48k
  case OpCode::V128__load64_zero:
1520
4.48k
    return checkAlignAndTrans(64, {ValType(TypeCode::I32)},
1521
4.48k
                              {ValType(TypeCode::V128)});
1522
398
  case OpCode::V128__load8_splat:
1523
398
    return checkAlignAndTrans(8, {ValType(TypeCode::I32)},
1524
398
                              {ValType(TypeCode::V128)});
1525
752
  case OpCode::V128__load16_splat:
1526
752
    return checkAlignAndTrans(16, {ValType(TypeCode::I32)},
1527
752
                              {ValType(TypeCode::V128)});
1528
617
  case OpCode::V128__load32_splat:
1529
798
  case OpCode::V128__load32_zero:
1530
798
    return checkAlignAndTrans(32, {ValType(TypeCode::I32)},
1531
798
                              {ValType(TypeCode::V128)});
1532
594
  case OpCode::V128__store:
1533
594
    return checkAlignAndTrans(
1534
594
        128, {ValType(TypeCode::I32), ValType(TypeCode::V128)}, {});
1535
367
  case OpCode::V128__load8_lane:
1536
367
    return checkAlignAndTrans(8,
1537
367
                              {ValType(TypeCode::I32), ValType(TypeCode::V128)},
1538
367
                              {ValType(TypeCode::V128)}, true);
1539
1.35k
  case OpCode::V128__load16_lane:
1540
1.35k
    return checkAlignAndTrans(16,
1541
1.35k
                              {ValType(TypeCode::I32), ValType(TypeCode::V128)},
1542
1.35k
                              {ValType(TypeCode::V128)}, true);
1543
252
  case OpCode::V128__load32_lane:
1544
252
    return checkAlignAndTrans(32,
1545
252
                              {ValType(TypeCode::I32), ValType(TypeCode::V128)},
1546
252
                              {ValType(TypeCode::V128)}, true);
1547
394
  case OpCode::V128__load64_lane:
1548
394
    return checkAlignAndTrans(64,
1549
394
                              {ValType(TypeCode::I32), ValType(TypeCode::V128)},
1550
394
                              {ValType(TypeCode::V128)}, true);
1551
311
  case OpCode::V128__store8_lane:
1552
311
    return checkAlignAndTrans(
1553
311
        8, {ValType(TypeCode::I32), ValType(TypeCode::V128)}, {}, true);
1554
176
  case OpCode::V128__store16_lane:
1555
176
    return checkAlignAndTrans(
1556
176
        16, {ValType(TypeCode::I32), ValType(TypeCode::V128)}, {}, true);
1557
825
  case OpCode::V128__store32_lane:
1558
825
    return checkAlignAndTrans(
1559
825
        32, {ValType(TypeCode::I32), ValType(TypeCode::V128)}, {}, true);
1560
267
  case OpCode::V128__store64_lane:
1561
267
    return checkAlignAndTrans(
1562
267
        64, {ValType(TypeCode::I32), ValType(TypeCode::V128)}, {}, true);
1563
1564
  // SIMD Const Instruction.
1565
555
  case OpCode::V128__const:
1566
555
    return StackTrans({}, {ValType(TypeCode::V128)});
1567
1568
  // SIMD Shuffle Instruction.
1569
234
  case OpCode::I8x16__shuffle: {
1570
    // Check all lane index < 32 by masking
1571
234
    const uint128_t Mask = (uint128_t(0xe0e0e0e0e0e0e0e0U) << 64U) |
1572
234
                           uint128_t(0xe0e0e0e0e0e0e0e0U);
1573
234
    const uint128_t Result = Instr.getNum().get<uint128_t>() & Mask;
1574
234
    if (Result) {
1575
5
      spdlog::error(ErrCode::Value::InvalidLaneIdx);
1576
5
      return Unexpect(ErrCode::Value::InvalidLaneIdx);
1577
5
    }
1578
229
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1579
229
                      {ValType(TypeCode::V128)});
1580
234
  }
1581
1582
  // SIMD Lane Instructions.
1583
931
  case OpCode::I8x16__extract_lane_s:
1584
1.06k
  case OpCode::I8x16__extract_lane_u:
1585
1.06k
    return checkLaneAndTrans(16, {ValType(TypeCode::V128)},
1586
1.06k
                             {ValType(TypeCode::I32)});
1587
873
  case OpCode::I8x16__replace_lane:
1588
873
    return checkLaneAndTrans(16,
1589
873
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1590
873
                             {ValType(TypeCode::V128)});
1591
701
  case OpCode::I16x8__extract_lane_s:
1592
1.40k
  case OpCode::I16x8__extract_lane_u:
1593
1.40k
    return checkLaneAndTrans(8, {ValType(TypeCode::V128)},
1594
1.40k
                             {ValType(TypeCode::I32)});
1595
563
  case OpCode::I16x8__replace_lane:
1596
563
    return checkLaneAndTrans(8,
1597
563
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1598
563
                             {ValType(TypeCode::V128)});
1599
1.20k
  case OpCode::I32x4__extract_lane:
1600
1.20k
    return checkLaneAndTrans(4, {ValType(TypeCode::V128)},
1601
1.20k
                             {ValType(TypeCode::I32)});
1602
694
  case OpCode::I32x4__replace_lane:
1603
694
    return checkLaneAndTrans(4,
1604
694
                             {ValType(TypeCode::V128), ValType(TypeCode::I32)},
1605
694
                             {ValType(TypeCode::V128)});
1606
230
  case OpCode::I64x2__extract_lane:
1607
230
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1608
230
                             {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
130
  case OpCode::F32x4__extract_lane:
1614
130
    return checkLaneAndTrans(4, {ValType(TypeCode::V128)},
1615
130
                             {ValType(TypeCode::F32)});
1616
115
  case OpCode::F32x4__replace_lane:
1617
115
    return checkLaneAndTrans(4,
1618
115
                             {ValType(TypeCode::V128), ValType(TypeCode::F32)},
1619
115
                             {ValType(TypeCode::V128)});
1620
322
  case OpCode::F64x2__extract_lane:
1621
322
    return checkLaneAndTrans(2, {ValType(TypeCode::V128)},
1622
322
                             {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
49.8k
  case OpCode::I8x16__splat:
1630
63.4k
  case OpCode::I16x8__splat:
1631
65.4k
  case OpCode::I32x4__splat:
1632
65.4k
    return StackTrans({ValType(TypeCode::I32)}, {ValType(TypeCode::V128)});
1633
767
  case OpCode::I64x2__splat:
1634
767
    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
561
  case OpCode::F64x2__splat:
1638
561
    return StackTrans({ValType(TypeCode::F64)}, {ValType(TypeCode::V128)});
1639
295
  case OpCode::V128__not:
1640
1.76k
  case OpCode::I8x16__abs:
1641
4.41k
  case OpCode::I8x16__neg:
1642
5.30k
  case OpCode::I8x16__popcnt:
1643
5.88k
  case OpCode::I16x8__abs:
1644
6.38k
  case OpCode::I16x8__neg:
1645
7.45k
  case OpCode::I16x8__extend_low_i8x16_s:
1646
7.60k
  case OpCode::I16x8__extend_high_i8x16_s:
1647
8.26k
  case OpCode::I16x8__extend_low_i8x16_u:
1648
8.32k
  case OpCode::I16x8__extend_high_i8x16_u:
1649
9.32k
  case OpCode::I16x8__extadd_pairwise_i8x16_s:
1650
10.7k
  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.6k
  case OpCode::I32x4__extend_high_i16x8_s:
1655
15.1k
  case OpCode::I32x4__extend_low_i16x8_u:
1656
15.5k
  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.3k
  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.8k
  case OpCode::I64x2__extend_high_i32x4_u:
1665
24.0k
  case OpCode::F32x4__abs:
1666
24.5k
  case OpCode::F32x4__neg:
1667
24.8k
  case OpCode::F32x4__sqrt:
1668
25.4k
  case OpCode::F64x2__abs:
1669
26.9k
  case OpCode::F64x2__neg:
1670
27.1k
  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.8k
  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.5k
  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.5k
  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.7k
  case OpCode::F32x4__nearest:
1685
50.7k
  case OpCode::F64x2__ceil:
1686
51.7k
  case OpCode::F64x2__floor:
1687
52.6k
  case OpCode::F64x2__trunc:
1688
53.0k
  case OpCode::F64x2__nearest:
1689
53.0k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)});
1690
1.10k
  case OpCode::I8x16__swizzle:
1691
1.36k
  case OpCode::I8x16__eq:
1692
2.02k
  case OpCode::I8x16__ne:
1693
2.25k
  case OpCode::I8x16__lt_s:
1694
2.58k
  case OpCode::I8x16__lt_u:
1695
3.62k
  case OpCode::I8x16__gt_s:
1696
3.95k
  case OpCode::I8x16__gt_u:
1697
4.21k
  case OpCode::I8x16__le_s:
1698
4.48k
  case OpCode::I8x16__le_u:
1699
5.34k
  case OpCode::I8x16__ge_s:
1700
5.73k
  case OpCode::I8x16__ge_u:
1701
6.03k
  case OpCode::I16x8__eq:
1702
6.78k
  case OpCode::I16x8__ne:
1703
7.24k
  case OpCode::I16x8__lt_s:
1704
8.47k
  case OpCode::I16x8__lt_u:
1705
9.22k
  case OpCode::I16x8__gt_s:
1706
10.3k
  case OpCode::I16x8__gt_u:
1707
10.6k
  case OpCode::I16x8__le_s:
1708
10.9k
  case OpCode::I16x8__le_u:
1709
11.5k
  case OpCode::I16x8__ge_s:
1710
12.1k
  case OpCode::I16x8__ge_u:
1711
12.5k
  case OpCode::I32x4__eq:
1712
12.8k
  case OpCode::I32x4__ne:
1713
13.2k
  case OpCode::I32x4__lt_s:
1714
13.5k
  case OpCode::I32x4__lt_u:
1715
13.7k
  case OpCode::I32x4__gt_s:
1716
14.2k
  case OpCode::I32x4__gt_u:
1717
15.0k
  case OpCode::I32x4__le_s:
1718
15.5k
  case OpCode::I32x4__le_u:
1719
15.6k
  case OpCode::I32x4__ge_s:
1720
16.1k
  case OpCode::I32x4__ge_u:
1721
16.4k
  case OpCode::I64x2__eq:
1722
16.8k
  case OpCode::I64x2__ne:
1723
17.2k
  case OpCode::I64x2__lt_s:
1724
17.5k
  case OpCode::I64x2__gt_s:
1725
17.7k
  case OpCode::I64x2__le_s:
1726
18.4k
  case OpCode::I64x2__ge_s:
1727
20.8k
  case OpCode::F32x4__eq:
1728
20.9k
  case OpCode::F32x4__ne:
1729
22.2k
  case OpCode::F32x4__lt:
1730
22.4k
  case OpCode::F32x4__gt:
1731
23.0k
  case OpCode::F32x4__le:
1732
23.1k
  case OpCode::F32x4__ge:
1733
23.6k
  case OpCode::F64x2__eq:
1734
24.0k
  case OpCode::F64x2__ne:
1735
24.5k
  case OpCode::F64x2__lt:
1736
24.8k
  case OpCode::F64x2__gt:
1737
25.3k
  case OpCode::F64x2__le:
1738
25.8k
  case OpCode::F64x2__ge:
1739
26.0k
  case OpCode::V128__and:
1740
26.3k
  case OpCode::V128__andnot:
1741
27.0k
  case OpCode::V128__or:
1742
27.5k
  case OpCode::V128__xor:
1743
28.1k
  case OpCode::I8x16__narrow_i16x8_s:
1744
28.6k
  case OpCode::I8x16__narrow_i16x8_u:
1745
29.0k
  case OpCode::I8x16__add:
1746
29.9k
  case OpCode::I8x16__add_sat_s:
1747
30.3k
  case OpCode::I8x16__add_sat_u:
1748
31.0k
  case OpCode::I8x16__sub:
1749
31.9k
  case OpCode::I8x16__sub_sat_s:
1750
32.1k
  case OpCode::I8x16__sub_sat_u:
1751
32.3k
  case OpCode::I8x16__min_s:
1752
33.6k
  case OpCode::I8x16__min_u:
1753
34.5k
  case OpCode::I8x16__max_s:
1754
35.0k
  case OpCode::I8x16__max_u:
1755
35.5k
  case OpCode::I8x16__avgr_u:
1756
35.9k
  case OpCode::I16x8__narrow_i32x4_s:
1757
36.6k
  case OpCode::I16x8__narrow_i32x4_u:
1758
37.3k
  case OpCode::I16x8__add:
1759
37.4k
  case OpCode::I16x8__add_sat_s:
1760
38.3k
  case OpCode::I16x8__add_sat_u:
1761
39.0k
  case OpCode::I16x8__sub:
1762
39.6k
  case OpCode::I16x8__sub_sat_s:
1763
39.7k
  case OpCode::I16x8__sub_sat_u:
1764
40.1k
  case OpCode::I16x8__mul:
1765
40.5k
  case OpCode::I16x8__min_s:
1766
40.9k
  case OpCode::I16x8__min_u:
1767
41.4k
  case OpCode::I16x8__max_s:
1768
42.4k
  case OpCode::I16x8__max_u:
1769
42.6k
  case OpCode::I16x8__avgr_u:
1770
42.9k
  case OpCode::I16x8__extmul_low_i8x16_s:
1771
43.4k
  case OpCode::I16x8__extmul_high_i8x16_s:
1772
43.6k
  case OpCode::I16x8__extmul_low_i8x16_u:
1773
44.7k
  case OpCode::I16x8__extmul_high_i8x16_u:
1774
45.0k
  case OpCode::I16x8__q15mulr_sat_s:
1775
45.2k
  case OpCode::I32x4__add:
1776
45.5k
  case OpCode::I32x4__sub:
1777
46.0k
  case OpCode::I32x4__mul:
1778
46.4k
  case OpCode::I32x4__min_s:
1779
46.7k
  case OpCode::I32x4__min_u:
1780
46.9k
  case OpCode::I32x4__max_s:
1781
47.2k
  case OpCode::I32x4__max_u:
1782
47.5k
  case OpCode::I32x4__extmul_low_i16x8_s:
1783
47.7k
  case OpCode::I32x4__extmul_high_i16x8_s:
1784
48.1k
  case OpCode::I32x4__extmul_low_i16x8_u:
1785
48.4k
  case OpCode::I32x4__extmul_high_i16x8_u:
1786
48.9k
  case OpCode::I64x2__add:
1787
49.3k
  case OpCode::I64x2__sub:
1788
49.8k
  case OpCode::I64x2__mul:
1789
49.9k
  case OpCode::I64x2__extmul_low_i32x4_s:
1790
50.5k
  case OpCode::I64x2__extmul_high_i32x4_s:
1791
50.9k
  case OpCode::I64x2__extmul_low_i32x4_u:
1792
51.6k
  case OpCode::I64x2__extmul_high_i32x4_u:
1793
53.3k
  case OpCode::F32x4__add:
1794
54.1k
  case OpCode::F32x4__sub:
1795
54.8k
  case OpCode::F32x4__mul:
1796
55.2k
  case OpCode::F32x4__div:
1797
55.6k
  case OpCode::F32x4__min:
1798
56.1k
  case OpCode::F32x4__max:
1799
57.7k
  case OpCode::F32x4__pmin:
1800
58.0k
  case OpCode::F32x4__pmax:
1801
58.2k
  case OpCode::F64x2__add:
1802
58.9k
  case OpCode::F64x2__sub:
1803
59.2k
  case OpCode::F64x2__mul:
1804
59.4k
  case OpCode::F64x2__div:
1805
59.6k
  case OpCode::F64x2__min:
1806
59.9k
  case OpCode::F64x2__max:
1807
60.5k
  case OpCode::F64x2__pmin:
1808
61.0k
  case OpCode::F64x2__pmax:
1809
61.3k
  case OpCode::I32x4__dot_i16x8_s:
1810
61.3k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)},
1811
61.3k
                      {ValType(TypeCode::V128)});
1812
223
  case OpCode::V128__bitselect:
1813
223
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128),
1814
223
                       ValType(TypeCode::V128)},
1815
223
                      {ValType(TypeCode::V128)});
1816
193
  case OpCode::V128__any_true:
1817
686
  case OpCode::I8x16__all_true:
1818
1.69k
  case OpCode::I8x16__bitmask:
1819
2.15k
  case OpCode::I16x8__all_true:
1820
2.55k
  case OpCode::I16x8__bitmask:
1821
3.21k
  case OpCode::I32x4__all_true:
1822
4.58k
  case OpCode::I32x4__bitmask:
1823
5.44k
  case OpCode::I64x2__all_true:
1824
5.82k
  case OpCode::I64x2__bitmask:
1825
5.82k
    return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::I32)});
1826
325
  case OpCode::I8x16__shl:
1827
2.07k
  case OpCode::I8x16__shr_s:
1828
3.05k
  case OpCode::I8x16__shr_u:
1829
3.18k
  case OpCode::I16x8__shl:
1830
3.73k
  case OpCode::I16x8__shr_s:
1831
3.83k
  case OpCode::I16x8__shr_u:
1832
5.40k
  case OpCode::I32x4__shl:
1833
5.75k
  case OpCode::I32x4__shr_s:
1834
5.95k
  case OpCode::I32x4__shr_u:
1835
6.19k
  case OpCode::I64x2__shl:
1836
7.16k
  case OpCode::I64x2__shr_s:
1837
7.31k
  case OpCode::I64x2__shr_u:
1838
7.31k
    return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::I32)},
1839
7.31k
                      {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
283
  case OpCode::Atomic__fence:
1874
283
    return {};
1875
1876
63
  case OpCode::Memory__atomic__notify:
1877
63
    return checkAlignAndTrans(
1878
63
        32, std::array{ValType(TypeCode::I32), ValType(TypeCode::I32)},
1879
63
        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
7
  case OpCode::Memory__atomic__wait64:
1887
7
    return checkAlignAndTrans(64,
1888
7
                              std::array{ValType(TypeCode::I32),
1889
7
                                         ValType(TypeCode::I64),
1890
7
                                         ValType(TypeCode::I64)},
1891
7
                              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.83M
  }
2149
1.83M
}
2150
2151
1.47M
void FormChecker::pushType(VType V) { ValStack.emplace_back(V); }
2152
2153
37.7k
void FormChecker::pushTypes(Span<const VType> Input) {
2154
37.7k
  for (auto Val : Input) {
2155
4.41k
    pushType(Val);
2156
4.41k
  }
2157
37.7k
}
2158
2159
1.51M
void FormChecker::pushTypes(Span<const ValType> Input) {
2160
1.51M
  for (auto Val : Input) {
2161
1.46M
    pushType(Val);
2162
1.46M
  }
2163
1.51M
}
2164
2165
1.59M
Expect<VType> FormChecker::popType() {
2166
1.59M
  if (ValStack.size() == CtrlStack.back().Height) {
2167
174k
    if (CtrlStack.back().IsUnreachable) {
2168
173k
      return unreachableVType();
2169
173k
    }
2170
    // Value stack underflow
2171
318
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2172
318
    spdlog::error("    Value stack underflow."sv);
2173
318
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2174
174k
  }
2175
1.42M
  auto T = std::move(ValStack.back());
2176
1.42M
  ValStack.pop_back();
2177
1.42M
  return T;
2178
1.59M
}
2179
2180
793k
Expect<VType> FormChecker::popType(ValType E) {
2181
793k
  EXPECTED_TRY(auto Type, popType());
2182
793k
  if (Type == unreachableVType()) {
2183
169k
    return E;
2184
169k
  }
2185
2186
624k
  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
623k
  return Type;
2193
624k
}
2194
2195
1.50M
Expect<void> FormChecker::popTypes(Span<const ValType> Input) {
2196
2.28M
  for (auto Val = Input.rbegin(); Val != Input.rend(); ++Val) {
2197
777k
    EXPECTED_TRY(popType(*Val));
2198
777k
  }
2199
1.50M
  return {};
2200
1.50M
}
2201
2202
void FormChecker::pushCtrl(Span<const ValType> In, Span<const ValType> Out,
2203
28.6k
                           const AST::Instruction *Jump, OpCode Code) {
2204
28.6k
  CtrlStack.emplace_back(In, Out, Jump, ValStack.size(), LocalInits.size(),
2205
28.6k
                         Code);
2206
28.6k
  pushTypes(In);
2207
28.6k
}
2208
2209
27.1k
Expect<FormChecker::CtrlFrame> FormChecker::popCtrl() {
2210
27.1k
  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
27.1k
  EXPECTED_TRY(popTypes(CtrlStack.back().EndTypes));
2217
27.0k
  if (ValStack.size() != CtrlStack.back().Height) {
2218
    // Value stack size not matched.
2219
105
    spdlog::error(ErrCode::Value::TypeCheckFailed);
2220
105
    spdlog::error("    Value stack underflow."sv);
2221
105
    return Unexpect(ErrCode::Value::TypeCheckFailed);
2222
105
  }
2223
  // When popping a frame, reset the inited locals during this frame.
2224
26.9k
  for (size_t I = CtrlStack.back().InitedLocal; I < LocalInits.size(); I++) {
2225
0
    Locals[LocalInits[I]].IsInit = false;
2226
0
  }
2227
26.9k
  LocalInits.erase(LocalInits.begin() +
2228
26.9k
                       static_cast<uint32_t>(CtrlStack.back().InitedLocal),
2229
26.9k
                   LocalInits.end());
2230
26.9k
  auto Head = std::move(CtrlStack.back());
2231
26.9k
  CtrlStack.pop_back();
2232
26.9k
  return Head;
2233
27.0k
}
2234
2235
Span<const ValType>
2236
44.7k
FormChecker::getLabelTypes(const FormChecker::CtrlFrame &F) {
2237
44.7k
  if (F.Code == OpCode::Loop) {
2238
4.52k
    return F.StartTypes;
2239
4.52k
  }
2240
40.2k
  return F.EndTypes;
2241
44.7k
}
2242
2243
219k
Expect<void> FormChecker::unreachable() {
2244
1.00M
  while (ValStack.size() > CtrlStack.back().Height) {
2245
782k
    EXPECTED_TRY(popType());
2246
782k
  }
2247
219k
  CtrlStack.back().IsUnreachable = true;
2248
219k
  return {};
2249
219k
}
2250
2251
Expect<void> FormChecker::StackTrans(Span<const ValType> Take,
2252
1.46M
                                     Span<const ValType> Put) {
2253
1.46M
  EXPECTED_TRY(popTypes(Take));
2254
1.46M
  pushTypes(Put);
2255
1.46M
  return {};
2256
1.46M
}
2257
2258
7.19k
Expect<void> FormChecker::StackPopAny() {
2259
7.19k
  EXPECTED_TRY(popType());
2260
7.18k
  return {};
2261
7.19k
}
2262
2263
} // namespace Validator
2264
} // namespace WasmEdge