diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index 2cb6abe619d84f..d0b16d7d707849 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -34,6 +34,7 @@ class WebAssemblyModule final : public JS::Object { explicit WebAssemblyModule(JS::Object& prototype) : JS::Object(prototype) { + m_machine.enable_instruction_count_limit(); } static Wasm::AbstractMachine& machine() { return m_machine; } diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 07a81d7fe9005f..d923987bdc700e 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -128,6 +128,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector([&](auto& global_section) { for (auto& entry : global_section.entries()) { Configuration config { m_store }; + if (m_should_limit_instruction_count) + config.enable_instruction_count_limit(); config.set_frame(Frame { auxiliary_instance, Vector {}, @@ -153,6 +155,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector references; for (auto& entry : segment.init) { Configuration config { m_store }; + if (m_should_limit_instruction_count) + config.enable_instruction_count_limit(); config.set_frame(Frame { main_module_instance, Vector {}, @@ -204,6 +208,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector {}, @@ -262,6 +268,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector {}, @@ -439,6 +447,8 @@ Result AbstractMachine::invoke(FunctionAddress address, Vector arguments) Result AbstractMachine::invoke(Interpreter& interpreter, FunctionAddress address, Vector arguments) { Configuration configuration { m_store }; + if (m_should_limit_instruction_count) + configuration.enable_instruction_count_limit(); return configuration.call(interpreter, address, move(arguments)); } diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index 29d3c414b80ea5..659a3bae789f2c 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -130,26 +130,26 @@ class Value { } } - Value(Value const& value) + ALWAYS_INLINE Value(Value const& value) : m_value(AnyValueType { value.m_value }) , m_type(value.m_type) { } - Value(Value&& value) + ALWAYS_INLINE Value(Value&& value) : m_value(move(value.m_value)) , m_type(move(value.m_type)) { } - Value& operator=(Value&& value) + ALWAYS_INLINE Value& operator=(Value&& value) { m_value = move(value.m_value); m_type = move(value.m_type); return *this; } - Value& operator=(Value const& value) + ALWAYS_INLINE Value& operator=(Value const& value) { m_value = value.m_value; m_type = value.m_type; @@ -157,7 +157,7 @@ class Value { } template - Optional to() + ALWAYS_INLINE Optional to() { Optional result; m_value.visit( @@ -505,10 +505,13 @@ class AbstractMachine { auto& store() const { return m_store; } auto& store() { return m_store; } + void enable_instruction_count_limit() { m_should_limit_instruction_count = true; } + private: Optional allocate_all_initial_phase(Module const&, ModuleInstance&, Vector&, Vector& global_values); Optional allocate_all_final_phase(Module const&, ModuleInstance&, Vector>& elements); Store m_store; + bool m_should_limit_instruction_count { false }; }; class Linker { diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 06a87b010dc8ef..dedde431607c59 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -37,12 +37,15 @@ void BytecodeInterpreter::interpret(Configuration& configuration) auto& instructions = configuration.frame().expression().instructions(); auto max_ip_value = InstructionPointer { instructions.size() }; auto& current_ip_value = configuration.ip(); + auto const should_limit_instruction_count = configuration.should_limit_instruction_count(); u64 executed_instructions = 0; while (current_ip_value < max_ip_value) { - if (executed_instructions++ >= Constants::max_allowed_executed_instructions_per_call) [[unlikely]] { - m_trap = Trap { "Exceeded maximum allowed number of instructions" }; - return; + if (should_limit_instruction_count) { + if (executed_instructions++ >= Constants::max_allowed_executed_instructions_per_call) [[unlikely]] { + m_trap = Trap { "Exceeded maximum allowed number of instructions" }; + return; + } } auto& instruction = instructions[current_ip_value.value()]; auto old_ip = current_ip_value; @@ -1123,17 +1126,15 @@ void DebuggerBytecodeInterpreter::interpret(Configuration& configuration, Instru } } - ScopeGuard guard { [&] { - if (post_interpret_hook) { - auto result = post_interpret_hook(configuration, ip, instruction, *this); - if (!result) { - m_trap = Trap { "Trapped by user request" }; - return; - } - } - } }; - BytecodeInterpreter::interpret(configuration, ip, instruction); + + if (post_interpret_hook) { + auto result = post_interpret_hook(configuration, ip, instruction, *this); + if (!result) { + m_trap = Trap { "Trapped by user request" }; + return; + } + } } } diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h index 41d2caacdbac48..fc4bcb5c04b326 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h @@ -50,7 +50,7 @@ struct BytecodeInterpreter : public Interpreter { T read_value(ReadonlyBytes data); Vector pop_values(Configuration& configuration, size_t count); - bool trap_if_not(bool value, StringView reason) + ALWAYS_INLINE bool trap_if_not(bool value, StringView reason) { if (!value) m_trap = Trap { reason }; diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Configuration.h b/Userland/Libraries/LibWasm/AbstractMachine/Configuration.h index 04cef62746aaac..580ad526e5630b 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Configuration.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/Configuration.h @@ -61,6 +61,9 @@ class Configuration { Result call(Interpreter&, FunctionAddress, Vector arguments); Result execute(Interpreter&); + void enable_instruction_count_limit() { m_should_limit_instruction_count = true; } + bool should_limit_instruction_count() const { return m_should_limit_instruction_count; } + void dump_stack(); private: @@ -69,6 +72,7 @@ class Configuration { Stack m_stack; size_t m_depth { 0 }; InstructionPointer m_ip; + bool m_should_limit_instruction_count { false }; }; } diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp index 96654696eb9522..d383994ad14378 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp @@ -25,6 +25,7 @@ namespace Web::Bindings { WebAssemblyObject::WebAssemblyObject(JS::GlobalObject& global_object) : Object(*global_object.object_prototype()) { + s_abstract_machine.enable_instruction_count_limit(); } void WebAssemblyObject::initialize(JS::GlobalObject& global_object) diff --git a/Userland/Utilities/wasm.cpp b/Userland/Utilities/wasm.cpp index 008bb2b27311fd..3229aefb4b7195 100644 --- a/Userland/Utilities/wasm.cpp +++ b/Userland/Utilities/wasm.cpp @@ -512,14 +512,16 @@ int main(int argc, char* argv[]) if (debug) launch_repl(); - if (result.is_trap()) - warnln("Execution trapped!"); - if (!result.values().is_empty()) - warnln("Returned:"); - for (auto& value : result.values()) { - Wasm::Printer printer { stream }; - g_stdout.write(" -> "sv.bytes()); - g_printer.print(value); + if (result.is_trap()) { + warnln("Execution trapped: {}", result.trap().reason); + } else { + if (!result.values().is_empty()) + warnln("Returned:"); + for (auto& value : result.values()) { + Wasm::Printer printer { stream }; + g_stdout.write(" -> "sv.bytes()); + g_printer.print(value); + } } } }