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> ¶ms) 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> ¶ms) 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