Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/executor/executor.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- wasmedge/executor/executor.h - Executor class definition ----------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file contains the declaration of the Executor class, which instantiates
12
/// and runs Wasm modules.
13
///
14
//===----------------------------------------------------------------------===//
15
#pragma once
16
17
#include "ast/component/component.h"
18
#include "ast/module.h"
19
#include "common/async.h"
20
#include "common/configure.h"
21
#include "common/defines.h"
22
#include "common/errcode.h"
23
#include "common/statistics.h"
24
#include "common/types.h"
25
#include "runtime/callingframe.h"
26
#include "runtime/instance/component/component.h"
27
#include "runtime/instance/module.h"
28
#include "runtime/stackmgr.h"
29
#include "runtime/storemgr.h"
30
#include "system/stacktrace.h"
31
32
#include <atomic>
33
#include <csignal>
34
#include <cstddef>
35
#include <cstdint>
36
#include <functional>
37
#include <memory>
38
#include <mutex>
39
#include <optional>
40
#include <shared_mutex>
41
#include <string_view>
42
#include <type_traits>
43
#include <utility>
44
#include <vector>
45
46
namespace WasmEdge {
47
namespace Executor {
48
49
namespace {
50
51
// Template return type aliasing
52
/// Accept unsigned integer types. (uint32_t, uint64_t)
53
template <typename T>
54
using TypeU = typename std::enable_if_t<IsWasmUnsignV<T>, Expect<void>>;
55
/// Accept integer types. (uint32_t, int32_t, uint64_t, int64_t)
56
template <typename T>
57
using TypeI = typename std::enable_if_t<IsWasmIntV<T>, Expect<void>>;
58
/// Accept floating types. (float, double)
59
template <typename T>
60
using TypeF = typename std::enable_if_t<IsWasmFloatV<T>, Expect<void>>;
61
/// Accept all num types. (uint32_t, int32_t, uint64_t, int64_t, float, double)
62
template <typename T>
63
using TypeT = typename std::enable_if_t<IsWasmNumV<T>, Expect<void>>;
64
/// Accept Wasm built-in num types. (uint32_t, uint64_t, float, double)
65
template <typename T>
66
using TypeN = typename std::enable_if_t<IsWasmNativeNumV<T>, Expect<void>>;
67
68
/// Accept (unsigned integer types, unsigned integer types).
69
template <typename T1, typename T2>
70
using TypeUU = typename std::enable_if_t<IsWasmUnsignV<T1> && IsWasmUnsignV<T2>,
71
                                         Expect<void>>;
72
/// Accept (integer types, unsigned integer types).
73
template <typename T1, typename T2>
74
using TypeIU = typename std::enable_if_t<IsWasmIntV<T1> && IsWasmUnsignV<T2>,
75
                                         Expect<void>>;
76
/// Accept (floating types, floating types).
77
template <typename T1, typename T2>
78
using TypeFF = typename std::enable_if_t<IsWasmFloatV<T1> && IsWasmFloatV<T2>,
79
                                         Expect<void>>;
80
/// Accept (integer types, floating types).
81
template <typename T1, typename T2>
82
using TypeIF =
83
    typename std::enable_if_t<IsWasmIntV<T1> && IsWasmFloatV<T2>, Expect<void>>;
84
/// Accept (floating types, integer types).
85
template <typename T1, typename T2>
86
using TypeFI =
87
    typename std::enable_if_t<IsWasmFloatV<T1> && IsWasmIntV<T2>, Expect<void>>;
88
/// Accept (Wasm built-in num types, Wasm built-in num types).
89
template <typename T1, typename T2>
90
using TypeNN =
91
    typename std::enable_if_t<IsWasmNativeNumV<T1> && IsWasmNativeNumV<T2> &&
92
                                  sizeof(T1) == sizeof(T2),
93
                              Expect<void>>;
94
95
} // namespace
96
97
/// Helper class for handling the pre- and post-host functions.
98
class HostFuncHandler {
99
public:
100
0
  void setPreHost(void *HostData, std::function<void(void *)> HostFunc) {
101
0
    std::unique_lock Lock(Mutex);
102
0
    PreHostData = HostData;
103
0
    PreHostFunc = HostFunc;
104
0
  }
105
0
  void setPostHost(void *HostData, std::function<void(void *)> HostFunc) {
106
0
    std::unique_lock Lock(Mutex);
107
0
    PostHostData = HostData;
108
0
    PostHostFunc = HostFunc;
109
0
  }
110
0
  void invokePreHostFunc() {
111
0
    std::function<void(void *)> FuncSnapshot;
112
0
    void *DataSnapshot = nullptr;
113
0
    {
114
0
      std::shared_lock Lock(Mutex);
115
0
      FuncSnapshot = PreHostFunc;
116
0
      DataSnapshot = PreHostData;
117
0
    }
118
0
    if (FuncSnapshot.operator bool()) {
119
0
      FuncSnapshot(DataSnapshot);
120
0
    }
121
0
  }
122
0
  void invokePostHostFunc() {
123
0
    std::function<void(void *)> FuncSnapshot;
124
0
    void *DataSnapshot = nullptr;
125
0
    {
126
0
      std::shared_lock Lock(Mutex);
127
0
      FuncSnapshot = PostHostFunc;
128
0
      DataSnapshot = PostHostData;
129
0
    }
130
0
    if (FuncSnapshot.operator bool()) {
131
0
      FuncSnapshot(DataSnapshot);
132
0
    }
133
0
  }
134
135
private:
136
  void *PreHostData = nullptr;
137
  void *PostHostData = nullptr;
138
  std::function<void(void *)> PreHostFunc = {};
139
  std::function<void(void *)> PostHostFunc = {};
140
  mutable std::shared_mutex Mutex;
141
};
142
143
/// Executor flow control class.
144
class Executor {
145
public:
146
  Executor(const Configure &Conf, Statistics::Statistics *S = nullptr) noexcept
147
0
      : Conf(Conf) {
148
0
    if (Conf.getStatisticsConfigure().isInstructionCounting() ||
149
0
        Conf.getStatisticsConfigure().isCostMeasuring() ||
150
0
        Conf.getStatisticsConfigure().isTimeMeasuring()) {
151
0
      Stat = S;
152
0
    } else {
153
0
      Stat = nullptr;
154
0
    }
155
0
    if (Stat) {
156
0
      Stat->setCostLimit(Conf.getStatisticsConfigure().getCostLimit());
157
0
    }
158
0
  }
159
160
  /// Getter for configuration.
161
0
  const Configure &getConfigure() const { return Conf; }
162
163
  /// Instantiate a WASM Module as an anonymous module instance.
164
  Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>>
165
  instantiateModule(Runtime::StoreManager &StoreMgr, const AST::Module &Mod);
166
167
  /// Instantiate and register a WASM module as a named module instance.
168
  Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>>
169
  registerModule(Runtime::StoreManager &StoreMgr, const AST::Module &Mod,
170
                 std::string_view Name);
171
172
  /// Register an instantiated module as a named module instance.
173
  Expect<void> registerModule(Runtime::StoreManager &StoreMgr,
174
                              const Runtime::Instance::ModuleInstance &ModInst);
175
176
  /// Register an instantiated module under the given alias name.
177
  Expect<void> registerModule(Runtime::StoreManager &StoreMgr,
178
                              const Runtime::Instance::ModuleInstance &ModInst,
179
                              std::string_view Name);
180
181
  /// Instantiate a Component as an anonymous component instance.
182
  Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>>
183
  instantiateComponent(Runtime::StoreManager &StoreMgr,
184
                       const AST::Component::Component &Comp);
185
186
  /// Instantiate and register a Component as a named component instance.
187
  Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>>
188
  registerComponent(Runtime::StoreManager &StoreMgr,
189
                    const AST::Component::Component &Comp,
190
                    std::string_view Name);
191
192
  /// Register an instantiated component into a named component instance.
193
  Expect<void>
194
  registerComponent(Runtime::StoreManager &StoreMgr,
195
                    const Runtime::Instance::ComponentInstance &CompInst);
196
197
  /// Register a host function which will be invoked before calling a
198
  /// host function.
199
  Expect<void> registerPreHostFunction(void *HostData,
200
                                       std::function<void(void *)> HostFunc);
201
202
  /// Register a host function which will be invoked after calling a
203
  /// host function.
204
  Expect<void> registerPostHostFunction(void *HostData,
205
                                        std::function<void(void *)> HostFunc);
206
207
  /// Register a callback for lazy function compilation
208
  void registerLazyCompilationCallback(
209
      std::function<Expect<void>(const Runtime::Instance::FunctionInstance *)>
210
0
          Callback) {
211
0
    LazyCompilationHandler = std::move(Callback);
212
0
  }
213
214
  /// Invoke a WASM function by function instance.
215
  Expect<std::vector<std::pair<ValVariant, ValType>>>
216
  invoke(const Runtime::Instance::FunctionInstance *FuncInst,
217
         Span<const ValVariant> Params, Span<const ValType> ParamTypes);
218
219
  /// Invoke a Component function by function instance.
220
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
221
  invoke(const Runtime::Instance::Component::FunctionInstance *FuncInst,
222
         Span<const ComponentValVariant> Params,
223
         Span<const ComponentValType> ParamTypes);
224
225
  /// Module-qualified stack trace of the most recent failed invocation on this
226
  /// thread. Valid right after an invocation returns an error, else stale.
227
0
  static Span<const StackTraceEntry> getRecordedStackTrace() noexcept {
228
0
    return Span<const StackTraceEntry>{StackTrace}.first(StackTraceSize);
229
0
  }
230
231
  /// Asynchronous invoke a WASM function by function instance.
232
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
233
  asyncInvoke(const Runtime::Instance::FunctionInstance *FuncInst,
234
              Span<const ValVariant> Params, Span<const ValType> ParamTypes);
235
236
  /// Stop execution
237
0
  void stop() noexcept {
238
0
    StopToken.store(1, std::memory_order_relaxed);
239
0
    atomicNotifyAll();
240
0
  }
241
242
private:
243
  /// Run Wasm bytecode expression for initialization.
244
  Expect<void> runExpression(Runtime::StackManager &StackMgr,
245
                             AST::InstrView Instrs);
246
247
  /// Run Wasm function.
248
  Expect<void> runFunction(Runtime::StackManager &StackMgr,
249
                           const Runtime::Instance::FunctionInstance &Func,
250
                           Span<const ValVariant> Params);
251
252
  /// Execute instructions.
253
  Expect<void> execute(Runtime::StackManager &StackMgr,
254
                       const AST::InstrView::iterator Start,
255
                       const AST::InstrView::iterator End);
256
257
  /// \name Functions for instantiation.
258
  /// @{
259
  /// Instantiation of Module Instance.
260
  Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>>
261
  instantiate(Runtime::StoreManager &StoreMgr, const AST::Module &Mod,
262
              std::optional<std::string_view> Name = std::nullopt);
263
264
  /// Instantiation of Imports.
265
  Expect<void> instantiate(
266
      std::function<const Runtime::Instance::ModuleInstance *(std::string_view)>
267
          ModuleFinder,
268
      Runtime::Instance::ModuleInstance &ModInst,
269
      const AST::ImportSection &ImportSec);
270
271
  /// Instantiation of Function Instances.
272
  Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst,
273
                           const AST::FunctionSection &FuncSec,
274
                           const AST::CodeSection &CodeSec);
275
276
  /// Instantiation of Table Instances.
277
  Expect<void> instantiate(Runtime::StackManager &StackMgr,
278
                           Runtime::Instance::ModuleInstance &ModInst,
279
                           const AST::TableSection &TabSec);
280
281
  /// Instantiation of Memory Instances.
282
  Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst,
283
                           const AST::MemorySection &MemSec);
284
285
  /// Instantiateion of Tag Instances.
286
  Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst,
287
                           const AST::TagSection &TagSec);
