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 std::optional<ExternRef> &&ref) { 91 if (ref) { 92 p->externref = ref->take_raw(cx); 93 } else { 94 p->externref = 0; 95 } 96 } 97 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 } 105 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; 120 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 } 124 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; 137 static bool matches(ValType::ListRef types) { 138 return WasmTypeList<std::tuple<T>>::matches(types); 139 } 140 static void store(Store::Context cx, wasmtime_val_raw_t *storage, T &&t) { 141 WasmType<T>::store(cx, storage, t); 142 } 143 static void store(Store::Context cx, wasmtime_val_raw_t *storage, 144 const T &t) { 145 WasmType<T>::store(cx, storage, t); 146 } 147 static T load(Store::Context cx, wasmtime_val_raw_t *storage) { 148 return WasmType<T>::load(cx, storage); 149 } 150 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; 157 static bool matches(ValType::ListRef types) { return types.size() == 0; } 158 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 } 164 static std::monostate load(Store::Context cx, wasmtime_val_raw_t *storage) { 165 (void)cx; 166 (void)storage; 167 return std::monostate(); 168 } 169 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); 176 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 } 183 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 } 192 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 } 201 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 } 205 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> 215 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> 228 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> 247 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> 267 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> 282 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> 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 * 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 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. 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> 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> 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> 502 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 */ 537 TrapResult<std::vector<Val>> call(Store::Context cx, 538 const std::vector<Val> ¶ms) 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>> 549 call(Store::Context cx, const std::initializer_list<Val> ¶ms) const { 550 return this->call(cx, params.begin(), params.end()); 551 } 552 553 /// Returns the type of this function. 554 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> 578 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. 589 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; 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 */ 612 TrapResult<Results> call(Store::Context cx, const Params ¶ms) 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. 633 const Func &func() const { return f; } 634 }; 635 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 645 inline Val::Val(Func func) : Val(std::optional(func)) {} 646 inline Val::Val(ExternRef ptr) : Val(std::optional(ptr)) {} 647 inline Val::Val(AnyRef ptr) : Val(std::optional(ptr)) {} 648 649 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 666 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 675 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