8221701: Archive constant BaseLocales
authorredestad
Wed, 03 Apr 2019 17:06:35 +0200
changeset 54412 41356f083e93
parent 54411 1ad7f5bcc670
child 54413 30067047ed88
8221701: Archive constant BaseLocales Reviewed-by: naoto
src/hotspot/share/memory/heapShared.cpp
src/java.base/share/classes/java/util/Locale.java
src/java.base/share/classes/sun/util/locale/BaseLocale.java
src/java.base/share/classes/sun/util/locale/LocaleUtils.java
src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java
src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java
--- a/src/hotspot/share/memory/heapShared.cpp	Wed Apr 03 16:55:41 2019 +0200
+++ b/src/hotspot/share/memory/heapShared.cpp	Wed Apr 03 17:06:35 2019 +0200
@@ -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[] = {
--- a/src/java.base/share/classes/java/util/Locale.java	Wed Apr 03 16:55:41 2019 +0200
+++ b/src/java.base/share/classes/java/util/Locale.java	Wed Apr 03 17:06:35 2019 +0200
@@ -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 JAPANESE;
 
     /** Useful constant for language.
      */
-    public static final Locale ITALIAN = createConstant("it", "");
+    public static final Locale KOREAN;
 
     /** Useful constant for language.
      */
-    public static final Locale JAPANESE = createConstant("ja", "");
+    public static final Locale CHINESE;
 
     /** Useful constant for language.
      */
-    public static final Locale KOREAN = createConstant("ko", "");
+    public static final Locale SIMPLIFIED_CHINESE;
 
     /** Useful constant for language.
      */
-    public static final Locale CHINESE = createConstant("zh", "");
+    public static final Locale TRADITIONAL_CHINESE;
+
+    /** Useful constant for country.
+     */
+    public static final Locale FRANCE;
 
-    /** Useful constant for language.
+    /** Useful constant for country.
+     */
+    public static final Locale GERMANY;
+
+    /** Useful constant for country.
+     */
+    public static final Locale ITALY;
+
+    /** Useful constant for country.
      */
-    public static final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
+    public static final Locale JAPAN;
+
+    /** Useful constant for country.
+     */
+    public static final Locale KOREA;
 
-    /** Useful constant for language.
+    /** Useful constant for country.
+     */
+    public static final Locale UK;
+
+    /** Useful constant for country.
      */
-    public static final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
+    public static final Locale US;
+
+    /** Useful constant for country.
+     */
+    public static final Locale CANADA;
 
     /** Useful constant for country.
      */
-    public static final Locale FRANCE = createConstant("fr", "FR");
+    public static final Locale CANADA_FRENCH;
 
-    /** Useful constant for country.
-     */
-    public static final Locale GERMANY = createConstant("de", "DE");
-
-    /** Useful constant for country.
+    /**
+     * 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 ITALY = createConstant("it", "IT");
+    public static final Locale ROOT;
+
+    private static final Map<BaseLocale, Locale> CONSTANT_LOCALES = new HashMap<>();
 
-    /** Useful constant for country.
-     */
-    public static final Locale JAPAN = createConstant("ja", "JP");
-
-    /** Useful constant for country.
-     */
-    public static final Locale KOREA = createConstant("ko", "KR");
+    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.
-     */
-    public static final Locale UK = createConstant("en", "GB");
-
-    /** Useful constant for country.
-     */
-    public static final Locale US = createConstant("en", "US");
-
-    /** Useful constant for country.
+    /**
+     * This method must be called only for creating the Locale.*
+     * constants due to making shortcuts.
      */
-    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 <code>Locale</code> constructed from the given
      * <code>language</code>, <code>country</code> and
      * <code>variant</code>. If the same <code>Locale</code> 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<Object, Locale> {
+
+        private static final Cache LOCALECACHE = new Cache();
+
         private Cache() {
         }
 
@@ -977,8 +1008,11 @@
     }
 
     private static Optional<LocaleExtensions> 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 {
--- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java	Wed Apr 03 16:55:41 2019 +0200
+++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java	Wed Apr 03 17:06:35 2019 +0200
@@ -32,14 +32,64 @@
 
 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 final String SEP = "_";
+    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;
+        }
+    }
 
-    private static final Cache CACHE = new Cache();
+    public static final String SEP = "_";
 
     private final String language;
     private final String script;
@@ -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<Key, BaseLocale> {
 
+        private static final Cache CACHE = new Cache();
+
         public Cache() {
         }
 
--- a/src/java.base/share/classes/sun/util/locale/LocaleUtils.java	Wed Apr 03 16:55:41 2019 +0200
+++ b/src/java.base/share/classes/sun/util/locale/LocaleUtils.java	Wed Apr 03 17:06:35 2019 +0200
@@ -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();
     }
 }
--- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Wed Apr 03 16:55:41 2019 +0200
+++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Wed Apr 03 17:06:35 2019 +0200
@@ -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<String> langtags) {
         if (Locale.ROOT.equals(locale)) {
             return true;
-}
+        }
 
         locale = locale.stripExtensions();
         if (langtags.contains(locale.toLanguageTag())) {
--- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java	Wed Apr 03 16:55:41 2019 +0200
+++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java	Wed Apr 03 17:06:35 2019 +0200
@@ -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<String> keyset = getZoneIDs();
         // Use a LinkedHashSet to preseve the order
         Set<String[]> value = new LinkedHashSet<>();
-        Set<String> tzIds = new HashSet<>(Set.of(TimeZone.getAvailableIDs()));
+        Set<String> tzIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs()));
         for (String key : keyset) {
             if (!key.startsWith(TZNB_EXCITY_PREFIX)) {
                 value.add(rb.getStringArray(key));