288
289
  /// Instantiation of Global Instances.
290
  Expect<void> instantiate(Runtime::StackManager &StackMgr,
291
                           Runtime::Instance::ModuleInstance &ModInst,
292
                           const AST::GlobalSection &GlobSec);
293
294
  /// Instantiation of Element Instances.
295
  Expect<void> instantiate(Runtime::StackManager &StackMgr,
296
                           Runtime::Instance::ModuleInstance &ModInst,
297
                           const AST::ElementSection &ElemSec);
298
299
  /// Initialize table with Element Instances.
300
  Expect<void> initTable(Runtime::StackManager &StackMgr,
301
                         const AST::ElementSection &ElemSec);
302
303
  /// Instantiation of Data Instances.
304
  Expect<void> instantiate(Runtime::StackManager &StackMgr,
305
                           Runtime::Instance::ModuleInstance &ModInst,
306
                           const AST::DataSection &DataSec);
307
308
  /// Initialize memory with Data Instances.
309
  Expect<void> initMemory(Runtime::StackManager &StackMgr,
310
                          const AST::DataSection &DataSec);
311
312
  /// Instantiation of Exports.
313
  Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst,
314
                           const AST::ExportSection &ExportSec);
315
  /// @}
316
317
  /// \name Functions for instantiation of component model.
318
  /// @{
319
  /// Instantiation of Component Instance.
320
  Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>>
321
  instantiate(Runtime::StoreManager &StoreMgr,
322
              const AST::Component::Component &Comp,
323
              std::optional<std::string_view> Name = std::nullopt);
324
325
  /// Instantiation of Child Component Instance.
326
  Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>>
327
  instantiate(Runtime::Instance::ComponentImportManager &ImportMgr,
328
              const AST::Component::Component &Comp);
329
330
  /// Instantiation of Child Core Module Instance.
331
  Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>>
332
  instantiate(Runtime::Instance::ComponentImportManager &ImportMgr,
333
              const AST::Module &Mod);
334
335
  /// Instantiation of Core Module Section.
336
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
337
                           const AST::Component::CoreModuleSection &CoreModSec);
338
339
  /// Instantiation of Core Instance Section.
340
  Expect<void>
341
  instantiate(Runtime::Instance::ComponentInstance &CompInst,
342
              const AST::Component::CoreInstanceSection &CoreInstSec);
343
344
  /// Instantiation of Core Type Section.
345
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
346
                           const AST::Component::CoreTypeSection &CoreTypeSec);
347
348
  /// Instantiation of Component Section.
349
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
350
                           const AST::Component::ComponentSection &CompSec);
351
352
  /// Instantiation of Instance Section.
353
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
354
                           const AST::Component::InstanceSection &InstSec);
355
356
  /// Instantiation of Alias Section.
357
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
358
                           const AST::Component::AliasSection &AliasSec);
359
360
  /// Instantiation of Type Section.
361
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
362
                           const AST::Component::TypeSection &TypeSec);
363
364
  /// Instantiation of Canonical Section.
365
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
366
                           const AST::Component::CanonSection &CanonSec);
367
368
  /// Instantiation of Start Section.
369
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
370
                           const AST::Component::StartSection &StartSec);
371
372
  /// Instantiation of Import Section.
373
  Expect<void> instantiate(Runtime::StoreManager &StoreMgr,
374
                           Runtime::Instance::ComponentInstance &CompInst,
375
                           const AST::Component::ImportSection &ImportSec);
376
377
  /// Instantiation of Import Section in the child component instance.
378
  Expect<void> instantiate(Runtime::Instance::ComponentImportManager &ImportMgr,
379
                           Runtime::Instance::ComponentInstance &CompInst,
380
                           const AST::Component::ImportSection &ImportSec);
381
382
  /// Instantiation of Export Section.
383
  Expect<void> instantiate(Runtime::Instance::ComponentInstance &CompInst,
384
                           const AST::Component::ExportSection &ExportSec);
385
  /// @}
386
387
  /// \name Helper Functions for canonical ABI
388
  /// @{
389
  Expect<std::vector<ValVariant>>
390
  convValsToCoreWASM(Span<const ComponentValVariant> Vals,
391
                     Span<const ComponentValType> ValTypes,
392
                     Runtime::Instance::FunctionInstance *RFuncInst,
393
                     Runtime::Instance::MemoryInstance *MemInst,
394
                     const Runtime::Instance::ComponentInstance *CompInst,
395
                     StringEncoding Enc = StringEncoding::UTF8);
396
397
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
398
  convValsToComponent(Span<const std::pair<ValVariant, ValType>> CoreVals,
399
                      Span<const ComponentValType> ValTypes,
400
                      Runtime::Instance::MemoryInstance *MemInst,
401
                      const Runtime::Instance::ComponentInstance *CompInst,
402
                      StringEncoding Enc = StringEncoding::UTF8);
403
  /// @}
404
405
  /// \name Helper Functions for block controls.
406
  /// @{
407
  /// Helper function for calling functions. Return the continuation iterator.
408
  /// Set `IsNativeEntry` when entering from the native code.
409
  Expect<AST::InstrView::iterator> enterFunction(
410
      Runtime::StackManager &StackMgr,
411
      const Runtime::Instance::FunctionInstance &Func,
412
      const AST::InstrView::iterator RetIt, bool IsTailCall = false,
413
      bool IsNativeEntry = false,
414
      const Runtime::Instance::ModuleInstance *CallerModInst = nullptr);
415
416
  /// Live module instances whose compiled code may be on the native stack at
417
  /// fault time: the current frame-stack modules plus every instance in a store
418
  /// reachable through their linked-module back-links. Rebuilt on each fault.
419
  std::vector<const Runtime::Instance::ModuleInstance *>
