From 620c495d3196194499776f6f1e9fc7638032c33c Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 11 Jun 2023 19:46:52 +0200 Subject: [PATCH] LibJS: Skip lazy intrinsic allocation check for objects without them Most JS::Objects don't have lazily-allocated intrinsic properties, so let's avoid doing hash lookups by putting a flag on JS::Object that tells us whether it's present in s_intrinsics. Takes CPU time spent in those hash lookups from 1-2.5% to nothing on various JS heavy pages. --- Userland/Libraries/LibJS/Runtime/Object.cpp | 14 +++++++++----- Userland/Libraries/LibJS/Runtime/Object.h | 3 +++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index ebfe8d84f6..7da195839d 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -70,7 +70,8 @@ Object::Object(Shape& shape) Object::~Object() { - s_intrinsics.remove(this); + if (m_has_intrinsic_accessors) + s_intrinsics.remove(this); } ThrowCompletionOr Object::initialize(Realm&) @@ -1086,8 +1087,10 @@ Optional Object::storage_get(PropertyKey const& property_key if (!metadata.has_value()) return {}; - if (auto accessor = find_intrinsic_accessor(this, property_key); accessor.has_value()) - const_cast(*this).m_storage[metadata->offset] = (*accessor)(shape().realm()); + if (m_has_intrinsic_accessors) { + if (auto accessor = find_intrinsic_accessor(this, property_key); accessor.has_value()) + const_cast(*this).m_storage[metadata->offset] = (*accessor)(shape().realm()); + } value = m_storage[metadata->offset]; attributes = metadata->attributes; @@ -1116,7 +1119,7 @@ void Object::storage_set(PropertyKey const& property_key, ValueAndAttributes con return; } - if (property_key.is_string()) { + if (m_has_intrinsic_accessors && property_key.is_string()) { if (auto intrinsics = s_intrinsics.find(this); intrinsics != s_intrinsics.end()) intrinsics->value.remove(property_key.as_string()); } @@ -1158,7 +1161,7 @@ void Object::storage_delete(PropertyKey const& property_key) if (property_key.is_number()) return m_indexed_properties.remove(property_key.as_number()); - if (property_key.is_string()) { + if (m_has_intrinsic_accessors && property_key.is_string()) { if (auto intrinsics = s_intrinsics.find(this); intrinsics != s_intrinsics.end()) intrinsics->value.remove(property_key.as_string()); } @@ -1217,6 +1220,7 @@ void Object::define_intrinsic_accessor(PropertyKey const& property_key, Property storage_set(property_key, { {}, attributes }); + m_has_intrinsic_accessors = true; auto& intrinsics = s_intrinsics.ensure(this); intrinsics.set(property_key.as_string(), move(accessor)); } diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index 2b56dd9257..b047a59abf 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -212,6 +212,9 @@ private: Object* prototype() { return shape().prototype(); } Object const* prototype() const { return shape().prototype(); } + // True if this object has lazily allocated intrinsic properties. + bool m_has_intrinsic_accessors { false }; + GCPtr m_shape; Vector m_storage; IndexedProperties m_indexed_properties;