Wasmtime
func.hh
Go to the documentation of this file.
1
5#ifndef WASMTIME_FUNC_HH
6#define WASMTIME_FUNC_HH
7
8#include <wasmtime/_func_class.hh>
9#include <wasmtime/_val_class.hh>
10
11namespace wasmtime {
12
13namespace detail {
14
17// NOLINTNEXTLINE
18#define NATIVE_WASM_TYPE(native, valkind, field) \
19 template <> struct WasmType<native> { \
20 static const bool valid = true; \
21 static ValType valtype() { return ValType::valkind(); } \
22 static void store(Store::Context cx, wasmtime_val_raw_t *p, \
23 const native &t) { \
24 (void)cx; \
25 p->field = t; \
26 } \
27 static native load(Store::Context cx, wasmtime_val_raw_t *p) { \
28 (void)cx; \
29 return p->field; \
30 } \
31 };
32
33NATIVE_WASM_TYPE(int32_t, i32, i32)
34NATIVE_WASM_TYPE(uint32_t, i32, i32)
35NATIVE_WASM_TYPE(int64_t, i64, i64)
36NATIVE_WASM_TYPE(uint64_t, i64, i64)
37NATIVE_WASM_TYPE(float, f32, f32)
38NATIVE_WASM_TYPE(double, f64, f64)
39
40#undef NATIVE_WASM_TYPE
41
43template <> struct WasmType<std::optional<Func>> {
45 static const bool valid = true;
47 static ValType valtype() { return ValType::funcref(); }
49 static void store(Store::Context cx, wasmtime_val_raw_t *p,
50 const std::optional<Func> func) {
51 if (func) {
52 p->funcref = wasmtime_func_to_raw(cx.capi(), &func->capi());
53 } else {
54 p->funcref = 0;
55 }
56 }
58 static std::optional<Func> load(Store::Context cx, wasmtime_val_raw_t *p) {
59 if (p->funcref == 0) {
60 return std::nullopt;
61 }
63 wasmtime_func_from_raw(cx.capi(), p->funcref, &ret);
64 return ret;
65 }
66};
67
69template <> struct WasmTypeList<std::monostate> {
70 static const bool valid = true;
71 static const size_t size = 0;
72 static bool matches(ValType::ListRef types) { return types.size() == 0; }
73 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
74 const std::monostate &t) {
75 (void)cx;
76 (void)storage;
77 (void)t;
78 }
79 static std::monostate load(Store::Context cx, wasmtime_val_raw_t *storage) {
80 (void)cx;
81 (void)storage;
82 return std::monostate();
83 }
84 static std::vector<ValType> types() { return {}; }
85};
86
88template <typename... T> struct WasmTypeList<std::tuple<T...>> {
89 static const bool valid = (WasmType<T>::valid && ...);
90 static const size_t size = sizeof...(T);
91 static bool matches(ValType::ListRef types) {
92 if (types.size() != size) {
93 return false;
94 }
95 size_t n = 0;
96 return ((WasmType<T>::valtype() == types.begin()[n++]) && ...);
97 }
98 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
99 std::tuple<T...> &&t) {
100 size_t n = 0;
101 std::apply(
102 [&](auto &...val) {
103 (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
104 },
105 t);
106 }
107 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
108 const std::tuple<T...> &t) {
109 size_t n = 0;
110 std::apply(
111 [&](const auto &...val) {
112 (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
113 },
114 t);
115 }
116 static std::tuple<T...> load(Store::Context cx, wasmtime_val_raw_t *storage) {
117 (void)cx;
118 return std::tuple<T...>{WasmType<T>::load(cx, storage++)...}; // NOLINT
119 }
120 static std::vector<ValType> types() { return {WasmType<T>::valtype()...}; }
121};
122
124template <> struct WasmHostRet<void> {
125 using Results = WasmTypeList<std::tuple<>>;
126
127 template <typename F, typename... A>
128 static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
129 A... args) {
130 (void)cx;
131 (void)raw;
132 f(args...);
133 return std::nullopt;
134 }
135};
136
137// Alternative method of returning "nothing" (also enables `std::monostate` in
138// the `R` type of `Result` below)
139template <> struct WasmHostRet<std::monostate> : public WasmHostRet<void> {};
140
143template <typename R> struct WasmHostRet<Result<R, Trap>> {
144 using Results = WasmTypeList<R>;
145
146 template <typename F, typename... A>
147 static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
148 A... args) {
149 Result<R, Trap> ret = f(args...);
150 if (!ret) {
151 return ret.err();
152 }
153 Results::store(cx, raw, ret.ok());
154 return std::nullopt;
155 }
156};
157
160template <typename R, typename... A> struct WasmHostFunc<R (*)(A...)> {
161 using Params = WasmTypeList<std::tuple<A...>>;
162 using Results = typename WasmHostRet<R>::Results;
163
164 template <typename F>
165 static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
166 auto params = Params::load(cx, raw);
167 return std::apply(
168 [&](const auto &...val) {
169 return WasmHostRet<R>::invoke(f, cx, raw, val...);
170 },
171 params);
172 }
173};
174
176template <typename R, typename... A>
177struct WasmHostFunc<R (*)(Caller, A...)> : public WasmHostFunc<R (*)(A...)> {
178 // Override `invoke` here to pass the `cx` as the first parameter
179 template <typename F>
180 static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
181 auto params = WasmTypeList<std::tuple<A...>>::load(cx, raw);
182 return std::apply(
183 [&](const auto &...val) {
184 return WasmHostRet<R>::invoke(f, cx, raw, cx, val...);
185 },
186 params);
187 }
188};
189
191template <typename R, typename C, typename... A>
192struct WasmHostFunc<R (C::*)(A...)> : public WasmHostFunc<R (*)(A...)> {};
193
195template <typename R, typename C, typename... A>
196struct WasmHostFunc<R (C::*)(A...) const> : public WasmHostFunc<R (*)(A...)> {};
197
200template <typename R, typename C, typename... A>
201struct WasmHostFunc<R (C::*)(Caller, A...)>
202 : public WasmHostFunc<R (*)(Caller, A...)> {};
203
206template <typename R, typename C, typename... A>
207struct WasmHostFunc<R (C::*)(Caller, A...) const>
208 : public WasmHostFunc<R (*)(Caller, A...)> {};
209
212template <typename T>
213struct WasmHostFunc<T, std::void_t<decltype(&T::operator())>>
214 : public WasmHostFunc<decltype(&T::operator())> {};
215
216} // namespace detail
217
218using namespace detail;
219
220template <typename F>
221inline wasm_trap_t *Func::raw_callback(void *env, wasmtime_caller_t *caller,
222 const wasmtime_val_t *args, size_t nargs,
223 wasmtime_val_t *results,
224 size_t nresults) {
225 static_assert(alignof(Val) == alignof(wasmtime_val_t));
226 static_assert(sizeof(Val) == sizeof(wasmtime_val_t));
227 F *func = reinterpret_cast<F *>(env); // NOLINT
228 Span<const Val> args_span(reinterpret_cast<const Val *>(args), // NOLINT
229 nargs);
230 Span<Val> results_span(reinterpret_cast<Val *>(results), // NOLINT
231 nresults);
232 Result<std::monostate, Trap> result =
233 (*func)(Caller(caller), args_span, results_span);
234 if (!result) {
235 return result.err().capi_release();
236 }
237 return nullptr;
238}
239
240template <typename I>
241inline TrapResult<std::vector<Val>>
242Func::call(Store::Context cx, const I &begin, const I &end) const {
243 std::vector<wasmtime_val_t> raw_params;
244 raw_params.reserve(end - begin);
245 for (auto i = begin; i != end; i++) {
246 raw_params.push_back(i->val);
247 }
248 size_t nresults = this->type(cx)->results().size();
249 std::vector<wasmtime_val_t> raw_results(nresults);
250
251 wasm_trap_t *trap = nullptr;
252 auto *error =
253 wasmtime_func_call(cx.ptr, &func, raw_params.data(), raw_params.size(),
254 raw_results.data(), raw_results.capacity(), &trap);
255 if (error != nullptr) {
256 return TrapError(Error(error));
257 }
258 if (trap != nullptr) {
259 return TrapError(Trap(trap));
260 }
261
262 std::vector<Val> results;
263 results.reserve(nresults);
264 for (size_t i = 0; i < nresults; i++) {
265 results.push_back(raw_results[i]);
266 }
267 return results;
268}
269
271Func::call(Store::Context cx, const std::initializer_list<Val> &params) const {
272 return this->call(cx, params.begin(), params.end());
273}
274
276Func::call(Store::Context cx, const std::vector<Val> &params) const {
277 return this->call(cx, params.begin(), params.end());
278}
279
280} // namespace wasmtime
281
282#endif // WASMTIME_FUNC_HH
Errors coming from Wasmtime.
Definition: error.hh:26
ValType::ListRef results() const
Returns the list of types this function type returns.
Definition: types/func.hh:43
TrapResult< std::vector< Val > > call(Store::Context cx, const I &begin, const I &end) const
Invoke a WebAssembly function.
Definition: func.hh:242
FuncType type(Store::Context cx) const
Returns the type of this function.
Definition: _func_class.hh:282
Fallible result type used for Wasmtime.
Definition: error.hh:70
An interior pointer into a Store.
Definition: _store_class.hh:65
Information about a WebAssembly trap.
Definition: trap.hh:113
size_t size() const
Returns how many types are in this list.
Definition: types/_val_class.hh:72
static ValType funcref()
Convenience constructor for the funcref value type.
Definition: types/_val_class.hh:137
WASM_API_EXTERN wasmtime_error_t * wasmtime_func_call(wasmtime_context_t *store, const wasmtime_func_t *func, const wasmtime_val_t *args, size_t nargs, wasmtime_val_t *results, size_t nresults, wasm_trap_t **trap)
Call a WebAssembly function.
WASM_API_EXTERN void * wasmtime_func_to_raw(wasmtime_context_t *context, const wasmtime_func_t *func)
Converts a func which belongs to context into a usize parameter that is suitable for insertion into a...
WASM_API_EXTERN void wasmtime_func_from_raw(wasmtime_context_t *context, void *raw, wasmtime_func_t *ret)
Converts a raw nonzero funcref value from wasmtime_val_raw_t into a wasmtime_func_t.
#define NATIVE_WASM_TYPE(native, valkind, field)
Definition: func.hh:18
Opaque struct representing a wasm trap.
Structure used to represent either a Trap or an Error.
Definition: trap.hh:153
Representation of a function in Wasmtime.
Definition: extern.h:26
Container for different kinds of wasm values.
Definition: val.h:376
Container for possible wasm values.
Definition: val.h:290
void * funcref
Definition: val.h:343