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