mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +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
Notes:
sideshowbarker
2024-07-18 17:55:24 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/e0493c509e3
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);
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Runtime/PropertyAttributes.h>
|
||||
|
@ -31,7 +33,9 @@ struct TransitionKey {
|
|||
}
|
||||
};
|
||||
|
||||
class Shape final : public Cell {
|
||||
class Shape final
|
||||
: public Cell
|
||||
, public Weakable<Shape> {
|
||||
public:
|
||||
virtual ~Shape() override;
|
||||
|
||||
|
@ -84,6 +88,7 @@ private:
|
|||
virtual const char* class_name() const override { return "Shape"; }
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
Shape* get_or_prune_cached_forward_transition(TransitionKey const&);
|
||||
void ensure_property_table() const;
|
||||
|
||||
PropertyAttributes m_attributes { 0 };
|
||||
|
@ -94,7 +99,7 @@ private:
|
|||
|
||||
mutable OwnPtr<HashMap<StringOrSymbol, PropertyMetadata>> m_property_table;
|
||||
|
||||
HashMap<TransitionKey, Shape*> m_forward_transitions;
|
||||
HashMap<TransitionKey, WeakPtr<Shape>> m_forward_transitions;
|
||||
Shape* m_previous { nullptr };
|
||||
StringOrSymbol m_property_name;
|
||||
Object* m_prototype { nullptr };
|
||||
|
|
Loading…
Reference in a new issue