diff --git a/Libraries/LibJS/Runtime/Intrinsics.cpp b/Libraries/LibJS/Runtime/Intrinsics.cpp index 3058b073e6b..f3edc27623f 100644 --- a/Libraries/LibJS/Runtime/Intrinsics.cpp +++ b/Libraries/LibJS/Runtime/Intrinsics.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022-2023, Linus Groh + * Copyright (c) 2020-2025, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -41,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -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 Intrinsics::default_collator() +{ + if (!m_default_collator) { + m_default_collator = as(*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 diff --git a/Libraries/LibJS/Runtime/Intrinsics.h b/Libraries/LibJS/Runtime/Intrinsics.h index 68f29ffb334..6d8deefe31e 100644 --- a/Libraries/LibJS/Runtime/Intrinsics.h +++ b/Libraries/LibJS/Runtime/Intrinsics.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022-2023, Linus Groh + * Copyright (c) 2020-2025, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -95,6 +96,8 @@ public: JS_ENUMERATE_ITERATOR_PROTOTYPES #undef __JS_ENUMERATE + [[nodiscard]] GC::Ref default_collator(); + private: Intrinsics(Realm& realm) : m_realm(realm) @@ -189,6 +192,8 @@ private: GC::Ptr m_##snake_name##_prototype; JS_ENUMERATE_ITERATOR_PROTOTYPES #undef __JS_ENUMERATE + + GC::Ptr m_default_collator; }; void add_restricted_function_properties(FunctionObject&, Realm&); diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp index efe8a8b24cf..2e694363b7c 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -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 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(*collator), string, that_value);