[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: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/main@{#76746}
This commit is contained in:
parent
0d42c9d0b1
commit
cd79e83f42
@ -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 "";
|
||||
namespace {
|
||||
|
||||
std::string GetStringFromLocales(Isolate* isolate, Handle<Object> locales) {
|
||||
if (locales->IsUndefined(isolate)) return "";
|
||||
return std::string(String::cast(*locales).ToCString().get());
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
} // 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;
|
||||
|
||||
ICUCachePair pair = value->second;
|
||||
if (pair.first != locale) return nullptr;
|
||||
|
||||
return pair.second.get();
|
||||
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(
|
||||
|
Loading…
Reference in New Issue
Block a user