From edb5547e370cfc4283cd5beb4fec694a171d4c70 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 3 May 2025 21:12:00 +0200 Subject: [PATCH] LibJS: Don't incrementally delete PropertyNameIterator while iterating We were spending a lot of time removing each property name from the iterator's underlying HashMap while iterating over it. This wasn't actually necessary, so let's stop doing it and instead just iterate over the property names with a stored HashTable iterator. 1.10x speedup on MicroBench/for-in-indexed-properties.js --- Libraries/LibJS/Bytecode/Interpreter.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index d224b7979e9..1ae0004e45d 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1728,20 +1728,20 @@ public: ThrowCompletionOr next(VM&, bool& done, Value& value) override { while (true) { - if (m_properties.is_empty()) { + if (m_iterator == m_properties.end()) { done = true; return {}; } - auto it = *m_properties.begin(); - ScopeGuard remove_first = [&] { m_properties.take_first(); }; + auto const& entry = *m_iterator; + ScopeGuard remove_first = [&] { ++m_iterator; }; // If the property is deleted, don't include it (invariant no. 2) - if (!TRY(m_object->has_property(it.key.key))) + if (!TRY(m_object->has_property(entry.key.key))) continue; done = false; - value = it.value; + value = entry.value; return {}; } } @@ -1751,6 +1751,7 @@ private: : Object(realm, nullptr) , m_object(object) , m_properties(move(properties)) + , m_iterator(m_properties.begin()) { } @@ -1763,6 +1764,7 @@ private: GC::Ref m_object; OrderedHashMap m_properties; + decltype(m_properties.begin()) m_iterator; }; GC_DEFINE_ALLOCATOR(PropertyNameIterator);