Coverage Report

Created: 2026-06-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/runtime/storemgr.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- wasmedge/runtime/storemgr.h - Store Manager definition ------------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file contains the definition of Store Manager.
12
///
13
//===----------------------------------------------------------------------===//
14
#pragma once
15
16
#include "runtime/instance/component/component.h"
17
#include "runtime/instance/module.h"
18
19
#include <mutex>
20
#include <shared_mutex>
21
#include <vector>
22
23
namespace WasmEdge {
24
25
namespace Executor {
26
class Executor;
27
}
28
29
namespace Runtime {
30
31
class StoreManager {
32
public:
33
0
  StoreManager() = default;
34
0
  ~StoreManager() {
35
    // When destroying this store manager, unlink all the registered module
36
    // instances.
37
0
    reset();
38
0
  }
39
40
  /// Get the length of the list of registered modules.
41
0
  uint32_t getModuleListSize() const noexcept {
42
0
    std::shared_lock Lock(Mutex);
43
0
    return static_cast<uint32_t>(NamedMod.size());
44
0
  }
45
46
  /// Get list of registered modules.
47
0
  template <typename CallbackT> auto getModuleList(CallbackT &&CallBack) const {
48
0
    std::shared_lock Lock(Mutex);
49
0
    return std::forward<CallbackT>(CallBack)(NamedMod);
50
0
  }
Unexecuted instantiation: auto WasmEdge::Runtime::StoreManager::getModuleList<WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}>(WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}) const
Unexecuted instantiation: wasmedge.cpp:auto WasmEdge::Runtime::StoreManager::getModuleList<WasmEdge_StoreListModule::$_0>(WasmEdge_StoreListModule::$_0&&) const
Unexecuted instantiation: wasmedge.cpp:auto WasmEdge::Runtime::StoreManager::getModuleList<WasmEdge_VMListRegisteredModule::$_0>(WasmEdge_VMListRegisteredModule::$_0&&) const
Unexecuted instantiation: module.cpp:auto WasmEdge::Runtime::StoreManager::getModuleList<WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}>(WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}) const
51
52
  /// Run Callback with the named module instance (or nullptr) while holding the
53
  /// shared lock, so the caller can pin a dependency before a concurrent
54
  /// unregisterModule destroys it.
55
  template <typename CallbackT>
56
0
  auto withModuleLocked(std::string_view Name, CallbackT &&Callback) const {
57
0
    return getModuleList([&](const auto &Mods) {
58
0
      const Instance::ModuleInstance *Found = nullptr;
59
0
      if (auto Iter = Mods.find(Name); likely(Iter != Mods.cend())) {
60
0
        Found = Iter->second;
61
0
      }
62
0
      return std::forward<CallbackT>(Callback)(Found);
63
0
    });
Unexecuted instantiation: auto WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}::operator()<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, WasmEdge::Runtime::Instance::ModuleInstance const*, std::__1::less<void>, std::__1::map<std::__1::pair<std::__1::allocator const, WasmEdge::Runtime::Instance::ModuleInstance const*> > > >(WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const) const
Unexecuted instantiation: module.cpp:auto WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}::operator()<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, WasmEdge::Runtime::Instance::ModuleInstance const*, std::__1::less<void>, std::__1::map<std::__1::pair<std::__1::allocator const, WasmEdge::Runtime::Instance::ModuleInstance const*> > > >(WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const) const
64
0
  }
Unexecuted instantiation: auto WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const
Unexecuted instantiation: module.cpp:auto WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const
65
66
  /// Find module by name. Returns the pointer with the lock already released;
67
  /// use withModuleLocked to pin or dereference the result race-free.
68
0
  const Instance::ModuleInstance *findModule(std::string_view Name) const {
69
0
    return withModuleLocked(
70
0
        Name, [](const Instance::ModuleInstance *Found) { return Found; });
71
0
  }
72
73
  /// Find component by name.
74
  const Instance::ComponentInstance *
75
0
  findComponent(std::string_view Name) const {
76
0
    std::shared_lock Lock(Mutex);
77
0
    if (auto Iter = NamedComp.find(Name); likely(Iter != NamedComp.cend())) {
78
0
      return Iter->second;
79
0
    }
80
0
    return nullptr;
81
0
  }
