Courtesy of https://github.com/bytecodealliance/wasmtime-cpp . Taken as is, with a small licensing blurb added on top.
2666 lines
85 KiB
C++
2666 lines
85 KiB
C++
/**
|
|
* Downloaded from https://github.com/bytecodealliance/wasmtime-cpp/blob/main/include/wasmtime.hh
|
|
* License: Apache License 2.0
|
|
*/
|
|
|
|
/**
|
|
* \mainpage
|
|
*
|
|
* This project is a C++ API for
|
|
* [Wasmtime](https://github.com/bytecodealliance/wasmtime). Support for the
|
|
* C++ API is exclusively built on the [C API of
|
|
* Wasmtime](https://docs.wasmtime.dev/c-api/), so the C++ support for this is
|
|
* simply a single header file. To use this header file, though, it must be
|
|
* combined with the header and binary of Wasmtime's C API. Note, though, that
|
|
* while this header is built on top of the `wasmtime.h` header file you should
|
|
* only need to use the contents of this header file to interact with Wasmtime.
|
|
*
|
|
* Examples can be [found
|
|
* online](https://github.com/bytecodealliance/wasmtime-cpp/tree/main/examples)
|
|
* and otherwise be sure to check out the
|
|
* [README](https://github.com/bytecodealliance/wasmtime-cpp/blob/main/README.md)
|
|
* for simple usage instructions. Otherwise you can dive right in to the
|
|
* reference documentation of \ref wasmtime.hh
|
|
*
|
|
* \example hello.cc
|
|
* \example gcd.cc
|
|
* \example linking.cc
|
|
* \example memory.cc
|
|
* \example interrupt.cc
|
|
* \example externref.cc
|
|
*/
|
|
|
|
/**
|
|
* \file wasmtime.hh
|
|
*/
|
|
|
|
#ifndef WASMTIME_HH
|
|
#define WASMTIME_HH
|
|
|
|
#include <any>
|
|
#include <initializer_list>
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <variant>
|
|
#include <vector>
|
|
#ifdef __cpp_lib_span
|
|
#include <span>
|
|
#endif
|
|
|
|
#include "wasmtime.h"
|
|
|
|
namespace wasmtime {
|
|
|
|
#ifdef __cpp_lib_span
|
|
|
|
/// \brief Alias to C++20 std::span when it is available
|
|
template <typename T, std::size_t Extent = std::dynamic_extent>
|
|
using Span = std::span<T, Extent>;
|
|
|
|
#else
|
|
|
|
/// \brief Means number of elements determined at runtime
|
|
inline constexpr size_t dynamic_extent =
|
|
std::numeric_limits<std::size_t>::max();
|
|
|
|
/**
|
|
* \brief Span class used when c++20 is not available
|
|
* @tparam T Type of data
|
|
* @tparam Extent Static size of data refered by Span class
|
|
*/
|
|
template <typename T, std::size_t Extent = dynamic_extent> class Span {
|
|
public:
|
|
/// \brief Type used to iterate over this span (a raw pointer)
|
|
using iterator = T *;
|
|
|
|
/// \brief Constructor of Span class
|
|
Span(T *t, std::size_t n) : ptr_{t}, size_{n} {}
|
|
|
|
/// \brief Constructor of Span class for containers
|
|
template <template <typename, typename> class Container>
|
|
Span(Container<T, std::allocator<T>> &range)
|
|
: ptr_{range.data()}, size_{range.size()} {}
|
|
|
|
/// \brief Returns item by index
|
|
T &operator[](ptrdiff_t idx) const {
|
|
return ptr_[idx]; // NOLINT
|
|
}
|
|
|
|
/// \brief Returns pointer to data
|
|
T *data() const { return ptr_; }
|
|
|
|
/// \brief Returns number of data that referred by Span class
|
|
std::size_t size() const { return size_; }
|
|
|
|
/// \brief Returns begin iterator
|
|
iterator begin() const { return ptr_; }
|
|
|
|
/// \brief Returns end iterator
|
|
iterator end() const {
|
|
return ptr_ + size_; // NOLINT
|
|
}
|
|
|
|
/// \brief Returns size in bytes
|
|
std::size_t size_bytes() const { return sizeof(T) * size_; }
|
|
|
|
private:
|
|
T *ptr_;
|
|
std::size_t size_;
|
|
};
|
|
|
|
#endif
|
|
|
|
/**
|
|
* \brief Errors coming from Wasmtime
|
|
*
|
|
* This class represents an error that came from Wasmtime and contains a textual
|
|
* description of the error that occurred.
|
|
*/
|
|
class Error {
|
|
std::string msg;
|
|
|
|
public:
|
|
/// \brief Creates an error from the raw C API representation
|
|
///
|
|
/// Takes ownership of the provided `error`.
|
|
Error(wasmtime_error_t *error) {
|
|
wasm_byte_vec_t msg_bytes;
|
|
wasmtime_error_message(error, &msg_bytes);
|
|
msg = std::string(msg_bytes.data, msg_bytes.size);
|
|
wasm_byte_vec_delete(&msg_bytes);
|
|
wasmtime_error_delete(error);
|
|
}
|
|
|
|
/// \brief Returns the error message associated with this error.
|
|
std::string_view message() const { return msg; }
|
|
};
|
|
|
|
/// \brief Used to print an error.
|
|
inline std::ostream &operator<<(std::ostream &os, const Error &e) {
|
|
os << e.message();
|
|
return os;
|
|
}
|
|
|
|
/**
|
|
* \brief Fallible result type used for Wasmtime.
|
|
*
|
|
* This type is used as the return value of many methods in the Wasmtime API.
|
|
* This behaves similarly to Rust's `Result<T, E>` and will be replaced with a
|
|
* C++ standard when it exists.
|
|
*/
|
|
template <typename T, typename E = Error> class Result {
|
|
std::variant<T, E> data;
|
|
|
|
public:
|
|
/// \brief Creates a `Result` from its successful value.
|
|
Result(T t) : data(std::move(t)) {}
|
|
/// \brief Creates a `Result` from an error value.
|
|
Result(E e) : data(std::move(e)) {}
|
|
|
|
/// \brief Returns `true` if this result is a success, `false` if it's an
|
|
/// error
|
|
explicit operator bool() { return data.index() == 0; }
|
|
|
|
/// \brief Returns the error, if present, aborts if this is not an error.
|
|
E &&err() { return std::get<E>(std::move(data)); }
|
|
/// \brief Returns the error, if present, aborts if this is not an error.
|
|
const E &&err() const { return std::get<E>(std::move(data)); }
|
|
|
|
/// \brief Returns the success, if present, aborts if this is an error.
|
|
T &&ok() { return std::get<T>(std::move(data)); }
|
|
/// \brief Returns the success, if present, aborts if this is an error.
|
|
const T &&ok() const { return std::get<T>(std::move(data)); }
|
|
|
|
/// \brief Returns the success, if present, aborts if this is an error.
|
|
T unwrap() {
|
|
if (*this) {
|
|
return this->ok();
|
|
}
|
|
std::cerr << "error: " << this->err().message() << "\n";
|
|
std::abort();
|
|
}
|
|
};
|
|
|
|
/// \brief Strategies passed to `Config::strategy`
|
|
enum class Strategy {
|
|
/// Automatically selects the compilation strategy
|
|
Auto = WASMTIME_STRATEGY_AUTO,
|
|
/// Requires Cranelift to be used for compilation
|
|
Cranelift = WASMTIME_STRATEGY_CRANELIFT,
|
|
/// Uses lightbeam for compilation (not supported)
|
|
Lightbeam = WASMTIME_STRATEGY_LIGHTBEAM,
|
|
};
|
|
|
|
/// \brief Values passed to `Config::cranelift_opt_level`
|
|
enum class OptLevel {
|
|
/// No extra optimizations performed
|
|
None = WASMTIME_OPT_LEVEL_NONE,
|
|
/// Optimize for speed
|
|
Speed = WASMTIME_OPT_LEVEL_SPEED,
|
|
/// Optimize for speed and generated code size
|
|
SpeedAndSize = WASMTIME_OPT_LEVEL_SPEED_AND_SIZE,
|
|
};
|
|
|
|
/// \brief Values passed to `Config::profiler`
|
|
enum class ProfilingStrategy {
|
|
/// No profiling enabled
|
|
None = WASMTIME_PROFILING_STRATEGY_NONE,
|
|
/// Profiling hooks via perf's jitdump
|
|
Jitdump = WASMTIME_PROFILING_STRATEGY_JITDUMP,
|
|
/// Profiling hooks via VTune
|
|
Vtune = WASMTIME_PROFILING_STRATEGY_VTUNE,
|
|
};
|
|
|
|
/**
|
|
* \brief Configuration for Wasmtime.
|
|
*
|
|
* This class is used to configure Wasmtime's compilation and various other
|
|
* settings such as enabled WebAssembly proposals.
|
|
*
|
|
* For more information be sure to consult the [rust
|
|
* documentation](https://docs.wasmtime.dev/api/wasmtime/struct.Config.html).
|
|
*/
|
|
class Config {
|
|
friend class Engine;
|
|
|
|
struct deleter {
|
|
void operator()(wasm_config_t *p) const { wasm_config_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasm_config_t, deleter> ptr;
|
|
|
|
public:
|
|
/// \brief Creates configuration with all the default settings.
|
|
Config() : ptr(wasm_config_new()) {}
|
|
|
|
/// \brief Configures whether dwarf debuginfo is emitted for assisting
|
|
/// in-process debugging.
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.debug_info
|
|
void debug_info(bool enable) {
|
|
wasmtime_config_debug_info_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures whether WebAssembly code can be interrupted.
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.interruptable
|
|
void interruptable(bool enable) {
|
|
wasmtime_config_interruptable_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures whether WebAssembly code will consume fuel and trap when
|
|
/// it runs out.
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.consume_fuel
|
|
void consume_fuel(bool enable) {
|
|
wasmtime_config_consume_fuel_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures the maximum amount of native stack wasm can consume.
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.max_wasm_stack
|
|
void max_wasm_stack(size_t stack) {
|
|
wasmtime_config_max_wasm_stack_set(ptr.get(), stack);
|
|
}
|
|
|
|
/// \brief Configures whether the WebAssembly threads proposal is enabled
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.wasm_threads
|
|
void wasm_threads(bool enable) {
|
|
wasmtime_config_wasm_threads_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures whether the WebAssembly reference types proposal is
|
|
/// enabled
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.wasm_reference_types
|
|
void wasm_reference_types(bool enable) {
|
|
wasmtime_config_wasm_reference_types_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures whether the WebAssembly simd proposal is enabled
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.wasm_simd
|
|
void wasm_simd(bool enable) {
|
|
wasmtime_config_wasm_simd_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures whether the WebAssembly bulk memory proposal is enabled
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.wasm_bulk_memory
|
|
void wasm_bulk_memory(bool enable) {
|
|
wasmtime_config_wasm_bulk_memory_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures whether the WebAssembly multi value proposal is enabled
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.wasm_multi_value
|
|
void wasm_multi_value(bool enable) {
|
|
wasmtime_config_wasm_multi_value_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures whether the WebAssembly module linking proposal is
|
|
/// enabled
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.wasm_module_linking
|
|
void wasm_module_linking(bool enable) {
|
|
wasmtime_config_wasm_module_linking_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures compilation strategy for wasm code.
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.strategy
|
|
[[nodiscard]] Result<std::monostate> strategy(Strategy strategy) {
|
|
auto *error = wasmtime_config_strategy_set(
|
|
ptr.get(), static_cast<wasmtime_strategy_t>(strategy));
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// \brief Configures whether cranelift's debug verifier is enabled
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.cranelift_debug_verifier
|
|
void cranelift_debug_verifier(bool enable) {
|
|
wasmtime_config_cranelift_debug_verifier_set(ptr.get(), enable);
|
|
}
|
|
|
|
/// \brief Configures cranelift's optimization level
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.cranelift_opt_level
|
|
void cranelift_opt_level(OptLevel level) {
|
|
wasmtime_config_cranelift_opt_level_set(
|
|
ptr.get(), static_cast<wasmtime_opt_level_t>(level));
|
|
}
|
|
|
|
/// \brief Configures an active wasm profiler
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.profiler
|
|
[[nodiscard]] Result<std::monostate> profiler(ProfilingStrategy profiler) {
|
|
auto *error = wasmtime_config_profiler_set(
|
|
ptr.get(), static_cast<wasmtime_profiling_strategy_t>(profiler));
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// \brief Configures the maximum size of memory to use a "static memory"
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.static_memory_maximum_size
|
|
void static_memory_maximum_size(size_t size) {
|
|
wasmtime_config_static_memory_maximum_size_set(ptr.get(), size);
|
|
}
|
|
|
|
/// \brief Configures the size of static memory's guard region
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.static_memory_guard_size
|
|
void static_memory_guard_size(size_t size) {
|
|
wasmtime_config_static_memory_guard_size_set(ptr.get(), size);
|
|
}
|
|
|
|
/// \brief Configures the size of dynamic memory's guard region
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.dynamic_memory_guard_size
|
|
void dynamic_memory_guard_size(size_t size) {
|
|
wasmtime_config_dynamic_memory_guard_size_set(ptr.get(), size);
|
|
}
|
|
|
|
/// \brief Loads the default cache configuration present on the system.
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.cache_config_load_default
|
|
[[nodiscard]] Result<std::monostate> cache_load_default() {
|
|
auto *error = wasmtime_config_cache_config_load(ptr.get(), nullptr);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// \brief Loads cache configuration from the specified filename.
|
|
///
|
|
/// https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.cache_config_load
|
|
[[nodiscard]] Result<std::monostate> cache_load(const std::string &path) {
|
|
auto *error = wasmtime_config_cache_config_load(ptr.get(), path.c_str());
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief Global compilation state in Wasmtime.
|
|
*
|
|
* Created with either default configuration or with a specified instance of
|
|
* configuration, an `Engine` is used as an umbrella "session" for all other
|
|
* operations in Wasmtime.
|
|
*/
|
|
class Engine {
|
|
friend class Store;
|
|
friend class Module;
|
|
friend class Linker;
|
|
|
|
struct deleter {
|
|
void operator()(wasm_engine_t *p) const { wasm_engine_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasm_engine_t, deleter> ptr;
|
|
|
|
public:
|
|
/// \brief Creates an engine with default compilation settings.
|
|
Engine() : ptr(wasm_engine_new()) {}
|
|
/// \brief Creates an engine with the specified compilation settings.
|
|
explicit Engine(Config config)
|
|
: ptr(wasm_engine_new_with_config(config.ptr.release())) {}
|
|
};
|
|
|
|
/**
|
|
* \brief Converts the WebAssembly text format into the WebAssembly binary
|
|
* format.
|
|
*
|
|
* This will parse the text format and attempt to translate it to the binary
|
|
* format. Note that the text parser assumes that all WebAssembly features are
|
|
* enabled and will parse syntax of future proposals. The exact syntax here
|
|
* parsed may be tweaked over time.
|
|
*
|
|
* Returns either an error if parsing failed or the wasm binary.
|
|
*/
|
|
[[nodiscard]] inline Result<std::vector<uint8_t>>
|
|
wat2wasm(std::string_view wat) {
|
|
wasm_byte_vec_t ret;
|
|
auto *error = wasmtime_wat2wasm(wat.data(), wat.size(), &ret);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
std::vector<uint8_t> vec;
|
|
// NOLINTNEXTLINE TODO can this be done without triggering lints?
|
|
Span<uint8_t> raw(reinterpret_cast<uint8_t *>(ret.data), ret.size);
|
|
vec.assign(raw.begin(), raw.end());
|
|
wasm_byte_vec_delete(&ret);
|
|
return vec;
|
|
}
|
|
|
|
/**
|
|
* \brief Min/max limits used for `MemoryType` and `TableType`
|
|
*/
|
|
class Limits {
|
|
friend class MemoryType;
|
|
friend class TableType;
|
|
|
|
wasm_limits_t raw;
|
|
|
|
public:
|
|
/// \brief Configures a minimum limit and no maximum limit.
|
|
explicit Limits(uint32_t min) : raw{} {
|
|
raw.min = min;
|
|
raw.max = wasm_limits_max_default;
|
|
}
|
|
/// \brief Configures both a minimum and a maximum limit.
|
|
Limits(uint32_t min, uint32_t max) : raw{} {
|
|
raw.min = min;
|
|
raw.max = max;
|
|
}
|
|
/// \brief Creates limits from the raw underlying C API.
|
|
Limits(const wasm_limits_t *limits) : raw(*limits) {}
|
|
|
|
/// \brief Returns the minimum size specified by these limits.
|
|
uint32_t min() const { return raw.min; }
|
|
|
|
/// \brief Returns optional maximum limit configured.
|
|
std::optional<uint32_t> max() const {
|
|
if (raw.max == wasm_limits_max_default) {
|
|
return std::nullopt;
|
|
}
|
|
return raw.max;
|
|
}
|
|
};
|
|
|
|
/// Different kinds of types accepted by Wasmtime.
|
|
enum class ValKind {
|
|
/// WebAssembly's `i32` type
|
|
I32,
|
|
/// WebAssembly's `i64` type
|
|
I64,
|
|
/// WebAssembly's `f32` type
|
|
F32,
|
|
/// WebAssembly's `f64` type
|
|
F64,
|
|
/// WebAssembly's `v128` type from the simd proposal
|
|
V128,
|
|
/// WebAssembly's `externref` type from the reference types
|
|
ExternRef,
|
|
/// WebAssembly's `funcref` type from the reference types
|
|
FuncRef,
|
|
};
|
|
|
|
/**
|
|
* \brief Type information about a WebAssembly value.
|
|
*
|
|
* Currently mostly just contains the `ValKind`.
|
|
*/
|
|
class ValType {
|
|
friend class TableType;
|
|
friend class GlobalType;
|
|
friend class FuncType;
|
|
|
|
struct deleter {
|
|
void operator()(wasm_valtype_t *p) const { wasm_valtype_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasm_valtype_t, deleter> ptr;
|
|
|
|
static wasm_valkind_t kind_to_c(ValKind kind) {
|
|
switch (kind) {
|
|
case ValKind::I32:
|
|
return WASM_I32;
|
|
case ValKind::I64:
|
|
return WASM_I64;
|
|
case ValKind::F32:
|
|
return WASM_F32;
|
|
case ValKind::F64:
|
|
return WASM_F64;
|
|
case ValKind::ExternRef:
|
|
return WASM_ANYREF;
|
|
case ValKind::FuncRef:
|
|
return WASM_FUNCREF;
|
|
case ValKind::V128:
|
|
return WASMTIME_V128;
|
|
}
|
|
}
|
|
|
|
public:
|
|
/// \brief Non-owning reference to a `ValType`, must not be used after the
|
|
/// original `ValType` is deleted.
|
|
class Ref {
|
|
friend class ValType;
|
|
|
|
const wasm_valtype_t *ptr;
|
|
|
|
public:
|
|
/// \brief Instantiates from the raw C API representation.
|
|
Ref(const wasm_valtype_t *ptr) : ptr(ptr) {}
|
|
/// Copy constructor
|
|
Ref(const ValType &ty) : Ref(ty.ptr.get()) {}
|
|
|
|
/// \brief Returns the corresponding "kind" for this type.
|
|
ValKind kind() const {
|
|
switch (wasm_valtype_kind(ptr)) {
|
|
case WASM_I32:
|
|
return ValKind::I32;
|
|
case WASM_I64:
|
|
return ValKind::I64;
|
|
case WASM_F32:
|
|
return ValKind::F32;
|
|
case WASM_F64:
|
|
return ValKind::F64;
|
|
case WASM_ANYREF:
|
|
return ValKind::ExternRef;
|
|
case WASM_FUNCREF:
|
|
return ValKind::FuncRef;
|
|
case WASMTIME_V128:
|
|
return ValKind::V128;
|
|
}
|
|
std::abort();
|
|
}
|
|
};
|
|
|
|
/// \brief Non-owning reference to a list of `ValType` instances. Must not be
|
|
/// used after the original owner is deleted.
|
|
class ListRef {
|
|
const wasm_valtype_vec_t *list;
|
|
|
|
public:
|
|
/// Creates a list from the raw underlying C API.
|
|
ListRef(const wasm_valtype_vec_t *list) : list(list) {}
|
|
|
|
/// This list iterates over a list of `ValType::Ref` instances.
|
|
typedef const Ref *iterator;
|
|
|
|
/// Pointer to the beginning of iteration
|
|
iterator begin() const {
|
|
return reinterpret_cast<Ref *>(&list->data[0]); // NOLINT
|
|
}
|
|
|
|
/// Pointer to the end of iteration
|
|
iterator end() const {
|
|
return reinterpret_cast<Ref *>(&list->data[list->size]); // NOLINT
|
|
}
|
|
|
|
/// Returns how many types are in this list.
|
|
size_t size() const { return list->size; }
|
|
};
|
|
|
|
private:
|
|
Ref ref;
|
|
ValType(wasm_valtype_t *ptr) : ptr(ptr), ref(ptr) {}
|
|
|
|
public:
|
|
/// Creates a new type from its kind.
|
|
ValType(ValKind kind) : ValType(wasm_valtype_new(kind_to_c(kind))) {}
|
|
/// Copies a `Ref` to a new owned value.
|
|
ValType(Ref other) : ValType(wasm_valtype_copy(other.ptr)) {}
|
|
/// Copies one type to a new one.
|
|
ValType(const ValType &other) : ValType(wasm_valtype_copy(other.ptr.get())) {}
|
|
/// Copies the contents of another type into this one.
|
|
ValType &operator=(const ValType &other) {
|
|
ptr.reset(wasm_valtype_copy(other.ptr.get()));
|
|
return *this;
|
|
}
|
|
~ValType() = default;
|
|
/// Moves the memory owned by another value type into this one.
|
|
ValType(ValType &&other) = default;
|
|
/// Moves the memory owned by another value type into this one.
|
|
ValType &operator=(ValType &&other) = default;
|
|
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator->() { return &ref; }
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator*() { return &ref; }
|
|
};
|
|
|
|
/**
|
|
* \brief Type information about a WebAssembly linear memory
|
|
*/
|
|
class MemoryType {
|
|
friend class Memory;
|
|
|
|
struct deleter {
|
|
void operator()(wasm_memorytype_t *p) const { wasm_memorytype_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasm_memorytype_t, deleter> ptr;
|
|
|
|
public:
|
|
/// \brief Non-owning reference to a `MemoryType`, must not be used after the
|
|
/// original owner has been deleted.
|
|
class Ref {
|
|
friend class MemoryType;
|
|
|
|
const wasm_memorytype_t *ptr;
|
|
|
|
public:
|
|
/// Creates a refernece from the raw C API representation.
|
|
Ref(const wasm_memorytype_t *ptr) : ptr(ptr) {}
|
|
/// Creates a reference from an original `MemoryType`.
|
|
Ref(const MemoryType &ty) : Ref(ty.ptr.get()) {}
|
|
|
|
/// Returns the underlying limits on this wasm memory type, specified in
|
|
/// units of wasm pages.
|
|
Limits limits() const { return Limits(wasm_memorytype_limits(ptr)); }
|
|
};
|
|
|
|
private:
|
|
Ref ref;
|
|
MemoryType(wasm_memorytype_t *ptr) : ptr(ptr), ref(ptr) {}
|
|
|
|
public:
|
|
/// Creates a new wasm memory from the specified limits.
|
|
explicit MemoryType(const Limits &limits)
|
|
: MemoryType(wasm_memorytype_new(&limits.raw)) {}
|
|
/// Creates a new wasm memory type from the specified ref, making a fresh
|
|
/// owned value.
|
|
MemoryType(Ref other) : MemoryType(wasm_memorytype_copy(other.ptr)) {}
|
|
/// Copies the provided type into a new type.
|
|
MemoryType(const MemoryType &other)
|
|
: MemoryType(wasm_memorytype_copy(other.ptr.get())) {}
|
|
/// Copies the provided type into a new type.
|
|
MemoryType &operator=(const MemoryType &other) {
|
|
ptr.reset(wasm_memorytype_copy(other.ptr.get()));
|
|
return *this;
|
|
}
|
|
~MemoryType() = default;
|
|
/// Moves the type information from another type into this one.
|
|
MemoryType(MemoryType &&other) = default;
|
|
/// Moves the type information from another type into this one.
|
|
MemoryType &operator=(MemoryType &&other) = default;
|
|
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator->() { return &ref; }
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator*() { return &ref; }
|
|
};
|
|
|
|
/**
|
|
* \brief Type information about a WebAssembly table.
|
|
*/
|
|
class TableType {
|
|
friend class Table;
|
|
|
|
struct deleter {
|
|
void operator()(wasm_tabletype_t *p) const { wasm_tabletype_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasm_tabletype_t, deleter> ptr;
|
|
|
|
public:
|
|
/// Non-owning reference to a `TableType`, must not be used after the original
|
|
/// owner is deleted.
|
|
class Ref {
|
|
friend class TableType;
|
|
|
|
const wasm_tabletype_t *ptr;
|
|
|
|
public:
|
|
/// Creates a reference from the raw underlying C API representation.
|
|
Ref(const wasm_tabletype_t *ptr) : ptr(ptr) {}
|
|
/// Creates a reference to the provided `TableType`.
|
|
Ref(const TableType &ty) : Ref(ty.ptr.get()) {}
|
|
|
|
/// Returns the limits, in units of elements, of this table.
|
|
Limits limits() const { return wasm_tabletype_limits(ptr); }
|
|
|
|
/// Returns the type of value that is stored in this table.
|
|
ValType::Ref element() const { return wasm_tabletype_element(ptr); }
|
|
};
|
|
|
|
private:
|
|
Ref ref;
|
|
TableType(wasm_tabletype_t *ptr) : ptr(ptr), ref(ptr) {}
|
|
|
|
public:
|
|
/// Creates a new table type from the specified value type and limits.
|
|
TableType(ValType ty, Limits limits)
|
|
: TableType(wasm_tabletype_new(ty.ptr.release(), &limits.raw)) {}
|
|
/// Clones the given reference into a new table type.
|
|
TableType(Ref other) : TableType(wasm_tabletype_copy(other.ptr)) {}
|
|
/// Copies another table type into this one.
|
|
TableType(const TableType &other)
|
|
: TableType(wasm_tabletype_copy(other.ptr.get())) {}
|
|
/// Copies another table type into this one.
|
|
TableType &operator=(const TableType &other) {
|
|
ptr.reset(wasm_tabletype_copy(other.ptr.get()));
|
|
return *this;
|
|
}
|
|
~TableType() = default;
|
|
/// Moves the table type resources from another type to this one.
|
|
TableType(TableType &&other) = default;
|
|
/// Moves the table type resources from another type to this one.
|
|
TableType &operator=(TableType &&other) = default;
|
|
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator->() { return &ref; }
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator*() { return &ref; }
|
|
};
|
|
|
|
/**
|
|
* \brief Type information about a WebAssembly global
|
|
*/
|
|
class GlobalType {
|
|
friend class Global;
|
|
|
|
struct deleter {
|
|
void operator()(wasm_globaltype_t *p) const { wasm_globaltype_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasm_globaltype_t, deleter> ptr;
|
|
|
|
public:
|
|
/// Non-owning reference to a `Global`, must not be used after the original
|
|
/// owner is deleted.
|
|
class Ref {
|
|
friend class GlobalType;
|
|
const wasm_globaltype_t *ptr;
|
|
|
|
public:
|
|
/// Creates a new reference from the raw underlying C API representation.
|
|
Ref(const wasm_globaltype_t *ptr) : ptr(ptr) {}
|
|
/// Creates a new reference to the specified type.
|
|
Ref(const GlobalType &ty) : Ref(ty.ptr.get()) {}
|
|
|
|
/// Returns whether or not this global type is mutable.
|
|
bool is_mutable() const {
|
|
return wasm_globaltype_mutability(ptr) == WASM_VAR;
|
|
}
|
|
|
|
/// Returns the type of value stored within this global type.
|
|
ValType::Ref content() const { return wasm_globaltype_content(ptr); }
|
|
};
|
|
|
|
private:
|
|
Ref ref;
|
|
GlobalType(wasm_globaltype_t *ptr) : ptr(ptr), ref(ptr) {}
|
|
|
|
public:
|
|
/// Creates a new global type from the specified value type and mutability.
|
|
GlobalType(ValType ty, bool mut)
|
|
: GlobalType(wasm_globaltype_new(
|
|
ty.ptr.release(),
|
|
(wasm_mutability_t)(mut ? WASM_VAR : WASM_CONST))) {}
|
|
/// Clones a reference into a uniquely owned global type.
|
|
GlobalType(Ref other) : GlobalType(wasm_globaltype_copy(other.ptr)) {}
|
|
/// Copies othe type information into this one.
|
|
GlobalType(const GlobalType &other)
|
|
: GlobalType(wasm_globaltype_copy(other.ptr.get())) {}
|
|
/// Copies othe type information into this one.
|
|
GlobalType &operator=(const GlobalType &other) {
|
|
ptr.reset(wasm_globaltype_copy(other.ptr.get()));
|
|
return *this;
|
|
}
|
|
~GlobalType() = default;
|
|
/// Moves the underlying type information from another global into this one.
|
|
GlobalType(GlobalType &&other) = default;
|
|
/// Moves the underlying type information from another global into this one.
|
|
GlobalType &operator=(GlobalType &&other) = default;
|
|
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator->() { return &ref; }
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator*() { return &ref; }
|
|
};
|
|
|
|
/**
|
|
* \brief Type information for a WebAssembly function.
|
|
*/
|
|
class FuncType {
|
|
friend class Func;
|
|
|
|
struct deleter {
|
|
void operator()(wasm_functype_t *p) const { wasm_functype_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasm_functype_t, deleter> ptr;
|
|
|
|
public:
|
|
/// Non-owning reference to a `FuncType`, must not be used after the original
|
|
/// owner has been deleted.
|
|
class Ref {
|
|
friend class FuncType;
|
|
const wasm_functype_t *ptr;
|
|
|
|
public:
|
|
/// Creates a new reference from the underlying C API representation.
|
|
Ref(const wasm_functype_t *ptr) : ptr(ptr) {}
|
|
/// Creates a new reference to the given type.
|
|
Ref(const FuncType &ty) : Ref(ty.ptr.get()) {}
|
|
|
|
/// Returns the list of types this function type takes as parameters.
|
|
ValType::ListRef params() const { return wasm_functype_params(ptr); }
|
|
|
|
/// Returns the list of types this function type returns.
|
|
ValType::ListRef results() const { return wasm_functype_results(ptr); }
|
|
};
|
|
|
|
private:
|
|
Ref ref;
|
|
FuncType(wasm_functype_t *ptr) : ptr(ptr), ref(ptr) {}
|
|
|
|
public:
|
|
/// Creates a new function type from the given list of parameters and results.
|
|
FuncType(std::initializer_list<ValType> params,
|
|
std::initializer_list<ValType> results)
|
|
: ref(nullptr) {
|
|
wasm_valtype_vec_t param_vec;
|
|
wasm_valtype_vec_t result_vec;
|
|
wasm_valtype_vec_new_uninitialized(¶m_vec, params.size());
|
|
wasm_valtype_vec_new_uninitialized(&result_vec, results.size());
|
|
size_t i = 0;
|
|
for (auto val : params) {
|
|
param_vec.data[i++] = val.ptr.release(); // NOLINT
|
|
}
|
|
i = 0;
|
|
for (auto val : results) {
|
|
result_vec.data[i++] = val.ptr.release(); // NOLINT
|
|
}
|
|
|
|
ptr.reset(wasm_functype_new(¶m_vec, &result_vec));
|
|
ref = ptr.get();
|
|
}
|
|
|
|
/// Copies a reference into a uniquely owned function type.
|
|
FuncType(Ref other) : FuncType(wasm_functype_copy(other.ptr)) {}
|
|
/// Copies another type's information into this one.
|
|
FuncType(const FuncType &other)
|
|
: FuncType(wasm_functype_copy(other.ptr.get())) {}
|
|
/// Copies another type's information into this one.
|
|
FuncType &operator=(const FuncType &other) {
|
|
ptr.reset(wasm_functype_copy(other.ptr.get()));
|
|
return *this;
|
|
}
|
|
~FuncType() = default;
|
|
/// Moves type information from anothe type into this one.
|
|
FuncType(FuncType &&other) = default;
|
|
/// Moves type information from anothe type into this one.
|
|
FuncType &operator=(FuncType &&other) = default;
|
|
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator->() { return &ref; }
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator*() { return &ref; }
|
|
};
|
|
|
|
/**
|
|
* \brief Type information about a WebAssembly import.
|
|
*/
|
|
class ImportType {
|
|
public:
|
|
/// Non-owning reference to an `ImportType`, must not be used after the
|
|
/// original owner is deleted.
|
|
class Ref {
|
|
friend class TypeList;
|
|
friend class ExternType;
|
|
|
|
const wasm_importtype_t *ptr;
|
|
|
|
// TODO: can this circle be broken another way?
|
|
const wasm_externtype_t *raw_type() { return wasm_importtype_type(ptr); }
|
|
|
|
public:
|
|
/// Creates a new reference from the raw underlying C API representation.
|
|
Ref(const wasm_importtype_t *ptr) : ptr(ptr) {}
|
|
|
|
/// Returns the module name associated with this import.
|
|
std::string_view module() {
|
|
const auto *name = wasm_importtype_module(ptr);
|
|
return std::string_view(name->data, name->size);
|
|
}
|
|
|
|
/// Returns the field name associated with this import.
|
|
std::string_view name() {
|
|
const auto *name = wasm_importtype_name(ptr);
|
|
return std::string_view(name->data, name->size);
|
|
}
|
|
};
|
|
|
|
/// An owned list of `ImportType` instances.
|
|
class List {
|
|
friend class InstanceType;
|
|
friend class ModuleType;
|
|
|
|
wasm_importtype_vec_t list;
|
|
|
|
public:
|
|
/// Creates an empty list
|
|
List() : list{} {
|
|
list.size = 0;
|
|
list.data = nullptr;
|
|
}
|
|
List(const List &other) = delete;
|
|
/// Moves another list into this one.
|
|
List(List &&other) noexcept : list(other.list) { other.list.size = 0; }
|
|
~List() {
|
|
if (list.size > 0) {
|
|
wasm_importtype_vec_delete(&list);
|
|
}
|
|
}
|
|
|
|
List &operator=(const List &other) = delete;
|
|
/// Moves another list into this one.
|
|
List &operator=(List &&other) noexcept {
|
|
std::swap(list, other.list);
|
|
return *this;
|
|
}
|
|
|
|
/// Iterator type, which is a list of non-owning `ImportType::Ref`
|
|
/// instances.
|
|
typedef const Ref *iterator;
|
|
/// Returns the start of iteration.
|
|
iterator begin() const {
|
|
return reinterpret_cast<iterator>(&list.data[0]); // NOLINT
|
|
}
|
|
/// Returns the end of iteration.
|
|
iterator end() const {
|
|
return reinterpret_cast<iterator>(&list.data[list.size]); // NOLINT
|
|
}
|
|
/// Returns the size of this list.
|
|
size_t size() const { return list.size; }
|
|
};
|
|
};
|
|
|
|
/**
|
|
* \brief Type information about a WebAssembly export
|
|
*/
|
|
class ExportType {
|
|
|
|
public:
|
|
/// \brief Non-owning reference to an `ExportType`.
|
|
///
|
|
/// Note to get type information you can use `ExternType::from_export`.
|
|
class Ref {
|
|
friend class ExternType;
|
|
|
|
const wasm_exporttype_t *ptr;
|
|
|
|
const wasm_externtype_t *raw_type() { return wasm_exporttype_type(ptr); }
|
|
|
|
public:
|
|
/// Creates a new reference from the raw underlying C API representation.
|
|
Ref(const wasm_exporttype_t *ptr) : ptr(ptr) {}
|
|
|
|
/// Returns the name of this export.
|
|
std::string_view name() {
|
|
const auto *name = wasm_exporttype_name(ptr);
|
|
return std::string_view(name->data, name->size);
|
|
}
|
|
};
|
|
|
|
/// An owned list of `ExportType` instances.
|
|
class List {
|
|
friend class InstanceType;
|
|
friend class ModuleType;
|
|
|
|
wasm_exporttype_vec_t list;
|
|
|
|
public:
|
|
/// Creates an empty list
|
|
List() : list{} {
|
|
list.size = 0;
|
|
list.data = nullptr;
|
|
}
|
|
List(const List &other) = delete;
|
|
/// Moves another list into this one.
|
|
List(List &&other) noexcept : list(other.list) { other.list.size = 0; }
|
|
~List() {
|
|
if (list.size > 0) {
|
|
wasm_exporttype_vec_delete(&list);
|
|
}
|
|
}
|
|
|
|
List &operator=(const List &other) = delete;
|
|
/// Moves another list into this one.
|
|
List &operator=(List &&other) noexcept {
|
|
std::swap(list, other.list);
|
|
return *this;
|
|
}
|
|
|
|
/// Iterator type, which is a list of non-owning `ExportType::Ref`
|
|
/// instances.
|
|
typedef const Ref *iterator;
|
|
/// Returns the start of iteration.
|
|
iterator begin() const {
|
|
return reinterpret_cast<iterator>(&list.data[0]); // NOLINT
|
|
}
|
|
/// Returns the end of iteration.
|
|
iterator end() const {
|
|
return reinterpret_cast<iterator>(&list.data[list.size]); // NOLINT
|
|
}
|
|
/// Returns the size of this list.
|
|
size_t size() const { return list.size; }
|
|
};
|
|
};
|
|
|
|
/**
|
|
* \brief Type information about a WebAssembly module.
|
|
*/
|
|
class ModuleType {
|
|
friend class Module;
|
|
|
|
struct deleter {
|
|
void operator()(wasmtime_moduletype_t *p) const {
|
|
wasmtime_moduletype_delete(p);
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<wasmtime_moduletype_t, deleter> ptr;
|
|
|
|
public:
|
|
/// Non-owning reference to a `ModuleType`, must not be used after the owner
|
|
/// has been deleted.
|
|
class Ref {
|
|
friend class ModuleType;
|
|
|
|
const wasmtime_moduletype_t *ptr;
|
|
|
|
public:
|
|
/// Creates a new reference from the raw underlying C API representation.
|
|
Ref(const wasmtime_moduletype_t *ptr) : ptr(ptr) {}
|
|
/// Creates a reference to the given type.
|
|
Ref(const ModuleType &ty) : Ref(ty.ptr.get()) {}
|
|
|
|
/// Returns the list of types imported by this module.
|
|
ImportType::List imports() const {
|
|
ImportType::List list;
|
|
wasmtime_moduletype_imports(ptr, &list.list);
|
|
return list;
|
|
}
|
|
|
|
/// Returns the list of types exported by this module.
|
|
ExportType::List exports() const {
|
|
ExportType::List list;
|
|
wasmtime_moduletype_exports(ptr, &list.list);
|
|
return list;
|
|
}
|
|
};
|
|
|
|
private:
|
|
Ref ref;
|
|
ModuleType(wasmtime_moduletype_t *ptr) : ptr(ptr), ref(ptr) {}
|
|
|
|
public:
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator->() { return &ref; }
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator*() { return &ref; }
|
|
};
|
|
|
|
/**
|
|
* \brief Type information about a WebAssembly instance.
|
|
*/
|
|
class InstanceType {
|
|
friend class Instance;
|
|
|
|
struct deleter {
|
|
void operator()(wasmtime_instancetype_t *p) const {
|
|
wasmtime_instancetype_delete(p);
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<wasmtime_instancetype_t, deleter> ptr;
|
|
|
|
public:
|
|
/// Non-owning reference to an `InstanceType`, must not be used after the
|
|
/// original owner is deleted.
|
|
class Ref {
|
|
friend class InstanceType;
|
|
|
|
const wasmtime_instancetype_t *ptr;
|
|
|
|
public:
|
|
/// Creates a new reference from the raw underlying C API representation.
|
|
Ref(const wasmtime_instancetype_t *ptr) : ptr(ptr) {}
|
|
/// Creates a new reference to the provided type.
|
|
Ref(const InstanceType &ty) : Ref(ty.ptr.get()) {}
|
|
|
|
/// Returns the list of types exported by this instance.
|
|
ExportType::List exports() const {
|
|
ExportType::List list;
|
|
wasmtime_instancetype_exports(ptr, &list.list);
|
|
return list;
|
|
}
|
|
};
|
|
|
|
private:
|
|
Ref ref;
|
|
InstanceType(wasmtime_instancetype_t *ptr) : ptr(ptr), ref(ptr) {}
|
|
|
|
public:
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator->() { return &ref; }
|
|
/// \brief Returns the underlying `Ref`, a non-owning reference pointing to
|
|
/// this instance.
|
|
Ref *operator*() { return &ref; }
|
|
};
|
|
|
|
/**
|
|
* \brief Generic type of a WebAssembly item.
|
|
*/
|
|
class ExternType {
|
|
friend class ExportType;
|
|
friend class ImportType;
|
|
|
|
public:
|
|
/// \typedef Ref
|
|
/// \brief Non-owning reference to an item's type
|
|
///
|
|
/// This cannot be used after the original owner has been deleted, and
|
|
/// otherwise this is used to determine what the actual type of the outer item
|
|
/// is.
|
|
typedef std::variant<FuncType::Ref, GlobalType::Ref, TableType::Ref,
|
|
MemoryType::Ref, ModuleType::Ref, InstanceType::Ref>
|
|
Ref;
|
|
|
|
/// Extract the type of the item imported by the provided type.
|
|
static Ref from_import(ImportType::Ref ty) {
|
|
// TODO: this would ideally be some sort of implicit constructor, unsure how
|
|
// to do that though...
|
|
return ref_from_c(ty.raw_type());
|
|
}
|
|
|
|
/// Extract the type of the item exported by the provided type.
|
|
static Ref from_export(ExportType::Ref ty) {
|
|
// TODO: this would ideally be some sort of implicit constructor, unsure how
|
|
// to do that though...
|
|
return ref_from_c(ty.raw_type());
|
|
}
|
|
|
|
private:
|
|
static Ref ref_from_c(const wasm_externtype_t *ptr) {
|
|
switch (wasm_externtype_kind(ptr)) {
|
|
case WASM_EXTERN_FUNC:
|
|
return wasm_externtype_as_functype_const(ptr);
|
|
case WASM_EXTERN_GLOBAL:
|
|
return wasm_externtype_as_globaltype_const(ptr);
|
|
case WASM_EXTERN_TABLE:
|
|
return wasm_externtype_as_tabletype_const(ptr);
|
|
case WASM_EXTERN_MEMORY:
|
|
return wasm_externtype_as_memorytype_const(ptr);
|
|
case WASMTIME_EXTERN_MODULE:
|
|
// Should probably just add const versions of these functions to
|
|
// wasmtime's C API?
|
|
return wasmtime_externtype_as_moduletype(
|
|
const_cast<wasm_externtype_t *>(ptr)); // NOLINT
|
|
case WASMTIME_EXTERN_INSTANCE:
|
|
return wasmtime_externtype_as_instancetype(
|
|
const_cast<wasm_externtype_t *>(ptr)); // NOLINT
|
|
}
|
|
std::abort();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief Non-owning reference to a WebAssembly function frame as part of a
|
|
* `Trace`
|
|
*
|
|
* A `FrameRef` represents a WebAssembly function frame on the stack which was
|
|
* collected as part of a trap.
|
|
*/
|
|
class FrameRef {
|
|
wasm_frame_t *frame;
|
|
|
|
public:
|
|
/// Returns the WebAssembly function index of this function, in the original
|
|
/// module.
|
|
uint32_t func_index() const { return wasm_frame_func_index(frame); }
|
|
/// Returns the offset, in bytes from the start of the function in the
|
|
/// original module, to this frame's program counter.
|
|
size_t func_offset() const { return wasm_frame_func_offset(frame); }
|
|
/// Returns the offset, in bytes from the start of the original module,
|
|
/// to this frame's program counter.
|
|
size_t module_offset() const { return wasm_frame_module_offset(frame); }
|
|
|
|
/// Returns the name, if present, associated with this function.
|
|
///
|
|
/// Note that this requires that the `name` section is present in the original
|
|
/// WebAssembly binary.
|
|
std::optional<std::string_view> func_name() const {
|
|
const auto *name = wasmtime_frame_func_name(frame);
|
|
if (name != nullptr) {
|
|
return std::string_view(name->data, name->size);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Returns the name, if present, associated with this function's module.
|
|
///
|
|
/// Note that this requires that the `name` section is present in the original
|
|
/// WebAssembly binary.
|
|
std::optional<std::string_view> module_name() const {
|
|
const auto *name = wasmtime_frame_module_name(frame);
|
|
if (name != nullptr) {
|
|
return std::string_view(name->data, name->size);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief An owned vector of `FrameRef` instances representing the WebAssembly
|
|
* call-stack on a trap.
|
|
*
|
|
* This can be used to iterate over the frames of a trap and determine what was
|
|
* running when a trap happened.
|
|
*/
|
|
class Trace {
|
|
friend class Trap;
|
|
|
|
wasm_frame_vec_t vec;
|
|
|
|
Trace(wasm_frame_vec_t vec) : vec(vec) {}
|
|
|
|
public:
|
|
~Trace() { wasm_frame_vec_delete(&vec); }
|
|
|
|
Trace(const Trace &other) = delete;
|
|
Trace(Trace &&other) = delete;
|
|
Trace &operator=(const Trace &other) = delete;
|
|
Trace &operator=(Trace &&other) = delete;
|
|
|
|
/// Iterator used to iterate over this trace.
|
|
typedef const FrameRef *iterator;
|
|
|
|
/// Returns the start of iteration
|
|
iterator begin() const {
|
|
return reinterpret_cast<FrameRef *>(&vec.data[0]); // NOLINT
|
|
}
|
|
/// Returns the end of iteration
|
|
iterator end() const {
|
|
return reinterpret_cast<FrameRef *>(&vec.data[vec.size]); // NOLINT
|
|
}
|
|
/// Returns the size of this trace, or how many frames it contains.
|
|
size_t size() const { return vec.size; }
|
|
};
|
|
|
|
/**
|
|
* \brief Information about a WebAssembly trap.
|
|
*
|
|
* Traps can happen during normal wasm execution (such as the `unreachable`
|
|
* instruction) but they can also happen in host-provided functions to a host
|
|
* function can simulate raising a trap.
|
|
*
|
|
* Traps have a message associated with them as well as a trace of WebAssembly
|
|
* frames on the stack.
|
|
*/
|
|
class Trap {
|
|
friend class Linker;
|
|
friend class Instance;
|
|
friend class Func;
|
|
|
|
struct deleter {
|
|
void operator()(wasm_trap_t *p) const { wasm_trap_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasm_trap_t, deleter> ptr;
|
|
|
|
Trap(wasm_trap_t *ptr) : ptr(ptr) {}
|
|
|
|
public:
|
|
/// Creates a new host-defined trap with the specified message.
|
|
explicit Trap(std::string_view msg)
|
|
: Trap(wasmtime_trap_new(msg.data(), msg.size())) {}
|
|
|
|
/// Returns the descriptive message associated with this trap
|
|
std::string message() const {
|
|
wasm_byte_vec_t msg;
|
|
wasm_trap_message(ptr.get(), &msg);
|
|
std::string ret(msg.data, msg.size - 1);
|
|
wasm_byte_vec_delete(&msg);
|
|
return ret;
|
|
}
|
|
|
|
/// If this trap represents a call to `exit` for WASI, this will return the
|
|
/// optional error code associated with the exit trap.
|
|
std::optional<int32_t> i32_exit() const {
|
|
int32_t status = 0;
|
|
if (wasmtime_trap_exit_status(ptr.get(), &status)) {
|
|
return status;
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Returns the trace of WebAssembly frames associated with this trap.
|
|
Trace trace() const {
|
|
wasm_frame_vec_t frames;
|
|
wasm_trap_trace(ptr.get(), &frames);
|
|
return Trace(frames);
|
|
}
|
|
};
|
|
|
|
/// Structure used to represent either a `Trap` or an `Error`.
|
|
struct TrapError {
|
|
/// Storage for what this trap represents.
|
|
std::variant<Trap, Error> data;
|
|
|
|
/// Creates a new `TrapError` from a `Trap`
|
|
TrapError(Trap t) : data(std::move(t)) {}
|
|
/// Creates a new `TrapError` from an `Error`
|
|
TrapError(Error e) : data(std::move(e)) {}
|
|
|
|
/// Dispatches internally to return the message associated with this error.
|
|
std::string message() {
|
|
if (auto *trap = std::get_if<Trap>(&data)) {
|
|
return trap->message();
|
|
}
|
|
if (auto *error = std::get_if<Error>(&data)) {
|
|
return std::string(error->message());
|
|
}
|
|
std::abort();
|
|
}
|
|
};
|
|
|
|
/// Result used by functions which can fail because of invariants being violated
|
|
/// (such as a type error) as well as because of a WebAssembly trap.
|
|
template <typename T> using TrapResult = Result<T, TrapError>;
|
|
|
|
/**
|
|
* \brief Representation of a compiled WebAssembly module.
|
|
*
|
|
* This type contains JIT code of a compiled WebAssembly module. A `Module` is
|
|
* connected to an `Engine` and can only be instantiated within that `Engine`.
|
|
* You can inspect a `Module` for its type information. This is passed as an
|
|
* argument to other APIs to instantiate it.
|
|
*/
|
|
class Module {
|
|
friend class Store;
|
|
friend class Instance;
|
|
friend class Linker;
|
|
|
|
struct deleter {
|
|
void operator()(wasmtime_module_t *p) const { wasmtime_module_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasmtime_module_t, deleter> ptr;
|
|
|
|
Module(wasmtime_module_t *raw) : ptr(raw) {}
|
|
|
|
public:
|
|
/// Copies another module into this one.
|
|
Module(const Module &other) : ptr(wasmtime_module_clone(other.ptr.get())) {}
|
|
/// Copies another module into this one.
|
|
Module &operator=(const Module &other) {
|
|
ptr.reset(wasmtime_module_clone(other.ptr.get()));
|
|
return *this;
|
|
}
|
|
~Module() = default;
|
|
/// Moves resources from another module into this one.
|
|
Module(Module &&other) = default;
|
|
/// Moves resources from another module into this one.
|
|
Module &operator=(Module &&other) = default;
|
|
|
|
/**
|
|
* \brief Compiles a module from the WebAssembly text format.
|
|
*
|
|
* This function will automatically use `wat2wasm` on the input and then
|
|
* delegate to the #compile function.
|
|
*/
|
|
[[nodiscard]] static Result<Module> compile(Engine &engine,
|
|
std::string_view wat) {
|
|
auto wasm = wat2wasm(wat);
|
|
if (!wasm) {
|
|
return wasm.err();
|
|
}
|
|
auto bytes = wasm.ok();
|
|
return compile(engine, bytes);
|
|
}
|
|
|
|
/**
|
|
* \brief Compiles a module from the WebAssembly binary format.
|
|
*
|
|
* This function compiles the provided WebAssembly binary specified by `wasm`
|
|
* within the compilation settings configured by `engine`. This method is
|
|
* synchronous and will not return until the module has finished compiling.
|
|
*
|
|
* This function can fail if the WebAssembly binary is invalid or doesn't
|
|
* validate (or similar).
|
|
*/
|
|
[[nodiscard]] static Result<Module> compile(Engine &engine,
|
|
Span<uint8_t> wasm) {
|
|
wasmtime_module_t *ret = nullptr;
|
|
auto *error =
|
|
wasmtime_module_new(engine.ptr.get(), wasm.data(), wasm.size(), &ret);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return Module(ret);
|
|
}
|
|
|
|
/**
|
|
* \brief Validates the provided WebAssembly binary without compiling it.
|
|
*
|
|
* This function will validate whether the provided binary is indeed valid
|
|
* within the compilation settings of the `engine` provided.
|
|
*/
|
|
[[nodiscard]] static Result<std::monostate> validate(Engine &engine,
|
|
Span<uint8_t> wasm) {
|
|
auto *error =
|
|
wasmtime_module_validate(engine.ptr.get(), wasm.data(), wasm.size());
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/**
|
|
* \brief Deserializes a previous list of bytes created with `serialize`.
|
|
*
|
|
* This function is intended to be much faster than `compile` where it uses
|
|
* the artifacts of a previous compilation to quickly create an in-memory
|
|
* module ready for instantiation.
|
|
*
|
|
* It is not safe to pass arbitrary input to this function, it is only safe to
|
|
* pass in output from previous calls to `serialize`. For more information see
|
|
* the Rust documentation -
|
|
* https://docs.wasmtime.dev/api/wasmtime/struct.Module.html#method.deserialize
|
|
*/
|
|
[[nodiscard]] static Result<Module> deserialize(Engine &engine,
|
|
Span<uint8_t> wasm) {
|
|
wasmtime_module_t *ret = nullptr;
|
|
auto *error = wasmtime_module_deserialize(engine.ptr.get(), wasm.data(),
|
|
wasm.size(), &ret);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return Module(ret);
|
|
}
|
|
|
|
/// Returns the type of this module, which can be used to inspect the
|
|
/// imports/exports.
|
|
ModuleType type() { return wasmtime_module_type(ptr.get()); }
|
|
|
|
/**
|
|
* \brief Serializes this module to a list of bytes.
|
|
*
|
|
* The returned bytes can then be used to later pass to `deserialize` to
|
|
* quickly recreate this module in a different process perhaps.
|
|
*/
|
|
[[nodiscard]] Result<std::vector<uint8_t>> serialize() const {
|
|
wasm_byte_vec_t bytes;
|
|
auto *error = wasmtime_module_serialize(ptr.get(), &bytes);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
std::vector<uint8_t> ret;
|
|
// NOLINTNEXTLINE TODO can this be done without triggering lints?
|
|
Span<uint8_t> raw(reinterpret_cast<uint8_t *>(bytes.data), bytes.size);
|
|
ret.assign(raw.begin(), raw.end());
|
|
wasm_byte_vec_delete(&bytes);
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief Handle used to interrupt execution of WebAssembly from another thread.
|
|
*/
|
|
class InterruptHandle {
|
|
friend class Store;
|
|
|
|
struct deleter {
|
|
void operator()(wasmtime_interrupt_handle_t *p) const {
|
|
wasmtime_interrupt_handle_delete(p);
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<wasmtime_interrupt_handle_t, deleter> ptr;
|
|
|
|
InterruptHandle(wasmtime_interrupt_handle_t *ptr) : ptr(ptr) {}
|
|
|
|
public:
|
|
/// Indicates that the WebAssembly executing in the store this handle is
|
|
/// connected to should be interrupted as soon as possible.
|
|
void interrupt() const { wasmtime_interrupt_handle_interrupt(ptr.get()); }
|
|
};
|
|
|
|
/**
|
|
* \brief Configuration for an instance of WASI.
|
|
*
|
|
* This is inserted into a store with `Store::Context::set_wasi`.
|
|
*/
|
|
class WasiConfig {
|
|
friend class Store;
|
|
|
|
struct deleter {
|
|
void operator()(wasi_config_t *p) const { wasi_config_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasi_config_t, deleter> ptr;
|
|
|
|
public:
|
|
/// Creates a new configuration object with default settings.
|
|
WasiConfig() : ptr(wasi_config_new()) {}
|
|
|
|
/// Configures the argv explicitly with the given string array.
|
|
void argv(const std::vector<std::string> &args) {
|
|
std::vector<const char *> ptrs;
|
|
ptrs.reserve(args.size());
|
|
for (const auto &arg : args) {
|
|
ptrs.push_back(arg.c_str());
|
|
}
|
|
|
|
wasi_config_set_argv(ptr.get(), (int)args.size(), ptrs.data());
|
|
}
|
|
|
|
/// Configures the argv for wasm to be inherited from this process itself.
|
|
void inherit_argv() { wasi_config_inherit_argv(ptr.get()); }
|
|
|
|
/// Configures the environment variables available to wasm, specified here as
|
|
/// a list of pairs where the first element of the pair is the key and the
|
|
/// second element is the value.
|
|
void env(const std::vector<std::pair<std::string, std::string>> &env) {
|
|
std::vector<const char *> names;
|
|
std::vector<const char *> values;
|
|
for (const auto &[name, value] : env) {
|
|
names.push_back(name.c_str());
|
|
values.push_back(value.c_str());
|
|
}
|
|
wasi_config_set_env(ptr.get(), (int)env.size(), names.data(),
|
|
values.data());
|
|
}
|
|
|
|
/// Indicates that the entire environment of this process should be inherited
|
|
/// by the wasi configuration.
|
|
void inherit_env() { wasi_config_inherit_env(ptr.get()); }
|
|
|
|
/// Configures the provided file to be used for the stdin of this WASI
|
|
/// configuration.
|
|
[[nodiscard]] bool stdin_file(const std::string &path) {
|
|
return wasi_config_set_stdin_file(ptr.get(), path.c_str());
|
|
}
|
|
|
|
/// Configures this WASI configuration to inherit its stdin from the host
|
|
/// process.
|
|
void inherit_stdin() { return wasi_config_inherit_stdin(ptr.get()); }
|
|
|
|
/// Configures the provided file to be created and all stdout output will be
|
|
/// written there.
|
|
[[nodiscard]] bool stdout_file(const std::string &path) {
|
|
return wasi_config_set_stdout_file(ptr.get(), path.c_str());
|
|
}
|
|
|
|
/// Configures this WASI configuration to inherit its stdout from the host
|
|
/// process.
|
|
void inherit_stdout() { return wasi_config_inherit_stdout(ptr.get()); }
|
|
|
|
/// Configures the provided file to be created and all stderr output will be
|
|
/// written there.
|
|
[[nodiscard]] bool stderr_file(const std::string &path) {
|
|
return wasi_config_set_stderr_file(ptr.get(), path.c_str());
|
|
}
|
|
|
|
/// Configures this WASI configuration to inherit its stdout from the host
|
|
/// process.
|
|
void inherit_stderr() { return wasi_config_inherit_stderr(ptr.get()); }
|
|
|
|
/// Opens `path` to be opened as `guest_path` in the WASI pseudo-filesystem.
|
|
[[nodiscard]] bool preopen_dir(const std::string &path,
|
|
const std::string &guest_path) {
|
|
return wasi_config_preopen_dir(ptr.get(), path.c_str(), guest_path.c_str());
|
|
}
|
|
};
|
|
|
|
class Caller;
|
|
|
|
/**
|
|
* \brief Owner of all WebAssembly objects
|
|
*
|
|
* A `Store` owns all WebAssembly objects such as instances, globals, functions,
|
|
* memories, etc. A `Store` is one of the main central points about working with
|
|
* WebAssembly since it's an argument to almost all APIs. The `Store` serves as
|
|
* a form of "context" to give meaning to the pointers of `Func` and friends.
|
|
*
|
|
* A `Store` can be sent between threads but it cannot generally be shared
|
|
* concurrently between threads. Memory associated with WebAssembly instances
|
|
* will be deallocated when the `Store` is deallocated.
|
|
*/
|
|
class Store {
|
|
struct deleter {
|
|
void operator()(wasmtime_store_t *p) const { wasmtime_store_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasmtime_store_t, deleter> ptr;
|
|
|
|
public:
|
|
/// Creates a new `Store` within the provided `Engine`.
|
|
explicit Store(Engine &engine)
|
|
: ptr(wasmtime_store_new(engine.ptr.get(), nullptr, nullptr)) {}
|
|
|
|
/**
|
|
* \brief An interior pointer into a `Store`.
|
|
*
|
|
* A `Context` object is created from either a `Store` or a `Caller`. It is an
|
|
* interior pointer into a `Store` and cannot be used outside the lifetime of
|
|
* the original object it was created from.
|
|
*
|
|
* This object is an argument to most APIs in Wasmtime but typically doesn't
|
|
* need to be constructed explicitly since it can be created from a `Store&`
|
|
* or a `Caller&`.
|
|
*/
|
|
class Context {
|
|
friend class Global;
|
|
friend class Table;
|
|
friend class Memory;
|
|
friend class Func;
|
|
friend class Instance;
|
|
friend class Linker;
|
|
wasmtime_context_t *ptr;
|
|
|
|
Context(wasmtime_context_t *ptr) : ptr(ptr) {}
|
|
|
|
public:
|
|
/// Creates a context referencing the provided `Store`.
|
|
Context(Store &store) : Context(wasmtime_store_context(store.ptr.get())) {}
|
|
/// Creates a context referencing the provided `Store`.
|
|
Context(Store *store) : Context(*store) {}
|
|
/// Creates a context referencing the provided `Caller`.
|
|
Context(Caller &caller);
|
|
/// Creates a context referencing the provided `Caller`.
|
|
Context(Caller *caller);
|
|
|
|
/// Runs a garbage collection pass in the referenced store to collect loose
|
|
/// `externref` values, if any are available.
|
|
void gc() { wasmtime_context_gc(ptr); }
|
|
|
|
/// Injects fuel to be consumed within this store.
|
|
///
|
|
/// Stores start with 0 fuel and if `Config::consume_fuel` is enabled then
|
|
/// this is required if you want to let WebAssembly actually execute.
|
|
///
|
|
/// Returns an error if fuel consumption isn't enabled.
|
|
[[nodiscard]] Result<std::monostate> add_fuel(uint64_t fuel) {
|
|
auto *error = wasmtime_context_add_fuel(ptr, fuel);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// Returns the amount of fuel consumed so far by executing WebAssembly.
|
|
///
|
|
/// Returns `std::nullopt` if fuel consumption is not enabled.
|
|
std::optional<uint64_t> fuel_consumed() const {
|
|
uint64_t fuel = 0;
|
|
if (wasmtime_context_fuel_consumed(ptr, &fuel)) {
|
|
return fuel;
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Configures the WASI state used by this store.
|
|
///
|
|
/// This will only have an effect if used in conjunction with
|
|
/// `Linker::define_wasi` because otherwise no host functions will use the
|
|
/// WASI state.
|
|
[[nodiscard]] Result<std::monostate> set_wasi(WasiConfig config) {
|
|
auto *error = wasmtime_context_set_wasi(ptr, config.ptr.release());
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// Returns a handle, which can be sent to another thread, which can be used
|
|
/// to interrupt execution of WebAssembly within this `Store`.
|
|
///
|
|
/// This requires `Config::interruptable` to be enabled to retun a handle.
|
|
std::optional<InterruptHandle> interrupt_handle() {
|
|
auto *handle = wasmtime_interrupt_handle_new(ptr);
|
|
if (handle != nullptr) {
|
|
return InterruptHandle(handle);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
};
|
|
|
|
/// Explicit function to acquire a `Context` from this store.
|
|
Context context() { return this; }
|
|
};
|
|
|
|
/**
|
|
* \brief Representation of a WebAssembly `externref` value.
|
|
*
|
|
* This class represents an value that cannot be forged by WebAssembly itself.
|
|
* All `ExternRef` values are guaranteed to be created by the host and its
|
|
* embedding. It's suitable to place private data structures in here which
|
|
* WebAssembly will not have access to, only other host functions will have
|
|
* access to them.
|
|
*/
|
|
class ExternRef {
|
|
friend class Val;
|
|
|
|
struct deleter {
|
|
void operator()(wasmtime_externref_t *p) const {
|
|
wasmtime_externref_delete(p);
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<wasmtime_externref_t, deleter> ptr;
|
|
|
|
static void finalizer(void *ptr) {
|
|
std::unique_ptr<std::any> _ptr(static_cast<std::any *>(ptr));
|
|
}
|
|
|
|
ExternRef(wasmtime_externref_t *ptr) : ptr(ptr) {}
|
|
|
|
public:
|
|
/// Creates a new `externref` value from the provided argument.
|
|
///
|
|
/// Note that `val` should be safe to send across threads and should own any
|
|
/// memory that it points to. Also note that `ExternRef` is similar to a
|
|
/// `std::shared_ptr` in that there can be many references to the same value.
|
|
explicit ExternRef(std::any val)
|
|
: ExternRef(wasmtime_externref_new(
|
|
std::make_unique<std::any>(std::move(val)).release(), finalizer)) {}
|
|
/// Performs a shallow copy of another `externref` value, creating another
|
|
/// reference to it.
|
|
ExternRef(const ExternRef &other)
|
|
: ExternRef(wasmtime_externref_clone(other.ptr.get())) {}
|
|
/// Performs a shallow copy of another `externref` value, creating another
|
|
/// reference to it.
|
|
ExternRef &operator=(const ExternRef &other) {
|
|
ptr.reset(wasmtime_externref_clone(other.ptr.get()));
|
|
return *this;
|
|
}
|
|
/// Moves the resources pointed to by `other` into `this`.
|
|
ExternRef(ExternRef &&other) = default;
|
|
/// Moves the resources pointed to by `other` into `this`.
|
|
ExternRef &operator=(ExternRef &&other) = default;
|
|
~ExternRef() = default;
|
|
|
|
/// Returns the underlying host data associated with this `ExternRef`.
|
|
std::any &data() {
|
|
return *static_cast<std::any *>(wasmtime_externref_data(ptr.get()));
|
|
}
|
|
};
|
|
|
|
class Func;
|
|
class Global;
|
|
class Instance;
|
|
class Memory;
|
|
class Table;
|
|
|
|
/// \typedef Extern
|
|
/// \brief Representation of an external WebAssembly item
|
|
typedef std::variant<Instance, Module, Func, Global, Memory, Table> Extern;
|
|
|
|
/**
|
|
* \brief Representation of a generic WebAssembly value.
|
|
*
|
|
* This is roughly equivalent to a tagged union of all possible WebAssembly
|
|
* values. This is later used as an argument with functions, globals, tables,
|
|
* etc.
|
|
*/
|
|
class Val {
|
|
friend class Global;
|
|
friend class Table;
|
|
friend class Func;
|
|
|
|
wasmtime_val_t val;
|
|
|
|
Val() : val{} {
|
|
val.kind = WASMTIME_I32;
|
|
val.of.i32 = 0;
|
|
}
|
|
Val(wasmtime_val_t val) : val(val) {}
|
|
|
|
public:
|
|
/// Creates a new `i32` WebAssembly value.
|
|
Val(int32_t i32) : val{} {
|
|
val.kind = WASMTIME_I32;
|
|
val.of.i32 = i32;
|
|
}
|
|
/// Creates a new `i64` WebAssembly value.
|
|
Val(int64_t i64) : val{} {
|
|
val.kind = WASMTIME_I64;
|
|
val.of.i64 = i64;
|
|
}
|
|
/// Creates a new `f32` WebAssembly value.
|
|
Val(float f32) : val{} {
|
|
val.kind = WASMTIME_F32;
|
|
val.of.f32 = f32;
|
|
}
|
|
/// Creates a new `f64` WebAssembly value.
|
|
Val(double f64) : val{} {
|
|
val.kind = WASMTIME_F64;
|
|
val.of.f64 = f64;
|
|
}
|
|
/// Creates a new `v128` WebAssembly value.
|
|
Val(const wasmtime_v128 &v128) : val{} {
|
|
val.kind = WASMTIME_V128;
|
|
val.of.i32 = 0;
|
|
memcpy(&val.of.v128[0], &v128[0], sizeof(wasmtime_v128));
|
|
}
|
|
/// Creates a new `funcref` WebAssembly value.
|
|
Val(std::optional<Func> func);
|
|
/// Creates a new `funcref` WebAssembly value which is not `ref.null func`.
|
|
Val(Func func);
|
|
/// Creates a new `externref` value.
|
|
Val(std::optional<ExternRef> ptr) : val{} {
|
|
val.kind = WASMTIME_EXTERNREF;
|
|
val.of.externref = nullptr;
|
|
if (ptr) {
|
|
val.of.externref = ptr->ptr.release();
|
|
}
|
|
}
|
|
/// Creates a new `externref` WebAssembly value which is not `ref.null
|
|
/// extern`.
|
|
Val(ExternRef ptr);
|
|
/// Copies the contents of another value into this one.
|
|
Val(const Val &other) : val{} {
|
|
val.kind = WASMTIME_I32;
|
|
val.of.i32 = 0;
|
|
wasmtime_val_copy(&val, &other.val);
|
|
}
|
|
/// Moves the resources from another value into this one.
|
|
Val(Val &&other) noexcept : val{} {
|
|
val.kind = WASMTIME_I32;
|
|
val.of.i32 = 0;
|
|
std::swap(val, other.val);
|
|
}
|
|
|
|
~Val() {
|
|
if (val.kind == WASMTIME_EXTERNREF && val.of.externref != nullptr) {
|
|
wasmtime_externref_delete(val.of.externref);
|
|
}
|
|
}
|
|
|
|
/// Copies the contents of another value into this one.
|
|
Val &operator=(const Val &other) noexcept {
|
|
if (val.kind == WASMTIME_EXTERNREF && val.of.externref != nullptr) {
|
|
wasmtime_externref_delete(val.of.externref);
|
|
}
|
|
wasmtime_val_copy(&val, &other.val);
|
|
return *this;
|
|
}
|
|
/// Moves the resources from another value into this one.
|
|
Val &operator=(Val &&other) noexcept {
|
|
std::swap(val, other.val);
|
|
return *this;
|
|
}
|
|
|
|
/// Returns the kind of value that this value has.
|
|
ValKind kind() const {
|
|
switch (val.kind) {
|
|
case WASMTIME_I32:
|
|
return ValKind::I32;
|
|
case WASMTIME_I64:
|
|
return ValKind::I64;
|
|
case WASMTIME_F32:
|
|
return ValKind::F32;
|
|
case WASMTIME_F64:
|
|
return ValKind::F64;
|
|
case WASMTIME_FUNCREF:
|
|
return ValKind::FuncRef;
|
|
case WASMTIME_EXTERNREF:
|
|
return ValKind::ExternRef;
|
|
case WASMTIME_V128:
|
|
return ValKind::V128;
|
|
}
|
|
std::abort();
|
|
}
|
|
|
|
/// Returns the underlying `i32`, requires `kind() == KindI32` or aborts the
|
|
/// process.
|
|
int32_t i32() const {
|
|
if (val.kind != WASMTIME_I32) {
|
|
std::abort();
|
|
}
|
|
return val.of.i32;
|
|
}
|
|
|
|
/// Returns the underlying `i64`, requires `kind() == KindI64` or aborts the
|
|
/// process.
|
|
int64_t i64() const {
|
|
if (val.kind != WASMTIME_I64) {
|
|
std::abort();
|
|
}
|
|
return val.of.i64;
|
|
}
|
|
|
|
/// Returns the underlying `f32`, requires `kind() == KindF32` or aborts the
|
|
/// process.
|
|
float f32() const {
|
|
if (val.kind != WASMTIME_F32) {
|
|
std::abort();
|
|
}
|
|
return val.of.f32;
|
|
}
|
|
|
|
/// Returns the underlying `f64`, requires `kind() == KindF64` or aborts the
|
|
/// process.
|
|
double f64() const {
|
|
if (val.kind != WASMTIME_F64) {
|
|
std::abort();
|
|
}
|
|
return val.of.f64;
|
|
}
|
|
|
|
/// Returns the underlying `v128`, requires `kind() == KindV128` or aborts
|
|
/// the process.
|
|
const wasmtime_v128 &v128() const {
|
|
if (val.kind != WASMTIME_V128) {
|
|
std::abort();
|
|
}
|
|
return val.of.v128;
|
|
}
|
|
|
|
/// Returns the underlying `externref`, requires `kind() == KindExternRef` or
|
|
/// aborts the process.
|
|
///
|
|
/// Note that `externref` is a nullable reference, hence the `optional` return
|
|
/// value.
|
|
std::optional<ExternRef> externref() const {
|
|
if (val.kind != WASMTIME_EXTERNREF) {
|
|
std::abort();
|
|
}
|
|
if (val.of.externref != nullptr) {
|
|
return ExternRef(wasmtime_externref_clone(val.of.externref));
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Returns the underlying `funcref`, requires `kind() == KindFuncRef` or
|
|
/// aborts the process.
|
|
///
|
|
/// Note that `funcref` is a nullable reference, hence the `optional` return
|
|
/// value.
|
|
std::optional<Func> funcref() const;
|
|
};
|
|
|
|
/**
|
|
* \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; }
|
|
};
|
|
|
|
inline Store::Context::Context(Caller &caller)
|
|
: Context(wasmtime_caller_context(caller.ptr)) {}
|
|
inline Store::Context::Context(Caller *caller) : Context(*caller) {}
|
|
|
|
/**
|
|
* \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;
|
|
|
|
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) {
|
|
F *func = reinterpret_cast<F *>(env); // NOLINT
|
|
Span<const Val> args_span(reinterpret_cast<const Val *>(args), // NOLINT
|
|
nargs);
|
|
Span<Val> results_span(reinterpret_cast<Val *>(results), // NOLINT
|
|
nresults);
|
|
Result<std::monostate, Trap> result =
|
|
(*func)(Caller(caller), args_span, results_span);
|
|
if (!result) {
|
|
return result.err().ptr.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.
|
|
*
|
|
* \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>
|
|
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 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.
|
|
*/
|
|
[[nodiscard]] TrapResult<std::vector<Val>>
|
|
call(Store::Context cx, const std::vector<Val> ¶ms) const {
|
|
std::vector<wasmtime_val_t> raw_params;
|
|
raw_params.reserve(params.size());
|
|
for (const auto ¶m : params) {
|
|
raw_params.push_back(param.val);
|
|
}
|
|
size_t nresults = this->type(cx)->results().size();
|
|
std::vector<wasmtime_val_t> raw_results(nresults);
|
|
|
|
wasm_trap_t *trap = nullptr;
|
|
auto *error =
|
|
wasmtime_func_call(cx.ptr, &func, raw_params.data(), raw_params.size(),
|
|
raw_results.data(), raw_results.capacity(), &trap);
|
|
if (error != nullptr) {
|
|
return TrapError(Error(error));
|
|
}
|
|
if (trap != nullptr) {
|
|
return TrapError(Trap(trap));
|
|
}
|
|
|
|
std::vector<Val> results;
|
|
results.reserve(nresults);
|
|
for (size_t i = 0; i < nresults; i++) {
|
|
results.push_back(raw_results[i]);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
/// Returns the type of this function.
|
|
FuncType type(Store::Context cx) const {
|
|
return wasmtime_func_type(cx.ptr, &func);
|
|
}
|
|
};
|
|
|
|
inline Val::Val(std::optional<Func> func) : val{} {
|
|
val.kind = WASMTIME_FUNCREF;
|
|
val.of.funcref.store_id = 0;
|
|
val.of.funcref.index = 0;
|
|
if (func) {
|
|
val.of.funcref = (*func).func;
|
|
}
|
|
}
|
|
|
|
inline Val::Val(Func func) : Val(std::optional(func)) {}
|
|
inline Val::Val(ExternRef ptr) : Val(std::optional(ptr)) {}
|
|
|
|
inline std::optional<Func> Val::funcref() const {
|
|
if (val.kind != WASMTIME_FUNCREF) {
|
|
std::abort();
|
|
}
|
|
if (val.of.funcref.store_id == 0) {
|
|
return std::nullopt;
|
|
}
|
|
return Func(val.of.funcref);
|
|
}
|
|
|
|
/**
|
|
* \brief A WebAssembly global.
|
|
*
|
|
* This class represents a WebAssembly global, either created through
|
|
* instantiating a module or a host global. Globals contain a WebAssembly value
|
|
* and can be read and optionally written to.
|
|
*
|
|
* 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 `Global`. Note that if the wrong `Store`
|
|
* is passed in then the process will be aborted.
|
|
*/
|
|
class Global {
|
|
friend class Instance;
|
|
wasmtime_global_t global;
|
|
|
|
public:
|
|
/// Creates as global from the raw underlying C API representation.
|
|
Global(wasmtime_global_t global) : global(global) {}
|
|
|
|
/**
|
|
* \brief Create a new WebAssembly global.
|
|
*
|
|
* \param cx the store in which to create the global
|
|
* \param ty the type that this global will have
|
|
* \param init the initial value of the global
|
|
*
|
|
* This function can fail if `init` does not have a value that matches `ty`.
|
|
*/
|
|
[[nodiscard]] static Result<Global>
|
|
create(Store::Context cx, const GlobalType &ty, const Val &init) {
|
|
wasmtime_global_t global;
|
|
auto *error = wasmtime_global_new(cx.ptr, ty.ptr.get(), &init.val, &global);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return Global(global);
|
|
}
|
|
|
|
/// Returns the type of this global.
|
|
GlobalType type(Store::Context cx) const {
|
|
return wasmtime_global_type(cx.ptr, &global);
|
|
}
|
|
|
|
/// Returns the current value of this global.
|
|
Val get(Store::Context cx) const {
|
|
Val val;
|
|
wasmtime_global_get(cx.ptr, &global, &val.val);
|
|
return val;
|
|
}
|
|
|
|
/// Sets this global to a new value.
|
|
///
|
|
/// This can fail if `val` has the wrong type or if this global isn't mutable.
|
|
[[nodiscard]] Result<std::monostate> set(Store::Context cx,
|
|
const Val &val) const {
|
|
auto *error = wasmtime_global_set(cx.ptr, &global, &val.val);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief A WebAssembly table.
|
|
*
|
|
* This class represents a WebAssembly table, either created through
|
|
* instantiating a module or a host table. Tables are contiguous vectors of
|
|
* WebAssembly reference types, currently either `externref` or `funcref`.
|
|
*
|
|
* 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 `Table`. Note that if the wrong `Store`
|
|
* is passed in then the process will be aborted.
|
|
*/
|
|
class Table {
|
|
friend class Instance;
|
|
wasmtime_table_t table;
|
|
|
|
public:
|
|
/// Creates a new table from the raw underlying C API representation.
|
|
Table(wasmtime_table_t table) : table(table) {}
|
|
|
|
/**
|
|
* \brief Creates a new host-defined table.
|
|
*
|
|
* \param cx the store in which to create the table.
|
|
* \param ty the type of the table to be created
|
|
* \param init the initial value for all table slots.
|
|
*
|
|
* Returns an error if `init` has the wrong value for the `ty` specified.
|
|
*/
|
|
[[nodiscard]] static Result<Table>
|
|
create(Store::Context cx, const TableType &ty, const Val &init) {
|
|
wasmtime_table_t table;
|
|
auto *error = wasmtime_table_new(cx.ptr, ty.ptr.get(), &init.val, &table);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return Table(table);
|
|
}
|
|
|
|
/// Returns the type of this table.
|
|
TableType type(Store::Context cx) const {
|
|
return wasmtime_table_type(cx.ptr, &table);
|
|
}
|
|
|
|
/// Returns the size, in elements, that the table currently has.
|
|
size_t size(Store::Context cx) const {
|
|
return wasmtime_table_size(cx.ptr, &table);
|
|
}
|
|
|
|
/// Loads a value from the specified index in this table.
|
|
///
|
|
/// Returns `std::nullopt` if `idx` is out of bounds.
|
|
std::optional<Val> get(Store::Context cx, uint32_t idx) const {
|
|
Val val;
|
|
if (wasmtime_table_get(cx.ptr, &table, idx, &val.val)) {
|
|
return val;
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Stores a value into the specified index in this table.
|
|
///
|
|
/// Returns an error if `idx` is out of bounds or if `val` has the wrong type.
|
|
[[nodiscard]] Result<std::monostate> set(Store::Context cx, uint32_t idx,
|
|
const Val &val) const {
|
|
auto *error = wasmtime_table_set(cx.ptr, &table, idx, &val.val);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// Grow this table.
|
|
///
|
|
/// \param cx the store that owns this table.
|
|
/// \param delta the number of new elements to be added to this table.
|
|
/// \param init the initial value of all new elements in this table.
|
|
///
|
|
/// Returns an error if `init` has the wrong type for this table. Otherwise
|
|
/// returns the previous size of the table before growth.
|
|
[[nodiscard]] Result<uint32_t> grow(Store::Context cx, uint32_t delta,
|
|
const Val &init) const {
|
|
uint32_t prev = 0;
|
|
auto *error = wasmtime_table_grow(cx.ptr, &table, delta, &init.val, &prev);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return prev;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief A WebAssembly linear memory.
|
|
*
|
|
* This class represents a WebAssembly memory, either created through
|
|
* instantiating a module or a host memory.
|
|
*
|
|
* 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 `Table`. Note that if the wrong `Store`
|
|
* is passed in then the process will be aborted.
|
|
*/
|
|
class Memory {
|
|
friend class Instance;
|
|
wasmtime_memory_t memory;
|
|
|
|
public:
|
|
/// Creates a new memory from the raw underlying C API representation.
|
|
Memory(wasmtime_memory_t memory) : memory(memory) {}
|
|
|
|
/// Creates a new host-defined memory with the type specified.
|
|
[[nodiscard]] static Result<Memory> create(Store::Context cx,
|
|
const MemoryType &ty) {
|
|
wasmtime_memory_t memory;
|
|
auto *error = wasmtime_memory_new(cx.ptr, ty.ptr.get(), &memory);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return Memory(memory);
|
|
}
|
|
|
|
/// Returns the type of this memory.
|
|
MemoryType type(Store::Context cx) const {
|
|
return wasmtime_memory_type(cx.ptr, &memory);
|
|
}
|
|
|
|
/// Returns the size, in WebAssembly pages, of this memory.
|
|
uint32_t size(Store::Context cx) const {
|
|
return wasmtime_memory_size(cx.ptr, &memory);
|
|
}
|
|
|
|
/// Returns a `span` of where this memory is located in the host.
|
|
///
|
|
/// Note that embedders need to be very careful in their usage of the returned
|
|
/// `span`. It can be invalidated with calls to `grow` and/or calls into
|
|
/// WebAssembly.
|
|
Span<uint8_t> data(Store::Context cx) const {
|
|
auto *base = wasmtime_memory_data(cx.ptr, &memory);
|
|
auto size = wasmtime_memory_data_size(cx.ptr, &memory);
|
|
return {base, size};
|
|
}
|
|
|
|
/// Grows the memory by `delta` WebAssembly pages.
|
|
///
|
|
/// On success returns the previous size of this memory in units of
|
|
/// WebAssembly pages.
|
|
[[nodiscard]] Result<uint32_t> grow(Store::Context cx, uint32_t delta) const {
|
|
uint32_t prev = 0;
|
|
auto *error = wasmtime_memory_grow(cx.ptr, &memory, delta, &prev);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return prev;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief A WebAssembly instance.
|
|
*
|
|
* This class represents a WebAssembly instance, created by instantiating a
|
|
* module. An instance is the collection of items exported by the module, which
|
|
* can be accessed through the `Store` that owns the instance.
|
|
*
|
|
* 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 `Instance`. Note that if the wrong
|
|
* `Store` is passed in then the process will be aborted.
|
|
*/
|
|
class Instance {
|
|
friend class Linker;
|
|
friend class Caller;
|
|
|
|
wasmtime_instance_t instance;
|
|
|
|
static Extern cvt(wasmtime_extern_t &e) {
|
|
switch (e.kind) {
|
|
case WASMTIME_EXTERN_FUNC:
|
|
return Func(e.of.func);
|
|
case WASMTIME_EXTERN_GLOBAL:
|
|
return Global(e.of.global);
|
|
case WASMTIME_EXTERN_MEMORY:
|
|
return Memory(e.of.memory);
|
|
case WASMTIME_EXTERN_TABLE:
|
|
return Table(e.of.table);
|
|
case WASMTIME_EXTERN_INSTANCE:
|
|
return Instance(e.of.instance);
|
|
case WASMTIME_EXTERN_MODULE:
|
|
return Module(e.of.module);
|
|
}
|
|
std::abort();
|
|
}
|
|
|
|
static void cvt(const Extern &e, wasmtime_extern_t &raw) {
|
|
if (const auto *func = std::get_if<Func>(&e)) {
|
|
raw.kind = WASMTIME_EXTERN_FUNC;
|
|
raw.of.func = func->func;
|
|
} else if (const auto *global = std::get_if<Global>(&e)) {
|
|
raw.kind = WASMTIME_EXTERN_GLOBAL;
|
|
raw.of.global = global->global;
|
|
} else if (const auto *table = std::get_if<Table>(&e)) {
|
|
raw.kind = WASMTIME_EXTERN_TABLE;
|
|
raw.of.table = table->table;
|
|
} else if (const auto *memory = std::get_if<Memory>(&e)) {
|
|
raw.kind = WASMTIME_EXTERN_MEMORY;
|
|
raw.of.memory = memory->memory;
|
|
} else if (const auto *instance = std::get_if<Instance>(&e)) {
|
|
raw.kind = WASMTIME_EXTERN_INSTANCE;
|
|
raw.of.instance = instance->instance;
|
|
} else if (const auto *module = std::get_if<Module>(&e)) {
|
|
raw.kind = WASMTIME_EXTERN_MODULE;
|
|
raw.of.module = module->ptr.get();
|
|
} else {
|
|
std::abort();
|
|
}
|
|
}
|
|
|
|
public:
|
|
/// Creates a new instance from the raw underlying C API representation.
|
|
Instance(wasmtime_instance_t instance) : instance(instance) {}
|
|
|
|
/**
|
|
* \brief Instantiates the module `m` with the provided `imports`
|
|
*
|
|
* \param cx the store in which to instantiate the provided module
|
|
* \param m the module to instantiate
|
|
* \param imports the list of imports to use to instantiate the module
|
|
*
|
|
* This `imports` parameter is expected to line up 1:1 with the imports
|
|
* required by the `m`. The type of `m` can be inspected to determine in which
|
|
* order to provide the imports. Note that this is a relatively low-level API
|
|
* and it's generally recommended to use `Linker` instead for name-based
|
|
* instantiation.
|
|
*
|
|
* This function can return an error if any of the `imports` have the wrong
|
|
* type, or if the wrong number of `imports` is provided.
|
|
*/
|
|
[[nodiscard]] static TrapResult<Instance>
|
|
create(Store::Context cx, const Module &m,
|
|
const std::vector<Extern> &imports) {
|
|
std::vector<wasmtime_extern_t> raw_imports;
|
|
for (const auto &item : imports) {
|
|
raw_imports.push_back(wasmtime_extern_t{});
|
|
auto &last = raw_imports.back();
|
|
Instance::cvt(item, last);
|
|
}
|
|
wasmtime_instance_t instance;
|
|
wasm_trap_t *trap = nullptr;
|
|
auto *error = wasmtime_instance_new(cx.ptr, m.ptr.get(), raw_imports.data(),
|
|
raw_imports.size(), &instance, &trap);
|
|
if (error != nullptr) {
|
|
return TrapError(Error(error));
|
|
}
|
|
if (trap != nullptr) {
|
|
return TrapError(Trap(trap));
|
|
}
|
|
return Instance(instance);
|
|
}
|
|
|
|
/// Returns the type of this instance.
|
|
InstanceType type(Store::Context cx) const {
|
|
return wasmtime_instance_type(cx.ptr, &instance);
|
|
}
|
|
|
|
/**
|
|
* \brief Load an instance's export by name.
|
|
*
|
|
* This function will look for an export named `name` on this instance and, if
|
|
* found, return it as an `Extern`.
|
|
*/
|
|
std::optional<Extern> get(Store::Context cx, std::string_view name) {
|
|
wasmtime_extern_t e;
|
|
if (!wasmtime_instance_export_get(cx.ptr, &instance, name.data(),
|
|
name.size(), &e)) {
|
|
return std::nullopt;
|
|
}
|
|
return Instance::cvt(e);
|
|
}
|
|
|
|
/**
|
|
* \brief Load an instance's export by index.
|
|
*
|
|
* This function will look for the `idx`th export of this instance. This will
|
|
* return both the name of the export as well as the exported item itself.
|
|
*/
|
|
std::optional<std::pair<std::string_view, Extern>> get(Store::Context cx,
|
|
size_t idx) {
|
|
wasmtime_extern_t e;
|
|
// I'm not sure why clang-tidy thinks this is using va_list or anything
|
|
// related to that...
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
|
char *name = nullptr;
|
|
size_t len = 0;
|
|
if (!wasmtime_instance_export_nth(cx.ptr, &instance, idx, &name, &len,
|
|
&e)) {
|
|
return std::nullopt;
|
|
}
|
|
std::string_view n(name, len);
|
|
return std::pair(n, Instance::cvt(e));
|
|
}
|
|
};
|
|
|
|
inline std::optional<Extern> Caller::get_export(std::string_view name) {
|
|
wasmtime_extern_t item;
|
|
if (wasmtime_caller_export_get(ptr, name.data(), name.size(), &item)) {
|
|
return Instance::cvt(item);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* \brief Helper class for linking modules together with name-based resolution.
|
|
*
|
|
* This class is used for easily instantiating `Module`s by defining names into
|
|
* the linker and performing name-based resolution during instantiation. A
|
|
* `Linker` can also be used to link in WASI functions to instantiate a module.
|
|
*/
|
|
class Linker {
|
|
struct deleter {
|
|
void operator()(wasmtime_linker_t *p) const { wasmtime_linker_delete(p); }
|
|
};
|
|
|
|
std::unique_ptr<wasmtime_linker_t, deleter> ptr;
|
|
|
|
public:
|
|
/// Creates a new linker which will instantiate in the given engine.
|
|
explicit Linker(Engine &engine)
|
|
: ptr(wasmtime_linker_new(engine.ptr.get())) {}
|
|
|
|
/// Configures whether shadowing previous names is allowed or not.
|
|
///
|
|
/// By default shadowing is not allowed.
|
|
void allow_shadowing(bool allow) {
|
|
wasmtime_linker_allow_shadowing(ptr.get(), allow);
|
|
}
|
|
|
|
/// Defines the provided item into this linker with the given name.
|
|
[[nodiscard]] Result<std::monostate>
|
|
define(std::string_view module, std::string_view name, const Extern &item) {
|
|
wasmtime_extern_t raw;
|
|
Instance::cvt(item, raw);
|
|
auto *error =
|
|
wasmtime_linker_define(ptr.get(), module.data(), module.size(),
|
|
name.data(), name.size(), &raw);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// Defines WASI functions within this linker.
|
|
///
|
|
/// Note that `Store::Context::set_wasi` must also be used for instantiated
|
|
/// modules to have access to configured WASI state.
|
|
[[nodiscard]] Result<std::monostate> define_wasi() {
|
|
auto *error = wasmtime_linker_define_wasi(ptr.get());
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// Defines all exports of the `instance` provided in this linker with the
|
|
/// given module name of `name`.
|
|
[[nodiscard]] Result<std::monostate>
|
|
define_instance(Store::Context cx, std::string_view name, Instance instance) {
|
|
auto *error = wasmtime_linker_define_instance(
|
|
ptr.get(), cx.ptr, name.data(), name.size(), &instance.instance);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// Instantiates the module `m` provided within the store `cx` using the items
|
|
/// defined within this linker.
|
|
[[nodiscard]] TrapResult<Instance> instantiate(Store::Context cx,
|
|
const Module &m) {
|
|
wasmtime_instance_t instance;
|
|
wasm_trap_t *trap = nullptr;
|
|
auto *error = wasmtime_linker_instantiate(ptr.get(), cx.ptr, m.ptr.get(),
|
|
&instance, &trap);
|
|
if (error != nullptr) {
|
|
return TrapError(Error(error));
|
|
}
|
|
if (trap != nullptr) {
|
|
return TrapError(Trap(trap));
|
|
}
|
|
return Instance(instance);
|
|
}
|
|
|
|
/// Defines instantiations of the module `m` within this linker under the
|
|
/// given `name`.
|
|
[[nodiscard]] Result<std::monostate>
|
|
module(Store::Context cx, std::string_view name, const Module &m) {
|
|
auto *error = wasmtime_linker_module(ptr.get(), cx.ptr, name.data(),
|
|
name.size(), m.ptr.get());
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return std::monostate();
|
|
}
|
|
|
|
/// Attempts to load the specified named item from this linker, returning
|
|
/// `std::nullopt` if it was not defiend.
|
|
[[nodiscard]] std::optional<Extern>
|
|
get(Store::Context cx, std::string_view module, std::string_view name) {
|
|
wasmtime_extern_t item;
|
|
if (wasmtime_linker_get(ptr.get(), cx.ptr, module.data(), module.size(),
|
|
name.data(), name.size(), &item)) {
|
|
return Instance::cvt(item);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Loads the "default" function, according to WASI commands and reactors, of
|
|
/// the module named `name` in this linker.
|
|
[[nodiscard]] Result<Func> get_default(Store::Context cx,
|
|
std::string_view name) {
|
|
wasmtime_func_t item;
|
|
auto *error = wasmtime_linker_get_default(ptr.get(), cx.ptr, name.data(),
|
|
name.size(), &item);
|
|
if (error != nullptr) {
|
|
return Error(error);
|
|
}
|
|
return Func(item);
|
|
}
|
|
};
|
|
|
|
} // namespace wasmtime
|
|
|
|
#endif // WASMTIME_HH
|