1453bb9a4SAlex Crichton /**
2453bb9a4SAlex Crichton * \file wasmtime/func.hh
3453bb9a4SAlex Crichton */
4453bb9a4SAlex Crichton
5453bb9a4SAlex Crichton #ifndef WASMTIME_FUNC_HH
6453bb9a4SAlex Crichton #define WASMTIME_FUNC_HH
7453bb9a4SAlex Crichton
83a5dda5fSAlex Crichton #include <array>
9453bb9a4SAlex Crichton #include <wasmtime/error.hh>
103a5dda5fSAlex Crichton #include <wasmtime/extern_declare.hh>
11453bb9a4SAlex Crichton #include <wasmtime/func.h>
12453bb9a4SAlex Crichton #include <wasmtime/span.hh>
13453bb9a4SAlex Crichton #include <wasmtime/store.hh>
14453bb9a4SAlex Crichton #include <wasmtime/trap.hh>
15453bb9a4SAlex Crichton #include <wasmtime/types/func.hh>
16a045eaa9SAlex Crichton #include <wasmtime/types/val.hh>
17453bb9a4SAlex Crichton #include <wasmtime/val.hh>
18453bb9a4SAlex Crichton
19453bb9a4SAlex Crichton namespace wasmtime {
20453bb9a4SAlex Crichton
21453bb9a4SAlex Crichton /**
22453bb9a4SAlex Crichton * \brief Structure provided to host functions to lookup caller information or
23453bb9a4SAlex Crichton * acquire a `Store::Context`.
24453bb9a4SAlex Crichton *
25453bb9a4SAlex Crichton * This structure is passed to all host functions created with `Func`. It can be
26453bb9a4SAlex Crichton * used to create a `Store::Context`.
27453bb9a4SAlex Crichton */
28453bb9a4SAlex Crichton class Caller {
29453bb9a4SAlex Crichton friend class Func;
30453bb9a4SAlex Crichton friend class Store;
31453bb9a4SAlex Crichton wasmtime_caller_t *ptr;
Caller(wasmtime_caller_t * ptr)32453bb9a4SAlex Crichton Caller(wasmtime_caller_t *ptr) : ptr(ptr) {}
33453bb9a4SAlex Crichton
34453bb9a4SAlex Crichton public:
35453bb9a4SAlex Crichton /// Attempts to load an exported item from the calling instance.
36453bb9a4SAlex Crichton ///
37453bb9a4SAlex Crichton /// For more information see the Rust documentation -
38453bb9a4SAlex Crichton /// https://docs.wasmtime.dev/api/wasmtime/struct.Caller.html#method.get_export
39453bb9a4SAlex Crichton std::optional<Extern> get_export(std::string_view name);
40453bb9a4SAlex Crichton
41453bb9a4SAlex Crichton /// Explicitly acquire a `Store::Context` from this `Caller`.
context()42453bb9a4SAlex Crichton Store::Context context() { return this; }
43453bb9a4SAlex Crichton };
44453bb9a4SAlex Crichton
Context(Caller & caller)45453bb9a4SAlex Crichton inline Store::Context::Context(Caller &caller)
46453bb9a4SAlex Crichton : Context(wasmtime_caller_context(caller.ptr)) {}
Context(Caller * caller)47453bb9a4SAlex Crichton inline Store::Context::Context(Caller *caller) : Context(*caller) {}
48453bb9a4SAlex Crichton
49453bb9a4SAlex Crichton namespace detail {
50453bb9a4SAlex Crichton
51453bb9a4SAlex Crichton /// A "trait" for native types that correspond to WebAssembly types for use with
52453bb9a4SAlex Crichton /// `Func::wrap` and `TypedFunc::call`
53a045eaa9SAlex Crichton template <typename T> struct WasmType {
54a045eaa9SAlex Crichton static const bool valid = false;
55a045eaa9SAlex Crichton };
56453bb9a4SAlex Crichton
57453bb9a4SAlex Crichton /// Helper macro to define `WasmType` definitions for primitive types like
58453bb9a4SAlex Crichton /// int32_t and such.
59453bb9a4SAlex Crichton // NOLINTNEXTLINE
60453bb9a4SAlex Crichton #define NATIVE_WASM_TYPE(native, valkind, field) \
61453bb9a4SAlex Crichton template <> struct WasmType<native> { \
62453bb9a4SAlex Crichton static const bool valid = true; \
63453bb9a4SAlex Crichton static const ValKind kind = ValKind::valkind; \
64453bb9a4SAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *p, \
65453bb9a4SAlex Crichton const native &t) { \
66eaa01d7bSTill Schneidereit (void)cx; \
67453bb9a4SAlex Crichton p->field = t; \
68453bb9a4SAlex Crichton } \
69453bb9a4SAlex Crichton static native load(Store::Context cx, wasmtime_val_raw_t *p) { \
70eaa01d7bSTill Schneidereit (void)cx; \
71453bb9a4SAlex Crichton return p->field; \
72453bb9a4SAlex Crichton } \
73453bb9a4SAlex Crichton };
74453bb9a4SAlex Crichton
75453bb9a4SAlex Crichton NATIVE_WASM_TYPE(int32_t, I32, i32)
76453bb9a4SAlex Crichton NATIVE_WASM_TYPE(uint32_t, I32, i32)
77453bb9a4SAlex Crichton NATIVE_WASM_TYPE(int64_t, I64, i64)
78453bb9a4SAlex Crichton NATIVE_WASM_TYPE(uint64_t, I64, i64)
79453bb9a4SAlex Crichton NATIVE_WASM_TYPE(float, F32, f32)
80453bb9a4SAlex Crichton NATIVE_WASM_TYPE(double, F64, f64)
81453bb9a4SAlex Crichton
82453bb9a4SAlex Crichton #undef NATIVE_WASM_TYPE
83453bb9a4SAlex Crichton
84453bb9a4SAlex Crichton /// Type information for `externref`, represented on the host as an optional
85453bb9a4SAlex Crichton /// `ExternRef`.
86453bb9a4SAlex Crichton template <> struct WasmType<std::optional<ExternRef>> {
87453bb9a4SAlex Crichton static const bool valid = true;
88453bb9a4SAlex Crichton static const ValKind kind = ValKind::ExternRef;
storewasmtime::detail::WasmType89453bb9a4SAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *p,
90adff9d9dSAlex Crichton std::optional<ExternRef> &&ref) {
91adff9d9dSAlex Crichton if (ref) {
92adff9d9dSAlex Crichton p->externref = ref->take_raw(cx);
93adff9d9dSAlex Crichton } else {
94adff9d9dSAlex Crichton p->externref = 0;
95adff9d9dSAlex Crichton }
96adff9d9dSAlex Crichton }
storewasmtime::detail::WasmType97adff9d9dSAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *p,
98453bb9a4SAlex Crichton const std::optional<ExternRef> &ref) {
99453bb9a4SAlex Crichton if (ref) {
100adff9d9dSAlex Crichton p->externref = ref->borrow_raw(cx);
101453bb9a4SAlex Crichton } else {
102453bb9a4SAlex Crichton p->externref = 0;
103453bb9a4SAlex Crichton }
104453bb9a4SAlex Crichton }
loadwasmtime::detail::WasmType105453bb9a4SAlex Crichton static std::optional<ExternRef> load(Store::Context cx,
106453bb9a4SAlex Crichton wasmtime_val_raw_t *p) {
107453bb9a4SAlex Crichton if (p->externref == 0) {
108453bb9a4SAlex Crichton return std::nullopt;
109453bb9a4SAlex Crichton }
110453bb9a4SAlex Crichton wasmtime_externref_t val;
111579ec46bSAlex Crichton wasmtime_externref_from_raw(cx.capi(), p->externref, &val);
112453bb9a4SAlex Crichton return ExternRef(val);
113453bb9a4SAlex Crichton }
114453bb9a4SAlex Crichton };
115453bb9a4SAlex Crichton
116453bb9a4SAlex Crichton /// Type information for the `V128` host value used as a wasm value.
117453bb9a4SAlex Crichton template <> struct WasmType<V128> {
118453bb9a4SAlex Crichton static const bool valid = true;
119453bb9a4SAlex Crichton static const ValKind kind = ValKind::V128;
storewasmtime::detail::WasmType120453bb9a4SAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *p, const V128 &t) {
121eaa01d7bSTill Schneidereit (void)cx;
122453bb9a4SAlex Crichton memcpy(&p->v128[0], &t.v128[0], sizeof(wasmtime_v128));
123453bb9a4SAlex Crichton }
loadwasmtime::detail::WasmType124eaa01d7bSTill Schneidereit static V128 load(Store::Context cx, wasmtime_val_raw_t *p) {
125eaa01d7bSTill Schneidereit (void)cx;
126eaa01d7bSTill Schneidereit return p->v128;
127eaa01d7bSTill Schneidereit }
128453bb9a4SAlex Crichton };
129453bb9a4SAlex Crichton
130453bb9a4SAlex Crichton /// A "trait" for a list of types and operations on them, used for `Func::wrap`
131453bb9a4SAlex Crichton /// and `TypedFunc::call`
132453bb9a4SAlex Crichton ///
133453bb9a4SAlex Crichton /// The base case is a single type which is a list of one element.
134453bb9a4SAlex Crichton template <typename T> struct WasmTypeList {
135453bb9a4SAlex Crichton static const bool valid = WasmType<T>::valid;
136453bb9a4SAlex Crichton static const size_t size = 1;
matcheswasmtime::detail::WasmTypeList137453bb9a4SAlex Crichton static bool matches(ValType::ListRef types) {
138453bb9a4SAlex Crichton return WasmTypeList<std::tuple<T>>::matches(types);
139453bb9a4SAlex Crichton }
storewasmtime::detail::WasmTypeList140adff9d9dSAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *storage, T &&t) {
141adff9d9dSAlex Crichton WasmType<T>::store(cx, storage, t);
142adff9d9dSAlex Crichton }
storewasmtime::detail::WasmTypeList143453bb9a4SAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *storage,
144453bb9a4SAlex Crichton const T &t) {
145453bb9a4SAlex Crichton WasmType<T>::store(cx, storage, t);
146453bb9a4SAlex Crichton }
loadwasmtime::detail::WasmTypeList147453bb9a4SAlex Crichton static T load(Store::Context cx, wasmtime_val_raw_t *storage) {
148453bb9a4SAlex Crichton return WasmType<T>::load(cx, storage);
149453bb9a4SAlex Crichton }
typeswasmtime::detail::WasmTypeList150453bb9a4SAlex Crichton static std::vector<ValType> types() { return {WasmType<T>::kind}; }
151453bb9a4SAlex Crichton };
152453bb9a4SAlex Crichton
153453bb9a4SAlex Crichton /// std::monostate translates to an empty list of types.
154453bb9a4SAlex Crichton template <> struct WasmTypeList<std::monostate> {
155453bb9a4SAlex Crichton static const bool valid = true;
156453bb9a4SAlex Crichton static const size_t size = 0;
matcheswasmtime::detail::WasmTypeList157453bb9a4SAlex Crichton static bool matches(ValType::ListRef types) { return types.size() == 0; }
storewasmtime::detail::WasmTypeList158453bb9a4SAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *storage,
159eaa01d7bSTill Schneidereit const std::monostate &t) {
160eaa01d7bSTill Schneidereit (void)cx;
161eaa01d7bSTill Schneidereit (void)storage;
162eaa01d7bSTill Schneidereit (void)t;
163eaa01d7bSTill Schneidereit }
loadwasmtime::detail::WasmTypeList164453bb9a4SAlex Crichton static std::monostate load(Store::Context cx, wasmtime_val_raw_t *storage) {
165eaa01d7bSTill Schneidereit (void)cx;
166eaa01d7bSTill Schneidereit (void)storage;
167453bb9a4SAlex Crichton return std::monostate();
168453bb9a4SAlex Crichton }
typeswasmtime::detail::WasmTypeList169453bb9a4SAlex Crichton static std::vector<ValType> types() { return {}; }
170453bb9a4SAlex Crichton };
171453bb9a4SAlex Crichton
172453bb9a4SAlex Crichton /// std::tuple<> translates to the corresponding list of types
173453bb9a4SAlex Crichton template <typename... T> struct WasmTypeList<std::tuple<T...>> {
174453bb9a4SAlex Crichton static const bool valid = (WasmType<T>::valid && ...);
175453bb9a4SAlex Crichton static const size_t size = sizeof...(T);
matcheswasmtime::detail::WasmTypeList176453bb9a4SAlex Crichton static bool matches(ValType::ListRef types) {
177453bb9a4SAlex Crichton if (types.size() != size) {
178453bb9a4SAlex Crichton return false;
179453bb9a4SAlex Crichton }
180453bb9a4SAlex Crichton size_t n = 0;
181453bb9a4SAlex Crichton return ((WasmType<T>::kind == types.begin()[n++].kind()) && ...);
182453bb9a4SAlex Crichton }
storewasmtime::detail::WasmTypeList183453bb9a4SAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *storage,
184adff9d9dSAlex Crichton std::tuple<T...> &&t) {
185adff9d9dSAlex Crichton size_t n = 0;
186adff9d9dSAlex Crichton std::apply(
187adff9d9dSAlex Crichton [&](auto &...val) {
188adff9d9dSAlex Crichton (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
189adff9d9dSAlex Crichton },
190adff9d9dSAlex Crichton t);
191adff9d9dSAlex Crichton }
storewasmtime::detail::WasmTypeList192adff9d9dSAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *storage,
193453bb9a4SAlex Crichton const std::tuple<T...> &t) {
194453bb9a4SAlex Crichton size_t n = 0;
195453bb9a4SAlex Crichton std::apply(
196453bb9a4SAlex Crichton [&](const auto &...val) {
197453bb9a4SAlex Crichton (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
198453bb9a4SAlex Crichton },
199453bb9a4SAlex Crichton t);
200453bb9a4SAlex Crichton }
loadwasmtime::detail::WasmTypeList201453bb9a4SAlex Crichton static std::tuple<T...> load(Store::Context cx, wasmtime_val_raw_t *storage) {
202eaa01d7bSTill Schneidereit (void)cx;
203eaa01d7bSTill Schneidereit return std::tuple<T...>{WasmType<T>::load(cx, storage++)...}; // NOLINT
204453bb9a4SAlex Crichton }
typeswasmtime::detail::WasmTypeList205453bb9a4SAlex Crichton static std::vector<ValType> types() { return {WasmType<T>::kind...}; }
206453bb9a4SAlex Crichton };
207453bb9a4SAlex Crichton
208453bb9a4SAlex Crichton /// A "trait" for what can be returned from closures specified to `Func::wrap`.
209453bb9a4SAlex Crichton ///
210453bb9a4SAlex Crichton /// The base case here is a bare return value like `int32_t`.
211453bb9a4SAlex Crichton template <typename R> struct WasmHostRet {
212453bb9a4SAlex Crichton using Results = WasmTypeList<R>;
213453bb9a4SAlex Crichton
214453bb9a4SAlex Crichton template <typename F, typename... A>
invokewasmtime::detail::WasmHostRet215453bb9a4SAlex Crichton static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
216453bb9a4SAlex Crichton A... args) {
217453bb9a4SAlex Crichton auto ret = f(args...);
218453bb9a4SAlex Crichton Results::store(cx, raw, ret);
219453bb9a4SAlex Crichton return std::nullopt;
220453bb9a4SAlex Crichton }
221453bb9a4SAlex Crichton };
222453bb9a4SAlex Crichton
223453bb9a4SAlex Crichton /// Host functions can return nothing
224453bb9a4SAlex Crichton template <> struct WasmHostRet<void> {
225453bb9a4SAlex Crichton using Results = WasmTypeList<std::tuple<>>;
226453bb9a4SAlex Crichton
227453bb9a4SAlex Crichton template <typename F, typename... A>
invokewasmtime::detail::WasmHostRet228453bb9a4SAlex Crichton static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
229453bb9a4SAlex Crichton A... args) {
230eaa01d7bSTill Schneidereit (void)cx;
231eaa01d7bSTill Schneidereit (void)raw;
232453bb9a4SAlex Crichton f(args...);
233453bb9a4SAlex Crichton return std::nullopt;
234453bb9a4SAlex Crichton }
235453bb9a4SAlex Crichton };
236453bb9a4SAlex Crichton
237453bb9a4SAlex Crichton // Alternative method of returning "nothing" (also enables `std::monostate` in
238453bb9a4SAlex Crichton // the `R` type of `Result` below)
239453bb9a4SAlex Crichton template <> struct WasmHostRet<std::monostate> : public WasmHostRet<void> {};
240453bb9a4SAlex Crichton
241453bb9a4SAlex Crichton /// Host functions can return a result which allows them to also possibly return
242453bb9a4SAlex Crichton /// a trap.
243453bb9a4SAlex Crichton template <typename R> struct WasmHostRet<Result<R, Trap>> {
244453bb9a4SAlex Crichton using Results = WasmTypeList<R>;
245453bb9a4SAlex Crichton
246453bb9a4SAlex Crichton template <typename F, typename... A>
invokewasmtime::detail::WasmHostRet247453bb9a4SAlex Crichton static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
248453bb9a4SAlex Crichton A... args) {
249453bb9a4SAlex Crichton Result<R, Trap> ret = f(args...);
250453bb9a4SAlex Crichton if (!ret) {
251453bb9a4SAlex Crichton return ret.err();
252453bb9a4SAlex Crichton }
253453bb9a4SAlex Crichton Results::store(cx, raw, ret.ok());
254453bb9a4SAlex Crichton return std::nullopt;
255453bb9a4SAlex Crichton }
256453bb9a4SAlex Crichton };
257453bb9a4SAlex Crichton
258453bb9a4SAlex Crichton template <typename F, typename = void> struct WasmHostFunc;
259453bb9a4SAlex Crichton
260453bb9a4SAlex Crichton /// Base type information for host free-function pointers being used as wasm
261453bb9a4SAlex Crichton /// functions
262453bb9a4SAlex Crichton template <typename R, typename... A> struct WasmHostFunc<R (*)(A...)> {
263453bb9a4SAlex Crichton using Params = WasmTypeList<std::tuple<A...>>;
264453bb9a4SAlex Crichton using Results = typename WasmHostRet<R>::Results;
265453bb9a4SAlex Crichton
266453bb9a4SAlex Crichton template <typename F>
invokewasmtime::detail::WasmHostFunc267453bb9a4SAlex Crichton static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
268453bb9a4SAlex Crichton auto params = Params::load(cx, raw);
269453bb9a4SAlex Crichton return std::apply(
270453bb9a4SAlex Crichton [&](const auto &...val) {
271453bb9a4SAlex Crichton return WasmHostRet<R>::invoke(f, cx, raw, val...);
272453bb9a4SAlex Crichton },
273453bb9a4SAlex Crichton params);
274453bb9a4SAlex Crichton }
275453bb9a4SAlex Crichton };
276453bb9a4SAlex Crichton
277453bb9a4SAlex Crichton /// Function type information, but with a `Caller` first parameter
278453bb9a4SAlex Crichton template <typename R, typename... A>
279453bb9a4SAlex Crichton struct WasmHostFunc<R (*)(Caller, A...)> : public WasmHostFunc<R (*)(A...)> {
280453bb9a4SAlex Crichton // Override `invoke` here to pass the `cx` as the first parameter
281453bb9a4SAlex Crichton template <typename F>
invokewasmtime::detail::WasmHostFunc282453bb9a4SAlex Crichton static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
283453bb9a4SAlex Crichton auto params = WasmTypeList<std::tuple<A...>>::load(cx, raw);
284453bb9a4SAlex Crichton return std::apply(
285453bb9a4SAlex Crichton [&](const auto &...val) {
286453bb9a4SAlex Crichton return WasmHostRet<R>::invoke(f, cx, raw, cx, val...);
287453bb9a4SAlex Crichton },
288453bb9a4SAlex Crichton params);
289453bb9a4SAlex Crichton }
290453bb9a4SAlex Crichton };
291453bb9a4SAlex Crichton
292453bb9a4SAlex Crichton /// Function type information, but with a class method.
293453bb9a4SAlex Crichton template <typename R, typename C, typename... A>
294453bb9a4SAlex Crichton struct WasmHostFunc<R (C::*)(A...)> : public WasmHostFunc<R (*)(A...)> {};
295453bb9a4SAlex Crichton
296453bb9a4SAlex Crichton /// Function type information, but with a const class method.
297453bb9a4SAlex Crichton template <typename R, typename C, typename... A>
298453bb9a4SAlex Crichton struct WasmHostFunc<R (C::*)(A...) const> : public WasmHostFunc<R (*)(A...)> {};
299453bb9a4SAlex Crichton
300453bb9a4SAlex Crichton /// Function type information, but as a host method with a `Caller` first
301453bb9a4SAlex Crichton /// parameter.
302453bb9a4SAlex Crichton template <typename R, typename C, typename... A>
303453bb9a4SAlex Crichton struct WasmHostFunc<R (C::*)(Caller, A...)>
304453bb9a4SAlex Crichton : public WasmHostFunc<R (*)(Caller, A...)> {};
305453bb9a4SAlex Crichton
306453bb9a4SAlex Crichton /// Function type information, but as a host const method with a `Caller`
307453bb9a4SAlex Crichton /// first parameter.
308453bb9a4SAlex Crichton template <typename R, typename C, typename... A>
309453bb9a4SAlex Crichton struct WasmHostFunc<R (C::*)(Caller, A...) const>
310453bb9a4SAlex Crichton : public WasmHostFunc<R (*)(Caller, A...)> {};
311453bb9a4SAlex Crichton
312453bb9a4SAlex Crichton /// Base type information for host callables being used as wasm
313453bb9a4SAlex Crichton /// functions
314453bb9a4SAlex Crichton template <typename T>
315453bb9a4SAlex Crichton struct WasmHostFunc<T, std::void_t<decltype(&T::operator())>>
316453bb9a4SAlex Crichton : public WasmHostFunc<decltype(&T::operator())> {};
317453bb9a4SAlex Crichton
318453bb9a4SAlex Crichton } // namespace detail
319453bb9a4SAlex Crichton
320453bb9a4SAlex Crichton using namespace detail;
321453bb9a4SAlex Crichton
322453bb9a4SAlex Crichton // forward-declaration for `Func::typed` below.
323453bb9a4SAlex Crichton template <typename Params, typename Results> class TypedFunc;
324453bb9a4SAlex Crichton
325453bb9a4SAlex Crichton /**
326453bb9a4SAlex Crichton * \brief Representation of a WebAssembly function.
327453bb9a4SAlex Crichton *
328453bb9a4SAlex Crichton * This class represents a WebAssembly function, either created through
329453bb9a4SAlex Crichton * instantiating a module or a host function.
330453bb9a4SAlex Crichton *
331453bb9a4SAlex Crichton * Note that this type does not itself own any resources. It points to resources
332453bb9a4SAlex Crichton * owned within a `Store` and the `Store` must be passed in as the first
333453bb9a4SAlex Crichton * argument to the functions defined on `Func`. Note that if the wrong `Store`
334453bb9a4SAlex Crichton * is passed in then the process will be aborted.
335453bb9a4SAlex Crichton */
336453bb9a4SAlex Crichton class Func {
337453bb9a4SAlex Crichton friend class Val;
338453bb9a4SAlex Crichton friend class Instance;
339453bb9a4SAlex Crichton friend class Linker;
340453bb9a4SAlex Crichton template <typename Params, typename Results> friend class TypedFunc;
341453bb9a4SAlex Crichton
342453bb9a4SAlex Crichton wasmtime_func_t func;
343453bb9a4SAlex Crichton
344453bb9a4SAlex Crichton template <typename F>
raw_callback(void * env,wasmtime_caller_t * caller,const wasmtime_val_t * args,size_t nargs,wasmtime_val_t * results,size_t nresults)345453bb9a4SAlex Crichton static wasm_trap_t *raw_callback(void *env, wasmtime_caller_t *caller,
346453bb9a4SAlex Crichton const wasmtime_val_t *args, size_t nargs,
347453bb9a4SAlex Crichton wasmtime_val_t *results, size_t nresults) {
348453bb9a4SAlex Crichton static_assert(alignof(Val) == alignof(wasmtime_val_t));
349453bb9a4SAlex Crichton static_assert(sizeof(Val) == sizeof(wasmtime_val_t));
350453bb9a4SAlex Crichton F *func = reinterpret_cast<F *>(env); // NOLINT
351453bb9a4SAlex Crichton Span<const Val> args_span(reinterpret_cast<const Val *>(args), // NOLINT
352453bb9a4SAlex Crichton nargs);
353453bb9a4SAlex Crichton Span<Val> results_span(reinterpret_cast<Val *>(results), // NOLINT
354453bb9a4SAlex Crichton nresults);
355453bb9a4SAlex Crichton Result<std::monostate, Trap> result =
356453bb9a4SAlex Crichton (*func)(Caller(caller), args_span, results_span);
357453bb9a4SAlex Crichton if (!result) {
358*311d023aSAlex Crichton return result.err().capi_release();
359453bb9a4SAlex Crichton }
360453bb9a4SAlex Crichton return nullptr;
361453bb9a4SAlex Crichton }
362453bb9a4SAlex Crichton
363453bb9a4SAlex Crichton template <typename F>
364453bb9a4SAlex Crichton static wasm_trap_t *
raw_callback_unchecked(void * env,wasmtime_caller_t * caller,wasmtime_val_raw_t * args_and_results,size_t nargs_and_results)365453bb9a4SAlex Crichton raw_callback_unchecked(void *env, wasmtime_caller_t *caller,
366453bb9a4SAlex Crichton wasmtime_val_raw_t *args_and_results,
367453bb9a4SAlex Crichton size_t nargs_and_results) {
368eaa01d7bSTill Schneidereit (void)nargs_and_results;
369453bb9a4SAlex Crichton using HostFunc = WasmHostFunc<F>;
370453bb9a4SAlex Crichton Caller cx(caller);
371453bb9a4SAlex Crichton F *func = reinterpret_cast<F *>(env); // NOLINT
372453bb9a4SAlex Crichton auto trap = HostFunc::invoke(*func, cx, args_and_results);
373453bb9a4SAlex Crichton if (trap) {
374*311d023aSAlex Crichton return trap->capi_release();
375453bb9a4SAlex Crichton }
376453bb9a4SAlex Crichton return nullptr;
377453bb9a4SAlex Crichton }
378453bb9a4SAlex Crichton
raw_finalize(void * env)379453bb9a4SAlex Crichton template <typename F> static void raw_finalize(void *env) {
380453bb9a4SAlex Crichton std::unique_ptr<F> ptr(reinterpret_cast<F *>(env)); // NOLINT
381453bb9a4SAlex Crichton }
382453bb9a4SAlex Crichton
383453bb9a4SAlex Crichton public:
384453bb9a4SAlex Crichton /// Creates a new function from the raw underlying C API representation.
Func(wasmtime_func_t func)385453bb9a4SAlex Crichton Func(wasmtime_func_t func) : func(func) {}
386453bb9a4SAlex Crichton
387453bb9a4SAlex Crichton /**
388453bb9a4SAlex Crichton * \brief Creates a new host-defined function.
389453bb9a4SAlex Crichton *
390453bb9a4SAlex Crichton * This constructor is used to create a host function within the store
391453bb9a4SAlex Crichton * provided. This is how WebAssembly can call into the host and make use of
392453bb9a4SAlex Crichton * external functionality.
393453bb9a4SAlex Crichton *
394453bb9a4SAlex Crichton * > **Note**: host functions created this way are more flexible but not
395453bb9a4SAlex Crichton * > as fast to call as those created by `Func::wrap`.
396453bb9a4SAlex Crichton *
397453bb9a4SAlex Crichton * \param cx the store to create the function within
398453bb9a4SAlex Crichton * \param ty the type of the function that will be created
399453bb9a4SAlex Crichton * \param f the host callback to be executed when this function is called.
400453bb9a4SAlex Crichton *
401453bb9a4SAlex Crichton * The parameter `f` is expected to be a lambda (or a lambda lookalike) which
402453bb9a4SAlex Crichton * takes three parameters:
403453bb9a4SAlex Crichton *
404453bb9a4SAlex Crichton * * The first parameter is a `Caller` to get recursive access to the store
405453bb9a4SAlex Crichton * and other caller state.
406453bb9a4SAlex Crichton * * The second parameter is a `Span<const Val>` which is the list of
407453bb9a4SAlex Crichton * parameters to the function. These parameters are guaranteed to be of the
408453bb9a4SAlex Crichton * types specified by `ty` when constructing this function.
409453bb9a4SAlex Crichton * * The last argument is `Span<Val>` which is where to write the return
410453bb9a4SAlex Crichton * values of the function. The function must produce the types of values
411453bb9a4SAlex Crichton * specified by `ty` or otherwise a trap will be raised.
412453bb9a4SAlex Crichton *
413453bb9a4SAlex Crichton * The parameter `f` is expected to return `Result<std::monostate, Trap>`.
414453bb9a4SAlex Crichton * This allows `f` to raise a trap if desired, or otherwise return no trap and
415453bb9a4SAlex Crichton * finish successfully. If a trap is raised then the results pointer does not
416453bb9a4SAlex Crichton * need to be written to.
417453bb9a4SAlex Crichton */
418453bb9a4SAlex Crichton template <typename F,
419453bb9a4SAlex Crichton std::enable_if_t<
420453bb9a4SAlex Crichton std::is_invocable_r_v<Result<std::monostate, Trap>, F, Caller,
421453bb9a4SAlex Crichton Span<const Val>, Span<Val>>,
422453bb9a4SAlex Crichton bool> = true>
Func(Store::Context cx,const FuncType & ty,F f)423453bb9a4SAlex Crichton Func(Store::Context cx, const FuncType &ty, F f) : func({}) {
424453bb9a4SAlex Crichton wasmtime_func_new(cx.ptr, ty.ptr.get(), raw_callback<F>,
425453bb9a4SAlex Crichton std::make_unique<F>(f).release(), raw_finalize<F>, &func);
426453bb9a4SAlex Crichton }
427453bb9a4SAlex Crichton
428453bb9a4SAlex Crichton /**
429453bb9a4SAlex Crichton * \brief Creates a new host function from the provided callback `f`,
430453bb9a4SAlex Crichton * inferring the WebAssembly function type from the host signature.
431453bb9a4SAlex Crichton *
432453bb9a4SAlex Crichton * This function is akin to the `Func` constructor except that the WebAssembly
433453bb9a4SAlex Crichton * type does not need to be specified and additionally the signature of `f`
434453bb9a4SAlex Crichton * is different. The main goal of this function is to enable WebAssembly to
435453bb9a4SAlex Crichton * call the function `f` as-fast-as-possible without having to validate any
436453bb9a4SAlex Crichton * types or such.
437453bb9a4SAlex Crichton *
438453bb9a4SAlex Crichton * The function `f` can optionally take a `Caller` as its first parameter,
439453bb9a4SAlex Crichton * but otherwise its arguments are translated to WebAssembly types:
440453bb9a4SAlex Crichton *
441453bb9a4SAlex Crichton * * `int32_t`, `uint32_t` - `i32`
442453bb9a4SAlex Crichton * * `int64_t`, `uint64_t` - `i64`
443453bb9a4SAlex Crichton * * `float` - `f32`
444453bb9a4SAlex Crichton * * `double` - `f64`
445453bb9a4SAlex Crichton * * `std::optional<Func>` - `funcref`
446453bb9a4SAlex Crichton * * `std::optional<ExternRef>` - `externref`
447453bb9a4SAlex Crichton * * `wasmtime::V128` - `v128`
448453bb9a4SAlex Crichton *
449453bb9a4SAlex Crichton * The function may only take these arguments and if it takes any other kinds
450453bb9a4SAlex Crichton * of arguments then it will fail to compile.
451453bb9a4SAlex Crichton *
452453bb9a4SAlex Crichton * The function may return a few different flavors of return values:
453453bb9a4SAlex Crichton *
454453bb9a4SAlex Crichton * * `void` - interpreted as returning nothing
455453bb9a4SAlex Crichton * * Any type above - interpreted as a singular return value.
456453bb9a4SAlex Crichton * * `std::tuple<T...>` where `T` is one of the valid argument types -
457453bb9a4SAlex Crichton * interpreted as returning multiple values.
458453bb9a4SAlex Crichton * * `Result<T, Trap>` where `T` is another valid return type - interpreted as
459453bb9a4SAlex Crichton * a function that returns `T` to wasm but is optionally allowed to also
460453bb9a4SAlex Crichton * raise a trap.
461453bb9a4SAlex Crichton *
462453bb9a4SAlex Crichton * It's recommended, if possible, to use this function over the `Func`
463453bb9a4SAlex Crichton * constructor since this is generally easier to work with and also enables
464453bb9a4SAlex Crichton * a faster path for WebAssembly to call this function.
465453bb9a4SAlex Crichton */
466453bb9a4SAlex Crichton template <typename F,
467453bb9a4SAlex Crichton std::enable_if_t<WasmHostFunc<F>::Params::valid, bool> = true,
468453bb9a4SAlex Crichton std::enable_if_t<WasmHostFunc<F>::Results::valid, bool> = true>
wrap(Store::Context cx,F f)469453bb9a4SAlex Crichton static Func wrap(Store::Context cx, F f) {
470453bb9a4SAlex Crichton using HostFunc = WasmHostFunc<F>;
471453bb9a4SAlex Crichton auto params = HostFunc::Params::types();
472453bb9a4SAlex Crichton auto results = HostFunc::Results::types();
473453bb9a4SAlex Crichton auto ty = FuncType::from_iters(params, results);
474453bb9a4SAlex Crichton wasmtime_func_t func;
475453bb9a4SAlex Crichton wasmtime_func_new_unchecked(cx.ptr, ty.ptr.get(), raw_callback_unchecked<F>,
476453bb9a4SAlex Crichton std::make_unique<F>(f).release(),
477453bb9a4SAlex Crichton raw_finalize<F>, &func);
478453bb9a4SAlex Crichton return func;
479453bb9a4SAlex Crichton }
480453bb9a4SAlex Crichton
481453bb9a4SAlex Crichton /**
482453bb9a4SAlex Crichton * \brief Invoke a WebAssembly function.
483453bb9a4SAlex Crichton *
484453bb9a4SAlex Crichton * This function will execute this WebAssembly function. This function muts be
485453bb9a4SAlex Crichton * defined within the `cx`'s store provided. The `params` argument is the list
486453bb9a4SAlex Crichton * of parameters that are passed to the wasm function, and the types of the
487453bb9a4SAlex Crichton * values within `params` must match the type signature of this function.
488453bb9a4SAlex Crichton *
489453bb9a4SAlex Crichton * This may return one of three values:
490453bb9a4SAlex Crichton *
491453bb9a4SAlex Crichton * * First the function could succeed, returning a vector of values
492453bb9a4SAlex Crichton * representing the results of the function.
493453bb9a4SAlex Crichton * * Otherwise a `Trap` might be generated by the WebAssembly function.
494453bb9a4SAlex Crichton * * Finally an `Error` could be returned indicating that `params` were not of
495453bb9a4SAlex Crichton * the right type.
496453bb9a4SAlex Crichton *
497453bb9a4SAlex Crichton * > **Note**: for optimized calls into WebAssembly where the function
498453bb9a4SAlex Crichton * > signature is statically known it's recommended to use `Func::typed` and
499453bb9a4SAlex Crichton * > `TypedFunc::call`.
500453bb9a4SAlex Crichton */
501453bb9a4SAlex Crichton template <typename I>
call(Store::Context cx,const I & begin,const I & end) const502453bb9a4SAlex Crichton TrapResult<std::vector<Val>> call(Store::Context cx, const I &begin,
503453bb9a4SAlex Crichton const I &end) const {
504453bb9a4SAlex Crichton std::vector<wasmtime_val_t> raw_params;
505453bb9a4SAlex Crichton raw_params.reserve(end - begin);
506453bb9a4SAlex Crichton for (auto i = begin; i != end; i++) {
507453bb9a4SAlex Crichton raw_params.push_back(i->val);
508453bb9a4SAlex Crichton }
509453bb9a4SAlex Crichton size_t nresults = this->type(cx)->results().size();
510453bb9a4SAlex Crichton std::vector<wasmtime_val_t> raw_results(nresults);
511453bb9a4SAlex Crichton
512453bb9a4SAlex Crichton wasm_trap_t *trap = nullptr;
513453bb9a4SAlex Crichton auto *error =
514453bb9a4SAlex Crichton wasmtime_func_call(cx.ptr, &func, raw_params.data(), raw_params.size(),
515453bb9a4SAlex Crichton raw_results.data(), raw_results.capacity(), &trap);
516453bb9a4SAlex Crichton if (error != nullptr) {
517453bb9a4SAlex Crichton return TrapError(Error(error));
518453bb9a4SAlex Crichton }
519453bb9a4SAlex Crichton if (trap != nullptr) {
520453bb9a4SAlex Crichton return TrapError(Trap(trap));
521453bb9a4SAlex Crichton }
522453bb9a4SAlex Crichton
523453bb9a4SAlex Crichton std::vector<Val> results;
524453bb9a4SAlex Crichton results.reserve(nresults);
525453bb9a4SAlex Crichton for (size_t i = 0; i < nresults; i++) {
526453bb9a4SAlex Crichton results.push_back(raw_results[i]);
527453bb9a4SAlex Crichton }
528453bb9a4SAlex Crichton return results;
529453bb9a4SAlex Crichton }
530453bb9a4SAlex Crichton
531453bb9a4SAlex Crichton /**
532453bb9a4SAlex Crichton * \brief Helper function for `call(Store::Context cx, const I &begin, const I
533453bb9a4SAlex Crichton * &end)`
534453bb9a4SAlex Crichton *
535453bb9a4SAlex Crichton * \see call(Store::Context cx, const I &begin, const I &end)
536453bb9a4SAlex Crichton */
call(Store::Context cx,const std::vector<Val> & params) const537453bb9a4SAlex Crichton TrapResult<std::vector<Val>> call(Store::Context cx,
538453bb9a4SAlex Crichton const std::vector<Val> ¶ms) const {
539453bb9a4SAlex Crichton return this->call(cx, params.begin(), params.end());
540453bb9a4SAlex Crichton }
541453bb9a4SAlex Crichton
542453bb9a4SAlex Crichton /**
543453bb9a4SAlex Crichton * \brief Helper function for `call(Store::Context cx, const I &begin, const I
544453bb9a4SAlex Crichton * &end)`
545453bb9a4SAlex Crichton *
546453bb9a4SAlex Crichton * \see call(Store::Context cx, const I &begin, const I &end)
547453bb9a4SAlex Crichton */
548453bb9a4SAlex Crichton TrapResult<std::vector<Val>>
call(Store::Context cx,const std::initializer_list<Val> & params) const549453bb9a4SAlex Crichton call(Store::Context cx, const std::initializer_list<Val> ¶ms) const {
550453bb9a4SAlex Crichton return this->call(cx, params.begin(), params.end());
551453bb9a4SAlex Crichton }
552453bb9a4SAlex Crichton
553453bb9a4SAlex Crichton /// Returns the type of this function.
type(Store::Context cx) const554453bb9a4SAlex Crichton FuncType type(Store::Context cx) const {
555453bb9a4SAlex Crichton return wasmtime_func_type(cx.ptr, &func);
556453bb9a4SAlex Crichton }
557453bb9a4SAlex Crichton
558453bb9a4SAlex Crichton /**
559453bb9a4SAlex Crichton * \brief Statically checks this function against the provided types.
560453bb9a4SAlex Crichton *
561453bb9a4SAlex Crichton * This function will check whether it takes the statically known `Params`
562453bb9a4SAlex Crichton * and returns the statically known `Results`. If the type check succeeds then
563453bb9a4SAlex Crichton * a `TypedFunc` is returned which enables a faster method of invoking
564453bb9a4SAlex Crichton * WebAssembly functions.
565453bb9a4SAlex Crichton *
566453bb9a4SAlex Crichton * The `Params` and `Results` specified as template parameters here are the
567453bb9a4SAlex Crichton * parameters and results of the wasm function. They can either be a bare
568453bb9a4SAlex Crichton * type which means that the wasm takes/returns one value, or they can be a
569453bb9a4SAlex Crichton * `std::tuple<T...>` of types to represent multiple arguments or multiple
570453bb9a4SAlex Crichton * returns.
571453bb9a4SAlex Crichton *
572453bb9a4SAlex Crichton * The valid types for this function are those mentioned as the arguments
573453bb9a4SAlex Crichton * for `Func::wrap`.
574453bb9a4SAlex Crichton */
575453bb9a4SAlex Crichton template <typename Params, typename Results,
576453bb9a4SAlex Crichton std::enable_if_t<WasmTypeList<Params>::valid, bool> = true,
577453bb9a4SAlex Crichton std::enable_if_t<WasmTypeList<Results>::valid, bool> = true>
typed(Store::Context cx) const578453bb9a4SAlex Crichton Result<TypedFunc<Params, Results>, Trap> typed(Store::Context cx) const {
579453bb9a4SAlex Crichton auto ty = this->type(cx);
580453bb9a4SAlex Crichton if (!WasmTypeList<Params>::matches(ty->params()) ||
581453bb9a4SAlex Crichton !WasmTypeList<Results>::matches(ty->results())) {
582453bb9a4SAlex Crichton return Trap("static type for this function does not match actual type");
583453bb9a4SAlex Crichton }
584453bb9a4SAlex Crichton TypedFunc<Params, Results> ret(*this);
585453bb9a4SAlex Crichton return ret;
586453bb9a4SAlex Crichton }
587453bb9a4SAlex Crichton
588453bb9a4SAlex Crichton /// Returns the raw underlying C API function this is using.
capi() const5893a5dda5fSAlex Crichton const wasmtime_func_t &capi() const { return func; }
590453bb9a4SAlex Crichton };
591453bb9a4SAlex Crichton
592453bb9a4SAlex Crichton /**
593453bb9a4SAlex Crichton * \brief A version of a WebAssembly `Func` where the type signature of the
594453bb9a4SAlex Crichton * function is statically known.
595453bb9a4SAlex Crichton */
596453bb9a4SAlex Crichton template <typename Params, typename Results> class TypedFunc {
597453bb9a4SAlex Crichton friend class Func;
598453bb9a4SAlex Crichton Func f;
TypedFunc(Func func)599453bb9a4SAlex Crichton TypedFunc(Func func) : f(func) {}
600453bb9a4SAlex Crichton
601453bb9a4SAlex Crichton public:
602453bb9a4SAlex Crichton /**
603453bb9a4SAlex Crichton * \brief Calls this function with the provided parameters.
604453bb9a4SAlex Crichton *
605453bb9a4SAlex Crichton * This function is akin to `Func::call` except that since static type
606453bb9a4SAlex Crichton * information is available it statically takes its parameters and statically
607453bb9a4SAlex Crichton * returns its results.
608453bb9a4SAlex Crichton *
609453bb9a4SAlex Crichton * Note that this function still may return a `Trap` indicating that calling
610453bb9a4SAlex Crichton * the WebAssembly function failed.
611453bb9a4SAlex Crichton */
call(Store::Context cx,const Params & params) const612adff9d9dSAlex Crichton TrapResult<Results> call(Store::Context cx, const Params ¶ms) const {
613453bb9a4SAlex Crichton std::array<wasmtime_val_raw_t, std::max(WasmTypeList<Params>::size,
614453bb9a4SAlex Crichton WasmTypeList<Results>::size)>
615453bb9a4SAlex Crichton storage;
616453bb9a4SAlex Crichton wasmtime_val_raw_t *ptr = storage.data();
617453bb9a4SAlex Crichton if (ptr == nullptr)
618453bb9a4SAlex Crichton ptr = reinterpret_cast<wasmtime_val_raw_t *>(alignof(wasmtime_val_raw_t));
619453bb9a4SAlex Crichton WasmTypeList<Params>::store(cx, ptr, params);
620453bb9a4SAlex Crichton wasm_trap_t *trap = nullptr;
621579ec46bSAlex Crichton auto *error = wasmtime_func_call_unchecked(cx.capi(), &f.func, ptr,
622a045eaa9SAlex Crichton storage.size(), &trap);
623453bb9a4SAlex Crichton if (error != nullptr) {
624453bb9a4SAlex Crichton return TrapError(Error(error));
625453bb9a4SAlex Crichton }
626453bb9a4SAlex Crichton if (trap != nullptr) {
627453bb9a4SAlex Crichton return TrapError(Trap(trap));
628453bb9a4SAlex Crichton }
629453bb9a4SAlex Crichton return WasmTypeList<Results>::load(cx, ptr);
630453bb9a4SAlex Crichton }
631453bb9a4SAlex Crichton
632453bb9a4SAlex Crichton /// Returns the underlying un-typed `Func` for this function.
func() const633453bb9a4SAlex Crichton const Func &func() const { return f; }
634453bb9a4SAlex Crichton };
635453bb9a4SAlex Crichton
Val(std::optional<Func> func)636453bb9a4SAlex Crichton inline Val::Val(std::optional<Func> func) : val{} {
637453bb9a4SAlex Crichton val.kind = WASMTIME_FUNCREF;
638453bb9a4SAlex Crichton if (func) {
639453bb9a4SAlex Crichton val.of.funcref = (*func).func;
640453bb9a4SAlex Crichton } else {
641453bb9a4SAlex Crichton wasmtime_funcref_set_null(&val.of.funcref);
642453bb9a4SAlex Crichton }
643453bb9a4SAlex Crichton }
644453bb9a4SAlex Crichton
Val(Func func)645453bb9a4SAlex Crichton inline Val::Val(Func func) : Val(std::optional(func)) {}
Val(ExternRef ptr)646453bb9a4SAlex Crichton inline Val::Val(ExternRef ptr) : Val(std::optional(ptr)) {}
Val(AnyRef ptr)647453bb9a4SAlex Crichton inline Val::Val(AnyRef ptr) : Val(std::optional(ptr)) {}
648453bb9a4SAlex Crichton
funcref() const649453bb9a4SAlex Crichton inline std::optional<Func> Val::funcref() const {
650453bb9a4SAlex Crichton if (val.kind != WASMTIME_FUNCREF) {
651453bb9a4SAlex Crichton std::abort();
652453bb9a4SAlex Crichton }
653453bb9a4SAlex Crichton if (val.of.funcref.store_id == 0) {
654453bb9a4SAlex Crichton return std::nullopt;
655453bb9a4SAlex Crichton }
656453bb9a4SAlex Crichton return Func(val.of.funcref);
657453bb9a4SAlex Crichton }
658453bb9a4SAlex Crichton
659453bb9a4SAlex Crichton /// Definition for the `funcref` native wasm type
660453bb9a4SAlex Crichton template <> struct detail::WasmType<std::optional<Func>> {
661453bb9a4SAlex Crichton /// @private
662453bb9a4SAlex Crichton static const bool valid = true;
663453bb9a4SAlex Crichton /// @private
664453bb9a4SAlex Crichton static const ValKind kind = ValKind::FuncRef;
665453bb9a4SAlex Crichton /// @private
storewasmtime::detail::WasmType666453bb9a4SAlex Crichton static void store(Store::Context cx, wasmtime_val_raw_t *p,
667453bb9a4SAlex Crichton const std::optional<Func> func) {
668453bb9a4SAlex Crichton if (func) {
669579ec46bSAlex Crichton p->funcref = wasmtime_func_to_raw(cx.capi(), &func->capi());
670453bb9a4SAlex Crichton } else {
671453bb9a4SAlex Crichton p->funcref = 0;
672453bb9a4SAlex Crichton }
673453bb9a4SAlex Crichton }
674453bb9a4SAlex Crichton /// @private
loadwasmtime::detail::WasmType675453bb9a4SAlex Crichton static std::optional<Func> load(Store::Context cx, wasmtime_val_raw_t *p) {
676453bb9a4SAlex Crichton if (p->funcref == 0) {
677453bb9a4SAlex Crichton return std::nullopt;
678453bb9a4SAlex Crichton }
679453bb9a4SAlex Crichton wasmtime_func_t ret;
680579ec46bSAlex Crichton wasmtime_func_from_raw(cx.capi(), p->funcref, &ret);
681453bb9a4SAlex Crichton return ret;
682453bb9a4SAlex Crichton }
683453bb9a4SAlex Crichton };
684453bb9a4SAlex Crichton
685453bb9a4SAlex Crichton } // namespace wasmtime
686453bb9a4SAlex Crichton
687453bb9a4SAlex Crichton #endif // WASMTIME_FUNC_HH
688