1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 10:47:35 +00:00

LibJS: Stop eagerly creating the backing store for IndexedProperties

The vast majority of objects do not, and are unlikely to ever need
indexed property storage. By delaying the creation of the backing
store of IndexedProperties we reduce the memory used by each object
and reduce allocation and deallocation by somewhere between 20 and
30%
This commit is contained in:
Anonymous 2022-02-11 22:46:17 -08:00 committed by Andreas Kling
parent d1cc67bbe1
commit 34a4ce7955
2 changed files with 32 additions and 4 deletions

View file

@ -77,6 +77,10 @@ bool SimpleIndexedPropertyStorage::set_array_like_size(size_t new_size)
return true;
}
GenericIndexedPropertyStorage::GenericIndexedPropertyStorage()
{
}
GenericIndexedPropertyStorage::GenericIndexedPropertyStorage(SimpleIndexedPropertyStorage&& storage)
{
m_array_size = storage.array_like_size();
@ -216,11 +220,14 @@ void IndexedPropertyIterator::skip_empty_indices()
Optional<ValueAndAttributes> IndexedProperties::get(u32 index) const
{
if (!m_storage)
return {};
return m_storage->get(index);
}
void IndexedProperties::put(u32 index, Value value, PropertyAttributes attributes)
{
ensure_storage();
if (m_storage->is_simple_storage() && (attributes != default_attributes || index > (array_like_size() + SPARSE_ARRAY_HOLE_THRESHOLD))) {
switch_to_generic_storage();
}
@ -230,12 +237,14 @@ void IndexedProperties::put(u32 index, Value value, PropertyAttributes attribute
void IndexedProperties::remove(u32 index)
{
VERIFY(m_storage);
VERIFY(m_storage->has_index(index));
m_storage->remove(index);
}
bool IndexedProperties::set_array_like_size(size_t new_size)
{
ensure_storage();
auto current_array_like_size = array_like_size();
// We can't use simple storage for lengths that don't fit in an i32.
@ -252,6 +261,8 @@ bool IndexedProperties::set_array_like_size(size_t new_size)
size_t IndexedProperties::real_size() const
{
if (!m_storage)
return 0;
if (m_storage->is_simple_storage()) {
auto& packed_elements = static_cast<const SimpleIndexedPropertyStorage&>(*m_storage).elements();
size_t size = 0;
@ -266,6 +277,8 @@ size_t IndexedProperties::real_size() const
Vector<u32> IndexedProperties::indices() const
{
if (!m_storage)
return {};
if (m_storage->is_simple_storage()) {
const auto& storage = static_cast<const SimpleIndexedPropertyStorage&>(*m_storage);
const auto& elements = storage.elements();
@ -285,8 +298,18 @@ Vector<u32> IndexedProperties::indices() const
void IndexedProperties::switch_to_generic_storage()
{
if (!m_storage) {
m_storage = make<GenericIndexedPropertyStorage>();
return;
}
auto& storage = static_cast<SimpleIndexedPropertyStorage&>(*m_storage);
m_storage = make<GenericIndexedPropertyStorage>(move(storage));
}
void IndexedProperties::ensure_storage()
{
if (!m_storage)
m_storage = make<SimpleIndexedPropertyStorage>();
}
}

View file

@ -72,6 +72,7 @@ private:
class GenericIndexedPropertyStorage final : public IndexedPropertyStorage {
public:
explicit GenericIndexedPropertyStorage(SimpleIndexedPropertyStorage&&);
explicit GenericIndexedPropertyStorage();
virtual bool has_index(u32 index) const override;
virtual Optional<ValueAndAttributes> get(u32 index) const override;
@ -116,11 +117,12 @@ public:
IndexedProperties() = default;
explicit IndexedProperties(Vector<Value> values)
: m_storage(make<SimpleIndexedPropertyStorage>(move(values)))
{
if (!values.is_empty())
m_storage = make<SimpleIndexedPropertyStorage>(move(values));
}
bool has_index(u32 index) const { return m_storage->has_index(index); }
bool has_index(u32 index) const { return m_storage ? m_storage->has_index(index) : false; }
Optional<ValueAndAttributes> get(u32 index) const;
void put(u32 index, Value value, PropertyAttributes attributes = default_attributes);
void remove(u32 index);
@ -131,7 +133,7 @@ public:
IndexedPropertyIterator end() const { return IndexedPropertyIterator(*this, array_like_size(), false); };
bool is_empty() const { return array_like_size() == 0; }
size_t array_like_size() const { return m_storage->array_like_size(); }
size_t array_like_size() const { return m_storage ? m_storage->array_like_size() : 0; }
bool set_array_like_size(size_t);
size_t real_size() const;
@ -141,6 +143,8 @@ public:
template<typename Callback>
void for_each_value(Callback callback)
{
if (!m_storage)
return;
if (m_storage->is_simple_storage()) {
for (auto& value : static_cast<SimpleIndexedPropertyStorage&>(*m_storage).elements())
callback(value);
@ -152,8 +156,9 @@ public:
private:
void switch_to_generic_storage();
void ensure_storage();
NonnullOwnPtr<IndexedPropertyStorage> m_storage { make<SimpleIndexedPropertyStorage>() };
OwnPtr<IndexedPropertyStorage> m_storage;
};
}