420
  collectLiveModules(const Runtime::StackManager &StackMgr) const noexcept;
421
422
  /// Helper function for branching to label.
423
  Expect<void> branchToLabel(Runtime::StackManager &StackMgr,
424
                             const AST::Instruction::JumpDescriptor &JumpDesc,
425
                             AST::InstrView::iterator &PC) noexcept;
426
427
  /// Helper function for throwing an exception. Pass `ExnInst` on `throw_ref`
428
  /// to reuse the exception instance and preserve exnref identity.
429
  Expect<void> throwException(
430
      Runtime::StackManager &StackMgr, Runtime::Instance::TagInstance &TagInst,
431
      AST::InstrView::iterator &PC,
432
      const Runtime::Instance::ExceptionInstance *ExnInst = nullptr) noexcept;
433
  /// @}
434
435
  /// \name Helper Function for checking memory offset boundary.
436
  /// @{
437
  Expect<void>
438
  checkOffsetOverflow(const Runtime::Instance::MemoryInstance &MemInst,
439
                      const AST::Instruction &Instr, const uint64_t Val,
440
                      const uint64_t Size) const noexcept;
441
  /// @}
442
443
  /// \name Helper Functions for GC instructions.
444
  /// @{
445
  Expect<RefVariant> structNew(const Runtime::Instance::ModuleInstance *ModInst,
446
                               const uint32_t TypeIdx,
447
                               Span<const ValVariant> Args = {}) const noexcept;
448
  Expect<ValVariant> structGet(const Runtime::Instance::ModuleInstance *ModInst,
449
                               const RefVariant Ref, const uint32_t TypeIdx,
450
                               const uint32_t Off,
451
                               const bool IsSigned = false) const noexcept;
452
  Expect<void> structSet(const Runtime::Instance::ModuleInstance *ModInst,
453
                         const RefVariant Ref, const ValVariant Val,
454
                         const uint32_t TypeIdx,
455
                         const uint32_t Off) const noexcept;
456
  Expect<RefVariant> arrayNew(const Runtime::Instance::ModuleInstance *ModInst,
457
                              const uint32_t TypeIdx, const uint32_t Length,
458
                              Span<const ValVariant> Args = {}) const noexcept;
459
  Expect<RefVariant>
460
  arrayNewData(const Runtime::Instance::ModuleInstance *ModInst,
461
               const uint32_t TypeIdx, const uint32_t DataIdx,
462
               const uint32_t Start, const uint32_t Length) const noexcept;
463
  Expect<RefVariant>
464
  arrayNewElem(const Runtime::Instance::ModuleInstance *ModInst,
465
               const uint32_t TypeIdx, const uint32_t ElemIdx,
466
               const uint32_t Start, const uint32_t Length) const noexcept;
467
  Expect<ValVariant> arrayGet(const Runtime::Instance::ModuleInstance *ModInst,
468
                              const RefVariant &Ref, const uint32_t TypeIdx,
469
                              const uint32_t Idx,
470
                              const bool IsSigned = false) const noexcept;
471
  Expect<void> arraySet(const Runtime::Instance::ModuleInstance *ModInst,
472
                        const RefVariant &Ref, const ValVariant &Val,
473
                        const uint32_t TypeIdx,
474
                        const uint32_t Idx) const noexcept;
475
  Expect<void> arrayFill(const Runtime::Instance::ModuleInstance *ModInst,
476
                         const RefVariant &Ref, const ValVariant &Val,
477
                         const uint32_t TypeIdx, const uint32_t Idx,
478
                         const uint32_t Cnt) const noexcept;
479
  Expect<void> arrayInitData(const Runtime::Instance::ModuleInstance *ModInst,
480
                             const RefVariant &Ref, const uint32_t TypeIdx,
481
                             const uint32_t DataIdx, const uint32_t DstIdx,
482
                             const uint32_t SrcIdx,
483
                             const uint32_t Cnt) const noexcept;
484
  Expect<void> arrayInitElem(const Runtime::Instance::ModuleInstance *ModInst,
485
                             const RefVariant &Ref, const uint32_t TypeIdx,
486
                             const uint32_t ElemIdx, const uint32_t DstIdx,
487
                             const uint32_t SrcIdx,
488
                             const uint32_t Cnt) const noexcept;
489
  Expect<void> arrayCopy(const Runtime::Instance::ModuleInstance *ModInst,
490
                         const RefVariant &DstRef, const uint32_t DstTypeIdx,
491
                         const uint32_t DstIdx, const RefVariant &SrcRef,
492
                         const uint32_t SrcTypeIdx, const uint32_t SrcIdx,
493
                         const uint32_t Cnt) const noexcept;
494
  /// @}
495
496
  /// \name Helper Functions for atomic operations.
497
  /// @{
498
  template <typename T>
499
  Expect<uint64_t> atomicWait(Runtime::Instance::MemoryInstance &MemInst,
500
                              uint64_t Address, EndianValue<T> Expected,
501
                              int64_t Timeout) noexcept;
502
  Expect<uint64_t> atomicNotify(Runtime::Instance::MemoryInstance &MemInst,
503
                                uint64_t Address, uint64_t Count) noexcept;
504
  void atomicNotifyAll() noexcept;
505
  /// @}
506
507
  /// \name Helper Functions for getting instances or types.
508
  /// @{
509
  /// Helper function for getting defined type by index.
510
  const AST::SubType *
511
  getDefTypeByIdx(const Runtime::Instance::ModuleInstance *ModInst,
512
                  const uint32_t Idx) const;
513
514
  /// Helper function for getting composite type by index. Assuming validated.
515
  const WasmEdge::AST::CompositeType &
516
  getCompositeTypeByIdx(const Runtime::Instance::ModuleInstance *ModInst,
517
                        const uint32_t Idx) const noexcept;
518
519
  /// Helper function for getting struct storage type by index.
520
  const ValType &
521
  getStructStorageTypeByIdx(const Runtime::Instance::ModuleInstance *ModInst,
522
                            const uint32_t Idx,
523
                            const uint32_t Off) const noexcept;
524
525
  /// Helper function for getting array storage type by index.
526
  const ValType &
527
  getArrayStorageTypeByIdx(const Runtime::Instance::ModuleInstance *ModInst,
528
                           const uint32_t Idx) const noexcept;
529
530
  /// Helper function for getting function instance by index.
531
  Runtime::Instance::FunctionInstance *
532
  getFuncInstByIdx(const Runtime::Instance::ModuleInstance *ModInst,
533
                   const uint32_t Idx) const;
534
535
  /// Helper function for getting table instance by index.
536
  Runtime::Instance::TableInstance *
537
  getTabInstByIdx(const Runtime::Instance::ModuleInstance *ModInst,
538
                  const uint32_t Idx) const;
539
540
  /// Helper function for getting memory instance by index.
541
  Runtime::Instance::MemoryInstance *
542
  getMemInstByIdx(const Runtime::Instance::ModuleInstance *ModInst,
543
                  const uint32_t Idx) const;
544
545
  /// Helper function for getting tag instance by index.
546
  Runtime::Instance::TagInstance *
547
  getTagInstByIdx(const Runtime::Instance::ModuleInstance *ModInst,
548
                  const uint32_t Idx) const;
549
550
  /// Helper function for getting global instance by index.
551
  Runtime::Instance::GlobalInstance *
552
  getGlobInstByIdx(const Runtime::Instance::ModuleInstance *ModInst,
553
                   const uint32_t Idx) const;
554
555
  /// Helper function for getting element instance by index.
556
  Runtime::Instance::ElementInstance *
557
  getElemInstByIdx(const Runtime::Instance::ModuleInstance *ModInst,
558
                   const uint32_t Idx) const;
559
560
  /// Helper function for getting data instance by index.
561
  Runtime::Instance::DataInstance *
562
  getDataInstByIdx(const Runtime::Instance::ModuleInstance *ModInst,
563
                   const uint32_t Idx) const;
564
565
  /// Helper function for converting into bottom abstract heap type.
566
  TypeCode toBottomType(const Runtime::Instance::ModuleInstance *ModInst,
567
                        const ValType &Type) const;
568
569
  /// Helper function for cleaning unused bits of numeric values in ValVariant.
570
  void cleanNumericVal(ValVariant &Val, const ValType &Type) const noexcept;
571
572
  /// Helper function for packing ValVariant for packed type.
573
  ValVariant packVal(const ValType &Type, const ValVariant &Val) const noexcept;
574
575
  /// Helper function for packing ValVariant vector for packed type.
576
  std::vector<ValVariant>
577
  packVals(const ValType &Type, std::vector<ValVariant> &&Vals) const noexcept;
578
579
  /// Helper function for unpacking ValVariant for packed type.
