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.
This commit is contained in:
Ali Mohammad Pur 2025-08-20 13:54:14 +02:00 committed by Ali Mohammad Pur
commit f7bdc596b4
Notes: github-actions[bot] 2025-08-26 13:22:01 +00:00
5 changed files with 19 additions and 6 deletions

View file

@ -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());

View file

@ -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<Value, 64, FastLastAccess::Yes> m_value_stack;
DoublyLinkedList<Label, 128> m_label_stack;
Vector<Label, 64> m_label_stack;
DoublyLinkedList<Frame, 128> m_frame_stack;
size_t m_depth { 0 };
u64 m_ip { 0 };

View file

@ -271,6 +271,7 @@ ErrorOr<void, ValidationError> 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::ExpressionTypeResult, ValidationError> 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());

View file

@ -361,6 +361,7 @@ private:
Context m_context;
Vector<Frame> m_frames;
size_t m_max_frame_size { 0 };
COWVector<GlobalType> m_globals_without_internal_globals;
};

View file

@ -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<Instruction> m_instructions;
mutable Optional<size_t> m_stack_usage_hint;
mutable Optional<size_t> m_frame_usage_hint;
};
class GlobalSection {