LibWeb: Make RopeString subclass so PrimitiveString can be smaller

By moving the LHS and RHS pointers used by rope strings into a
RopeString subclass, we shrink PrimitiveString by 16 bytes. Most strings
are not rope strings, so this ends up saving quite a bit of memory.
This commit is contained in:
Andreas Kling 2025-03-30 00:08:39 +00:00 committed by Andreas Kling
commit 152691f9eb
Notes: github-actions[bot] 2025-03-30 06:17:46 +00:00
2 changed files with 56 additions and 23 deletions

View file

@ -20,14 +20,17 @@
namespace JS {
GC_DEFINE_ALLOCATOR(PrimitiveString);
GC_DEFINE_ALLOCATOR(RopeString);
PrimitiveString::PrimitiveString(PrimitiveString& lhs, PrimitiveString& rhs)
: m_is_rope(true)
, m_lhs(&lhs)
, m_rhs(&rhs)
RopeString::RopeString(GC::Ref<PrimitiveString> lhs, GC::Ref<PrimitiveString> rhs)
: PrimitiveString(RopeTag::Rope)
, m_lhs(lhs)
, m_rhs(rhs)
{
}
RopeString::~RopeString() = default;
PrimitiveString::PrimitiveString(String string)
: m_utf8_string(move(string))
{
@ -46,13 +49,11 @@ PrimitiveString::~PrimitiveString()
vm().utf16_string_cache().remove(*m_utf16_string);
}
void PrimitiveString::visit_edges(Cell::Visitor& visitor)
void RopeString::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
if (m_is_rope) {
visitor.visit(m_lhs);
visitor.visit(m_rhs);
}
visitor.visit(m_lhs);
visitor.visit(m_rhs);
}
bool PrimitiveString::is_empty() const
@ -192,7 +193,7 @@ GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, PrimitiveString& lhs, P
if (rhs_empty)
return lhs;
return vm.heap().allocate<PrimitiveString>(lhs, rhs);
return vm.heap().allocate<RopeString>(lhs, rhs);
}
void PrimitiveString::resolve_rope_if_needed(EncodingPreference preference) const
@ -200,6 +201,13 @@ void PrimitiveString::resolve_rope_if_needed(EncodingPreference preference) cons
if (!m_is_rope)
return;
auto const& rope_string = static_cast<RopeString const&>(*this);
return rope_string.resolve(preference);
}
void RopeString::resolve(EncodingPreference preference) const
{
// This vector will hold all the pieces of the rope that need to be assembled
// into the resolved string.
Vector<PrimitiveString const*> pieces;
@ -213,8 +221,9 @@ void PrimitiveString::resolve_rope_if_needed(EncodingPreference preference) cons
while (!stack.is_empty()) {
auto const* current = stack.take_last();
if (current->m_is_rope) {
stack.append(current->m_rhs);
stack.append(current->m_lhs);
auto& current_rope_string = static_cast<RopeString const&>(*current);
stack.append(current_rope_string.m_rhs);
stack.append(current_rope_string.m_lhs);
continue;
}