580
  ValVariant unpackVal(const ValType &Type, const ValVariant &Val,
581
                       bool IsSigned = false) const noexcept;
582
  /// @}
583
584
  /// \name Interpreter - Run instructions functions
585
  /// @{
586
  /// ======= Control instructions =======
587
  Expect<void> runIfElseOp(Runtime::StackManager &StackMgr,
588
                           const AST::Instruction &Instr,
589
                           AST::InstrView::iterator &PC) noexcept;
590
  Expect<void> runThrowOp(Runtime::StackManager &StackMgr,
591
                          const AST::Instruction &Instr,
592
                          AST::InstrView::iterator &PC) noexcept;
593
  Expect<void> runThrowRefOp(Runtime::StackManager &StackMgr,
594
                             const AST::Instruction &Instr,
595
                             AST::InstrView::iterator &PC) noexcept;
596
  Expect<void> runBrOp(Runtime::StackManager &StackMgr,
597
                       const AST::Instruction &Instr,
598
                       AST::InstrView::iterator &PC) noexcept;
599
  Expect<void> runBrIfOp(Runtime::StackManager &StackMgr,
600
                         const AST::Instruction &Instr,
601
                         AST::InstrView::iterator &PC) noexcept;
602
  Expect<void> runBrOnNullOp(Runtime::StackManager &StackMgr,
603
                             const AST::Instruction &Instr,
604
                             AST::InstrView::iterator &PC) noexcept;
605
  Expect<void> runBrOnNonNullOp(Runtime::StackManager &StackMgr,
606
                                const AST::Instruction &Instr,
607
                                AST::InstrView::iterator &PC) noexcept;
608
  Expect<void> runBrTableOp(Runtime::StackManager &StackMgr,
609
                            const AST::Instruction &Instr,
610
                            AST::InstrView::iterator &PC) noexcept;
611
  Expect<void> runBrOnCastOp(Runtime::StackManager &StackMgr,
612
                             const AST::Instruction &Instr,
613
                             AST::InstrView::iterator &PC,
614
                             bool IsReverse = false) noexcept;
615
  Expect<void> runReturnOp(Runtime::StackManager &StackMgr,
616
                           AST::InstrView::iterator &PC) noexcept;
617
  Expect<void> runCallOp(Runtime::StackManager &StackMgr,
618
                         const AST::Instruction &Instr,
619
                         AST::InstrView::iterator &PC,
620
                         bool IsTailCall = false) noexcept;
621
  Expect<void> runCallRefOp(Runtime::StackManager &StackMgr,
622
                            const AST::Instruction &Instr,
623
                            AST::InstrView::iterator &PC,
624
                            bool IsTailCall = false) noexcept;
625
  Expect<void> runCallIndirectOp(Runtime::StackManager &StackMgr,
626
                                 const AST::Instruction &Instr,
627
                                 AST::InstrView::iterator &PC,
628
                                 bool IsTailCall = false) noexcept;
629
  Expect<void> runTryTableOp(Runtime::StackManager &StackMgr,
630
                             const AST::Instruction &Instr,
631
                             AST::InstrView::iterator &PC) noexcept;
632
  /// ======= Variable instructions =======
633
  Expect<void> runLocalGetOp(Runtime::StackManager &StackMgr,
634
                             uint32_t StackOffset) const noexcept;
635
  Expect<void> runLocalSetOp(Runtime::StackManager &StackMgr,
636
                             uint32_t StackOffset) const noexcept;
637
  Expect<void> runLocalTeeOp(Runtime::StackManager &StackMgr,
638
                             uint32_t StackOffset) const noexcept;
639
  Expect<void> runGlobalGetOp(Runtime::StackManager &StackMgr,
640
                              uint32_t Idx) const noexcept;
641
  Expect<void> runGlobalSetOp(Runtime::StackManager &StackMgr,
642
                              uint32_t Idx) const noexcept;
643
  /// ======= Reference instructions =======
644
  Expect<void> runRefNullOp(Runtime::StackManager &StackMgr,
645
                            const ValType &Type) const noexcept;
646
  Expect<void> runRefIsNullOp(ValVariant &Val) const noexcept;
647
  Expect<void> runRefFuncOp(Runtime::StackManager &StackMgr,
648
                            uint32_t Idx) const noexcept;
649
  Expect<void> runRefEqOp(ValVariant &Val1,
650
                          const ValVariant &Val2) const noexcept;
651
  Expect<void> runRefAsNonNullOp(RefVariant &Val,
652
                                 const AST::Instruction &Instr) const noexcept;
653
  Expect<void> runStructNewOp(Runtime::StackManager &StackMgr,
654
                              const uint32_t TypeIdx,
655
                              const bool IsDefault = false) const noexcept;
656
  Expect<void> runStructGetOp(Runtime::StackManager &StackMgr,
657
                              const uint32_t TypeIdx, const uint32_t Off,
658
                              const AST::Instruction &Instr,
659
                              const bool IsSigned = false) const noexcept;
660
  Expect<void> runStructSetOp(Runtime::StackManager &StackMgr,
661
                              const ValVariant &Val, const uint32_t TypeIdx,
662
                              const uint32_t Off,
663
                              const AST::Instruction &Instr) const noexcept;
664
  Expect<void> runArrayNewOp(Runtime::StackManager &StackMgr,
665
                             const uint32_t TypeIdx, const uint32_t InitCnt,
666
                             uint32_t Length) const noexcept;
667
  Expect<void> runArrayNewDataOp(Runtime::StackManager &StackMgr,
668
                                 const uint32_t TypeIdx, const uint32_t DataIdx,
669
                                 const AST::Instruction &Instr) const noexcept;
670
  Expect<void> runArrayNewElemOp(Runtime::StackManager &StackMgr,
671
                                 const uint32_t TypeIdx, const uint32_t ElemIdx,
672
                                 const AST::Instruction &Instr) const noexcept;
673
  Expect<void> runArrayGetOp(Runtime::StackManager &StackMgr,
674
                             const uint32_t TypeIdx,
675
                             const AST::Instruction &Instr,
676
                             const bool IsSigned = false) const noexcept;
677
  Expect<void> runArraySetOp(Runtime::StackManager &StackMgr,
678
                             const ValVariant &Val, const uint32_t TypeIdx,
679
                             const AST::Instruction &Instr) const noexcept;
680
  Expect<void> runArrayLenOp(ValVariant &Val,
681
                             const AST::Instruction &Instr) const noexcept;
682
  Expect<void> runArrayFillOp(Runtime::StackManager &StackMgr,
683
                              const uint32_t Cnt, const ValVariant &Val,
684
                              const uint32_t TypeIdx,
685
                              const AST::Instruction &Instr) const noexcept;
686
  Expect<void> runArrayCopyOp(Runtime::StackManager &StackMgr,
687
                              const uint32_t Cnt, const uint32_t DstTypeIdx,
688
                              const uint32_t SrcTypeIdx,
689
                              const AST::Instruction &Instr) const noexcept;
690
  Expect<void> runArrayInitDataOp(Runtime::StackManager &StackMgr,
691
                                  const uint32_t Cnt, const uint32_t TypeIdx,
692
                                  const uint32_t DataIdx,
693
                                  const AST::Instruction &Instr) const noexcept;
694
  Expect<void> runArrayInitElemOp(Runtime::StackManager &StackMgr,
695
                                  const uint32_t Cnt, const uint32_t TypeIdx,
696
                                  const uint32_t ElemIdx,
697
                                  const AST::Instruction &Instr) const noexcept;
698
  Expect<void> runRefTestOp(const Runtime::Instance::ModuleInstance *ModInst,
699
                            ValVariant &Val, const AST::Instruction &Instr,
700
                            const bool IsCast = false) const noexcept;
701
  Expect<void> runRefConvOp(RefVariant &Val, TypeCode TCode) const noexcept;
702
  Expect<void> runRefI31Op(ValVariant &Val) const noexcept;
703
  Expect<void> runI31GetOp(ValVariant &Val, const AST::Instruction &Instr,
704
                           const bool IsSigned = false) const noexcept;
705
  /// ======= Table instructions =======
706
  Expect<void> runTableGetOp(Runtime::StackManager &StackMgr,
707
                             Runtime::Instance::TableInstance &TabInst,
708
                             const AST::Instruction &Instr);
709
  Expect<void> runTableSetOp(Runtime::StackManager &StackMgr,
710
                             Runtime::Instance::TableInstance &TabInst,
711
                             const AST::Instruction &Instr);
712
  Expect<void> runTableInitOp(Runtime::StackManager &StackMgr,
713
                              Runtime::Instance::TableInstance &TabInst,
714
                              Runtime::Instance::ElementInstance &ElemInst,
715
                              const AST::Instruction &Instr);
716
  Expect<void> runElemDropOp(Runtime::Instance::ElementInstance &ElemInst);
