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