1 /** 2 * \file wasmtime/linker.hh 3 */ 4 5 #ifndef WASMTIME_LINKER_HH 6 #define WASMTIME_LINKER_HH 7 8 #include <wasmtime/engine.hh> 9 #include <wasmtime/error.hh> 10 #include <wasmtime/extern.hh> 11 #include <wasmtime/helpers.hh> 12 #include <wasmtime/instance.hh> 13 #include <wasmtime/linker.h> 14 #include <wasmtime/store.hh> 15 #include <wasmtime/trap.hh> 16 17 namespace wasmtime { 18 19 /** 20 * \brief Helper class for linking modules together with name-based resolution. 21 * 22 * This class is used for easily instantiating `Module`s by defining names into 23 * the linker and performing name-based resolution during instantiation. A 24 * `Linker` can also be used to link in WASI functions to instantiate a module. 25 */ 26 class Linker { 27 WASMTIME_OWN_WRAPPER(Linker, wasmtime_linker); 28 29 /// Creates a new linker which will instantiate in the given engine. Linker(Engine & engine)30 explicit Linker(Engine &engine) : ptr(wasmtime_linker_new(engine.capi())) {} 31 32 /// Configures whether shadowing previous names is allowed or not. 33 /// 34 /// By default shadowing is not allowed. allow_shadowing(bool allow)35 void allow_shadowing(bool allow) { 36 wasmtime_linker_allow_shadowing(ptr.get(), allow); 37 } 38 39 /// Defines the provided item into this linker with the given name. define(Store::Context cx,std::string_view module,std::string_view name,const Extern & item)40 Result<std::monostate> define(Store::Context cx, std::string_view module, 41 std::string_view name, const Extern &item) { 42 wasmtime_extern_t raw; 43 detail::cvt_extern(item, raw); 44 auto *error = 45 wasmtime_linker_define(ptr.get(), cx.ptr, module.data(), module.size(), 46 name.data(), name.size(), &raw); 47 if (error != nullptr) { 48 return Error(error); 49 } 50 return std::monostate(); 51 } 52 53 #ifdef WASMTIME_FEATURE_WASI 54 /// Defines WASI functions within this linker. 55 /// 56 /// Note that `Store::Context::set_wasi` must also be used for instantiated 57 /// modules to have access to configured WASI state. define_wasi()58 Result<std::monostate> define_wasi() { 59 auto *error = wasmtime_linker_define_wasi(ptr.get()); 60 if (error != nullptr) { 61 return Error(error); 62 } 63 return std::monostate(); 64 } 65 #endif // WASMTIME_FEATURE_WASI 66 67 /// Defines all exports of the `instance` provided in this linker with the 68 /// given module name of `name`. 69 Result<std::monostate> define_instance(Store::Context cx,std::string_view name,Instance instance)70 define_instance(Store::Context cx, std::string_view name, Instance instance) { 71 auto *error = wasmtime_linker_define_instance( 72 ptr.get(), cx.ptr, name.data(), name.size(), &instance.instance); 73 if (error != nullptr) { 74 return Error(error); 75 } 76 return std::monostate(); 77 } 78 79 /// Instantiates the module `m` provided within the store `cx` using the items 80 /// defined within this linker. instantiate(Store::Context cx,const Module & m)81 TrapResult<Instance> instantiate(Store::Context cx, const Module &m) { 82 wasmtime_instance_t instance; 83 wasm_trap_t *trap = nullptr; 84 auto *error = wasmtime_linker_instantiate(ptr.get(), cx.ptr, m.capi(), 85 &instance, &trap); 86 if (error != nullptr) { 87 return TrapError(Error(error)); 88 } 89 if (trap != nullptr) { 90 return TrapError(Trap(trap)); 91 } 92 return Instance(instance); 93 } 94 95 /// Defines instantiations of the module `m` within this linker under the 96 /// given `name`. module(Store::Context cx,std::string_view name,const Module & m)97 Result<std::monostate> module(Store::Context cx, std::string_view name, 98 const Module &m) { 99 auto *error = wasmtime_linker_module(ptr.get(), cx.ptr, name.data(), 100 name.size(), m.capi()); 101 if (error != nullptr) { 102 return Error(error); 103 } 104 return std::monostate(); 105 } 106 107 /// Attempts to load the specified named item from this linker, returning 108 /// `std::nullopt` if it was not defined. 109 [[nodiscard]] std::optional<Extern> get(Store::Context cx,std::string_view module,std::string_view name)110 get(Store::Context cx, std::string_view module, std::string_view name) { 111 wasmtime_extern_t item; 112 if (wasmtime_linker_get(ptr.get(), cx.ptr, module.data(), module.size(), 113 name.data(), name.size(), &item)) { 114 return detail::cvt_extern(item); 115 } 116 return std::nullopt; 117 } 118 119 /// Defines a new function in this linker in the style of the `Func` 120 /// constructor. 121 template <typename F, 122 std::enable_if_t< 123 std::is_invocable_r_v<Result<std::monostate, Trap>, F, Caller, 124 Span<const Val>, Span<Val>>, 125 bool> = true> func_new(std::string_view module,std::string_view name,const FuncType & ty,F && f)126 Result<std::monostate> func_new(std::string_view module, 127 std::string_view name, const FuncType &ty, 128 F &&f) { 129 130 auto *error = wasmtime_linker_define_func( 131 ptr.get(), module.data(), module.length(), name.data(), name.length(), 132 ty.ptr.get(), Func::raw_callback<std::remove_reference_t<F>>, 133 std::make_unique<std::remove_reference_t<F>>(std::forward<F>(f)) 134 .release(), 135 Func::raw_finalize<std::remove_reference_t<F>>); 136 137 if (error != nullptr) { 138 return Error(error); 139 } 140 141 return std::monostate(); 142 } 143 144 /// Defines a new function in this linker in the style of the `Func::wrap` 145 /// constructor. 146 template <typename F, 147 std::enable_if_t<WasmHostFunc<F>::Params::valid, bool> = true, 148 std::enable_if_t<WasmHostFunc<F>::Results::valid, bool> = true> func_wrap(std::string_view module,std::string_view name,F && f)149 Result<std::monostate> func_wrap(std::string_view module, 150 std::string_view name, F &&f) { 151 using HostFunc = WasmHostFunc<F>; 152 auto params = HostFunc::Params::types(); 153 auto results = HostFunc::Results::types(); 154 auto ty = FuncType::from_iters(params, results); 155 auto *error = wasmtime_linker_define_func_unchecked( 156 ptr.get(), module.data(), module.length(), name.data(), name.length(), 157 ty.ptr.get(), Func::raw_callback_unchecked<std::remove_reference_t<F>>, 158 std::make_unique<std::remove_reference_t<F>>(std::forward<F>(f)) 159 .release(), 160 Func::raw_finalize<std::remove_reference_t<F>>); 161 162 if (error != nullptr) { 163 return Error(error); 164 } 165 166 return std::monostate(); 167 } 168 169 /// Loads the "default" function, according to WASI commands and reactors, of 170 /// the module named `name` in this linker. get_default(Store::Context cx,std::string_view name)171 Result<Func> get_default(Store::Context cx, std::string_view name) { 172 wasmtime_func_t item; 173 auto *error = wasmtime_linker_get_default(ptr.get(), cx.ptr, name.data(), 174 name.size(), &item); 175 if (error != nullptr) { 176 return Error(error); 177 } 178 return Func(item); 179 } 180 181 /// \brief Defines any import of `module` previously unknown to this linker 182 /// as a trap. define_unknown_imports_as_traps(Module & module)183 Result<std::monostate> define_unknown_imports_as_traps(Module &module) { 184 auto *error = wasmtime_linker_define_unknown_imports_as_traps( 185 ptr.get(), module.capi()); 186 if (error != nullptr) { 187 return Error(error); 188 } 189 return std::monostate(); 190 } 191 192 /// \brief Defines any import of `module` previously unknown to this linker 193 /// as the "default" value for that import, for example a function that 194 /// returns zeros. 195 Result<std::monostate> define_unknown_imports_as_default_values(Store::Context cx,Module & module)196 define_unknown_imports_as_default_values(Store::Context cx, Module &module) { 197 auto *error = wasmtime_linker_define_unknown_imports_as_default_values( 198 ptr.get(), cx.ptr, module.capi()); 199 if (error != nullptr) { 200 return Error(error); 201 } 202 return std::monostate(); 203 } 204 }; 205 206 } // namespace wasmtime 207 208 #endif // WASMTIME_LINKER_HH 209