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