提交 60f5e3d5 编写于 作者: M Matt Witherspoon

Add a new WASM backend: wabt

Add a new WASM backend using wabt’s interpreter. This interpreter is considerably faster than the current default of binaryen — a replay on the mainnet typically completes in less than half the time compared to binaryen.
上级 2a1b0ef6
......@@ -27,3 +27,6 @@
[submodule "libraries/fc"]
path = libraries/fc
url = https://github.com/EOSIO/fc
[submodule "libraries/wabt"]
path = libraries/wabt
url = http://github.com/EOSIO/wabt
......@@ -8,3 +8,8 @@ add_subdirectory( appbase )
add_subdirectory( chain )
add_subdirectory( testing )
add_subdirectory( abi_generator )
#turn these off for now
set(BUILD_TESTS OFF CACHE BOOL "Build GTest-based tests")
set(RUN_RE2C OFF CACHE BOOL "Run re2c")
add_subdirectory( wabt )
......@@ -38,6 +38,7 @@ add_library( eosio_chain
webassembly/wavm.cpp
webassembly/binaryen.cpp
webassembly/wabt.cpp
# get_config.cpp
# global_property_object.cpp
......@@ -50,12 +51,14 @@ add_library( eosio_chain
)
target_link_libraries( eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime
wasm asmjs passes cfg ast emscripten-optimizer support softfloat builtins
wasm asmjs passes cfg ast emscripten-optimizer support softfloat builtins libwabt
)
target_include_directories( eosio_chain
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include"
"${CMAKE_CURRENT_SOURCE_DIR}/../../externals/binaryen/src"
"${CMAKE_SOURCE_DIR}/libraries/wabt"
"${CMAKE_BINARY_DIR}/libraries/wabt"
)
install( TARGETS eosio_chain
......
......@@ -54,6 +54,7 @@ namespace eosio { namespace chain {
enum class vm_type {
wavm,
binaryen,
wabt
};
wasm_interface(vm_type vm);
......@@ -76,4 +77,4 @@ namespace eosio{ namespace chain {
std::istream& operator>>(std::istream& in, wasm_interface::vm_type& runtime);
}}
FC_REFLECT_ENUM( eosio::chain::wasm_interface::vm_type, (wavm)(binaryen) )
FC_REFLECT_ENUM( eosio::chain::wasm_interface::vm_type, (wavm)(binaryen)(wabt) )
......@@ -3,6 +3,7 @@
#include <eosio/chain/wasm_interface.hpp>
#include <eosio/chain/webassembly/wavm.hpp>
#include <eosio/chain/webassembly/binaryen.hpp>
#include <eosio/chain/webassembly/wabt.hpp>
#include <eosio/chain/webassembly/runtime_interface.hpp>
#include <eosio/chain/wasm_eosio_injection.hpp>
#include <eosio/chain/transaction_context.hpp>
......@@ -28,6 +29,8 @@ namespace eosio { namespace chain {
runtime_interface = std::make_unique<webassembly::wavm::wavm_runtime>();
else if(vm == wasm_interface::vm_type::binaryen)
runtime_interface = std::make_unique<webassembly::binaryen::binaryen_runtime>();
else if(vm == wasm_interface::vm_type::wabt)
runtime_interface = std::make_unique<webassembly::wabt_runtime::wabt_runtime>();
else
EOS_THROW(wasm_exception, "wasm_interface_impl fall through");
}
......@@ -95,7 +98,8 @@ namespace eosio { namespace chain {
#define _REGISTER_INTRINSIC_EXPLICIT(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\
_REGISTER_WAVM_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\
_REGISTER_BINARYEN_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)
_REGISTER_BINARYEN_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\
_REGISTER_WABT_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)
#define _REGISTER_INTRINSIC4(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\
_REGISTER_INTRINSIC_EXPLICIT(CLS, MOD, METHOD, WASM_SIG, NAME, SIG )
......
......@@ -1913,6 +1913,8 @@ std::istream& operator>>(std::istream& in, wasm_interface::vm_type& runtime) {
runtime = eosio::chain::wasm_interface::vm_type::wavm;
else if (s == "binaryen")
runtime = eosio::chain::wasm_interface::vm_type::binaryen;
else if (s == "wabt")
runtime = eosio::chain::wasm_interface::vm_type::wabt;
else
in.setstate(std::ios_base::failbit);
return in;
......
#include <eosio/chain/webassembly/wabt.hpp>
#include <eosio/chain/apply_context.hpp>
#include <eosio/chain/wasm_eosio_constraints.hpp>
//wabt includes
#include <src/interp.h>
#include <src/binary-reader-interp.h>
namespace eosio { namespace chain { namespace webassembly { namespace wabt_runtime {
//yep 🤮
static wabt_apply_instance_vars* static_wabt_vars;
using namespace wabt;
using namespace wabt::interp;
namespace wasm_constraints = eosio::chain::wasm_constraints;
class wabt_instantiated_module : public wasm_instantiated_module_interface {
public:
wabt_instantiated_module(std::unique_ptr<interp::Environment> e, std::vector<uint8_t> initial_mem, interp::DefinedModule* mod) :
_env(move(e)), _instatiated_module(mod), _initial_memory(initial_mem),
_executor(_env.get(), nullptr, Thread::Options(64*1024,
wasm_constraints::maximum_call_depth+2))
{
for(Index i = 0; i < _env->GetGlobalCount(); ++i) {
if(_env->GetGlobal(i)->mutable_ == false)
continue;
_initial_globals.emplace_back(_env->GetGlobal(i), _env->GetGlobal(i)->typed_value);
}
if(_env->GetMemoryCount())
_initial_memory_configuration = _env->GetMemory(0)->page_limits;
}
void apply(apply_context& context) override {
//reset mutable globals
for(const auto& mg : _initial_globals)
mg.first->typed_value = mg.second;
wabt_apply_instance_vars this_run_vars{nullptr, context};
static_wabt_vars = &this_run_vars;
//reset memory to inital size & copy back in initial data
if(_env->GetMemoryCount()) {
Memory* memory = this_run_vars.memory = _env->GetMemory(0);
memory->page_limits = _initial_memory_configuration;
memory->data.resize(_initial_memory_configuration.initial * WABT_PAGE_SIZE);
memset(memory->data.data(), 0, memory->data.size());
memcpy(memory->data.data(), _initial_memory.data(), _initial_memory.size());
}
_params[0].set_i64(uint64_t(context.receiver));
_params[1].set_i64(uint64_t(context.act.account));
_params[2].set_i64(uint64_t(context.act.name));
ExecResult res = _executor.RunStartFunction(_instatiated_module);
EOS_ASSERT( res.result == interp::Result::Ok, wasm_execution_error, "wabt start function failure (${s})", ("s", ResultToString(res.result)) );
res = _executor.RunExportByName(_instatiated_module, "apply", _params);
EOS_ASSERT( res.result == interp::Result::Ok, wasm_execution_error, "wabt execution failure (${s})", ("s", ResultToString(res.result)) );
}
private:
std::unique_ptr<interp::Environment> _env;
DefinedModule* _instatiated_module; //this is owned by the Environment
std::vector<uint8_t> _initial_memory;
TypedValues _params{3, TypedValue(Type::I64)};
std::vector<std::pair<Global*, TypedValue>> _initial_globals;
Limits _initial_memory_configuration;
Executor _executor;
};
wabt_runtime::wabt_runtime() {}
std::unique_ptr<wasm_instantiated_module_interface> wabt_runtime::instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t> initial_memory) {
std::unique_ptr<interp::Environment> env = std::make_unique<interp::Environment>();
for(auto it = intrinsic_registrator::get_map().begin() ; it != intrinsic_registrator::get_map().end(); ++it) {
interp::HostModule* host_module = env->AppendHostModule(it->first);
for(auto itf = it->second.begin(); itf != it->second.end(); ++itf) {
host_module->AppendFuncExport(itf->first, itf->second.sig, [fn=itf->second.func](const auto* f, const auto* fs, const auto& args, auto& res) {
TypedValue ret = fn(*static_wabt_vars, args);
if(ret.type != Type::Void)
res[0] = ret;
return interp::Result::Ok;
});
}
}
interp::DefinedModule* instantiated_module = nullptr;
ErrorHandlerBuffer error_handler(Location::Type::Binary);
wabt::Result res = ReadBinaryInterp(env.get(), code_bytes, code_size, read_binary_options, &error_handler, &instantiated_module);
EOS_ASSERT( Succeeded(res), wasm_execution_error, "Error building wabt interp: ${e}", ("e", error_handler.buffer()) );
return std::make_unique<wabt_instantiated_module>(std::move(env), initial_memory, instantiated_module);
}
}}}}
......@@ -332,6 +332,8 @@ namespace eosio { namespace testing {
vcfg.wasm_runtime = chain::wasm_interface::vm_type::binaryen;
else if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--wavm"))
vcfg.wasm_runtime = chain::wasm_interface::vm_type::wavm;
else if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--wabt"))
vcfg.wasm_runtime = chain::wasm_interface::vm_type::wabt;
}
......
......@@ -100,6 +100,8 @@ namespace eosio { namespace testing {
cfg.wasm_runtime = chain::wasm_interface::vm_type::binaryen;
else if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--wavm"))
cfg.wasm_runtime = chain::wasm_interface::vm_type::wavm;
else if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--wabt"))
cfg.wasm_runtime = chain::wasm_interface::vm_type::wabt;
else
cfg.wasm_runtime = chain::wasm_interface::vm_type::binaryen;
}
......
Subproject commit 67381cbe17e0ef87d40f3376e99aea7fff0fa0b1
......@@ -38,6 +38,9 @@ add_test(NAME unit_test_binaryen COMMAND unit_test
add_test(NAME unit_test_wavm COMMAND unit_test
-t \!wasm_tests/weighted_cpu_limit_tests
--report_level=detailed --color_output --catch_system_errors=no -- --wavm)
add_test(NAME unit_test_wabt COMMAND unit_test
-t \!wasm_tests/weighted_cpu_limit_tests
--report_level=detailed --color_output -- --wabt)
if(ENABLE_COVERAGE_TESTING)
......
......@@ -45,6 +45,8 @@ class whitelist_blacklist_tester {
cfg.wasm_runtime = chain::wasm_interface::vm_type::binaryen;
else if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--wavm"))
cfg.wasm_runtime = chain::wasm_interface::vm_type::wavm;
else if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--wabt"))
cfg.wasm_runtime = chain::wasm_interface::vm_type::wabt;
else
cfg.wasm_runtime = chain::wasm_interface::vm_type::binaryen;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册