# HG changeset patch # User redestad # Date 1554133855 -7200 # Mon Apr 01 17:50:55 2019 +0200 # Node ID 36abef35ceadb4fa0ef270b035ddc9e1d992967b # Parent f062188117adc692641c0c6932bbf770c5cc2bd9 8221701: Archive constant BaseLocales Reviewed-by: TBD diff --git a/src/hotspot/share/memory/heapShared.cpp b/src/hotspot/share/memory/heapShared.cpp --- a/src/hotspot/share/memory/heapShared.cpp +++ b/src/hotspot/share/memory/heapShared.cpp @@ -69,6 +69,7 @@ {"java/lang/Short$ShortCache", "archivedCache"}, {"java/lang/Character$CharacterCache", "archivedCache"}, {"java/util/jar/Attributes$Name", "KNOWN_NAMES"}, + {"sun/util/locale/BaseLocale", "constantBaseLocales"}, }; // Entry fields for subgraphs archived in the open archive heap region. static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = { diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -484,63 +484,119 @@ */ public final class Locale implements Cloneable, Serializable { - private static final Cache LOCALECACHE = new Cache(); + /** Useful constant for language. + */ + public static final Locale ENGLISH; /** Useful constant for language. */ - public static final Locale ENGLISH = createConstant("en", ""); + public static final Locale FRENCH; /** Useful constant for language. */ - public static final Locale FRENCH = createConstant("fr", ""); + public static final Locale GERMAN; /** Useful constant for language. */ - public static final Locale GERMAN = createConstant("de", ""); + public static final Locale ITALIAN; /** Useful constant for language. */ - public static final Locale ITALIAN = createConstant("it", ""); + public static final Locale JAPANESE; /** Useful constant for language. */ - public static final Locale JAPANESE = createConstant("ja", ""); + public static final Locale KOREAN; /** Useful constant for language. */ - public static final Locale KOREAN = createConstant("ko", ""); + public static final Locale CHINESE; /** Useful constant for language. */ - public static final Locale CHINESE = createConstant("zh", ""); + public static final Locale SIMPLIFIED_CHINESE; /** Useful constant for language. */ - public static final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN"); - - /** Useful constant for language. - */ - public static final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW"); + public static final Locale TRADITIONAL_CHINESE; /** Useful constant for country. */ - public static final Locale FRANCE = createConstant("fr", "FR"); + public static final Locale FRANCE; /** Useful constant for country. */ - public static final Locale GERMANY = createConstant("de", "DE"); + public static final Locale GERMANY; /** Useful constant for country. */ - public static final Locale ITALY = createConstant("it", "IT"); + public static final Locale ITALY; /** Useful constant for country. */ - public static final Locale JAPAN = createConstant("ja", "JP"); + public static final Locale JAPAN; /** Useful constant for country. */ - public static final Locale KOREA = createConstant("ko", "KR"); + public static final Locale KOREA; + + /** Useful constant for country. + */ + public static final Locale UK; + + /** Useful constant for country. + */ + public static final Locale US; + + /** Useful constant for country. + */ + public static final Locale CANADA; + + /** Useful constant for country. + */ + public static final Locale CANADA_FRENCH; + + /** + * Useful constant for the root locale. The root locale is the locale whose + * language, country, and variant are empty ("") strings. This is regarded + * as the base locale of all locales, and is used as the language/country + * neutral locale for the locale sensitive operations. + * + * @since 1.6 + */ + public static final Locale ROOT; + + private static final Map CONSTANT_LOCALES = new HashMap<>(); + + static { + var baseLocales = BaseLocale.constantBaseLocales; + boolean fromArchive = baseLocales != null; + if (!fromArchive) { + baseLocales = new HashMap<>(); + } + ENGLISH = constant("en", "", baseLocales, fromArchive); + FRENCH = constant("fr", "", baseLocales, fromArchive); + GERMAN = constant("de", "", baseLocales, fromArchive); + ITALIAN = constant("it", "", baseLocales, fromArchive); + JAPANESE = constant("ja", "", baseLocales, fromArchive); + KOREAN = constant("ko", "", baseLocales, fromArchive); + CHINESE = constant("zh", "", baseLocales, fromArchive); + SIMPLIFIED_CHINESE = constant("zh", "CN", baseLocales, fromArchive); + TRADITIONAL_CHINESE = constant("zh", "TW", baseLocales, fromArchive); + FRANCE = constant("fr", "FR", baseLocales, fromArchive); + GERMANY = constant("de", "DE", baseLocales, fromArchive); + ITALY = constant("it", "IT", baseLocales, fromArchive); + JAPAN = constant("ja", "JP", baseLocales, fromArchive); + KOREA = constant("ko", "KR", baseLocales, fromArchive); + UK = constant("en", "GB", baseLocales, fromArchive); + US = constant("en", "US", baseLocales, fromArchive); + CANADA = constant("en", "CA", baseLocales, fromArchive); + CANADA_FRENCH = constant("fr", "CA", baseLocales, fromArchive); + ROOT = constant("", "", baseLocales, fromArchive); + if (!fromArchive) { + BaseLocale.constantBaseLocales = Map.copyOf(baseLocales); + } + } /** Useful constant for country. */ @@ -554,31 +610,31 @@ */ public static final Locale TAIWAN = TRADITIONAL_CHINESE; - /** Useful constant for country. + /** + * This method must be called only for creating the Locale.* + * constants due to making shortcuts. */ - public static final Locale UK = createConstant("en", "GB"); - - /** Useful constant for country. - */ - public static final Locale US = createConstant("en", "US"); - - /** Useful constant for country. - */ - public static final Locale CANADA = createConstant("en", "CA"); - - /** Useful constant for country. - */ - public static final Locale CANADA_FRENCH = createConstant("fr", "CA"); - - /** - * Useful constant for the root locale. The root locale is the locale whose - * language, country, and variant are empty ("") strings. This is regarded - * as the base locale of all locales, and is used as the language/country - * neutral locale for the locale sensitive operations. - * - * @since 1.6 - */ - public static final Locale ROOT = createConstant("", ""); + private static Locale constant(String lang, + String country, + Map> baseLocaleMap, + boolean fromArchive) { + BaseLocale base; + if (fromArchive) { + var countryMap = baseLocaleMap.get(lang); + base = countryMap.get(country); + } else { + base = BaseLocale.createInstance(lang, country); + var countryMap = baseLocaleMap.get(lang); + if (countryMap == null) { + countryMap = new HashMap<>(); + baseLocaleMap.put(lang, countryMap); + } + countryMap.put(country, base); + } + Locale locale = new Locale(base, null); + CONSTANT_LOCALES.put(base, locale); + return locale; + } /** * The key for the private use extension ('x'). @@ -709,7 +765,7 @@ * @exception NullPointerException thrown if any argument is null. */ public Locale(String language, String country, String variant) { - if (language== null || country == null || variant == null) { + if (language == null || country == null || variant == null) { throw new NullPointerException(); } baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant); @@ -767,15 +823,6 @@ } /** - * This method must be called only for creating the Locale.* - * constants due to making shortcuts. - */ - private static Locale createConstant(String lang, String country) { - BaseLocale base = BaseLocale.createInstance(lang, country); - return getInstance(base, null); - } - - /** * Returns a Locale constructed from the given * language, country and * variant. If the same Locale instance @@ -809,14 +856,21 @@ static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) { if (extensions == null) { - return LOCALECACHE.get(baseloc); + Locale locale = CONSTANT_LOCALES.get(baseloc); + if (locale != null) { + return locale; + } + return Cache.LOCALECACHE.get(baseloc); } else { LocaleKey key = new LocaleKey(baseloc, extensions); - return LOCALECACHE.get(key); + return Cache.LOCALECACHE.get(key); } } private static class Cache extends LocaleObjectCache { + + private static final Cache LOCALECACHE = new Cache(); + private Cache() { } @@ -977,8 +1031,11 @@ } private static Optional getDefaultExtensions(String extensionsProp) { + if (LocaleUtils.isEmpty(extensionsProp)) { + return Optional.empty(); + } + LocaleExtensions exts = null; - try { exts = new InternalLocaleBuilder() .setExtensions(extensionsProp) @@ -2308,6 +2365,7 @@ String country = (String)fields.get("country", ""); String variant = (String)fields.get("variant", ""); String extStr = (String)fields.get("extensions", ""); + baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); if (!extStr.isEmpty()) { try { diff --git a/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/src/java.base/share/classes/sun/util/locale/BaseLocale.java --- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java +++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java @@ -32,15 +32,23 @@ package sun.util.locale; +import jdk.internal.misc.VM; +import jdk.internal.vm.annotation.Stable; + import java.lang.ref.SoftReference; +import java.util.Map; import java.util.StringJoiner; public final class BaseLocale { + // Initialized by java.util.Locale + public static @Stable Map> constantBaseLocales; + static { + VM.initializeFromArchive(BaseLocale.class); + } + public static final String SEP = "_"; - private static final Cache CACHE = new Cache(); - private final String language; private final String script; private final String region; @@ -68,15 +76,17 @@ // Called for creating the Locale.* constants. No argument // validation is performed. public static BaseLocale createInstance(String language, String region) { + assert LocaleUtils.toLowerString(language).intern() == language + && LocaleUtils.toUpperString(region).intern() == region; BaseLocale base = new BaseLocale(language, "", region, "", false); - CACHE.put(new Key(base), base); return base; } public static BaseLocale getInstance(String language, String script, String region, String variant) { - // JDK uses deprecated ISO639.1 language codes for he, yi and id + if (language != null) { + // JDK uses deprecated ISO639.1 language codes for he, yi and id if (LocaleUtils.caseIgnoreMatch(language, "he")) { language = "iw"; } else if (LocaleUtils.caseIgnoreMatch(language, "yi")) { @@ -84,11 +94,31 @@ } else if (LocaleUtils.caseIgnoreMatch(language, "id")) { language = "in"; } + } else { + language = ""; + } + if (script == null) { + script = ""; + } + if (region == null) { + region = ""; + } + if (variant == null) { + variant = ""; + } + + // Check for constant base locales first + if (script.isEmpty() && variant.isEmpty()) { + BaseLocale baseLocale = constantBaseLocales + .getOrDefault(LocaleUtils.toLowerString(language), Map.of()) + .get(LocaleUtils.toUpperString(region)); + if (baseLocale != null) { + return baseLocale; + } } Key key = new Key(language, script, region, variant, false); - BaseLocale baseLocale = CACHE.get(key); - return baseLocale; + return Cache.CACHE.get(key); } public String getLanguage() { @@ -171,46 +201,8 @@ private final boolean normalized; private final int hash; - /** - * Creates a Key. language and region must be normalized - * (intern'ed in the proper case). - */ - private Key(BaseLocale locale) { - this.holder = locale; - this.holderRef = null; - this.normalized = true; - String language = locale.getLanguage(); - String region = locale.getRegion(); - assert LocaleUtils.toLowerString(language).intern() == language - && LocaleUtils.toUpperString(region).intern() == region - && locale.getVariant() == "" - && locale.getScript() == ""; - - int h = language.hashCode(); - if (region != "") { - int len = region.length(); - for (int i = 0; i < len; i++) { - h = 31 * h + LocaleUtils.toLower(region.charAt(i)); - } - } - hash = h; - } - private Key(String language, String script, String region, String variant, boolean normalize) { - if (language == null) { - language = ""; - } - if (script == null) { - script = ""; - } - if (region == null) { - region = ""; - } - if (variant == null) { - variant = ""; - } - BaseLocale locale = new BaseLocale(language, script, region, variant, normalize); this.normalized = normalize; if (normalized) { @@ -291,6 +283,8 @@ private static class Cache extends LocaleObjectCache { + private static final Cache CACHE = new Cache(); + public Cache() { } diff --git a/src/java.base/share/classes/sun/util/locale/LocaleUtils.java b/src/java.base/share/classes/sun/util/locale/LocaleUtils.java --- a/src/java.base/share/classes/sun/util/locale/LocaleUtils.java +++ b/src/java.base/share/classes/sun/util/locale/LocaleUtils.java @@ -206,19 +206,19 @@ return true; } - static boolean isEmpty(String str) { + public static boolean isEmpty(String str) { return str == null || str.isEmpty(); } - static boolean isEmpty(Set set) { + public static boolean isEmpty(Set set) { return set == null || set.isEmpty(); } - static boolean isEmpty(Map map) { + public static boolean isEmpty(Map map) { return map == null || map.isEmpty(); } - static boolean isEmpty(List list) { + public static boolean isEmpty(List list) { return list == null || list.isEmpty(); } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -491,8 +491,7 @@ */ private static class AvailableJRELocales { private static final Locale[] localeList = createAvailableLocales(); - private AvailableJRELocales() { - } + private AvailableJRELocales() {} } private static Locale[] createAvailableLocales() { @@ -535,7 +534,7 @@ public boolean isSupportedProviderLocale(Locale locale, Set langtags) { if (Locale.ROOT.equals(locale)) { return true; -} + } locale = locale.stripExtensions(); if (langtags.contains(locale.toLanguageTag())) { diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -44,6 +44,7 @@ import java.lang.ref.SoftReference; import java.text.MessageFormat; import java.text.NumberFormat; +import java.util.Arrays; import java.util.Calendar; import java.util.HashSet; import java.util.LinkedHashSet; @@ -325,7 +326,7 @@ Set keyset = getZoneIDs(); // Use a LinkedHashSet to preseve the order Set value = new LinkedHashSet<>(); - Set tzIds = new HashSet<>(Set.of(TimeZone.getAvailableIDs())); + Set tzIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs())); for (String key : keyset) { if (!key.startsWith(TZNB_EXCITY_PREFIX)) { value.add(rb.getStringArray(key));