diff options
author | Ali Mohammad Pur <mpfard@serenityos.org> | 2021-07-17 01:04:37 +0430 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-17 01:04:37 +0430 |
commit | 35394dbfaa23b44a293da85b20a63a10f73572c3 (patch) | |
tree | 152449f3fa61c4b32d70c6fb12896b32429aada2 | |
parent | 3099a6bf2add35ac6a0c7ce4cbb6c794d6269d19 (diff) | |
download | serenity-35394dbfaa23b44a293da85b20a63a10f73572c3.zip |
LibWasm: Some more performance stuff (#8812)
* wasm: Don't try to print the function results if it traps
* LibWasm: Inline some very hot functions
These are mostly pretty small functions too, and they were about ~10%
of runtime.
* LibWasm+Everywhere: Make the instruction count limit configurable
...and enable it for LibWeb and test-wasm.
Note that `wasm` will not be limited by this.
* LibWasm: Remove a useless use of ScopeGuard
There are no multiple exit paths in that function, so we can just put
the ending logic right at the end of the function instead.
8 files changed, 49 insertions, 27 deletions
diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index 2cb6abe619..d0b16d7d70 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -34,6 +34,7 @@ public: 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 07a81d7fe9..d923987bdc 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<Ex module.for_each_section_of_type<GlobalSection>([&](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<Value> {}, @@ -153,6 +155,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex Vector<Reference> 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<Value> {}, @@ -204,6 +208,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex return IterationDecision::Break; } Configuration config { m_store }; + if (m_should_limit_instruction_count) + config.enable_instruction_count_limit(); config.set_frame(Frame { main_module_instance, Vector<Value> {}, @@ -262,6 +268,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex segment.value().visit( [&](DataSection::Data::Active const& data) { Configuration config { m_store }; + if (m_should_limit_instruction_count) + config.enable_instruction_count_limit(); config.set_frame(Frame { main_module_instance, Vector<Value> {}, @@ -439,6 +447,8 @@ Result AbstractMachine::invoke(FunctionAddress address, Vector<Value> arguments) Result AbstractMachine::invoke(Interpreter& interpreter, FunctionAddress address, Vector<Value> 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 29d3c414b8..659a3bae78 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -130,26 +130,26 @@ public: } } - 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 @@ public: } template<typename T> - Optional<T> to() + ALWAYS_INLINE Optional<T> to() { Optional<T> result; m_value.visit( @@ -505,10 +505,13 @@ public: auto& store() const { return m_store; } auto& store() { return m_store; } + void enable_instruction_count_limit() { m_should_limit_instruction_count = true; } + private: Optional<InstantiationError> allocate_all_initial_phase(Module const&, ModuleInstance&, Vector<ExternValue>&, Vector<Value>& global_values); Optional<InstantiationError> allocate_all_final_phase(Module const&, ModuleInstance&, Vector<Vector<Reference>>& 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 06a87b010d..dedde43160 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 41d2caacdb..fc4bcb5c04 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h @@ -50,7 +50,7 @@ protected: T read_value(ReadonlyBytes data); Vector<Value> 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 04cef62746..580ad526e5 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Configuration.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/Configuration.h @@ -61,6 +61,9 @@ public: Result call(Interpreter&, FunctionAddress, Vector<Value> 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 @@ private: 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 96654696eb..d383994ad1 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 008bb2b273..3229aefb4b 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); + } } } } |