diff --git a/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp b/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp index 719eb17aa5828669aa29641c820d4b59e7d4f1ca..630c14e144dcff4707316534f74c374deb107453 100644 --- a/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp @@ -30,32 +30,17 @@ struct intrinsic_registrator { }; struct interpreter_interface : ModuleInstance::ExternalInterface { + interpreter_interface(linear_memory_type& memory, call_indirect_table_type& table, const uint32_t& sbrk_bytes) + :memory(memory),table(table), sbrk_bytes(sbrk_bytes) + {} + void importGlobals(std::map& globals, Module& wasm) override { } - void init(Module& wasm, ModuleInstance& instance) override { - FC_ASSERT(wasm.memory.initial * wasm::Memory::kPageSize <= wasm_constraints::maximum_linear_memory); - // initialize the linear memory - memset(memory.data, 0, wasm.memory.initial * Memory::kPageSize); - for(size_t i = 0; i < wasm.memory.segments.size(); i++ ) { - const auto& segment = wasm.memory.segments.at(i); - Address offset = ConstantExpressionRunner(instance.globals).visit(segment.offset).value.geti32(); - char *base = memory.data + offset; - FC_ASSERT(offset + segment.data.size() <= wasm_constraints::maximum_linear_memory); - memcpy(base, segment.data.data(), segment.data.size()); - } - table.resize(wasm.table.initial); - for (auto& segment : wasm.table.segments) { - Address offset = ConstantExpressionRunner(instance.globals).visit(segment.offset).value.geti32(); - assert(offset + segment.data.size() <= wasm.table.initial); - for (size_t i = 0; i != segment.data.size(); ++i) { - table[offset + i] = segment.data[i]; - } - } + void init(Module& wasm, ModuleInstance& instance) override { - sbrk_bytes = wasm.memory.initial * Memory::kPageSize; } Literal callImport(Import *import, LiteralList &args) override @@ -141,18 +126,19 @@ struct interpreter_interface : ModuleInstance::ExternalInterface { void store32(Address addr, int32_t value) override { store_memory(addr, value); } void store64(Address addr, int64_t value) override { store_memory(addr, value); } - linear_memory_type memory; - call_indirect_table_type table; - uint32_t sbrk_bytes; + linear_memory_type& memory; + call_indirect_table_type& table; + const uint32_t& sbrk_bytes; }; struct info; class entry { public: unique_ptr module; - unique_ptr interface; - unique_ptr instance; - + linear_memory_type memory; + call_indirect_table_type table; + interpreter_interface* interface; + uint32_t sbrk_bytes; void reset(const info& ); @@ -167,16 +153,15 @@ public: static entry build(const char* wasm_binary, size_t wasm_binary_size); private: - entry(unique_ptr&& module, unique_ptr&& interface, unique_ptr&& instance); + entry(unique_ptr&& module, linear_memory_type&& memory, call_indirect_table_type&& table, uint32_t sbrk_bytes); }; struct info { info( const entry& binaryen ) { - int num_segments = binaryen.module->memory.segments.size(); - default_sbrk_bytes = binaryen.interface->sbrk_bytes; - const char* start = binaryen.interface->memory.data; + default_sbrk_bytes = binaryen.sbrk_bytes; + const char* start = binaryen.memory.data; const char* high_watermark = start + (binaryen.module->memory.initial * Memory::kPageSize); while (high_watermark > start) { if (*high_watermark) { diff --git a/libraries/chain/webassembly/binaryen.cpp b/libraries/chain/webassembly/binaryen.cpp index acddcf979fcdb6bac24a9c67740663616cd8db32..f62d15f1dff599c117672740bd8bebc4b9f5b5b5 100644 --- a/libraries/chain/webassembly/binaryen.cpp +++ b/libraries/chain/webassembly/binaryen.cpp @@ -8,7 +8,10 @@ namespace eosio { namespace chain { namespace webassembly { namespace binaryen { void entry::call(const string &entry_point, LiteralList& args, apply_context &context) { - instance->callExport(Name(entry_point), args); + interpreter_interface local_interface(memory, table, sbrk_bytes); + interface = &local_interface; + ModuleInstance instance(*module.get(), interface); + instance.callExport(Name(entry_point), args); } void entry::call_apply(apply_context& context) @@ -30,7 +33,7 @@ int entry::sbrk(int num_bytes) { constexpr uint32_t NBPPL2 = 16; const uint32_t num_pages = module->memory.initial; const uint32_t min_bytes = (num_pages << NBPPL2) > UINT32_MAX ? UINT32_MAX : num_pages << NBPPL2; - const uint32_t prev_num_bytes = interface->sbrk_bytes; //_num_bytes; + const uint32_t prev_num_bytes = sbrk_bytes; //_num_bytes; // round the absolute value of num_bytes to an alignment boundary num_bytes = (num_bytes + 7) & ~7; @@ -41,18 +44,19 @@ int entry::sbrk(int num_bytes) { throw eosio::chain::page_memory_error(); // update the number of bytes allocated, and compute the number of pages needed - interface->sbrk_bytes += num_bytes; + sbrk_bytes += num_bytes; return prev_num_bytes; } void entry::reset(const info& base_info) { const auto& image = base_info.mem_image; - char *base = interface->memory.data; + char *base = memory.data; memcpy(base, image.data(), image.size()); - if (interface->sbrk_bytes > image.size()) { - memset(interface->memory.data + image.size(), 0, interface->sbrk_bytes - image.size()); + if (sbrk_bytes > image.size()) { + memset(memory.data + image.size(), 0, sbrk_bytes - image.size()); } - interface->sbrk_bytes = base_info.default_sbrk_bytes; + sbrk_bytes = base_info.default_sbrk_bytes; + interface = nullptr; } @@ -63,21 +67,52 @@ entry entry::build(const char* wasm_binary, size_t wasm_binary_size) { WasmBinaryBuilder builder(*module, code, false); builder.read(); - unique_ptr interface(new interpreter_interface()); - unique_ptr instance(new ModuleInstance(*module.get(), interface.get())); + linear_memory_type memory; + call_indirect_table_type table; + + FC_ASSERT(module->memory.initial * Memory::kPageSize <= wasm_constraints::maximum_linear_memory); + + // create a temporary globals to use + TrivialGlobalManager globals; + for (auto& global : module->globals) { + globals[global->name] = ConstantExpressionRunner(globals).visit(global->init).value; + } + + // initialize the linear memory + memset(memory.data, 0, module->memory.initial * Memory::kPageSize); + for(size_t i = 0; i < module->memory.segments.size(); i++ ) { + const auto& segment = module->memory.segments.at(i); + Address offset = ConstantExpressionRunner(globals).visit(segment.offset).value.geti32(); + char *base = memory.data + offset; + FC_ASSERT(offset + segment.data.size() <= wasm_constraints::maximum_linear_memory); + memcpy(base, segment.data.data(), segment.data.size()); + } + + table.resize(module->table.initial); + for (auto& segment : module->table.segments) { + Address offset = ConstantExpressionRunner(globals).visit(segment.offset).value.geti32(); + assert(offset + segment.data.size() <= module->table.initial); + for (size_t i = 0; i != segment.data.size(); ++i) { + table[offset + i] = segment.data[i]; + } + } + + uint32_t sbrk_bytes = module->memory.initial * Memory::kPageSize; //TODO: validate - return entry(move(module), move(interface), move(instance)); + return entry(move(module), std::move(memory), std::move(table), sbrk_bytes); } catch (const ParseException &e) { FC_THROW_EXCEPTION(wasm_execution_error, "Error building interpreter: ${s}", ("s", e.text)); } }; -entry::entry(unique_ptr&& module, unique_ptr&& interface, unique_ptr&& instance) +entry::entry(unique_ptr&& module, linear_memory_type&& memory, call_indirect_table_type&& table, uint32_t sbrk_bytes) :module(forward(module)) -,interface(forward(interface)) -,instance (forward(instance)) +,memory(forward(memory)) +,table (forward(table)) +,interface(nullptr) +,sbrk_bytes(sbrk_bytes) { }