82
83
  /// Reset this store manager and unlink all the registered module instances.
84
0
  void reset() noexcept {
85
0
    std::unique_lock Lock(Mutex);
86
0
    for (auto &&[Name, ModInst] : NamedMod) {
87
0
      (const_cast<Instance::ModuleInstance *>(ModInst))
88
0
          ->unlinkStore(this, Name);
89
0
    }
90
0
    NamedMod.clear();
91
0
    NamedComp.clear();
92
0
  }
93
94
  /// Register a named module in this store.
95
0
  Expect<void> registerModule(const Instance::ModuleInstance *ModInst) {
96
0
    return registerModule(ModInst, ModInst->getModuleName());
97
0
  }
98
99
  /// Register a module instance in this store under the given alias name.
100
  Expect<void> registerModule(const Instance::ModuleInstance *ModInst,
101
0
                              std::string_view Name) {
102
0
    std::unique_lock Lock(Mutex);
103
0
    auto Iter = NamedMod.find(Name);
104
0
    if (likely(Iter != NamedMod.cend())) {
105
0
      return Unexpect(ErrCode::Value::ModuleNameConflict);
106
0
    }
107
0
    NamedMod.emplace(std::string(Name), ModInst);
108
    // Link the module instance to this store manager.
109
0
    (const_cast<Instance::ModuleInstance *>(ModInst))
110
0
        ->linkStore(this, Name,
111
0
                    [](const Instance::ModuleInstance::LinkedStoreKey &Key,
112
0
                       const Instance::ModuleInstance *) {
113
                      // The unlink callback: erase the alias name from the
114
                      // store.
115
0
                      std::unique_lock CallbackLock(Key.first->Mutex);
116
0
                      (Key.first->NamedMod).erase(Key.second);
117
0
                    });
118
0
    return {};
119
0
  }
120
121
  /// Unregister a named module from this store.
122
0
  Expect<void> unregisterModule(std::string_view Name) {
123
0
    std::unique_lock Lock(Mutex);
124
0
    auto Iter = NamedMod.find(Name);
125
0
    if (Iter == NamedMod.cend()) {
126
0
      return Unexpect(ErrCode::Value::UnknownImport);
127
0
    }
128
0
    (const_cast<Instance::ModuleInstance *>(Iter->second))
129
0
        ->unlinkStore(this, Name);
130
0
    NamedMod.erase(Iter);
131
0
    return {};
132
0
  }
133
134
  /// Register a named component in this store.
135
0
  Expect<void> registerComponent(const Instance::ComponentInstance *CompInst) {
136
0
    std::unique_lock Lock(Mutex);
137
0
    auto Iter = NamedComp.find(CompInst->getComponentName());
138
0
    if (likely(Iter != NamedComp.cend())) {
139
0
      return Unexpect(ErrCode::Value::ModuleNameConflict);
140
0
    }
141
0
    NamedComp.emplace(CompInst->getComponentName(), CompInst);
142
0
    return {};
143
0
  }
144
145
private:
146
  friend class Executor::Executor;
147
148
  /// \name Mutex for thread-safe.
149
  mutable std::shared_mutex Mutex;
150
151
  /// Collect the instantiation failed module.
152
0
  void recycleModule(std::unique_ptr<Instance::ModuleInstance> &&Mod) {
153
0
    if (FailedMod) {
154
0
      auto *OldMod = FailedMod.release();
155
0
      if (OldMod) {
156
0
        OldMod->terminate();
157
0
      }
158
0
    }
159
0
    FailedMod = std::move(Mod);
160
0
  }
161
162
  /// \name Module name mapping.
163
  std::map<std::string, const Instance::ModuleInstance *, std::less<>> NamedMod;
164
  /// \name Component name mapping.
165
  std::map<std::string, const Instance::ComponentInstance *, std::less<>>
166
      NamedComp;
167
168
  /// \name Last instantiation failed module.
169
  /// According to the current spec, instances should remain referenceable even
170
  /// if instantiation failed. Therefore, store the failed module instance here
171
  /// to keep the instances alive.
172
  /// FIXME: Is this necessary to be a vector?
173
  std::unique_ptr<Instance::ModuleInstance> FailedMod;
174
};
175
176
} // namespace Runtime
177
} // namespace WasmEdge