717
  Expect<void> runTableCopyOp(Runtime::StackManager &StackMgr,
718
                              Runtime::Instance::TableInstance &TabInstDst,
719
                              Runtime::Instance::TableInstance &TabInstSrc,
720
                              const AST::Instruction &Instr);
721
  Expect<void> runTableGrowOp(Runtime::StackManager &StackMgr,
722
                              Runtime::Instance::TableInstance &TabInst);
723
  Expect<void> runTableSizeOp(Runtime::StackManager &StackMgr,
724
                              Runtime::Instance::TableInstance &TabInst);
725
  Expect<void> runTableFillOp(Runtime::StackManager &StackMgr,
726
                              Runtime::Instance::TableInstance &TabInst,
727
                              const AST::Instruction &Instr);
728
  /// ======= Memory instructions =======
729
  template <typename T, uint32_t BitWidth = sizeof(T) * 8>
730
  TypeT<T> runLoadOp(Runtime::StackManager &StackMgr,
731
                     Runtime::Instance::MemoryInstance &MemInst,
732
                     const AST::Instruction &Instr);
733
  template <typename T, uint32_t BitWidth = sizeof(T) * 8>
734
  TypeN<T> runStoreOp(Runtime::StackManager &StackMgr,
735
                      Runtime::Instance::MemoryInstance &MemInst,
736
                      const AST::Instruction &Instr);
737
  Expect<void> runMemorySizeOp(Runtime::StackManager &StackMgr,
738
                               Runtime::Instance::MemoryInstance &MemInst);
739
  Expect<void> runMemoryGrowOp(Runtime::StackManager &StackMgr,
740
                               Runtime::Instance::MemoryInstance &MemInst);
741
  Expect<void> runMemoryInitOp(Runtime::StackManager &StackMgr,
742
                               Runtime::Instance::MemoryInstance &MemInst,
743
                               Runtime::Instance::DataInstance &DataInst,
744
                               const AST::Instruction &Instr);
745
  Expect<void> runDataDropOp(Runtime::Instance::DataInstance &DataInst);
746
  Expect<void> runMemoryCopyOp(Runtime::StackManager &StackMgr,
747
                               Runtime::Instance::MemoryInstance &MemInstDst,
748
                               Runtime::Instance::MemoryInstance &MemInstSrc,
749
                               const AST::Instruction &Instr);
750
  Expect<void> runMemoryFillOp(Runtime::StackManager &StackMgr,
751
                               Runtime::Instance::MemoryInstance &MemInst,
752
                               const AST::Instruction &Instr);
753
  /// ======= Test and Relation Numeric instructions =======
754
  template <typename T> TypeU<T> runEqzOp(ValVariant &Val) const;
755
  template <typename T>
756
  TypeT<T> runEqOp(ValVariant &Val1, const ValVariant &Val2) const;
757
  template <typename T>
758
  TypeT<T> runNeOp(ValVariant &Val1, const ValVariant &Val2) const;
759
  template <typename T>
760
  TypeT<T> runLtOp(ValVariant &Val1, const ValVariant &Val2) const;
761
  template <typename T>
762
  TypeT<T> runGtOp(ValVariant &Val1, const ValVariant &Val2) const;
763
  template <typename T>
764
  TypeT<T> runLeOp(ValVariant &Val1, const ValVariant &Val2) const;
765
  template <typename T>
766
  TypeT<T> runGeOp(ValVariant &Val1, const ValVariant &Val2) const;
767
  /// ======= Unary Numeric instructions =======
768
  template <typename T> TypeU<T> runClzOp(ValVariant &Val) const;
769
  template <typename T> TypeU<T> runCtzOp(ValVariant &Val) const;
770
  template <typename T> TypeU<T> runPopcntOp(ValVariant &Val) const;
771
  template <typename T> TypeF<T> runAbsOp(ValVariant &Val) const;
772
  template <typename T> TypeF<T> runNegOp(ValVariant &Val) const;
773
  template <typename T> TypeF<T> runCeilOp(ValVariant &Val) const;
774
  template <typename T> TypeF<T> runFloorOp(ValVariant &Val) const;
775
  template <typename T> TypeF<T> runTruncOp(ValVariant &Val) const;
776
  template <typename T> TypeF<T> runNearestOp(ValVariant &Val) const;
777
  template <typename T> TypeF<T> runSqrtOp(ValVariant &Val) const;
778
  /// ======= Binary Numeric instructions =======
779
  template <typename T>
780
  TypeN<T> runAddOp(ValVariant &Val1, const ValVariant &Val2) const;
781
  template <typename T>
782
  TypeN<T> runSubOp(ValVariant &Val1, const ValVariant &Val2) const;
783
  template <typename T>
784
  TypeN<T> runMulOp(ValVariant &Val1, const ValVariant &Val2) const;
785
  template <typename T>
786
  TypeT<T> runDivOp(const AST::Instruction &Instr, ValVariant &Val1,
787
                    const ValVariant &Val2) const;
788
  template <typename T>
789
  TypeI<T> runRemOp(const AST::Instruction &Instr, ValVariant &Val1,
790
                    const ValVariant &Val2) const;
791
  template <typename T>
792
  TypeU<T> runAndOp(ValVariant &Val1, const ValVariant &Val2) const;
793
  template <typename T>
794
  TypeU<T> runOrOp(ValVariant &Val1, const ValVariant &Val2) const;
795
  template <typename T>
796
  TypeU<T> runXorOp(ValVariant &Val1, const ValVariant &Val2) const;
797
  template <typename T>
798
  TypeU<T> runShlOp(ValVariant &Val1, const ValVariant &Val2) const;
799
  template <typename T>
800
  TypeI<T> runShrOp(ValVariant &Val1, const ValVariant &Val2) const;
801
  template <typename T>
802
  TypeU<T> runRotlOp(ValVariant &Val1, const ValVariant &Val2) const;
803
  template <typename T>
804
  TypeU<T> runRotrOp(ValVariant &Val1, const ValVariant &Val2) const;
805
  template <typename T>
806
  TypeF<T> runMinOp(ValVariant &Val1, const ValVariant &Val2) const;
807
  template <typename T>
808
  TypeF<T> runMaxOp(ValVariant &Val1, const ValVariant &Val2) const;
809
  template <typename T>
810
  TypeF<T> runCopysignOp(ValVariant &Val1, const ValVariant &Val2) const;
811
  /// ======= Cast Numeric instructions =======
812
  template <typename TIn, typename TOut>
813
  TypeUU<TIn, TOut> runWrapOp(ValVariant &Val) const;
814
  template <typename TIn, typename TOut>
815
  TypeFI<TIn, TOut> runTruncateOp(const AST::Instruction &Instr,
816
                                  ValVariant &Val) const;
817
  template <typename TIn, typename TOut>
818
  TypeFI<TIn, TOut> runTruncateSatOp(ValVariant &Val) const;
819
  template <typename TIn, typename TOut, size_t B = sizeof(TIn) * 8>
820
  TypeIU<TIn, TOut> runExtendOp(ValVariant &Val) const;
821
  template <typename TIn, typename TOut>
822
  TypeIF<TIn, TOut> runConvertOp(ValVariant &Val) const;
823
  template <typename TIn, typename TOut>
824
  TypeFF<TIn, TOut> runDemoteOp(ValVariant &Val) const;
825
  template <typename TIn, typename TOut>
826
  TypeFF<TIn, TOut> runPromoteOp(ValVariant &Val) const;
827
  template <typename TIn, typename TOut>
828
  TypeNN<TIn, TOut> runReinterpretOp(ValVariant &Val) const;
829
  /// ======= SIMD Memory instructions =======
830
  template <typename TIn, typename TOut>
831
  Expect<void> runLoadExpandOp(Runtime::StackManager &StackMgr,
832
                               Runtime::Instance::MemoryInstance &MemInst,
833
                               const AST::Instruction &Instr);
834
  template <typename T>
835
  Expect<void> runLoadSplatOp(Runtime::StackManager &StackMgr,
836
                              Runtime::Instance::MemoryInstance &MemInst,
837
                              const AST::Instruction &Instr);
838
  template <typename T>
839
  Expect<void> runLoadLaneOp(Runtime::StackManager &StackMgr,
840
                             Runtime::Instance::MemoryInstance &MemInst,
841
                             const AST::Instruction &Instr);
842
  template <typename T>
843
  Expect<void> runStoreLaneOp(Runtime::StackManager &StackMgr,
844
                              Runtime::Instance::MemoryInstance &MemInst,
845
                              const AST::Instruction &Instr);
846
  /// ======= SIMD Lane instructions =======
847
  template <typename TIn, typename TOut = TIn>
848
  Expect<void> runExtractLaneOp(ValVariant &Val, const uint8_t Index) const;
849
  template <typename TIn, typename TOut = TIn>
