Coverage Report

Created: 2026-06-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/vm/vm.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- wasmedge/vm/vm.h - VM execution flow class definition -------------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file defines the VM class.
12
///
13
//===----------------------------------------------------------------------===//
14
#pragma once
15
16
#include "common/async.h"
17
#include "common/configure.h"
18
#include "common/errcode.h"
19
#include "common/filesystem.h"
20
#include "common/types.h"
21
22
#include "executor/executor.h"
23
#include "loader/loader.h"
24
#include "validator/validator.h"
25
26
#include "runtime/instance/module.h"
27
#include "runtime/storemgr.h"
28
29
#ifdef WASMEDGE_USE_LLVM
30
#include "llvm/lazyjit.h"
31
#endif
32
33
#include <cstdint>
34
#include <memory>
35
#include <shared_mutex>
36
#include <string>
37
#include <string_view>
38
#include <type_traits>
39
#include <unordered_map>
40
#include <utility>
41
#include <variant>
42
#include <vector>
43
44
namespace WasmEdge {
45
namespace VM {
46
47
/// VM execution flow class
48
class VM {
49
public:
50
  VM() = delete;
51
  VM(const Configure &Conf);
52
  VM(const Configure &Conf, Runtime::StoreManager &S);
53
0
  ~VM() {
54
0
    if (ActiveModInst) {
55
0
      auto *RawMod = ActiveModInst.release();
56
0
      if (RawMod) {
57
0
        RawMod->terminate();
58
0
      }
59
0
    }
60
0
    cleanupModInstContainer(RegModInsts);
61
0
    cleanupModInstContainer(BuiltInModInsts);
62
0
    cleanupModInstContainer(PlugInModInsts);
63
0
  }
64
65
  /// ======= Functions can be called before the instantiated stage. =======
66
  /// Register wasm modules and host modules.
67
  Expect<void> registerModule(std::string_view Name,
68
0
                              const std::filesystem::path &Path) {
69
0
    std::unique_lock Lock(Mutex);
70
0
    return unsafeRegisterModule(Name, Path);
71
0
  }
72
0
  Expect<void> registerModule(std::string_view Name, Span<const Byte> Code) {
73
0
    std::unique_lock Lock(Mutex);
74
0
    return unsafeRegisterModule(Name, Code);
75
0
  }
76
  Expect<void> registerModule(std::string_view Name,
77
0
                              const AST::Module &Module) {
78
0
    std::unique_lock Lock(Mutex);
79
0
    return unsafeRegisterModule(Name, Module);
80
0
  }
81
  Expect<void>
82
0
  registerModule(const Runtime::Instance::ModuleInstance &ModInst) {
83
0
    return registerModule(ModInst.getModuleName(), ModInst);
84
0
  }
85
  Expect<void>
86
  registerModule(std::string_view Name,
87
0
                 const Runtime::Instance::ModuleInstance &ModInst) {
88
0
    std::unique_lock Lock(Mutex);
89
0
    return unsafeRegisterModule(Name, ModInst);
90
0
  }
91
92
  /// Unregister a named module instance.
93
0
  Expect<void> unregisterModule(std::string_view Name) {
94
0
    std::unique_lock Lock(Mutex);
95
0
    return unsafeUnregisterModule(Name);
96
0
  }
97
98
  /// Rapidly load, validate, instantiate, and run wasm function.
99
  Expect<std::vector<std::pair<ValVariant, ValType>>>
100
  runWasmFile(const std::filesystem::path &Path, std::string_view Func,
101
              Span<const ValVariant> Params = {},
102
0
              Span<const ValType> ParamTypes = {}) {
103
0
    std::unique_lock Lock(Mutex);
104
0
    return unsafeRunWasmFile(Path, Func, Params, ParamTypes);
105
0
  }
106
  Expect<std::vector<std::pair<ValVariant, ValType>>>
107
  runWasmFile(Span<const Byte> Code, std::string_view Func,
108
              Span<const ValVariant> Params = {},
109
0
              Span<const ValType> ParamTypes = {}) {
110
0
    std::unique_lock Lock(Mutex);
111
0
    return unsafeRunWasmFile(Code, Func, Params, ParamTypes);
112
0
  }
113
  Expect<std::vector<std::pair<ValVariant, ValType>>>
114
  runWasmFile(const AST::Module &Module, std::string_view Func,
115
              Span<const ValVariant> Params = {},
116
0
              Span<const ValType> ParamTypes = {}) {
117
0
    std::unique_lock Lock(Mutex);
118
0
    return unsafeRunWasmFile(Module, Func, Params, ParamTypes);
119
0
  }
120
121
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
122
  asyncRunWasmFile(const std::filesystem::path &Path, std::string_view Func,
123
                   Span<const ValVariant> Params = {},
124
                   Span<const ValType> ParamTypes = {});
125
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
126
  asyncRunWasmFile(Span<const Byte> Code, std::string_view Func,
127
                   Span<const ValVariant> Params = {},
128
                   Span<const ValType> ParamTypes = {});
129
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
130
  asyncRunWasmFile(const AST::Module &Module, std::string_view Func,
131
                   Span<const ValVariant> Params = {},
132
                   Span<const ValType> ParamTypes = {});
133
134
  /// Let runtimeTool check which arguments should be prepared.
135
0
  bool holdsModule() {
136
0
    if (ActiveModInst) {
137
0
      return true;
138
0
    }
139
0
    return false;
140
0
  }
141
0
  bool holdsComponent() {
142
0
    if (ActiveCompInst) {
143
0
      return true;
144
0
    }
145
0
    return false;
146
0
  }
147
148
  /// Load given wasm file, wasm bytecode, or wasm module.
149
0
  Expect<void> loadWasm(const std::filesystem::path &Path) {
150
0
    std::unique_lock Lock(Mutex);
151
0
    return unsafeLoadWasm(Path);
152
0
  }
153
0
  Expect<void> loadWasm(Span<const Byte> Code) {
154
0
    std::unique_lock Lock(Mutex);
155
0
    return unsafeLoadWasm(Code);
156
0
  }
157
0
  Expect<void> loadWasm(const AST::Module &Module) {
158
0
    std::unique_lock Lock(Mutex);
159
0
    return unsafeLoadWasm(Module);
160
0
  }
161
162
  /// ======= Functions can be called after the loaded stage. =======
163
  /// Validate loaded wasm module.
164
0
  Expect<void> validate() {
165
0
    std::unique_lock Lock(Mutex);
166
0
    return unsafeValidate();
167
0
  }
168
169
  /// Force-set the VM stage to Validated for a loaded component without
170
  /// actually running validation. Only used in spec tests and will be removed
171
  /// when component-model is fully supported.
172
  /// Returns failure if no component is loaded.
173
0
  Expect<void> forceValidateForComponent() {
174
0
    std::unique_lock Lock(Mutex);
175
0
    if (Stage < VMStage::Loaded || !Comp) {
176
0
      return Unexpect(ErrCode::Value::WrongVMWorkflow);
177
0
    }
178
0
    Comp->setIsValidated();
179
0
    Stage = VMStage::Validated;
180
0
    return {};
181
0
  }
182
183
  /// ======= Functions can be called after the validated stage. =======
184
  /// Instantiate validated wasm module.
185
0
  Expect<void> instantiate() {
186
0
    std::unique_lock Lock(Mutex);
187
0
    return unsafeInstantiate();
188
0
  }
189
190
  /// ======= Functions can be called after the instantiated stage. =======
191
  /// Execute wasm with given input.
192
  Expect<std::vector<std::pair<ValVariant, ValType>>>
193
  execute(std::string_view Func, Span<const ValVariant> Params = {},
194
0
          Span<const ValType> ParamTypes = {}) {
195
0
    std::shared_lock Lock(Mutex);
196
0
    return unsafeExecute(Func, Params, ParamTypes);
197
0
  }
198
199
  /// Execute a function of a registered module with the given input.
200
  Expect<std::vector<std::pair<ValVariant, ValType>>>
201
  execute(std::string_view ModName, std::string_view Func,
202
          Span<const ValVariant> Params = {},
203
0
          Span<const ValType> ParamTypes = {}) {
204
0
    std::shared_lock Lock(Mutex);
205
0
    return unsafeExecute(ModName, Func, Params, ParamTypes);
206
0
  }
207
208
  /// Execute a component function with the given input.
209
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
210
  executeComponent(std::string_view Func,
211
                   Span<const ComponentValVariant> Params = {},
212
0
                   Span<const ComponentValType> ParamTypes = {}) {
213
0
    std::shared_lock Lock(Mutex);
214
0
    return unsafeExecuteComponent(Func, Params, ParamTypes);
215
0
  }
216
217
  /// Execute a function of a registered component with the given input.
218
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
219
  executeComponent(std::string_view CompName, std::string_view Func,
220
                   Span<const ComponentValVariant> Params = {},
221
0
                   Span<const ComponentValType> ParamTypes = {}) {
222
0
    std::shared_lock Lock(Mutex);
223
0
    return unsafeExecuteComponent(CompName, Func, Params, ParamTypes);
224
0
  }
225
226
  /// Asynchronously execute Wasm with the given input.
227
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
228
  asyncExecute(std::string_view Func, Span<const ValVariant> Params = {},
229
               Span<const ValType> ParamTypes = {});
230
231
  /// Asynchronously execute a function of a registered module with the given
232
  /// input.
233
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
234
  asyncExecute(std::string_view ModName, std::string_view Func,
235
               Span<const ValVariant> Params = {},
236
               Span<const ValType> ParamTypes = {});
237
238
  /// Asynchronously execute a component function with the given input.
239
  Async<Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>>
240
  asyncExecuteComponent(std::string_view Func,
241
                        Span<const ComponentValVariant> Params = {},
242
                        Span<const ComponentValType> ParamTypes = {});
243
244
  /// Asynchronously execute a function of a registered component with the given
245
  /// input.
246
  Async<Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>>
247
  asyncExecuteComponent(std::string_view ModName, std::string_view Func,
248
                        Span<const ComponentValVariant> Params = {},
249
                        Span<const ComponentValType> ParamTypes = {});
250
251
  /// Stop execution
252
0
  void stop() noexcept { ExecutorEngine.stop(); }
253
254
  /// ======= Functions which are stageless. =======
255
  /// Clean up VM status
256
0
  void cleanup() {
257
0
    std::unique_lock Lock(Mutex);
258
0
    return unsafeCleanup();
259
0
  }
260
261
  /// Get list of callable functions and corresponding function types.
262
  std::vector<std::pair<std::string, const AST::FunctionType &>>
263
0
  getFunctionList() const {
264
0
    std::shared_lock Lock(Mutex);
265
0
    return unsafeGetFunctionList();
266
0
  }
267
268
  /// Get list of callable component functions and corresponding function types.
269
  std::vector<std::pair<std::string, const AST::Component::FuncType &>>
270
0
  getComponentFunctionList() const {
271
0
    std::shared_lock Lock(Mutex);
272
0
    return unsafeGetComponentFunctionList();
273
0
  }
274
275
  /// Get pre-registered module instance by configuration.
276
  Runtime::Instance::ModuleInstance *
277
0
  getImportModule(const HostRegistration Type) const {
278
0
    std::shared_lock Lock(Mutex);
279
0
    return unsafeGetImportModule(Type);
280
0
  }
281
282
  /// Get current instantiated module instance.
283
0
  const Runtime::Instance::ModuleInstance *getActiveModule() const {
284
0
    std::shared_lock Lock(Mutex);
285
0
    return unsafeGetActiveModule();
286
0
  }
287
288
  /// Getter for the store set in the VM.
289
0
  Runtime::StoreManager &getStoreManager() noexcept { return StoreRef; }
290
0
  const Runtime::StoreManager &getStoreManager() const noexcept {
291
0
    return StoreRef;
292
0
  }
293
294
  /// Getter for the loader in the VM.
295
0
  Loader::Loader &getLoader() noexcept { return LoaderEngine; }
296
297
  /// Getter for the validator in the VM.
298
0
  Validator::Validator &getValidator() noexcept { return ValidatorEngine; }
299
300
  /// Getter for the executor in the VM.
301
0
  Executor::Executor &getExecutor() noexcept { return ExecutorEngine; }
302
303
  /// Getter for statistics.
304
0
  Statistics::Statistics &getStatistics() noexcept { return Stat; }
305
306
#ifdef WASMEDGE_USE_LLVM
307
  /// Getter for the number of lazily compiled functions.
308
0
  uint32_t getLazyCompiledFuncCount() const noexcept {
309
0
    return LazyEngine ? LazyEngine->compiledFunctionCount() : 0;
310
0
  }
311
#endif
312
313
private:
314
  /// Release and terminate all module instances in a sequence or map
315
  /// container, then clear the container.
316
  template <typename ContainerT>
317
0
  void cleanupModInstContainer(ContainerT &Container) {
318
0
    for (auto &Item : Container) {
319
0
      Runtime::Instance::ModuleInstance *ModInst;
320
      if constexpr (std::is_same_v<
321
                        typename ContainerT::value_type,
322
0
                        std::unique_ptr<Runtime::Instance::ModuleInstance>>) {
323
0
        ModInst = Item.release();
324
0
      } else {
325
0
        ModInst = Item.second.release();
326
0
      }
327
0
      if (ModInst) {
328
0
        ModInst->terminate();
329
0
      }
330
0
    }
331
0
    Container.clear();
332
0
  }
Unexecuted instantiation: void WasmEdge::VM::VM::cleanupModInstContainer<std::__1::vector<std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> >, std::__1::allocator<std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> > > > >(std::__1::vector<std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> >, std::__1::allocator<std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> > > >&)
Unexecuted instantiation: void WasmEdge::VM::VM::cleanupModInstContainer<std::__1::unordered_map<WasmEdge::HostRegistration, std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> >, std::__1::hash<WasmEdge::HostRegistration>, std::__1::equal_to<WasmEdge::HostRegistration>, std::__1::allocator<std::__1::pair<WasmEdge::HostRegistration const, std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> > > > > >(std::__1::unordered_map<WasmEdge::HostRegistration, std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> >, std::__1::hash<WasmEdge::HostRegistration>, std::__1::equal_to<WasmEdge::HostRegistration>, std::__1::allocator<std::__1::pair<WasmEdge::HostRegistration const, std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> > > > >&)
333
334
  Expect<void> unsafeRegisterModule(std::string_view Name,
335
                                    const std::filesystem::path &Path);
336
  Expect<void> unsafeRegisterModule(std::string_view Name,
337
                                    Span<const Byte> Code);
338
  Expect<void> unsafeRegisterModule(std::string_view Name,
339
                                    const AST::Module &Module);
340
  Expect<void> unsafeRegisterModule(std::string_view Name,
341
                                    std::shared_ptr<AST::Module> Module);
342
  Expect<void>
343
  unsafeRegisterModule(std::string_view Name,
344
                       const Runtime::Instance::ModuleInstance &ModInst);
345
346
  Expect<void> unsafeUnregisterModule(std::string_view Name);
347
348
  Expect<std::vector<std::pair<ValVariant, ValType>>>
349
  unsafeRunWasmFile(const std::filesystem::path &Path, std::string_view Func,
350
                    Span<const ValVariant> Params = {},
351
                    Span<const ValType> ParamTypes = {});
352
  Expect<std::vector<std::pair<ValVariant, ValType>>>
353
  unsafeRunWasmFile(Span<const Byte> Code, std::string_view Func,
354
                    Span<const ValVariant> Params = {},
355
                    Span<const ValType> ParamTypes = {});
356
  Expect<std::vector<std::pair<ValVariant, ValType>>>
357
  unsafeRunWasmFile(const AST::Module &Module, std::string_view Func,
358
                    Span<const ValVariant> Params = {},
359
                    Span<const ValType> ParamTypes = {});
360
  Expect<std::vector<std::pair<ValVariant, ValType>>>
361
  unsafeRunWasmFile(const AST::Component::Component &Component,
362
                    std::string_view Func, Span<const ValVariant> Params = {},
363
                    Span<const ValType> ParamTypes = {});
364
365
  Expect<void> unsafeLoadWasm(const std::filesystem::path &Path);
366
  Expect<void> unsafeLoadWasm(Span<const Byte> Code);
367
  Expect<void> unsafeLoadWasm(const AST::Module &Module);
368
369
  Expect<void> unsafeValidate();
370
371
  Expect<void> unsafeInstantiate();
372
373
  /// In JIT or lazy JIT mode, compile and attach an executable to the loaded
374
  /// module if it does not carry one yet. Eager JIT compilation failures fall
375
  /// back to the interpreter; without LLVM support this only logs a warning.
376
  Expect<void> unsafeLoadJITExecutable();
377
378
  Expect<std::vector<std::pair<ValVariant, ValType>>>
379
  unsafeExecute(std::string_view Func, Span<const ValVariant> Params = {},
380
                Span<const ValType> ParamTypes = {});
381
  Expect<std::vector<std::pair<ValVariant, ValType>>>
382
  unsafeExecute(std::string_view Mod, std::string_view Func,
383
                Span<const ValVariant> Params = {},
384
                Span<const ValType> ParamTypes = {});
385
386
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
387
  unsafeExecuteComponent(std::string_view Func,
388
                         Span<const ComponentValVariant> Params = {},
389
                         Span<const ComponentValType> ParamTypes = {});
390
391
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
392
  unsafeExecuteComponent(std::string_view Comp, std::string_view Func,
393
                         Span<const ComponentValVariant> Params = {},
394
                         Span<const ComponentValType> ParamTypes = {});
395
396
  void unsafeCleanup();
397
398
  std::vector<std::pair<std::string, const AST::FunctionType &>>
399
  unsafeGetFunctionList() const;
400
401
  std::vector<std::pair<std::string, const AST::Component::FuncType &>>
402
  unsafeGetComponentFunctionList() const;
403
404
  Runtime::Instance::ModuleInstance *
405
  unsafeGetImportModule(const HostRegistration Type) const;
406
407
  const Runtime::Instance::ModuleInstance *unsafeGetActiveModule() const;
408
409
  enum class VMStage : uint8_t { Inited, Loaded, Validated, Instantiated };
410
  enum class WasmUnitKind : uint8_t { Module, Component };
411
412
  /// Store a parsed wasm unit into the matching slot and report its kind.
413
  /// The slot for the other kind keeps its previous content.
414
  WasmUnitKind
415
  unsafeStoreWasmUnit(std::variant<std::unique_ptr<AST::Component::Component>,
416
                                   std::unique_ptr<AST::Module>> &&Unit);
417
418
  /// Registering a module or running another wasm unit resets the active
419
  /// instantiation in the store, so the stage falls back to Validated and
420
  /// the instantiation must restart.
421
0
  void unsafeRevertStageToValidated() {
422
0
    if (Stage == VMStage::Instantiated) {
423
0
      Stage = VMStage::Validated;
424
0
    }
425
0
  }
426
427
  void unsafeInitVM();
428
  void unsafeLoadBuiltInHosts();
429
  void unsafeLoadPlugInHosts();
430
  void unsafeRegisterBuiltInHosts();
431
  void unsafeRegisterPlugInHosts();
432
433
  /// Helper function for execution.
434
  Expect<std::vector<std::pair<ValVariant, ValType>>>
435
  unsafeExecute(const Runtime::Instance::ModuleInstance *ModInst,
436
                std::string_view Func, Span<const ValVariant> Params = {},
437
                Span<const ValType> ParamTypes = {});
438
439
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
440
  unsafeExecuteComponent(const Runtime::Instance::ComponentInstance *CompInst,
441
                         std::string_view Func,
442
                         Span<const ComponentValVariant> Params = {},
443
                         Span<const ComponentValType> ParamTypes = {});
444
445
  /// \name VM environment.
446
  /// @{
447
  const Configure Conf;
448
  Statistics::Statistics Stat;
449
  VMStage Stage;
450
  mutable std::shared_mutex Mutex;
451
  /// @}
452
453
  /// \name VM components.
454
  /// @{
455
  Loader::Loader LoaderEngine;
456
  Validator::Validator ValidatorEngine;
457
#ifdef WASMEDGE_USE_LLVM
458
  /// Lazy JIT engine. Created only when the run mode is LazyJIT. Declared
459
  /// before the executor so it outlives the executor-registered lazy
460
  /// compilation callback that references it.
461
  std::unique_ptr<LLVM::LazyJITEngine> LazyEngine;
462
#endif
463
  Executor::Executor ExecutorEngine;
464
  /// @}
465
466
  /// \name VM Storage.
467
  /// @{
468
  /// Loaded AST module.
469
  std::shared_ptr<AST::Module> Mod;
470
  std::unique_ptr<AST::Component::Component> Comp;
471
  /// Active module instance.
472
  std::unique_ptr<Runtime::Instance::ModuleInstance> ActiveModInst;
473
  std::unique_ptr<Runtime::Instance::ComponentInstance> ActiveCompInst;
474
  /// Registered module instances by user.
475
  std::vector<std::unique_ptr<Runtime::Instance::ModuleInstance>> RegModInsts;
476
  /// Built-in module instances mapped to the configurations. For WASI.
477
  std::unordered_map<HostRegistration,
478
                     std::unique_ptr<Runtime::Instance::ModuleInstance>>
479
      BuiltInModInsts;
480
  /// Loaded module instances from plug-ins.
481
  std::vector<std::unique_ptr<Runtime::Instance::ModuleInstance>>
482
      PlugInModInsts;
483
  std::vector<std::unique_ptr<Runtime::Instance::ComponentInstance>>
484
      PlugInCompInsts;
485
  /// Self-owned store (nullptr if an outside store is assigned in constructor).
486
  std::unique_ptr<Runtime::StoreManager> Store;
487
  /// Reference to the store.
488
  Runtime::StoreManager &StoreRef;
489
  /// @}
490
};
491
492
} // namespace VM
493
} // namespace WasmEdge