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
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
84#ifdef WASMTIME_FEATURE_GC
87template <> struct WasmType<std::optional<ExternRef>> {
88 static const bool valid = true;
89 static const ValKind kind = ValKind::ExternRef;
90 static void store(Store::Context cx, wasmtime_val_raw_t *p,
91 std::optional<ExternRef> &&ref) {
92 if (ref) {
93 p->externref = ref->take_raw(cx);
94 } else {
95 p->externref = 0;
96 }
97 }
98 static void store(Store::Context cx, wasmtime_val_raw_t *p,
99 const std::optional<ExternRef> &ref) {
100 if (ref) {
101 p->externref = ref->borrow_raw(cx);
102 } else {
103 p->externref = 0;
104 }
105 }
106
107 static std::optional<ExternRef> load(Store::Context cx,
109 if (p->externref == 0) {
110 return std::nullopt;
111 }
112 wasmtime_externref_t val;
113 wasmtime_externref_from_raw(cx.capi(), p->externref, &val);
114 return ExternRef(val);
115 }
116};
117#endif // WASMTIME_FEATURE_GC
118
120template <> struct WasmType<V128> {
121 static const bool valid = true;
122 static const ValKind kind = ValKind::V128;
123 static void store(Store::Context cx, wasmtime_val_raw_t *p, const V128 &t) {
124 (void)cx;
125 memcpy(&p->v128[0], &t.v128[0], sizeof(wasmtime_v128));
126 }
127 static V128 load(Store::Context cx, wasmtime_val_raw_t *p) {
128 (void)cx;
129 return p->v128;
130 }
131};
132
137template <typename T> struct WasmTypeList {
138 static const bool valid = WasmType<T>::valid;
139 static const size_t size = 1;
140 static bool matches(ValType::ListRef types) {
141 return WasmTypeList<std::tuple<T>>::matches(types);
142 }
143 static void store(Store::Context cx, wasmtime_val_raw_t *storage, T &&t) {
144 WasmType<T>::store(cx, storage, t);
145 }
146 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
147 const T &t) {
148 WasmType<T>::store(cx, storage, t);
149 }
150 static T load(Store::Context cx, wasmtime_val_raw_t *storage) {
151 return WasmType<T>::load(cx, storage);
152 }
153 static std::vector<ValType> types() { return {WasmType<T>::kind}; }
154};
155
157template <> struct WasmTypeList<std::monostate> {
158 static const bool valid = true;
159 static const size_t size = 0;
160 static bool matches(ValType::ListRef types) { return types.size() == 0; }
161 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
162 const std::monostate &t) {
163 (void)cx;
164 (void)storage;
165 (void)t;
166 }
167 static std::monostate load(Store::Context cx, wasmtime_val_raw_t *storage) {
168 (void)cx;
169 (void)storage;
170 return std::monostate();
171 }
172 static std::vector<ValType> types() { return {}; }
173};
174
176template <typename... T> struct WasmTypeList<std::tuple<T...>> {
177 static const bool valid = (WasmType<T>::valid && ...);
178 static const size_t size = sizeof...(T);
179 static bool matches(ValType::ListRef types) {
180 if (types.size() != size) {
181 return false;
182 }
183 size_t n = 0;
184 return ((WasmType<T>::kind == types.begin()[n++].kind()) && ...);
185 }
186 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
187 std::tuple<T...> &&t) {
188 size_t n = 0;
189 std::apply(
190 [&](auto &...val) {
191 (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
192 },
193 t);
194 }
195 static void store(Store::Context cx, wasmtime_val_raw_t *storage,
196 const std::tuple<T...> &t) {
197 size_t n = 0;
198 std::apply(
199 [&](const auto &...val) {
200 (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
201 },
202 t);
203 }
204 static std::tuple<T...> load(Store::Context cx, wasmtime_val_raw_t *storage) {
205 (void)cx;
206 return std::tuple<T...>{WasmType<T>::load(cx, storage++)...}; // NOLINT
207 }
208 static std::vector<ValType> types() { return {WasmType<T>::kind...}; }
209};
210
214template <typename R> struct WasmHostRet {
215 using Results = WasmTypeList<R>;
216
217 template <typename F, typename... A>
218 static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
219 A... args) {
220 auto ret = f(args...);
221 Results::store(cx, raw, ret);
222 return std::nullopt;
223 }
224};
225
227template <> struct WasmHostRet<void> {
228 using Results = WasmTypeList<std::tuple<>>;
229
230 template <typename F, typename... A>
231 static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
232 A... args) {
233 (void)cx;
234 (void)raw;
235 f(args...);
236 return std::nullopt;
237 }
238};
239
240// Alternative method of returning "nothing" (also enables `std::monostate` in
241// the `R` type of `Result` below)
242template <> struct WasmHostRet<std::monostate> : public WasmHostRet<void> {};
243
246template <typename R> struct WasmHostRet<Result<R, Trap>> {
247 using Results = WasmTypeList<R>;
248
249 template <typename F, typename... A>
250 static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
251 A... args) {
252 Result<R, Trap> ret = f(args...);
253 if (!ret) {
254 return ret.err();
255 }
256 Results::store(cx, raw, ret.ok());
257 return std::nullopt;
258 }
259};
260
261template <typename F, typename = void> struct WasmHostFunc;
262
265template <typename R, typename... A> struct WasmHostFunc<R (*)(A...)> {
266 using Params = WasmTypeList<std::tuple<A...>>;
267 using Results = typename WasmHostRet<R>::Results;
268
269 template <typename F>
270 static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
271 auto params = Params::load(cx, raw);
272 return std::apply(
273 [&](const auto &...val) {
274 return WasmHostRet<R>::invoke(f, cx, raw, val...);
275 },
276 params);
277 }
278};
279
281template <typename R, typename... A>
282struct WasmHostFunc<R (*)(Caller, A...)> : public WasmHostFunc<R (*)(A...)> {
283 // Override `invoke` here to pass the `cx` as the first parameter
284 template <typename F>
285 static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
286 auto params = WasmTypeList<std::tuple<A...>>::load(cx, raw);
287 return std::apply(
288 [&](const auto &...val) {
289 return WasmHostRet<R>::invoke(f, cx, raw, cx, val...);
290 },
291 params);
292 }
293};
294
296template <typename R, typename C, typename... A>
297struct WasmHostFunc<R (C::*)(A...)> : public WasmHostFunc<R (*)(A...)> {};
298
300template <typename R, typename C, typename... A>
301struct WasmHostFunc<R (C::*)(A...) const> : public WasmHostFunc<R (*)(A...)> {};
302
305template <typename R, typename C, typename... A>
306struct WasmHostFunc<R (C::*)(Caller, A...)>
307 : public WasmHostFunc<R (*)(Caller, A...)> {};
308
311template <typename R, typename C, typename... A>
312struct WasmHostFunc<R (C::*)(Caller, A...) const>
313 : public WasmHostFunc<R (*)(Caller, A...)> {};
314
317template <typename T>
318struct WasmHostFunc<T, std::void_t<decltype(&T::operator())>>
319 : public WasmHostFunc<decltype(&T::operator())> {};
320
321} // namespace detail
322
323using namespace detail;
324
325// forward-declaration for `Func::typed` below.
326template <typename Params, typename Results> class TypedFunc;
327
339class Func {
340 friend class Val;
341 friend class Instance;
342 friend class Linker;
343 template <typename Params, typename Results> friend class TypedFunc;
344
345 wasmtime_func_t func;
346
347 template <typename F>
348 static wasm_trap_t *raw_callback(void *env, wasmtime_caller_t *caller,
349 const wasmtime_val_t *args, size_t nargs,
350 wasmtime_val_t *results, size_t nresults) {
351 static_assert(alignof(Val) == alignof(wasmtime_val_t));
352 static_assert(sizeof(Val) == sizeof(wasmtime_val_t));
353 F *func = reinterpret_cast<F *>(env); // NOLINT
354 Span<const Val> args_span(reinterpret_cast<const Val *>(args), // NOLINT
355 nargs);
356 Span<Val> results_span(reinterpret_cast<Val *>(results), // NOLINT
357 nresults);
359 (*func)(Caller(caller), args_span, results_span);
360 if (!result) {
361 return result.err().capi_release();
362 }
363 return nullptr;
364 }
365
366 template <typename F>
367 static wasm_trap_t *
368 raw_callback_unchecked(void *env, wasmtime_caller_t *caller,
369 wasmtime_val_raw_t *args_and_results,
370 size_t nargs_and_results) {
371 (void)nargs_and_results;
372 using HostFunc = WasmHostFunc<F>;
373 Caller cx(caller);
374 F *func = reinterpret_cast<F *>(env); // NOLINT
375 auto trap = HostFunc::invoke(*func, cx, args_and_results);
376 if (trap) {
377 return trap->capi_release();
378 }
379 return nullptr;
380 }
381
382 template <typename F> static void raw_finalize(void *env) {
383 std::unique_ptr<F> ptr(reinterpret_cast<F *>(env)); // NOLINT
384 }
385
386public:
388 Func(wasmtime_func_t func) : func(func) {}
389
421 template <typename F,
422 std::enable_if_t<
423 std::is_invocable_r_v<Result<std::monostate, Trap>, F, Caller,
425 bool> = true>
426 Func(Store::Context cx, const FuncType &ty, F f) : func({}) {
427 wasmtime_func_new(cx.ptr, ty.ptr.get(), raw_callback<F>,
428 std::make_unique<F>(f).release(), raw_finalize<F>, &func);
429 }
430
469 template <typename F,
470 std::enable_if_t<WasmHostFunc<F>::Params::valid, bool> = true,
471 std::enable_if_t<WasmHostFunc<F>::Results::valid, bool> = true>
472 static Func wrap(Store::Context cx, F f) {
473 using HostFunc = WasmHostFunc<F>;
474 auto params = HostFunc::Params::types();
475 auto results = HostFunc::Results::types();
476 auto ty = FuncType::from_iters(params, results);
477 wasmtime_func_t func;
478 wasmtime_func_new_unchecked(cx.ptr, ty.ptr.get(), raw_callback_unchecked<F>,
479 std::make_unique<F>(f).release(),
480 raw_finalize<F>, &func);
481 return func;
482 }
483
504 template <typename I>
506 const I &end) const {
507 std::vector<wasmtime_val_t> raw_params;
508 raw_params.reserve(end - begin);
509 for (auto i = begin; i != end; i++) {
510 raw_params.push_back(i->val);
511 }
512 size_t nresults = this->type(cx)->results().size();
513 std::vector<wasmtime_val_t> raw_results(nresults);
514
515 wasm_trap_t *trap = nullptr;
516 auto *error =
517 wasmtime_func_call(cx.ptr, &func, raw_params.data(), raw_params.size(),
518 raw_results.data(), raw_results.capacity(), &trap);
519 if (error != nullptr) {
520 return TrapError(Error(error));
521 }
522 if (trap != nullptr) {
523 return TrapError(Trap(trap));
524 }
525
526 std::vector<Val> results;
527 results.reserve(nresults);
528 for (size_t i = 0; i < nresults; i++) {
529 results.push_back(raw_results[i]);
530 }
531 return results;
532 }
533
541 const std::vector<Val> &params) const {
542 return this->call(cx, params.begin(), params.end());
543 }
544
552 call(Store::Context cx, const std::initializer_list<Val> &params) const {
553 return this->call(cx, params.begin(), params.end());
554 }
555
558 return wasmtime_func_type(cx.ptr, &func);
559 }
560
578 template <typename Params, typename Results,
579 std::enable_if_t<WasmTypeList<Params>::valid, bool> = true,
580 std::enable_if_t<WasmTypeList<Results>::valid, bool> = true>
582 auto ty = this->type(cx);
583 if (!WasmTypeList<Params>::matches(ty->params()) ||
584 !WasmTypeList<Results>::matches(ty->results())) {
585 return Trap("static type for this function does not match actual type");
586 }
588 return ret;
589 }
590
592 const wasmtime_func_t &capi() const { return func; }
593};
594
599template <typename Params, typename Results> class TypedFunc {
600 friend class Func;
601 Func f;
602 TypedFunc(Func func) : f(func) {}
603
604public:
615 TrapResult<Results> call(Store::Context cx, const Params &params) const {
616 std::array<wasmtime_val_raw_t, std::max(WasmTypeList<Params>::size,
617 WasmTypeList<Results>::size)>
618 storage;
619 wasmtime_val_raw_t *ptr = storage.data();
620 if (ptr == nullptr)
621 ptr = reinterpret_cast<wasmtime_val_raw_t *>(alignof(wasmtime_val_raw_t));
622 WasmTypeList<Params>::store(cx, ptr, params);
623 wasm_trap_t *trap = nullptr;
624 auto *error = wasmtime_func_call_unchecked(cx.capi(), &f.func, ptr,
625 storage.size(), &trap);
626 if (error != nullptr) {
627 return TrapError(Error(error));
628 }
629 if (trap != nullptr) {
630 return TrapError(Trap(trap));
631 }
632 return WasmTypeList<Results>::load(cx, ptr);
633 }
634
636 const Func &func() const { return f; }
637};
638
639inline Val::Val(std::optional<Func> func) : val{} {
641 if (func) {
642 val.of.funcref = (*func).func;
643 } else {
644 wasmtime_funcref_set_null(&val.of.funcref);
645 }
646}
647
648inline Val::Val(Func func) : Val(std::optional(func)) {}
649inline Val::Val(ExternRef ptr) : Val(std::optional(ptr)) {}
650inline Val::Val(AnyRef ptr) : Val(std::optional(ptr)) {}
651
652inline std::optional<Func> Val::funcref() const {
653 if (val.kind != WASMTIME_FUNCREF) {
654 std::abort();
655 }
656 if (val.of.funcref.store_id == 0) {
657 return std::nullopt;
658 }
659 return Func(val.of.funcref);
660}
661
663template <> struct detail::WasmType<std::optional<Func>> {
665 static const bool valid = true;
667 static const ValKind kind = ValKind::FuncRef;
669 static void store(Store::Context cx, wasmtime_val_raw_t *p,
670 const std::optional<Func> func) {
671 if (func) {
672 p->funcref = wasmtime_func_to_raw(cx.capi(), &func->capi());
673 } else {
674 p->funcref = 0;
675 }
676 }
678 static std::optional<Func> load(Store::Context cx, wasmtime_val_raw_t *p) {
679 if (p->funcref == 0) {
680 return std::nullopt;
681 }
682 wasmtime_func_t ret;
683 wasmtime_func_from_raw(cx.capi(), p->funcref, &ret);
684 return ret;
685 }
686};
687
688} // namespace wasmtime
689
690#endif // WASMTIME_FUNC_HH
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:59
Store::Context context()
Explicitly acquire a Store::Context from this Caller.
Definition: func.hh:42
Errors coming from Wasmtime.
Definition: error.hh:26
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:76
Representation of a WebAssembly function.
Definition: func.hh:339
TrapResult< std::vector< Val > > call(Store::Context cx, const I &begin, const I &end) const
Invoke a WebAssembly function.
Definition: func.hh:505
Func(wasmtime_func_t func)
Creates a new function from the raw underlying C API representation.
Definition: func.hh:388
FuncType type(Store::Context cx) const
Returns the type of this function.
Definition: func.hh:557
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:540
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:472
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:552
const wasmtime_func_t & capi() const
Returns the raw underlying C API function this is using.
Definition: func.hh:592
Func(Store::Context cx, const FuncType &ty, F f)
Creates a new host-defined function.
Definition: func.hh:426
Result< TypedFunc< Params, Results >, Trap > typed(Store::Context cx) const
Statically checks this function against the provided types.
Definition: func.hh:581
A WebAssembly instance.
Definition: instance.hh:32
Helper class for linking modules together with name-based resolution.
Definition: linker.hh:26
Fallible result type used for Wasmtime.
Definition: error.hh:70
E && err()
Returns the error, if present, aborts if this is not an error.
Definition: error.hh:84
Span class used when c++20 is not available.
Definition: span.hh:47
An interior pointer into a Store.
Definition: store.hh:69
Context(wasmtime_context_t *ptr)
Creates a context from the raw C API pointer.
Definition: store.hh:86
const wasmtime_context_t * capi() const
Returns the underlying C API pointer.
Definition: store.hh:190
Owner of all WebAssembly objects.
Definition: store.hh:45
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:599
const Func & func() const
Returns the underlying un-typed Func for this function.
Definition: func.hh:636
TrapResult< Results > call(Store::Context cx, const Params &params) const
Calls this function with the provided parameters.
Definition: func.hh:615
Representation of a generic WebAssembly value.
Definition: val.hh:240
std::optional< Func > funcref() const
Definition: func.hh:652
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_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.
WASM_API_EXTERN wasmtime_context_t * wasmtime_caller_context(wasmtime_caller_t *caller)
Returns the store context of the caller object.
WASM_API_EXTERN wasm_functype_t * wasmtime_func_type(const wasmtime_context_t *store, const wasmtime_func_t *func)
Returns the type of the function specified.
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.
WASM_API_EXTERN 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_API_EXTERN 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.
#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:153
Representation of a function in Wasmtime.
Definition: extern.h:26
Container for different kinds of wasm values.
Definition: val.h:546
wasmtime_valkind_t kind
Discriminant of which field of of is valid.
Definition: val.h:548
wasmtime_valunion_t of
Container for the extern item's value.
Definition: val.h:550
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:470
uint32_t externref
Definition: val.h:506
wasmtime_v128 v128
Definition: val.h:490
void * funcref
Definition: val.h:513
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:401
#define WASMTIME_FUNCREF
Value of wasmtime_valkind_t meaning that wasmtime_val_t is a funcref.
Definition: val.h:388