850
  Expect<void> runReplaceLaneOp(ValVariant &Val1, const ValVariant &Val2,
851
                                const uint8_t Index) const;
852
  /// ======= SIMD Numeric instructions =======
853
  template <typename TIn, typename TOut = TIn>
854
  Expect<void> runSplatOp(ValVariant &Val) const;
855
  template <typename T>
856
  Expect<void> runVectorEqOp(ValVariant &Val1, const ValVariant &Val2) const;
857
  template <typename T>
858
  Expect<void> runVectorNeOp(ValVariant &Val1, const ValVariant &Val2) const;
859
  template <typename T>
860
  Expect<void> runVectorLtOp(ValVariant &Val1, const ValVariant &Val2) const;
861
  template <typename T>
862
  Expect<void> runVectorGtOp(ValVariant &Val1, const ValVariant &Val2) const;
863
  template <typename T>
864
  Expect<void> runVectorLeOp(ValVariant &Val1, const ValVariant &Val2) const;
865
  template <typename T>
866
  Expect<void> runVectorGeOp(ValVariant &Val1, const ValVariant &Val2) const;
867
  template <typename T> Expect<void> runVectorAbsOp(ValVariant &Val) const;
868
  template <typename T> Expect<void> runVectorNegOp(ValVariant &Val) const;
869
  inline Expect<void> runVectorPopcntOp(ValVariant &Val) const;
870
  template <typename T> Expect<void> runVectorSqrtOp(ValVariant &Val) const;
871
  template <typename TIn, typename TOut>
872
  Expect<void> runVectorTruncSatOp(ValVariant &Val) const;
873
  template <typename TIn, typename TOut>
874
  Expect<void> runVectorConvertOp(ValVariant &Val) const;
875
  inline Expect<void> runVectorDemoteOp(ValVariant &Val) const;
876
  inline Expect<void> runVectorPromoteOp(ValVariant &Val) const;
877
  inline Expect<void> runVectorAnyTrueOp(ValVariant &Val) const;
878
  template <typename T> Expect<void> runVectorAllTrueOp(ValVariant &Val) const;
879
  template <typename T> Expect<void> runVectorBitMaskOp(ValVariant &Val) const;
880
  template <typename TIn, typename TOut>
881
  Expect<void> runVectorNarrowOp(ValVariant &Val1,
882
                                 const ValVariant &Val2) const;
883
  template <typename TIn, typename TOut>
884
  Expect<void> runVectorExtendLowOp(ValVariant &Val) const;
885
  template <typename TIn, typename TOut>
886
  Expect<void> runVectorExtendHighOp(ValVariant &Val) const;
887
  template <typename TIn, typename TOut>
888
  Expect<void> runVectorExtAddPairwiseOp(ValVariant &Val) const;
889
  template <typename TIn, typename TOut>
890
  Expect<void> runVectorExtMulLowOp(ValVariant &Val1,
891
                                    const ValVariant &Val2) const;
892
  template <typename TIn, typename TOut>
893
  Expect<void> runVectorExtMulHighOp(ValVariant &Val1,
894
                                     const ValVariant &Val2) const;
895
  inline Expect<void> runVectorQ15MulSatOp(ValVariant &Val1,
896
                                           const ValVariant &Val2) const;
897
  template <typename T>
898
  Expect<void> runVectorShlOp(ValVariant &Val1, const ValVariant &Val2) const;
899
  template <typename T>
900
  Expect<void> runVectorShrOp(ValVariant &Val1, const ValVariant &Val2) const;
901
  template <typename T>
902
  Expect<void> runVectorAddOp(ValVariant &Val1, const ValVariant &Val2) const;
903
  template <typename T>
904
  Expect<void> runVectorAddSatOp(ValVariant &Val1,
905
                                 const ValVariant &Val2) const;
906
  template <typename T>
907
  Expect<void> runVectorSubOp(ValVariant &Val1, const ValVariant &Val2) const;
908
  template <typename T>
909
  Expect<void> runVectorSubSatOp(ValVariant &Val1,
910
                                 const ValVariant &Val2) const;
911
  template <typename T>
912
  Expect<void> runVectorMulOp(ValVariant &Val1, const ValVariant &Val2) const;
913
  template <typename T>
914
  Expect<void> runVectorDivOp(ValVariant &Val1, const ValVariant &Val2) const;
915
  template <typename T>
916
  Expect<void> runVectorMinOp(ValVariant &Val1, const ValVariant &Val2) const;
917
  template <typename T>
918
  Expect<void> runVectorMaxOp(ValVariant &Val1, const ValVariant &Val2) const;
919
  template <typename T>
920
  Expect<void> runVectorFMinOp(ValVariant &Val1, const ValVariant &Val2) const;
921
  template <typename T>
922
  Expect<void> runVectorFMaxOp(ValVariant &Val1, const ValVariant &Val2) const;
923
  template <typename T, typename ET>
924
  Expect<void> runVectorAvgrOp(ValVariant &Val1, const ValVariant &Val2) const;
925
  template <typename T> Expect<void> runVectorCeilOp(ValVariant &Val) const;
926
  template <typename T> Expect<void> runVectorFloorOp(ValVariant &Val) const;
927
  template <typename T> Expect<void> runVectorTruncOp(ValVariant &Val) const;
928
  template <typename T> Expect<void> runVectorNearestOp(ValVariant &Val) const;
929
  /// ======= Relaxed SIMD instructions =======
930
  template <typename T>
931
  Expect<void> runVectorRelaxedLaneselectOp(ValVariant &Val1,
932
                                            const ValVariant &Val2,
933
                                            const ValVariant &Mask) const;
934
  inline Expect<void>
935
  runVectorRelaxedIntegerDotProductOp(ValVariant &Val1,
936
                                      const ValVariant &Val2) const;
937
  inline Expect<void> runVectorRelaxedIntegerDotProductOpAdd(
938
      ValVariant &Val1, const ValVariant &Val2, const ValVariant &C) const;
939
  /// ======= Atomic instructions =======
940
  Expect<void> runAtomicNotifyOp(Runtime::StackManager &StackMgr,
941
                                 Runtime::Instance::MemoryInstance &MemInst,
942
                                 const AST::Instruction &Instr);
943
  Expect<void> runMemoryFenceOp();
944
  template <typename T>
945
  TypeT<T> runAtomicWaitOp(Runtime::StackManager &StackMgr,
946
                           Runtime::Instance::MemoryInstance &MemInst,
947
                           const AST::Instruction &Instr);
948
  template <typename T, typename I>
949
  TypeT<T> runAtomicLoadOp(Runtime::StackManager &StackMgr,
950
                           Runtime::Instance::MemoryInstance &MemInst,
951
                           const AST::Instruction &Instr);
952
  template <typename T, typename I>
953
  TypeT<T> runAtomicStoreOp(Runtime::StackManager &StackMgr,
954
                            Runtime::Instance::MemoryInstance &MemInst,
955
                            const AST::Instruction &Instr);
956
  template <typename T, typename I>
957
  TypeT<T> runAtomicAddOp(Runtime::StackManager &StackMgr,
958
                          Runtime::Instance::MemoryInstance &MemInst,
959
                          const AST::Instruction &Instr);
960
  template <typename T, typename I>
961
  TypeT<T> runAtomicSubOp(Runtime::StackManager &StackMgr,
962
                          Runtime::Instance::MemoryInstance &MemInst,
963
                          const AST::Instruction &Instr);
964
  template <typename T, typename I>
965
  TypeT<T> runAtomicOrOp(Runtime::StackManager &StackMgr,
966
                         Runtime::Instance::MemoryInstance &MemInst,
967
                         const AST::Instruction &Instr);
968
  template <typename T, typename I>
969
  TypeT<T> runAtomicAndOp(Runtime::StackManager &StackMgr,
970
                          Runtime::Instance::MemoryInstance &MemInst,
971
                          const AST::Instruction &Instr);
972
  template <typename T, typename I>
973
  TypeT<T> runAtomicXorOp(Runtime::StackManager &StackMgr,
974
                          Runtime::Instance::MemoryInstance &MemInst,
975
                          const AST::Instruction &Instr);
976
  template <typename T, typename I>
977
  TypeT<T> runAtomicExchangeOp(Runtime::StackManager &StackMgr,
978
                               Runtime::Instance::MemoryInstance &MemInst,
979
                               const AST::Instruction &Instr);
980
  template <typename T, typename I>
981
  TypeT<T>
982
  runAtomicCompareExchangeOp(Runtime::StackManager &StackMgr,
983
                             Runtime::Instance::MemoryInstance &MemInst,
984
                             const AST::Instruction &Instr);
985
  /// @}
986
987
public:
988
  /// \name AOT/JIT - Run compiled functions
989
  /// @{
