Wasmtime
func.hh
Go to the documentation of this file.
1
5#ifndef WASMTIME_FUNC_HH
6#define WASMTIME_FUNC_HH
7
8#include <array>
9#include <wasmtime/error.hh>
10#include <wasmtime/extern_declare.hh>
11#include <wasmtime/func.h>
12#include <wasmtime/span.hh>
13#include <wasmtime/store.hh>
14#include <wasmtime/trap.hh>
16#include <wasmtime/types/val.hh>
17#include <wasmtime/val.hh>
18
19namespace wasmtime {
20
28class Caller {
29 friend class Func;
30 friend class Store;
32 Caller(wasmtime_caller_t *ptr) : ptr(ptr) {}
33
34public:
39 std::optional<Extern> get_export(std::string_view name);
40
42 Store::Context context() { return this; }
43};
44
45inline Store::Context::Context(Caller &caller)
46 : Context(wasmtime_caller_context(caller.ptr)) {}
47inline Store::Context::Context(Caller *caller) : Context(*caller) {}
48
49namespace detail {
50
53template <typename T> struct WasmType {
54 static const bool valid = false;
55};
56
59// NOLINTNEXTLINE
60#define NATIVE_WASM_TYPE(native, valkind, field) \
61 template <> struct WasmType<native> { \
62 static const bool valid = true; \
63 static const ValKind kind = ValKind::valkind; \
64 static void store(Store::Context cx, wasmtime_val_raw_t *p, \
65 const native &t) { \
66 (void)cx; \
67 p->field = t; \
68 } \
69 static native load(Store::Context cx, wasmtime_val_raw_t *p) { \
70 (void)cx; \
71 return p->field; \
72 } \
73 };
74
75NATIVE_WASM_TYPE(int32_t, I32, i32)
76NATIVE_WASM_TYPE(uint32_t, I32, i32)
77NATIVE_WASM_TYPE(int64_t, I64, i64)
78NATIVE_WASM_TYPE(uint64_t, I64, i64)
79NATIVE_WASM_TYPE(float, F32, f32)
80NATIVE_WASM_TYPE(double, F64, f64)
81
82#undef NATIVE_WASM_TYPE
83
86template <> struct WasmType<std::optional<ExternRef>> {
87 static const bool valid = true;
88 static const ValKind kind = ValKind::ExternRef;
89 static void store(Store::Context cx, wasmtime_val_raw_t *p,
90 std::optional<ExternRef> &&ref) {
91 if (ref) {
92 p->externref = ref->take_raw(cx);
93 } else {
94 p->externref = 0;
95 }
96 }
97 static void store(Store::Context cx, wasmtime_val_raw_t *p,
98 const std::optional<ExternRef> &ref) {
99 if (ref) {
100 p->externref = ref->borrow_raw(cx);
101 } else {
102 p->externref = 0;
103 }
104 }
105 static std::optional<ExternRef> load(Store::Context cx,
107 if (p->externref == 0) {
108 return std::nullopt;
109 }
111 wasmtime_externref_from_raw(cx.raw_context(), p->externref, &val);
112 return ExternRef(val);
113 }
114};
115
117template <> struct WasmType<V128> {
118 static const bool valid = true;
119 static const ValKind kind = ValKind::V128;
120 static void store(Store::Context cx, wasmtime_val_raw_t *p, const V128 &t) {
121 (void)cx;
122 memcpy(&p->v128[0], &t.v128[0], sizeof(wasmtime_v128));
123 }
124 static V128 load(Store::Context cx, wasmtime_val_raw_t *p) {
125 (void)cx;
126 return p->v128;
127 }
128};
129
134template <typename T> struct WasmTypeList {
135 static const bool valid = WasmType<T>::valid;
136 static const size_t size = 1;
137 static bool matches(ValType::ListRef types) {
138 return WasmTypeList<std::tuple<T>>::matches(types);
139 }
140 static void store(Store::Context cx, wasmtime_val_raw_t *storage, T &&t) {
141 WasmType<T>::store(cx, storage, t);
142 }
143 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
144 const T &t) {
145 WasmType<T>::store(cx, storage, t);
146 }
147 static T load(Store::Context cx, wasmtime_val_raw_t *storage) {
148 return WasmType<T>::load(cx, storage);
149 }
150 static std::vector<ValType> types() { return {WasmType<T>::kind}; }
151};
152
154template <> struct WasmTypeList<std::monostate> {
155 static const bool valid = true;
156 static const size_t size = 0;
157 static bool matches(ValType::ListRef types) { return types.size() == 0; }
158 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
159 const std::monostate &t) {
160 (void)cx;
161 (void)storage;
162 (void)t;
163 }
164 static std::monostate load(Store::Context cx, wasmtime_val_raw_t *storage) {
165 (void)cx;
166 (void)storage;
167 return std::monostate();
168 }
169 static std::vector<ValType> types() { return {}; }
170};
171
173template <typename... T> struct WasmTypeList<std::tuple<T...>> {
174 static const bool valid = (WasmType<T>::valid && ...);
175 static const size_t size = sizeof...(T);
176 static bool matches(ValType::ListRef types) {
177 if (types.size() != size) {
178 return false;
179 }
180 size_t n = 0;
181 return ((WasmType<T>::kind == types.begin()[n++].kind()) && ...);
182 }
183 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
184 std::tuple<T...> &&t) {
185 size_t n = 0;
186 std::apply(
187 [&](auto &...val) {
188 (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
189 },
190 t);
191 }
192 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
193 const std::tuple<T...> &t) {
194 size_t n = 0;
195 std::apply(
196 [&](const auto &...val) {
197 (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
198 },
199 t);
200 }
201 static std::tuple<T...> load(Store::Context cx, wasmtime_val_raw_t *storage) {
202 (void)cx;
203 return std::tuple<T...>{WasmType<T>::load(cx, storage++)...}; // NOLINT
204 }
205 static std::vector<ValType> types() { return {WasmType<T>::kind...}; }
206};
207
211template <typename R> struct WasmHostRet {
212 using Results = WasmTypeList<R>;
213
214 template <typename F, typename... A>
215 static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
216 A... args) {
217 auto ret = f(args...);
218 Results::store(cx, raw, ret);
219 return std::nullopt;
220 }
221};
222
224template <> struct WasmHostRet<void> {
225 using Results = WasmTypeList<std::tuple<>>;
226
227 template <typename F, typename... A>
228 static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
229 A... args) {
230 (void)cx;
231 (void)raw;
232 f(args...);
233 return std::nullopt;
234 }
235};
236
237// Alternative method of returning "nothing" (also enables `std::monostate` in
238// the `R` type of `Result` below)
239template <> struct WasmHostRet<std::monostate> : public WasmHostRet<void> {};
240
243template <typename R> struct WasmHostRet<Result<R, Trap>> {
244 using Results = WasmTypeList<R>;
245
246 template <typename F, typename... A>
247 static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
248 A... args) {
249 Result<R, Trap> ret = f(args...);
250 if (!ret) {
251 return ret.err();
252 }
253 Results::store(cx, raw, ret.ok());
254 return std::nullopt;
255 }
256};
257
258template <typename F, typename = void> struct WasmHostFunc;
259
262template <typename R, typename... A> struct WasmHostFunc<R (*)(A...)> {
263 using Params = WasmTypeList<std::tuple<A...>>;
264 using Results = typename WasmHostRet<R>::Results;
265
266 template <typename F>
267 static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
268 auto params = Params::load(cx, raw);
269 return std::apply(
270 [&](const auto &...val) {
271 return WasmHostRet<R>::invoke(f, cx, raw, val...);
272 },
273 params);
274 }
275};
276
278template <typename R, typename... A>
279struct WasmHostFunc<R (*)(Caller, A...)> : public WasmHostFunc<R (*)(A...)> {
280 // Override `invoke` here to pass the `cx` as the first parameter
281 template <typename F>
282 static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
283 auto params = WasmTypeList<std::tuple<A...>>::load(cx, raw);
284 return std::apply(
285 [&](const auto &...val) {
286 return WasmHostRet<R>::invoke(f, cx, raw, cx, val...);
287 },
288 params);
289 }
290};
291
293template <typename R, typename C, typename... A>
294struct WasmHostFunc<R (C::*)(A...)> : public WasmHostFunc<R (*)(A...)> {};
295
297template <typename R, typename C, typename... A>
298struct WasmHostFunc<R (C::*)(A...) const> : public WasmHostFunc<R (*)(A...)> {};
299
302template <typename R, typename C, typename... A>
303struct WasmHostFunc<R (C::*)(Caller, A...)>
304 : public WasmHostFunc<R (*)(Caller, A...)> {};
305
308template <typename R, typename C, typename... A>
309struct WasmHostFunc<R (C::*)(Caller, A...) const>
310 : public WasmHostFunc<R (*)(Caller, A...)> {};
311
314template <typename T>
315struct WasmHostFunc<T, std::void_t<decltype(&T::operator())>>
316 : public WasmHostFunc<decltype(&T::operator())> {};
317
318} // namespace detail
319
320using namespace detail;
321
322// forward-declaration for `Func::typed` below.
323template <typename Params, typename Results> class TypedFunc;
324
336class Func {
337 friend class Val;
338 friend class Instance;
339 friend class Linker;
340 template <typename Params, typename Results> friend class TypedFunc;
341
342 wasmtime_func_t func;
343
344 template <typename F>
345 static wasm_trap_t *raw_callback(void *env, wasmtime_caller_t *caller,
346 const wasmtime_val_t *args, size_t nargs,
347 wasmtime_val_t *results, size_t nresults) {
348 static_assert(alignof(Val) == alignof(wasmtime_val_t));
349 static_assert(sizeof(Val) == sizeof(wasmtime_val_t));
350 F *func = reinterpret_cast<F *>(env); // NOLINT
351 Span<const Val> args_span(reinterpret_cast<const Val *>(args), // NOLINT
352 nargs);
353 Span<Val> results_span(reinterpret_cast<Val *>(results), // NOLINT
354 nresults);
356 (*func)(Caller(caller), args_span, results_span);
357 if (!result) {
358 return result.err().ptr.release();
359 }
360 return nullptr;
361 }
362
363 template <typename F>
364 static wasm_trap_t *
365 raw_callback_unchecked(void *env, wasmtime_caller_t *caller,
366 wasmtime_val_raw_t *args_and_results,
367 size_t nargs_and_results) {
368 (void)nargs_and_results;
369 using HostFunc = WasmHostFunc<F>;
370 Caller cx(caller);
371 F *func = reinterpret_cast<F *>(env); // NOLINT
372 auto trap = HostFunc::invoke(*func, cx, args_and_results);
373 if (trap) {
374 return trap->ptr.release();
375 }
376 return nullptr;
377 }
378
379 template <typename F> static void raw_finalize(void *env) {
380 std::unique_ptr<F> ptr(reinterpret_cast<F *>(env)); // NOLINT
381 }
382
383public:
385 Func(wasmtime_func_t func) : func(func) {}
386
418 template <typename F,
419 std::enable_if_t<
420 std::is_invocable_r_v<Result<std::monostate, Trap>, F, Caller,
422 bool> = true>
423 Func(Store::Context cx, const FuncType &ty, F f) : func({}) {
424 wasmtime_func_new(cx.ptr, ty.ptr.get(), raw_callback<F>,
425 std::make_unique<F>(f).release(), raw_finalize<F>, &func);
426 }
427
466 template <typename F,
467 std::enable_if_t<WasmHostFunc<F>::Params::valid, bool> = true,
468 std::enable_if_t<WasmHostFunc<F>::Results::valid, bool> = true>
469 static Func wrap(Store::Context cx, F f) {
470 using HostFunc = WasmHostFunc<F>;
471 auto params = HostFunc::Params::types();
472 auto results = HostFunc::Results::types();
473 auto ty = FuncType::from_iters(params, results);
474 wasmtime_func_t func;
475 wasmtime_func_new_unchecked(cx.ptr, ty.ptr.get(), raw_callback_unchecked<F>,
476 std::make_unique<F>(f).release(),
477 raw_finalize<F>, &func);
478 return func;
479 }
480
501 template <typename I>
503 const I &end) const {
504 std::vector<wasmtime_val_t> raw_params;
505 raw_params.reserve(end - begin);
506 for (auto i = begin; i != end; i++) {
507 raw_params.push_back(i->val);
508 }
509 size_t nresults = this->type(cx)->results().size();
510 std::vector<wasmtime_val_t> raw_results(nresults);
511
512 wasm_trap_t *trap = nullptr;
513 auto *error =
514 wasmtime_func_call(cx.ptr, &func, raw_params.data(), raw_params.size(),
515 raw_results.data(), raw_results.capacity(), &trap);
516 if (error != nullptr) {
517 return TrapError(Error(error));
518 }
519 if (trap != nullptr) {
520 return TrapError(Trap(trap));
521 }
522
523 std::vector<Val> results;
524 results.reserve(nresults);
525 for (size_t i = 0; i < nresults; i++) {
526 results.push_back(raw_results[i]);
527 }
528 return results;
529 }
530
538 const std::vector<Val> &params) const {
539 return this->call(cx, params.begin(), params.end());
540 }
541
549 call(Store::Context cx, const std::initializer_list<Val> &params) const {
550 return this->call(cx, params.begin(), params.end());
551 }
552
555 return wasmtime_func_type(cx.ptr, &func);
556 }
557
575 template <typename Params, typename Results,
576 std::enable_if_t<WasmTypeList<Params>::valid, bool> = true,
577 std::enable_if_t<WasmTypeList<Results>::valid, bool> = true>
579 auto ty = this->type(cx);
580 if (!WasmTypeList<Params>::matches(ty->params()) ||
581 !WasmTypeList<Results>::matches(ty->results())) {
582 return Trap("static type for this function does not match actual type");
583 }
585 return ret;
586 }
587
589 const wasmtime_func_t &capi() const { return func; }
590};
591
596template <typename Params, typename Results> class TypedFunc {
597 friend class Func;
598 Func f;
599 TypedFunc(Func func) : f(func) {}
600
601public:
612 TrapResult<Results> call(Store::Context cx, const Params &params) const {
613 std::array<wasmtime_val_raw_t, std::max(WasmTypeList<Params>::size,
614 WasmTypeList<Results>::size)>
615 storage;
616 wasmtime_val_raw_t *ptr = storage.data();
617 if (ptr == nullptr)
618 ptr = reinterpret_cast<wasmtime_val_raw_t *>(alignof(wasmtime_val_raw_t));
619 WasmTypeList<Params>::store(cx, ptr, params);
620 wasm_trap_t *trap = nullptr;
621 auto *error = wasmtime_func_call_unchecked(cx.raw_context(), &f.func, ptr,
622 storage.size(), &trap);
623 if (error != nullptr) {
624 return TrapError(Error(error));
625 }
626 if (trap != nullptr) {
627 return TrapError(Trap(trap));
628 }
629 return WasmTypeList<Results>::load(cx, ptr);
630 }
631
633 const Func &func() const { return f; }
634};
635
636inline Val::Val(std::optional<Func> func) : val{} {
638 if (func) {
639 val.of.funcref = (*func).func;
640 } else {
641 wasmtime_funcref_set_null(&val.of.funcref);
642 }
643}
644
645inline Val::Val(Func func) : Val(std::optional(func)) {}
646inline Val::Val(ExternRef ptr) : Val(std::optional(ptr)) {}
647inline Val::Val(AnyRef ptr) : Val(std::optional(ptr)) {}
648
649inline std::optional<Func> Val::funcref() const {
650 if (val.kind != WASMTIME_FUNCREF) {
651 std::abort();
652 }
653 if (val.of.funcref.store_id == 0) {
654 return std::nullopt;
655 }
656 return Func(val.of.funcref);
657}
658
660template <> struct detail::WasmType<std::optional<Func>> {
662 static const bool valid = true;
664 static const ValKind kind = ValKind::FuncRef;
666 static void store(Store::Context cx, wasmtime_val_raw_t *p,
667 const std::optional<Func> func) {
668 if (func) {
669 p->funcref = wasmtime_func_to_raw(cx.raw_context(), &func->capi());
670 } else {
671 p->funcref = 0;
672 }
673 }
675 static std::optional<Func> load(Store::Context cx, wasmtime_val_raw_t *p) {
676 if (p->funcref == 0) {
677 return std::nullopt;
678 }
679 wasmtime_func_t ret;
680 wasmtime_func_from_raw(cx.raw_context(), p->funcref, &ret);
681 return ret;
682 }
683};
684
685} // namespace wasmtime
686
687#endif // WASMTIME_FUNC_HH
Representation of a WebAssembly anyref value.
Definition: val.hh:105
Structure provided to host functions to lookup caller information or acquire a Store::Context.
Definition: func.hh:28
std::optional< Extern > get_export(std::string_view name)
Definition: extern.hh:53
Store::Context context()
Explicitly acquire a Store::Context from this Caller.
Definition: func.hh:42
Errors coming from Wasmtime.
Definition: error.hh:25
Representation of a WebAssembly externref value.
Definition: val.hh:28
Type information for a WebAssembly function.
Definition: types/func.hh:15
static FuncType from_iters(P params, R results)
Creates a new function type from the given list of parameters and results.
Definition: types/func.hh:75
Representation of a WebAssembly function.
Definition: func.hh:336
TrapResult< std::vector< Val > > call(Store::Context cx, const I &begin, const I &end) const
Invoke a WebAssembly function.
Definition: func.hh:502
Func(wasmtime_func_t func)
Creates a new function from the raw underlying C API representation.
Definition: func.hh:385
FuncType type(Store::Context cx) const
Returns the type of this function.
Definition: func.hh:554
TrapResult< std::vector< Val > > call(Store::Context cx, const std::vector< Val > &params) const
Helper function for call(Store::Context cx, const I &begin, const I &end)
Definition: func.hh:537
static Func wrap(Store::Context cx, F f)
Creates a new host function from the provided callback f, inferring the WebAssembly function type fro...
Definition: func.hh:469
TrapResult< std::vector< Val > > call(Store::Context cx, const std::initializer_list< Val > &params) const
Helper function for call(Store::Context cx, const I &begin, const I &end)
Definition: func.hh:549
const wasmtime_func_t & capi() const
Returns the raw underlying C API function this is using.
Definition: func.hh:589
Func(Store::Context cx, const FuncType &ty, F f)
Creates a new host-defined function.
Definition: func.hh:423
Result< TypedFunc< Params, Results >, Trap > typed(Store::Context cx) const
Statically checks this function against the provided types.
Definition: func.hh:578
A WebAssembly instance.
Definition: instance.hh:31
Helper class for linking modules together with name-based resolution.
Definition: linker.hh:25
Fallible result type used for Wasmtime.
Definition: error.hh:82
E && err()
Returns the error, if present, aborts if this is not an error.
Definition: error.hh:96
Span class used when c++20 is not available.
Definition: span.hh:47
An interior pointer into a Store.
Definition: store.hh:60
wasmtime_context_t * raw_context()
Returns the raw context pointer for the C API.
Definition: store.hh:153
Owner of all WebAssembly objects.
Definition: store.hh:33
Information about a WebAssembly trap.
Definition: trap.hh:113
A version of a WebAssembly Func where the type signature of the function is statically known.
Definition: func.hh:596
const Func & func() const
Returns the underlying un-typed Func for this function.
Definition: func.hh:633
TrapResult< Results > call(Store::Context cx, const Params &params) const
Calls this function with the provided parameters.
Definition: func.hh:612
Representation of a generic WebAssembly value.
Definition: val.hh:204
std::optional< Func > funcref() const
Definition: func.hh:649
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.
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.
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...
wasmtime_error_t * wasmtime_func_call_unchecked(wasmtime_context_t *store, const wasmtime_func_t *func, wasmtime_val_raw_t *args_and_results, size_t args_and_results_len, wasm_trap_t **trap)
Call a WebAssembly function in an "unchecked" fashion.
void wasmtime_func_new(wasmtime_context_t *store, const wasm_functype_t *type, wasmtime_func_callback_t callback, void *env, void(*finalizer)(void *), wasmtime_func_t *ret)
Creates a new host-defined function.
wasmtime_context_t * wasmtime_caller_context(wasmtime_caller_t *caller)
Returns the store context of the caller object.
void wasmtime_func_new_unchecked(wasmtime_context_t *store, const wasm_functype_t *type, wasmtime_func_unchecked_callback_t callback, void *env, void(*finalizer)(void *), wasmtime_func_t *ret)
Creates a new host function in the same manner of wasmtime_func_new, but the function-to-call has no ...
wasm_functype_t * wasmtime_func_type(const wasmtime_context_t *store, const wasmtime_func_t *func)
Returns the type of the function specified.
#define NATIVE_WASM_TYPE(native, valkind, field)
Definition: func.hh:60
Opaque struct representing a wasm trap.
Structure used to represent either a Trap or an Error.
Definition: trap.hh:165
A host-defined un-forgeable reference to pass into WebAssembly.
Definition: val.h:178
Representation of a function in Wasmtime.
Definition: extern.h:25
uint64_t store_id
Definition: extern.h:31
Container for different kinds of wasm values.
Definition: val.h:456
wasmtime_valkind_t kind
Discriminant of which field of of is valid.
Definition: val.h:458
wasmtime_valunion_t of
Container for the extern item's value.
Definition: val.h:460
ValKind
Different kinds of types accepted by Wasmtime.
Definition: types/val.hh:16
@ V128
WebAssembly's v128 type from the simd proposal.
Container for possible wasm values.
Definition: val.h:380
uint32_t externref
Definition: val.h:416
wasmtime_v128 v128
Definition: val.h:400
void * funcref
Definition: val.h:423
wasmtime_func_t funcref
Definition: val.h:344
union wasmtime_val_raw wasmtime_val_raw_t
Convenience alias for wasmtime_val_raw.
uint8_t wasmtime_v128[16]
A 128-bit value representing the WebAssembly v128 type. Bytes are stored in little-endian order.
Definition: val.h:315
void wasmtime_externref_from_raw(wasmtime_context_t *context, uint32_t raw, wasmtime_externref_t *out)
Converts a raw externref value coming from wasmtime_val_raw_t into a wasmtime_externref_t.
#define WASMTIME_FUNCREF
Value of wasmtime_valkind_t meaning that wasmtime_val_t is a funcref.
Definition: val.h:305