# HG changeset patch # User redestad # Date 1554289038 -7200 # Wed Apr 03 12:57:18 2019 +0200 # Node ID 67429e96871c9cfd9c83542b22f736370ef6bd34 # Parent 40a7e2fc9bebd804819e2e6e4c8b41b1499b416f 8221701: Archive constant BaseLocales Reviewed-by: naoto 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,111 @@ */ 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 { + ENGLISH = createConstant(BaseLocale.ENGLISH); + FRENCH = createConstant(BaseLocale.FRENCH); + GERMAN = createConstant(BaseLocale.GERMAN); + ITALIAN = createConstant(BaseLocale.ITALIAN); + JAPANESE = createConstant(BaseLocale.JAPANESE); + KOREAN = createConstant(BaseLocale.KOREAN); + CHINESE = createConstant(BaseLocale.CHINESE); + SIMPLIFIED_CHINESE = createConstant(BaseLocale.SIMPLIFIED_CHINESE); + TRADITIONAL_CHINESE = createConstant(BaseLocale.TRADITIONAL_CHINESE); + FRANCE = createConstant(BaseLocale.FRANCE); + GERMANY = createConstant(BaseLocale.GERMANY); + ITALY = createConstant(BaseLocale.ITALY); + JAPAN = createConstant(BaseLocale.JAPAN); + KOREA = createConstant(BaseLocale.KOREA); + UK = createConstant(BaseLocale.UK); + US = createConstant(BaseLocale.US); + CANADA = createConstant(BaseLocale.CANADA); + CANADA_FRENCH = createConstant(BaseLocale.CANADA_FRENCH); + ROOT = createConstant(BaseLocale.ROOT); + } /** Useful constant for country. */ @@ -554,31 +602,16 @@ */ 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 createConstant(byte baseType) { + BaseLocale base = BaseLocale.constantBaseLocales[baseType]; + Locale locale = new Locale(base, null); + CONSTANT_LOCALES.put(base, locale); + return locale; + } /** * The key for the private use extension ('x'). @@ -709,7 +742,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 +800,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 @@ -803,20 +827,27 @@ extensions = getCompatibilityExtensions(language, script, country, variant); } - BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant); + BaseLocale baseloc = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); return getInstance(baseloc, extensions); } 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 +1008,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 +2342,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,65 @@ package sun.util.locale; +import jdk.internal.misc.VM; +import jdk.internal.vm.annotation.Stable; + import java.lang.ref.SoftReference; import java.util.StringJoiner; public final class BaseLocale { + public static @Stable BaseLocale[] constantBaseLocales; + public static final byte ENGLISH = 0, + FRENCH = 1, + GERMAN = 2, + ITALIAN = 3, + JAPANESE = 4, + KOREAN = 5, + CHINESE = 6, + SIMPLIFIED_CHINESE = 7, + TRADITIONAL_CHINESE = 8, + FRANCE = 9, + GERMANY = 10, + ITALY = 11, + JAPAN = 12, + KOREA = 13, + UK = 14, + US = 15, + CANADA = 16, + CANADA_FRENCH = 17, + ROOT = 18, + NUM_CONSTANTS = 19; + static { + VM.initializeFromArchive(BaseLocale.class); + BaseLocale[] baseLocales = constantBaseLocales; + if (baseLocales == null) { + baseLocales = new BaseLocale[NUM_CONSTANTS]; + baseLocales[ENGLISH] = createInstance("en", ""); + baseLocales[FRENCH] = createInstance("fr", ""); + baseLocales[GERMAN] = createInstance("de", ""); + baseLocales[ITALIAN] = createInstance("it", ""); + baseLocales[JAPANESE] = createInstance("ja", ""); + baseLocales[KOREAN] = createInstance("ko", ""); + baseLocales[CHINESE] = createInstance("zh", ""); + baseLocales[SIMPLIFIED_CHINESE] = createInstance("zh", "CN"); + baseLocales[TRADITIONAL_CHINESE] = createInstance("zh", "TW"); + baseLocales[FRANCE] = createInstance("fr", "FR"); + baseLocales[GERMANY] = createInstance("de", "DE"); + baseLocales[ITALY] = createInstance("it", "IT"); + baseLocales[JAPAN] = createInstance("ja", "JP"); + baseLocales[KOREA] = createInstance("ko", "KR"); + baseLocales[UK] = createInstance("en", "GB"); + baseLocales[US] = createInstance("en", "US"); + baseLocales[CANADA] = createInstance("en", "CA"); + baseLocales[CANADA_FRENCH] = createInstance("fr", "CA"); + baseLocales[ROOT] = createInstance("", ""); + constantBaseLocales = baseLocales; + } + } + public static final String SEP = "_"; - private static final Cache CACHE = new Cache(); - private final String language; private final String script; private final String region; @@ -67,28 +117,53 @@ // Called for creating the Locale.* constants. No argument // validation is performed. - public static BaseLocale createInstance(String language, String region) { - BaseLocale base = new BaseLocale(language, "", region, "", false); - CACHE.put(new Key(base), base); - return base; + private static BaseLocale createInstance(String language, String region) { + return new BaseLocale(language, "", region, "", false); } public static BaseLocale getInstance(String language, String script, String region, String variant) { + + if (script == null) { + script = ""; + } + if (region == null) { + region = ""; + } + if (language == null) { + language = null; + } + if (variant == null) { + variant = ""; + } + + // Non-allocating for most uses + language = LocaleUtils.toLowerString(language); + region = LocaleUtils.toUpperString(region); + + // Check for constant base locales first + if (script.isEmpty() && variant.isEmpty()) { + for (BaseLocale baseLocale : constantBaseLocales) { + if (baseLocale.getLanguage().equals(language) + && baseLocale.getRegion().equals(region)) { + return baseLocale; + } + } + } + // JDK uses deprecated ISO639.1 language codes for he, yi and id - if (language != null) { - if (LocaleUtils.caseIgnoreMatch(language, "he")) { + if (!language.isEmpty()) { + if (language.equals("he")) { language = "iw"; - } else if (LocaleUtils.caseIgnoreMatch(language, "yi")) { + } else if (language.equals("yi")) { language = "ji"; - } else if (LocaleUtils.caseIgnoreMatch(language, "id")) { + } else if (language.equals("id")) { language = "in"; } } 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 +246,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 +328,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));