1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
#ifndef WASMTIME_FUNC_CLASS_HH
#define WASMTIME_FUNC_CLASS_HH
#include <array>
#include <wasmtime/_store_class.hh>
#include <wasmtime/error.hh>
#include <wasmtime/extern_declare.hh>
#include <wasmtime/func.h>
#include <wasmtime/span.hh>
#include <wasmtime/trap.hh>
#include <wasmtime/types/func.hh>
#include <wasmtime/types/val.hh>
namespace wasmtime {
class Val;
/**
* \brief Structure provided to host functions to lookup caller information or
* acquire a `Store::Context`.
*
* This structure is passed to all host functions created with `Func`. It can be
* used to create a `Store::Context`.
*/
class Caller {
friend class Func;
friend class Store;
wasmtime_caller_t *ptr;
Caller(wasmtime_caller_t *ptr) : ptr(ptr) {}
public:
/// Attempts to load an exported item from the calling instance.
///
/// For more information see the Rust documentation -
/// https://docs.wasmtime.dev/api/wasmtime/struct.Caller.html#method.get_export
std::optional<Extern> get_export(std::string_view name);
/// Explicitly acquire a `Store::Context` from this `Caller`.
Store::Context context() { return this; }
};
namespace detail {
/// A "trait" for native types that correspond to WebAssembly types for use with
/// `Func::wrap` and `TypedFunc::call`
template <typename T> struct WasmType {
static const bool valid = false;
};
/// A "trait" for a list of types and operations on them, used for `Func::wrap`
/// and `TypedFunc::call`
///
/// The base case is a single type which is a list of one element.
template <typename T> struct WasmTypeList {
static const bool valid = WasmType<T>::valid;
static const size_t size = 1;
static bool matches(ValType::ListRef types) {
return WasmTypeList<std::tuple<T>>::matches(types);
}
static void store(Store::Context cx, wasmtime_val_raw_t *storage, T &&t) {
WasmType<T>::store(cx, storage, t);
}
static void store(Store::Context cx, wasmtime_val_raw_t *storage,
const T &t) {
WasmType<T>::store(cx, storage, t);
}
static T load(Store::Context cx, wasmtime_val_raw_t *storage) {
return WasmType<T>::load(cx, storage);
}
static std::vector<ValType> types() { return {WasmType<T>::valtype()}; }
};
/// A "trait" for what can be returned from closures specified to `Func::wrap`.
///
/// The base case here is a bare return value like `int32_t`.
template <typename R> struct WasmHostRet {
using Results = WasmTypeList<R>;
template <typename F, typename... A>
static std::optional<Trap> invoke(F f, Caller cx, wasmtime_val_raw_t *raw,
A... args) {
auto ret = f(args...);
Results::store(cx, raw, ret);
return std::nullopt;
}
};
template <typename F, typename = void> struct WasmHostFunc;
} // namespace detail
using namespace detail;
// forward-declaration for `Func::typed` below.
template <typename Params, typename Results> class TypedFunc;
/**
* \brief Representation of a WebAssembly function.
*
* This class represents a WebAssembly function, either created through
* instantiating a module or a host function.
*
* Note that this type does not itself own any resources. It points to resources
* owned within a `Store` and the `Store` must be passed in as the first
* argument to the functions defined on `Func`. Note that if the wrong `Store`
* is passed in then the process will be aborted.
*/
class Func {
friend class Val;
friend class Instance;
friend class Linker;
template <typename Params, typename Results> friend class TypedFunc;
wasmtime_func_t func;
template <typename F>
static wasm_trap_t *raw_callback(void *env, wasmtime_caller_t *caller,
const wasmtime_val_t *args, size_t nargs,
wasmtime_val_t *results, size_t nresults);
template <typename F>
static wasm_trap_t *
raw_callback_unchecked(void *env, wasmtime_caller_t *caller,
wasmtime_val_raw_t *args_and_results,
size_t nargs_and_results) {
(void)nargs_and_results;
using HostFunc = WasmHostFunc<F>;
Caller cx(caller);
F *func = reinterpret_cast<F *>(env); // NOLINT
auto trap = HostFunc::invoke(*func, cx, args_and_results);
if (trap) {
return trap->capi_release();
}
return nullptr;
}
template <typename F> static void raw_finalize(void *env) {
std::unique_ptr<F> ptr(reinterpret_cast<F *>(env)); // NOLINT
}
public:
/// Creates a new function from the raw underlying C API representation.
Func(wasmtime_func_t func) : func(func) {}
/**
* \brief Creates a new host-defined function.
*
* This constructor is used to create a host function within the store
* provided. This is how WebAssembly can call into the host and make use of
* external functionality.
*
* > **Note**: host functions created this way are more flexible but not
* > as fast to call as those created by `Func::wrap`.
*
* \param cx the store to create the function within
* \param ty the type of the function that will be created
* \param f the host callback to be executed when this function is called.
*
* The parameter `f` is expected to be a lambda (or a lambda lookalike) which
* takes three parameters:
*
* * The first parameter is a `Caller` to get recursive access to the store
* and other caller state.
* * The second parameter is a `Span<const Val>` which is the list of
* parameters to the function. These parameters are guaranteed to be of the
* types specified by `ty` when constructing this function.
* * The last argument is `Span<Val>` which is where to write the return
* values of the function. The function must produce the types of values
* specified by `ty` or otherwise a trap will be raised.
*
* The parameter `f` is expected to return `Result<std::monostate, Trap>`.
* This allows `f` to raise a trap if desired, or otherwise return no trap and
* finish successfully. If a trap is raised then the results pointer does not
* need to be written to.
*/
template <typename F,
std::enable_if_t<
std::is_invocable_r_v<Result<std::monostate, Trap>, F, Caller,
Span<const Val>, Span<Val>>,
bool> = true>
Func(Store::Context cx, const FuncType &ty, F f) : func({}) {
wasmtime_func_new(cx.ptr, ty.ptr.get(), raw_callback<F>,
std::make_unique<F>(f).release(), raw_finalize<F>, &func);
}
/**
* \brief Creates a new host function from the provided callback `f`,
* inferring the WebAssembly function type from the host signature.
*
* This function is akin to the `Func` constructor except that the WebAssembly
* type does not need to be specified and additionally the signature of `f`
* is different. The main goal of this function is to enable WebAssembly to
* call the function `f` as-fast-as-possible without having to validate any
* types or such.
*
* The function `f` can optionally take a `Caller` as its first parameter,
* but otherwise its arguments are translated to WebAssembly types:
*
* * `int32_t`, `uint32_t` - `i32`
* * `int64_t`, `uint64_t` - `i64`
* * `float` - `f32`
* * `double` - `f64`
* * `std::optional<Func>` - `funcref`
* * `std::optional<ExternRef>` - `externref`
* * `wasmtime::V128` - `v128`
*
* The function may only take these arguments and if it takes any other kinds
* of arguments then it will fail to compile.
*
* The function may return a few different flavors of return values:
*
* * `void` - interpreted as returning nothing
* * Any type above - interpreted as a singular return value.
* * `std::tuple<T...>` where `T` is one of the valid argument types -
* interpreted as returning multiple values.
* * `Result<T, Trap>` where `T` is another valid return type - interpreted as
* a function that returns `T` to wasm but is optionally allowed to also
* raise a trap.
*
* It's recommended, if possible, to use this function over the `Func`
* constructor since this is generally easier to work with and also enables
* a faster path for WebAssembly to call this function.
*/
template <typename F,
std::enable_if_t<WasmHostFunc<F>::Params::valid, bool> = true,
std::enable_if_t<WasmHostFunc<F>::Results::valid, bool> = true>
static Func wrap(Store::Context cx, F f) {
using HostFunc = WasmHostFunc<F>;
auto params = HostFunc::Params::types();
auto results = HostFunc::Results::types();
auto ty = FuncType::from_iters(params, results);
wasmtime_func_t func;
wasmtime_func_new_unchecked(cx.ptr, ty.ptr.get(), raw_callback_unchecked<F>,
std::make_unique<F>(f).release(),
raw_finalize<F>, &func);
return func;
}
/**
* \brief Invoke a WebAssembly function.
*
* This function will execute this WebAssembly function. This function muts be
* defined within the `cx`'s store provided. The `params` argument is the list
* of parameters that are passed to the wasm function, and the types of the
* values within `params` must match the type signature of this function.
*
* This may return one of three values:
*
* * First the function could succeed, returning a vector of values
* representing the results of the function.
* * Otherwise a `Trap` might be generated by the WebAssembly function.
* * Finally an `Error` could be returned indicating that `params` were not of
* the right type.
*
* > **Note**: for optimized calls into WebAssembly where the function
* > signature is statically known it's recommended to use `Func::typed` and
* > `TypedFunc::call`.
*/
template <typename I>
TrapResult<std::vector<Val>> call(Store::Context cx, const I &begin,
const I &end) const;
/**
* \brief Helper function for `call(Store::Context cx, const I &begin, const I
* &end)`
*
* \see call(Store::Context cx, const I &begin, const I &end)
*/
TrapResult<std::vector<Val>> call(Store::Context cx,
const std::vector<Val> ¶ms) const;
/**
* \brief Helper function for `call(Store::Context cx, const I &begin, const I
* &end)`
*
* \see call(Store::Context cx, const I &begin, const I &end)
*/
TrapResult<std::vector<Val>>
call(Store::Context cx, const std::initializer_list<Val> ¶ms) const;
/// Returns the type of this function.
FuncType type(Store::Context cx) const {
return wasmtime_func_type(cx.ptr, &func);
}
/**
* \brief Statically checks this function against the provided types.
*
* This function will check whether it takes the statically known `Params`
* and returns the statically known `Results`. If the type check succeeds then
* a `TypedFunc` is returned which enables a faster method of invoking
* WebAssembly functions.
*
* The `Params` and `Results` specified as template parameters here are the
* parameters and results of the wasm function. They can either be a bare
* type which means that the wasm takes/returns one value, or they can be a
* `std::tuple<T...>` of types to represent multiple arguments or multiple
* returns.
*
* The valid types for this function are those mentioned as the arguments
* for `Func::wrap`.
*/
template <typename Params, typename Results,
std::enable_if_t<WasmTypeList<Params>::valid, bool> = true,
std::enable_if_t<WasmTypeList<Results>::valid, bool> = true>
Result<TypedFunc<Params, Results>, Trap> typed(Store::Context cx) const {
auto ty = this->type(cx);
if (!WasmTypeList<Params>::matches(ty->params()) ||
!WasmTypeList<Results>::matches(ty->results())) {
return Trap("static type for this function does not match actual type");
}
TypedFunc<Params, Results> ret(*this);
return ret;
}
/// Returns the raw underlying C API function this is using.
const wasmtime_func_t &capi() const { return func; }
};
/**
* \brief A version of a WebAssembly `Func` where the type signature of the
* function is statically known.
*/
template <typename Params, typename Results> class TypedFunc {
friend class Func;
Func f;
TypedFunc(Func func) : f(func) {}
public:
/**
* \brief Calls this function with the provided parameters.
*
* This function is akin to `Func::call` except that since static type
* information is available it statically takes its parameters and statically
* returns its results.
*
* Note that this function still may return a `Trap` indicating that calling
* the WebAssembly function failed.
*/
TrapResult<Results> call(Store::Context cx, const Params ¶ms) const {
std::array<wasmtime_val_raw_t, std::max(WasmTypeList<Params>::size,
WasmTypeList<Results>::size)>
storage;
wasmtime_val_raw_t *ptr = storage.data();
if (ptr == nullptr)
ptr = reinterpret_cast<wasmtime_val_raw_t *>(alignof(wasmtime_val_raw_t));
WasmTypeList<Params>::store(cx, ptr, params);
wasm_trap_t *trap = nullptr;
auto *error = wasmtime_func_call_unchecked(cx.capi(), &f.func, ptr,
storage.size(), &trap);
if (error != nullptr) {
return TrapError(Error(error));
}
if (trap != nullptr) {
return TrapError(Trap(trap));
}
return WasmTypeList<Results>::load(cx, ptr);
}
/// Returns the underlying un-typed `Func` for this function.
const Func &func() const { return f; }
};
} // namespace wasmtime
#endif // WASMTIME_FUNC_CLASS_HH