990
  Expect<void> proxyTrap(Runtime::StackManager &StackMgr,
991
                         const uint32_t Code) noexcept;
992
  Expect<void> proxyCall(Runtime::StackManager &StackMgr,
993
                         const Runtime::Instance::ModuleInstance *ModInst,
994
                         const uint32_t FuncIdx, const ValVariant *Args,
995
                         ValVariant *Rets) noexcept;
996
  Expect<void>
997
  proxyCallIndirect(Runtime::StackManager &StackMgr,
998
                    const Runtime::Instance::ModuleInstance *ModInst,
999
                    const uint32_t TableIdx, const uint32_t FuncTypeIdx,
1000
                    const uint64_t FuncIdx, const ValVariant *Args,
1001
                    ValVariant *Rets) noexcept;
1002
  Expect<void> proxyCallRef(Runtime::StackManager &StackMgr,
1003
                            const Runtime::Instance::ModuleInstance *ModInst,
1004
                            const RefVariant Ref, const ValVariant *Args,
1005
                            ValVariant *Rets) noexcept;
1006
  Expect<RefVariant>
1007
  proxyRefFunc(Runtime::StackManager &StackMgr,
1008
               const Runtime::Instance::ModuleInstance *ModInst,
1009
               const uint32_t FuncIdx) noexcept;
1010
  Expect<RefVariant>
1011
  proxyStructNew(Runtime::StackManager &StackMgr,
1012
                 const Runtime::Instance::ModuleInstance *ModInst,
1013
                 const uint32_t TypeIdx, const ValVariant *Args,
1014
                 const uint32_t ArgSize) noexcept;
1015
  Expect<void> proxyStructGet(Runtime::StackManager &StackMgr,
1016
                              const Runtime::Instance::ModuleInstance *ModInst,
1017
                              const RefVariant Ref, const uint32_t TypeIdx,
1018
                              const uint32_t Off, const bool IsSigned,
1019
                              ValVariant *Ret) noexcept;
1020
  Expect<void> proxyStructSet(Runtime::StackManager &StackMgr,
1021
                              const Runtime::Instance::ModuleInstance *ModInst,
1022
                              const RefVariant Ref, const uint32_t TypeIdx,
1023
                              const uint32_t Off,
1024
                              const ValVariant *Val) noexcept;
1025
  Expect<RefVariant>
1026
  proxyArrayNew(Runtime::StackManager &StackMgr,
1027
                const Runtime::Instance::ModuleInstance *ModInst,
1028
                const uint32_t TypeIdx, const uint32_t Length,
1029
                const ValVariant *Args, const uint32_t ArgSize) noexcept;
1030
  Expect<RefVariant>
1031
  proxyArrayNewData(Runtime::StackManager &StackMgr,
1032
                    const Runtime::Instance::ModuleInstance *ModInst,
1033
                    const uint32_t TypeIdx, const uint32_t DataIdx,
1034
                    const uint32_t Start, const uint32_t Length) noexcept;
1035
  Expect<RefVariant>
1036
  proxyArrayNewElem(Runtime::StackManager &StackMgr,
1037
                    const Runtime::Instance::ModuleInstance *ModInst,
1038
                    const uint32_t TypeIdx, const uint32_t ElemIdx,
1039
                    const uint32_t Start, const uint32_t Length) noexcept;
1040
  Expect<void> proxyArrayGet(Runtime::StackManager &StackMgr,
1041
                             const Runtime::Instance::ModuleInstance *ModInst,
1042
                             const RefVariant Ref, const uint32_t TypeIdx,
1043
                             const uint32_t Idx, const bool IsSigned,
1044
                             ValVariant *Ret) noexcept;
1045
  Expect<void> proxyArraySet(Runtime::StackManager &StackMgr,
1046
                             const Runtime::Instance::ModuleInstance *ModInst,
1047
                             const RefVariant Ref, const uint32_t TypeIdx,
1048
                             const uint32_t Idx,
1049
                             const ValVariant *Val) noexcept;
1050
  Expect<uint32_t> proxyArrayLen(Runtime::StackManager &StackMgr,
1051
                                 const RefVariant Ref) noexcept;
1052
  Expect<void> proxyArrayFill(Runtime::StackManager &StackMgr,
1053
                              const Runtime::Instance::ModuleInstance *ModInst,
1054
                              const RefVariant Ref, const uint32_t TypeIdx,
1055
                              const uint32_t Idx, const uint32_t Cnt,
1056
                              const ValVariant *Val) noexcept;
1057
  Expect<void> proxyArrayCopy(Runtime::StackManager &StackMgr,
1058
                              const Runtime::Instance::ModuleInstance *ModInst,
1059
                              const RefVariant DstRef,
1060
                              const uint32_t DstTypeIdx, const uint32_t DstIdx,
1061
                              const RefVariant SrcRef,
1062
                              const uint32_t SrcTypeIdx, const uint32_t SrcIdx,
1063
                              const uint32_t Cnt) noexcept;
1064
  Expect<void>
1065
  proxyArrayInitData(Runtime::StackManager &StackMgr,
1066
                     const Runtime::Instance::ModuleInstance *ModInst,
1067
                     const RefVariant Ref, const uint32_t TypeIdx,
1068
                     const uint32_t DataIdx, const uint32_t DstIdx,
1069
                     const uint32_t SrcIdx, const uint32_t Cnt) noexcept;
1070
  Expect<void>
1071
  proxyArrayInitElem(Runtime::StackManager &StackMgr,
1072
                     const Runtime::Instance::ModuleInstance *ModInst,
1073
                     const RefVariant Ref, const uint32_t TypeIdx,
1074
                     const uint32_t ElemIdx, const uint32_t DstIdx,
1075
                     const uint32_t SrcIdx, const uint32_t Cnt) noexcept;
1076
  Expect<uint32_t>
1077
  proxyRefTest(Runtime::StackManager &StackMgr,
1078
               const Runtime::Instance::ModuleInstance *ModInst,
1079
               const RefVariant Ref, ValType VTTest) noexcept;
1080
  Expect<RefVariant>
1081
  proxyRefCast(Runtime::StackManager &StackMgr,
1082
               const Runtime::Instance::ModuleInstance *ModInst,
1083
               const RefVariant Ref, ValType VTCast) noexcept;
1084
  Expect<void> proxyTableInit(Runtime::StackManager &StackMgr,
1085
                              const Runtime::Instance::ModuleInstance *ModInst,
1086
                              const uint32_t TableIdx, const uint32_t ElemIdx,
1087
                              const uint64_t DstOff, const uint32_t SrcOff,
1088
                              const uint32_t Len) noexcept;
1089
  Expect<void> proxyElemDrop(Runtime::StackManager &StackMgr,
1090
                             const Runtime::Instance::ModuleInstance *ModInst,
1091
                             const uint32_t ElemIdx) noexcept;
1092
  Expect<void> proxyTableCopy(Runtime::StackManager &StackMgr,
1093
                              const Runtime::Instance::ModuleInstance *ModInst,
1094
                              const uint32_t TableIdxDst,
1095
                              const uint32_t TableIdxSrc, const uint64_t DstOff,
1096
                              const uint64_t SrcOff,
1097
                              const uint64_t Len) noexcept;
1098
  Expect<uint64_t>
1099
  proxyTableGrow(Runtime::StackManager &StackMgr,
1100
                 const Runtime::Instance::ModuleInstance *ModInst,
1101
                 const uint32_t TableIdx, const RefVariant Val,
1102
                 const uint64_t NewSize) noexcept;
1103
  Expect<void> proxyTableFill(Runtime::StackManager &StackMgr,
1104
                              const Runtime::Instance::ModuleInstance *ModInst,
1105
                              const uint32_t TableIdx, const uint64_t Off,
1106
                              const RefVariant Ref,
1107
                              const uint64_t Len) noexcept;
1108
  Expect<uint64_t>
1109
  proxyMemGrow(Runtime::StackManager &StackMgr,
1110
               const Runtime::Instance::ModuleInstance *ModInst,
1111
               const uint32_t MemIdx, const uint64_t NewSize) noexcept;
1112
  Expect<void> proxyMemInit(Runtime::StackManager &StackMgr,
1113
                            const Runtime::Instance::ModuleInstance *ModInst,
1114
                            const uint32_t MemIdx, const uint32_t DataIdx,
1115
                            const uint64_t DstOff, const uint32_t SrcOff,
1116
                            const uint32_t Len) noexcept;
1117
  Expect<void> proxyDataDrop(Runtime::StackManager &StackMgr,
1118
                             const Runtime::Instance::ModuleInstance *ModInst,
1119
                             const uint32_t DataIdx) noexcept;
