Coverage Report

Created: 2026-06-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/executor/helper.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "executor/executor.h"
5
6
#include "common/spdlog.h"
7
#include "system/fault.h"
8
#include "system/stacktrace.h"
9
10
#include <cstdint>
11
#include <utility>
12
#include <vector>
13
14
namespace WasmEdge {
15
namespace Executor {
16
17
Executor::SavedThreadLocal::SavedThreadLocal(
18
    Executor &Ex, Runtime::StackManager &StackMgr,
19
0
    const Runtime::Instance::FunctionInstance &Func) noexcept {
20
  // Prepare the execution context.
21
0
  auto *ModInst =
22
0
      const_cast<Runtime::Instance::ModuleInstance *>(Func.getModule());
23
0
  SavedThis = This;
24
0
  This = &Ex;
25
26
0
  SavedExecutionContext = ExecutionContext;
27
0
  ExecutionContext.StopToken = &Ex.StopToken;
28
0
  ExecutionContext.Memories = ModInst->MemoryPtrs.data();
29
0
  ExecutionContext.Globals = ModInst->GlobalPtrs.data();
30
0
  if (Ex.Stat) {
31
0
    ExecutionContext.InstrCount = &Ex.Stat->getInstrCountRef();
32
0
    ExecutionContext.CostTable = Ex.Stat->getCostTable().data();
33
0
    ExecutionContext.Gas = &Ex.Stat->getTotalCostRef();
34
0
    ExecutionContext.GasLimit = Ex.Stat->getCostLimit();
35
0
  }
36
37
0
  SavedCurrentStack = CurrentStack;
38
0
  CurrentStack = &StackMgr;
39
0
}
40
41
0
Executor::SavedThreadLocal::~SavedThreadLocal() noexcept {
42
0
  CurrentStack = SavedCurrentStack;
43
0
  ExecutionContext = SavedExecutionContext;
44
0
  This = SavedThis;
45
0
}
46
47
Expect<AST::InstrView::iterator>
48
Executor::enterFunction(Runtime::StackManager &StackMgr,
49
                        const Runtime::Instance::FunctionInstance &Func,
50
0
                        const AST::InstrView::iterator RetIt, bool IsTailCall) {
51
  // RetIt: the return position when the entered function returns.
52
53
  // Check whether interruption occurred.
54
0
  if (unlikely(StopToken.exchange(0, std::memory_order_relaxed))) {
55
0
    spdlog::error(ErrCode::Value::Interrupted);
56
0
    return Unexpect(ErrCode::Value::Interrupted);
57
0
  }
58
59
  // Get the function type for the parameter and return counts.
60
0
  const auto &FuncType = Func.getFuncType();
61
0
  const uint32_t ArgsN = static_cast<uint32_t>(FuncType.getParamTypes().size());
62
0
  const uint32_t RetsN =
63
0
      static_cast<uint32_t>(FuncType.getReturnTypes().size());
64
65
  // For the exception handler, remove the inactive handlers caused by the
66
  // branches.
67
0
  const auto Instrs = Func.getInstrs();
68
0
  if (likely(RetIt) && RetIt != Instrs.begin()) {
69
0
    StackMgr.removeInactiveHandler(RetIt - 1);
70
0
  }
71
72
0
  if (Func.isHostFunction()) {
73
    // Host function case: Push args and call function.
74
0
    auto &HostFunc = Func.getHostFunc();
75
76
    // Finalize the host module on its first host-function invocation, after
77
    // which adding host instances to it is rejected.
78
0
    if (const auto *HostModInst = Func.getModule()) {
79
0
      HostModInst->finalizeInstantiation();
80
0
    }
81
82
    // Generate CallingFrame from current frame.
83
    // The module instance will be nullptr if current frame is a dummy frame.
84
    // For this case, use the module instance of this host function.
85
0
    const auto *ModInst = StackMgr.getModule();
86
0
    if (ModInst == nullptr) {
87
0
      ModInst = Func.getModule();
88
0
    }
89
0
    Runtime::CallingFrame CallFrame(this, ModInst);
90
91
    // Push frame.
92
0
    StackMgr.pushFrame(Func.getModule(), // Module instance
93
0
                       RetIt,            // Return PC
94
0
                       ArgsN,            // Only args, no locals in stack
95
0
                       RetsN,            // Returns num
96
0
                       IsTailCall        // For tail-call
97
0
    );
98
99
    // Do the statistics if the statistics turned on.
100
0
    if (Stat) {
101
      // Check host function cost.
102
0
      if (unlikely(!Stat->addCost(HostFunc.getCost()))) {
103
0
        spdlog::error(ErrCode::Value::CostLimitExceeded);
104
0
        return Unexpect(ErrCode::Value::CostLimitExceeded);
105
0
      }
106
      // Start recording time of running host function.
107
0
      Stat->stopRecordWasm();
108
0
      Stat->startRecordHost();
109
0
    }
110
111
    // Call pre-host-function
112
0
    HostFuncHelper.invokePreHostFunc();
113
114
    // Run host function.
115
0
    Span<ValVariant> Args = StackMgr.getTopSpan(ArgsN);
116
0
    for (uint32_t I = 0; I < ArgsN; I++) {
117
      // For the number type cases of the arguments, the unused bits should be
118
      // erased due to the security issue.
119
0
      cleanNumericVal(Args[I], FuncType.getParamTypes()[I]);
120
0
    }
121
0
    std::vector<ValVariant> Rets(RetsN);
122
0
    auto Ret = HostFunc.run(CallFrame, std::move(Args), Rets);
123
124
    // Call post-host-function
125
0
    HostFuncHelper.invokePostHostFunc();
126
127
    // Do the statistics if the statistics turned on.
128
0
    if (Stat) {
129
      // Stop recording time of running host function.
130
0
      Stat->stopRecordHost();
131
0
      Stat->startRecordWasm();
132
0
    }
133
134
    // Check the host function execution status.
135
0
    if (!Ret) {
136
0
      if (Ret.error() == ErrCode::Value::HostFuncError ||
137
0
          Ret.error().getCategory() != ErrCategory::WASM) {
138
0
        spdlog::error(Ret.error());
139
0
      }
140
0
      return Unexpect(Ret);
141
0
    }
142
143
    // Push returns back to the stack.
144
0
    for (auto &R : Rets) {
145
0
      StackMgr.push(std::move(R));
146
0
    }
147
148
    // For host function case, the continuation will be the continuation from
149
    // the popped frame.
150
0
    return StackMgr.popFrame();
151
0
  } else if (Func.isCompiledFunction()) {
152
    // Compiled function case: Execute the function and jump to the
153
    // continuation.
154
155
    // Push frame.
156
0
    StackMgr.pushFrame(Func.getModule(), // Module instance
157
0
                       RetIt,            // Return PC
158
0
                       ArgsN,            // Only args, no locals in stack
159
0
                       RetsN,            // Returns num
160
0
                       IsTailCall        // For tail-call
161
0
    );
162
163
    // Prepare arguments.
164
0
    Span<ValVariant> Args = StackMgr.getTopSpan(ArgsN);
165
0
    std::vector<ValVariant> Rets(RetsN);
166
0
    SavedThreadLocal Saved(*this, StackMgr, Func);
167
168
0
    ErrCode Err;
169
0
    try {
170
      // Get symbol and execute the function.
171
0
      Fault FaultHandler;
172
0
      uint32_t Code = PREPARE_FAULT(FaultHandler);
173
0
      if (Code != 0) {
174
0
        auto InnerStackTrace = FaultHandler.stacktrace();
175
0
        {
176
0
          std::array<void *, 256> Buffer;
177
0
          auto OuterStackTrace = stackTrace(Buffer);
178
0
          while (!OuterStackTrace.empty() && !InnerStackTrace.empty() &&
179
0
                 InnerStackTrace[InnerStackTrace.size() - 1] ==
180
0
                     OuterStackTrace[OuterStackTrace.size() - 1]) {
181
0
            InnerStackTrace = InnerStackTrace.first(InnerStackTrace.size() - 1);
182
0
            OuterStackTrace = OuterStackTrace.first(OuterStackTrace.size() - 1);
183
0
          }
184
0
        }
185
0
        StackTraceSize =
186
0
            compiledStackTrace(StackMgr, InnerStackTrace, StackTrace).size();
187
0
        Err = ErrCode(static_cast<ErrCategory>(Code >> 24), Code);
188
0
      } else {
189
0
        auto &Wrapper = FuncType.getSymbol();
190
0
        Wrapper(&ExecutionContext, Func.getSymbol().get(), Args.data(),
191
0
                Rets.data());
192
0
      }
193
0
    } catch (const ErrCode &E) {
194
0
      Err = E;
195
0
    }
196
0
    if (unlikely(Err)) {
197
0
      if (Err != ErrCode::Value::Terminated) {
198
0
        spdlog::error(Err);
199
0
      }
200
0
      StackTraceSize +=
201
0
          interpreterStackTrace(
202
0
              StackMgr, Span<uint32_t>{StackTrace}.subspan(StackTraceSize))
203
0
              .size();
204
0
      return Unexpect(Err);
205
0
    }
206
207
    // Push returns back to the stack.
208
0
    for (uint32_t I = 0; I < Rets.size(); ++I) {
209
0
      StackMgr.push(Rets[I]);
210
0
    }
211
212
    // For compiled function case, the continuation will be the continuation
213
    // from the popped frame.
214
0
    return StackMgr.popFrame();
215
0
  } else {
216
    // Native function case: Jump to the start of the function body.
217
218
    // Push local variables into the stack.
219
0
    for (auto &Def : Func.getLocals()) {
220
0
      if (Def.second.isRefType() && !Def.second.isAbsHeapType()) {
221
        // For non-abstract heap types (concrete type indices), convert the
222
        // null ref to the abstract heap type so that ref.cast/ref.test won't
223
        // dereference a null pointer when checking the type.
224
0
        const auto &CompType = Func.getModule()
225
0
                                   ->unsafeGetType(Def.second.getTypeIndex())
226
0
                                   ->getCompositeType();
227
0
        auto BotTypeCode =
228
0
            CompType.isFunc() ? TypeCode::NullFuncRef : TypeCode::NullRef;
229
0
        RefVariant InitVal(ValType(TypeCode::RefNull, BotTypeCode));
230
0
        for (uint32_t I = 0; I < Def.first; I++) {
231
0
          StackMgr.push(InitVal);
232
0
        }
233
0
      } else {
234
0
        for (uint32_t I = 0; I < Def.first; I++) {
235
0
          StackMgr.push(ValueFromType(Def.second));
236
0
        }
237
0
      }
238
0
    }
239
240
    // Push frame.
241
    // The PC must -1 here because in the interpreter mode execution, the PC
242
    // will increase after the callee returns.
243
0
    StackMgr.pushFrame(Func.getModule(),           // Module instance
244
0
                       RetIt - 1,                  // Return PC
245
0
                       ArgsN + Func.getLocalNum(), // Arguments num + local num
246
0
                       RetsN,                      // Returns num
247
0
                       IsTailCall                  // For tail-call
248
0
    );
249
250
    // For native function case, the continuation will be the start of the
251
    // function body.
252
0
    return Instrs.begin();
253
0
  }
254
0
}
255
256
Expect<void>
257
Executor::branchToLabel(Runtime::StackManager &StackMgr,
258
                        const AST::Instruction::JumpDescriptor &JumpDesc,
259
0
                        AST::InstrView::iterator &PC) noexcept {
260
  // Check the stop token.
261
0
  if (unlikely(StopToken.exchange(0, std::memory_order_relaxed))) {
262
0
    spdlog::error(ErrCode::Value::Interrupted);
263
0
    return Unexpect(ErrCode::Value::Interrupted);
264
0
  }
265
266
0
  StackMgr.eraseValueStack(JumpDesc.StackEraseBegin, JumpDesc.StackEraseEnd);
267
  // PC needs -1 here because the PC will increase in the next iteration.
268
0
  PC += (JumpDesc.PCOffset - 1);
269
0
  return {};
270
0
}
271
272
Expect<void> Executor::throwException(
273
    Runtime::StackManager &StackMgr, Runtime::Instance::TagInstance &TagInst,
274
    AST::InstrView::iterator &PC,
275
0
    const Runtime::Instance::ExceptionInstance *ExnInst) noexcept {
276
0
  StackMgr.removeInactiveHandler(PC);
277
0
  auto AssocValSize = TagInst.getTagType().getAssocValSize();
278
0
  while (true) {
279
    // Pop the top handler.
280
0
    auto Handler = StackMgr.popTopHandler(AssocValSize);
281
0
    if (!Handler.has_value()) {
282
0
      break;
283
0
    }
284
    // Checking through the catch clause.
285
0
    for (const auto &C : Handler->CatchClause) {
286
0
      if (!C.IsAll && getTagInstByIdx(StackMgr, C.TagIndex) != &TagInst) {
287
        // Specific-tag clauses require tag-address equivalence; skip the
288
        // ones that do not match.
289
0
        continue;
290
0
      }
291
0
      if (C.IsRef) {
292
        // Allocate the exception instance lazily on the first catch_ref;
293
        // reuse the one passed in by throw_ref to preserve exnref identity.
294
0
        const Runtime::Instance::ExceptionInstance *Inst = ExnInst;
295
0
        if (Inst == nullptr) {
296
0
          auto Payload = StackMgr.getTopSpan(AssocValSize);
297
0
          std::vector<ValVariant> Vec(Payload.begin(), Payload.end());
298
0
          auto *ModInst = const_cast<Runtime::Instance::ModuleInstance *>(
299
0
              StackMgr.getModule());
300
0
          Inst = ModInst->newException(&TagInst, std::move(Vec));
301
0
        }
302
0
        StackMgr.push(
303
0
            RefVariant(ValType(TypeCode::Ref, TypeCode::ExnRef), Inst));
304
0
      }
305
      // When an exception is caught, move the PC to the try block and branch to
306
      // the label.
307
308
0
      PC = Handler->Try;
309
0
      return branchToLabel(StackMgr, C.Jump, PC);
310
0
    }
311
0
  }
312
0
  spdlog::error(ErrCode::Value::UncaughtException);
313
0
  return Unexpect(ErrCode::Value::UncaughtException);
314
0
}
315
316
Expect<void>
317
Executor::checkOffsetOverflow(const Runtime::Instance::MemoryInstance &MemInst,
318
                              const AST::Instruction &Instr, const uint64_t Val,
319
0
                              const uint64_t Size) const noexcept {
320
  // This function simply checks that the calculated offset fits in 64 bits.
321
0
  uint64_t StartOffset;
322
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
323
  if (std::numeric_limits<uint64_t>::max() - Instr.getMemoryOffset() < Val) {
324
    StartOffset = Instr.getMemoryOffset() + Val;
325
#else
326
0
  if (unlikely(
327
0
          __builtin_add_overflow(Instr.getMemoryOffset(), Val, &StartOffset))) {
328
0
#endif
329
0
    spdlog::error(ErrCode::Value::MemoryOutOfBounds);
330
0
    spdlog::error(
331
0
        ErrInfo::InfoBoundary(StartOffset, Size, MemInst.getSize(), true));
332
0
    spdlog::error(
333
0
        ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
334
0
    return Unexpect(ErrCode::Value::MemoryOutOfBounds);
335
0
  }
336
0
  return {};
337
0
}
338
339
const AST::SubType *Executor::getDefTypeByIdx(Runtime::StackManager &StackMgr,
340
0
                                              const uint32_t Idx) const {
341
0
  const auto *ModInst = StackMgr.getModule();
342
  // When the top frame is a dummy frame, the instance cannot be found.
343
0
  if (unlikely(ModInst == nullptr)) {
344
0
    return nullptr;
345
0
  }
346
0
  return ModInst->unsafeGetType(Idx);
347
0
}
348
349
const WasmEdge::AST::CompositeType &
350
Executor::getCompositeTypeByIdx(Runtime::StackManager &StackMgr,
351
0
                                const uint32_t Idx) const noexcept {
352
0
  auto *DefType = getDefTypeByIdx(StackMgr, Idx);
353
0
  assuming(DefType);
354
0
  const auto &CompType = DefType->getCompositeType();
355
0
  assuming(!CompType.isFunc());
356
0
  return CompType;
357
0
}
358
359
const ValType &
360
Executor::getStructStorageTypeByIdx(Runtime::StackManager &StackMgr,
361
                                    const uint32_t Idx,
362
0
                                    const uint32_t Off) const noexcept {
363
0
  const auto &CompType = getCompositeTypeByIdx(StackMgr, Idx);
364
0
  assuming(static_cast<uint32_t>(CompType.getFieldTypes().size()) > Off);
365
0
  return CompType.getFieldTypes()[Off].getStorageType();
366
0
}
367
368
const ValType &
369
Executor::getArrayStorageTypeByIdx(Runtime::StackManager &StackMgr,
370
0
                                   const uint32_t Idx) const noexcept {
371
0
  const auto &CompType = getCompositeTypeByIdx(StackMgr, Idx);
372
0
  assuming(static_cast<uint32_t>(CompType.getFieldTypes().size()) == 1);
373
0
  return CompType.getFieldTypes()[0].getStorageType();
374
0
}
375
376
Runtime::Instance::FunctionInstance *
377
Executor::getFuncInstByIdx(Runtime::StackManager &StackMgr,
378
0
                           const uint32_t Idx) const {
379
0
  const auto *ModInst = StackMgr.getModule();
380
  // When the top frame is a dummy frame, the instance cannot be found.
381
0
  if (unlikely(ModInst == nullptr)) {
382
0
    return nullptr;
383
0
  }
384
0
  return ModInst->unsafeGetFunction(Idx);
385
0
}
386
387
Runtime::Instance::TableInstance *
388
Executor::getTabInstByIdx(Runtime::StackManager &StackMgr,
389
0
                          const uint32_t Idx) const {
390
0
  const auto *ModInst = StackMgr.getModule();
391
  // When the top frame is a dummy frame, the instance cannot be found.
392
0
  if (unlikely(ModInst == nullptr)) {
393
0
    return nullptr;
394
0
  }
395
0
  return ModInst->unsafeGetTable(Idx);
396
0
}
397
398
Runtime::Instance::MemoryInstance *
399
Executor::getMemInstByIdx(Runtime::StackManager &StackMgr,
400
0
                          const uint32_t Idx) const {
401
0
  const auto *ModInst = StackMgr.getModule();
402
  // When the top frame is a dummy frame, the instance cannot be found.
403
0
  if (unlikely(ModInst == nullptr)) {
404
0
    return nullptr;
405
0
  }
406
0
  return ModInst->unsafeGetMemory(Idx);
407
0
}
408
409
Runtime::Instance::TagInstance *
410
Executor::getTagInstByIdx(Runtime::StackManager &StackMgr,
411
0
                          const uint32_t Idx) const {
412
0
  const auto *ModInst = StackMgr.getModule();
413
  // When the top frame is a dummy frame, the instance cannot be found.
414
0
  if (unlikely(ModInst == nullptr)) {
415
0
    return nullptr;
416
0
  }
417
0
  return ModInst->unsafeGetTag(Idx);
418
0
}
419
420
Runtime::Instance::GlobalInstance *
421
Executor::getGlobInstByIdx(Runtime::StackManager &StackMgr,
422
0
                           const uint32_t Idx) const {
423
0
  const auto *ModInst = StackMgr.getModule();
424
  // When the top frame is a dummy frame, the instance cannot be found.
425
0
  if (unlikely(ModInst == nullptr)) {
426
0
    return nullptr;
427
0
  }
428
0
  return ModInst->unsafeGetGlobal(Idx);
429
0
}
430
431
Runtime::Instance::ElementInstance *
432
Executor::getElemInstByIdx(Runtime::StackManager &StackMgr,
433
0
                           const uint32_t Idx) const {
434
0
  const auto *ModInst = StackMgr.getModule();
435
  // When the top frame is a dummy frame, the instance cannot be found.
436
0
  if (unlikely(ModInst == nullptr)) {
437
0
    return nullptr;
438
0
  }
439
0
  return ModInst->unsafeGetElem(Idx);
440
0
}
441
442
Runtime::Instance::DataInstance *
443
Executor::getDataInstByIdx(Runtime::StackManager &StackMgr,
444
0
                           const uint32_t Idx) const {
445
0
  const auto *ModInst = StackMgr.getModule();
446
  // When the top frame is a dummy frame, the instance cannot be found.
447
0
  if (unlikely(ModInst == nullptr)) {
448
0
    return nullptr;
449
0
  }
450
0
  return ModInst->unsafeGetData(Idx);
451
0
}
452
453
TypeCode Executor::toBottomType(Runtime::StackManager &StackMgr,
454
0
                                const ValType &Type) const {
455
0
  if (Type.isRefType()) {
456
0
    if (Type.isAbsHeapType()) {
457
0
      switch (Type.getHeapTypeCode()) {
458
0
      case TypeCode::NullFuncRef:
459
0
      case TypeCode::FuncRef:
460
0
        return TypeCode::NullFuncRef;
461
0
      case TypeCode::NullExternRef:
462
0
      case TypeCode::ExternRef:
463
0
        return TypeCode::NullExternRef;
464
0
      case TypeCode::NullRef:
465
0
      case TypeCode::AnyRef:
466
0
      case TypeCode::EqRef:
467
0
      case TypeCode::I31Ref:
468
0
      case TypeCode::StructRef:
469
0
      case TypeCode::ArrayRef:
470
0
        return TypeCode::NullRef;
471
0
      case TypeCode::NullExnRef:
472
0
      case TypeCode::ExnRef:
473
0
        return TypeCode::NullExnRef;
474
0
      default:
475
0
        assumingUnreachable();
476
0
      }
477
0
    } else {
478
0
      const auto &CompType = StackMgr.getModule()
479
0
                                 ->unsafeGetType(Type.getTypeIndex())
480
0
                                 ->getCompositeType();
481
0
      if (CompType.isFunc()) {
482
0
        return TypeCode::NullFuncRef;
483
0
      } else {
484
0
        return TypeCode::NullRef;
485
0
      }
486
0
    }
487
0
  } else {
488
0
    return Type.getCode();
489
0
  }
490
0
}
491
492
void Executor::cleanNumericVal(ValVariant &Val,
493
0
                               const ValType &Type) const noexcept {
494
0
  if (Type.isNumType()) {
495
0
    switch (Type.getCode()) {
496
0
    case TypeCode::I32: {
497
0
      uint32_t V = Val.get<uint32_t>();
498
0
      Val.emplace<uint128_t>(static_cast<uint128_t>(0U));
499
0
      Val.emplace<uint32_t>(V);
500
0
      break;
501
0
    }
502
0
    case TypeCode::F32: {
503
0
      float V = Val.get<float>();
504
0
      Val.emplace<uint128_t>(static_cast<uint128_t>(0U));
505
0
      Val.emplace<float>(V);
506
0
      break;
507
0
    }
508
0
    case TypeCode::I64: {
509
0
      uint64_t V = Val.get<uint64_t>();
510
0
      Val.emplace<uint128_t>(static_cast<uint128_t>(0U));
511
0
      Val.emplace<uint64_t>(V);
512
0
      break;
513
0
    }
514
0
    case TypeCode::F64: {
515
0
      double V = Val.get<double>();
516
0
      Val.emplace<uint128_t>(static_cast<uint128_t>(0U));
517
0
      Val.emplace<double>(V);
518
0
      break;
519
0
    }
520
0
    default:
521
0
      break;
522
0
    }
523
0
  }
524
0
}
525
526
ValVariant Executor::packVal(const ValType &Type,
527
0
                             const ValVariant &Val) const noexcept {
528
0
  if (Type.isPackType()) {
529
0
    switch (Type.getCode()) {
530
0
    case TypeCode::I8:
531
0
      if constexpr (Endian::native == Endian::little) {
532
0
        return ValVariant(Val.get<uint32_t>() & 0xFFU);
533
      } else {
534
        return ValVariant(Val.get<uint32_t>() << 24);
535
      }
536
0
    case TypeCode::I16:
537
0
      if constexpr (Endian::native == Endian::little) {
538
0
        return ValVariant(Val.get<uint32_t>() & 0xFFFFU);
539
      } else {
540
        return ValVariant(Val.get<uint32_t>() << 16);
541
      }
542
0
    default:
543
0
      assumingUnreachable();
544
0
    }
545
0
  }
546
0
  return Val;
547
0
}
548
549
std::vector<ValVariant>
550
Executor::packVals(const ValType &Type,
551
0
                   std::vector<ValVariant> &&Vals) const noexcept {
552
0
  for (uint32_t I = 0; I < Vals.size(); I++) {
553
0
    Vals[I] = packVal(Type, Vals[I]);
554
0
  }
555
0
  return std::move(Vals);
556
0
}
557
558
ValVariant Executor::unpackVal(const ValType &Type, const ValVariant &Val,
559
0
                               bool IsSigned) const noexcept {
560
0
  if (Type.isPackType()) {
561
0
    uint32_t Num = Val.get<uint32_t>();
562
0
    switch (Type.getCode()) {
563
0
    case TypeCode::I8:
564
      if constexpr (Endian::native == Endian::big) {
565
        Num >>= 24;
566
      }
567
0
      if (IsSigned) {
568
0
        return static_cast<uint32_t>(static_cast<int8_t>(Num));
569
0
      } else {
570
0
        return static_cast<uint32_t>(static_cast<uint8_t>(Num));
571
0
      }
572
0
    case TypeCode::I16:
573
      if constexpr (Endian::native == Endian::big) {
574
        Num >>= 16;
575
      }
576
0
      if (IsSigned) {
577
0
        return static_cast<uint32_t>(static_cast<int16_t>(Num));
578
0
      } else {
579
0
        return static_cast<uint32_t>(static_cast<uint16_t>(Num));
580
0
      }
581
0
    default:
582
0
      assumingUnreachable();
583
0
    }
584
0
  }
585
0
  return Val;
586
0
}
587
588
} // namespace Executor
589
} // namespace WasmEdge