|
3 | 3 | * [Wasmtime](https://github.com/bytecodealliance/wasmtime). Support for the |
4 | 4 | * C++ API is exclusively built on the [C API of |
5 | 5 | * Wasmtime](https://docs.wasmtime.dev/c-api/), so the C++ support for this is |
6 | | - * simply a single header file. To use this header file, though, it must be |
7 | | - * combined with the header and binary of Wasmtime's C API. Note, though, that |
8 | | - * while this header is built on top of the `wasmtime.h` header file you should |
9 | | - * only need to use the contents of this header file to interact with Wasmtime. |
| 6 | + * just a set of header files. Like the C API the C++ API is split into |
| 7 | + * separate headers to be included on an as-needed basis. Types shouldn't |
| 8 | + * need to use the C API, but if something is missing please feel free to file |
| 9 | + * an issue. |
10 | 10 | * |
11 | 11 | * Examples can be [found |
12 | 12 | * online](https://github.com/bytecodealliance/wasmtime/tree/main/examples) |
|
30 | 30 | #ifndef WASMTIME_HH |
31 | 31 | #define WASMTIME_HH |
32 | 32 |
|
33 | | -#include <any> |
34 | | -#include <array> |
35 | | -#include <cstdio> |
36 | | -#include <initializer_list> |
37 | | -#include <iosfwd> |
38 | | -#include <limits> |
39 | | -#include <memory> |
40 | | -#include <optional> |
41 | | -#include <ostream> |
42 | | -#include <variant> |
43 | | -#include <vector> |
44 | | - |
45 | | -#include <wasmtime.h> |
46 | 33 | #include <wasmtime/config.hh> |
47 | 34 | #include <wasmtime/engine.hh> |
48 | 35 | #include <wasmtime/error.hh> |
49 | 36 | #include <wasmtime/extern.hh> |
50 | 37 | #include <wasmtime/func.hh> |
51 | 38 | #include <wasmtime/global.hh> |
| 39 | +#include <wasmtime/instance.hh> |
| 40 | +#include <wasmtime/linker.hh> |
52 | 41 | #include <wasmtime/memory.hh> |
53 | 42 | #include <wasmtime/module.hh> |
54 | 43 | #include <wasmtime/store.hh> |
|
58 | 47 | #include <wasmtime/val.hh> |
59 | 48 | #include <wasmtime/wasi.hh> |
60 | 49 |
|
61 | | -namespace wasmtime { |
62 | | - |
63 | | -/** |
64 | | - * \brief A WebAssembly instance. |
65 | | - * |
66 | | - * This class represents a WebAssembly instance, created by instantiating a |
67 | | - * module. An instance is the collection of items exported by the module, which |
68 | | - * can be accessed through the `Store` that owns the instance. |
69 | | - * |
70 | | - * Note that this type does not itself own any resources. It points to resources |
71 | | - * owned within a `Store` and the `Store` must be passed in as the first |
72 | | - * argument to the functions defined on `Instance`. Note that if the wrong |
73 | | - * `Store` is passed in then the process will be aborted. |
74 | | - */ |
75 | | -class Instance { |
76 | | - friend class Linker; |
77 | | - friend class Caller; |
78 | | - |
79 | | - wasmtime_instance_t instance; |
80 | | - |
81 | | - static Extern cvt(wasmtime_extern_t &e) { |
82 | | - switch (e.kind) { |
83 | | - case WASMTIME_EXTERN_FUNC: |
84 | | - return Func(e.of.func); |
85 | | - case WASMTIME_EXTERN_GLOBAL: |
86 | | - return Global(e.of.global); |
87 | | - case WASMTIME_EXTERN_MEMORY: |
88 | | - return Memory(e.of.memory); |
89 | | - case WASMTIME_EXTERN_TABLE: |
90 | | - return Table(e.of.table); |
91 | | - } |
92 | | - std::abort(); |
93 | | - } |
94 | | - |
95 | | - static void cvt(const Extern &e, wasmtime_extern_t &raw) { |
96 | | - if (const auto *func = std::get_if<Func>(&e)) { |
97 | | - raw.kind = WASMTIME_EXTERN_FUNC; |
98 | | - raw.of.func = func->func; |
99 | | - } else if (const auto *global = std::get_if<Global>(&e)) { |
100 | | - raw.kind = WASMTIME_EXTERN_GLOBAL; |
101 | | - raw.of.global = global->global; |
102 | | - } else if (const auto *table = std::get_if<Table>(&e)) { |
103 | | - raw.kind = WASMTIME_EXTERN_TABLE; |
104 | | - raw.of.table = table->table; |
105 | | - } else if (const auto *memory = std::get_if<Memory>(&e)) { |
106 | | - raw.kind = WASMTIME_EXTERN_MEMORY; |
107 | | - raw.of.memory = memory->memory; |
108 | | - } else { |
109 | | - std::abort(); |
110 | | - } |
111 | | - } |
112 | | - |
113 | | -public: |
114 | | - /// Creates a new instance from the raw underlying C API representation. |
115 | | - Instance(wasmtime_instance_t instance) : instance(instance) {} |
116 | | - |
117 | | - /** |
118 | | - * \brief Instantiates the module `m` with the provided `imports` |
119 | | - * |
120 | | - * \param cx the store in which to instantiate the provided module |
121 | | - * \param m the module to instantiate |
122 | | - * \param imports the list of imports to use to instantiate the module |
123 | | - * |
124 | | - * This `imports` parameter is expected to line up 1:1 with the imports |
125 | | - * required by the `m`. The type of `m` can be inspected to determine in which |
126 | | - * order to provide the imports. Note that this is a relatively low-level API |
127 | | - * and it's generally recommended to use `Linker` instead for name-based |
128 | | - * instantiation. |
129 | | - * |
130 | | - * This function can return an error if any of the `imports` have the wrong |
131 | | - * type, or if the wrong number of `imports` is provided. |
132 | | - */ |
133 | | - static TrapResult<Instance> create(Store::Context cx, const Module &m, |
134 | | - const std::vector<Extern> &imports) { |
135 | | - std::vector<wasmtime_extern_t> raw_imports; |
136 | | - for (const auto &item : imports) { |
137 | | - raw_imports.push_back(wasmtime_extern_t{}); |
138 | | - auto &last = raw_imports.back(); |
139 | | - Instance::cvt(item, last); |
140 | | - } |
141 | | - wasmtime_instance_t instance; |
142 | | - wasm_trap_t *trap = nullptr; |
143 | | - auto *error = wasmtime_instance_new(cx.ptr, m.ptr.get(), raw_imports.data(), |
144 | | - raw_imports.size(), &instance, &trap); |
145 | | - if (error != nullptr) { |
146 | | - return TrapError(Error(error)); |
147 | | - } |
148 | | - if (trap != nullptr) { |
149 | | - return TrapError(Trap(trap)); |
150 | | - } |
151 | | - return Instance(instance); |
152 | | - } |
153 | | - |
154 | | - /** |
155 | | - * \brief Load an instance's export by name. |
156 | | - * |
157 | | - * This function will look for an export named `name` on this instance and, if |
158 | | - * found, return it as an `Extern`. |
159 | | - */ |
160 | | - std::optional<Extern> get(Store::Context cx, std::string_view name) { |
161 | | - wasmtime_extern_t e; |
162 | | - if (!wasmtime_instance_export_get(cx.ptr, &instance, name.data(), |
163 | | - name.size(), &e)) { |
164 | | - return std::nullopt; |
165 | | - } |
166 | | - return Instance::cvt(e); |
167 | | - } |
168 | | - |
169 | | - /** |
170 | | - * \brief Load an instance's export by index. |
171 | | - * |
172 | | - * This function will look for the `idx`th export of this instance. This will |
173 | | - * return both the name of the export as well as the exported item itself. |
174 | | - */ |
175 | | - std::optional<std::pair<std::string_view, Extern>> get(Store::Context cx, |
176 | | - size_t idx) { |
177 | | - wasmtime_extern_t e; |
178 | | - // I'm not sure why clang-tidy thinks this is using va_list or anything |
179 | | - // related to that... |
180 | | - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) |
181 | | - char *name = nullptr; |
182 | | - size_t len = 0; |
183 | | - if (!wasmtime_instance_export_nth(cx.ptr, &instance, idx, &name, &len, |
184 | | - &e)) { |
185 | | - return std::nullopt; |
186 | | - } |
187 | | - std::string_view n(name, len); |
188 | | - return std::pair(n, Instance::cvt(e)); |
189 | | - } |
190 | | -}; |
191 | | - |
192 | | -inline std::optional<Extern> Caller::get_export(std::string_view name) { |
193 | | - wasmtime_extern_t item; |
194 | | - if (wasmtime_caller_export_get(ptr, name.data(), name.size(), &item)) { |
195 | | - return Instance::cvt(item); |
196 | | - } |
197 | | - return std::nullopt; |
198 | | -} |
199 | | - |
200 | | -/** |
201 | | - * \brief Helper class for linking modules together with name-based resolution. |
202 | | - * |
203 | | - * This class is used for easily instantiating `Module`s by defining names into |
204 | | - * the linker and performing name-based resolution during instantiation. A |
205 | | - * `Linker` can also be used to link in WASI functions to instantiate a module. |
206 | | - */ |
207 | | -class Linker { |
208 | | - struct deleter { |
209 | | - void operator()(wasmtime_linker_t *p) const { wasmtime_linker_delete(p); } |
210 | | - }; |
211 | | - |
212 | | - std::unique_ptr<wasmtime_linker_t, deleter> ptr; |
213 | | - |
214 | | -public: |
215 | | - /// Creates a new linker which will instantiate in the given engine. |
216 | | - explicit Linker(Engine &engine) |
217 | | - : ptr(wasmtime_linker_new(engine.ptr.get())) {} |
218 | | - |
219 | | - /// Configures whether shadowing previous names is allowed or not. |
220 | | - /// |
221 | | - /// By default shadowing is not allowed. |
222 | | - void allow_shadowing(bool allow) { |
223 | | - wasmtime_linker_allow_shadowing(ptr.get(), allow); |
224 | | - } |
225 | | - |
226 | | - /// Defines the provided item into this linker with the given name. |
227 | | - Result<std::monostate> define(Store::Context cx, std::string_view module, |
228 | | - std::string_view name, const Extern &item) { |
229 | | - wasmtime_extern_t raw; |
230 | | - Instance::cvt(item, raw); |
231 | | - auto *error = |
232 | | - wasmtime_linker_define(ptr.get(), cx.ptr, module.data(), module.size(), |
233 | | - name.data(), name.size(), &raw); |
234 | | - if (error != nullptr) { |
235 | | - return Error(error); |
236 | | - } |
237 | | - return std::monostate(); |
238 | | - } |
239 | | - |
240 | | - /// Defines WASI functions within this linker. |
241 | | - /// |
242 | | - /// Note that `Store::Context::set_wasi` must also be used for instantiated |
243 | | - /// modules to have access to configured WASI state. |
244 | | - Result<std::monostate> define_wasi() { |
245 | | - auto *error = wasmtime_linker_define_wasi(ptr.get()); |
246 | | - if (error != nullptr) { |
247 | | - return Error(error); |
248 | | - } |
249 | | - return std::monostate(); |
250 | | - } |
251 | | - |
252 | | - /// Defines all exports of the `instance` provided in this linker with the |
253 | | - /// given module name of `name`. |
254 | | - Result<std::monostate> |
255 | | - define_instance(Store::Context cx, std::string_view name, Instance instance) { |
256 | | - auto *error = wasmtime_linker_define_instance( |
257 | | - ptr.get(), cx.ptr, name.data(), name.size(), &instance.instance); |
258 | | - if (error != nullptr) { |
259 | | - return Error(error); |
260 | | - } |
261 | | - return std::monostate(); |
262 | | - } |
263 | | - |
264 | | - /// Instantiates the module `m` provided within the store `cx` using the items |
265 | | - /// defined within this linker. |
266 | | - TrapResult<Instance> instantiate(Store::Context cx, const Module &m) { |
267 | | - wasmtime_instance_t instance; |
268 | | - wasm_trap_t *trap = nullptr; |
269 | | - auto *error = wasmtime_linker_instantiate(ptr.get(), cx.ptr, m.ptr.get(), |
270 | | - &instance, &trap); |
271 | | - if (error != nullptr) { |
272 | | - return TrapError(Error(error)); |
273 | | - } |
274 | | - if (trap != nullptr) { |
275 | | - return TrapError(Trap(trap)); |
276 | | - } |
277 | | - return Instance(instance); |
278 | | - } |
279 | | - |
280 | | - /// Defines instantiations of the module `m` within this linker under the |
281 | | - /// given `name`. |
282 | | - Result<std::monostate> module(Store::Context cx, std::string_view name, |
283 | | - const Module &m) { |
284 | | - auto *error = wasmtime_linker_module(ptr.get(), cx.ptr, name.data(), |
285 | | - name.size(), m.ptr.get()); |
286 | | - if (error != nullptr) { |
287 | | - return Error(error); |
288 | | - } |
289 | | - return std::monostate(); |
290 | | - } |
291 | | - |
292 | | - /// Attempts to load the specified named item from this linker, returning |
293 | | - /// `std::nullopt` if it was not defined. |
294 | | - [[nodiscard]] std::optional<Extern> |
295 | | - get(Store::Context cx, std::string_view module, std::string_view name) { |
296 | | - wasmtime_extern_t item; |
297 | | - if (wasmtime_linker_get(ptr.get(), cx.ptr, module.data(), module.size(), |
298 | | - name.data(), name.size(), &item)) { |
299 | | - return Instance::cvt(item); |
300 | | - } |
301 | | - return std::nullopt; |
302 | | - } |
303 | | - |
304 | | - /// Defines a new function in this linker in the style of the `Func` |
305 | | - /// constructor. |
306 | | - template <typename F, |
307 | | - std::enable_if_t< |
308 | | - std::is_invocable_r_v<Result<std::monostate, Trap>, F, Caller, |
309 | | - Span<const Val>, Span<Val>>, |
310 | | - bool> = true> |
311 | | - Result<std::monostate> func_new(std::string_view module, |
312 | | - std::string_view name, const FuncType &ty, |
313 | | - F &&f) { |
314 | | - |
315 | | - auto *error = wasmtime_linker_define_func( |
316 | | - ptr.get(), module.data(), module.length(), name.data(), name.length(), |
317 | | - ty.ptr.get(), Func::raw_callback<std::remove_reference_t<F>>, |
318 | | - std::make_unique<std::remove_reference_t<F>>(std::forward<F>(f)) |
319 | | - .release(), |
320 | | - Func::raw_finalize<std::remove_reference_t<F>>); |
321 | | - |
322 | | - if (error != nullptr) { |
323 | | - return Error(error); |
324 | | - } |
325 | | - |
326 | | - return std::monostate(); |
327 | | - } |
328 | | - |
329 | | - /// Defines a new function in this linker in the style of the `Func::wrap` |
330 | | - /// constructor. |
331 | | - template <typename F, |
332 | | - std::enable_if_t<WasmHostFunc<F>::Params::valid, bool> = true, |
333 | | - std::enable_if_t<WasmHostFunc<F>::Results::valid, bool> = true> |
334 | | - Result<std::monostate> func_wrap(std::string_view module, |
335 | | - std::string_view name, F &&f) { |
336 | | - using HostFunc = WasmHostFunc<F>; |
337 | | - auto params = HostFunc::Params::types(); |
338 | | - auto results = HostFunc::Results::types(); |
339 | | - auto ty = FuncType::from_iters(params, results); |
340 | | - auto *error = wasmtime_linker_define_func_unchecked( |
341 | | - ptr.get(), module.data(), module.length(), name.data(), name.length(), |
342 | | - ty.ptr.get(), Func::raw_callback_unchecked<std::remove_reference_t<F>>, |
343 | | - std::make_unique<std::remove_reference_t<F>>(std::forward<F>(f)) |
344 | | - .release(), |
345 | | - Func::raw_finalize<std::remove_reference_t<F>>); |
346 | | - |
347 | | - if (error != nullptr) { |
348 | | - return Error(error); |
349 | | - } |
350 | | - |
351 | | - return std::monostate(); |
352 | | - } |
353 | | - |
354 | | - /// Loads the "default" function, according to WASI commands and reactors, of |
355 | | - /// the module named `name` in this linker. |
356 | | - Result<Func> get_default(Store::Context cx, std::string_view name) { |
357 | | - wasmtime_func_t item; |
358 | | - auto *error = wasmtime_linker_get_default(ptr.get(), cx.ptr, name.data(), |
359 | | - name.size(), &item); |
360 | | - if (error != nullptr) { |
361 | | - return Error(error); |
362 | | - } |
363 | | - return Func(item); |
364 | | - } |
365 | | -}; |
366 | | - |
367 | | -} // namespace wasmtime |
368 | | - |
369 | 50 | #endif // WASMTIME_HH |
0 commit comments