1120
  Expect<void> proxyMemCopy(Runtime::StackManager &StackMgr,
1121
                            const Runtime::Instance::ModuleInstance *ModInst,
1122
                            const uint32_t DstMemIdx, const uint32_t SrcMemIdx,
1123
                            const uint64_t DstOff, const uint64_t SrcOff,
1124
                            const uint64_t Len) noexcept;
1125
  Expect<void> proxyMemFill(Runtime::StackManager &StackMgr,
1126
                            const Runtime::Instance::ModuleInstance *ModInst,
1127
                            const uint32_t MemIdx, const uint64_t Off,
1128
                            const uint8_t Val, const uint64_t Len) noexcept;
1129
  Expect<uint64_t>
1130
  proxyMemAtomicNotify(Runtime::StackManager &StackMgr,
1131
                       const Runtime::Instance::ModuleInstance *ModInst,
1132
                       const uint32_t MemIdx, const uint64_t Offset,
1133
                       const uint64_t Count) noexcept;
1134
  Expect<uint64_t>
1135
  proxyMemAtomicWait(Runtime::StackManager &StackMgr,
1136
                     const Runtime::Instance::ModuleInstance *ModInst,
1137
                     const uint32_t MemIdx, const uint64_t Offset,
1138
                     const uint64_t Expected, const int64_t Timeout,
1139
                     const uint32_t BitWidth) noexcept;
1140
  Expect<void *> proxyTableGetFuncSymbol(
1141
      Runtime::StackManager &StackMgr,
1142
      const Runtime::Instance::ModuleInstance *ModInst, const uint32_t TableIdx,
1143
      const uint32_t FuncTypeIdx, const uint64_t FuncIdx,
1144
      Runtime::Instance::ModuleInstance::ModuleContext **CalleeCtxOut) noexcept;
1145
  Expect<void *> proxyRefGetFuncSymbol(
1146
      Runtime::StackManager &StackMgr,
1147
      const Runtime::Instance::ModuleInstance *ModInst, const RefVariant Ref,
1148
      Runtime::Instance::ModuleInstance::ModuleContext **CalleeCtxOut) noexcept;
1149
  Expect<void *>
1150
  proxyFuncGetFuncSymbol(Runtime::StackManager &StackMgr,
1151
                         const Runtime::Instance::ModuleInstance *ModInst,
1152
                         const uint32_t FuncIdx) noexcept;
1153
  Expect<void> proxyThrow(Runtime::StackManager &StackMgr,
1154
                          const Runtime::Instance::ModuleInstance *ModInst,
1155
                          const uint32_t TagIdx, const ValVariant *Vals,
1156
                          const uint32_t Num) noexcept;
1157
  Expect<void> proxyThrowRef(Runtime::StackManager &StackMgr,
1158
                             const RefVariant Ref) noexcept;
1159
  Expect<void> proxyCatchPop(Runtime::StackManager &StackMgr,
1160
                             const Runtime::Instance::ModuleInstance *ModInst,
1161
                             ValVariant *Out, const uint32_t PopPayload,
1162
                             const uint32_t NeedRef) noexcept;
1163
  /// @}
1164
1165
  /// Callbacks for compiled modules
1166
  static const Executable::IntrinsicsTable Intrinsics;
1167
  /// Proxy helper template struct
1168
  template <typename FuncPtr> struct ProxyHelper;
1169
1170
private:
1171
  /// Execution context for compiled functions.
1172
  struct ExecutorContext {
1173
    std::atomic_uint64_t *InstrCount;
1174
    uint64_t *CostTable;
1175
    std::atomic_uint64_t *Gas;
1176
    uint64_t GasLimit;
1177
    std::atomic_uint32_t *StopToken;
1178
    void *const *PendingExnTagAddr;
1179
  };
1180
1181
  /// Compiled code reads this struct by field index through the mirrored
1182
  /// ExecCtx type built in lib/llvm/compiler/context.cpp. Keep both in the same
1183
  /// order.
1184
  static_assert(offsetof(ExecutorContext, InstrCount) == 0);
1185
  static_assert(offsetof(ExecutorContext, InstrCount) <
1186
                offsetof(ExecutorContext, CostTable));
1187
  static_assert(offsetof(ExecutorContext, CostTable) <
1188
                offsetof(ExecutorContext, Gas));
1189
  static_assert(offsetof(ExecutorContext, Gas) <
1190
                offsetof(ExecutorContext, GasLimit));
1191
  static_assert(offsetof(ExecutorContext, GasLimit) <
1192
                offsetof(ExecutorContext, StopToken));
1193
  static_assert(offsetof(ExecutorContext, StopToken) <
1194
                offsetof(ExecutorContext, PendingExnTagAddr));
1195
1196
  /// Restores thread local VM reference after overwriting it.
1197
  struct SavedThreadLocal {
1198
    SavedThreadLocal(Executor &Ex, Runtime::StackManager &StackMgr,
1199
                     [[maybe_unused]] const Runtime::Instance::FunctionInstance
1200
                         &Func) noexcept;
1201
1202
    SavedThreadLocal(const SavedThreadLocal &) = delete;
1203
    SavedThreadLocal(SavedThreadLocal &&) = delete;
1204
1205
    ~SavedThreadLocal() noexcept;
1206
1207
    Executor *SavedThis;
1208
    Runtime::StackManager *SavedCurrentStack;
1209
    ExecutorContext SavedExecutionContext;
1210
  };
1211
1212
  /// Pending exception passing across the compiled and the native-entered
1213
  /// frames. A non-null tag means pending; the exception instance keeps the
1214
  /// throw_ref identity.
1215
  struct PendingExnStruct {
1216
    /// Tag instance of the pending exception. Null when no exception is
1217
    /// pending.
1218
    Runtime::Instance::TagInstance *TagInst = nullptr;
1219
    /// Exception instance identity. Null for a fresh throw; set on rethrowing
1220
    /// to keep the exnref identity.
1221
    const Runtime::Instance::ExceptionInstance *Inst = nullptr;
1222
1223
    /// Getter and setter of the payload values.
1224
0
    const std::vector<ValVariant> &getPayload() const noexcept {
1225
0
      return Payload;
1226
0
    }
1227
0
    void setPayload(Span<const ValVariant> Vals) noexcept {
1228
0
      Payload.assign(Vals.begin(), Vals.end());
1229
0
    }
1230
1231
  private:
1232
    std::vector<ValVariant> Payload;
1233
  };
1234
1235
  /// Pointer to current object.
1236
  static thread_local Executor *This;
1237
  /// Stack passed into compiled functions
1238
  static thread_local Runtime::StackManager *CurrentStack;
1239
  /// Execution context for compiled functions
1240
  static thread_local ExecutorContext ExecutionContext;
1241
  /// Pending exception for compiled functions
1242
  static thread_local PendingExnStruct PendingExn;
1243
  /// Record stack trace on error
1244
  static thread_local std::array<StackTraceEntry, 256> StackTrace;
1245
  static thread_local size_t StackTraceSize;
1246
1247
  /// WasmEdge configuration
1248
  const Configure Conf;
1249
  /// Executor statistics
1250
  Statistics::Statistics *Stat;
1251
  /// Stop execution
1252
  std::atomic_uint32_t StopToken = 0;
1253
  /// Memory instance this Executor is currently waiting on (for stop()).
1254
  std::atomic<Runtime::Instance::MemoryInstance *> WaitingMemory = nullptr;
1255
  /// Executor Host Function Handler
1256
  HostFuncHandler HostFuncHelper = {};
1257
  /// Callback for lazy function compilation
1258
  std::function<Expect<void>(const Runtime::Instance::FunctionInstance *)>
1259
      LazyCompilationHandler;
1260
1261
  /// Helper function for triggering lazy compilation.
1262
  /// XXX: Calling checkLazyCompilation in one thread while another thread calls
1263
  /// unsafeUpgradeToCompiled on the same FuncInst could result in a race
1264
  /// condition if checking FuncInst->isCompiledFunction() directly here. As a
1265
  /// temporary workaround, checks for compilation state are deferred to the
1266
  /// LazyCompilationHandler, which must serialize them against compiled-state
1267
  /// upgrades (the lazy JIT engine does so under its internal lock).
1268
  Expect<void> checkLazyCompilation(
1269
0
      const Runtime::Instance::FunctionInstance *FuncInst) const noexcept {
1270
0
    if (unlikely(LazyCompilationHandler != nullptr)) {
1271
0
      return LazyCompilationHandler(FuncInst);
1272
0
    }
1273
0
    return {};
1274
0
  }
1275
};
1276
1277
} // namespace Executor
1278
} // namespace WasmEdge
1279
1280
#include "engine/atomic.ipp"
1281
#include "engine/binary_numeric.ipp"
1282
#include "engine/cast_numeric.ipp"
1283
#include "engine/memory.ipp"
1284
#include "engine/relation_numeric.ipp"
1285
#include "engine/unary_numeric.ipp"