mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 10:08:10 +00:00
LibJS: Make the forward transition chain weakly cached
Before this patch, every shape would permanently remember every other shape it had ever transitioned to. This could lead to pathological accumulation of unused shape objects in some cases. Fix this by using WeakPtr instead of a strongly visited Shape* in the the forward transition chain map. This means that we will now miss out on some shape sharing opportunities, but since this is not required for correctness it doesn't matter. Note that the backward transition chain is still strongly cached, as it's necessary for the reification of property tables. An interesting future optimization could be to allow property tables to get garbage collected (by detaching them from the shape object) and then reconstituted from the backwards transition chain (if needed.)
This commit is contained in:
parent
8c96640157
commit
e0493c509e
2 changed files with 24 additions and 9 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -23,10 +23,23 @@ Shape* Shape::create_unique_clone() const
|
|||
return new_shape;
|
||||
}
|
||||
|
||||
Shape* Shape::get_or_prune_cached_forward_transition(TransitionKey const& key)
|
||||
{
|
||||
auto it = m_forward_transitions.find(key);
|
||||
if (it == m_forward_transitions.end())
|
||||
return nullptr;
|
||||
if (!it->value) {
|
||||
// The cached forward transition has gone stale (from garbage collection). Prune it.
|
||||
m_forward_transitions.remove(it);
|
||||
return nullptr;
|
||||
}
|
||||
return it->value;
|
||||
}
|
||||
|
||||
Shape* Shape::create_put_transition(const StringOrSymbol& property_name, PropertyAttributes attributes)
|
||||
{
|
||||
TransitionKey key { property_name, attributes };
|
||||
if (auto* existing_shape = m_forward_transitions.get(key).value_or(nullptr))
|
||||
if (auto* existing_shape = get_or_prune_cached_forward_transition(key))
|
||||
return existing_shape;
|
||||
auto* new_shape = heap().allocate_without_global_object<Shape>(*this, property_name, attributes, TransitionType::Put);
|
||||
m_forward_transitions.set(key, new_shape);
|
||||
|
@ -36,7 +49,7 @@ Shape* Shape::create_put_transition(const StringOrSymbol& property_name, Propert
|
|||
Shape* Shape::create_configure_transition(const StringOrSymbol& property_name, PropertyAttributes attributes)
|
||||
{
|
||||
TransitionKey key { property_name, attributes };
|
||||
if (auto* existing_shape = m_forward_transitions.get(key).value_or(nullptr))
|
||||
if (auto* existing_shape = get_or_prune_cached_forward_transition(key))
|
||||
return existing_shape;
|
||||
auto* new_shape = heap().allocate_without_global_object<Shape>(*this, property_name, attributes, TransitionType::Configure);
|
||||
m_forward_transitions.set(key, new_shape);
|
||||
|
@ -88,9 +101,6 @@ void Shape::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(m_prototype);
|
||||
visitor.visit(m_previous);
|
||||
m_property_name.visit_edges(visitor);
|
||||
for (auto& it : m_forward_transitions)
|
||||
visitor.visit(it.value);
|
||||
|
||||
if (m_property_table) {
|
||||
for (auto& it : *m_property_table)
|
||||
it.key.visit_edges(visitor);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue