1 /// \file wasmtime/component/linker.hh 2 3 #ifndef WASMTIME_COMPONENT_LINKER_HH 4 #define WASMTIME_COMPONENT_LINKER_HH 5 6 #include <wasmtime/conf.h> 7 8 #ifdef WASMTIME_FEATURE_COMPONENT_MODEL 9 10 #include <memory> 11 #include <string_view> 12 #include <wasmtime/component/instance.hh> 13 #include <wasmtime/component/linker.h> 14 #include <wasmtime/component/val.hh> 15 #include <wasmtime/engine.hh> 16 #include <wasmtime/module.hh> 17 18 namespace wasmtime { 19 namespace component { 20 21 /** 22 * \brief Helper class for linking modules together with name-based resolution. 23 * 24 * This class is used for easily instantiating `Module`s by defining names into 25 * the linker and performing name-based resolution during instantiation. A 26 * `Linker` can also be used to link in WASI functions to instantiate a module. 27 */ 28 class LinkerInstance { 29 WASMTIME_OWN_WRAPPER(LinkerInstance, wasmtime_component_linker_instance); 30 31 /** 32 * \brief Adds a module to this linker instance under the specified name. 33 */ add_module(std::string_view name,Module & module)34 Result<std::monostate> add_module(std::string_view name, Module &module) { 35 wasmtime_error_t *error = wasmtime_component_linker_instance_add_module( 36 ptr.get(), name.data(), name.size(), module.capi()); 37 if (error != nullptr) { 38 return Error(error); 39 } 40 return std::monostate(); 41 } 42 43 /** 44 * \brief Adds an new instance to this linker instance under the specified 45 * name. 46 * 47 * Note that this `LinkerInstance` can no longer be used until the returned 48 * `LinkerInstance` is dropped. 49 */ add_instance(std::string_view name)50 Result<LinkerInstance> add_instance(std::string_view name) { 51 wasmtime_component_linker_instance_t *ret = nullptr; 52 wasmtime_error_t *error = wasmtime_component_linker_instance_add_instance( 53 ptr.get(), name.data(), name.size(), &ret); 54 if (error != nullptr) { 55 return Error(error); 56 } 57 return LinkerInstance(ret); 58 } 59 60 private: 61 template <typename F> 62 static wasmtime_error_t * raw_callback(void * env,wasmtime_context_t * store,const wasmtime_component_func_type_t * ty_const,wasmtime_component_val_t * args,size_t nargs,wasmtime_component_val_t * results,size_t nresults)63 raw_callback(void *env, wasmtime_context_t *store, 64 const wasmtime_component_func_type_t *ty_const, 65 wasmtime_component_val_t *args, size_t nargs, 66 wasmtime_component_val_t *results, size_t nresults) { 67 static_assert(alignof(Val) == alignof(wasmtime_component_val_t)); 68 static_assert(sizeof(Val) == sizeof(wasmtime_component_val_t)); 69 wasmtime_component_func_type_t *ty = 70 const_cast<wasmtime_component_func_type_t *>(ty_const); 71 F *func = reinterpret_cast<F *>(env); 72 Span<Val> args_span(Val::from_capi(args), nargs); 73 Span<Val> results_span(Val::from_capi(results), nresults); 74 Result<std::monostate> result = 75 (*func)(Store::Context(store), *FuncType::from_capi(&ty), args_span, 76 results_span); 77 78 if (!result) { 79 return result.err().capi_release(); 80 } 81 return nullptr; 82 } 83 raw_finalize(void * env)84 template <typename F> static void raw_finalize(void *env) { 85 std::unique_ptr<F> ptr(reinterpret_cast<F *>(env)); 86 } 87 88 public: 89 /// \brief Defines a function within this linker instance. 90 template <typename F, 91 std::enable_if_t< 92 std::is_invocable_r_v<Result<std::monostate>, F, Store::Context, 93 const FuncType &, Span<Val>, Span<Val>>, 94 bool> = true> add_func(std::string_view name,F && f)95 Result<std::monostate> add_func(std::string_view name, F &&f) { 96 auto *error = wasmtime_component_linker_instance_add_func( 97 ptr.get(), name.data(), name.length(), 98 raw_callback<std::remove_reference_t<F>>, 99 std::make_unique<std::remove_reference_t<F>>(std::forward<F>(f)) 100 .release(), 101 raw_finalize<std::remove_reference_t<F>>); 102 103 if (error != nullptr) { 104 return Error(error); 105 } 106 107 return std::monostate(); 108 } 109 110 private: 111 template <typename F> 112 static wasmtime_error_t * raw_resource_destructor_callback(void * env,wasmtime_context_t * store,uint32_t rep)113 raw_resource_destructor_callback(void *env, wasmtime_context_t *store, 114 uint32_t rep) { 115 F *func = reinterpret_cast<F *>(env); 116 Result<std::monostate> result = (*func)(Store::Context(store), rep); 117 if (!result) { 118 return result.err().capi_release(); 119 } 120 return nullptr; 121 } 122 123 public: 124 /// \brief Defines a new resource in this linker with the provided 125 /// destructor. 126 template <typename F, 127 std::enable_if_t<std::is_invocable_r_v<Result<std::monostate>, F, 128 Store::Context, uint32_t>, 129 bool> = true> add_resource(std::string_view name,const ResourceType & ty,F && f)130 Result<std::monostate> add_resource(std::string_view name, 131 const ResourceType &ty, F &&f) { 132 auto *error = wasmtime_component_linker_instance_add_resource( 133 ptr.get(), name.data(), name.length(), ty.capi(), 134 raw_resource_destructor_callback<std::remove_reference_t<F>>, 135 std::make_unique<std::remove_reference_t<F>>(std::forward<F>(f)) 136 .release(), 137 raw_finalize<std::remove_reference_t<F>>); 138 139 if (error != nullptr) { 140 return Error(error); 141 } 142 143 return std::monostate(); 144 } 145 }; 146 147 /** 148 * \brief Class used to instantiate a `Component` into an instance. 149 */ 150 class Linker { 151 WASMTIME_OWN_WRAPPER(Linker, wasmtime_component_linker); 152 153 /// Creates a new linker which will instantiate in the given engine. Linker(Engine & engine)154 explicit Linker(Engine &engine) 155 : ptr(wasmtime_component_linker_new(engine.capi())) {} 156 157 /** 158 * \brief Gets the "root" instance of this linker which can be used to define 159 * items into the linker under the top-level namespace. 160 * 161 * This `Linker` cannot be used while the returned `LinkerInstance` is in 162 * scope. To use more methods on this `Linker` it's required that the instance 163 * returned here is dropped first. 164 */ root()165 LinkerInstance root() { 166 wasmtime_component_linker_instance_t *instance_capi = 167 wasmtime_component_linker_root(ptr.get()); 168 return LinkerInstance(instance_capi); 169 } 170 171 /** 172 * \brief Defines all unknown imports of `component` as trapping functions. 173 */ 174 Result<std::monostate> define_unknown_imports_as_traps(const Component & component)175 define_unknown_imports_as_traps(const Component &component) { 176 auto err = wasmtime_component_linker_define_unknown_imports_as_traps( 177 ptr.get(), component.capi()); 178 if (err) 179 return Error(err); 180 return std::monostate(); 181 } 182 183 /// Configures whether shadowing previous names is allowed or not. 184 /// 185 /// By default shadowing is not allowed. allow_shadowing(bool allow)186 void allow_shadowing(bool allow) { 187 wasmtime_component_linker_allow_shadowing(ptr.get(), allow); 188 } 189 190 /// \brief Instantiates the given component within this linker. instantiate(Store::Context cx,Component & component)191 Result<Instance> instantiate(Store::Context cx, Component &component) { 192 wasmtime_component_instance_t ret; 193 wasmtime_error_t *error = wasmtime_component_linker_instantiate( 194 ptr.get(), cx.capi(), component.capi(), &ret); 195 if (error != nullptr) { 196 return Error(error); 197 } 198 return Instance(ret); 199 } 200 201 #ifdef WASMTIME_FEATURE_WASI 202 /** 203 * \brief Adds WASIp2 API definitions to this linker. 204 * 205 * This will use the WASIp2 API definitions in Wasmtime to this linker. Note 206 * that this adds *synchronous* versions of WASIp2 definitions which will 207 * block the caller when invoked. Internally this will use Wasmtime's 208 * default async runtime implemented with Tokio to handle async I/O. 209 */ add_wasip2()210 Result<std::monostate> add_wasip2() { 211 wasmtime_error_t *error = wasmtime_component_linker_add_wasip2(ptr.get()); 212 if (error != nullptr) { 213 return Error(error); 214 } 215 return std::monostate(); 216 } 217 #endif // WASMTIME_FEATURE_WASI 218 219 #ifdef WASMTIME_FEATURE_WASI_HTTP 220 /** 221 * \brief Adds WASI HTTP definitions to this linker. 222 * 223 * This adds `wasi:http/types` and `wasi:http/outgoing-handler` to the linker. 224 * Requires WASIp2 to be added first via \ref add_wasip2. 225 */ add_wasi_http()226 Result<std::monostate> add_wasi_http() { 227 wasmtime_error_t *error = 228 wasmtime_component_linker_add_wasi_http(ptr.get()); 229 if (error != nullptr) { 230 return Error(error); 231 } 232 return std::monostate(); 233 } 234 #endif // WASMTIME_FEATURE_WASI_HTTP 235 }; 236 237 } // namespace component 238 } // namespace wasmtime 239 240 #endif // WASMTIME_FEATURE_COMPONENT_MODEL 241 242 #endif // WASMTIME_COMPONENT_LINKER_H 243