diff --git a/BUILD b/BUILD index 840ccd3a2..74e861df9 100644 --- a/BUILD +++ b/BUILD @@ -23,8 +23,9 @@ cc_library( "src/**/*.h", ], exclude = [ - "src/**/wavm*", "src/**/v8*", + "src/**/wamr*", + "src/**/wavm*", ], ), hdrs = glob(["src/**/*.h"]), diff --git a/WORKSPACE b/WORKSPACE index 77ecd3a0b..2008efc3e 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -7,3 +7,7 @@ proxy_wasm_cpp_host_repositories() load("@proxy_wasm_cpp_host//bazel:dependencies.bzl", "proxy_wasm_cpp_host_dependencies") proxy_wasm_cpp_host_dependencies() + +load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") + +rules_foreign_cc_dependencies() diff --git a/bazel/external/wamr.BUILD b/bazel/external/wamr.BUILD new file mode 100644 index 000000000..f1d82a061 --- /dev/null +++ b/bazel/external/wamr.BUILD @@ -0,0 +1,25 @@ +licenses(["notice"]) # Apache 2 + +load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake") + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "srcs", + srcs = glob(["**"]), + visibility = ["//visibility:public"], +) + +cmake( + name = "libiwasm", + cache_entries = { + "WAMR_BUILD_INTERP": "1", + "WAMR_BUILD_JIT": "0", + "WAMR_BUILD_AOT": "0", + "WAMR_BUILD_SIMD": "0", + "WAMR_BUILD_MULTI_MODULE": "1", + "WAMR_BUILD_LIBC_WASI": "0", + }, + lib_source = ":srcs", + out_shared_libs = ["libiwasm.so"], +) diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index 280368494..d87c8fbbd 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -36,6 +36,14 @@ def proxy_wasm_cpp_host_repositories(): urls = ["https://github.com/google/googletest/archive/release-1.10.0.tar.gz"], ) + http_archive( + name = "wamr", + build_file = "@proxy_wasm_cpp_host//bazel/external:wamr.BUILD", + sha256 = "1d870f396bb6bdcb5c816326655b19a2877bbdf879255c335b8e84ce4ee37780", + strip_prefix = "wasm-micro-runtime-9710d9325f426121cc1f2c62386a71d0c022d613", + url = "https://github.com/bytecodealliance/wasm-micro-runtime/archive/9710d9325f426121cc1f2c62386a71d0c022d613.tar.gz", + ) + http_archive( name = "wasmtime", build_file = "@proxy_wasm_cpp_host//bazel/external:wasmtime.BUILD", @@ -65,3 +73,10 @@ def proxy_wasm_cpp_host_repositories(): strip_prefix = "protobuf-655310ca192a6e3a050e0ca0b7084a2968072260", url = "https://github.com/protocolbuffers/protobuf/archive/655310ca192a6e3a050e0ca0b7084a2968072260.tar.gz", ) + + http_archive( + name = "rules_foreign_cc", + sha256 = "d54742ffbdc6924f222d2179f0e10e911c5c659c4ae74158e9fe827aad862ac6", + strip_prefix = "rules_foreign_cc-0.2.0", + url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.2.0.tar.gz", + ) diff --git a/include/proxy-wasm/wamr.h b/include/proxy-wasm/wamr.h new file mode 100644 index 000000000..98ff72e31 --- /dev/null +++ b/include/proxy-wasm/wamr.h @@ -0,0 +1,26 @@ +// Copyright 2016-2019 Envoy Project Authors +// Copyright 2020 Google LLC +// +// 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. + +#pragma once + +#include + +#include "include/proxy-wasm/wasm_vm.h" + +namespace proxy_wasm { + +std::unique_ptr createWamrVm(); + +} // namespace proxy_wasm diff --git a/src/wamr/types.h b/src/wamr/types.h new file mode 100644 index 000000000..4ea9c4fb4 --- /dev/null +++ b/src/wamr/types.h @@ -0,0 +1,45 @@ +// Copyright 2020 Google LLC +// +// 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/common/types.h" +#include "wasm_c_api.h" + +namespace proxy_wasm { +namespace wamr { + +using WasmEnginePtr = common::CSmartPtr; +using WasmFuncPtr = common::CSmartPtr; +using WasmStorePtr = common::CSmartPtr; +using WasmModulePtr = common::CSmartPtr; +using WasmMemoryPtr = common::CSmartPtr; +using WasmTablePtr = common::CSmartPtr; +using WasmInstancePtr = common::CSmartPtr; +using WasmFunctypePtr = common::CSmartPtr; +using WasmTrapPtr = common::CSmartPtr; +using WasmExternPtr = common::CSmartPtr; + +using WasmByteVec = + common::CSmartType; +using WasmImporttypeVec = common::CSmartType; +using WasmExportTypeVec = common::CSmartType; +using WasmExternVec = + common::CSmartType; +using WasmValtypeVec = + common::CSmartType; + +} // namespace wamr + +} // namespace proxy_wasm diff --git a/src/wamr/wamr.cc b/src/wamr/wamr.cc new file mode 100644 index 000000000..5cc63f06b --- /dev/null +++ b/src/wamr/wamr.cc @@ -0,0 +1,631 @@ +// Copyright 2016-2019 Envoy Project Authors +// Copyright 2020 Google LLC +// +// 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 "include/proxy-wasm/wamr.h" +#include "include/proxy-wasm/wasm_vm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/wamr/types.h" +#include "wasm_c_api.h" +#include "src/common/bytecode_util.h" + +namespace proxy_wasm { +namespace wamr { + +struct HostFuncData { + HostFuncData(std::string name) : name_(std::move(name)) {} + + std::string name_; + WasmFuncPtr callback_; + void *raw_func_; + WasmVm *vm_; +}; + +using HostFuncDataPtr = std::unique_ptr; + +wasm_engine_t *engine() { + static const auto engine = WasmEnginePtr(wasm_engine_new()); + return engine.get(); +} + +class Wamr : public WasmVm { +public: + Wamr() {} + + std::string_view runtime() override { return "wamr"; } + std::string_view getPrecompiledSectionName() override { return ""; } + + Cloneable cloneable() override { return Cloneable::NotCloneable; } + std::unique_ptr clone() override { return nullptr; } + + AbiVersion getAbiVersion() override; + + bool load(const std::string &code, bool allow_precompiled = false) override; + bool link(std::string_view debug_name) override; + uint64_t getMemorySize() override; + std::optional getMemory(uint64_t pointer, uint64_t size) override; + bool setMemory(uint64_t pointer, uint64_t size, const void *data) override; + bool getWord(uint64_t pointer, Word *word) override; + bool setWord(uint64_t pointer, Word word) override; + size_t getWordSize() override { return sizeof(uint32_t); }; + +#define _REGISTER_HOST_FUNCTION(T) \ + void registerCallback(std::string_view module_name, std::string_view function_name, T, \ + typename ConvertFunctionTypeWordToUint32::type f) override { \ + registerHostFunctionImpl(module_name, function_name, f); \ + }; + FOR_ALL_WASM_VM_IMPORTS(_REGISTER_HOST_FUNCTION) +#undef _REGISTER_HOST_FUNCTION + +#define _GET_MODULE_FUNCTION(T) \ + void getFunction(std::string_view function_name, T *f) override { \ + getModuleFunctionImpl(function_name, f); \ + }; + FOR_ALL_WASM_VM_EXPORTS(_GET_MODULE_FUNCTION) +#undef _GET_MODULE_FUNCTION +private: + template + void registerHostFunctionImpl(std::string_view module_name, std::string_view function_name, + void (*function)(void *, Args...)); + + template + void registerHostFunctionImpl(std::string_view module_name, std::string_view function_name, + R (*function)(void *, Args...)); + + template + void getModuleFunctionImpl(std::string_view function_name, + std::function *function); + + template + void getModuleFunctionImpl(std::string_view function_name, + std::function *function); + + WasmStorePtr store_; + WasmModulePtr module_; + WasmInstancePtr instance_; + + WasmMemoryPtr memory_; + WasmTablePtr table_; + + std::unordered_map host_functions_; + std::unordered_map module_functions_; + AbiVersion abi_version_; +}; + +bool Wamr::load(const std::string &code, bool allow_precompiled) { + store_ = wasm_store_new(engine()); + + // Get ABI version from bytecode. + if (!common::BytecodeUtil::getAbiVersion(code, abi_version_)) { + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); + return false; + } + + std::string stripped; + if (!common::BytecodeUtil::getStrippedSource(code, stripped)) { + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); + return false; + }; + + WasmByteVec stripped_vec; + wasm_byte_vec_new(stripped_vec.get(), stripped.size(), stripped.data()); + module_ = wasm_module_new(store_.get(), stripped_vec.get()); + + return module_ != nullptr; +} + +static bool equalValTypes(const wasm_valtype_vec_t *left, const wasm_valtype_vec_t *right) { + if (left->size != right->size) { + return false; + } + + for (size_t i = 0; i < left->size; i++) { + if (wasm_valtype_kind(left->data[i]) != wasm_valtype_kind(right->data[i])) { + return false; + } + } + + return true; +} + +static std::string printValue(const wasm_val_t &value) { + switch (value.kind) { + case WASM_I32: + return std::to_string(value.of.i32); + case WASM_I64: + return std::to_string(value.of.i64); + case WASM_F32: + return std::to_string(value.of.f32); + case WASM_F64: + return std::to_string(value.of.f64); + default: + return "unknown"; + } +} + +static std::string printValues(const wasm_val_t values[], size_t size) { + if (size == 0) { + return ""; + } + + std::string s; + for (size_t i = 0; i < size; i++) { + if (i) { + s.append(", "); + } + s.append(printValue(values[i])); + } + return s; +} + +static const char *printValKind(wasm_valkind_t kind) { + switch (kind) { + case WASM_I32: + return "i32"; + case WASM_I64: + return "i64"; + case WASM_F32: + return "f32"; + case WASM_F64: + return "f64"; + case WASM_ANYREF: + return "anyref"; + case WASM_FUNCREF: + return "funcref"; + default: + return "unknown"; + } +} + +static std::string printValTypes(const wasm_valtype_vec_t *types) { + if (types->size == 0) { + return "void"; + } + + std::string s; + s.reserve(types->size * 8 /* max size + " " */ - 1); + for (size_t i = 0; i < types->size; i++) { + if (i) { + s.append(" "); + } + s.append(printValKind(wasm_valtype_kind(types->data[i]))); + } + return s; +} + +bool Wamr::link(std::string_view debug_name) { + assert(module_ != nullptr); + + WasmImporttypeVec import_types; + wasm_module_imports(module_.get(), import_types.get()); + + std::vector imports; + for (size_t i = 0; i < import_types.get()->size; i++) { + const wasm_name_t *module_name_ptr = wasm_importtype_module(import_types.get()->data[i]); + const wasm_name_t *name_ptr = wasm_importtype_name(import_types.get()->data[i]); + const wasm_externtype_t *extern_type = wasm_importtype_type(import_types.get()->data[i]); + + std::string_view module_name(module_name_ptr->data, module_name_ptr->size); + std::string_view name(name_ptr->data, name_ptr->size); + assert(name_ptr->size > 0); + switch (wasm_externtype_kind(extern_type)) { + case WASM_EXTERN_FUNC: { + auto it = host_functions_.find(std::string(module_name) + "." + std::string(name)); + if (it == host_functions_.end()) { + fail(FailState::UnableToInitializeCode, + std::string("Failed to load Wasm module due to a missing import: ") + + std::string(module_name) + "." + std::string(name)); + break; + } + + auto func = it->second->callback_.get(); + const wasm_functype_t *exp_type = wasm_externtype_as_functype_const(extern_type); + WasmFunctypePtr actual_type = wasm_func_type(it->second->callback_.get()); + if (!equalValTypes(wasm_functype_params(exp_type), wasm_functype_params(actual_type.get())) || + !equalValTypes(wasm_functype_results(exp_type), + wasm_functype_results(actual_type.get()))) { + fail( + FailState::UnableToInitializeCode, + std::string("Failed to load Wasm module due to an import type mismatch for function ") + + std::string(module_name) + "." + std::string(name) + + ", want: " + printValTypes(wasm_functype_params(exp_type)) + " -> " + + printValTypes(wasm_functype_results(exp_type)) + + ", but host exports: " + printValTypes(wasm_functype_params(actual_type.get())) + + " -> " + printValTypes(wasm_functype_results(actual_type.get()))); + break; + } + imports.push_back(wasm_func_as_extern(func)); + } break; + case WASM_EXTERN_GLOBAL: { + // TODO(mathetake): add support when/if needed. + fail(FailState::UnableToInitializeCode, + "Failed to load Wasm module due to a missing import: " + std::string(module_name) + "." + + std::string(name)); + } break; + case WASM_EXTERN_MEMORY: { + assert(memory_ == nullptr); + const wasm_memorytype_t *memory_type = + wasm_externtype_as_memorytype_const(extern_type); // owned by `extern_type` + memory_ = wasm_memory_new(store_.get(), memory_type); + imports.push_back(wasm_memory_as_extern(memory_.get())); + } break; + case WASM_EXTERN_TABLE: { + assert(table_ == nullptr); + const wasm_tabletype_t *table_type = + wasm_externtype_as_tabletype_const(extern_type); // owned by `extern_type` + table_ = wasm_table_new(store_.get(), table_type, nullptr); + imports.push_back(wasm_table_as_extern(table_.get())); + } break; + } + } + + if (import_types.get()->size != imports.size()) { + return false; + } + + instance_ = wasm_instance_new(store_.get(), module_.get(), imports.data(), nullptr); + assert(instance_ != nullptr); + + WasmExportTypeVec export_types; + wasm_module_exports(module_.get(), export_types.get()); + + WasmExternVec exports; + wasm_instance_exports(instance_.get(), exports.get()); + + for (size_t i = 0; i < export_types.get()->size; i++) { + const wasm_externtype_t *exp_extern_type = wasm_exporttype_type(export_types.get()->data[i]); + wasm_extern_t *actual_extern = exports.get()->data[i]; + + wasm_externkind_t kind = wasm_extern_kind(actual_extern); + assert(kind == wasm_externtype_kind(exp_extern_type)); + switch (kind) { + case WASM_EXTERN_FUNC: { + WasmFuncPtr func = wasm_func_copy(wasm_extern_as_func(actual_extern)); + const wasm_name_t *name_ptr = wasm_exporttype_name(export_types.get()->data[i]); + module_functions_.insert_or_assign(std::string(name_ptr->data, name_ptr->size), + std::move(func)); + } break; + case WASM_EXTERN_GLOBAL: { + // TODO(mathetake): add support when/if needed. + } break; + case WASM_EXTERN_MEMORY: { + assert(memory_ == nullptr); + memory_ = wasm_memory_copy(wasm_extern_as_memory(actual_extern)); + assert(memory_ != nullptr); + } break; + case WASM_EXTERN_TABLE: { + // TODO(mathetake): add support when/if needed. + } break; + } + } + return true; +} + +uint64_t Wamr::getMemorySize() { return wasm_memory_data_size(memory_.get()); } + +std::optional Wamr::getMemory(uint64_t pointer, uint64_t size) { + assert(memory_ != nullptr); + if (pointer + size > wasm_memory_data_size(memory_.get())) { + return std::nullopt; + } + return std::string_view(wasm_memory_data(memory_.get()) + pointer, size); +} + +bool Wamr::setMemory(uint64_t pointer, uint64_t size, const void *data) { + assert(memory_ != nullptr); + if (pointer + size > wasm_memory_data_size(memory_.get())) { + return false; + } + ::memcpy(wasm_memory_data(memory_.get()) + pointer, data, size); + return true; +} + +bool Wamr::getWord(uint64_t pointer, Word *word) { + assert(memory_ != nullptr); + constexpr auto size = sizeof(uint32_t); + if (pointer + size > wasm_memory_data_size(memory_.get())) { + return false; + } + + uint32_t word32; + ::memcpy(&word32, wasm_memory_data(memory_.get()) + pointer, size); + word->u64_ = word32; + return true; +} + +bool Wamr::setWord(uint64_t pointer, Word word) { + constexpr auto size = sizeof(uint32_t); + if (pointer + size > wasm_memory_data_size(memory_.get())) { + return false; + } + uint32_t word32 = word.u32(); + ::memcpy(wasm_memory_data(memory_.get()) + pointer, &word32, size); + return true; +} + +template void assignVal(T t, wasm_val_t &val); +template <> void assignVal(Word t, wasm_val_t &val) { + val.kind = WASM_I32; + val.of.i32 = static_cast(t.u64_); +} +template <> void assignVal(uint32_t t, wasm_val_t &val) { + val.kind = WASM_I32; + val.of.i32 = static_cast(t); +} +template <> void assignVal(uint64_t t, wasm_val_t &val) { + val.kind = WASM_I64; + val.of.i64 = static_cast(t); +} +template <> void assignVal(double t, wasm_val_t &val) { + val.kind = WASM_F64; + val.of.f64 = t; +} + +template wasm_val_t makeVal(T t) { + wasm_val_t val{}; + assignVal(t, val); + return val; +} + +template struct ConvertWordType { + using type = T; // NOLINT(readability-identifier-naming) +}; +template <> struct ConvertWordType { + using type = uint32_t; // NOLINT(readability-identifier-naming) +}; + +template auto convertArgToValTypePtr(); +template <> auto convertArgToValTypePtr() { return wasm_valtype_new_i32(); }; +template <> auto convertArgToValTypePtr() { return wasm_valtype_new_i32(); }; +template <> auto convertArgToValTypePtr() { return wasm_valtype_new_i64(); }; +template <> auto convertArgToValTypePtr() { return wasm_valtype_new_i64(); }; +template <> auto convertArgToValTypePtr() { return wasm_valtype_new_f64(); }; + +template T convertValueTypeToArg(wasm_val_t val); +template <> uint32_t convertValueTypeToArg(wasm_val_t val) { + return static_cast(val.of.i32); +} +template <> Word convertValueTypeToArg(wasm_val_t val) { return val.of.i32; } +template <> int64_t convertValueTypeToArg(wasm_val_t val) { return val.of.i64; } +template <> uint64_t convertValueTypeToArg(wasm_val_t val) { + return static_cast(val.of.i64); +} +template <> double convertValueTypeToArg(wasm_val_t val) { return val.of.f64; } + +template +constexpr T convertValTypesToArgsTupleImpl(const U &arr, std::index_sequence) { + return std::make_tuple( + convertValueTypeToArg>::type>(arr[I])...); +} + +template ::value>> +constexpr T convertValTypesToArgsTuple(const U &arr) { + return convertValTypesToArgsTupleImpl(arr, Is()); +} + +template +void convertArgsTupleToValTypesImpl(wasm_valtype_vec_t *types, std::index_sequence) { + auto size = std::tuple_size::value; + auto ps = std::array::value>{ + convertArgToValTypePtr::type>()...}; + wasm_valtype_vec_new(types, size, ps.data()); +} + +template ::value>> +void convertArgsTupleToValTypes(wasm_valtype_vec_t *types) { + convertArgsTupleToValTypesImpl(types, Is()); +} + +template WasmFunctypePtr newWasmNewFuncType() { + wasm_valtype_vec_t params, results; + convertArgsTupleToValTypes(¶ms); + convertArgsTupleToValTypes>(&results); + return wasm_functype_new(¶ms, &results); +} + +template WasmFunctypePtr newWasmNewFuncType() { + wasm_valtype_vec_t params, results; + convertArgsTupleToValTypes(¶ms); + convertArgsTupleToValTypes>(&results); + return wasm_functype_new(¶ms, &results); +} + +template +void Wamr::registerHostFunctionImpl(std::string_view module_name, std::string_view function_name, + void (*function)(void *, Args...)) { + auto data = + std::make_unique(std::string(module_name) + "." + std::string(function_name)); + + WasmFunctypePtr type = newWasmNewFuncType>(); + WasmFuncPtr func = wasm_func_new_with_env( + store_.get(), type.get(), + [](void *data, const wasm_val_t params[], wasm_val_t results[]) -> wasm_trap_t * { + auto func_data = reinterpret_cast(data); + const bool log = func_data->vm_->cmpLogLevel(LogLevel::trace); + if (log) { + func_data->vm_->integration()->trace("[vm->host] " + func_data->name_ + "(" + + printValues(params, sizeof...(Args)) + ")"); + } + auto args_tuple = convertValTypesToArgsTuple>(params); + auto args = std::tuple_cat(std::make_tuple(current_context_), args_tuple); + auto fn = reinterpret_cast(func_data->raw_func_); + std::apply(fn, args); + if (log) { + func_data->vm_->integration()->trace("[vm<-host] " + func_data->name_ + " return: void"); + } + return nullptr; + }, + data.get(), nullptr); + + data->vm_ = this; + data->callback_ = std::move(func); + data->raw_func_ = reinterpret_cast(function); + host_functions_.insert_or_assign(std::string(module_name) + "." + std::string(function_name), + std::move(data)); +}; + +template +void Wamr::registerHostFunctionImpl(std::string_view module_name, std::string_view function_name, + R (*function)(void *, Args...)) { + auto data = + std::make_unique(std::string(module_name) + "." + std::string(function_name)); + WasmFunctypePtr type = newWasmNewFuncType>(); + WasmFuncPtr func = wasm_func_new_with_env( + store_.get(), type.get(), + [](void *data, const wasm_val_t params[], wasm_val_t results[]) -> wasm_trap_t * { + auto func_data = reinterpret_cast(data); + const bool log = func_data->vm_->cmpLogLevel(LogLevel::trace); + if (log) { + func_data->vm_->integration()->trace("[vm->host] " + func_data->name_ + "(" + + printValues(params, sizeof...(Args)) + ")"); + } + auto args_tuple = convertValTypesToArgsTuple>(params); + auto args = std::tuple_cat(std::make_tuple(current_context_), args_tuple); + auto fn = reinterpret_cast(func_data->raw_func_); + R res = std::apply(fn, args); + assignVal(res, results[0]); + if (log) { + func_data->vm_->integration()->trace("[vm<-host] " + func_data->name_ + + " return: " + std::to_string(res)); + } + return nullptr; + }, + data.get(), nullptr); + + data->vm_ = this; + data->callback_ = std::move(func); + data->raw_func_ = reinterpret_cast(function); + host_functions_.insert_or_assign(std::string(module_name) + "." + std::string(function_name), + std::move(data)); +}; + +template +void Wamr::getModuleFunctionImpl(std::string_view function_name, + std::function *function) { + + auto it = module_functions_.find(std::string(function_name)); + if (it == module_functions_.end()) { + *function = nullptr; + return; + } + + WasmValtypeVec exp_args, exp_returns; + convertArgsTupleToValTypes>(exp_args.get()); + convertArgsTupleToValTypes>(exp_returns.get()); + wasm_func_t *func = it->second.get(); + WasmFunctypePtr func_type = wasm_func_type(func); + + if (!equalValTypes(wasm_functype_params(func_type.get()), exp_args.get()) || + !equalValTypes(wasm_functype_results(func_type.get()), exp_returns.get())) { + fail(FailState::UnableToInitializeCode, + "Bad function signature for: " + std::string(function_name) + ", want: " + + printValTypes(exp_args.get()) + " -> " + printValTypes(exp_returns.get()) + + ", but the module exports: " + printValTypes(wasm_functype_params(func_type.get())) + + " -> " + printValTypes(wasm_functype_results(func_type.get()))); + return; + } + + *function = [func, function_name, this](ContextBase *context, Args... args) -> void { + wasm_val_t params[] = {makeVal(args)...}; + const bool log = cmpLogLevel(LogLevel::trace); + if (log) { + integration()->trace("[host->vm] " + std::string(function_name) + "(" + + printValues(params, sizeof...(Args)) + ")"); + } + SaveRestoreContext saved_context(context); + WasmTrapPtr trap{wasm_func_call(func, params, nullptr)}; + if (trap) { + WasmByteVec error_message; + wasm_trap_message(trap.get(), error_message.get()); + fail(FailState::RuntimeError, + "Function: " + std::string(function_name) + " failed:\n" + + std::string(error_message.get()->data, error_message.get()->size)); + return; + } + if (log) { + integration()->trace("[host<-vm] " + std::string(function_name) + " return: void"); + } + }; +}; + +template +void Wamr::getModuleFunctionImpl(std::string_view function_name, + std::function *function) { + auto it = module_functions_.find(std::string(function_name)); + if (it == module_functions_.end()) { + *function = nullptr; + return; + } + WasmValtypeVec exp_args, exp_returns; + convertArgsTupleToValTypes>(exp_args.get()); + convertArgsTupleToValTypes>(exp_returns.get()); + wasm_func_t *func = it->second.get(); + WasmFunctypePtr func_type = wasm_func_type(func); + if (!equalValTypes(wasm_functype_params(func_type.get()), exp_args.get()) || + !equalValTypes(wasm_functype_results(func_type.get()), exp_returns.get())) { + fail(FailState::UnableToInitializeCode, + "Bad function signature for: " + std::string(function_name) + ", want: " + + printValTypes(exp_args.get()) + " -> " + printValTypes(exp_returns.get()) + + ", but the module exports: " + printValTypes(wasm_functype_params(func_type.get())) + + " -> " + printValTypes(wasm_functype_results(func_type.get()))); + return; + } + + *function = [func, function_name, this](ContextBase *context, Args... args) -> R { + wasm_val_t params[] = {makeVal(args)...}; + wasm_val_t results[1]; + const bool log = cmpLogLevel(LogLevel::trace); + if (log) { + integration()->trace("[host->vm] " + std::string(function_name) + "(" + + printValues(params, sizeof...(Args)) + ")"); + } + SaveRestoreContext saved_context(context); + WasmTrapPtr trap{wasm_func_call(func, params, results)}; + if (trap) { + WasmByteVec error_message; + wasm_trap_message(trap.get(), error_message.get()); + fail(FailState::RuntimeError, + "Function: " + std::string(function_name) + " failed:\n" + + std::string(error_message.get()->data, error_message.get()->size)); + return R{}; + } + R ret = convertValueTypeToArg(results[0]); + if (log) { + integration()->trace("[host<-vm] " + std::string(function_name) + + " return: " + std::to_string(ret)); + } + return ret; + }; +}; + +AbiVersion Wamr::getAbiVersion() { return abi_version_; } + +} // namespace wamr + +std::unique_ptr createWamrVm() { return std::make_unique(); } + +} // namespace proxy_wasm diff --git a/test/utility.cc b/test/utility.cc index e55a5773c..5b999c0c4 100644 --- a/test/utility.cc +++ b/test/utility.cc @@ -26,6 +26,9 @@ std::vector getRuntimes() { #endif #if defined(WASM_WASMTIME) "wasmtime", +#endif +#if defined(WASM_WAMR) + "wamr", #endif "" }; diff --git a/test/utility.h b/test/utility.h index 22a86f1f0..05ed1cf59 100644 --- a/test/utility.h +++ b/test/utility.h @@ -32,6 +32,9 @@ #if defined(WASM_WASMTIME) #include "include/proxy-wasm/wasmtime.h" #endif +#if defined(WASM_WAMR) +#include "include/proxy-wasm/wamr.h" +#endif namespace proxy_wasm { @@ -79,6 +82,10 @@ class TestVM : public testing::TestWithParam { #if defined(WASM_WASMTIME) } else if (runtime_ == "wasmtime") { vm_ = proxy_wasm::createWasmtimeVm(); +#endif +#if defined(WASM_WAMR) + } else if (runtime_ == "wamr") { + vm_ = proxy_wasm::createWamrVm(); #endif } vm_->integration().reset(integration_);