1 /**
2  * \file wasmtime/func.hh
3  */
4 
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>
15 #include <wasmtime/types/func.hh>
16 #include <wasmtime/types/val.hh>
17 #include <wasmtime/val.hh>
18 
19 namespace wasmtime {
20 
21 /**
22  * \brief Structure provided to host functions to lookup caller information or
23  * acquire a `Store::Context`.
24  *
25  * This structure is passed to all host functions created with `Func`. It can be
26  * used to create a `Store::Context`.
27  */
28 class Caller {
29   friend class Func;
30   friend class Store;
31   wasmtime_caller_t *ptr;
32   Caller(wasmtime_caller_t *ptr) : ptr(ptr) {}
33 
34 public:
35   /// Attempts to load an exported item from the calling instance.
36   ///
37   /// For more information see the Rust documentation -
38   /// https://docs.wasmtime.dev/api/wasmtime/struct.Caller.html#method.get_export
39   std::optional<Extern> get_export(std::string_view name);
40 
41   /// Explicitly acquire a `Store::Context` from this `Caller`.
42   Store::Context context() { return this; }
43 };
44 
45 inline Store::Context::Context(Caller &caller)
46     : Context(wasmtime_caller_context(caller.ptr)) {}
47 inline Store::Context::Context(Caller *caller) : Context(*caller) {}
48 
49 namespace detail {
50 
51 /// A "trait" for native types that correspond to WebAssembly types for use with
52 /// `Func::wrap` and `TypedFunc::call`
53 template <typename T> struct WasmType {
54   static const bool valid = false;
55 };
56 
57 /// Helper macro to define `WasmType` definitions for primitive types like
58 /// int32_t and such.
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       p->field = t;                                                            \
67     }                                                                          \
68     static native load(Store::Context cx, wasmtime_val_raw_t *p) {             \
69       return p->field;                                                         \
70     }                                                                          \
71   };
72 
73 NATIVE_WASM_TYPE(int32_t, I32, i32)
74 NATIVE_WASM_TYPE(uint32_t, I32, i32)
75 NATIVE_WASM_TYPE(int64_t, I64, i64)
76 NATIVE_WASM_TYPE(uint64_t, I64, i64)
77 NATIVE_WASM_TYPE(float, F32, f32)
78 NATIVE_WASM_TYPE(double, F64, f64)
79 
80 #undef NATIVE_WASM_TYPE
81 
82 /// Type information for `externref`, represented on the host as an optional
83 /// `ExternRef`.
84 template <> struct WasmType<std::optional<ExternRef>> {
85   static const bool valid = true;
86   static const ValKind kind = ValKind::ExternRef;
87   static void store(Store::Context cx, wasmtime_val_raw_t *p,
88                     const std::optional<ExternRef> &ref) {
89     if (ref) {
90       p->externref = wasmtime_externref_to_raw(cx.raw_context(), ref->raw());
91     } else {
92       p->externref = 0;
93     }
94   }
95   static std::optional<ExternRef> load(Store::Context cx,
96                                        wasmtime_val_raw_t *p) {
97     if (p->externref == 0) {
98       return std::nullopt;
99     }
100     wasmtime_externref_t val;
101     wasmtime_externref_from_raw(cx.raw_context(), p->externref, &val);
102     return ExternRef(val);
103   }
104 };
105 
106 /// Type information for the `V128` host value used as a wasm value.
107 template <> struct WasmType<V128> {
108   static const bool valid = true;
109   static const ValKind kind = ValKind::V128;
110   static void store(Store::Context cx, wasmtime_val_raw_t *p, const V128 &t) {
111     memcpy(&p->v128[0], &t.v128[0], sizeof(wasmtime_v128));
112   }
113   static V128 load(Store::Context cx, wasmtime_val_raw_t *p) { return p->v128; }
114 };
115 
116 /// A "trait" for a list of types and operations on them, used for `Func::wrap`
117 /// and `TypedFunc::call`
118 ///
119 /// The base case is a single type which is a list of one element.
120 template <typename T> struct WasmTypeList {
121   static const bool valid = WasmType<T>::valid;
122   static const size_t size = 1;
123   static bool matches(ValType::ListRef types) {
124     return WasmTypeList<std::tuple<T>>::matches(types);
125   }
126   static void store(Store::Context cx, wasmtime_val_raw_t *storage,
127                     const T &t) {
128     WasmType<T>::store(cx, storage, t);
129   }
130   static T load(Store::Context cx, wasmtime_val_raw_t *storage) {
131     return WasmType<T>::load(cx, storage);
132   }
133   static std::vector<ValType> types() { return {WasmType<T>::kind}; }
134 };
135 
136 /// std::monostate translates to an empty list of types.
137 template <> struct WasmTypeList<std::monostate> {
138   static const bool valid = true;
139   static const size_t size = 0;
140   static bool matches(ValType::ListRef types) { return types.size() == 0; }
141   static void store(Store::Context cx, wasmtime_val_raw_t *storage,
142                     const std::monostate &t) {}
143   static std::monostate load(Store::Context cx, wasmtime_val_raw_t *storage) {
144     return std::monostate();
145   }
146   static std::vector<ValType> types() { return {}; }
147 };
148 
149 /// std::tuple<> translates to the corresponding list of types
150 template <typename... T> struct WasmTypeList<std::tuple<T...>> {
151   static const bool valid = (WasmType<T>::valid && ...);
152   static const size_t size = sizeof...(T);
153   static bool matches(ValType::ListRef types) {
154     if (types.size() != size) {
155       return false;
156     }
157     size_t n = 0;
158     return ((WasmType<T>::kind == types.begin()[n++].kind()) && ...);
159   }
160   static void store(Store::Context cx, wasmtime_val_raw_t *storage,
161                     const std::tuple<T...> &t) {
162     size_t n = 0;
163     std::apply(
164         [&](const auto &...val) {
165           (WasmType<T>::store(cx, &storage[n++], val), ...); // NOLINT
166         },
167         t);
168   }
169   static std::tuple<T...> load(Store::Context cx, wasmtime_val_raw_t *storage) {
170     size_t n = 0;
171     return std::tuple<T...>{WasmType<T>::load(cx, &storage[n++])...}; // NOLINT
172   }
173   static std::vector<ValType> types() { return {WasmType<T>::kind...}; }
174 };
175 
176 /// A "trait" for what can be returned from closures specified to `Func::wrap`.
177 ///
178 /// The base case here is a bare return value like `int32_t`.
179 template <typename R> struct WasmHostRet {
180   using Results = WasmTypeList<R>;
181 
182   template <typename F, typename... A>
183   static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
184                                     A... args) {
185     auto ret = f(args...);
186     Results::store(cx, raw, ret);
187     return std::nullopt;
188   }
189 };
190 
191 /// Host functions can return nothing
192 template <> struct WasmHostRet<void> {
193   using Results = WasmTypeList<std::tuple<>>;
194 
195   template <typename F, typename... A>
196   static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
197                                     A... args) {
198     f(args...);
199     return std::nullopt;
200   }
201 };
202 
203 // Alternative method of returning "nothing" (also enables `std::monostate` in
204 // the `R` type of `Result` below)
205 template <> struct WasmHostRet<std::monostate> : public WasmHostRet<void> {};
206 
207 /// Host functions can return a result which allows them to also possibly return
208 /// a trap.
209 template <typename R> struct WasmHostRet<Result<R, Trap>> {
210   using Results = WasmTypeList<R>;
211 
212   template <typename F, typename... A>
213   static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
214                                     A... args) {
215     Result<R, Trap> ret = f(args...);
216     if (!ret) {
217       return ret.err();
218     }
219     Results::store(cx, raw, ret.ok());
220     return std::nullopt;
221   }
222 };
223 
224 template <typename F, typename = void> struct WasmHostFunc;
225 
226 /// Base type information for host free-function pointers being used as wasm
227 /// functions
228 template <typename R, typename... A> struct WasmHostFunc<R (*)(A...)> {
229   using Params = WasmTypeList<std::tuple<A...>>;
230   using Results = typename WasmHostRet<R>::Results;
231 
232   template <typename F>
233   static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
234     auto params = Params::load(cx, raw);
235     return std::apply(
236         [&](const auto &...val) {
237           return WasmHostRet<R>::invoke(f, cx, raw, val...);
238         },
239         params);
240   }
241 };
242 
243 /// Function type information, but with a `Caller` first parameter
244 template <typename R, typename... A>
245 struct WasmHostFunc<R (*)(Caller, A...)> : public WasmHostFunc<R (*)(A...)> {
246   // Override `invoke` here to pass the `cx` as the first parameter
247   template <typename F>
248   static std::optional<Trap> invoke(F &f, Caller cx, wasmtime_val_raw_t *raw) {
249     auto params = WasmTypeList<std::tuple<A...>>::load(cx, raw);
250     return std::apply(
251         [&](const auto &...val) {
252           return WasmHostRet<R>::invoke(f, cx, raw, cx, val...);
253         },
254         params);
255   }
256 };
257 
258 /// Function type information, but with a class method.
259 template <typename R, typename C, typename... A>
260 struct WasmHostFunc<R (C::*)(A...)> : public WasmHostFunc<R (*)(A...)> {};
261 
262 /// Function type information, but with a const class method.
263 template <typename R, typename C, typename... A>
264 struct WasmHostFunc<R (C::*)(A...) const> : public WasmHostFunc<R (*)(A...)> {};
265 
266 /// Function type information, but as a host method with a `Caller` first
267 /// parameter.
268 template <typename R, typename C, typename... A>
269 struct WasmHostFunc<R (C::*)(Caller, A...)>
270     : public WasmHostFunc<R (*)(Caller, A...)> {};
271 
272 /// Function type information, but as a host const method with a `Caller`
273 /// first parameter.
274 template <typename R, typename C, typename... A>
275 struct WasmHostFunc<R (C::*)(Caller, A...) const>
276     : public WasmHostFunc<R (*)(Caller, A...)> {};
277 
278 /// Base type information for host callables being used as wasm
279 /// functions
280 template <typename T>
281 struct WasmHostFunc<T, std::void_t<decltype(&T::operator())>>
282     : public WasmHostFunc<decltype(&T::operator())> {};
283 
284 } // namespace detail
285 
286 using namespace detail;
287 
288 // forward-declaration for `Func::typed` below.
289 template <typename Params, typename Results> class TypedFunc;
290 
291 /**
292  * \brief Representation of a WebAssembly function.
293  *
294  * This class represents a WebAssembly function, either created through
295  * instantiating a module or a host function.
296  *
297  * Note that this type does not itself own any resources. It points to resources
298  * owned within a `Store` and the `Store` must be passed in as the first
299  * argument to the functions defined on `Func`. Note that if the wrong `Store`
300  * is passed in then the process will be aborted.
301  */
302 class Func {
303   friend class Val;
304   friend class Instance;
305   friend class Linker;
306   template <typename Params, typename Results> friend class TypedFunc;
307 
308   wasmtime_func_t func;
309 
310   template <typename F>
311   static wasm_trap_t *raw_callback(void *env, wasmtime_caller_t *caller,
312                                    const wasmtime_val_t *args, size_t nargs,
313                                    wasmtime_val_t *results, size_t nresults) {
314     static_assert(alignof(Val) == alignof(wasmtime_val_t));
315     static_assert(sizeof(Val) == sizeof(wasmtime_val_t));
316     F *func = reinterpret_cast<F *>(env);                          // NOLINT
317     Span<const Val> args_span(reinterpret_cast<const Val *>(args), // NOLINT
318                               nargs);
319     Span<Val> results_span(reinterpret_cast<Val *>(results), // NOLINT
320                            nresults);
321     Result<std::monostate, Trap> result =
322         (*func)(Caller(caller), args_span, results_span);
323     if (!result) {
324       return result.err().ptr.release();
325     }
326     return nullptr;
327   }
328 
329   template <typename F>
330   static wasm_trap_t *
331   raw_callback_unchecked(void *env, wasmtime_caller_t *caller,
332                          wasmtime_val_raw_t *args_and_results,
333                          size_t nargs_and_results) {
334     using HostFunc = WasmHostFunc<F>;
335     Caller cx(caller);
336     F *func = reinterpret_cast<F *>(env); // NOLINT
337     auto trap = HostFunc::invoke(*func, cx, args_and_results);
338     if (trap) {
339       return trap->ptr.release();
340     }
341     return nullptr;
342   }
343 
344   template <typename F> static void raw_finalize(void *env) {
345     std::unique_ptr<F> ptr(reinterpret_cast<F *>(env)); // NOLINT
346   }
347 
348 public:
349   /// Creates a new function from the raw underlying C API representation.
350   Func(wasmtime_func_t func) : func(func) {}
351 
352   /**
353    * \brief Creates a new host-defined function.
354    *
355    * This constructor is used to create a host function within the store
356    * provided. This is how WebAssembly can call into the host and make use of
357    * external functionality.
358    *
359    * > **Note**: host functions created this way are more flexible but not
360    * > as fast to call as those created by `Func::wrap`.
361    *
362    * \param cx the store to create the function within
363    * \param ty the type of the function that will be created
364    * \param f the host callback to be executed when this function is called.
365    *
366    * The parameter `f` is expected to be a lambda (or a lambda lookalike) which
367    * takes three parameters:
368    *
369    * * The first parameter is a `Caller` to get recursive access to the store
370    *   and other caller state.
371    * * The second parameter is a `Span<const Val>` which is the list of
372    *   parameters to the function. These parameters are guaranteed to be of the
373    *   types specified by `ty` when constructing this function.
374    * * The last argument is `Span<Val>` which is where to write the return
375    *   values of the function. The function must produce the types of values
376    *   specified by `ty` or otherwise a trap will be raised.
377    *
378    * The parameter `f` is expected to return `Result<std::monostate, Trap>`.
379    * This allows `f` to raise a trap if desired, or otherwise return no trap and
380    * finish successfully. If a trap is raised then the results pointer does not
381    * need to be written to.
382    */
383   template <typename F,
384             std::enable_if_t<
385                 std::is_invocable_r_v<Result<std::monostate, Trap>, F, Caller,
386                                       Span<const Val>, Span<Val>>,
387                 bool> = true>
388   Func(Store::Context cx, const FuncType &ty, F f) : func({}) {
389     wasmtime_func_new(cx.ptr, ty.ptr.get(), raw_callback<F>,
390                       std::make_unique<F>(f).release(), raw_finalize<F>, &func);
391   }
392 
393   /**
394    * \brief Creates a new host function from the provided callback `f`,
395    * inferring the WebAssembly function type from the host signature.
396    *
397    * This function is akin to the `Func` constructor except that the WebAssembly
398    * type does not need to be specified and additionally the signature of `f`
399    * is different. The main goal of this function is to enable WebAssembly to
400    * call the function `f` as-fast-as-possible without having to validate any
401    * types or such.
402    *
403    * The function `f` can optionally take a `Caller` as its first parameter,
404    * but otherwise its arguments are translated to WebAssembly types:
405    *
406    * * `int32_t`, `uint32_t` - `i32`
407    * * `int64_t`, `uint64_t` - `i64`
408    * * `float` - `f32`
409    * * `double` - `f64`
410    * * `std::optional<Func>` - `funcref`
411    * * `std::optional<ExternRef>` - `externref`
412    * * `wasmtime::V128` - `v128`
413    *
414    * The function may only take these arguments and if it takes any other kinds
415    * of arguments then it will fail to compile.
416    *
417    * The function may return a few different flavors of return values:
418    *
419    * * `void` - interpreted as returning nothing
420    * * Any type above - interpreted as a singular return value.
421    * * `std::tuple<T...>` where `T` is one of the valid argument types -
422    *   interpreted as returning multiple values.
423    * * `Result<T, Trap>` where `T` is another valid return type - interpreted as
424    *   a function that returns `T` to wasm but is optionally allowed to also
425    *   raise a trap.
426    *
427    * It's recommended, if possible, to use this function over the `Func`
428    * constructor since this is generally easier to work with and also enables
429    * a faster path for WebAssembly to call this function.
430    */
431   template <typename F,
432             std::enable_if_t<WasmHostFunc<F>::Params::valid, bool> = true,
433             std::enable_if_t<WasmHostFunc<F>::Results::valid, bool> = true>
434   static Func wrap(Store::Context cx, F f) {
435     using HostFunc = WasmHostFunc<F>;
436     auto params = HostFunc::Params::types();
437     auto results = HostFunc::Results::types();
438     auto ty = FuncType::from_iters(params, results);
439     wasmtime_func_t func;
440     wasmtime_func_new_unchecked(cx.ptr, ty.ptr.get(), raw_callback_unchecked<F>,
441                                 std::make_unique<F>(f).release(),
442                                 raw_finalize<F>, &func);
443     return func;
444   }
445 
446   /**
447    * \brief Invoke a WebAssembly function.
448    *
449    * This function will execute this WebAssembly function. This function muts be
450    * defined within the `cx`'s store provided. The `params` argument is the list
451    * of parameters that are passed to the wasm function, and the types of the
452    * values within `params` must match the type signature of this function.
453    *
454    * This may return one of three values:
455    *
456    * * First the function could succeed, returning a vector of values
457    *   representing the results of the function.
458    * * Otherwise a `Trap` might be generated by the WebAssembly function.
459    * * Finally an `Error` could be returned indicating that `params` were not of
460    *   the right type.
461    *
462    * > **Note**: for optimized calls into WebAssembly where the function
463    * > signature is statically known it's recommended to use `Func::typed` and
464    * > `TypedFunc::call`.
465    */
466   template <typename I>
467   TrapResult<std::vector<Val>> call(Store::Context cx, const I &begin,
468                                     const I &end) const {
469     std::vector<wasmtime_val_t> raw_params;
470     raw_params.reserve(end - begin);
471     for (auto i = begin; i != end; i++) {
472       raw_params.push_back(i->val);
473     }
474     size_t nresults = this->type(cx)->results().size();
475     std::vector<wasmtime_val_t> raw_results(nresults);
476 
477     wasm_trap_t *trap = nullptr;
478     auto *error =
479         wasmtime_func_call(cx.ptr, &func, raw_params.data(), raw_params.size(),
480                            raw_results.data(), raw_results.capacity(), &trap);
481     if (error != nullptr) {
482       return TrapError(Error(error));
483     }
484     if (trap != nullptr) {
485       return TrapError(Trap(trap));
486     }
487 
488     std::vector<Val> results;
489     results.reserve(nresults);
490     for (size_t i = 0; i < nresults; i++) {
491       results.push_back(raw_results[i]);
492     }
493     return results;
494   }
495 
496   /**
497    * \brief Helper function for `call(Store::Context cx, const I &begin, const I
498    * &end)`
499    *
500    * \see call(Store::Context cx, const I &begin, const I &end)
501    */
502   TrapResult<std::vector<Val>> call(Store::Context cx,
503                                     const std::vector<Val> &params) const {
504     return this->call(cx, params.begin(), params.end());
505   }
506 
507   /**
508    * \brief Helper function for `call(Store::Context cx, const I &begin, const I
509    * &end)`
510    *
511    * \see call(Store::Context cx, const I &begin, const I &end)
512    */
513   TrapResult<std::vector<Val>>
514   call(Store::Context cx, const std::initializer_list<Val> &params) const {
515     return this->call(cx, params.begin(), params.end());
516   }
517 
518   /// Returns the type of this function.
519   FuncType type(Store::Context cx) const {
520     return wasmtime_func_type(cx.ptr, &func);
521   }
522 
523   /**
524    * \brief Statically checks this function against the provided types.
525    *
526    * This function will check whether it takes the statically known `Params`
527    * and returns the statically known `Results`. If the type check succeeds then
528    * a `TypedFunc` is returned which enables a faster method of invoking
529    * WebAssembly functions.
530    *
531    * The `Params` and `Results` specified as template parameters here are the
532    * parameters and results of the wasm function. They can either be a bare
533    * type which means that the wasm takes/returns one value, or they can be a
534    * `std::tuple<T...>` of types to represent multiple arguments or multiple
535    * returns.
536    *
537    * The valid types for this function are those mentioned as the arguments
538    * for `Func::wrap`.
539    */
540   template <typename Params, typename Results,
541             std::enable_if_t<WasmTypeList<Params>::valid, bool> = true,
542             std::enable_if_t<WasmTypeList<Results>::valid, bool> = true>
543   Result<TypedFunc<Params, Results>, Trap> typed(Store::Context cx) const {
544     auto ty = this->type(cx);
545     if (!WasmTypeList<Params>::matches(ty->params()) ||
546         !WasmTypeList<Results>::matches(ty->results())) {
547       return Trap("static type for this function does not match actual type");
548     }
549     TypedFunc<Params, Results> ret(*this);
550     return ret;
551   }
552 
553   /// Returns the raw underlying C API function this is using.
554   const wasmtime_func_t &capi() const { return func; }
555 };
556 
557 /**
558  * \brief A version of a WebAssembly `Func` where the type signature of the
559  * function is statically known.
560  */
561 template <typename Params, typename Results> class TypedFunc {
562   friend class Func;
563   Func f;
564   TypedFunc(Func func) : f(func) {}
565 
566 public:
567   /**
568    * \brief Calls this function with the provided parameters.
569    *
570    * This function is akin to `Func::call` except that since static type
571    * information is available it statically takes its parameters and statically
572    * returns its results.
573    *
574    * Note that this function still may return a `Trap` indicating that calling
575    * the WebAssembly function failed.
576    */
577   TrapResult<Results> call(Store::Context cx, Params params) const {
578     std::array<wasmtime_val_raw_t, std::max(WasmTypeList<Params>::size,
579                                             WasmTypeList<Results>::size)>
580         storage;
581     wasmtime_val_raw_t *ptr = storage.data();
582     if (ptr == nullptr)
583       ptr = reinterpret_cast<wasmtime_val_raw_t *>(alignof(wasmtime_val_raw_t));
584     WasmTypeList<Params>::store(cx, ptr, params);
585     wasm_trap_t *trap = nullptr;
586     auto *error = wasmtime_func_call_unchecked(cx.raw_context(), &f.func, ptr,
587                                                storage.size(), &trap);
588     if (error != nullptr) {
589       return TrapError(Error(error));
590     }
591     if (trap != nullptr) {
592       return TrapError(Trap(trap));
593     }
594     return WasmTypeList<Results>::load(cx, ptr);
595   }
596 
597   /// Returns the underlying un-typed `Func` for this function.
598   const Func &func() const { return f; }
599 };
600 
601 inline Val::Val(std::optional<Func> func) : val{} {
602   val.kind = WASMTIME_FUNCREF;
603   if (func) {
604     val.of.funcref = (*func).func;
605   } else {
606     wasmtime_funcref_set_null(&val.of.funcref);
607   }
608 }
609 
610 inline Val::Val(Func func) : Val(std::optional(func)) {}
611 inline Val::Val(ExternRef ptr) : Val(std::optional(ptr)) {}
612 inline Val::Val(AnyRef ptr) : Val(std::optional(ptr)) {}
613 
614 inline std::optional<Func> Val::funcref() const {
615   if (val.kind != WASMTIME_FUNCREF) {
616     std::abort();
617   }
618   if (val.of.funcref.store_id == 0) {
619     return std::nullopt;
620   }
621   return Func(val.of.funcref);
622 }
623 
624 /// Definition for the `funcref` native wasm type
625 template <> struct detail::WasmType<std::optional<Func>> {
626   /// @private
627   static const bool valid = true;
628   /// @private
629   static const ValKind kind = ValKind::FuncRef;
630   /// @private
631   static void store(Store::Context cx, wasmtime_val_raw_t *p,
632                     const std::optional<Func> func) {
633     if (func) {
634       p->funcref = wasmtime_func_to_raw(cx.raw_context(), &func->capi());
635     } else {
636       p->funcref = 0;
637     }
638   }
639   /// @private
640   static std::optional<Func> load(Store::Context cx, wasmtime_val_raw_t *p) {
641     if (p->funcref == 0) {
642       return std::nullopt;
643     }
644     wasmtime_func_t ret;
645     wasmtime_func_from_raw(cx.raw_context(), p->funcref, &ret);
646     return ret;
647   }
648 };
649 
650 } // namespace wasmtime
651 
652 #endif // WASMTIME_FUNC_HH
653