Explorar o código

LibWasm: Make Frame a value type as well

This means stack operations will no longer do extra allocations.
Ali Mohammad Pur %!s(int64=4) %!d(string=hai) anos
pai
achega
bc936a5fac

+ 12 - 12
Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp

@@ -107,15 +107,15 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex
 
     module.for_each_section_of_type<GlobalSection>([&](auto& global_section) {
         for (auto& entry : global_section.entries()) {
-            auto frame = make<Frame>(
-                auxiliary_instance,
-                Vector<Value> {},
-                entry.expression(),
-                1);
             Configuration config { m_store };
             config.pre_interpret_hook = &pre_interpret_hook;
             config.post_interpret_hook = &post_interpret_hook;
-            config.set_frame(move(frame));
+            config.set_frame(Frame {
+                auxiliary_instance,
+                Vector<Value> {},
+                entry.expression(),
+                1,
+            });
             auto result = config.execute();
             // What if this traps?
             if (result.is_trap())
@@ -139,15 +139,15 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex
         for (auto& segment : data_section.data()) {
             segment.value().visit(
                 [&](const DataSection::Data::Active& data) {
-                    auto frame = make<Frame>(
-                        main_module_instance,
-                        Vector<Value> {},
-                        data.offset,
-                        1);
                     Configuration config { m_store };
                     config.pre_interpret_hook = &pre_interpret_hook;
                     config.post_interpret_hook = &post_interpret_hook;
-                    config.set_frame(move(frame));
+                    config.set_frame(Frame {
+                        main_module_instance,
+                        Vector<Value> {},
+                        data.offset,
+                        1,
+                    });
                     auto result = config.execute();
                     size_t offset = 0;
                     result.values().first().value().visit(

+ 3 - 4
Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h

@@ -392,8 +392,6 @@ private:
 };
 
 class Frame {
-    AK_MAKE_NONCOPYABLE(Frame);
-
 public:
     explicit Frame(const ModuleInstance& module, Vector<Value> locals, const Expression& expression, size_t arity)
         : m_module(module)
@@ -418,7 +416,7 @@ private:
 
 class Stack {
 public:
-    using EntryType = Variant<Value, Label, NonnullOwnPtr<Frame>>;
+    using EntryType = Variant<Value, Label, Frame>;
     Stack() = default;
 
     [[nodiscard]] bool is_empty() const { return m_data.is_empty(); }
@@ -428,9 +426,10 @@ public:
 
     auto size() const { return m_data.size(); }
     auto& entries() const { return m_data; }
+    auto& entries() { return m_data; }
 
 private:
-    Vector<EntryType> m_data;
+    Vector<EntryType, 64> m_data;
 };
 
 using InstantiationResult = AK::Result<NonnullOwnPtr<ModuleInstance>, InstantiationError>;

+ 8 - 9
Userland/Libraries/LibWasm/AbstractMachine/Configuration.cpp

@@ -35,13 +35,12 @@ Result Configuration::call(FunctionAddress address, Vector<Value> arguments)
         for (auto& type : wasm_function->code().locals())
             locals.empend(type, 0ull);
 
-        auto frame = make<Frame>(
+        set_frame(Frame {
             wasm_function->module(),
             move(locals),
             wasm_function->code().body(),
-            wasm_function->type().results().size());
-
-        set_frame(move(frame));
+            wasm_function->type().results().size(),
+        });
         return execute();
     }
 
@@ -61,8 +60,8 @@ Result Configuration::execute()
         return Trap {};
 
     Vector<Value> results;
-    results.ensure_capacity(m_current_frame->arity());
-    for (size_t i = 0; i < m_current_frame->arity(); ++i)
+    results.ensure_capacity(frame().arity());
+    for (size_t i = 0; i < frame().arity(); ++i)
         results.append(move(stack().pop().get<Value>()));
     auto label = stack().pop();
     // ASSERT: label == current frame
@@ -83,9 +82,9 @@ void Configuration::dump_stack()
                         dbgln("    *{}", v.value());
                 });
             },
-            [](const NonnullOwnPtr<Frame>& f) {
-                dbgln("    frame({})", f->arity());
-                for (auto& local : f->locals()) {
+            [](const Frame& f) {
+                dbgln("    frame({})", f.arity());
+                for (auto& local : f.locals()) {
                     local.value().visit([]<typename T>(const T& v) {
                         if constexpr (IsIntegral<T> || IsFloatingPoint<T>)
                             dbgln("        {}", v);

+ 7 - 6
Userland/Libraries/LibWasm/AbstractMachine/Configuration.h

@@ -18,14 +18,15 @@ public:
     }
 
     Optional<Label> nth_label(size_t);
-    void set_frame(NonnullOwnPtr<Frame> frame)
+    void set_frame(Frame&& frame)
     {
-        m_current_frame = frame.ptr();
+        m_current_frame_index = m_stack.size();
+        Label label(frame.arity(), frame.expression().instructions().size());
         m_stack.push(move(frame));
-        m_stack.push(Label(m_current_frame->arity(), m_current_frame->expression().instructions().size()));
+        m_stack.push(label);
     }
-    auto& frame() const { return m_current_frame; }
-    auto& frame() { return m_current_frame; }
+    auto& frame() const { return m_stack.entries()[m_current_frame_index].get<Frame>(); }
+    auto& frame() { return m_stack.entries()[m_current_frame_index].get<Frame>(); }
     auto& ip() const { return m_ip; }
     auto& ip() { return m_ip; }
     auto& depth() const { return m_depth; }
@@ -45,7 +46,7 @@ public:
 
 private:
     Store& m_store;
-    Frame* m_current_frame { nullptr };
+    size_t m_current_frame_index { 0 };
     Stack m_stack;
     size_t m_depth { 0 };
     InstructionPointer m_ip;

+ 18 - 18
Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp

@@ -31,7 +31,7 @@ namespace Wasm {
 
 void Interpreter::interpret(Configuration& configuration)
 {
-    auto& instructions = configuration.frame()->expression().instructions();
+    auto& instructions = configuration.frame().expression().instructions();
     auto max_ip_value = InstructionPointer { instructions.size() };
     auto& current_ip_value = configuration.ip();
 
@@ -73,7 +73,7 @@ void Interpreter::branch_to_label(Configuration& configuration, LabelIndex index
 
 ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const Instruction& instruction, size_t size)
 {
-    auto& address = configuration.frame()->module().memories().first();
+    auto& address = configuration.frame().module().memories().first();
     auto memory = configuration.store().get(address);
     if (!memory) {
         m_do_trap = true;
@@ -97,7 +97,7 @@ ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const
 
 void Interpreter::store_to_memory(Configuration& configuration, const Instruction& instruction, ReadonlyBytes data)
 {
-    auto& address = configuration.frame()->module().memories().first();
+    auto& address = configuration.frame().module().memories().first();
     auto memory = configuration.store().get(address);
     TRAP_IF_NOT(memory);
     auto& arg = instruction.arguments().get<Instruction::MemoryArgument>();
@@ -366,11 +366,11 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
     case Instructions::nop.value():
         return;
     case Instructions::local_get.value():
-        configuration.stack().push(Value(configuration.frame()->locals()[instruction.arguments().get<LocalIndex>().value()]));
+        configuration.stack().push(Value(configuration.frame().locals()[instruction.arguments().get<LocalIndex>().value()]));
         return;
     case Instructions::local_set.value(): {
         auto entry = configuration.stack().pop();
-        configuration.frame()->locals()[instruction.arguments().get<LocalIndex>().value()] = move(entry.get<Value>());
+        configuration.frame().locals()[instruction.arguments().get<LocalIndex>().value()] = move(entry.get<Value>());
         return;
     }
     case Instructions::i32_const.value():
@@ -448,7 +448,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
     }
     case Instructions::return_.value(): {
         Vector<Stack::EntryType> results;
-        auto& frame = *configuration.frame();
+        auto& frame = configuration.frame();
         results.ensure_capacity(frame.arity());
         for (size_t i = 0; i < frame.arity(); ++i)
             results.prepend(configuration.stack().pop());
@@ -460,7 +460,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
                 last_label = entry.get<Label>();
                 continue;
             }
-            if (entry.has<NonnullOwnPtr<Frame>>()) {
+            if (entry.has<Frame>()) {
                 // Push the frame back
                 configuration.stack().push(move(entry));
                 // Push its label back (if there is one)
@@ -475,7 +475,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
             configuration.stack().push(move(result));
 
         // Jump past the call/indirect instruction
-        configuration.ip() = configuration.frame()->expression().instructions().size() - 1;
+        configuration.ip() = configuration.frame().expression().instructions().size() - 1;
         return;
     }
     case Instructions::br.value():
@@ -489,14 +489,14 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
         goto unimplemented;
     case Instructions::call.value(): {
         auto index = instruction.arguments().get<FunctionIndex>();
-        auto address = configuration.frame()->module().functions()[index.value()];
+        auto address = configuration.frame().module().functions()[index.value()];
         dbgln_if(WASM_TRACE_DEBUG, "call({})", address.value());
         call_address(configuration, address);
         return;
     }
     case Instructions::call_indirect.value(): {
         auto& args = instruction.arguments().get<Instruction::IndirectCallArgs>();
-        auto table_address = configuration.frame()->module().tables()[args.table.value()];
+        auto table_address = configuration.frame().module().tables()[args.table.value()];
         auto table_instance = configuration.store().get(table_address);
         auto index = configuration.stack().pop().get<Value>().to<i32>();
         TRAP_IF_NOT(index.has_value());
@@ -565,15 +565,15 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
     case Instructions::local_tee.value(): {
         auto value = configuration.stack().peek().get<Value>();
         auto local_index = instruction.arguments().get<LocalIndex>();
-        TRAP_IF_NOT(configuration.frame()->locals().size() > local_index.value());
+        TRAP_IF_NOT(configuration.frame().locals().size() > local_index.value());
         dbgln_if(WASM_TRACE_DEBUG, "stack:peek -> locals({})", local_index.value());
-        configuration.frame()->locals()[local_index.value()] = move(value);
+        configuration.frame().locals()[local_index.value()] = move(value);
         return;
     }
     case Instructions::global_get.value(): {
         auto global_index = instruction.arguments().get<GlobalIndex>();
-        TRAP_IF_NOT(configuration.frame()->module().globals().size() > global_index.value());
-        auto address = configuration.frame()->module().globals()[global_index.value()];
+        TRAP_IF_NOT(configuration.frame().module().globals().size() > global_index.value());
+        auto address = configuration.frame().module().globals()[global_index.value()];
         dbgln_if(WASM_TRACE_DEBUG, "global({}) -> stack", address.value());
         auto global = configuration.store().get(address);
         configuration.stack().push(Value(global->value()));
@@ -581,8 +581,8 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
     }
     case Instructions::global_set.value(): {
         auto global_index = instruction.arguments().get<GlobalIndex>();
-        TRAP_IF_NOT(configuration.frame()->module().globals().size() > global_index.value());
-        auto address = configuration.frame()->module().globals()[global_index.value()];
+        TRAP_IF_NOT(configuration.frame().module().globals().size() > global_index.value());
+        auto address = configuration.frame().module().globals()[global_index.value()];
         auto value = configuration.stack().pop().get<Value>();
         dbgln_if(WASM_TRACE_DEBUG, "stack -> global({})", address.value());
         auto global = configuration.store().get(address);
@@ -590,7 +590,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
         return;
     }
     case Instructions::memory_size.value(): {
-        auto address = configuration.frame()->module().memories()[0];
+        auto address = configuration.frame().module().memories()[0];
         auto instance = configuration.store().get(address);
         auto pages = instance->size() / Constants::page_size;
         dbgln_if(WASM_TRACE_DEBUG, "memory.size -> stack({})", pages);
@@ -598,7 +598,7 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
         return;
     }
     case Instructions::memory_grow.value(): {
-        auto address = configuration.frame()->module().memories()[0];
+        auto address = configuration.frame().module().memories()[0];
         auto instance = configuration.store().get(address);
         i32 old_pages = instance->size() / Constants::page_size;
         auto new_pages = configuration.stack().pop().get<Value>().to<i32>();

+ 5 - 5
Userland/Utilities/wasm.cpp

@@ -155,10 +155,10 @@ static bool pre_interpret_hook(Wasm::Configuration& config, Wasm::InstructionPoi
             Optional<Wasm::FunctionAddress> address;
             auto index = args[1].to_uint<u64>();
             if (index.has_value()) {
-                address = config.frame()->module().functions()[index.value()];
+                address = config.frame().module().functions()[index.value()];
             } else {
                 auto& name = args[1];
-                for (auto& export_ : config.frame()->module().exports()) {
+                for (auto& export_ : config.frame().module().exports()) {
                     if (export_.name() == name) {
                         if (auto addr = export_.value().get_pointer<Wasm::FunctionAddress>()) {
                             address = *addr;
@@ -437,12 +437,12 @@ int main(int argc, char* argv[])
 
             if (debug) {
                 Wasm::Configuration config { machine.store() };
-                auto frame = make<Wasm::Frame>(
+                config.set_frame(Wasm::Frame {
                     *module_instance,
                     Vector<Wasm::Value> {},
                     instance->get<Wasm::WasmFunction>().code().body(),
-                    1);
-                config.set_frame(move(frame));
+                    1,
+                });
                 const Wasm::Instruction instr { Wasm::Instructions::nop };
                 Wasm::InstructionPointer ip { 0 };
                 g_continue = false;