From f7bdc596b44508c73e20240feee86b2298ab910a Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Wed, 20 Aug 2025 13:54:14 +0200 Subject: [PATCH] LibWasm: Avoid allocations for the label stack as much as possible Namely, find an upper bound at validation time so we can allocate the space when entering the frame. Also drop labels at once instead of popping them off one at a time now that we're using a Vector. --- .../LibWasm/AbstractMachine/BytecodeInterpreter.cpp | 7 +++---- Libraries/LibWasm/AbstractMachine/Configuration.h | 4 +++- Libraries/LibWasm/AbstractMachine/Validator.cpp | 9 ++++++++- Libraries/LibWasm/AbstractMachine/Validator.h | 1 + Libraries/LibWasm/Types.h | 4 ++++ 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 47a9af93260..6a3cfe9de26 100644 --- a/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -267,8 +267,7 @@ void BytecodeInterpreter::interpret_impl(Configuration& configuration, Expressio RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); } case Instructions::return_.value(): { - while (configuration.label_stack().size() - 1 != configuration.frame().label_index()) - configuration.label_stack().take_last(); + configuration.label_stack().shrink(configuration.frame().label_index() + 1, true); configuration.ip() = max_ip_value; RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); } @@ -2233,8 +2232,8 @@ void BytecodeInterpreter::interpret_impl(Configuration& configuration, Expressio void BytecodeInterpreter::branch_to_label(Configuration& configuration, LabelIndex index) { dbgln_if(WASM_TRACE_DEBUG, "Branch to label with index {}...", index.value()); - for (size_t i = 0; i < index.value(); ++i) - configuration.label_stack().take_last(); + auto& label_stack = configuration.label_stack(); + label_stack.shrink(label_stack.size() - index.value(), true); auto label = configuration.label_stack().last(); dbgln_if(WASM_TRACE_DEBUG, "...which is actually IP {}, and has {} result(s)", label.continuation().value(), label.arity()); diff --git a/Libraries/LibWasm/AbstractMachine/Configuration.h b/Libraries/LibWasm/AbstractMachine/Configuration.h index d3fca15caf0..eb5e161bb18 100644 --- a/Libraries/LibWasm/AbstractMachine/Configuration.h +++ b/Libraries/LibWasm/AbstractMachine/Configuration.h @@ -25,6 +25,8 @@ public: frame.label_index() = m_label_stack.size(); if (auto hint = frame.expression().stack_usage_hint(); hint.has_value()) m_value_stack.ensure_capacity(*hint + m_value_stack.size()); + if (auto hint = frame.expression().frame_usage_hint(); hint.has_value()) + m_label_stack.ensure_capacity(*hint + m_label_stack.size()); m_frame_stack.append(move(frame)); m_label_stack.append(label); m_locals_base = m_frame_stack.unchecked_last().locals().data(); @@ -120,7 +122,7 @@ public: private: Store& m_store; Vector m_value_stack; - DoublyLinkedList m_label_stack; + Vector m_label_stack; DoublyLinkedList m_frame_stack; size_t m_depth { 0 }; u64 m_ip { 0 }; diff --git a/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Libraries/LibWasm/AbstractMachine/Validator.cpp index 19efac5e3b6..94a54ec45d0 100644 --- a/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -271,6 +271,7 @@ ErrorOr Validator::validate(CodeSection const& section) } function_validator.m_frames.empend(function_type, FrameKind::Function, (size_t)0); + function_validator.m_max_frame_size = max(function_validator.m_max_frame_size, function_validator.m_frames.size()); auto results = TRY(function_validator.validate(function.body(), function_type.results())); if (results.result_types.size() != function_type.results().size()) @@ -1971,6 +1972,7 @@ VALIDATE_INSTRUCTION(block) TRY(stack.take(parameters[parameters.size() - i])); m_frames.empend(block_type, FrameKind::Block, stack.size()); + m_max_frame_size = max(m_max_frame_size, m_frames.size()); for (auto& parameter : parameters) stack.append(parameter); @@ -1987,6 +1989,7 @@ VALIDATE_INSTRUCTION(loop) TRY(stack.take(parameters[parameters.size() - i])); m_frames.empend(block_type, FrameKind::Loop, stack.size()); + m_max_frame_size = max(m_max_frame_size, m_frames.size()); for (auto& parameter : parameters) stack.append(parameter); @@ -2007,6 +2010,7 @@ VALIDATE_INSTRUCTION(if_) TRY(stack.take(parameters[parameters.size() - i])); m_frames.empend(block_type, FrameKind::If, stack.size()); + m_max_frame_size = max(m_max_frame_size, m_frames.size()); for (auto& parameter : parameters) stack.append(parameter); @@ -3734,9 +3738,12 @@ ErrorOr Validator::validate(Ex for (auto& type : result_types) stack.append(type); m_frames.take_last(); - VERIFY(m_frames.is_empty()); expression.set_stack_usage_hint(stack.max_known_size()); + expression.set_frame_usage_hint(m_max_frame_size); + + VERIFY(m_frames.is_empty()); + m_max_frame_size = 0; // Now that we're in happy land, try to compile the expression down to a list of labels to help dispatch. expression.compiled_instructions = try_compile_instructions(expression, m_context.functions.span()); diff --git a/Libraries/LibWasm/AbstractMachine/Validator.h b/Libraries/LibWasm/AbstractMachine/Validator.h index 64b32befac4..69d59fd985a 100644 --- a/Libraries/LibWasm/AbstractMachine/Validator.h +++ b/Libraries/LibWasm/AbstractMachine/Validator.h @@ -361,6 +361,7 @@ private: Context m_context; Vector m_frames; + size_t m_max_frame_size { 0 }; COWVector m_globals_without_internal_globals; }; diff --git a/Libraries/LibWasm/Types.h b/Libraries/LibWasm/Types.h index 495f8409267..6093fc12de3 100644 --- a/Libraries/LibWasm/Types.h +++ b/Libraries/LibWasm/Types.h @@ -758,11 +758,15 @@ public: void set_stack_usage_hint(size_t value) const { m_stack_usage_hint = value; } auto stack_usage_hint() const { return m_stack_usage_hint; } + void set_frame_usage_hint(size_t value) const { m_frame_usage_hint = value; } + auto frame_usage_hint() const { return m_frame_usage_hint; } + mutable CompiledInstructions compiled_instructions; private: Vector m_instructions; mutable Optional m_stack_usage_hint; + mutable Optional m_frame_usage_hint; }; class GlobalSection {