1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 09:34:57 +09:00

LibJS: Cache the Intl.Collator in String.prototype.localeCompare()

In the very common case that no special constructor options are provided
for the Intl.Collator when calling localeCompare() on a string, we can
cache and reuse a default-constructed Intl.Collator, saving lots of time
and space.

This shaves a fair bit of load time off of https://wpt.fyi/ where they
use Array.prototype.sort() and localeCompare() to sort a big JSON thing.

Time spent in sort():
- Before: 1656 ms
- After: 135 ms
This commit is contained in:
Andreas Kling 2025-01-23 18:20:29 +01:00 committed by Andreas Kling
parent 65c1c492f9
commit d465e2aa2b
Notes: github-actions[bot] 2025-01-23 20:39:21 +00:00
3 changed files with 26 additions and 1 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2020-2025, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -41,6 +42,7 @@
#include <LibJS/Runtime/GeneratorFunctionConstructor.h>
#include <LibJS/Runtime/GeneratorFunctionPrototype.h>
#include <LibJS/Runtime/GeneratorPrototype.h>
#include <LibJS/Runtime/Intl/Collator.h>
#include <LibJS/Runtime/Intl/CollatorConstructor.h>
#include <LibJS/Runtime/Intl/CollatorPrototype.h>
#include <LibJS/Runtime/Intl/DateTimeFormatConstructor.h>
@ -418,6 +420,16 @@ void Intrinsics::visit_edges(Visitor& visitor)
visitor.visit(m_##snake_name##_prototype);
JS_ENUMERATE_ITERATOR_PROTOTYPES
#undef __JS_ENUMERATE
visitor.visit(m_default_collator);
}
GC::Ref<Intl::Collator> Intrinsics::default_collator()
{
if (!m_default_collator) {
m_default_collator = as<Intl::Collator>(*MUST(construct(this->vm(), intl_collator_constructor(), js_undefined(), js_undefined())));
}
return *m_default_collator;
}
// 10.2.4 AddRestrictedFunctionProperties ( F, realm ), https://tc39.es/ecma262/#sec-addrestrictedfunctionproperties

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2020-2025, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -95,6 +96,8 @@ public:
JS_ENUMERATE_ITERATOR_PROTOTYPES
#undef __JS_ENUMERATE
[[nodiscard]] GC::Ref<Intl::Collator> default_collator();
private:
Intrinsics(Realm& realm)
: m_realm(realm)
@ -189,6 +192,8 @@ private:
GC::Ptr<Object> m_##snake_name##_prototype;
JS_ENUMERATE_ITERATOR_PROTOTYPES
#undef __JS_ENUMERATE
GC::Ptr<Intl::Collator> m_default_collator;
};
void add_restricted_function_properties(FunctionObject&, Realm&);

View file

@ -544,7 +544,15 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::locale_compare)
auto that_value = TRY(vm.argument(0).to_string(vm));
// 4. Let collator be ? Construct(%Collator%, « locales, options »).
auto collator = TRY(construct(vm, realm.intrinsics().intl_collator_constructor(), vm.argument(1), vm.argument(2)));
auto locales = vm.argument(1);
auto options = vm.argument(2);
// OPTIMIZATION: If both locales and options are undefined, we can use a cached default-constructed Collator.
GC::Ptr<Object> collator;
if (locales.is_undefined() && options.is_undefined())
collator = realm.intrinsics().default_collator();
else
collator = TRY(construct(vm, realm.intrinsics().intl_collator_constructor(), locales, options));
// 5. Return CompareStrings(collator, S, thatValue).
return Intl::compare_strings(static_cast<Intl::Collator const&>(*collator), string, that_value);