From b5ca290605a631b43d71fe47c01ea37cf6a40ba9 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Sat, 4 Dec 2021 17:56:58 +0330 Subject: [PATCH] LibWasm: Implement memory.init and passive mode data --- .../AbstractMachine/AbstractMachine.cpp | 33 ++++++++++++++++-- .../LibWasm/AbstractMachine/AbstractMachine.h | 27 ++++++++++++++- .../AbstractMachine/BytecodeInterpreter.cpp | 34 +++++++++++++++---- .../AbstractMachine/BytecodeInterpreter.h | 2 +- .../LibWasm/AbstractMachine/Validator.cpp | 3 ++ 5 files changed, 88 insertions(+), 11 deletions(-) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 90789d8c09..6893296e29 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -54,6 +54,13 @@ Optional Store::allocate(GlobalType const& type, Value value) return address; } +Optional Store::allocate_data(Vector initializer) +{ + DataAddress address { m_datas.size() }; + m_datas.append(DataInstance { move(initializer) }); + return address; +} + Optional Store::allocate(ValueType const& type, Vector references) { ElementAddress address { m_elements.size() }; @@ -101,6 +108,14 @@ ElementInstance* Store::get(ElementAddress address) return &m_elements[value]; } +DataInstance* Store::get(DataAddress address) +{ + auto value = address.value(); + if (m_datas.size() <= value) + return nullptr; + return &m_datas[value]; +} + ErrorOr AbstractMachine::validate(Module& module) { if (module.validation_status() != Module::ValidationStatus::Unchecked) { @@ -304,7 +319,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vectoris_error()) return; if (main_module_instance.memories().size() <= data.index.value()) { @@ -314,6 +329,13 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vectordata().overwrite(offset, data.init.data(), data.init.size()); } }, - [&](DataSection::Data::Passive const&) { - // FIXME: What do we do here? + [&](DataSection::Data::Passive const& passive) { + auto maybe_data_address = m_store.allocate_data(passive.init); + if (!maybe_data_address.has_value()) { + instantiation_result = InstantiationError { "Failed to allocate a data instance for a passive data segment"sv }; + return; + } + main_module_instance.datas().append(*maybe_data_address); }); } }); diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index 381f7e4e21..4527bb4a10 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -34,6 +34,7 @@ TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, true, true, false, false, false, true, Ext TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, true, true, false, false, false, true, TableAddress); TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, true, true, false, false, false, true, GlobalAddress); TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, true, true, false, false, false, true, ElementAddress); +TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, true, true, false, false, false, true, DataAddress); TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, true, true, false, false, false, true, MemoryAddress); // FIXME: These should probably be made generic/virtual if/when we decide to do something more @@ -214,12 +215,14 @@ class ModuleInstance { public: explicit ModuleInstance( Vector types, Vector function_addresses, Vector table_addresses, - Vector memory_addresses, Vector global_addresses, Vector exports) + Vector memory_addresses, Vector global_addresses, Vector data_addresses, + Vector exports) : m_types(move(types)) , m_functions(move(function_addresses)) , m_tables(move(table_addresses)) , m_memories(move(memory_addresses)) , m_globals(move(global_addresses)) + , m_datas(move(data_addresses)) , m_exports(move(exports)) { } @@ -232,6 +235,7 @@ public: auto& memories() const { return m_memories; } auto& globals() const { return m_globals; } auto& elements() const { return m_elements; } + auto& datas() const { return m_datas; } auto& exports() const { return m_exports; } auto& types() { return m_types; } @@ -240,6 +244,7 @@ public: auto& memories() { return m_memories; } auto& globals() { return m_globals; } auto& elements() { return m_elements; } + auto& datas() { return m_datas; } auto& exports() { return m_exports; } private: @@ -249,6 +254,7 @@ private: Vector m_memories; Vector m_globals; Vector m_elements; + Vector m_datas; Vector m_exports; }; @@ -385,6 +391,22 @@ private: Value m_value; }; +class DataInstance { +public: + explicit DataInstance(Vector data) + : m_data(move(data)) + { + } + + size_t size() const { return m_data.size(); } + + Vector& data() { return m_data; } + Vector const& data() const { return m_data; } + +private: + Vector m_data; +}; + class ElementInstance { public: explicit ElementInstance(ValueType type, Vector references) @@ -409,6 +431,7 @@ public: Optional allocate(HostFunction&&); Optional allocate(TableType const&); Optional allocate(MemoryType const&); + Optional allocate_data(Vector); Optional allocate(GlobalType const&, Value); Optional allocate(ValueType const&, Vector); @@ -416,6 +439,7 @@ public: TableInstance* get(TableAddress); MemoryInstance* get(MemoryAddress); GlobalInstance* get(GlobalAddress); + DataInstance* get(DataAddress); ElementInstance* get(ElementAddress); private: @@ -424,6 +448,7 @@ private: Vector m_memories; Vector m_globals; Vector m_elements; + Vector m_datas; }; class Label { diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 73ba496167..1b64d8704e 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -227,17 +227,17 @@ void BytecodeInterpreter::pop_and_store(Configuration& configuration, Instructio auto entry = configuration.stack().pop(); auto value = ConvertToRaw {}(*entry.get().to()); dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> temporary({}b)", value, sizeof(StoreT)); - store_to_memory(configuration, instruction, { &value, sizeof(StoreT) }); + auto base_entry = configuration.stack().pop(); + auto base = base_entry.get().to(); + store_to_memory(configuration, instruction, { &value, sizeof(StoreT) }, *base); } -void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruction const& instruction, ReadonlyBytes data) +void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruction const& instruction, ReadonlyBytes data, i32 base) { auto& address = configuration.frame().module().memories().first(); auto memory = configuration.store().get(address); auto& arg = instruction.arguments().get(); - auto entry = configuration.stack().pop(); - auto base = entry.get().to(); - u64 instance_address = static_cast(bit_cast(base.value())) + arg.offset; + u64 instance_address = static_cast(bit_cast(base)) + arg.offset; Checked addition { instance_address }; addition += data.size(); if (addition.has_overflow() || addition.value() > memory->size()) { @@ -888,7 +888,29 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi return unary_operation>(configuration); case Instructions::i64_trunc_sat_f64_u.value(): return unary_operation>(configuration); - case Instructions::memory_init.value(): + case Instructions::memory_init.value(): { + auto data_index = instruction.arguments().get(); + auto& data_address = configuration.frame().module().datas()[data_index.value()]; + auto& data = *configuration.store().get(data_address); + auto count = *configuration.stack().pop().get().to(); + auto source_offset = *configuration.stack().pop().get().to(); + auto destination_offset = *configuration.stack().pop().get().to(); + + TRAP_IF_NOT(count > 0); + TRAP_IF_NOT(source_offset + count > 0); + TRAP_IF_NOT(static_cast(source_offset + count) <= data.size()); + + Instruction synthetic_store_instruction { + Instructions::i32_store8, + Instruction::MemoryArgument { 0, 0 } + }; + + for (size_t i = 0; i < (size_t)count; ++i) { + auto value = data.data()[source_offset + i]; + store_to_memory(configuration, synthetic_store_instruction, { &value, sizeof(value) }, destination_offset + i); + } + return; + } case Instructions::data_drop.value(): case Instructions::memory_copy.value(): case Instructions::memory_fill.value(): diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h index 8528578275..b3e46b05bb 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h @@ -39,7 +39,7 @@ protected: void load_and_push(Configuration&, Instruction const&); template void pop_and_store(Configuration&, Instruction const&); - void store_to_memory(Configuration&, Instruction const&, ReadonlyBytes data); + void store_to_memory(Configuration&, Instruction const&, ReadonlyBytes data, i32 base); void call_address(Configuration&, FunctionAddress); template diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp index 857ca555be..e573e11dfd 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -103,6 +103,9 @@ ErrorOr Validator::validate(Module& module) for (auto& segment : section.segments()) m_context.elements.unchecked_append(segment.type); }); + module.for_each_section_of_type([this](DataSection const& section) { + m_context.datas.resize(section.data().size()); + }); // FIXME: C.refs is the set funcidx(module with funcs=ϵ with start=ϵ), // i.e., the set of function indices occurring in the module, except in its functions or start function.