diff options
author | Ben Smith <binji@chromium.org> | 2020-02-21 14:11:44 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-21 14:11:44 -0800 |
commit | 24a12ecfdde0246527506c87bd82460beb761c57 (patch) | |
tree | 242550e84d516926a71bef00342f4f57d011d4f6 /src/interp/interp-wasm-c-api.cc | |
parent | bb4b65186668ff3ebd2f088778337608969a9567 (diff) | |
download | wabt-24a12ecfdde0246527506c87bd82460beb761c57.tar.gz wabt-24a12ecfdde0246527506c87bd82460beb761c57.tar.bz2 wabt-24a12ecfdde0246527506c87bd82460beb761c57.zip |
New interpreter (#1330)
It's modeled closely on the wasm-c-api. All runtime objects are
garbage-collected. The GC'd objects are subclasses of `Object` and all
stored in the `Store`. GC roots can be created using a RefPtr<T> struct.
The `Module` stores no runtime objects, only description structs (named
`*Desc`, e.g. `FuncDesc`). Instantiation takes these descriptors and
turns them into runtime objects (e.g. `FuncDesc` is used to create a
`Func`). Only import-matching occurs during instantiation; all other
validation is assumed to have occurred during Module compilation.
As with the previous interpreter, the wasm instructions are not executed
directly, and instead compiled to an instruction stream that is easier
to interpret (e.g. all branches become gotos). It's still a stack
machine, though.
The previous interpreter would always compile and instantiate in one
step, which means that it was always known whether an imported function
is a host function or wasm function. As a result, calls between modules
that stayed in wasm could be very cheap (just update PC). Now that the
module is compiled before instantiation, an imported function call
always has to check first, which may be a slight performance hit.
One major difference to the structure of the interpreter is that
floating-point values are passed directly, instead of using their
equivalent bit pattern. This is more convenient in general, but requires
annotating all functions with WABT_VECTORCALL so Visual Studio x86 works
properly (otherwise floats are passed in the x87 FP stack).
Instruction stream decoding/tracing/disassembling is now all handled in
the `Istream` class. This reduces a lot of duplication between the
three, which makes the logging-all-opcodes and tracing-all-opcodes less
valuable, so I've removed them.
Here are the changes to files:
binary-reader-metadata.{h,cc} -> [removed]
interp-{disassemble.trace}.cc -> istream.{h,cc}
There are new helper files:
interp-util.{h,cc}: Primarily print debugging functions
interp-math.h: Templates used for handling wasm math
Diffstat (limited to 'src/interp/interp-wasm-c-api.cc')
-rw-r--r-- | src/interp/interp-wasm-c-api.cc | 1571 |
1 files changed, 690 insertions, 881 deletions
diff --git a/src/interp/interp-wasm-c-api.cc b/src/interp/interp-wasm-c-api.cc index d5ff9ae3..111df5ab 100644 --- a/src/interp/interp-wasm-c-api.cc +++ b/src/interp/interp-wasm-c-api.cc @@ -17,564 +17,487 @@ #include <wasm.h> #include "src/binary-reader.h" +#include "src/cast.h" #include "src/error-formatter.h" -#include "src/error.h" #include "src/interp/binary-reader-interp.h" -#include "src/interp/binary-reader-metadata.h" +#include "src/interp/interp-util.h" #include "src/interp/interp.h" -#include "src/ir.h" -#include "src/stream.h" using namespace wabt; using namespace wabt::interp; +#define own + #ifndef NDEBUG -#define TRACE(str, ...) fprintf(stderr, "CAPI: " str, ##__VA_ARGS__) +#define TRACE0() TRACE("") +#define TRACE(str, ...) \ + fprintf(stderr, "CAPI: [%s] " str "\n", __func__, ##__VA_ARGS__) +#define TRACE_NO_NL(str, ...) \ + fprintf(stderr, "CAPI: [%s] " str, __func__, ##__VA_ARGS__) #else +#define TRACE0(...) #define TRACE(...) +#define TRACE_NO_NL(...) #endif static Features s_features; -static Stream* s_trace_stream; -static Thread::Options s_thread_options; static std::unique_ptr<FileStream> s_log_stream; static std::unique_ptr<FileStream> s_stdout_stream; -struct wasm_valtype_t { - wasm_valkind_t kind; -}; +// Type conversion utilities +static ValueType ToWabtValueType(wasm_valkind_t); +static wasm_valkind_t FromWabtValueType(ValueType); -struct wasm_config_t {}; +static wasm_externkind_t FromWabtExternKind(ExternKind ); -struct wasm_externtype_t { - wasm_externkind_t kind; +static ValueTypes ToWabtValueTypes(const wasm_valtype_vec_t* types); +static void FromWabtValueTypes(const ValueTypes&, wasm_valtype_vec_t* out); - protected: - wasm_externtype_t(wasm_externkind_t kind) : kind(kind) {} -}; +static wasm_mutability_t FromWabtMutability(Mutability); +static Mutability ToWabtMutability(wasm_mutability_t); -struct wasm_globaltype_t : wasm_externtype_t { - wasm_globaltype_t(wasm_valtype_t type, bool mutable_) - : wasm_externtype_t(WASM_EXTERN_GLOBAL), type(type), mutable_(mutable_) {} - wasm_valtype_t type; - bool mutable_; -}; +static Limits ToWabtLimits(const wasm_limits_t&); +static wasm_limits_t FromWabtLimits(const Limits&); -struct wasm_tabletype_t : wasm_externtype_t { - wasm_tabletype_t(wasm_valtype_t elemtype, wasm_limits_t limits) - : wasm_externtype_t(WASM_EXTERN_TABLE), - elemtype(elemtype), - limits(limits) {} - wasm_valtype_t elemtype; - wasm_limits_t limits; -}; - -struct wasm_memorytype_t : wasm_externtype_t { - wasm_memorytype_t(wasm_limits_t limits) - : wasm_externtype_t(WASM_EXTERN_MEMORY), limits(limits) {} - wasm_limits_t limits; -}; +// Value conversion utilities +static TypedValue ToWabtValue(const wasm_val_t&); +static wasm_val_t FromWabtValue(Store&, const TypedValue&); -struct wasm_importtype_t {}; +static Values ToWabtValues(const wasm_val_t values[], size_t count); +static void FromWabtValues(Store& store, + wasm_val_t values[], + const ValueTypes& types, + const Values& wabt_values); -struct wasm_exporttype_t { - wasm_exporttype_t(wasm_name_t name, wasm_externtype_t* type) - : name(name), type(type) {} +// Structs +struct wasm_config_t {}; - wasm_exporttype_t(const wasm_exporttype_t& other) { - name = other.name; - type = MakeUnique<wasm_externtype_t>(*other.type.get()); - } +struct wasm_engine_t {}; - wasm_name_t name; - std::unique_ptr<wasm_externtype_t> type; +struct wasm_valtype_t { + ValueType I; }; -struct wasm_engine_t {}; - -struct wasm_store_t { - wasm_store_t(Environment* env, Executor* executor) - : env(env), executor(executor) {} +struct wasm_externtype_t { + static std::unique_ptr<wasm_externtype_t> New(std::unique_ptr<ExternType>); - ~wasm_store_t() { - TRACE("~store\n"); + std::unique_ptr<wasm_externtype_t> Clone() const { + return New(I->Clone()); } - Environment* env; - std::unique_ptr<Executor> executor; -}; + virtual ~wasm_externtype_t() {} -enum class WasmRefType { Extern, Module, Instance, Trap, Foreign }; - -std::string WasmRefTypeToString(WasmRefType t) { - switch (t) { - case WasmRefType::Extern: - return "extern"; - case WasmRefType::Module: - return "module"; - case WasmRefType::Instance: - return "instance"; - case WasmRefType::Trap: - return "trap"; - case WasmRefType::Foreign: - return "foreign"; - } - WABT_UNREACHABLE; -} - -struct wasm_ref_t { - wasm_ref_t(WasmRefType kind) : kind(kind) {} - wasm_ref_t(const wasm_ref_t& other) - : kind(other.kind), - host_info(other.host_info), - finalizer(other.finalizer) {} - - virtual ~wasm_ref_t() { - if (finalizer) { - finalizer(host_info); - } - } + wasm_externtype_t(const wasm_externtype_t& other) = delete; + wasm_externtype_t& operator=(const wasm_externtype_t& other) = delete; - virtual wasm_ref_t* Copy() const { return new wasm_ref_t(kind); } + template <typename T> + T* As() const { return cast<T>(I.get()); } - bool Same(const wasm_ref_t& other) const; + std::unique_ptr<ExternType> I; - WasmRefType kind; - void* host_info = nullptr; - void (*finalizer)(void*) = nullptr; + protected: + wasm_externtype_t(std::unique_ptr<ExternType> et) : I(std::move(et)) {} }; -struct wasm_extern_ref_t : wasm_ref_t { - wasm_extern_ref_t(ExternalKind kind, Index index) - : wasm_ref_t(WasmRefType::Extern), kind(kind), index(index) {} - - wasm_extern_ref_t(const wasm_extern_ref_t& other) - : wasm_ref_t(other), kind(other.kind), index(other.index) {} +struct wasm_functype_t : wasm_externtype_t { + wasm_functype_t(own wasm_valtype_vec_t* params, + own wasm_valtype_vec_t* results) + : wasm_externtype_t{MakeUnique<FuncType>(ToWabtValueTypes(params), + ToWabtValueTypes(results))}, + params(*params), + results(*results) {} - wasm_ref_t* Copy() const override { return new wasm_extern_ref_t(*this); } + wasm_functype_t(FuncType ft) : wasm_externtype_t{MakeUnique<FuncType>(ft)} { + FromWabtValueTypes(ft.params, ¶ms); + FromWabtValueTypes(ft.results, &results); + } - bool Same(const wasm_extern_ref_t& other) const { - return kind == other.kind && index == other.index; + ~wasm_functype_t() { + wasm_valtype_vec_delete(¶ms); + wasm_valtype_vec_delete(&results); } - ExternalKind kind; - Index index; + // Stored here because API requires returning pointers. + wasm_valtype_vec_t params; + wasm_valtype_vec_t results; }; -struct wasm_foreign_ref_t : wasm_ref_t { - wasm_foreign_ref_t(Index index) : wasm_ref_t(WasmRefType::Foreign), index(index) {} - wasm_foreign_ref_t(const wasm_foreign_ref_t& other) : wasm_ref_t(other), index(other.index) {} +struct wasm_globaltype_t : wasm_externtype_t { + wasm_globaltype_t(own wasm_valtype_t* type, wasm_mutability_t mut) + : wasm_externtype_t{MakeUnique<GlobalType>(type->I, + ToWabtMutability(mut))}, + valtype{*type} { + wasm_valtype_delete(type); + } - wasm_ref_t* Copy() const override { return new wasm_foreign_ref_t(*this); } + wasm_globaltype_t(GlobalType gt) + : wasm_externtype_t{MakeUnique<GlobalType>(gt)}, valtype{gt.type} {} - Index index; + // Stored here because API requires returning pointers. + wasm_valtype_t valtype; }; -struct wasm_foreign_t : wasm_foreign_ref_t { - wasm_foreign_t(Index index) : wasm_foreign_ref_t(index) {} - - bool Same(const wasm_foreign_t& other) const { - TRACE("wasm_foreign_t %u %u\n", index, other.index); - return index == other.index; +struct wasm_tabletype_t : wasm_externtype_t { + wasm_tabletype_t(own wasm_valtype_t* type, const wasm_limits_t* limits) + : wasm_externtype_t{MakeUnique<TableType>(type->I, + ToWabtLimits(*limits))}, + elemtype(*type), + limits(*limits) { + wasm_valtype_delete(type); } + + wasm_tabletype_t(TableType tt) + : wasm_externtype_t{MakeUnique<TableType>(tt)}, + elemtype{tt.element}, + limits{FromWabtLimits(tt.limits)} {} + + // Stored here because API requires returning pointers. + wasm_valtype_t elemtype; + wasm_limits_t limits; }; -struct WasmInstance { - WasmInstance(wasm_store_t* store, DefinedModule* module) - : store(store), module(module) {} +struct wasm_memorytype_t : wasm_externtype_t { + wasm_memorytype_t(const wasm_limits_t* limits) + : wasm_externtype_t{MakeUnique<MemoryType>(ToWabtLimits(*limits))}, + limits{*limits} {} - ~WasmInstance() { - TRACE("~WasmInstance\n"); - } + wasm_memorytype_t(MemoryType mt) + : wasm_externtype_t{MakeUnique<MemoryType>(mt)}, + limits{FromWabtLimits(mt.limits)} {} - wasm_store_t* store; - std::unique_ptr<DefinedModule> module; + // Stored here because API requires returning pointers. + wasm_limits_t limits; }; -struct wasm_instance_t : wasm_ref_t { - wasm_instance_t(wasm_store_t* store, DefinedModule* module) - : wasm_ref_t(WasmRefType::Instance), - ptr(std::make_shared<WasmInstance>(store, module)) {} +// static +std::unique_ptr<wasm_externtype_t> wasm_externtype_t::New( + std::unique_ptr<ExternType> ptr) { + switch (ptr->kind) { + case ExternKind::Func: + return MakeUnique<wasm_functype_t>(*cast<FuncType>(ptr.get())); - wasm_instance_t(std::shared_ptr<WasmInstance> ptr) - : wasm_ref_t(WasmRefType::Instance), ptr(ptr) {} + case ExternKind::Table: + return MakeUnique<wasm_tabletype_t>(*cast<TableType>(ptr.get())); - wasm_instance_t(const wasm_instance_t& other) - : wasm_ref_t(other), ptr(other.ptr) {} + case ExternKind::Memory: + return MakeUnique<wasm_memorytype_t>(*cast<MemoryType>(ptr.get())); - wasm_ref_t* Copy() const override { return new wasm_instance_t(*this); } + case ExternKind::Global: + return MakeUnique<wasm_globaltype_t>(*cast<GlobalType>(ptr.get())); - bool Same(const wasm_instance_t& other) const { return ptr == other.ptr; } + case ExternKind::Event: + break; + } - std::shared_ptr<WasmInstance> ptr; -}; + assert(false); + return {}; +} -struct wasm_module_t : wasm_ref_t { - wasm_module_t(wasm_store_t* store, - const wasm_byte_vec_t* in, - ModuleMetadata* metadata) - : wasm_ref_t(WasmRefType::Module), store(store), metadata(metadata) { - wasm_byte_vec_copy(&binary, in); - } +struct wasm_importtype_t { + ImportType I; +}; - bool Same(const wasm_module_t& other) const { - assert(false); - return true; +struct wasm_exporttype_t { + wasm_exporttype_t(ExportType et) + : I(et), + extern_{wasm_externtype_t::New(et.type->Clone())}, + name{I.name.size(), const_cast<wasm_byte_t*>(I.name.data())} {} + + wasm_exporttype_t(const wasm_exporttype_t& other) + : wasm_exporttype_t(other.I) {} + + wasm_exporttype_t& operator=(const wasm_exporttype_t& other) { + wasm_exporttype_t copy(other); + std::swap(I, copy.I); + std::swap(extern_, copy.extern_); + std::swap(name, copy.name); + return *this; } - ~wasm_module_t() { - TRACE("~module\n"); - wasm_byte_vec_delete(&binary); - } + ExportType I; + // Stored here because API requires returning pointers. + std::unique_ptr<wasm_externtype_t> extern_; + wasm_name_t name; +}; - wasm_store_t* store; - wasm_byte_vec_t binary; - std::unique_ptr<ModuleMetadata> metadata; +struct wasm_store_t { + wasm_store_t(const Features& features) : I(features) {} + Store I; }; -struct wasm_shared_module_t : wasm_module_t {}; +struct wasm_ref_t { + wasm_ref_t(RefPtr<Object> ptr) : I(ptr) {} -bool wasm_ref_t::Same(const wasm_ref_t& other) const { - TRACE("wasm_ref_t::Same kind=%d other=%d\n", static_cast<int>(kind), - static_cast<int>(other.kind)); - if (kind != other.kind) - return false; - TRACE("wasm_ref_t::Same x\n"); - if (other.host_info != host_info && other.finalizer != finalizer) - return false; - TRACE("wasm_ref_t::Same 2\n"); - switch (kind) { - case WasmRefType::Extern: - return static_cast<const wasm_extern_ref_t*>(this)->Same( - static_cast<const wasm_extern_ref_t&>(other)); - case WasmRefType::Instance: - return static_cast<const wasm_instance_t*>(this)->Same( - static_cast<const wasm_instance_t&>(other)); - case WasmRefType::Module: - return static_cast<const wasm_module_t*>(this)->Same( - static_cast<const wasm_module_t&>(other)); - case WasmRefType::Foreign: - return static_cast<const wasm_foreign_t*>(this)->Same( - static_cast<const wasm_foreign_t&>(other)); - case WasmRefType::Trap: - return true; - } - WABT_UNREACHABLE; -} + template <typename T> + T* As() const { return cast<T>(I.get()); } -struct wasm_frame_t { - wasm_instance_t* instance; - size_t offset; - uint32_t func_index; + RefPtr<Object> I; }; -// Type conversion utilities -static Type ToWabtType(wasm_valkind_t kind); -static wasm_valkind_t FromWabtType(Type type); - -Limits ToWabtLimits(const wasm_limits_t& limits) { - return Limits(limits.min, limits.max); -} +struct wasm_frame_t { + Frame I; +}; -wasm_limits_t FromWabtLimits(const Limits& limits) { - return wasm_limits_t{(uint32_t)limits.initial, (uint32_t)limits.max}; -} +struct wasm_trap_t : wasm_ref_t { + wasm_trap_t(RefPtr<Trap> ptr) : wasm_ref_t(ptr) {} +}; -// Value conversion utilities -static TypedValue ToWabtValue(const wasm_val_t& value); -static void ToWabtValues(TypedValues& out_values, - const wasm_val_t values[], - size_t count); -static wasm_val_t FromWabtValue(std::shared_ptr<WasmInstance> instance, - const TypedValue& value); -static void FromWabtValues(std::shared_ptr<WasmInstance> instance, - wasm_val_t values[], - const TypedValues& wabt_values); +struct wasm_foreign_t : wasm_ref_t { + wasm_foreign_t(RefPtr<Foreign> ptr) : wasm_ref_t(ptr) {} +}; -struct wasm_functype_t : wasm_externtype_t { - wasm_functype_t(interp::FuncSignature& sig) - : wasm_externtype_t(WASM_EXTERN_FUNC) { - TRACE("new wasm_functype_t %" PRIzx " -> %" PRIzx "\n", sig.param_types.size(), - sig.result_types.size()); - wasm_valtype_vec_new_uninitialized(¶ms, sig.param_types.size()); - wasm_valtype_vec_new_uninitialized(&results, sig.result_types.size()); - - for (size_t i = 0; i < sig.param_types.size(); i++) { - params.data[i] = new wasm_valtype_t{FromWabtType(sig.param_types[i])}; - } - for (size_t i = 0; i < sig.result_types.size(); i++) { - results.data[i] = new wasm_valtype_t{FromWabtType(sig.result_types[i])}; - } +struct wasm_module_t : wasm_ref_t { + wasm_module_t(RefPtr<Module> ptr, const wasm_byte_vec_t* in) + : wasm_ref_t(ptr) { + wasm_byte_vec_copy(&binary, in); } - wasm_functype_t(wasm_valtype_vec_t* params, wasm_valtype_vec_t* results) - : wasm_externtype_t(WASM_EXTERN_FUNC), - params(*params), - results(*results) {} - - ~wasm_functype_t() { - TRACE("~wasm_functype_t\n"); - wasm_valtype_vec_delete(¶ms); - wasm_valtype_vec_delete(&results); + wasm_module_t(const wasm_module_t& other) : wasm_ref_t(other.I) { + wasm_byte_vec_copy(&binary, &other.binary); } - interp::FuncSignature Sig() const { - std::vector<Type> param_vec; - std::vector<Type> result_vec; - for (size_t i = 0; i < params.size; i++) { - param_vec.push_back(ToWabtType(wasm_valtype_kind(params.data[i]))); - } - for (size_t i = 0; i < results.size; i++) { - result_vec.push_back(ToWabtType(wasm_valtype_kind(results.data[i]))); - } - return interp::FuncSignature{param_vec, result_vec}; + wasm_module_t& operator=(const wasm_module_t& other) { + wasm_module_t copy(other); + std::swap(I, copy.I); + std::swap(binary, copy.binary); + return *this; } - wasm_valtype_vec_t params; - wasm_valtype_vec_t results; + ~wasm_module_t() { + wasm_byte_vec_delete(&binary); + } + // TODO: This is used for wasm_module_serialize/wasm_module_deserialize. + // Currently the standard wasm binary bytes are cached here, but it would be + // better to have a serialization of ModuleDesc instead. + wasm_byte_vec_t binary; }; -struct wasm_extern_t : wasm_extern_ref_t { - virtual ~wasm_extern_t() = default; - - interp::Environment* Env() const { return instance.get()->store->env; } - - wasm_extern_t(const wasm_extern_t& other) - : wasm_extern_ref_t(other), instance(other.instance) {} - - virtual wasm_externtype_t* ExternType() const = 0; - - std::shared_ptr<WasmInstance> instance; +struct wasm_shared_module_t : wasm_module_t {}; - protected: - wasm_extern_t(std::shared_ptr<WasmInstance> instance, - ExternalKind kind, - Index index) - : wasm_extern_ref_t(kind, index), instance(instance) {} +struct wasm_extern_t : wasm_ref_t { + wasm_extern_t(RefPtr<Extern> ptr) : wasm_ref_t(ptr) {} }; struct wasm_func_t : wasm_extern_t { - wasm_func_t(std::shared_ptr<WasmInstance> instance, Index index) - : wasm_extern_t(instance, ExternalKind::Func, index) {} - - interp::Func* GetFunc() const { return Env()->GetFunc(index); } - - interp::FuncSignature* GetSig() const { - return Env()->GetFuncSignature(GetFunc()->sig_index); - } - - wasm_externtype_t* ExternType() const override { - return new wasm_functype_t(*GetSig()); - } + wasm_func_t(RefPtr<Func> ptr) : wasm_extern_t(ptr) {} }; struct wasm_global_t : wasm_extern_t { - wasm_global_t(std::shared_ptr<WasmInstance> instance, Index index) - : wasm_extern_t(instance, ExternalKind::Global, index) {} - - interp::Global* GetGlobal() const { return Env()->GetGlobal(index); } - - wasm_externtype_t* ExternType() const override { - auto* g = GetGlobal(); - return new wasm_globaltype_t({FromWabtType(g->type)}, g->mutable_); - } + wasm_global_t(RefPtr<Global> ptr) : wasm_extern_t(ptr) {} }; struct wasm_table_t : wasm_extern_t { - wasm_table_t(std::shared_ptr<WasmInstance> instance, Index index) - : wasm_extern_t(instance, ExternalKind::Table, index) {} - - interp::Table* GetTable() const { return Env()->GetTable(index); } - - wasm_externtype_t* ExternType() const override { - auto* t = GetTable(); - return new wasm_tabletype_t({FromWabtType(t->elem_type)}, - FromWabtLimits(t->limits)); - } + wasm_table_t(RefPtr<Table> ptr) : wasm_extern_t(ptr) {} }; struct wasm_memory_t : wasm_extern_t { - wasm_memory_t(std::shared_ptr<WasmInstance> instance, Index index) - : wasm_extern_t(instance, ExternalKind::Memory, index) {} - - interp::Memory* GetMemory() const { - auto* env = instance.get()->store->env; - return env->GetMemory(index); - } - - wasm_externtype_t* ExternType() const override { - auto* mem = GetMemory(); - return new wasm_memorytype_t(FromWabtLimits(mem->page_limits)); - } + wasm_memory_t(RefPtr<Memory> ptr) : wasm_extern_t(ptr) {} }; -struct wasm_trap_t : wasm_ref_t { - wasm_trap_t(const wasm_message_t* msg) : wasm_ref_t(WasmRefType::Trap) { - wasm_name_copy(&message, msg); - } - wasm_message_t message; +struct wasm_instance_t : wasm_ref_t { + wasm_instance_t(RefPtr<Instance> ptr) : wasm_ref_t(ptr) {} }; -// Helper functions - -static Type ToWabtType(wasm_valkind_t kind) { +// Type conversion utilities +static ValueType ToWabtValueType(wasm_valkind_t kind) { switch (kind) { case WASM_I32: - return Type::I32; + return ValueType::I32; case WASM_I64: - return Type::I64; + return ValueType::I64; case WASM_F32: - return Type::F32; + return ValueType::F32; case WASM_F64: - return Type::F64; + return ValueType::F64; case WASM_ANYREF: - return Type::Anyref; + return ValueType::Anyref; case WASM_FUNCREF: - return Type::Funcref; + return ValueType::Funcref; default: - TRACE("unexpected wasm_valkind_t: %d\n", kind); + TRACE("unexpected wasm_valkind_t: %d", kind); WABT_UNREACHABLE; } WABT_UNREACHABLE; } -static wasm_valkind_t FromWabtType(Type type) { +static wasm_valkind_t FromWabtValueType(ValueType type) { switch (type) { - case Type::I32: + case ValueType::I32: return WASM_I32; - case Type::I64: + case ValueType::I64: return WASM_I64; - case Type::F32: + case ValueType::F32: return WASM_F32; - case Type::F64: + case ValueType::F64: return WASM_F64; - case Type::Anyref: + case ValueType::Anyref: + case ValueType::Hostref: + case ValueType::Nullref: return WASM_ANYREF; - case Type::Funcref: + case ValueType::Funcref: return WASM_FUNCREF; default: WABT_UNREACHABLE; } } +static wasm_externkind_t FromWabtExternKind(ExternKind kind) { + switch (kind) { + case ExternalKind::Func: + return WASM_EXTERN_FUNC; + case ExternalKind::Global: + return WASM_EXTERN_GLOBAL; + case ExternalKind::Table: + return WASM_EXTERN_TABLE; + case ExternalKind::Memory: + return WASM_EXTERN_MEMORY; + case ExternalKind::Event: + WABT_UNREACHABLE; + } + WABT_UNREACHABLE; +} + +static ValueTypes ToWabtValueTypes(const wasm_valtype_vec_t* types) { + ValueTypes result; + for (size_t i = 0; i < types->size; ++i) { + result.push_back(types->data[i]->I); + } + return result; +} + +static void FromWabtValueTypes(const ValueTypes& types, + wasm_valtype_vec_t* out) { + wasm_valtype_vec_new_uninitialized(out, types.size()); + for (size_t i = 0; i < types.size(); ++i) { + out->data[i] = wasm_valtype_new(FromWabtValueType(types[i])); + } +} + +static wasm_mutability_t FromWabtMutability(Mutability mut) { + return mut == Mutability::Var ? WASM_VAR : WASM_CONST; +} + +static Mutability ToWabtMutability(wasm_mutability_t mut) { + return mut == WASM_VAR ? Mutability::Var : Mutability::Const; +} + +// Value conversion utilities + static TypedValue ToWabtValue(const wasm_val_t& value) { - TypedValue out(ToWabtType(value.kind)); + TypedValue out; + out.type = ToWabtValueType(value.kind); switch (value.kind) { case WASM_I32: - out.set_i32(value.of.i32); + out.value.Set(value.of.i32); break; case WASM_I64: - out.set_i64(value.of.i64); + out.value.Set(value.of.i64); break; case WASM_F32: - out.set_f32(value.of.f32); + out.value.Set(value.of.f32); break; case WASM_F64: - out.set_f64(value.of.f64); - break; - case WASM_FUNCREF: { - auto* ext = static_cast<wasm_extern_t*>(value.of.ref); - assert(ext->kind == ExternalKind::Func); - out.set_ref(Ref{RefType::Func, ext->index}); + out.value.Set(value.of.f64); break; - } - case WASM_ANYREF: { - wasm_ref_t* ref = value.of.ref; - if (!ref) { - out.set_ref(Ref{RefType::Null, kInvalidIndex}); - break; - } - if (ref->kind == WasmRefType::Foreign) { - auto* f = static_cast<wasm_foreign_t*>(ref); - out.set_ref(Ref{RefType::Host, f->index}); - out.type = Type::Hostref; - break; - } - printf("unexpected WASM_ANYREF in ToWabtValue: %d\n", - static_cast<int>(ref->kind)); - WABT_UNREACHABLE; + case WASM_ANYREF: + case WASM_FUNCREF: + out.value.Set(value.of.ref ? value.of.ref->I->self() : Ref::Null); break; - } default: - TRACE("unexpected wasm type: %d\n", value.kind); + TRACE("unexpected wasm type: %d", value.kind); assert(false); } - TRACE("ToWabtValue -> %s\n", TypedValueToString(out).c_str()); + TRACE("-> %s", TypedValueToString(out).c_str()); return out; } -static void ToWabtValues(TypedValues& wabt_values, - const wasm_val_t values[], - size_t count) { - for (size_t i = 0; i < count; i++) { - wabt_values.push_back(ToWabtValue(values[i])); - } -} - -// wasm_byte_vec - -static wasm_val_t FromWabtValue(std::shared_ptr<WasmInstance> instance, - const TypedValue& value) { - TRACE("FromWabtValue: %s\n", TypedValueToString(value).c_str()); +static wasm_val_t FromWabtValue(Store& store, const TypedValue& tv) { + TRACE("%s", TypedValueToString(tv).c_str()); wasm_val_t out_value; - switch (value.type) { + switch (tv.type) { case Type::I32: out_value.kind = WASM_I32; - out_value.of.i32 = value.get_i32(); + out_value.of.i32 = tv.value.Get<s32>(); break; case Type::I64: out_value.kind = WASM_I64; - out_value.of.i64 = value.get_i64(); + out_value.of.i64 = tv.value.Get<s64>(); break; case Type::F32: out_value.kind = WASM_F32; - out_value.of.f32 = value.get_f32(); + out_value.of.f32 = tv.value.Get<f32>(); break; case Type::F64: out_value.kind = WASM_F64; - out_value.of.f64 = value.get_f64(); + out_value.of.f64 = tv.value.Get<f64>(); break; + case Type::Anyref: case Type::Funcref: - out_value.kind = WASM_FUNCREF; - out_value.of.ref = new wasm_func_t(instance, value.get_ref().index); - break; case Type::Hostref: - out_value.kind = WASM_ANYREF; - out_value.of.ref = new wasm_foreign_t(value.get_ref().index); - break; - case Type::Nullref: - out_value.kind = WASM_ANYREF; - out_value.of.ref = nullptr; + case Type::Nullref: { + Ref ref = tv.value.Get<Ref>(); + // Get the actual type for this reference; tv.type uses the function + // signature, which may be to general (e.g. anyref). + Type type = store.GetValueType(ref); + out_value.kind = FromWabtValueType(type); + switch (type) { + case Type::Funcref: + out_value.of.ref = new wasm_func_t(store.UnsafeGet<Func>(ref)); + break; + + case Type::Hostref: + out_value.of.ref = new wasm_foreign_t(store.UnsafeGet<Foreign>(ref)); + break; + + case Type::Nullref: + out_value.of.ref = nullptr; + break; + + default: WABT_UNREACHABLE; + } break; + } default: - TRACE("unexpected wabt type: %d\n", static_cast<int>(value.type)); + TRACE("unexpected wabt type: %d", static_cast<int>(tv.type)); assert(false); } return out_value; } -static void FromWabtValues(std::shared_ptr<WasmInstance> instance, - wasm_val_t values[], - const TypedValues& wabt_values) { - for (size_t i = 0; i < wabt_values.size(); i++) { - values[i] = FromWabtValue(instance, wabt_values[i]); +static Limits ToWabtLimits(const wasm_limits_t& limits) { + return Limits(limits.min, limits.max); +} + +static wasm_limits_t FromWabtLimits(const Limits& limits) { + return wasm_limits_t{(uint32_t)limits.initial, (uint32_t)limits.max}; +} + +static Values ToWabtValues(const wasm_val_t values[], size_t count) { + Values result; + for (size_t i = 0; i < count; ++i) { + result.push_back(ToWabtValue(values[i]).value); } + return result; } -static wasm_externkind_t FromWabtExternalKind(ExternalKind kind) { - switch (kind) { - case ExternalKind::Func: - return WASM_EXTERN_FUNC; - case ExternalKind::Global: - return WASM_EXTERN_GLOBAL; - case ExternalKind::Table: - return WASM_EXTERN_TABLE; - case ExternalKind::Memory: - return WASM_EXTERN_MEMORY; - case ExternalKind::Event: - WABT_UNREACHABLE; +static void FromWabtValues(Store& store, + wasm_val_t values[], + const ValueTypes& types, + const Values& wabt_values) { + assert(types.size() == wabt_values.size()); + for (size_t i = 0; i < types.size(); ++i) { + values[i] = FromWabtValue(store, TypedValue{types[i], wabt_values[i]}); } - WABT_UNREACHABLE; +} + +static std::string ToString(const wasm_message_t* msg) { + return std::string(msg->data, msg->size); +} + +static wasm_message_t FromString(const std::string& s) { + wasm_message_t result; + wasm_byte_vec_new(&result, s.size() + 1, s.c_str()); + return result; } static ReadBinaryOptions GetOptions() { @@ -593,22 +516,22 @@ extern "C" { // wasm_valtype -wasm_valtype_t* wasm_valtype_new(wasm_valkind_t kind) { - return new wasm_valtype_t{kind}; +own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t kind) { + return new wasm_valtype_t{ToWabtValueType(kind)}; } wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t* type) { assert(type); - return type->kind; + return FromWabtValueType(type->I); } // Helpers -static void print_sig(const interp::FuncSignature& sig) { +static void print_sig(const FuncType& sig) { #ifndef NDEBUG fprintf(stderr, "("); bool first = true; - for (auto Type : sig.param_types) { + for (auto Type : sig.params) { if (!first) { fprintf(stderr, ", "); } @@ -617,7 +540,7 @@ static void print_sig(const interp::FuncSignature& sig) { } fprintf(stderr, ") -> ("); first = true; - for (auto Type : sig.result_types) { + for (auto Type : sig.results) { if (!first) { fprintf(stderr, ", "); } @@ -630,7 +553,7 @@ static void print_sig(const interp::FuncSignature& sig) { // wasm_val -void wasm_val_delete(wasm_val_t* val) { +void wasm_val_delete(own wasm_val_t* val) { assert(val); if (wasm_valkind_is_ref(val->kind)) { delete val->of.ref; @@ -638,134 +561,100 @@ void wasm_val_delete(wasm_val_t* val) { } } -void wasm_val_copy(wasm_val_t* out, const wasm_val_t* in) { - TRACE("wasm_val_copy %s\n", TypedValueToString(ToWabtValue(*in)).c_str()); - *out = *in; - TRACE("wasm_val_copy -> %p %s\n", out, - TypedValueToString(ToWabtValue(*out)).c_str()); +void wasm_val_copy(own wasm_val_t* out, const wasm_val_t* in) { + TRACE("%s", TypedValueToString(ToWabtValue(*in)).c_str()); + if (wasm_valkind_is_ref(in->kind)) { + out->kind = in->kind; + out->of.ref = in->of.ref ? new wasm_ref_t{*in->of.ref} : nullptr; + } else { + *out = *in; + } + TRACE("-> %p %s", out, TypedValueToString(ToWabtValue(*out)).c_str()); } // wasm_trap -wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t* msg) { - return new wasm_trap_t(msg); +own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t* msg) { + return new wasm_trap_t{Trap::New(store->I, ToString(msg))}; } -void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) { +void wasm_trap_message(const wasm_trap_t* trap, own wasm_message_t* out) { assert(trap); - wasm_name_copy(out, &trap->message); + *out = FromString(trap->As<Trap>()->message()); } -wasm_frame_t* wasm_trap_origin(const wasm_trap_t* trap) { +own wasm_frame_t* wasm_trap_origin(const wasm_trap_t* trap) { // TODO(sbc): Implement stack traces return nullptr; } -void wasm_trap_trace(const wasm_trap_t* trap, wasm_frame_vec_t* out) { +void wasm_trap_trace(const wasm_trap_t* trap, own wasm_frame_vec_t* out) { assert(trap); assert(out); wasm_frame_vec_new_empty(out); // std::string msg(trap->message.data, trap->message.size); - // fTRACE(stderr, "error: %s\n", msg.c_str()); - return; + // TRACE(stderr, "error: %s\n", msg.c_str()); } // wasm_engine -wasm_engine_t* wasm_engine_new() { +own wasm_engine_t* wasm_engine_new() { return new wasm_engine_t(); } -wasm_engine_t* wasm_engine_new_with_config(wasm_config_t*) { +own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*) { assert(false); return nullptr; } // wasm_store -wasm_store_t* wasm_store_new(wasm_engine_t* engine) { +own wasm_store_t* wasm_store_new(wasm_engine_t* engine) { assert(engine); - if (!s_trace_stream) { - s_trace_stream = s_stdout_stream.get(); - } - Environment* env = new Environment(s_features); - Executor* executor = new Executor(env, s_trace_stream, s_thread_options); - return new wasm_store_t(env, executor); + return new wasm_store_t(s_features); } // wasm_module -wasm_module_t* wasm_module_new(wasm_store_t* store, - const wasm_byte_vec_t* binary) { +own wasm_module_t* wasm_module_new(wasm_store_t* store, + const wasm_byte_vec_t* binary) { Errors errors; - ModuleMetadata* metadata = nullptr; - wabt::Result result = ReadBinaryMetadata(binary->data, binary->size, - GetOptions(), &errors, &metadata); - if (!Succeeded(result)) { + ModuleDesc module_desc; + if (Failed(ReadBinaryInterp(binary->data, binary->size, GetOptions(), &errors, + &module_desc))) { + FormatErrorsToFile(errors, Location::Type::Binary); return nullptr; } - return new wasm_module_t(store, binary, metadata); + + return new wasm_module_t{Module::New(store->I, module_desc), binary}; } void wasm_module_exports(const wasm_module_t* module, - wasm_exporttype_vec_t* out) { - size_t num_exports = module->metadata->exports.size(); - TRACE("wasm_module_exports: %" PRIzx "\n", num_exports); - wasm_exporttype_vec_new_uninitialized(out, num_exports); - auto* env = module->store->env; - for (size_t i = 0; i < num_exports; i++) { - interp::Export& exp = module->metadata->exports[i]; - wasm_name_t name; - wasm_name_new_from_string(&name, exp.name.c_str()); - TRACE("module_export: %s\n", exp.name.c_str()); - switch (exp.kind) { - case ExternalKind::Func: { - interp::Func* func = env->GetFunc(exp.index); - auto* type = - new wasm_functype_t(*env->GetFuncSignature(func->sig_index)); - out->data[i] = new wasm_exporttype_t{name, type}; - break; - } - case ExternalKind::Global: { - auto* g = env->GetGlobal(exp.index); - auto* type = - new wasm_globaltype_t({FromWabtType(g->type)}, g->mutable_); - out->data[i] = new wasm_exporttype_t{name, type}; - break; - } - case ExternalKind::Table: { - auto* t = env->GetTable(exp.index); - auto* type = new wasm_tabletype_t({FromWabtType(t->elem_type)}, - FromWabtLimits(t->limits)); - out->data[i] = new wasm_exporttype_t{name, type}; - break; - } - case ExternalKind::Memory: { - auto* mem = env->GetMemory(exp.index); - auto* type = new wasm_memorytype_t(FromWabtLimits(mem->page_limits)); - out->data[i] = new wasm_exporttype_t{name, type}; - break; - } - case ExternalKind::Event: - WABT_UNREACHABLE; - } + own wasm_exporttype_vec_t* out) { + auto&& export_types = module->As<Module>()->export_types(); + TRACE("%" PRIzx, export_types.size()); + wasm_exporttype_vec_new_uninitialized(out, export_types.size()); + + for (size_t i = 0; i < export_types.size(); ++i) { + out->data[i] = new wasm_exporttype_t{export_types[i]}; } } -void wasm_module_serialize(const wasm_module_t* module, wasm_byte_vec_t* out) { +void wasm_module_serialize(const wasm_module_t* module, + own wasm_byte_vec_t* out) { wasm_byte_vec_copy(out, &module->binary); } -wasm_module_t* wasm_module_deserialize(wasm_store_t* store, - const wasm_byte_vec_t* bytes) { +own wasm_module_t* wasm_module_deserialize(wasm_store_t* store, + const wasm_byte_vec_t* bytes) { return wasm_module_new(store, bytes); } // wasm_exporttype -wasm_exporttype_t* wasm_exporttype_new(wasm_name_t* name, - wasm_externtype_t* type) { - return new wasm_exporttype_t{*name, type}; +own wasm_exporttype_t* wasm_exporttype_new(own wasm_name_t* name, + wasm_externtype_t* type) { + return new wasm_exporttype_t{ExportType{ToString(name), type->I->Clone()}}; } const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t* ex) { @@ -773,103 +662,62 @@ const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t* ex) { } const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* ex) { - TRACE("wasm_exporttype_type %p\n", ex); + TRACE("%p", ex); assert(ex); - return ex->type.get(); + return ex->extern_.get(); } // wasm_instance -wasm_instance_t* wasm_instance_new(wasm_store_t* store, - const wasm_module_t* module, - const wasm_extern_t* const imports[], - wasm_trap_t** trap_out) { - TRACE("wasm_instance_new: %p %p\n", store, module); +own wasm_instance_t* wasm_instance_new(wasm_store_t* store, + const wasm_module_t* module, + const wasm_extern_t* const imports[], + own wasm_trap_t** trap_out) { + TRACE("%p %p", store, module); assert(module); - assert(module->metadata); assert(store); - assert(store->env); - Errors errors; - DefinedModule* interp_module = nullptr; - std::vector<interp::Export> wabt_imports; - std::vector<interp::Export*> wabt_import_ptrs; - - for (size_t i = 0; i < module->metadata->imports.size(); i++) { - wabt_imports.emplace_back("", imports[i]->kind, imports[i]->index); + RefVec import_refs; + for (size_t i = 0; i < module->As<Module>()->import_types().size(); i++) { + import_refs.push_back(imports[i]->I->self()); } - for (auto& i : wabt_imports) { - wabt_import_ptrs.push_back(&i); - } - - wabt::Result result = - ReadBinaryInterp(store->env, module->binary.data, module->binary.size, - GetOptions(), wabt_import_ptrs, &errors, &interp_module); - - FormatErrorsToFile(errors, Location::Type::Binary); - if (!Succeeded(result)) { - TRACE("ReadBinaryInterp failed!\n"); + Trap::Ptr trap; + auto instance = + Instance::Instantiate(store->I, module->I->self(), import_refs, &trap); + if (trap) { + *trap_out = new wasm_trap_t{trap}; return nullptr; } - ExecResult exec_result = store->executor->Initialize(interp_module); - if (!exec_result.ok()) { - TRACE("Initialize failed!\n"); - wasm_name_t msg; - wasm_name_new_from_string(&msg, ResultToString(exec_result.result).c_str()); - wasm_trap_t* trap = wasm_trap_new(store, &msg); - *trap_out = trap; - return nullptr; - } - return new wasm_instance_t(store, interp_module); + return new wasm_instance_t{instance}; } void wasm_instance_exports(const wasm_instance_t* instance, - wasm_extern_vec_t* out) { - WasmInstance& wasm_instance = *instance->ptr.get(); - DefinedModule* module = wasm_instance.module.get(); - size_t num_exports = module->exports.size(); - wasm_extern_vec_new_uninitialized(out, num_exports); - TRACE("wasm_instance_exports: %" PRIzx "\n", num_exports); - - for (size_t i = 0; i < num_exports; i++) { - interp::Export* export_ = &module->exports[i]; - TRACE("getexport: '%s' %d\n", export_->name.c_str(), - static_cast<int>(export_->kind)); - switch (export_->kind) { - case ExternalKind::Func: - out->data[i] = new wasm_func_t(instance->ptr, export_->index); - break; - case ExternalKind::Global: - out->data[i] = new wasm_global_t(instance->ptr, export_->index); - break; - case ExternalKind::Table: - out->data[i] = new wasm_table_t(instance->ptr, export_->index); - break; - case ExternalKind::Memory: - out->data[i] = new wasm_memory_t(instance->ptr, export_->index); - break; - case ExternalKind::Event: - WABT_UNREACHABLE; - } + own wasm_extern_vec_t* out) { + auto&& exports = instance->As<Instance>()->exports(); + wasm_extern_vec_new_uninitialized(out, exports.size()); + TRACE("%" PRIzx, exports.size()); + + for (size_t i = 0; i < exports.size(); ++i) { + out->data[i] = + new wasm_extern_t{instance->I.store()->UnsafeGet<Extern>(exports[i])}; } } // wasm_functype -wasm_functype_t* wasm_functype_new(wasm_valtype_vec_t* params, - wasm_valtype_vec_t* results) { - TRACE("wasm_functype_new params=%" PRIzx " args=%" PRIzx "\n", params->size, results->size); - auto* res = new wasm_functype_t(params, results); - interp::FuncSignature sig = res->Sig(); - TRACE("wasm_functype_new -> "); - print_sig(sig); +own wasm_functype_t* wasm_functype_new(own wasm_valtype_vec_t* params, + own wasm_valtype_vec_t* results) { + TRACE("params=%" PRIzx " args=%" PRIzx, params->size, results->size); + auto* res = new wasm_functype_t{params, results}; + TRACE_NO_NL(""); + print_sig(*res->As<FuncType>()); return res; } const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t* f) { - TRACE("wasm_functype_params: %" PRIzx "\n", f->params.size); + TRACE("%" PRIzx, f->params.size); return &f->params; } @@ -878,145 +726,120 @@ const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t* f) { } // wasm_func - -static wasm_func_t* do_wasm_func_new( - wasm_store_t* store, - const wasm_functype_t* type, - wasm_func_callback_t host_callback, - wasm_func_callback_with_env_t host_callback_with_env, - void* env, - void (*finalizer)(void*)) { - TRACE("do_wasm_func_new\n"); - type->Sig(); - auto instance = std::make_shared<WasmInstance>(store, nullptr); - - HostFunc::Callback callback = - [instance, host_callback, host_callback_with_env, env]( - const HostFunc* func, const interp::FuncSignature* sig, - const TypedValues& args, TypedValues& results) -> interp::Result { - TRACE("calling host function: "); - print_sig(*sig); - wasm_val_t* host_args = new wasm_val_t[args.size()]; - wasm_val_t* host_results = new wasm_val_t[sig->result_types.size()]; - FromWabtValues(instance, host_args, args); - wasm_trap_t* trap; - if (host_callback) { - trap = host_callback(host_args, host_results); - } else { - assert(host_callback_with_env); - trap = host_callback_with_env(env, host_args, host_results); - } +own wasm_func_t* wasm_func_new(wasm_store_t* store, + const wasm_functype_t* type, + wasm_func_callback_t callback) { + FuncType wabt_type = *type->As<FuncType>(); + auto lambda = [=](const Values& wabt_params, Values& wabt_results, + Trap::Ptr* out_trap) -> Result { + wasm_val_vec_t params, results; + wasm_val_vec_new_uninitialized(¶ms, wabt_params.size()); + wasm_val_vec_new_uninitialized(&results, wabt_results.size()); + FromWabtValues(store->I, params.data, wabt_type.params, wabt_params); + auto trap = callback(params.data, results.data); + wasm_val_vec_delete(¶ms); if (trap) { - TRACE("host function trapped\n"); - delete[] host_args; - delete[] host_results; - return interp::ResultType::TrapHostTrapped; + *out_trap = trap->I.As<Trap>(); + wasm_trap_delete(trap); + // Can't use wasm_val_vec_delete since it wasn't populated. + delete[] results.data; + return Result::Error; } - TRACE("adding result types: %" PRIzx "\n", sig->result_types.size()); - for (size_t i = 0; i < sig->result_types.size(); i++) { - TRACE("result: %p\n", &host_results[i]); - results[i] = ToWabtValue(host_results[i]); - TRACE("added result value: %s\n", TypedValueToString(results[i]).c_str()); - } - delete[] host_args; - delete[] host_results; - return interp::ResultType::Ok; + wabt_results = ToWabtValues(results.data, results.size); + wasm_val_vec_delete(&results); + return Result::Ok; }; - type->Sig(); - type->Sig(); - static int function_count = 0; - std::string name = std::string("function") + std::to_string(function_count++); - store->env->EmplaceBackFuncSignature(type->Sig()); - Index sig_index = store->env->GetFuncSignatureCount() - 1; - auto* host_func = new HostFunc("extern", name, sig_index, callback); - store->env->EmplaceBackFunc(host_func); - Index func_index = store->env->GetFuncCount() - 1; - return new wasm_func_t(instance, func_index); -} - -wasm_func_t* wasm_func_new(wasm_store_t* store, - const wasm_functype_t* type, - wasm_func_callback_t callback) { - return do_wasm_func_new(store, type, callback, nullptr, nullptr, nullptr); -} + return new wasm_func_t{HostFunc::New(store->I, wabt_type, lambda)}; +} + +own wasm_func_t* wasm_func_new_with_env(wasm_store_t* store, + const wasm_functype_t* type, + wasm_func_callback_with_env_t callback, + void* env, + void (*finalizer)(void*)) { + FuncType wabt_type = *type->As<FuncType>(); + auto lambda = [=](const Values& wabt_params, Values& wabt_results, + Trap::Ptr* out_trap) -> Result { + wasm_val_vec_t params, results; + wasm_val_vec_new_uninitialized(¶ms, wabt_params.size()); + wasm_val_vec_new_uninitialized(&results, wabt_results.size()); + FromWabtValues(store->I, params.data, wabt_type.params, wabt_params); + auto trap = callback(env, params.data, results.data); + wasm_val_vec_delete(¶ms); + if (trap) { + *out_trap = trap->I.As<Trap>(); + wasm_trap_delete(trap); + // Can't use wasm_val_vec_delete since it wasn't populated. + delete[] results.data; + return Result::Error; + } + wabt_results = ToWabtValues(results.data, results.size); + wasm_val_vec_delete(&results); + return Result::Ok; + }; -wasm_func_t* wasm_func_new_with_env(wasm_store_t* store, - const wasm_functype_t* type, - wasm_func_callback_with_env_t callback, - void* env, - void (*finalizer)(void*)) { - return do_wasm_func_new(store, type, nullptr, callback, env, finalizer); + // TODO: This finalizer is different from the host_info finalizer. + return new wasm_func_t{HostFunc::New(store->I, wabt_type, lambda)}; } -wasm_functype_t* wasm_func_type(const wasm_func_t* func) { - TRACE("wasm_func_type\n"); - return new wasm_functype_t(*func->GetSig()); +own wasm_functype_t* wasm_func_type(const wasm_func_t* func) { + TRACE0(); + return new wasm_functype_t{func->As<Func>()->type()}; } size_t wasm_func_result_arity(const wasm_func_t* func) { - interp::Func* wabt_func = func->GetFunc(); - auto* env = func->instance.get()->store->env; - interp::FuncSignature* sig = env->GetFuncSignature(wabt_func->sig_index); - return sig->result_types.size(); + return func->As<Func>()->type().results.size(); } size_t wasm_func_param_arity(const wasm_func_t* func) { - interp::Func* wabt_func = func->GetFunc(); - auto* env = func->instance.get()->store->env; - interp::FuncSignature* sig = env->GetFuncSignature(wabt_func->sig_index); - return sig->param_types.size(); -} - -wasm_trap_t* wasm_func_call(const wasm_func_t* f, - const wasm_val_t args[], - wasm_val_t results[]) { - TRACE("wasm_func_call %d\n", f->index); - assert(f); - wasm_store_t* store = f->instance.get()->store; - assert(store); - wasm_functype_t* functype = wasm_func_type(f); - TypedValues wabt_args; - ToWabtValues(wabt_args, args, functype->params.size); - wasm_functype_delete(functype); - assert(f->kind == ExternalKind::Func); - ExecResult res = store->executor->RunFunction(f->index, wabt_args); - if (!res.ok()) { - std::string msg = ResultToString(res.result); - TRACE("wasm_func_call failed: %s\n", msg.c_str()); - wasm_name_t message; - wasm_name_new_from_string(&message, msg.c_str()); - wasm_trap_t* trap = wasm_trap_new(store, &message); - wasm_name_delete(&message); - return trap; + return func->As<Func>()->type().params.size(); +} + +own wasm_trap_t* wasm_func_call(const wasm_func_t* f, + const wasm_val_t args[], + wasm_val_t results[]) { + // TODO: get some information about the function; name/index + // TRACE("%d", f->index); + + auto&& func_type = f->As<Func>()->type(); + Values wabt_args = ToWabtValues(args, func_type.params.size()); + Values wabt_results; + Trap::Ptr trap; + if (Failed( + f->As<Func>()->Call(*f->I.store(), wabt_args, wabt_results, &trap))) { + return new wasm_trap_t{trap}; } - FromWabtValues(f->instance, results, res.values); + FromWabtValues(*f->I.store(), results, func_type.results, wabt_results); return nullptr; } // wasm_globaltype -wasm_globaltype_t* wasm_globaltype_new(wasm_valtype_t* type, - wasm_mutability_t mut) { +own wasm_globaltype_t* wasm_globaltype_new(own wasm_valtype_t* type, + wasm_mutability_t mut) { assert(type); - return new wasm_globaltype_t(*type, mut == WASM_VAR); + auto* result = new wasm_globaltype_t{GlobalType{ + type->I, mut == WASM_CONST ? Mutability::Const : Mutability::Var}}; + wasm_valtype_delete(type); + return result; } wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t* type) { assert(type); - return type->mutable_; + return FromWabtMutability(type->As<GlobalType>()->mut); } const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t* type) { assert(type); - return &type->type; + return &type->valtype; } // wasm_tabletype -wasm_tabletype_t* wasm_tabletype_new(wasm_valtype_t* type, - const wasm_limits_t* limits) { - return new wasm_tabletype_t(*type, *limits); +own wasm_tabletype_t* wasm_tabletype_new(own wasm_valtype_t* type, + const wasm_limits_t* limits) { + return new wasm_tabletype_t{type, limits}; } const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t* type) { @@ -1029,8 +852,8 @@ const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t* type) { // wasm_memorytype -wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t* limits) { - return new wasm_memorytype_t(*limits); +own wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t* limits) { + return new wasm_memorytype_t(limits); } const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t* t) { @@ -1039,236 +862,160 @@ const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t* t) { // wasm_global -wasm_global_t* wasm_global_new(wasm_store_t* store, - const wasm_globaltype_t* type, - const wasm_val_t* val) { - assert(store && store && type); +own wasm_global_t* wasm_global_new(wasm_store_t* store, + const wasm_globaltype_t* type, + const wasm_val_t* val) { + assert(store && type); TypedValue value = ToWabtValue(*val); - TRACE("wasm_global_new: %s\n", TypedValueToString(value).c_str()); - interp::Global* g = store->env->EmplaceBackGlobal(value.type, type->mutable_); - g->typed_value = value; - Index global_index = store->env->GetGlobalCount() - 1; - auto instance = std::make_shared<WasmInstance>(store, nullptr); - return new wasm_global_t(instance, global_index); + TRACE("%s", TypedValueToString(value).c_str()); + return new wasm_global_t{ + Global::New(store->I, *type->As<GlobalType>(), value.value)}; } -wasm_globaltype_t* wasm_global_type(const wasm_global_t* global) { - assert(global); - assert(false); - WABT_UNREACHABLE; +own wasm_globaltype_t* wasm_global_type(const wasm_global_t* global) { + return new wasm_globaltype_t{global->As<Global>()->type()}; } -void wasm_global_get(const wasm_global_t* global, wasm_val_t* out) { +void wasm_global_get(const wasm_global_t* global, own wasm_val_t* out) { assert(global); - TRACE("wasm_global_get"); - interp::Global* interp_global = global->GetGlobal(); - TRACE(" -> %s\n", TypedValueToString(interp_global->typed_value).c_str()); - *out = FromWabtValue(global->instance, interp_global->typed_value); - return; + TRACE0(); + TypedValue tv{global->As<Global>()->type().type, global->As<Global>()->Get()}; + TRACE(" -> %s", TypedValueToString(tv).c_str()); + *out = FromWabtValue(*global->I.store(), tv); } void wasm_global_set(wasm_global_t* global, const wasm_val_t* val) { - TRACE("wasm_global_set\n"); - interp::Global* g = global->GetGlobal(); - g->typed_value = ToWabtValue(*val); + TRACE0(); + if (wasm_valkind_is_ref(val->kind)) { + global->As<Global>()->Set(*global->I.store(), val->of.ref->I->self()); + } else { + global->As<Global>()->UnsafeSet(ToWabtValue(*val).value); + } } // wasm_table -wasm_table_t* wasm_table_new(wasm_store_t* store, - const wasm_tabletype_t* type, - wasm_ref_t* init) { - store->env->EmplaceBackTable(ToWabtType(type->elemtype.kind), - ToWabtLimits(type->limits)); - Index index = store->env->GetTableCount() - 1; - auto instance = std::make_shared<WasmInstance>(store, nullptr); - return new wasm_table_t(instance, index); +own wasm_table_t* wasm_table_new(wasm_store_t* store, + const wasm_tabletype_t* type, + wasm_ref_t* init) { + return new wasm_table_t{Table::New(store->I, *type->As<TableType>())}; } -wasm_tabletype_t* wasm_table_type(const wasm_table_t*) { - assert(false); - return nullptr; +own wasm_tabletype_t* wasm_table_type(const wasm_table_t* table) { + return new wasm_tabletype_t{table->As<Table>()->type()}; } wasm_table_size_t wasm_table_size(const wasm_table_t* table) { - return table->GetTable()->size(); + return table->As<Table>()->size(); } -wasm_ref_t* wasm_table_get(const wasm_table_t* t, wasm_table_size_t index) { - interp::Table* table = t->GetTable(); - // TODO(sbc): This duplicates code from the CallIndirect handler. I imagine - // we will refactor this when we implment the TableGet opcode. - if (index >= table->size()) +own wasm_ref_t* wasm_table_get(const wasm_table_t* table, + wasm_table_size_t index) { + Ref ref; + if (Failed(table->As<Table>()->Get(index, &ref))) { return nullptr; - switch (table->entries[index].kind) { - case RefType::Func: { - Index func_index = table->entries[index].index; - if (func_index == kInvalidIndex) - return nullptr; - TRACE("wasm_table_get: %u -> %u\n", index, func_index); - return new wasm_extern_ref_t(ExternalKind::Func, func_index); - } - case RefType::Host: - return new wasm_foreign_ref_t(table->entries[index].index); - case RefType::Null: - return nullptr; } - WABT_UNREACHABLE; + if (ref == Ref::Null) { + return nullptr; + } + return new wasm_ref_t{table->I.store()->UnsafeGet<Object>(ref)}; } -bool wasm_table_set(wasm_table_t* t, wasm_table_size_t index, wasm_ref_t* ref) { - interp::Table* table = t->GetTable(); - if (index >= table->size()) { - return false; - } - TRACE("wasm_table_set %p\n", ref); - if (!ref) { - table->entries[index] = Ref{RefType::Null, kInvalidIndex}; - return true; - } - TRACE("wasm_table_set %s\n", WasmRefTypeToString(ref->kind).c_str()); - switch (ref->kind) { - case WasmRefType::Extern: { - auto* ext = static_cast<wasm_extern_ref_t*>(ref); - switch (ext->kind) { - case ExternalKind::Func: - table->entries[index] = Ref{RefType::Func, ext->index}; - break; - case ExternalKind::Table: - case ExternalKind::Memory: - case ExternalKind::Global: - case ExternalKind::Event: - return false; - } - break; - } - case WasmRefType::Foreign: { - auto* f = static_cast<wasm_foreign_ref_t*>(ref); - table->entries[index] = Ref{RefType::Host, f->index}; - break; - } - case WasmRefType::Module: - case WasmRefType::Instance: - case WasmRefType::Trap: - return false; - } - return true; +bool wasm_table_set(wasm_table_t* table, + wasm_table_size_t index, + wasm_ref_t* ref) { + return Succeeded(table->As<Table>()->Set(*table->I.store(), index, + ref ? ref->I->self() : Ref::Null)); } -bool wasm_table_grow(wasm_table_t* t, +bool wasm_table_grow(wasm_table_t* table, wasm_table_size_t delta, wasm_ref_t* init) { - interp::Table* table = t->GetTable(); - size_t cursize = table->size(); - size_t newsize = cursize + delta; - if (newsize > table->limits.max) { - return false; - } - TRACE("wasm_table_grow %" PRIzx " -> %" PRIzx "\n", cursize, newsize); - auto* ext = static_cast<wasm_extern_ref_t*>(init); - if (ext && ext->kind != ExternalKind::Func) { - return false; - } - Ref init_ref{RefType::Null, kInvalidIndex}; - if (ext) { - init_ref = Ref{RefType::Func, ext->index}; - } - table->entries.resize(newsize, init_ref); - return true; + return Succeeded(table->As<Table>()->Grow( + *table->I.store(), delta, init ? init->I->self() : Ref::Null)); } // wams_memory -wasm_memory_t* wasm_memory_new(wasm_store_t* store, - const wasm_memorytype_t* type) { - TRACE("wasm_memory_new\n"); - store->env->EmplaceBackMemory(Limits(type->limits.min, type->limits.max)); - Index index = store->env->GetMemoryCount() - 1; - auto instance = std::make_shared<WasmInstance>(store, nullptr); - return new wasm_memory_t(instance, index); +own wasm_memory_t* wasm_memory_new(wasm_store_t* store, + const wasm_memorytype_t* type) { + TRACE0(); + return new wasm_memory_t{Memory::New(store->I, *type->As<MemoryType>())}; } -byte_t* wasm_memory_data(wasm_memory_t* m) { - interp::Memory* memory = m->GetMemory(); - return memory->data.data(); +byte_t* wasm_memory_data(wasm_memory_t* memory) { + return reinterpret_cast<byte_t*>(memory->As<Memory>()->UnsafeData()); } -wasm_memory_pages_t wasm_memory_size(const wasm_memory_t* m) { - interp::Memory* memory = m->GetMemory(); - return memory->data.size() / WABT_PAGE_SIZE; +wasm_memory_pages_t wasm_memory_size(const wasm_memory_t* memory) { + return memory->As<Memory>()->PageSize(); } -size_t wasm_memory_data_size(const wasm_memory_t* m) { - interp::Memory* memory = m->GetMemory(); - return memory->data.size(); +size_t wasm_memory_data_size(const wasm_memory_t* memory) { + return memory->As<Memory>()->ByteSize(); } -bool wasm_memory_grow(wasm_memory_t* m, wasm_memory_pages_t delta) { - interp::Memory* memory = m->GetMemory(); - size_t cursize = memory->data.size() / WABT_PAGE_SIZE; - size_t newsize = cursize + delta; - if (newsize > memory->page_limits.max) { - return false; - } - TRACE("wasm_memory_grow %" PRIzx " -> %" PRIzx "\n", cursize, newsize); - memory->data.resize(newsize * WABT_PAGE_SIZE); - return true; +bool wasm_memory_grow(wasm_memory_t* memory, wasm_memory_pages_t delta) { + return Succeeded(memory->As<Memory>()->Grow(delta)); } // wasm_frame +own wasm_frame_t* wasm_frame_copy(const wasm_frame_t* frame) { + return new wasm_frame_t{*frame}; +} + wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) { - assert(frame); - return frame->instance; + // TODO + return nullptr; } size_t wasm_frame_module_offset(const wasm_frame_t* frame) { - assert(frame); - return frame->offset; + // TODO + return 0; } size_t wasm_frame_func_offset(const wasm_frame_t* frame) { - assert(false); + // TODO return 0; } uint32_t wasm_frame_func_index(const wasm_frame_t* frame) { - assert(frame); - return frame->func_index; + // TODO + return 0; } // wasm_externtype wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t* type) { assert(type); - return type->kind; + return FromWabtExternKind(type->I->kind); } // wasm_extern -wasm_externtype_t* wasm_extern_type(const wasm_extern_t* extern_) { - return extern_->ExternType(); +own wasm_externtype_t* wasm_extern_type(const wasm_extern_t* extern_) { + return wasm_externtype_t::New(extern_->As<Extern>()->extern_type().Clone()) + .release(); } wasm_externkind_t wasm_extern_kind(const wasm_extern_t* extern_) { - return FromWabtExternalKind(extern_->kind); + return FromWabtExternKind(extern_->As<Extern>()->extern_type().kind); } // wasm_foreign -wasm_foreign_t* wasm_foreign_new(wasm_store_t* store) { - store->env->EmplaceBackHostObject(); - Index new_index = store->env->GetHostCount() - 1; - return new wasm_foreign_t(new_index); +own wasm_foreign_t* wasm_foreign_new(wasm_store_t* store) { + return new wasm_foreign_t{Foreign::New(store->I, nullptr)}; } // vector types -#define WASM_IMPL_OWN(name) \ - void wasm_##name##_delete(wasm_##name##_t* t) { \ - assert(t); \ - TRACE("wasm_" #name "_delete\n"); \ - delete t; \ +#define WASM_IMPL_OWN(name) \ + void wasm_##name##_delete(own wasm_##name##_t* t) { \ + assert(t); \ + TRACE0(); \ + delete t; \ } WASM_IMPL_OWN(frame); @@ -1276,84 +1023,146 @@ WASM_IMPL_OWN(config); WASM_IMPL_OWN(engine); WASM_IMPL_OWN(store); -#define WASM_IMPL_VEC(name, ptr_or_none) \ - void wasm_##name##_vec_new(wasm_##name##_vec_t* vec, size_t size, \ - wasm_##name##_t ptr_or_none const src[]) { \ - TRACE("wasm_" #name "_vec_new\n"); \ +#define WASM_IMPL_VEC_BASE(name, ptr_or_none) \ + void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out) { \ + TRACE0(); \ + wasm_##name##_vec_new_uninitialized(out, 0); \ + } \ + void wasm_##name##_vec_new_uninitialized(own wasm_##name##_vec_t* vec, \ + size_t size) { \ + TRACE("%" PRIzx, size); \ + vec->size = size; \ + vec->data = size ? new wasm_##name##_t ptr_or_none[size] : nullptr; \ + } + +#define WASM_IMPL_VEC_PLAIN(name) \ + WASM_IMPL_VEC_BASE(name, ) \ + void wasm_##name##_vec_new(own wasm_##name##_vec_t* vec, size_t size, \ + own wasm_##name##_t const src[]) { \ + TRACE0(); \ wasm_##name##_vec_new_uninitialized(vec, size); \ - memcpy(vec->data, src, size * sizeof(wasm_##name##_t ptr_or_none)); \ + memcpy(vec->data, src, size * sizeof(wasm_##name##_t)); \ } \ - void wasm_##name##_vec_new_empty(wasm_##name##_vec_t* out) { \ - TRACE("wasm_" #name "_vec_new_empty\n"); \ - out->data = nullptr; \ - out->size = 0; \ + void wasm_##name##_vec_copy(own wasm_##name##_vec_t* out, \ + const wasm_##name##_vec_t* vec) { \ + TRACE("%" PRIzx, vec->size); \ + wasm_##name##_vec_new_uninitialized(out, vec->size); \ + memcpy(out->data, vec->data, vec->size * sizeof(wasm_##name##_t)); \ } \ - void wasm_##name##_vec_new_uninitialized(wasm_##name##_vec_t* vec, \ - size_t size) { \ - TRACE("wasm_" #name "_vec_new_uninitialized %" PRIzx "\n", size); \ - vec->size = size; \ - if (size) \ - vec->data = new wasm_##name##_t ptr_or_none[size]; \ - else \ - vec->data = nullptr; \ + void wasm_##name##_vec_delete(own wasm_##name##_vec_t* vec) { \ + TRACE0(); \ + delete[] vec->data; \ + vec->size = 0; \ + } + +WASM_IMPL_VEC_PLAIN(byte); + +// Special implementation for wasm_val_t, since it's weird. +WASM_IMPL_VEC_BASE(val, ) +void wasm_val_vec_new(own wasm_val_vec_t* vec, + size_t size, + own wasm_val_t const src[]) { + TRACE0(); + wasm_val_vec_new_uninitialized(vec, size); + for (size_t i = 0; i < size; ++i) { + vec->data[i] = src[i]; + } +} + +void wasm_val_vec_copy(own wasm_val_vec_t* out, const wasm_val_vec_t* vec) { + TRACE("%" PRIzx, vec->size); + wasm_val_vec_new_uninitialized(out, vec->size); + for (size_t i = 0; i < vec->size; ++i) { + wasm_val_copy(&out->data[i], &vec->data[i]); + } +} + +void wasm_val_vec_delete(own wasm_val_vec_t* vec) { + TRACE0(); + for (size_t i = 0; i < vec->size; ++i) { + wasm_val_delete(&vec->data[i]); + } + delete[] vec->data; + vec->size = 0; +} + +#define WASM_IMPL_VEC_OWN(name) \ + WASM_IMPL_VEC_BASE(name, *) \ + void wasm_##name##_vec_new(own wasm_##name##_vec_t* vec, size_t size, \ + own wasm_##name##_t* const src[]) { \ + TRACE0(); \ + wasm_##name##_vec_new_uninitialized(vec, size); \ + for (size_t i = 0; i < size; ++i) { \ + vec->data[i] = src[i]; \ + } \ } \ - void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \ + void wasm_##name##_vec_copy(own wasm_##name##_vec_t* out, \ const wasm_##name##_vec_t* vec) { \ - TRACE("wasm_" #name "_vec_copy %" PRIzx "\n", vec->size); \ + TRACE("%" PRIzx, vec->size); \ wasm_##name##_vec_new_uninitialized(out, vec->size); \ - memcpy(out->data, vec->data, \ - vec->size * sizeof(wasm_##name##_t ptr_or_none)); \ + for (size_t i = 0; i < vec->size; ++i) { \ + out->data[i] = wasm_##name##_copy(vec->data[i]); \ + } \ } \ void wasm_##name##_vec_delete(wasm_##name##_vec_t* vec) { \ - TRACE("wasm_" #name "_vec_delete\n"); \ - if (vec->data) { \ - delete vec->data; \ + TRACE0(); \ + for (size_t i = 0; i < vec->size; ++i) { \ + delete vec->data[i]; \ } \ + delete[] vec->data; \ vec->size = 0; \ } -WASM_IMPL_VEC(byte, ); -WASM_IMPL_VEC(val, ); -WASM_IMPL_VEC(frame, *); -WASM_IMPL_VEC(extern, *); +WASM_IMPL_VEC_OWN(frame); +WASM_IMPL_VEC_OWN(extern); -#define WASM_IMPL_TYPE(name) \ - WASM_IMPL_OWN(name) \ - WASM_IMPL_VEC(name, *) \ - wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t* other) { \ - return new wasm_##name##_t(*other); \ +#define WASM_IMPL_TYPE(name) \ + WASM_IMPL_OWN(name) \ + WASM_IMPL_VEC_OWN(name) \ + own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t* other) { \ + TRACE0(); \ + return new wasm_##name##_t(*other); \ } WASM_IMPL_TYPE(valtype); -WASM_IMPL_TYPE(functype); -WASM_IMPL_TYPE(globaltype); -WASM_IMPL_TYPE(tabletype); -WASM_IMPL_TYPE(memorytype); -WASM_IMPL_TYPE(externtype); WASM_IMPL_TYPE(importtype); WASM_IMPL_TYPE(exporttype); -#define WASM_IMPL_REF_BASE(name) \ - WASM_IMPL_OWN(name) \ - wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t* ref) { \ - TRACE("wasm_" #name "_copy\n"); \ - return static_cast<wasm_##name##_t*>(ref->Copy()); \ - } \ - bool wasm_##name##_same(const wasm_##name##_t* ref, \ - const wasm_##name##_t* other) { \ - TRACE("wasm_" #name "_same\n"); \ - return ref->Same(*other); \ - } \ - void* wasm_##name##_get_host_info(const wasm_##name##_t* ref) { \ - return ref->host_info; \ - } \ - void wasm_##name##_set_host_info(wasm_##name##_t* ref, void* info) { \ - ref->host_info = info; \ - } \ - void wasm_##name##_set_host_info_with_finalizer( \ - wasm_##name##_t* ref, void* info, void (*finalizer)(void*)) { \ - ref->host_info = info; \ - ref->finalizer = finalizer; \ +#define WASM_IMPL_TYPE_CLONE(name) \ + WASM_IMPL_OWN(name) \ + WASM_IMPL_VEC_OWN(name) \ + own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t* other) { \ + TRACE0(); \ + return static_cast<wasm_##name##_t*>(other->Clone().release()); \ + } + +WASM_IMPL_TYPE_CLONE(functype); +WASM_IMPL_TYPE_CLONE(globaltype); +WASM_IMPL_TYPE_CLONE(tabletype); +WASM_IMPL_TYPE_CLONE(memorytype); +WASM_IMPL_TYPE_CLONE(externtype); + +#define WASM_IMPL_REF_BASE(name) \ + WASM_IMPL_OWN(name) \ + own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t* ref) { \ + TRACE0(); \ + return new wasm_##name##_t(*ref); \ + } \ + bool wasm_##name##_same(const wasm_##name##_t* ref, \ + const wasm_##name##_t* other) { \ + TRACE0(); \ + return ref->I == other->I; \ + } \ + void* wasm_##name##_get_host_info(const wasm_##name##_t* ref) { \ + return ref->I->host_info(); \ + } \ + void wasm_##name##_set_host_info(wasm_##name##_t* ref, void* info) { \ + ref->I->set_host_info(info); \ + } \ + void wasm_##name##_set_host_info_with_finalizer( \ + wasm_##name##_t* ref, void* info, void (*finalizer)(void*)) { \ + ref->I->set_host_info(info); \ + ref->I->set_finalizer([=](Object* o) { finalizer(o->host_info()); }); \ } #define WASM_IMPL_REF(name) \ @@ -1383,17 +1192,17 @@ WASM_IMPL_REF(memory); WASM_IMPL_REF(table); WASM_IMPL_REF(trap); -#define WASM_IMPL_SHARABLE_REF(name) \ - WASM_IMPL_REF(name) \ - WASM_IMPL_OWN(shared_##name) \ - wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t* t) { \ - return static_cast<wasm_shared_##name##_t*>( \ - const_cast<wasm_##name##_t*>(t)); \ - } \ - wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, \ - const wasm_shared_##name##_t* t) { \ - return static_cast<wasm_##name##_t*>( \ - const_cast<wasm_shared_##name##_t*>(t)); \ +#define WASM_IMPL_SHARABLE_REF(name) \ + WASM_IMPL_REF(name) \ + WASM_IMPL_OWN(shared_##name) \ + own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t* t) { \ + return static_cast<wasm_shared_##name##_t*>( \ + const_cast<wasm_##name##_t*>(t)); \ + } \ + own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, \ + const wasm_shared_##name##_t* t) { \ + return static_cast<wasm_##name##_t*>( \ + const_cast<wasm_shared_##name##_t*>(t)); \ } WASM_IMPL_SHARABLE_REF(module) |