Skip to content

Commit

Permalink
storeBuffer optimization
Browse files Browse the repository at this point in the history
Signed-off-by: iceseer <[email protected]>
  • Loading branch information
iceseer committed Mar 2, 2023
1 parent 19911a6 commit 9734e1e
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 14 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ if("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(AppleClang|Clang|GNU)$")
add_flag(-Wno-gnu-zero-variadic-macro-arguments) # https://stackoverflow.com/questions/21266380/is-the-gnu-zero-variadic-macro-arguments-safe-to-ignore

# cmake-format: on
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU)$")
add_flag(-Wnon-virtual-dtor)
endif()

if((("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(AppleClang|Clang)$")
AND (${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL "12.0"))
Expand Down
3 changes: 2 additions & 1 deletion core/runtime/binaryen/binaryen_memory_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
namespace kagome::runtime::binaryen {

std::unique_ptr<MemoryImpl> BinaryenMemoryFactory::make(
wasm::ShellExternalInterface::Memory *memory, WasmSize heap_base) const {
RuntimeExternalInterface::InternalMemory *memory,
WasmSize heap_base) const {
return std::make_unique<MemoryImpl>(memory, heap_base);
}

Expand Down
4 changes: 3 additions & 1 deletion core/runtime/binaryen/binaryen_memory_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define KAGOME_BINARYEN_WASM_MEMORY_FACTORY_HPP

#include "runtime/binaryen/memory_impl.hpp"
#include "runtime/binaryen/runtime_external_interface.hpp"

namespace kagome::runtime::binaryen {

Expand All @@ -15,7 +16,8 @@ namespace kagome::runtime::binaryen {
virtual ~BinaryenMemoryFactory() = default;

virtual std::unique_ptr<MemoryImpl> make(
wasm::ShellExternalInterface::Memory *memory, WasmSize heap_base) const;
RuntimeExternalInterface::InternalMemory *memory,
WasmSize heap_base) const;
};

} // namespace kagome::runtime::binaryen
Expand Down
8 changes: 3 additions & 5 deletions core/runtime/binaryen/memory_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace kagome::runtime::binaryen {

MemoryImpl::MemoryImpl(wasm::ShellExternalInterface::Memory *memory,
MemoryImpl::MemoryImpl(RuntimeExternalInterface::InternalMemory *memory,
std::unique_ptr<MemoryAllocator> &&allocator)
: memory_{memory},
size_{kInitialMemorySize},
Expand All @@ -19,7 +19,7 @@ namespace kagome::runtime::binaryen {
resize(size_);
}

MemoryImpl::MemoryImpl(wasm::ShellExternalInterface::Memory *memory,
MemoryImpl::MemoryImpl(RuntimeExternalInterface::InternalMemory *memory,
WasmSize heap_base)
: MemoryImpl{memory,
std::make_unique<MemoryAllocator>(
Expand Down Expand Up @@ -125,9 +125,7 @@ namespace kagome::runtime::binaryen {
gsl::span<const uint8_t> value) {
const auto size = static_cast<size_t>(value.size());
BOOST_ASSERT((allocator_->checkAddress(addr, size)));
for (size_t i = addr, j = 0; i < addr + size; i++, j++) {
memory_->set(i, value[j]);
}
memory_->set(addr, std::move(value));
}

WasmSpan MemoryImpl::storeBuffer(gsl::span<const uint8_t> value) {
Expand Down
7 changes: 4 additions & 3 deletions core/runtime/binaryen/memory_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "common/literals.hpp"
#include "log/logger.hpp"
#include "primitives/math.hpp"
#include "runtime/binaryen/runtime_external_interface.hpp"
#include "runtime/memory.hpp"

namespace kagome::runtime {
Expand All @@ -37,9 +38,9 @@ namespace kagome::runtime::binaryen {
*/
class MemoryImpl final : public Memory {
public:
MemoryImpl(wasm::ShellExternalInterface::Memory *memory,
MemoryImpl(RuntimeExternalInterface::InternalMemory *memory,
std::unique_ptr<MemoryAllocator> &&allocator);
MemoryImpl(wasm::ShellExternalInterface::Memory *memory,
MemoryImpl(RuntimeExternalInterface::InternalMemory *memory,
WasmSize heap_base);
MemoryImpl(const MemoryImpl &copy) = delete;
MemoryImpl &operator=(const MemoryImpl &copy) = delete;
Expand Down Expand Up @@ -94,7 +95,7 @@ namespace kagome::runtime::binaryen {
}

private:
wasm::ShellExternalInterface::Memory *memory_;
RuntimeExternalInterface::InternalMemory *memory_;
WasmSize size_;
std::unique_ptr<MemoryAllocator> allocator_;

Expand Down
102 changes: 101 additions & 1 deletion core/runtime/binaryen/runtime_external_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ namespace kagome::runtime::binaryen {
methodsRegistration();
}

wasm::ShellExternalInterface::Memory *RuntimeExternalInterface::getMemory() {
RuntimeExternalInterface::InternalMemory *
RuntimeExternalInterface::getMemory() {
return &memory;
}

Expand Down Expand Up @@ -296,4 +297,103 @@ namespace kagome::runtime::binaryen {
return callHostApiFunc<mf>(this_.host_api_.get(), arguments);
}

void RuntimeExternalInterface::init(wasm::Module &wasm,
wasm::ModuleInstance &instance) {
memory.resize(wasm.memory.initial * wasm::Memory::kPageSize);
// apply memory segments
for (auto &segment : wasm.memory.segments) {
wasm::Address offset =
(uint32_t)wasm::ConstantExpressionRunner<wasm::TrivialGlobalManager>(
instance.globals)
.visit(segment.offset)
.value.geti32();
if (offset + segment.data.size()
> wasm.memory.initial * wasm::Memory::kPageSize) {
trap("invalid offset when initializing memory");
}
for (size_t i = 0; i != segment.data.size(); ++i) {
memory.set(offset + i, segment.data[i]);
}
}

table.resize(wasm.table.initial);
for (auto &segment : wasm.table.segments) {
wasm::Address offset =
(uint32_t)wasm::ConstantExpressionRunner<wasm::TrivialGlobalManager>(
instance.globals)
.visit(segment.offset)
.value.geti32();
if (offset + segment.data.size() > wasm.table.initial) {
trap("invalid offset when initializing table");
}
for (size_t i = 0; i != segment.data.size(); ++i) {
table[offset + i] = segment.data[i];
}
}
}

void RuntimeExternalInterface::importGlobals(
std::map<wasm::Name, wasm::Literal> &globals, wasm::Module &wasm) {
// add spectest globals
wasm::ModuleUtils::iterImportedGlobals(wasm, [&](wasm::Global *import) {
if (import->module == wasm::SPECTEST && import->base == wasm::GLOBAL) {
switch (import->type) {
case wasm::i32:
globals[import->name] = wasm::Literal(int32_t(666));
break;
case wasm::i64:
globals[import->name] = wasm::Literal(int64_t(666));
break;
case wasm::f32:
globals[import->name] = wasm::Literal(float(666.6));
break;
case wasm::f64:
globals[import->name] = wasm::Literal(double(666.6));
break;
case wasm::v128:
assert(false && "v128 not implemented yet");
case wasm::none:
case wasm::unreachable:
WASM_UNREACHABLE();
}
}
});
if (wasm.memory.imported() && wasm.memory.module == wasm::SPECTEST
&& wasm.memory.base == wasm::MEMORY) {
// imported memory has initial 1 and max 2
wasm.memory.initial = 1;
wasm.memory.max = 2;
}
}

wasm::Literal RuntimeExternalInterface::callTable(
wasm::Index index,
wasm::LiteralList &arguments,
wasm::Type result,
wasm::ModuleInstance &instance) {
if (index >= table.size()) {
trap("callTable overflow");
}
auto *func = instance.wasm.getFunctionOrNull(table[index]);
if (!func) {
trap("uninitialized table element");
}
if (func->params.size() != arguments.size()) {
trap("callIndirect: bad # of arguments");
}
for (size_t i = 0; i < func->params.size(); i++) {
if (func->params[i] != arguments[i].type) {
trap("callIndirect: bad argument type");
}
}
if (func->result != result) {
trap("callIndirect: bad result type");
}
if (func->imported()) {
return callImport(func, arguments);
} else {
return instance.callFunctionInternal(func->name, arguments);
}
}

} // namespace kagome::runtime::binaryen
127 changes: 125 additions & 2 deletions core/runtime/binaryen/runtime_external_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,138 @@ namespace wasm {

namespace kagome::runtime::binaryen {

class RuntimeExternalInterface : public wasm::ShellExternalInterface {
class RuntimeExternalInterface
: public wasm::ModuleInstance::ExternalInterface {
class Memory {
using Mem = std::vector<char>;
Mem memory;
template <typename T>
static bool aligned(const char *address) {
static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2");
return 0 == (reinterpret_cast<uintptr_t>(address) & (sizeof(T) - 1));
}
Memory(Memory &) = delete;
Memory &operator=(const Memory &) = delete;

public:
Memory() = default;
void resize(size_t newSize) {
// Ensure the smallest allocation is large enough that most allocators
// will provide page-aligned storage. This hopefully allows the
// interpreter's memory to be as aligned as the memory being simulated,
// ensuring that the performance doesn't needlessly degrade.
//
// The code is optimistic this will work until WG21's p0035r0 happens.
const size_t minSize = 1 << 12;
size_t oldSize = memory.size();
memory.resize(std::max(minSize, newSize));
if (newSize < oldSize && newSize < minSize) {
std::memset(&memory[newSize], 0, minSize - newSize);
}
}
auto getSize() const {
return memory.size();
}
auto getData() const {
return gsl::span<Mem::value_type const>(memory);
}
template <typename T>
void set(size_t address, T value) {
if (aligned<T>(&memory[address])) {
*reinterpret_cast<T *>(&memory[address]) = value;
} else {
std::memcpy(&memory[address], &value, sizeof(T));
}
}
template <typename T>
void set(size_t address, gsl::span<T> value) {
static_assert(std::is_trivially_copyable_v<T>,
"T must be trivially copyable");
std::memcpy(&memory[address], value.data(), sizeof(T) * value.size());
}
template <typename T>
T get(size_t address) {
if (aligned<T>(&memory[address])) {
return *reinterpret_cast<T *>(&memory[address]);
} else {
T loaded;
std::memcpy(&loaded, &memory[address], sizeof(T));
return loaded;
}
}
} memory;

std::vector<wasm::Name> table;

public:
using InternalMemory = Memory;

explicit RuntimeExternalInterface(
std::shared_ptr<host_api::HostApi> host_api);

void init(wasm::Module &wasm, wasm::ModuleInstance &instance) override;
void importGlobals(std::map<wasm::Name, wasm::Literal> &globals,
wasm::Module &wasm) override;
wasm::Literal callTable(wasm::Index index,
wasm::LiteralList &arguments,
wasm::Type result,
wasm::ModuleInstance &instance) override;

virtual ~RuntimeExternalInterface() = default;

wasm::Literal callImport(wasm::Function *import,
wasm::LiteralList &arguments) override;

wasm::ShellExternalInterface::Memory *getMemory();
InternalMemory *getMemory();

int8_t load8s(wasm::Address addr) override {
return memory.get<int8_t>(addr);
}
uint8_t load8u(wasm::Address addr) override {
return memory.get<uint8_t>(addr);
}
int16_t load16s(wasm::Address addr) override {
return memory.get<int16_t>(addr);
}
uint16_t load16u(wasm::Address addr) override {
return memory.get<uint16_t>(addr);
}
int32_t load32s(wasm::Address addr) override {
return memory.get<int32_t>(addr);
}
uint32_t load32u(wasm::Address addr) override {
return memory.get<uint32_t>(addr);
}
int64_t load64s(wasm::Address addr) override {
return memory.get<int64_t>(addr);
}
uint64_t load64u(wasm::Address addr) override {
return memory.get<uint64_t>(addr);
}
std::array<uint8_t, 16> load128(wasm::Address addr) override {
return memory.get<std::array<uint8_t, 16>>(addr);
}

void store8(wasm::Address addr, int8_t value) override {
memory.set<int8_t>(addr, value);
}
void store16(wasm::Address addr, int16_t value) override {
memory.set<int16_t>(addr, value);
}
void store32(wasm::Address addr, int32_t value) override {
memory.set<int32_t>(addr, value);
}
void store64(wasm::Address addr, int64_t value) override {
memory.set<int64_t>(addr, value);
}
void store128(wasm::Address addr,
const std::array<uint8_t, 16> &value) override {
memory.set<std::array<uint8_t, 16>>(addr, value);
}

void growMemory(wasm::Address /*oldSize*/, wasm::Address newSize) override {
memory.resize(newSize);
}

void trap(const char *why) override {
logger_->error("Trap: {}", why);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace kagome::runtime::binaryen {

MOCK_METHOD(std::unique_ptr<MemoryImpl>,
make,
(wasm::ShellExternalInterface::Memory * memory,
(RuntimeExternalInterface::InternalMemory * memory,
WasmSize heap_base),
(const, override));
};
Expand Down

0 comments on commit 9734e1e

Please sign in to comment.