Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/include/runtime/component/hostfunc.h
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
#pragma once
4
5
#include "ast/instruction.h"
6
#include "common/symbol.h"
7
#include "common/types.h"
8
9
#include <memory>
10
#include <numeric>
11
#include <string>
12
#include <vector>
13
14
namespace WasmEdge {
15
namespace Runtime {
16
namespace Component {
17
18
class HostFunctionBase {
19
public:
20
0
  HostFunctionBase() : FuncType{AST::FunctionType()} {}
21
0
  virtual ~HostFunctionBase() = default;
22
23
  /// Run host function body.
24
  virtual Expect<void> run(Span<const ValInterface> Args,
25
                           Span<ValInterface> Rets) = 0;
26
27
  /// Getter of function type.
28
0
  const AST::FunctionType &getFuncType() const noexcept { return FuncType; }
29
0
  AST::FunctionType &getFuncType() noexcept { return FuncType; }
30
31
protected:
32
  AST::FunctionType FuncType;
33
};
34
35
template <typename ArgT> struct convert {
36
  static ArgT run(const ValInterface &V) {
37
    return std::get<ValVariant>(V).template get<ArgT>();
38
  }
39
};
40
template <> struct convert<bool> {
41
0
  static bool run(const ValInterface &V) { return std::get<bool>(V); }
42
};
43
template <> struct convert<uint8_t> {
44
0
  static uint8_t run(const ValInterface &V) { return std::get<uint8_t>(V); }
45
};
46
template <> struct convert<uint16_t> {
47
0
  static uint16_t run(const ValInterface &V) { return std::get<uint16_t>(V); }
48
};
49
template <> struct convert<uint32_t> {
50
0
  static uint32_t run(const ValInterface &V) { return std::get<uint32_t>(V); }
51
};
52
template <> struct convert<uint64_t> {
53
0
  static uint64_t run(const ValInterface &V) { return std::get<uint64_t>(V); }
54
};
55
template <> struct convert<int8_t> {
56
0
  static int8_t run(const ValInterface &V) { return std::get<int8_t>(V); }
57
};
58
template <> struct convert<int16_t> {
59
0
  static int16_t run(const ValInterface &V) { return std::get<int16_t>(V); }
60
};
61
62
template <> struct convert<std::string> {
63
0
  static std::string run(const ValInterface &V) {
64
0
    return std::get<std::string>(V);
65
0
  }
66
};
67
template <typename T> struct convert<List<T>> {
68
  static List<T> run(const ValInterface &V) {
69
    auto *C = std::get<std::shared_ptr<ValComp>>(V).get();
70
    return *dynamic_cast<List<T> *>(C);
71
  }
72
};
73
template <typename... Types> struct convert<Record<Types...>> {
74
  static Record<Types...> run(const ValInterface &V) {
75
    auto *C = std::get<std::shared_ptr<ValComp>>(V).get();
76
    return *dynamic_cast<Record<Types...> *>(C);
77
  }
78
};
79
template <typename... Types> struct convert<Tuple<Types...>> {
80
  static Tuple<Types...> run(const ValInterface &V) {
81
    auto *C = std::get<std::shared_ptr<ValComp>>(V).get();
82
    return *dynamic_cast<Tuple<Types...> *>(C);
83
  }
84
};
85
template <typename T> struct convert<Option<T>> {
86
  static Option<T> run(const ValInterface &V) {
87
    auto *C = std::get<std::shared_ptr<ValComp>>(V).get();
88
    return *dynamic_cast<Option<T> *>(C);
89
  }
90
};
91
template <> struct convert<Enum> {
92
0
  static Enum run(const ValInterface &V) {
93
0
    auto *C = std::get<std::shared_ptr<ValComp>>(V).get();
94
0
    return *dynamic_cast<Enum *>(C);
95
0
  }
96
};
97
template <typename V, typename E> struct convert<Result<V, E>> {
98
  static Result<V, E> run(const ValInterface &Val) {
99
    auto *C = std::get<std::shared_ptr<ValComp>>(Val).get();
100
    return *dynamic_cast<Result<V, E> *>(C);
101
  }
102
};
103
104
template <typename ArgT> struct emplace {
105
  static void run(ValInterface &V, ArgT Arg) {
106
    std::get<ValVariant>(V).emplace<ArgT>(Arg);
107
  }
108
};
109
template <> struct emplace<bool> {
110
0
  static void run(ValInterface &V, bool Arg) { V.emplace<bool>(Arg); }
111
};
112
template <> struct emplace<uint8_t> {
113
0
  static void run(ValInterface &V, uint8_t Arg) { V.emplace<uint8_t>(Arg); }
114
};
115
template <> struct emplace<uint16_t> {
116
0
  static void run(ValInterface &V, uint16_t Arg) { V.emplace<uint16_t>(Arg); }
117
};
118
template <> struct emplace<uint32_t> {
119
0
  static void run(ValInterface &V, uint32_t Arg) { V.emplace<uint32_t>(Arg); }
120
};
121
template <> struct emplace<uint64_t> {
122
0
  static void run(ValInterface &V, uint64_t Arg) { V.emplace<uint64_t>(Arg); }
123
};
124
template <> struct emplace<int8_t> {
125
0
  static void run(ValInterface &V, int8_t Arg) { V.emplace<int8_t>(Arg); }
126
};
127
template <> struct emplace<int16_t> {
128
0
  static void run(ValInterface &V, int16_t Arg) { V.emplace<int16_t>(Arg); }
129
};
130
template <> struct emplace<std::string> {
131
0
  static void run(ValInterface &V, std::string Arg) {
132
0
    V.emplace<std::string>(Arg);
133
0
  }
134
};
135
template <typename T> struct emplace<List<T>> {
136
  static void run(ValInterface &V, List<T> Arg) {
137
    V.emplace<std::shared_ptr<ValComp>>(std::make_shared<List<T>>(Arg));
138
  }
139
};
140
template <typename... Types> struct emplace<Record<Types...>> {
141
  static void run(ValInterface &V, Record<Types...> Arg) {
142
    V.emplace<std::shared_ptr<ValComp>>(
143
        std::make_shared<Record<Types...>>(Arg));
144
  }
145
};
146
template <typename... Types> struct emplace<Tuple<Types...>> {
147
  static void run(ValInterface &V, Tuple<Types...> Arg) {
148
    V.emplace<std::shared_ptr<ValComp>>(std::make_shared<Tuple<Types...>>(Arg));
149
  }
150
};
151
template <typename T> struct emplace<Option<T>> {
152
  static void run(ValInterface &V, Option<T> Arg) {
153
    V.emplace<std::shared_ptr<ValComp>>(std::make_shared<Option<T>>(Arg));
154
  }
155
};
156
template <> struct emplace<Enum> {
157
0
  static void run(ValInterface &V, Enum Arg) {
158
0
    V.emplace<std::shared_ptr<ValComp>>(std::make_shared<Enum>(Arg));
159
0
  }
160
};
161
template <typename V, typename E> struct emplace<Result<V, E>> {
162
  static void run(ValInterface &Val, Result<V, E> Arg) {
163
    Val.emplace<std::shared_ptr<ValComp>>(std::make_shared<Result<V, E>>(Arg));
164
  }
165
};
166
template <typename... Types>
167
struct emplace<WasmEdge::Component::Variant<Types...>> {
168
  static void run(ValInterface &V, WasmEdge::Component::Variant<Types...> Arg) {
169
    V.emplace<std::shared_ptr<ValComp>>(
170
        std::make_shared<WasmEdge::Component::Variant<Types...>>(Arg));
171
  }
172
};
173
174
template <typename T> class HostFunction : public HostFunctionBase {
175
public:
176
  HostFunction() : HostFunctionBase() { initializeFuncType(); }
177
178
  Expect<void> run(Span<const ValInterface> Args,
179
                   Span<ValInterface> Rets) override {
180
    using F = FuncTraits<decltype(&T::body)>;
181
    if (unlikely(F::ArgsN != Args.size())) {
182
      return Unexpect(ErrCode::Value::FuncSigMismatch);
183
    }
184
    if (unlikely(F::RetsN != Rets.size())) {
185
      return Unexpect(ErrCode::Value::FuncSigMismatch);
186
    }
187
    return invoke(Args.first<F::ArgsN>(), Rets.first<F::RetsN>());
188
  }
189
190
protected:
191
  template <typename SpanA, typename SpanR>
192
  Expect<void> invoke(SpanA &&Args, SpanR &&Rets) {
193
    using F = FuncTraits<decltype(&T::body)>;
194
    using ArgsT = typename F::ArgsT;
195
196
    auto GeneralArguments = std::tie(*static_cast<T *>(this));
197
    auto ArgTuple = toTuple<ArgsT>(std::forward<SpanA>(Args),
198
                                   std::make_index_sequence<F::ArgsN>());
199
    auto FuncArgTuple =
200
        std::tuple_cat(std::move(GeneralArguments), std::move(ArgTuple));
201
    if constexpr (F::hasReturn) {
202
      EXPECTED_TRY(typename F::RetsT RetTuple,
203
                   std::apply(&T::body, std::move(FuncArgTuple)));
204
      fromTuple(std::forward<SpanR>(Rets), std::move(RetTuple),
205
                std::make_index_sequence<F::RetsN>());
206
    } else {
207
      EXPECTED_TRY(std::apply(&T::body, std::move(FuncArgTuple)));
208
    }
209
210
    return {};
211
  }
212
213
  void initializeFuncType() {
214
    auto &FuncType = getFuncType();
215
    using F = FuncTraits<decltype(&T::body)>;
216
    using ArgsT = typename F::ArgsT;
217
    FuncType.getParamTypes().reserve(F::ArgsN);
218
    pushValType<ArgsT>(std::make_index_sequence<F::ArgsN>());
219
    if constexpr (F::hasReturn) {
220
      FuncType.getReturnTypes().reserve(F::RetsN);
221
      using RetsT = typename F::RetsT;
222
      pushRetType<RetsT>(std::make_index_sequence<F::RetsN>());
223
    }
224
  }
225
226
private:
227
  template <typename U> struct Wrap {
228
    using Type = std::tuple<U>;
229
  };
230
  template <typename... U> struct Wrap<std::tuple<U...>> {
231
    using Type = std::tuple<U...>;
232
  };
233
  template <typename> struct FuncTraits;
234
  template <typename R, typename C, typename... A>
235
  struct FuncTraits<Expect<R> (C::*)(A...)> {
236
    using ArgsT = std::tuple<A...>;
237
    using RetsT = typename Wrap<R>::Type;
238
    static inline constexpr const std::size_t ArgsN = std::tuple_size_v<ArgsT>;
239
    static inline constexpr const std::size_t RetsN = std::tuple_size_v<RetsT>;
240
    static inline constexpr const bool hasReturn = true;
241
  };
242
  template <typename C, typename... A>
243
  struct FuncTraits<Expect<void> (C::*)(A...)> {
244
    using ArgsT = std::tuple<A...>;
245
    static inline constexpr const std::size_t ArgsN = std::tuple_size_v<ArgsT>;
246
    static inline constexpr const std::size_t RetsN = 0;
247
    static inline constexpr const bool hasReturn = false;
248
  };
249
250
  template <typename Tuple, typename SpanT, size_t... Indices>
251
  static Tuple toTuple(SpanT &&Args, std::index_sequence<Indices...>) {
252
    return Tuple(convert<std::tuple_element_t<Indices, Tuple>>::run(
253
        std::forward<SpanT>(Args)[Indices])...);
254
  }
255
256
  template <typename Tuple, typename SpanT, size_t... Indices>
257
  static void fromTuple(SpanT &&Rets, Tuple &&V,
258
                        std::index_sequence<Indices...>) {
259
    (emplace<std::tuple_element_t<Indices, Tuple>>::run(
260
         std::forward<SpanT>(Rets)[Indices],
261
         std::get<Indices>(std::forward<Tuple>(V))),
262
     ...);
263
  }
264
265
  template <typename Tuple, std::size_t... Indices>
266
  void pushValType(std::index_sequence<Indices...>) {
267
    (FuncType.getParamTypes().push_back(
268
         Wit<std::tuple_element_t<Indices, Tuple>>::type()),
269
     ...);
270
  }
271
272
  template <typename Tuple, std::size_t... Indices>
273
  void pushRetType(std::index_sequence<Indices...>) {
274
    (FuncType.getReturnTypes().push_back(
275
         Wit<std::tuple_element_t<Indices, Tuple>>::type()),
276
     ...);
277
  }
278
};
279
280
} // namespace Component
281
} // namespace Runtime
282
} // namespace WasmEdge