Commit cd79e83f authored by Jakob Gruber's avatar Jakob Gruber Committed by V8 LUCI CQ

[intl] Refactor the icu object cache and unhandlify CompareStrings

The icu object cache consists of 5 keys at most -> change it from
an unordered_set to a plain array.

Possible return values of CompareStrings are {-1,0,1}. Return those
directly instead of going through Factory::NewNumberFromInt.

Bug: v8:12196
Change-Id: Ia42bb6b1a0ebdc99550f604aa79cb438b150ee88
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3149454
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76746}
parent 0d42c9d0
......@@ -9333,7 +9333,7 @@ void v8::Isolate::LocaleConfigurationChangeNotification() {
#ifdef V8_INTL_SUPPORT
i_isolate->ResetDefaultLocale();
i_isolate->ClearCachedIcuObjects();
i_isolate->clear_cached_icu_objects();
#endif // V8_INTL_SUPPORT
}
......
......@@ -1009,7 +1009,8 @@ BUILTIN(CollatorInternalCompare) {
// 7. Return CompareStrings(collator, X, Y).
icu::Collator* icu_collator = collator->icu_collator().raw();
CHECK_NOT_NULL(icu_collator);
return *Intl::CompareStrings(isolate, *icu_collator, string_x, string_y);
return Smi::FromInt(
Intl::CompareStrings(isolate, *icu_collator, string_x, string_y));
}
// ecma402 #sec-%segmentiteratorprototype%.next
......
......@@ -140,21 +140,25 @@ BUILTIN(StringPrototypeLocaleCompare) {
HandleScope handle_scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringLocaleCompare);
const char* method = "String.prototype.localeCompare";
static const char* const kMethod = "String.prototype.localeCompare";
#ifdef V8_INTL_SUPPORT
TO_THIS_STRING(str1, method);
TO_THIS_STRING(str1, kMethod);
Handle<String> str2;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, str2, Object::ToString(isolate, args.atOrUndefined(isolate, 1)));
RETURN_RESULT_OR_FAILURE(
isolate, Intl::StringLocaleCompare(
isolate, str1, str2, args.atOrUndefined(isolate, 2),
args.atOrUndefined(isolate, 3), method));
base::Optional<int> result = Intl::StringLocaleCompare(
isolate, str1, str2, args.atOrUndefined(isolate, 2),
args.atOrUndefined(isolate, 3), kMethod);
if (!result.has_value()) {
DCHECK(isolate->has_pending_exception());
return ReadOnlyRoots(isolate).exception();
}
return Smi::FromInt(result.value());
#else
DCHECK_LE(2, args.length());
TO_THIS_STRING(str1, method);
TO_THIS_STRING(str1, kMethod);
Handle<String> str2;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str2,
Object::ToString(isolate, args.at(1)));
......
......@@ -4800,48 +4800,47 @@ void Isolate::CollectSourcePositionsForAllBytecodeArrays() {
}
#ifdef V8_INTL_SUPPORT
namespace {
std::string GetStringFromLocale(Handle<Object> locales_obj) {
DCHECK(locales_obj->IsString() || locales_obj->IsUndefined());
if (locales_obj->IsString()) {
return std::string(String::cast(*locales_obj).ToCString().get());
}
return "";
std::string GetStringFromLocales(Isolate* isolate, Handle<Object> locales) {
if (locales->IsUndefined(isolate)) return "";
return std::string(String::cast(*locales).ToCString().get());
}
} // namespace
icu::UMemory* Isolate::get_cached_icu_object(ICUObjectCacheType cache_type,
Handle<Object> locales_obj) {
std::string locale = GetStringFromLocale(locales_obj);
auto value = icu_object_cache_.find(cache_type);
if (value == icu_object_cache_.end()) return nullptr;
bool StringEqualsLocales(Isolate* isolate, const std::string& str,
Handle<Object> locales) {
if (locales->IsUndefined(isolate)) return str == "";
return Handle<String>::cast(locales)->IsEqualTo(
base::VectorOf(str.c_str(), str.length()));
}
ICUCachePair pair = value->second;
if (pair.first != locale) return nullptr;
} // namespace
return pair.second.get();
icu::UMemory* Isolate::get_cached_icu_object(ICUObjectCacheType cache_type,
Handle<Object> locales) {
const ICUObjectCacheEntry& entry =
icu_object_cache_[static_cast<int>(cache_type)];
return StringEqualsLocales(this, entry.locales, locales) ? entry.obj.get()
: nullptr;
}
void Isolate::set_icu_object_in_cache(
ICUObjectCacheType cache_type, Handle<Object> locales_obj,
std::shared_ptr<icu::UMemory> icu_formatter) {
std::string locale = GetStringFromLocale(locales_obj);
ICUCachePair pair = std::make_pair(locale, icu_formatter);
auto it = icu_object_cache_.find(cache_type);
if (it == icu_object_cache_.end()) {
icu_object_cache_.insert({cache_type, pair});
} else {
it->second = pair;
}
void Isolate::set_icu_object_in_cache(ICUObjectCacheType cache_type,
Handle<Object> locales,
std::shared_ptr<icu::UMemory> obj) {
icu_object_cache_[static_cast<int>(cache_type)] = {
GetStringFromLocales(this, locales), std::move(obj)};
}
void Isolate::clear_cached_icu_object(ICUObjectCacheType cache_type) {
icu_object_cache_.erase(cache_type);
icu_object_cache_[static_cast<int>(cache_type)] = ICUObjectCacheEntry{};
}
void Isolate::ClearCachedIcuObjects() { icu_object_cache_.clear(); }
void Isolate::clear_cached_icu_objects() {
for (int i = 0; i < kICUObjectCacheTypeCount; i++) {
clear_cached_icu_object(static_cast<ICUObjectCacheType>(i));
}
}
#endif // V8_INTL_SUPPORT
......
......@@ -1350,18 +1350,18 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
default_locale_ = locale;
}
// enum to access the icu object cache.
enum class ICUObjectCacheType{
kDefaultCollator, kDefaultNumberFormat, kDefaultSimpleDateFormat,
kDefaultSimpleDateFormatForTime, kDefaultSimpleDateFormatForDate};
static constexpr int kICUObjectCacheTypeCount = 5;
icu::UMemory* get_cached_icu_object(ICUObjectCacheType cache_type,
Handle<Object> locales);
void set_icu_object_in_cache(ICUObjectCacheType cache_type,
Handle<Object> locale,
Handle<Object> locales,
std::shared_ptr<icu::UMemory> obj);
void clear_cached_icu_object(ICUObjectCacheType cache_type);
void ClearCachedIcuObjects();
void clear_cached_icu_objects();
#endif // V8_INTL_SUPPORT
......@@ -2047,14 +2047,18 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
#ifdef V8_INTL_SUPPORT
std::string default_locale_;
struct ICUObjectCacheTypeHash {
std::size_t operator()(ICUObjectCacheType a) const {
return static_cast<std::size_t>(a);
}
// The cache stores the most recently accessed {locales,obj} pair for each
// cache type.
struct ICUObjectCacheEntry {
std::string locales;
std::shared_ptr<icu::UMemory> obj;
ICUObjectCacheEntry() = default;
ICUObjectCacheEntry(std::string locales, std::shared_ptr<icu::UMemory> obj)
: locales(locales), obj(std::move(obj)) {}
};
typedef std::pair<std::string, std::shared_ptr<icu::UMemory>> ICUCachePair;
std::unordered_map<ICUObjectCacheType, ICUCachePair, ICUObjectCacheTypeHash>
icu_object_cache_;
ICUObjectCacheEntry icu_object_cache_[kICUObjectCacheTypeCount];
#endif // V8_INTL_SUPPORT
// true if being profiled. Causes collection of extra compile info.
......
......@@ -999,7 +999,7 @@ MaybeHandle<String> Intl::StringLocaleConvertCase(Isolate* isolate,
}
}
MaybeHandle<Object> Intl::StringLocaleCompare(
base::Optional<int> Intl::StringLocaleCompare(
Isolate* isolate, Handle<String> string1, Handle<String> string2,
Handle<Object> locales, Handle<Object> options, const char* method) {
// We only cache the instance when locales is a string/undefined and
......@@ -1025,9 +1025,9 @@ MaybeHandle<Object> Intl::StringLocaleCompare(
isolate);
Handle<JSCollator> collator;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, collator,
New<JSCollator>(isolate, constructor, locales, options, method), Object);
MaybeHandle<JSCollator> maybe_collator =
New<JSCollator>(isolate, constructor, locales, options, method);
if (!maybe_collator.ToHandle(&collator)) return {};
if (can_cache) {
isolate->set_icu_object_in_cache(
Isolate::ICUObjectCacheType::kDefaultCollator, locales,
......@@ -1038,26 +1038,19 @@ MaybeHandle<Object> Intl::StringLocaleCompare(
}
// ecma402/#sec-collator-comparestrings
Handle<Object> Intl::CompareStrings(Isolate* isolate,
const icu::Collator& icu_collator,
Handle<String> string1,
Handle<String> string2) {
Factory* factory = isolate->factory();
int Intl::CompareStrings(Isolate* isolate, const icu::Collator& icu_collator,
Handle<String> string1, Handle<String> string2) {
// Early return for identical strings.
if (string1.is_identical_to(string2)) {
return factory->NewNumberFromInt(UCollationResult::UCOL_EQUAL);
return UCollationResult::UCOL_EQUAL;
}
// Early return for empty strings.
if (string1->length() == 0) {
return factory->NewNumberFromInt(string2->length() == 0
? UCollationResult::UCOL_EQUAL
: UCollationResult::UCOL_LESS);
}
if (string2->length() == 0) {
return factory->NewNumberFromInt(UCollationResult::UCOL_GREATER);
return string2->length() == 0 ? UCollationResult::UCOL_EQUAL
: UCollationResult::UCOL_LESS;
}
if (string2->length() == 0) return UCollationResult::UCOL_GREATER;
string1 = String::Flatten(isolate, string1);
string2 = String::Flatten(isolate, string2);
......@@ -1070,7 +1063,7 @@ Handle<Object> Intl::CompareStrings(Isolate* isolate,
if (!string_piece2.empty()) {
result = icu_collator.compareUTF8(string_piece1, string_piece2, status);
DCHECK(U_SUCCESS(status));
return factory->NewNumberFromInt(result);
return result;
}
}
......@@ -1078,8 +1071,7 @@ Handle<Object> Intl::CompareStrings(Isolate* isolate,
icu::UnicodeString string_val2 = Intl::ToICUUnicodeString(isolate, string2);
result = icu_collator.compare(string_val1, string_val2, status);
DCHECK(U_SUCCESS(status));
return factory->NewNumberFromInt(result);
return result;
}
// ecma402/#sup-properties-of-the-number-prototype-object
......
......@@ -158,13 +158,14 @@ class Intl {
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ConvertToLower(
Isolate* isolate, Handle<String> s);
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> StringLocaleCompare(
V8_WARN_UNUSED_RESULT static base::Optional<int> StringLocaleCompare(
Isolate* isolate, Handle<String> s1, Handle<String> s2,
Handle<Object> locales, Handle<Object> options, const char* method);
V8_WARN_UNUSED_RESULT static Handle<Object> CompareStrings(
Isolate* isolate, const icu::Collator& collator, Handle<String> s1,
Handle<String> s2);
V8_WARN_UNUSED_RESULT static int CompareStrings(Isolate* isolate,
const icu::Collator& collator,
Handle<String> s1,
Handle<String> s2);
// ecma402/#sup-properties-of-the-number-prototype-object
V8_WARN_UNUSED_RESULT static MaybeHandle<String> NumberToLocaleString(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment