summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interp/binary-reader-interp.cc102
-rw-r--r--src/interp/binary-reader-interp.h12
-rw-r--r--src/interp/binary-reader-metadata.cc74
-rw-r--r--src/interp/binary-reader-metadata.h43
-rw-r--r--src/interp/interp-wasm-c-api.cc1432
-rw-r--r--src/interp/interp.h7
6 files changed, 1627 insertions, 43 deletions
diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc
index 5312e78b..fc40bc67 100644
--- a/src/interp/binary-reader-interp.cc
+++ b/src/interp/binary-reader-interp.cc
@@ -60,6 +60,7 @@ class BinaryReaderInterp : public BinaryReaderNop {
BinaryReaderInterp(Environment* env,
DefinedModule* module,
std::unique_ptr<OutputBuffer> istream,
+ const std::vector<Export*>& imports_,
Errors* errors,
const Features& features);
@@ -323,11 +324,15 @@ class BinaryReaderInterp : public BinaryReaderNop {
string_view name);
wabt::Result FindRegisteredModule(string_view module_name,
Module** out_module);
- wabt::Result GetModuleExport(Module* module,
- string_view field_name,
- Export** out_export);
+ wabt::Result ResolveImport(Index import_index,
+ ExternalKind kind,
+ string_view module_name,
+ string_view field_name,
+ Index sig_index,
+ Export** out_export);
Features features_;
+ const std::vector<Export*>& imports_;
Errors* errors_ = nullptr;
Environment* env_ = nullptr;
DefinedModule* module_ = nullptr;
@@ -363,9 +368,11 @@ class BinaryReaderInterp : public BinaryReaderNop {
BinaryReaderInterp::BinaryReaderInterp(Environment* env,
DefinedModule* module,
std::unique_ptr<OutputBuffer> istream,
+ const std::vector<Export*>& imports,
Errors* errors,
const Features& features)
: features_(features),
+ imports_(imports),
errors_(errors),
env_(env),
module_(module),
@@ -765,16 +772,35 @@ wabt::Result BinaryReaderInterp::FindRegisteredModule(string_view module_name,
return wabt::Result::Ok;
}
-wabt::Result BinaryReaderInterp::GetModuleExport(Module* module,
- string_view field_name,
- Export** out_export) {
- Export* export_ = module->GetExport(field_name);
- if (!export_) {
- PrintError("unknown module field \"" PRIstringview "\"",
- WABT_PRINTF_STRING_VIEW_ARG(field_name));
- return wabt::Result::Error;
+wabt::Result BinaryReaderInterp::ResolveImport(Index import_index,
+ ExternalKind kind,
+ string_view module_name,
+ string_view field_name,
+ Index sig_index,
+ Export** out_export) {
+ Export* export_ = nullptr;
+ if (!imports_.empty()) {
+ export_ = imports_[import_index];
+ } else {
+ Module* module;
+ CHECK_RESULT(FindRegisteredModule(module_name, &module));
+
+ // Func imports get special handled due to the face that they can be
+ // overloaded on signature.
+ if (kind == ExternalKind::Func) {
+ export_ = module->GetFuncExport(env_, field_name, sig_index);
+ }
+ if (!export_) {
+ export_ = module->GetExport(field_name);
+ if (!export_) {
+ PrintError("unknown module field \"" PRIstringview "\"",
+ WABT_PRINTF_STRING_VIEW_ARG(field_name));
+ return wabt::Result::Error;
+ }
+ }
}
+ CHECK_RESULT(CheckImportKind(module_name, field_name, kind, export_->kind));
*out_export = export_;
return wabt::Result::Ok;
}
@@ -786,20 +812,9 @@ wabt::Result BinaryReaderInterp::OnImportFunc(Index import_index,
Index sig_index) {
Index env_sig_index = TranslateSigIndexToEnv(sig_index);
- Module* import_module;
- CHECK_RESULT(FindRegisteredModule(module_name, &import_module));
-
- Export* export_ =
- import_module->GetFuncExport(env_, field_name, env_sig_index);
- if (!export_) {
- // If GetFuncExport fails then GetModuleExport will fail too. But it's
- // useful to call here to share the same error handling code as other
- // imports.
- CHECK_RESULT(GetModuleExport(import_module, field_name, &export_));
- }
-
- CHECK_RESULT(CheckImportKind(module_name, field_name, ExternalKind::Func,
- export_->kind));
+ Export* export_;
+ CHECK_RESULT(ResolveImport(import_index, ExternalKind::Func, module_name,
+ field_name, env_sig_index, &export_));
Func* func = env_->GetFunc(export_->index);
if (!env_->FuncSignaturesAreEqual(env_sig_index, func->sig_index)) {
@@ -819,12 +834,9 @@ wabt::Result BinaryReaderInterp::OnImportTable(Index import_index,
Type elem_type,
const Limits* elem_limits) {
has_table = true;
- Module* import_module;
- CHECK_RESULT(FindRegisteredModule(module_name, &import_module));
-
Export* export_;
- CHECK_RESULT(GetModuleExport(import_module, field_name, &export_));
- CHECK_RESULT(CheckImportKind(module_name, field_name, ExternalKind::Table, export_->kind));
+ CHECK_RESULT(ResolveImport(import_index, ExternalKind::Table, module_name,
+ field_name, 0, &export_));
Table* table = env_->GetTable(export_->index);
if (elem_type != table->elem_type) {
@@ -849,12 +861,9 @@ wabt::Result BinaryReaderInterp::OnImportMemory(Index import_index,
return wabt::Result::Error;
}
- Module* import_module;
- CHECK_RESULT(FindRegisteredModule(module_name, &import_module));
-
Export* export_;
- CHECK_RESULT(GetModuleExport(import_module, field_name, &export_));
- CHECK_RESULT(CheckImportKind(module_name, field_name, ExternalKind::Memory, export_->kind));
+ CHECK_RESULT(ResolveImport(import_index, ExternalKind::Memory, module_name,
+ field_name, 0, &export_));
Memory* memory = env_->GetMemory(export_->index);
CHECK_RESULT(CheckImportLimits(page_limits, &memory->page_limits));
@@ -890,18 +899,13 @@ wabt::Result BinaryReaderInterp::OnImportGlobal(Index import_index,
Index global_index,
Type type,
bool mutable_) {
- Module* import_module;
- CHECK_RESULT(FindRegisteredModule(module_name, &import_module));
-
Export* export_;
- CHECK_RESULT(GetModuleExport(import_module, field_name, &export_));
- CHECK_RESULT(CheckImportKind(module_name, field_name, ExternalKind::Global,
- export_->kind));
+ CHECK_RESULT(ResolveImport(import_index, ExternalKind::Global, module_name,
+ field_name, 0, &export_));
Global* exported_global = env_->GetGlobal(export_->index);
GlobalType expected = {type, mutable_};
GlobalType actual = {exported_global->type, exported_global->mutable_};
-
if (Failed(CheckGlobalType(actual, expected))) {
return wabt::Result::Error;
}
@@ -1932,6 +1936,7 @@ wabt::Result ReadBinaryInterp(Environment* env,
const void* data,
size_t size,
const ReadBinaryOptions& options,
+ const std::vector<Export*>& imports,
Errors* errors,
DefinedModule** out_module) {
// Need to mark before taking ownership of env->istream.
@@ -1941,7 +1946,7 @@ wabt::Result ReadBinaryInterp(Environment* env,
IstreamOffset istream_offset = istream->size();
DefinedModule* module = new DefinedModule(env);
- BinaryReaderInterp reader(env, module, std::move(istream), errors,
+ BinaryReaderInterp reader(env, module, std::move(istream), imports, errors,
options.features);
env->EmplaceBackModule(module);
@@ -1959,4 +1964,15 @@ wabt::Result ReadBinaryInterp(Environment* env,
return result;
}
+wabt::Result ReadBinaryInterp(Environment* env,
+ const void* data,
+ size_t size,
+ const ReadBinaryOptions& options,
+ Errors* errors,
+ DefinedModule** out_module) {
+ std::vector<Export*> empty_imports;
+ return ReadBinaryInterp(env, data, size, options, empty_imports, errors,
+ out_module);
+}
+
} // namespace wabt
diff --git a/src/interp/binary-reader-interp.h b/src/interp/binary-reader-interp.h
index 767b9479..e6110f5e 100644
--- a/src/interp/binary-reader-interp.h
+++ b/src/interp/binary-reader-interp.h
@@ -24,6 +24,7 @@ namespace wabt {
namespace interp {
+struct Export;
struct DefinedModule;
class Environment;
@@ -31,6 +32,7 @@ class Environment;
struct ReadBinaryOptions;
+// Read and instantiate a module in the given environment.
Result ReadBinaryInterp(interp::Environment* env,
const void* data,
size_t size,
@@ -38,6 +40,16 @@ Result ReadBinaryInterp(interp::Environment* env,
Errors*,
interp::DefinedModule** out_module);
+// Read and instantiate a module in the given environment. Similar to above but
+// using using a fixed set of exports to resolve the module exports.
+Result ReadBinaryInterp(interp::Environment* env,
+ const void* data,
+ size_t size,
+ const ReadBinaryOptions& options,
+ const std::vector<interp::Export*>& imports,
+ Errors*,
+ interp::DefinedModule** out_module);
+
} // namespace wabt
#endif /* WABT_BINARY_READER_INTERP_H_ */
diff --git a/src/interp/binary-reader-metadata.cc b/src/interp/binary-reader-metadata.cc
new file mode 100644
index 00000000..8cbed78e
--- /dev/null
+++ b/src/interp/binary-reader-metadata.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/interp/binary-reader-metadata.h"
+
+#include "src/binary-reader-nop.h"
+#include "src/binary-reader.h"
+#include "src/interp/interp.h"
+#include "src/string-view.h"
+
+namespace wabt {
+
+using namespace interp;
+
+namespace {
+
+class BinaryReaderMetadata : public BinaryReaderNop {
+ public:
+ BinaryReaderMetadata(ModuleMetadata* metadata,
+ Errors* errors,
+ const Features& features)
+ : metadata_(metadata) {}
+ wabt::Result OnImport(Index index,
+ ExternalKind kind,
+ string_view module_name,
+ string_view field_name) override {
+ metadata_->imports.emplace_back(kind, module_name, field_name);
+ return wabt::Result::Ok;
+ }
+
+ wabt::Result OnExport(Index index,
+ ExternalKind kind,
+ Index item_index,
+ string_view name) override {
+ metadata_->exports.emplace_back(name, kind, item_index);
+ return wabt::Result::Ok;
+ }
+
+ private:
+ ModuleMetadata* metadata_;
+};
+
+} // end anonymous namespace
+
+wabt::Result ReadBinaryMetadata(const void* data,
+ size_t size,
+ const ReadBinaryOptions& options,
+ Errors* errors,
+ ModuleMetadata** out_metadata) {
+ ModuleMetadata* metadata = new ModuleMetadata();
+ BinaryReaderMetadata reader(metadata, errors, options.features);
+ wabt::Result result = ReadBinary(data, size, &reader, options);
+ if (!Succeeded(result)) {
+ delete metadata;
+ return result;
+ }
+ *out_metadata = metadata;
+ return result;
+}
+
+} // namespace wabt
diff --git a/src/interp/binary-reader-metadata.h b/src/interp/binary-reader-metadata.h
new file mode 100644
index 00000000..13834560
--- /dev/null
+++ b/src/interp/binary-reader-metadata.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WABT_BINARY_READER_METADATA_H_
+#define WABT_BINARY_READER_METADATA_H_
+
+#include "src/common.h"
+#include "src/error.h"
+
+namespace wabt {
+
+namespace interp {
+
+struct ModuleMetadata;
+
+} // namespace interp
+
+struct ReadBinaryOptions;
+
+// Reads just the binary metadata, used by C-API to get module imports names
+// (and potentially other metadata) before instantiation time.
+Result ReadBinaryMetadata(const void* data,
+ size_t size,
+ const ReadBinaryOptions& options,
+ Errors*,
+ interp::ModuleMetadata** out_metadata);
+
+} // namespace wabt
+
+#endif /* WABT_BINARY_READER_METADATA_H_ */
diff --git a/src/interp/interp-wasm-c-api.cc b/src/interp/interp-wasm-c-api.cc
new file mode 100644
index 00000000..d5ff9ae3
--- /dev/null
+++ b/src/interp/interp-wasm-c-api.cc
@@ -0,0 +1,1432 @@
+/*
+ * Copyright 2020 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <wasm.h>
+
+#include "src/binary-reader.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.h"
+#include "src/ir.h"
+#include "src/stream.h"
+
+using namespace wabt;
+using namespace wabt::interp;
+
+#ifndef NDEBUG
+#define TRACE(str, ...) fprintf(stderr, "CAPI: " str, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#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;
+};
+
+struct wasm_config_t {};
+
+struct wasm_externtype_t {
+ wasm_externkind_t kind;
+
+ protected:
+ wasm_externtype_t(wasm_externkind_t kind) : kind(kind) {}
+};
+
+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_;
+};
+
+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;
+};
+
+struct wasm_importtype_t {};
+
+struct wasm_exporttype_t {
+ wasm_exporttype_t(wasm_name_t name, wasm_externtype_t* type)
+ : name(name), type(type) {}
+
+ wasm_exporttype_t(const wasm_exporttype_t& other) {
+ name = other.name;
+ type = MakeUnique<wasm_externtype_t>(*other.type.get());
+ }
+
+ wasm_name_t name;
+ std::unique_ptr<wasm_externtype_t> type;
+};
+
+struct wasm_engine_t {};
+
+struct wasm_store_t {
+ wasm_store_t(Environment* env, Executor* executor)
+ : env(env), executor(executor) {}
+
+ ~wasm_store_t() {
+ TRACE("~store\n");
+ }
+
+ Environment* env;
+ std::unique_ptr<Executor> executor;
+};
+
+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);
+ }
+ }
+
+ virtual wasm_ref_t* Copy() const { return new wasm_ref_t(kind); }
+
+ bool Same(const wasm_ref_t& other) const;
+
+ WasmRefType kind;
+ void* host_info = nullptr;
+ void (*finalizer)(void*) = nullptr;
+};
+
+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) {}
+
+ wasm_ref_t* Copy() const override { return new wasm_extern_ref_t(*this); }
+
+ bool Same(const wasm_extern_ref_t& other) const {
+ return kind == other.kind && index == other.index;
+ }
+
+ ExternalKind kind;
+ Index index;
+};
+
+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) {}
+
+ wasm_ref_t* Copy() const override { return new wasm_foreign_ref_t(*this); }
+
+ Index index;
+};
+
+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 WasmInstance {
+ WasmInstance(wasm_store_t* store, DefinedModule* module)
+ : store(store), module(module) {}
+
+ ~WasmInstance() {
+ TRACE("~WasmInstance\n");
+ }
+
+ wasm_store_t* store;
+ std::unique_ptr<DefinedModule> module;
+};
+
+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)) {}
+
+ wasm_instance_t(std::shared_ptr<WasmInstance> ptr)
+ : wasm_ref_t(WasmRefType::Instance), ptr(ptr) {}
+
+ wasm_instance_t(const wasm_instance_t& other)
+ : wasm_ref_t(other), ptr(other.ptr) {}
+
+ wasm_ref_t* Copy() const override { return new wasm_instance_t(*this); }
+
+ bool Same(const wasm_instance_t& other) const { return ptr == other.ptr; }
+
+ std::shared_ptr<WasmInstance> ptr;
+};
+
+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);
+ }
+
+ bool Same(const wasm_module_t& other) const {
+ assert(false);
+ return true;
+ }
+
+ ~wasm_module_t() {
+ TRACE("~module\n");
+ wasm_byte_vec_delete(&binary);
+ }
+
+ wasm_store_t* store;
+ wasm_byte_vec_t binary;
+ std::unique_ptr<ModuleMetadata> metadata;
+};
+
+struct wasm_shared_module_t : wasm_module_t {};
+
+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;
+}
+
+struct wasm_frame_t {
+ wasm_instance_t* instance;
+ size_t offset;
+ uint32_t func_index;
+};
+
+// 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);
+}
+
+wasm_limits_t FromWabtLimits(const Limits& limits) {
+ return wasm_limits_t{(uint32_t)limits.initial, (uint32_t)limits.max};
+}
+
+// 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_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(&params, 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])};
+ }
+ }
+
+ 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(&params);
+ wasm_valtype_vec_delete(&results);
+ }
+
+ 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_valtype_vec_t params;
+ wasm_valtype_vec_t results;
+};
+
+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;
+
+ protected:
+ wasm_extern_t(std::shared_ptr<WasmInstance> instance,
+ ExternalKind kind,
+ Index index)
+ : wasm_extern_ref_t(kind, index), instance(instance) {}
+};
+
+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());
+ }
+};
+
+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_);
+ }
+};
+
+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));
+ }
+};
+
+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));
+ }
+};
+
+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;
+};
+
+// Helper functions
+
+static Type ToWabtType(wasm_valkind_t kind) {
+ switch (kind) {
+ case WASM_I32:
+ return Type::I32;
+ case WASM_I64:
+ return Type::I64;
+ case WASM_F32:
+ return Type::F32;
+ case WASM_F64:
+ return Type::F64;
+ case WASM_ANYREF:
+ return Type::Anyref;
+ case WASM_FUNCREF:
+ return Type::Funcref;
+ default:
+ TRACE("unexpected wasm_valkind_t: %d\n", kind);
+ WABT_UNREACHABLE;
+ }
+ WABT_UNREACHABLE;
+}
+
+static wasm_valkind_t FromWabtType(Type type) {
+ switch (type) {
+ case Type::I32:
+ return WASM_I32;
+ case Type::I64:
+ return WASM_I64;
+ case Type::F32:
+ return WASM_F32;
+ case Type::F64:
+ return WASM_F64;
+ case Type::Anyref:
+ return WASM_ANYREF;
+ case Type::Funcref:
+ return WASM_FUNCREF;
+ default:
+ WABT_UNREACHABLE;
+ }
+}
+
+static TypedValue ToWabtValue(const wasm_val_t& value) {
+ TypedValue out(ToWabtType(value.kind));
+ switch (value.kind) {
+ case WASM_I32:
+ out.set_i32(value.of.i32);
+ break;
+ case WASM_I64:
+ out.set_i64(value.of.i64);
+ break;
+ case WASM_F32:
+ out.set_f32(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});
+ 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;
+ break;
+ }
+ default:
+ TRACE("unexpected wasm type: %d\n", value.kind);
+ assert(false);
+ }
+ TRACE("ToWabtValue -> %s\n", 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());
+ wasm_val_t out_value;
+ switch (value.type) {
+ case Type::I32:
+ out_value.kind = WASM_I32;
+ out_value.of.i32 = value.get_i32();
+ break;
+ case Type::I64:
+ out_value.kind = WASM_I64;
+ out_value.of.i64 = value.get_i64();
+ break;
+ case Type::F32:
+ out_value.kind = WASM_F32;
+ out_value.of.f32 = value.get_f32();
+ break;
+ case Type::F64:
+ out_value.kind = WASM_F64;
+ out_value.of.f64 = value.get_f64();
+ break;
+ 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;
+ break;
+ default:
+ TRACE("unexpected wabt type: %d\n", static_cast<int>(value.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 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;
+ }
+ WABT_UNREACHABLE;
+}
+
+static ReadBinaryOptions GetOptions() {
+ const bool kReadDebugNames = true;
+ const bool kStopOnFirstError = true;
+ const bool kFailOnCustomSectionError = true;
+ s_features.EnableAll();
+ if (getenv("WASM_API_DEBUG") != nullptr) {
+ s_log_stream = FileStream::CreateStdout();
+ }
+ return ReadBinaryOptions(s_features, s_log_stream.get(), kReadDebugNames,
+ kStopOnFirstError, kFailOnCustomSectionError);
+}
+
+extern "C" {
+
+// wasm_valtype
+
+wasm_valtype_t* wasm_valtype_new(wasm_valkind_t kind) {
+ return new wasm_valtype_t{kind};
+}
+
+wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t* type) {
+ assert(type);
+ return type->kind;
+}
+
+// Helpers
+
+static void print_sig(const interp::FuncSignature& sig) {
+#ifndef NDEBUG
+ fprintf(stderr, "(");
+ bool first = true;
+ for (auto Type : sig.param_types) {
+ if (!first) {
+ fprintf(stderr, ", ");
+ }
+ first = false;
+ fprintf(stderr, "%s", GetTypeName(Type));
+ }
+ fprintf(stderr, ") -> (");
+ first = true;
+ for (auto Type : sig.result_types) {
+ if (!first) {
+ fprintf(stderr, ", ");
+ }
+ first = false;
+ fprintf(stderr, "%s", GetTypeName(Type));
+ }
+ fprintf(stderr, ")\n");
+#endif
+}
+
+// wasm_val
+
+void wasm_val_delete(wasm_val_t* val) {
+ assert(val);
+ if (wasm_valkind_is_ref(val->kind)) {
+ delete val->of.ref;
+ val->of.ref = nullptr;
+ }
+}
+
+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());
+}
+
+// wasm_trap
+
+wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t* msg) {
+ return new wasm_trap_t(msg);
+}
+
+void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) {
+ assert(trap);
+ wasm_name_copy(out, &trap->message);
+}
+
+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) {
+ 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;
+}
+
+// wasm_engine
+
+wasm_engine_t* wasm_engine_new() {
+ return new wasm_engine_t();
+}
+
+wasm_engine_t* wasm_engine_new_with_config(wasm_config_t*) {
+ assert(false);
+ return nullptr;
+}
+
+// wasm_store
+
+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);
+}
+
+// wasm_module
+
+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)) {
+ return nullptr;
+ }
+ return new wasm_module_t(store, binary, metadata);
+}
+
+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;
+ }
+ }
+}
+
+void wasm_module_serialize(const wasm_module_t* module, 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) {
+ 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};
+}
+
+const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t* ex) {
+ return &ex->name;
+}
+
+const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* ex) {
+ TRACE("wasm_exporttype_type %p\n", ex);
+ assert(ex);
+ return ex->type.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);
+ 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);
+ }
+
+ 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");
+ 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);
+}
+
+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;
+ }
+ }
+}
+
+// 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);
+ return res;
+}
+
+const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t* f) {
+ TRACE("wasm_functype_params: %" PRIzx "\n", f->params.size);
+ return &f->params;
+}
+
+const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t* f) {
+ return &f->results;
+}
+
+// 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);
+ }
+ if (trap) {
+ TRACE("host function trapped\n");
+ delete[] host_args;
+ delete[] host_results;
+ return interp::ResultType::TrapHostTrapped;
+ }
+ 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;
+ };
+
+ 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);
+}
+
+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);
+}
+
+wasm_functype_t* wasm_func_type(const wasm_func_t* func) {
+ TRACE("wasm_func_type\n");
+ return new wasm_functype_t(*func->GetSig());
+}
+
+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();
+}
+
+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;
+ }
+ FromWabtValues(f->instance, results, res.values);
+ return nullptr;
+}
+
+// wasm_globaltype
+
+wasm_globaltype_t* wasm_globaltype_new(wasm_valtype_t* type,
+ wasm_mutability_t mut) {
+ assert(type);
+ return new wasm_globaltype_t(*type, mut == WASM_VAR);
+}
+
+wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t* type) {
+ assert(type);
+ return type->mutable_;
+}
+
+const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t* type) {
+ assert(type);
+ return &type->type;
+}
+
+// wasm_tabletype
+
+wasm_tabletype_t* wasm_tabletype_new(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) {
+ return &type->elemtype;
+}
+
+const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t* type) {
+ return &type->limits;
+}
+
+// wasm_memorytype
+
+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) {
+ return &t->limits;
+}
+
+// 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);
+ 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);
+}
+
+wasm_globaltype_t* wasm_global_type(const wasm_global_t* global) {
+ assert(global);
+ assert(false);
+ WABT_UNREACHABLE;
+}
+
+void wasm_global_get(const wasm_global_t* global, 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;
+}
+
+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);
+}
+
+// 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);
+}
+
+wasm_tabletype_t* wasm_table_type(const wasm_table_t*) {
+ assert(false);
+ return nullptr;
+}
+
+wasm_table_size_t wasm_table_size(const wasm_table_t* table) {
+ return table->GetTable()->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())
+ 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;
+}
+
+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_grow(wasm_table_t* t,
+ 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;
+}
+
+// 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);
+}
+
+byte_t* wasm_memory_data(wasm_memory_t* m) {
+ interp::Memory* memory = m->GetMemory();
+ return memory->data.data();
+}
+
+wasm_memory_pages_t wasm_memory_size(const wasm_memory_t* m) {
+ interp::Memory* memory = m->GetMemory();
+ return memory->data.size() / WABT_PAGE_SIZE;
+}
+
+size_t wasm_memory_data_size(const wasm_memory_t* m) {
+ interp::Memory* memory = m->GetMemory();
+ return memory->data.size();
+}
+
+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;
+}
+
+// wasm_frame
+
+wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) {
+ assert(frame);
+ return frame->instance;
+}
+
+size_t wasm_frame_module_offset(const wasm_frame_t* frame) {
+ assert(frame);
+ return frame->offset;
+}
+
+size_t wasm_frame_func_offset(const wasm_frame_t* frame) {
+ assert(false);
+ return 0;
+}
+
+uint32_t wasm_frame_func_index(const wasm_frame_t* frame) {
+ assert(frame);
+ return frame->func_index;
+}
+
+// wasm_externtype
+
+wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t* type) {
+ assert(type);
+ return type->kind;
+}
+
+// wasm_extern
+
+wasm_externtype_t* wasm_extern_type(const wasm_extern_t* extern_) {
+ return extern_->ExternType();
+}
+
+wasm_externkind_t wasm_extern_kind(const wasm_extern_t* extern_) {
+ return FromWabtExternalKind(extern_->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);
+}
+
+// vector types
+
+#define WASM_IMPL_OWN(name) \
+ void wasm_##name##_delete(wasm_##name##_t* t) { \
+ assert(t); \
+ TRACE("wasm_" #name "_delete\n"); \
+ delete t; \
+ }
+
+WASM_IMPL_OWN(frame);
+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"); \
+ wasm_##name##_vec_new_uninitialized(vec, size); \
+ memcpy(vec->data, src, size * sizeof(wasm_##name##_t ptr_or_none)); \
+ } \
+ 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_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_copy(wasm_##name##_vec_t* out, \
+ const wasm_##name##_vec_t* vec) { \
+ TRACE("wasm_" #name "_vec_copy %" PRIzx "\n", vec->size); \
+ wasm_##name##_vec_new_uninitialized(out, vec->size); \
+ memcpy(out->data, vec->data, \
+ vec->size * sizeof(wasm_##name##_t ptr_or_none)); \
+ } \
+ void wasm_##name##_vec_delete(wasm_##name##_vec_t* vec) { \
+ TRACE("wasm_" #name "_vec_delete\n"); \
+ if (vec->data) { \
+ delete vec->data; \
+ } \
+ vec->size = 0; \
+ }
+
+WASM_IMPL_VEC(byte, );
+WASM_IMPL_VEC(val, );
+WASM_IMPL_VEC(frame, *);
+WASM_IMPL_VEC(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); \
+ }
+
+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_REF(name) \
+ WASM_IMPL_REF_BASE(name) \
+ wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t* subclass) { \
+ return subclass; \
+ } \
+ wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t* ref) { \
+ return static_cast<wasm_##name##_t*>(ref); \
+ } \
+ const wasm_ref_t* wasm_##name##_as_ref_const( \
+ const wasm_##name##_t* subclass) { \
+ return subclass; \
+ } \
+ const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t* ref) { \
+ return static_cast<const wasm_##name##_t*>(ref); \
+ }
+
+WASM_IMPL_REF_BASE(ref);
+
+WASM_IMPL_REF(extern);
+WASM_IMPL_REF(foreign);
+WASM_IMPL_REF(func);
+WASM_IMPL_REF(global);
+WASM_IMPL_REF(instance);
+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)); \
+ }
+
+WASM_IMPL_SHARABLE_REF(module)
+
+#define WASM_IMPL_EXTERN(name) \
+ const wasm_##name##type_t* wasm_externtype_as_##name##type_const( \
+ const wasm_externtype_t* t) { \
+ return static_cast<const wasm_##name##type_t*>(t); \
+ } \
+ wasm_##name##type_t* wasm_externtype_as_##name##type(wasm_externtype_t* t) { \
+ return static_cast<wasm_##name##type_t*>(t); \
+ } \
+ wasm_externtype_t* wasm_##name##type_as_externtype(wasm_##name##type_t* t) { \
+ return static_cast<wasm_externtype_t*>(t); \
+ } \
+ const wasm_externtype_t* wasm_##name##type_as_externtype_const( \
+ const wasm_##name##type_t* t) { \
+ return static_cast<const wasm_externtype_t*>(t); \
+ } \
+ wasm_extern_t* wasm_##name##_as_extern(wasm_##name##_t* name) { \
+ return static_cast<wasm_extern_t*>(name); \
+ } \
+ const wasm_extern_t* wasm_##name##_as_extern_const( \
+ const wasm_##name##_t* name) { \
+ return static_cast<const wasm_extern_t*>(name); \
+ } \
+ wasm_##name##_t* wasm_extern_as_##name(wasm_extern_t* ext) { \
+ return static_cast<wasm_##name##_t*>(ext); \
+ }
+
+WASM_IMPL_EXTERN(table);
+WASM_IMPL_EXTERN(func);
+WASM_IMPL_EXTERN(global);
+WASM_IMPL_EXTERN(memory);
+
+} // extern "C"
diff --git a/src/interp/interp.h b/src/interp/interp.h
index 6d445b56..bbc1c407 100644
--- a/src/interp/interp.h
+++ b/src/interp/interp.h
@@ -342,6 +342,13 @@ struct Export {
class Environment;
+struct ModuleMetadata {
+ WABT_DISALLOW_COPY_AND_ASSIGN(ModuleMetadata);
+ ModuleMetadata() = default;
+ std::vector<Import> imports;
+ std::vector<Export> exports;
+};
+
struct Module {
WABT_DISALLOW_COPY_AND_ASSIGN(Module);
Module(Environment* env, bool is_host);