From 34a4ce7955c52a457a9e42fe80aa3c28717be8a9 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Fri, 11 Feb 2022 22:46:17 -0800 Subject: [PATCH] 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% --- .../LibJS/Runtime/IndexedProperties.cpp | 23 +++++++++++++++++++ .../LibJS/Runtime/IndexedProperties.h | 13 +++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp b/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp index 1d7bd301e5..bae17bbd2b 100644 --- a/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp +++ b/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp @@ -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 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(*m_storage).elements(); size_t size = 0; @@ -266,6 +277,8 @@ size_t IndexedProperties::real_size() const Vector IndexedProperties::indices() const { + if (!m_storage) + return {}; if (m_storage->is_simple_storage()) { const auto& storage = static_cast(*m_storage); const auto& elements = storage.elements(); @@ -285,8 +298,18 @@ Vector IndexedProperties::indices() const void IndexedProperties::switch_to_generic_storage() { + if (!m_storage) { + m_storage = make(); + return; + } auto& storage = static_cast(*m_storage); m_storage = make(move(storage)); } +void IndexedProperties::ensure_storage() +{ + if (!m_storage) + m_storage = make(); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/IndexedProperties.h b/Userland/Libraries/LibJS/Runtime/IndexedProperties.h index 7fa69abae2..51826f41f5 100644 --- a/Userland/Libraries/LibJS/Runtime/IndexedProperties.h +++ b/Userland/Libraries/LibJS/Runtime/IndexedProperties.h @@ -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 get(u32 index) const override; @@ -116,11 +117,12 @@ public: IndexedProperties() = default; explicit IndexedProperties(Vector values) - : m_storage(make(move(values))) { + if (!values.is_empty()) + m_storage = make(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 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 void for_each_value(Callback callback) { + if (!m_storage) + return; if (m_storage->is_simple_storage()) { for (auto& value : static_cast(*m_storage).elements()) callback(value); @@ -152,8 +156,9 @@ public: private: void switch_to_generic_storage(); + void ensure_storage(); - NonnullOwnPtr m_storage { make() }; + OwnPtr m_storage; }; }