mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 20:32:44 +00:00 
			
		
		
		
	LibWasm: Make Interpreter a virtual interface
This allows multiply different kinds of interpreters to be used by the runtime; currently a BytecodeInterpreter and a DebuggerBytecodeInterpreter is provided.
This commit is contained in:
		
							parent
							
								
									f91fa79fc5
								
							
						
					
					
						commit
						c5df55a8a2
					
				
					 7 changed files with 86 additions and 66 deletions
				
			
		|  | @ -4,6 +4,7 @@ | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include "Interpreter.h" | ||||||
| #include <LibWasm/AbstractMachine/AbstractMachine.h> | #include <LibWasm/AbstractMachine/AbstractMachine.h> | ||||||
| #include <LibWasm/AbstractMachine/Configuration.h> | #include <LibWasm/AbstractMachine/Configuration.h> | ||||||
| #include <LibWasm/Types.h> | #include <LibWasm/Types.h> | ||||||
|  | @ -105,18 +106,18 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex | ||||||
|             auxiliary_instance.globals().append(*ptr); |             auxiliary_instance.globals().append(*ptr); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     BytecodeInterpreter interpreter; | ||||||
|  | 
 | ||||||
|     module.for_each_section_of_type<GlobalSection>([&](auto& global_section) { |     module.for_each_section_of_type<GlobalSection>([&](auto& global_section) { | ||||||
|         for (auto& entry : global_section.entries()) { |         for (auto& entry : global_section.entries()) { | ||||||
|             Configuration config { m_store }; |             Configuration config { m_store }; | ||||||
|             config.pre_interpret_hook = &pre_interpret_hook; |  | ||||||
|             config.post_interpret_hook = &post_interpret_hook; |  | ||||||
|             config.set_frame(Frame { |             config.set_frame(Frame { | ||||||
|                 auxiliary_instance, |                 auxiliary_instance, | ||||||
|                 Vector<Value> {}, |                 Vector<Value> {}, | ||||||
|                 entry.expression(), |                 entry.expression(), | ||||||
|                 1, |                 1, | ||||||
|             }); |             }); | ||||||
|             auto result = config.execute(); |             auto result = config.execute(interpreter); | ||||||
|             // What if this traps?
 |             // What if this traps?
 | ||||||
|             if (result.is_trap()) |             if (result.is_trap()) | ||||||
|                 instantiation_result = InstantiationError { "Global value construction trapped" }; |                 instantiation_result = InstantiationError { "Global value construction trapped" }; | ||||||
|  | @ -140,15 +141,13 @@ InstantiationResult AbstractMachine::instantiate(const Module& module, Vector<Ex | ||||||
|             segment.value().visit( |             segment.value().visit( | ||||||
|                 [&](const DataSection::Data::Active& data) { |                 [&](const DataSection::Data::Active& data) { | ||||||
|                     Configuration config { m_store }; |                     Configuration config { m_store }; | ||||||
|                     config.pre_interpret_hook = &pre_interpret_hook; |  | ||||||
|                     config.post_interpret_hook = &post_interpret_hook; |  | ||||||
|                     config.set_frame(Frame { |                     config.set_frame(Frame { | ||||||
|                         main_module_instance, |                         main_module_instance, | ||||||
|                         Vector<Value> {}, |                         Vector<Value> {}, | ||||||
|                         data.offset, |                         data.offset, | ||||||
|                         1, |                         1, | ||||||
|                     }); |                     }); | ||||||
|                     auto result = config.execute(); |                     auto result = config.execute(interpreter); | ||||||
|                     size_t offset = 0; |                     size_t offset = 0; | ||||||
|                     result.values().first().value().visit( |                     result.values().first().value().visit( | ||||||
|                         [&](const auto& value) { offset = value; }, |                         [&](const auto& value) { offset = value; }, | ||||||
|  | @ -284,11 +283,15 @@ Optional<InstantiationError> AbstractMachine::allocate_all(const Module& module, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Result AbstractMachine::invoke(FunctionAddress address, Vector<Value> arguments) | Result AbstractMachine::invoke(FunctionAddress address, Vector<Value> arguments) | ||||||
|  | { | ||||||
|  |     BytecodeInterpreter interpreter; | ||||||
|  |     return invoke(interpreter, address, move(arguments)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Result AbstractMachine::invoke(Interpreter& interpreter, FunctionAddress address, Vector<Value> arguments) | ||||||
| { | { | ||||||
|     Configuration configuration { m_store }; |     Configuration configuration { m_store }; | ||||||
|     configuration.pre_interpret_hook = &pre_interpret_hook; |     return configuration.call(interpreter, address, move(arguments)); | ||||||
|     configuration.post_interpret_hook = &post_interpret_hook; |  | ||||||
|     return configuration.call(address, move(arguments)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Linker::link(const ModuleInstance& instance) | void Linker::link(const ModuleInstance& instance) | ||||||
|  |  | ||||||
|  | @ -441,13 +441,11 @@ public: | ||||||
|     // Load and instantiate a module, and link it into this interpreter.
 |     // Load and instantiate a module, and link it into this interpreter.
 | ||||||
|     InstantiationResult instantiate(const Module&, Vector<ExternValue>); |     InstantiationResult instantiate(const Module&, Vector<ExternValue>); | ||||||
|     Result invoke(FunctionAddress, Vector<Value>); |     Result invoke(FunctionAddress, Vector<Value>); | ||||||
|  |     Result invoke(Interpreter&, FunctionAddress, Vector<Value>); | ||||||
| 
 | 
 | ||||||
|     auto& store() const { return m_store; } |     auto& store() const { return m_store; } | ||||||
|     auto& store() { return m_store; } |     auto& store() { return m_store; } | ||||||
| 
 | 
 | ||||||
|     Function<bool(Configuration&, InstructionPointer&, const Instruction&)> pre_interpret_hook; |  | ||||||
|     Function<bool(Configuration&, InstructionPointer&, const Instruction&, const Interpreter&)> post_interpret_hook; |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     Optional<InstantiationError> allocate_all(const Module&, ModuleInstance&, Vector<ExternValue>&, Vector<Value>& global_values); |     Optional<InstantiationError> allocate_all(const Module&, ModuleInstance&, Vector<ExternValue>&, Vector<Value>& global_values); | ||||||
|     Store m_store; |     Store m_store; | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ void Configuration::unwind(Badge<CallFrameHandle>, const CallFrameHandle& frame_ | ||||||
|     VERIFY(m_stack.size() == frame_handle.stack_size); |     VERIFY(m_stack.size() == frame_handle.stack_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Result Configuration::call(FunctionAddress address, Vector<Value> arguments) | Result Configuration::call(Interpreter& interpreter, FunctionAddress address, Vector<Value> arguments) | ||||||
| { | { | ||||||
|     auto* function = m_store.get(address); |     auto* function = m_store.get(address); | ||||||
|     if (!function) |     if (!function) | ||||||
|  | @ -52,7 +52,7 @@ Result Configuration::call(FunctionAddress address, Vector<Value> arguments) | ||||||
|             wasm_function->type().results().size(), |             wasm_function->type().results().size(), | ||||||
|         }); |         }); | ||||||
|         m_ip = 0; |         m_ip = 0; | ||||||
|         return execute(); |         return execute(interpreter); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // It better be a host function, else something is really wrong.
 |     // It better be a host function, else something is really wrong.
 | ||||||
|  | @ -60,12 +60,8 @@ Result Configuration::call(FunctionAddress address, Vector<Value> arguments) | ||||||
|     return host_function.function()(*this, arguments); |     return host_function.function()(*this, arguments); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Result Configuration::execute() | Result Configuration::execute(Interpreter& interpreter) | ||||||
| { | { | ||||||
|     Interpreter interpreter; |  | ||||||
|     interpreter.pre_interpret_hook = pre_interpret_hook; |  | ||||||
|     interpreter.post_interpret_hook = post_interpret_hook; |  | ||||||
| 
 |  | ||||||
|     interpreter.interpret(*this); |     interpreter.interpret(*this); | ||||||
|     if (interpreter.did_trap()) |     if (interpreter.did_trap()) | ||||||
|         return Trap {}; |         return Trap {}; | ||||||
|  |  | ||||||
|  | @ -58,14 +58,11 @@ public: | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     void unwind(Badge<CallFrameHandle>, const CallFrameHandle&); |     void unwind(Badge<CallFrameHandle>, const CallFrameHandle&); | ||||||
|     Result call(FunctionAddress, Vector<Value> arguments); |     Result call(Interpreter&, FunctionAddress, Vector<Value> arguments); | ||||||
|     Result execute(); |     Result execute(Interpreter&); | ||||||
| 
 | 
 | ||||||
|     void dump_stack(); |     void dump_stack(); | ||||||
| 
 | 
 | ||||||
|     Function<bool(Configuration&, InstructionPointer&, const Instruction&)>* pre_interpret_hook { nullptr }; |  | ||||||
|     Function<bool(Configuration&, InstructionPointer&, const Instruction&, const Interpreter&)>* post_interpret_hook { nullptr }; |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     Store& m_store; |     Store& m_store; | ||||||
|     size_t m_current_frame_index { 0 }; |     size_t m_current_frame_index { 0 }; | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ namespace Wasm { | ||||||
|         }                                                                                      \ |         }                                                                                      \ | ||||||
|     } while (false) |     } while (false) | ||||||
| 
 | 
 | ||||||
| void Interpreter::interpret(Configuration& configuration) | void BytecodeInterpreter::interpret(Configuration& configuration) | ||||||
| { | { | ||||||
|     auto& instructions = configuration.frame().expression().instructions(); |     auto& instructions = configuration.frame().expression().instructions(); | ||||||
|     auto max_ip_value = InstructionPointer { instructions.size() }; |     auto max_ip_value = InstructionPointer { instructions.size() }; | ||||||
|  | @ -46,7 +46,7 @@ void Interpreter::interpret(Configuration& configuration) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Interpreter::branch_to_label(Configuration& configuration, LabelIndex index) | void BytecodeInterpreter::branch_to_label(Configuration& configuration, LabelIndex index) | ||||||
| { | { | ||||||
|     dbgln_if(WASM_TRACE_DEBUG, "Branch to label with index {}...", index.value()); |     dbgln_if(WASM_TRACE_DEBUG, "Branch to label with index {}...", index.value()); | ||||||
|     auto label = configuration.nth_label(index.value()); |     auto label = configuration.nth_label(index.value()); | ||||||
|  | @ -71,7 +71,7 @@ void Interpreter::branch_to_label(Configuration& configuration, LabelIndex index | ||||||
|     configuration.ip() = label->continuation(); |     configuration.ip() = label->continuation(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const Instruction& instruction, size_t size) | ReadonlyBytes BytecodeInterpreter::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); |     auto memory = configuration.store().get(address); | ||||||
|  | @ -95,7 +95,7 @@ ReadonlyBytes Interpreter::load_from_memory(Configuration& configuration, const | ||||||
|     return memory->data().bytes().slice(instance_address, size); |     return memory->data().bytes().slice(instance_address, size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Interpreter::store_to_memory(Configuration& configuration, const Instruction& instruction, ReadonlyBytes data) | void BytecodeInterpreter::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); |     auto memory = configuration.store().get(address); | ||||||
|  | @ -113,7 +113,7 @@ void Interpreter::store_to_memory(Configuration& configuration, const Instructio | ||||||
|     data.copy_to(memory->data().bytes().slice(instance_address, data.size())); |     data.copy_to(memory->data().bytes().slice(instance_address, data.size())); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Interpreter::call_address(Configuration& configuration, FunctionAddress address) | void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAddress address) | ||||||
| { | { | ||||||
|     auto instance = configuration.store().get(address); |     auto instance = configuration.store().get(address); | ||||||
|     TRAP_IF_NOT(instance); |     TRAP_IF_NOT(instance); | ||||||
|  | @ -129,7 +129,7 @@ void Interpreter::call_address(Configuration& configuration, FunctionAddress add | ||||||
|     Result result { Trap {} }; |     Result result { Trap {} }; | ||||||
|     { |     { | ||||||
|         Configuration::CallFrameHandle handle { configuration }; |         Configuration::CallFrameHandle handle { configuration }; | ||||||
|         result = configuration.call(address, move(args)); |         result = configuration.call(*this, address, move(args)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (result.is_trap()) { |     if (result.is_trap()) { | ||||||
|  | @ -215,7 +215,7 @@ void Interpreter::call_address(Configuration& configuration, FunctionAddress add | ||||||
|     } while (false) |     } while (false) | ||||||
| 
 | 
 | ||||||
| template<typename T> | template<typename T> | ||||||
| T Interpreter::read_value(ReadonlyBytes data) | T BytecodeInterpreter::read_value(ReadonlyBytes data) | ||||||
| { | { | ||||||
|     T value; |     T value; | ||||||
|     InputMemoryStream stream { data }; |     InputMemoryStream stream { data }; | ||||||
|  | @ -226,7 +226,7 @@ T Interpreter::read_value(ReadonlyBytes data) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<> | template<> | ||||||
| float Interpreter::read_value<float>(ReadonlyBytes data) | float BytecodeInterpreter::read_value<float>(ReadonlyBytes data) | ||||||
| { | { | ||||||
|     InputMemoryStream stream { data }; |     InputMemoryStream stream { data }; | ||||||
|     LittleEndian<u32> raw_value; |     LittleEndian<u32> raw_value; | ||||||
|  | @ -237,7 +237,7 @@ float Interpreter::read_value<float>(ReadonlyBytes data) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<> | template<> | ||||||
| double Interpreter::read_value<double>(ReadonlyBytes data) | double BytecodeInterpreter::read_value<double>(ReadonlyBytes data) | ||||||
| { | { | ||||||
|     InputMemoryStream stream { data }; |     InputMemoryStream stream { data }; | ||||||
|     LittleEndian<u64> raw_value; |     LittleEndian<u64> raw_value; | ||||||
|  | @ -282,7 +282,7 @@ struct ConvertToRaw<double> { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template<typename V, typename T> | template<typename V, typename T> | ||||||
| MakeSigned<T> Interpreter::checked_signed_truncate(V value) | MakeSigned<T> BytecodeInterpreter::checked_signed_truncate(V value) | ||||||
| { | { | ||||||
|     if (isnan(value) || isinf(value)) { // "undefined", let's just trap.
 |     if (isnan(value) || isinf(value)) { // "undefined", let's just trap.
 | ||||||
|         m_do_trap = true; |         m_do_trap = true; | ||||||
|  | @ -305,7 +305,7 @@ MakeSigned<T> Interpreter::checked_signed_truncate(V value) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<typename V, typename T> | template<typename V, typename T> | ||||||
| MakeUnsigned<T> Interpreter::checked_unsigned_truncate(V value) | MakeUnsigned<T> BytecodeInterpreter::checked_unsigned_truncate(V value) | ||||||
| { | { | ||||||
|     if (isnan(value) || isinf(value)) { // "undefined", let's just trap.
 |     if (isnan(value) || isinf(value)) { // "undefined", let's just trap.
 | ||||||
|         m_do_trap = true; |         m_do_trap = true; | ||||||
|  | @ -326,7 +326,7 @@ MakeUnsigned<T> Interpreter::checked_unsigned_truncate(V value) | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Vector<Value> Interpreter::pop_values(Configuration& configuration, size_t count) | Vector<Value> BytecodeInterpreter::pop_values(Configuration& configuration, size_t count) | ||||||
| { | { | ||||||
|     Vector<Value> results; |     Vector<Value> results; | ||||||
|     for (size_t i = 0; i < count; ++i) { |     for (size_t i = 0; i < count; ++i) { | ||||||
|  | @ -339,28 +339,10 @@ Vector<Value> Interpreter::pop_values(Configuration& configuration, size_t count | ||||||
|     return results; |     return results; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip, const Instruction& instruction) | void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPointer& ip, const Instruction& instruction) | ||||||
| { | { | ||||||
|     dbgln_if(WASM_TRACE_DEBUG, "Executing instruction {} at ip {}", instruction_name(instruction.opcode()), ip.value()); |     dbgln_if(WASM_TRACE_DEBUG, "Executing instruction {} at ip {}", instruction_name(instruction.opcode()), ip.value()); | ||||||
| 
 | 
 | ||||||
|     if (pre_interpret_hook && *pre_interpret_hook) { |  | ||||||
|         auto result = pre_interpret_hook->operator()(configuration, ip, instruction); |  | ||||||
|         if (!result) { |  | ||||||
|             m_do_trap = true; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ScopeGuard guard { [&] { |  | ||||||
|         if (post_interpret_hook && *post_interpret_hook) { |  | ||||||
|             auto result = post_interpret_hook->operator()(configuration, ip, instruction, *this); |  | ||||||
|             if (!result) { |  | ||||||
|                 m_do_trap = true; |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } }; |  | ||||||
| 
 |  | ||||||
|     switch (instruction.opcode().value()) { |     switch (instruction.opcode().value()) { | ||||||
|     case Instructions::unreachable.value(): |     case Instructions::unreachable.value(): | ||||||
|         m_do_trap = true; |         m_do_trap = true; | ||||||
|  | @ -912,4 +894,28 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void DebuggerBytecodeInterpreter::interpret(Configuration& configuration, InstructionPointer& ip, const Instruction& instruction) | ||||||
|  | { | ||||||
|  |     if (pre_interpret_hook) { | ||||||
|  |         auto result = pre_interpret_hook(configuration, ip, instruction); | ||||||
|  |         if (!result) { | ||||||
|  |             m_do_trap = true; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ScopeGuard guard { [&] { | ||||||
|  |         if (post_interpret_hook) { | ||||||
|  |             auto result = post_interpret_hook(configuration, ip, instruction, *this); | ||||||
|  |             if (!result) { | ||||||
|  |                 m_do_trap = true; | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } }; | ||||||
|  | 
 | ||||||
|  |     BytecodeInterpreter::interpret(configuration, ip, instruction); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -11,15 +11,20 @@ | ||||||
| namespace Wasm { | namespace Wasm { | ||||||
| 
 | 
 | ||||||
| struct Interpreter { | struct Interpreter { | ||||||
|     void interpret(Configuration&); |     virtual ~Interpreter() = default; | ||||||
|     bool did_trap() const { return m_do_trap; } |     virtual void interpret(Configuration&) = 0; | ||||||
|     void clear_trap() { m_do_trap = false; } |     virtual bool did_trap() const = 0; | ||||||
|  |     virtual void clear_trap() = 0; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
|     Function<bool(Configuration&, InstructionPointer&, const Instruction&)>* pre_interpret_hook { nullptr }; | struct BytecodeInterpreter : public Interpreter { | ||||||
|     Function<bool(Configuration&, InstructionPointer&, const Instruction&, const Interpreter&)>* post_interpret_hook { nullptr }; |     virtual void interpret(Configuration&) override; | ||||||
|  |     virtual ~BytecodeInterpreter() override = default; | ||||||
|  |     virtual bool did_trap() const override { return m_do_trap; } | ||||||
|  |     virtual void clear_trap() override { m_do_trap = false; } | ||||||
| 
 | 
 | ||||||
| private: | protected: | ||||||
|     void interpret(Configuration&, InstructionPointer&, const Instruction&); |     virtual void interpret(Configuration&, InstructionPointer&, const Instruction&); | ||||||
|     void branch_to_label(Configuration&, LabelIndex); |     void branch_to_label(Configuration&, LabelIndex); | ||||||
|     ReadonlyBytes load_from_memory(Configuration&, const Instruction&, size_t); |     ReadonlyBytes load_from_memory(Configuration&, const Instruction&, size_t); | ||||||
|     void store_to_memory(Configuration&, const Instruction&, ReadonlyBytes data); |     void store_to_memory(Configuration&, const Instruction&, ReadonlyBytes data); | ||||||
|  | @ -44,4 +49,14 @@ private: | ||||||
|     bool m_do_trap { false }; |     bool m_do_trap { false }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct DebuggerBytecodeInterpreter : public BytecodeInterpreter { | ||||||
|  |     virtual ~DebuggerBytecodeInterpreter() override = default; | ||||||
|  | 
 | ||||||
|  |     Function<bool(Configuration&, InstructionPointer&, const Instruction&)> pre_interpret_hook; | ||||||
|  |     Function<bool(Configuration&, InstructionPointer&, const Instruction&, const Interpreter&)> post_interpret_hook; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     virtual void interpret(Configuration&, InstructionPointer&, const Instruction&) override; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ static auto g_stdout = Core::OutputFileStream::standard_error(); | ||||||
| static Wasm::Printer g_printer { g_stdout }; | static Wasm::Printer g_printer { g_stdout }; | ||||||
| static bool g_continue { false }; | static bool g_continue { false }; | ||||||
| static void (*old_signal)(int); | static void (*old_signal)(int); | ||||||
|  | static Wasm::DebuggerBytecodeInterpreter g_interpreter; | ||||||
| 
 | 
 | ||||||
| static void print_buffer(ReadonlyBytes buffer, int split) | static void print_buffer(ReadonlyBytes buffer, int split) | ||||||
| { | { | ||||||
|  | @ -190,7 +191,11 @@ static bool pre_interpret_hook(Wasm::Configuration& config, Wasm::InstructionPoi | ||||||
|             for (auto& param : type.parameters()) |             for (auto& param : type.parameters()) | ||||||
|                 values.append(Wasm::Value { param, values_to_push.take_last() }); |                 values.append(Wasm::Value { param, values_to_push.take_last() }); | ||||||
| 
 | 
 | ||||||
|             auto result = config.call(*address, move(values)); |             Wasm::Result result { Wasm::Trap {} }; | ||||||
|  |             { | ||||||
|  |                 Wasm::Configuration::CallFrameHandle handle { config }; | ||||||
|  |                 result = config.call(g_interpreter, *address, move(values)); | ||||||
|  |             } | ||||||
|             if (result.is_trap()) |             if (result.is_trap()) | ||||||
|                 warnln("Execution trapped!"); |                 warnln("Execution trapped!"); | ||||||
|             if (!result.values().is_empty()) |             if (!result.values().is_empty()) | ||||||
|  | @ -328,8 +333,8 @@ int main(int argc, char* argv[]) | ||||||
|         Core::EventLoop main_loop; |         Core::EventLoop main_loop; | ||||||
|         if (debug) { |         if (debug) { | ||||||
|             g_line_editor = Line::Editor::construct(); |             g_line_editor = Line::Editor::construct(); | ||||||
|             machine.pre_interpret_hook = pre_interpret_hook; |             g_interpreter.pre_interpret_hook = pre_interpret_hook; | ||||||
|             machine.post_interpret_hook = post_interpret_hook; |             g_interpreter.post_interpret_hook = post_interpret_hook; | ||||||
|         } |         } | ||||||
|         // First, resolve the linked modules
 |         // First, resolve the linked modules
 | ||||||
|         NonnullOwnPtrVector<Wasm::ModuleInstance> linked_instances; |         NonnullOwnPtrVector<Wasm::ModuleInstance> linked_instances; | ||||||
|  | @ -433,7 +438,7 @@ int main(int argc, char* argv[]) | ||||||
|                 outln(); |                 outln(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             auto result = machine.invoke(run_address.value(), move(values)); |             auto result = machine.invoke(g_interpreter, run_address.value(), move(values)); | ||||||
| 
 | 
 | ||||||
|             if (debug) { |             if (debug) { | ||||||
|                 Wasm::Configuration config { machine.store() }; |                 Wasm::Configuration config { machine.store() }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ali Mohammad Pur
						Ali Mohammad Pur