Commit 011739b1 authored by Frank Tang's avatar Frank Tang Committed by Commit Bot

[Intl] Improve Intl constructor performance

Lazy initialize some data once.

$ python -u tools/run_perf.py --binary-override-path   out/x64.release/d8 --filter "JSTests/Intl"   test/js-perf-test/JSTests.json
INFO      >>> Running suite: JSTests/Intl
INFO      >>> Stdout (#1):
NewIntlCollator-Intl(Score): 2047
NewIntlDateTimeFormat-Intl(Score): 26.5
NewIntlNumberFormat-Intl(Score): 449
NewIntlPluralRules-Intl(Score): 670
NewIntlListFormat-Intl(Score): 1762
NewIntlRelativeTimeFormat-Intl(Score): 918


Compare to performance baseline scores in
https://chromium-review.googlesource.com/c/v8/v8/+/1455717

Bug: chromium:928098
Change-Id: I7f213f50eb261474fb38d9592725a101939020d8
Reviewed-on: https://chromium-review.googlesource.com/c/1455727
Commit-Queue: Frank Tang <ftang@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59425}
parent 151a0afb
......@@ -250,6 +250,30 @@ class Intl {
const std::vector<std::string>& requested_locales, MatcherOption options,
const std::set<std::string>& relevant_extension_keys);
// A helper template to implement the GetAvailableLocales
// Usage in src/objects/js-XXX.cc
//
// const std::set<std::string>& JSXxx::GetAvailableLocales() {
// static base::LazyInstance<Intl::AvailableLocales<icu::YYY>>::type
// available_locales = LAZY_INSTANCE_INITIALIZER;
// return available_locales.Pointer()->Get();
// }
template <typename T>
class AvailableLocales {
public:
AvailableLocales() {
int32_t num_locales = 0;
const icu::Locale* icu_available_locales =
T::getAvailableLocales(num_locales);
set = Intl::BuildLocaleSet(icu_available_locales, num_locales);
}
virtual ~AvailableLocales() {}
const std::set<std::string>& Get() const { return set; }
private:
std::set<std::string> set;
};
// Utility function to set text to BreakIterator.
static Managed<icu::UnicodeString> SetTextToBreakIterator(
Isolate* isolate, Handle<String> text,
......
......@@ -186,11 +186,10 @@ String JSV8BreakIterator::BreakType(Isolate* isolate,
return ReadOnlyRoots(isolate).unknown_string();
}
std::set<std::string> JSV8BreakIterator::GetAvailableLocales() {
int32_t num_locales = 0;
const icu::Locale* icu_available_locales =
icu::BreakIterator::getAvailableLocales(num_locales);
return Intl::BuildLocaleSet(icu_available_locales, num_locales);
const std::set<std::string>& JSV8BreakIterator::GetAvailableLocales() {
static base::LazyInstance<Intl::AvailableLocales<icu::BreakIterator>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
} // namespace internal
......
......@@ -35,7 +35,7 @@ class JSV8BreakIterator : public JSObject {
static Handle<JSObject> ResolvedOptions(
Isolate* isolate, Handle<JSV8BreakIterator> break_iterator);
static std::set<std::string> GetAvailableLocales();
static const std::set<std::string>& GetAvailableLocales();
static void AdoptText(Isolate* isolate,
Handle<JSV8BreakIterator> break_iterator,
......
......@@ -484,11 +484,10 @@ MaybeHandle<JSCollator> JSCollator::Initialize(Isolate* isolate,
return collator;
}
std::set<std::string> JSCollator::GetAvailableLocales() {
int32_t num_locales = 0;
const icu::Locale* icu_available_locales =
icu::Collator::getAvailableLocales(num_locales);
return Intl::BuildLocaleSet(icu_available_locales, num_locales);
const std::set<std::string>& JSCollator::GetAvailableLocales() {
static base::LazyInstance<Intl::AvailableLocales<icu::Collator>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
} // namespace internal
......
......@@ -40,7 +40,7 @@ class JSCollator : public JSObject {
static Handle<JSObject> ResolvedOptions(Isolate* isolate,
Handle<JSCollator> collator);
static std::set<std::string> GetAvailableLocales();
static const std::set<std::string>& GetAvailableLocales();
DECL_CAST(JSCollator)
DECL_PRINTER(JSCollator)
......
......@@ -54,7 +54,7 @@ class PatternItem {
std::vector<const char*> allowed_values;
};
const std::vector<PatternItem> GetPatternItems() {
static const std::vector<PatternItem> BuildPatternItems() {
const std::vector<const char*> kLongShort = {"long", "short"};
const std::vector<const char*> kNarrowLongShort = {"narrow", "long", "short"};
const std::vector<const char*> k2DigitNumeric = {"2-digit", "numeric"};
......@@ -107,6 +107,22 @@ const std::vector<PatternItem> GetPatternItems() {
return kPatternItems;
}
class PatternItems {
public:
PatternItems() : data(BuildPatternItems()) {}
virtual ~PatternItems() {}
const std::vector<PatternItem>& Get() const { return data; }
private:
const std::vector<PatternItem> data;
};
static const std::vector<PatternItem>& GetPatternItems() {
static base::LazyInstance<PatternItems>::type items =
LAZY_INSTANCE_INITIALIZER;
return items.Pointer()->Get();
}
class PatternData {
public:
PatternData(const std::string property, std::vector<PatternMap> pairs,
......@@ -154,23 +170,57 @@ const std::vector<PatternData> CreateData(const char* digit2,
// kk 24
// K hour in am/pm (0~11) K 0
// KK 00
const std::vector<PatternData> GetPatternData(Intl::HourCycle hour_cycle) {
const std::vector<PatternData> data = CreateData("jj", "j");
const std::vector<PatternData> data_h11 = CreateData("KK", "K");
const std::vector<PatternData> data_h12 = CreateData("hh", "h");
const std::vector<PatternData> data_h23 = CreateData("HH", "H");
const std::vector<PatternData> data_h24 = CreateData("kk", "k");
class Pattern {
public:
Pattern(const char* d1, const char* d2) : data(CreateData(d1, d2)) {}
virtual ~Pattern() {}
virtual const std::vector<PatternData>& Get() const { return data; }
private:
std::vector<PatternData> data;
};
#define DEFFINE_TRAIT(name, d1, d2) \
struct name { \
static void Construct(void* allocated_ptr) { \
new (allocated_ptr) Pattern(d1, d2); \
} \
};
DEFFINE_TRAIT(H11Trait, "KK", "K")
DEFFINE_TRAIT(H12Trait, "hh", "h")
DEFFINE_TRAIT(H23Trait, "HH", "H")
DEFFINE_TRAIT(H24Trait, "kk", "k")
DEFFINE_TRAIT(HDefaultTrait, "jj", "j")
#undef DEFFINE_TRAIT
const std::vector<PatternData>& GetPatternData(Intl::HourCycle hour_cycle) {
switch (hour_cycle) {
case Intl::HourCycle::kH11:
return data_h11;
case Intl::HourCycle::kH12:
return data_h12;
case Intl::HourCycle::kH23:
return data_h23;
case Intl::HourCycle::kH24:
return data_h24;
case Intl::HourCycle::kUndefined:
return data;
case Intl::HourCycle::kH11: {
static base::LazyInstance<Pattern, H11Trait>::type h11 =
LAZY_INSTANCE_INITIALIZER;
return h11.Pointer()->Get();
}
case Intl::HourCycle::kH12: {
static base::LazyInstance<Pattern, H12Trait>::type h12 =
LAZY_INSTANCE_INITIALIZER;
return h12.Pointer()->Get();
}
case Intl::HourCycle::kH23: {
static base::LazyInstance<Pattern, H23Trait>::type h23 =
LAZY_INSTANCE_INITIALIZER;
return h23.Pointer()->Get();
}
case Intl::HourCycle::kH24: {
static base::LazyInstance<Pattern, H24Trait>::type h24 =
LAZY_INSTANCE_INITIALIZER;
return h24.Pointer()->Get();
}
case Intl::HourCycle::kUndefined: {
static base::LazyInstance<Pattern, HDefaultTrait>::type hDefault =
LAZY_INSTANCE_INITIALIZER;
return hDefault.Pointer()->Get();
}
default:
UNREACHABLE();
}
......@@ -1362,11 +1412,10 @@ MaybeHandle<Object> JSDateTimeFormat::FormatToParts(
return result;
}
std::set<std::string> JSDateTimeFormat::GetAvailableLocales() {
int32_t num_locales = 0;
const icu::Locale* icu_available_locales =
icu::DateFormat::getAvailableLocales(num_locales);
return Intl::BuildLocaleSet(icu_available_locales, num_locales);
const std::set<std::string>& JSDateTimeFormat::GetAvailableLocales() {
static base::LazyInstance<Intl::AvailableLocales<icu::DateFormat>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
Handle<String> JSDateTimeFormat::HourCycleAsString() const {
......
......@@ -71,7 +71,7 @@ class JSDateTimeFormat : public JSObject {
Isolate* isolate, Handle<Object> date, Handle<Object> locales,
Handle<Object> options, RequiredOption required, DefaultsOption defaults);
static std::set<std::string> GetAvailableLocales();
static const std::set<std::string>& GetAvailableLocales();
Handle<String> HourCycleAsString() const;
DECL_CAST(JSDateTimeFormat)
......
......@@ -411,15 +411,14 @@ MaybeHandle<String> JSListFormat::FormatList(Isolate* isolate,
return Intl::ToString(isolate, formatted);
}
std::set<std::string> JSListFormat::GetAvailableLocales() {
int32_t num_locales = 0;
const std::set<std::string>& JSListFormat::GetAvailableLocales() {
// TODO(ftang): for now just use
// icu::Locale::getAvailableLocales(count) until we migrate to
// Intl::GetAvailableLocales().
// ICU FR at https://unicode-org.atlassian.net/browse/ICU-20015
const icu::Locale* icu_available_locales =
icu::Locale::getAvailableLocales(num_locales);
return Intl::BuildLocaleSet(icu_available_locales, num_locales);
static base::LazyInstance<Intl::AvailableLocales<icu::Locale>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
// ecma42 #sec-formatlisttoparts
......
......@@ -49,7 +49,7 @@ class JSListFormat : public JSObject {
Isolate* isolate, Handle<JSListFormat> format_holder,
Handle<JSArray> list);
static std::set<std::string> GetAvailableLocales();
static const std::set<std::string>& GetAvailableLocales();
Handle<String> StyleAsString() const;
Handle<String> TypeAsString() const;
......
......@@ -747,11 +747,10 @@ MaybeHandle<JSArray> JSNumberFormat::FormatToParts(
return result;
}
std::set<std::string> JSNumberFormat::GetAvailableLocales() {
int32_t num_locales = 0;
const icu::Locale* icu_available_locales =
icu::NumberFormat::getAvailableLocales(num_locales);
return Intl::BuildLocaleSet(icu_available_locales, num_locales);
const std::set<std::string>& JSNumberFormat::GetAvailableLocales() {
static base::LazyInstance<Intl::AvailableLocales<icu::NumberFormat>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
} // namespace internal
......
......@@ -64,7 +64,7 @@ class JSNumberFormat : public JSObject {
Isolate* isolate, const icu::NumberFormat& number_format,
Handle<Object> numeric_obj);
static std::set<std::string> GetAvailableLocales();
static const std::set<std::string>& GetAvailableLocales();
Handle<String> StyleAsString() const;
Handle<String> CurrencyDisplayAsString() const;
......
......@@ -314,16 +314,15 @@ Handle<JSObject> JSPluralRules::ResolvedOptions(
return options;
}
std::set<std::string> JSPluralRules::GetAvailableLocales() {
int32_t num_locales = 0;
const std::set<std::string>& JSPluralRules::GetAvailableLocales() {
// TODO(ftang): For PluralRules, filter out locales that
// don't support PluralRules.
// PluralRules is missing an appropriate getAvailableLocales method,
// so we should filter from all locales, but it's not clear how; see
// https://ssl.icu-project.org/trac/ticket/12756
const icu::Locale* icu_available_locales =
icu::Locale::getAvailableLocales(num_locales);
return Intl::BuildLocaleSet(icu_available_locales, num_locales);
static base::LazyInstance<Intl::AvailableLocales<icu::Locale>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
} // namespace internal
......
......@@ -40,7 +40,7 @@ class JSPluralRules : public JSObject {
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ResolvePlural(
Isolate* isolate, Handle<JSPluralRules> plural_rules, double number);
static std::set<std::string> GetAvailableLocales();
static const std::set<std::string>& GetAvailableLocales();
// [[Type]] is one of the values "cardinal" or "ordinal",
// identifying the plural rules used.
......
......@@ -409,11 +409,10 @@ MaybeHandle<Object> JSRelativeTimeFormat::Format(
formatted.length()));
}
std::set<std::string> JSRelativeTimeFormat::GetAvailableLocales() {
int32_t num_locales = 0;
const icu::Locale* icu_available_locales =
icu::DateFormat::getAvailableLocales(num_locales);
return Intl::BuildLocaleSet(icu_available_locales, num_locales);
const std::set<std::string>& JSRelativeTimeFormat::GetAvailableLocales() {
static base::LazyInstance<Intl::AvailableLocales<icu::DateFormat>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
} // namespace internal
......
......@@ -50,7 +50,7 @@ class JSRelativeTimeFormat : public JSObject {
Handle<JSRelativeTimeFormat> format_holder, const char* func_name,
bool to_parts);
static std::set<std::string> GetAvailableLocales();
static const std::set<std::string>& GetAvailableLocales();
DECL_CAST(JSRelativeTimeFormat)
......
......@@ -162,11 +162,10 @@ Handle<String> JSSegmenter::GranularityAsString() const {
}
}
std::set<std::string> JSSegmenter::GetAvailableLocales() {
int32_t num_locales = 0;
const icu::Locale* icu_available_locales =
icu::BreakIterator::getAvailableLocales(num_locales);
return Intl::BuildLocaleSet(icu_available_locales, num_locales);
const std::set<std::string>& JSSegmenter::GetAvailableLocales() {
static base::LazyInstance<Intl::AvailableLocales<icu::BreakIterator>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
} // namespace internal
......
......@@ -39,7 +39,7 @@ class JSSegmenter : public JSObject {
V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions(
Isolate* isolate, Handle<JSSegmenter> segmenter_holder);
static std::set<std::string> GetAvailableLocales();
static const std::set<std::string>& GetAvailableLocales();
Handle<String> GranularityAsString() const;
......
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