Coverage Report

Created: 2026-06-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/executor/executor.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "executor/executor.h"
5
6
#include "common/errinfo.h"
7
#include "common/spdlog.h"
8
#include "system/stacktrace.h"
9
10
using namespace std::literals;
11
12
namespace WasmEdge {
13
namespace Executor {
14
15
/// Instantiate a WASM Module. See "include/executor/executor.h".
16
Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>>
17
Executor::instantiateModule(Runtime::StoreManager &StoreMgr,
18
0
                            const AST::Module &Mod) {
19
0
  return instantiate(StoreMgr, Mod).map_error([this](auto E) {
20
    // If statistics are enabled, dump them here.
21
    // When an error occurs, subsequent execution will not run.
22
0
    if (Stat) {
23
0
      Stat->dumpToLog(Conf);
24
0
    }
25
0
    return E;
26
0
  });
27
0
}
28
29
/// Register a named WASM module. See "include/executor/executor.h".
30
Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>>
31
Executor::registerModule(Runtime::StoreManager &StoreMgr,
32
0
                         const AST::Module &Mod, std::string_view Name) {
33
0
  return instantiate(StoreMgr, Mod, Name).map_error([this](auto E) {
34
    // If statistics are enabled, dump them here.
35
    // When an error occurs, subsequent execution will not run.
36
0
    if (Stat) {
37
0
      Stat->dumpToLog(Conf);
38
0
    }
39
0
    return E;
40
0
  });
41
0
}
42
43
/// Register an instantiated module. See "include/executor/executor.h".
44
Expect<void>
45
Executor::registerModule(Runtime::StoreManager &StoreMgr,
46
0
                         const Runtime::Instance::ModuleInstance &ModInst) {
47
0
  return StoreMgr.registerModule(&ModInst).map_error([](auto E) {
48
0
    spdlog::error(E);
49
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
50
0
    return E;
51
0
  });
52
0
}
53
54
/// Register an instantiated module under an alias name.
55
Expect<void>
56
Executor::registerModule(Runtime::StoreManager &StoreMgr,
57
                         const Runtime::Instance::ModuleInstance &ModInst,
58
0
                         std::string_view Name) {
59
0
  return StoreMgr.registerModule(&ModInst, Name).map_error([](auto E) {
60
0
    spdlog::error(E);
61
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
62
0
    return E;
63
0
  });
64
0
}
65
66
/// Instantiate a Component. See "include/executor/executor.h".
67
Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>>
68
Executor::instantiateComponent(Runtime::StoreManager &StoreMgr,
69
0
                               const AST::Component::Component &Comp) {
70
0
  return instantiate(StoreMgr, Comp);
71
0
}
72
73
/// Register a named Component. See "include/executor/executor.h".
74
Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>>
75
Executor::registerComponent(Runtime::StoreManager &StoreMgr,
76
                            const AST::Component::Component &Comp,
77
0
                            std::string_view Name) {
78
0
  return instantiate(StoreMgr, Comp, Name);
79
0
}
80
81
/// Register an instantiated Component. See "include/executor/executor.h".
82
Expect<void> Executor::registerComponent(
83
    Runtime::StoreManager &StoreMgr,
84
0
    const Runtime::Instance::ComponentInstance &CompInst) {
85
0
  return StoreMgr.registerComponent(&CompInst).map_error([](auto E) {
86
0
    spdlog::error(E);
87
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
88
0
    return E;
89
0
  });
90
0
}
91
92
/// Register a host function which will be invoked before calling a
93
/// host function.
94
Expect<void> Executor::registerPreHostFunction(
95
0
    void *HostData = nullptr, std::function<void(void *)> HostFunc = nullptr) {
96
0
  HostFuncHelper.setPreHost(HostData, HostFunc);
97
0
  return {};
98
0
}
99
100
/// Register a host function which will be invoked after calling a
101
/// host function.
102
Expect<void> Executor::registerPostHostFunction(
103
0
    void *HostData = nullptr, std::function<void(void *)> HostFunc = nullptr) {
104
0
  HostFuncHelper.setPostHost(HostData, HostFunc);
105
0
  return {};
106
0
}
107
108
/// Invoke function. See "include/executor/executor.h".
109
Expect<std::vector<std::pair<ValVariant, ValType>>>
110
Executor::invoke(const Runtime::Instance::FunctionInstance *FuncInst,
111
                 Span<const ValVariant> Params,
112
0
                 Span<const ValType> ParamTypes) {
113
0
  if (unlikely(FuncInst == nullptr)) {
114
0
    spdlog::error(ErrCode::Value::FuncNotFound);
115
0
    return Unexpect(ErrCode::Value::FuncNotFound);
116
0
  }
117
118
  // Matching arguments and function type.
119
0
  const auto &FuncType = FuncInst->getFuncType();
120
0
  const auto &PTypes = FuncType.getParamTypes();
121
0
  const auto &RTypes = FuncType.getReturnTypes();
122
  // The defined type list may be empty if the function is an independent
123
  // function instance, that is, the module instance will be nullptr. In this
124
  // case, all value types are number types or abstract heap types.
125
  //
126
  // If a function belongs to a component instance, its type should already be
127
  // converted, so the type list is not needed.
128
0
  WasmEdge::Span<const WasmEdge::AST::SubType *const> TypeList = {};
129
0
  if (FuncInst->getModule()) {
130
0
    TypeList = FuncInst->getModule()->getTypeList();
131
0
  }
132
0
  if (!AST::TypeMatcher::matchTypes(TypeList, ParamTypes, PTypes)) {
133
0
    spdlog::error(ErrCode::Value::FuncSigMismatch);
134
0
    spdlog::error(ErrInfo::InfoMismatch(
135
0
        PTypes, RTypes, std::vector(ParamTypes.begin(), ParamTypes.end()),
136
0
        RTypes));
137
0
    return Unexpect(ErrCode::Value::FuncSigMismatch);
138
0
  }
139
140
  // Check the reference value validation.
141
0
  for (uint32_t I = 0; I < ParamTypes.size(); ++I) {
142
0
    if (ParamTypes[I].isRefType() && (!ParamTypes[I].isNullableRefType() &&
143
0
                                      Params[I].get<RefVariant>().isNull())) {
144
0
      spdlog::error(ErrCode::Value::NonNullRequired);
145
0
      spdlog::error("    Cannot pass a null reference as argument of {}."sv,
146
0
                    ParamTypes[I]);
147
0
      return Unexpect(ErrCode::Value::NonNullRequired);
148
0
    }
149
0
  }
150
151
0
  Runtime::StackManager StackMgr;
152
153
  // Call runFunction.
154
0
  EXPECTED_TRY(runFunction(StackMgr, *FuncInst, Params).map_error([](auto E) {
155
0
    if (E != ErrCode::Value::Terminated) {
156
0
      dumpStackTrace(Span<const uint32_t>{StackTrace}.first(StackTraceSize));
157
0
    }
158
0
    return E;
159
0
  }));
160
161
  // Get return values.
162
0
  std::vector<std::pair<ValVariant, ValType>> Returns(RTypes.size());
163
0
  for (uint32_t I = 0; I < RTypes.size(); ++I) {
164
0
    auto Val = StackMgr.pop();
165
0
    const auto &RType = RTypes[RTypes.size() - I - 1];
166
0
    if (RType.isRefType()) {
167
      // For the reference type cases of the return values, they should be
168
      // transformed into abstract heap types due to the opaque of type indices.
169
0
      auto &RefType = Val.get<RefVariant>().getType();
170
0
      if (RefType.isExternalized()) {
171
        // First handle the forced externalized value type case.
172
0
        RefType = ValType(TypeCode::Ref, TypeCode::ExternRef);
173
0
      }
174
0
      if (!RefType.isAbsHeapType()) {
175
        // The instance must not be nullptr because the null references are
176
        // already dynamic typed into the top abstract heap type.
177
0
        auto *Inst =
178
0
            Val.get<RefVariant>().getPtr<Runtime::Instance::CompositeBase>();
179
0
        assuming(Inst);
180
        // The ModInst may be nullptr only in the independent host function
181
        // instance. Therefore the module instance here must not be nullptr
182
        // because the independent host function instance cannot be imported and
183
        // be referred by instructions.
184
0
        const auto *ModInst = Inst->getModule();
185
0
        const auto *DefType = *ModInst->getType(RefType.getTypeIndex());
186
0
        RefType =
187
0
            ValType(RefType.getCode(), DefType->getCompositeType().expand());
188
0
      }
189
      // Should use the value type from the reference here due to the dynamic
190
      // typing rule of the null references.
191
0
      Returns[RTypes.size() - I - 1] = std::make_pair(Val, RefType);
192
0
    } else {
193
      // For the number type cases of the return values, the unused bits should
194
      // be erased due to the security issue.
195
0
      cleanNumericVal(Val, RType);
196
0
      Returns[RTypes.size() - I - 1] = std::make_pair(Val, RType);
197
0
    }
198
0
  }
199
200
  // After execution, the value stack size should be 0.
201
0
  assuming(StackMgr.size() == 0);
202
0
  return Returns;
203
0
}
204
205
/// Async invoke function. See "include/executor/executor.h".
206
Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
207
Executor::asyncInvoke(const Runtime::Instance::FunctionInstance *FuncInst,
208
                      Span<const ValVariant> Params,
209
0
                      Span<const ValType> ParamTypes) {
210
0
  Expect<std::vector<std::pair<ValVariant, ValType>>> (Executor::*FPtr)(
211
0
      const Runtime::Instance::FunctionInstance *, Span<const ValVariant>,
212
0
      Span<const ValType>) = &Executor::invoke;
213
0
  return {FPtr, *this, FuncInst, std::vector(Params.begin(), Params.end()),
214
0
          std::vector(ParamTypes.begin(), ParamTypes.end())};
215
0
}
216
217
/// Invoke component function. See "include/executor/executor.h".
218
Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
219
Executor::invoke(const Runtime::Instance::Component::FunctionInstance *FuncInst,
220
                 Span<const ComponentValVariant> Params,
221
0
                 Span<const ComponentValType> ParamTypes) {
222
0
  if (unlikely(FuncInst == nullptr)) {
223
0
    spdlog::error(ErrCode::Value::FuncNotFound);
224
0
    return Unexpect(ErrCode::Value::FuncNotFound);
225
0
  }
226
227
  // Matching arguments and function type.
228
  // TODO: COMPONENT - type matching.
229
  // const auto &FuncType = FuncInst->getFuncType();
230
  // const auto PTypes = FuncType.getParamList();
231
0
  const auto &ExpectedFuncType = FuncInst->getFuncType();
232
0
  const size_t ExpectedArity = ExpectedFuncType.getParamList().size();
233
0
  if (Params.size() != ParamTypes.size() || ParamTypes.size() < ExpectedArity) {
234
0
    spdlog::error(ErrCode::Value::FuncSigMismatch);
235
0
    spdlog::error("    expected {} argument(s), got {}"sv, ExpectedArity,
236
0
                  ParamTypes.size());
237
0
    return Unexpect(ErrCode::Value::FuncSigMismatch);
238
0
  }
239
240
  // Convert the component params into core WASM params.
241
0
  auto *ReallocFuncInst = FuncInst->getAllocFunction();
242
0
  auto *MemInst = FuncInst->getMemoryInstance();
243
0
  std::vector<ValVariant> CoreWASMArgs =
244
0
      convValsToCoreWASM(Params, ParamTypes, ReallocFuncInst, MemInst);
245
246
  // Call runFunction.
247
0
  auto *CoreFuncInst = FuncInst->getLowerFunction();
248
0
  assuming(CoreFuncInst);
249
0
  const auto &CoreFuncType = CoreFuncInst->getFuncType();
250
  // TODO: COMPONENT - check the ABI types between core functype and args.
251
0
  EXPECTED_TRY(auto CoreWASMReturns, invoke(CoreFuncInst, CoreWASMArgs,
252
0
                                            CoreFuncType.getParamTypes()));
253
254
  // Get return values.
255
0
  std::vector<ComponentValType> ReturnTypes;
256
0
  for (const auto &Type : FuncInst->getFuncType().getResultList()) {
257
0
    ReturnTypes.push_back(Type.getValType());
258
0
  }
259
0
  EXPECTED_TRY(auto Returns,
260
0
               convValsToComponent(CoreWASMReturns, ReturnTypes, MemInst));
261
0
  assuming(Returns.size() == ReturnTypes.size());
262
0
  return Returns;
263
0
}
264
265
} // namespace Executor
266
} // namespace WasmEdge