changeset 17733:06168eefa456

8186517: sun.nio.cs.StandardCharsets$Aliases and Classes can be lazily loaded Reviewed-by: sherman, martin, plevart
author redestad
date Wed, 30 Aug 2017 20:12:53 +0200
parents 787703ab9a62
children 4ab6d768430f
files make/src/classes/build/tools/charsetmapping/DBCS.java make/src/classes/build/tools/charsetmapping/SBCS.java make/src/classes/build/tools/charsetmapping/SPI.java make/src/classes/build/tools/charsetmapping/SRC.java src/java.base/share/classes/java/lang/StringCoding.java src/java.base/share/classes/java/nio/charset/Charset.java src/java.base/share/classes/java/nio/charset/StandardCharsets.java src/java.base/share/classes/sun/nio/cs/CESU_8.java src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template src/java.base/share/classes/sun/nio/cs/US_ASCII.java src/java.base/share/classes/sun/nio/cs/UTF_16.java src/java.base/share/classes/sun/nio/cs/UTF_16BE.java src/java.base/share/classes/sun/nio/cs/UTF_16LE.java src/java.base/share/classes/sun/nio/cs/UTF_16LE_BOM.java src/java.base/share/classes/sun/nio/cs/UTF_32.java src/java.base/share/classes/sun/nio/cs/UTF_32BE.java src/java.base/share/classes/sun/nio/cs/UTF_32BE_BOM.java src/java.base/share/classes/sun/nio/cs/UTF_32LE.java src/java.base/share/classes/sun/nio/cs/UTF_32LE_BOM.java src/java.base/share/classes/sun/nio/cs/UTF_8.java
diffstat 21 files changed, 116 insertions(+), 75 deletions(-) [+]
line wrap: on
line diff
--- a/make/src/classes/build/tools/charsetmapping/DBCS.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/make/src/classes/build/tools/charsetmapping/DBCS.java	Wed Aug 30 20:12:53 2017 +0200
@@ -179,7 +179,7 @@
                        .replace("$NAME_CLZ$", clzName)
                        .replace("$NAME_ALIASES$",
                                 "sun.nio.cs".equals(pkgName) ?
-                                "StandardCharsets.aliases_" + clzName :
+                                "StandardCharsets.aliases_" + clzName + "()" :
                                 "ExtendedCharsets.aliasesFor(\"" + csName + "\")")
                        .replace("$NAME_CS$" , csName)
                        .replace("$CONTAINS$",
--- a/make/src/classes/build/tools/charsetmapping/SBCS.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/make/src/classes/build/tools/charsetmapping/SBCS.java	Wed Aug 30 20:12:53 2017 +0200
@@ -161,7 +161,7 @@
             if (line.indexOf("$NAME_ALIASES$", i) != -1) {
                 if ("sun.nio.cs".equals(pkgName))
                     line = line.replace("$NAME_ALIASES$",
-                                        "StandardCharsets.aliases_" + clzName);
+                                        "StandardCharsets.aliases_" + clzName + "()");
                 else
                     line = line.replace("$NAME_ALIASES$",
                                         "ExtendedCharsets.aliasesFor(\"" + csName + "\")");
--- a/make/src/classes/build/tools/charsetmapping/SPI.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/make/src/classes/build/tools/charsetmapping/SPI.java	Wed Aug 30 20:12:53 2017 +0200
@@ -93,21 +93,28 @@
                                  .filter(cs -> cs.pkgName.equals("sun.nio.cs"))
                                  .forEach( cs -> {
                              if (cs.aliases == null || cs.aliases.length == 0) {
-                                 out.printf("    static final String[] aliases_%s = null;%n%n",
+                                 out.printf("    static String[] aliases_%s() { return null; }%n%n",
                                             cs.clzName);
                              } else {
+                                 boolean methodEnd = true;
                                  // non-final for SJIS and MS932 to support sun.nio.cs.map
                                  if (cs.clzName.equals("SJIS") || cs.clzName.equals("MS932")) {
+                                     out.printf("    static String[] aliases_%s() { return aliases_%s; }%n%n",
+                                                cs.clzName, cs.clzName);
                                      out.printf("    static String[] aliases_%s = new String[] {%n",
                                                 cs.clzName);
+                                     methodEnd = false;
                                  } else {
-                                     out.printf("    static final String[] aliases_%s = new String[] {%n",
+                                     out.printf("    static String[] aliases_%s() { return new String[] {%n",
                                                 cs.clzName);
                                  }
                                  for (String alias : cs.aliases) {
-                                     out.printf("        \"%s\",%n", alias);
+                                     out.printf("            \"%s\",%n", alias);
                                  }
-                                 out.printf("    };%n%n");
+                                 out.printf("        };%n%n");
+                                 if (methodEnd) {
+                                     out.printf("    }%n%n");
+                                 }
                              }
                          });
                          Charset cs = charsets.get("SJIS");
--- a/make/src/classes/build/tools/charsetmapping/SRC.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/make/src/classes/build/tools/charsetmapping/SRC.java	Wed Aug 30 20:12:53 2017 +0200
@@ -51,7 +51,7 @@
                 } else if (line.indexOf("$ALIASES$") != -1) {
                     if ("sun.nio.cs".equals(pkgName))
                         out.println(line.replace("$ALIASES$",
-                                                 "StandardCharsets.aliases_" + clzName));
+                                                 "StandardCharsets.aliases_" + clzName + "()"));
                     else
                         out.println(line.replace("$ALIASES$",
                                                  "ExtendedCharsets.aliasesFor(\"" + csName + "\")"));
--- a/src/java.base/share/classes/java/lang/StringCoding.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/java/lang/StringCoding.java	Wed Aug 30 20:12:53 2017 +0200
@@ -42,6 +42,7 @@
 import sun.nio.cs.HistoricallyNamedCharset;
 import sun.nio.cs.ArrayDecoder;
 import sun.nio.cs.ArrayEncoder;
+import sun.nio.cs.StandardCharsets;
 
 import static java.lang.String.LATIN1;
 import static java.lang.String.UTF16;
@@ -61,9 +62,9 @@
     private static final ThreadLocal<SoftReference<StringEncoder>> encoder =
         new ThreadLocal<>();
 
-    private static final Charset ISO_8859_1 = Charset.forName("iso-8859-1");
-    private static final Charset US_ASCII = Charset.forName("us-ascii");
-    private static final Charset UTF_8 = Charset.forName("utf-8");
+    private static final Charset ISO_8859_1 = sun.nio.cs.ISO_8859_1.INSTANCE;
+    private static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE;
+    private static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE;
 
     private static boolean warnUnsupportedCharset = true;
 
--- a/src/java.base/share/classes/java/nio/charset/Charset.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/java/nio/charset/Charset.java	Wed Aug 30 20:12:53 2017 +0200
@@ -609,7 +609,7 @@
                 if (cs != null)
                     defaultCharset = cs;
                 else
-                    defaultCharset = forName("UTF-8");
+                    defaultCharset = sun.nio.cs.UTF_8.INSTANCE;
             }
         }
         return defaultCharset;
@@ -639,11 +639,10 @@
         String[] as = Objects.requireNonNullElse(aliases, zeroAliases);
 
         // Skip checks for the standard, built-in Charsets we always load
-        // during initialization.  Use of identity is intentional to be
-        // consistent with sun.nio.cs.StandardCharsets
-        if (canonicalName != StandardCharsets.ISO_8859_1
-                && canonicalName != StandardCharsets.US_ASCII
-                && canonicalName != StandardCharsets.UTF_8) {
+        // during initialization.
+        if (canonicalName != "ISO-8859-1"
+                && canonicalName != "US-ASCII"
+                && canonicalName != "UTF-8") {
             checkName(canonicalName);
             for (int i = 0; i < as.length; i++) {
                 checkName(as[i]);
--- a/src/java.base/share/classes/java/nio/charset/StandardCharsets.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/java/nio/charset/StandardCharsets.java	Wed Aug 30 20:12:53 2017 +0200
@@ -41,15 +41,15 @@
      * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
      * Unicode character set
      */
-    public static final Charset US_ASCII = Charset.forName("US-ASCII");
+    public static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE;
     /**
      * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
      */
-    public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+    public static final Charset ISO_8859_1 = sun.nio.cs.ISO_8859_1.INSTANCE;
     /**
      * Eight-bit UCS Transformation Format
      */
-    public static final Charset UTF_8 = Charset.forName("UTF-8");
+    public static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE;
     /**
      * Sixteen-bit UCS Transformation Format, big-endian byte order
      */
--- a/src/java.base/share/classes/sun/nio/cs/CESU_8.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/CESU_8.java	Wed Aug 30 20:12:53 2017 +0200
@@ -52,7 +52,7 @@
 class CESU_8 extends Unicode
 {
     public CESU_8() {
-        super("CESU-8", StandardCharsets.aliases_CESU_8);
+        super("CESU-8", StandardCharsets.aliases_CESU_8());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java	Wed Aug 30 20:12:53 2017 +0200
@@ -31,18 +31,19 @@
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
-import java.util.Arrays;
 import java.util.Objects;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
 
-class ISO_8859_1
+public class ISO_8859_1
     extends Charset
     implements HistoricallyNamedCharset
 {
 
+    public static final ISO_8859_1 INSTANCE = new ISO_8859_1();
+
     public ISO_8859_1() {
-        super(StandardCharsets.ISO_8859_1, StandardCharsets.aliases_ISO_8859_1);
+        super("ISO-8859-1", StandardCharsets.aliases_ISO_8859_1());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template	Wed Aug 30 20:12:53 2017 +0200
@@ -33,6 +33,8 @@
 import java.nio.charset.spi.CharsetProvider;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
+import jdk.internal.vm.annotation.Stable;
 import sun.security.action.GetPropertyAction;
 
 public class StandardCharsets extends CharsetProvider {
@@ -43,31 +45,52 @@
     _INCLUDE_CACHE_MAP_
 
     // Maps canonical names to class names
-    private final Map<String,String> classMap;
+    private @Stable Map<String,String> classMap;
+
     // Maps alias names to canonical names
-    private final Map<String,String> aliasMap;
+    private @Stable Map<String,String> aliasMap;
+
     // Maps canonical names to cached instances
-    private final Map<String,Charset> cache;
+    private @Stable Map<String,Charset> cache;
 
-    private static final String packagePrefix = "sun.nio.cs";
-
-    public static final String US_ASCII = "US-ASCII";
-
-    public static final String ISO_8859_1 = "ISO-8859-1";
-
-    public static final String UTF_8 = "UTF-8";
+    private static final String packagePrefix = "sun.nio.cs.";
 
     public StandardCharsets() {
-        this.aliasMap = new Aliases();
-        this.classMap = new Classes();
-        this.cache = new Cache();
     }
 
     private String canonicalize(String csn) {
-        String acn = aliasMap.get(csn);
+        String acn = aliasMap().get(csn);
         return (acn != null) ? acn : csn;
     }
 
+    private Map<String,String> aliasMap() {
+        Map<String,String> map = aliasMap;
+        if (map == null) {
+            aliasMap = map = new Aliases();
+        }
+        return map;
+    }
+
+    private Map<String,String> classMap() {
+        Map<String,String> map = classMap;
+        if (map == null) {
+            classMap = map = new Classes();
+        }
+        return map;
+    }
+
+    private Map<String,Charset> cache() {
+        Map<String,Charset> map = cache;
+        if (map == null) {
+            map = new Cache();
+            map.put("utf-8", UTF_8.INSTANCE);
+            map.put("iso-8859-1", ISO_8859_1.INSTANCE);
+            map.put("us-ascii", US_ASCII.INSTANCE);
+            cache = map;
+        }
+        return map;
+    }
+
     // Private ASCII-only version, optimized for interpretation during startup
     //
     private static String toLower(String s) {
@@ -82,47 +105,47 @@
         }
         if (allLower)
             return s;
-        char[] ca = new char[n];
+        StringBuilder sb = new StringBuilder(n);
         for (int i = 0; i < n; i++) {
             int c = s.charAt(i);
             if (((c - 'A') | ('Z' - c)) >= 0)
-                ca[i] = (char)(c + 0x20);
+                sb.append((char)(c + 0x20));
             else
-                ca[i] = (char)c;
+                sb.append((char)c);
         }
-        return new String(ca);
+        return sb.toString();
     }
 
     private Charset lookup(String charsetName) {
         init();
-        String csn = canonicalize(toLower(charsetName));
+
+        // By checking these built-ins we can avoid initializing Aliases and
+        // Classes eagerly during bootstrap
+        String csn;
+        if (charsetName.equals("UTF-8")) {
+            return UTF_8.INSTANCE;
+        } else if (charsetName.equals("US-ASCII")) {
+            return US_ASCII.INSTANCE;
+        } else if (charsetName.equals("ISO-8859-1")) {
+            return ISO_8859_1.INSTANCE;
+        } else {
+            csn = canonicalize(toLower(charsetName));
+        }
 
         // Check cache first
-        Charset cs = cache.get(csn);
+        Charset cs = cache().get(csn);
         if (cs != null)
             return cs;
 
         // Do we even support this charset?
-        String cln = classMap.get(csn);
+        String cln = classMap().get(csn);
         if (cln == null)
             return null;
 
-        // As all charset class names added to classMap are string literals we
-        // can check identity here as an optimization
-        if (cln == US_ASCII) {
-            return cache(csn, new US_ASCII());
-        }
-        if (cln == ISO_8859_1) {
-            return cache(csn, new ISO_8859_1());
-        }
-        if (cln == UTF_8) {
-            return cache(csn, new UTF_8());
-        }
-
         // Instantiate the charset and cache it
         try {
             @SuppressWarnings("deprecation")
-            Object o = Class.forName(packagePrefix + "." + cln,
+            Object o = Class.forName(packagePrefix + cln,
                                      true,
                                      this.getClass().getClassLoader()).newInstance();
             return cache(csn, (Charset)o);
@@ -134,23 +157,28 @@
     }
 
     private Charset cache(String csn, Charset cs) {
-        cache.put(csn, cs);
+        cache().put(csn, cs);
         return cs;
     }
 
     public final Charset charsetForName(String charsetName) {
         synchronized (this) {
-            return lookup(canonicalize(charsetName));
+            return lookup(charsetName);
         }
     }
 
     public final Iterator<Charset> charsets() {
+        Set<String> charsetNames;
         synchronized (this) {
             init();
+            // Ensure initialized in synchronized block
+            charsetNames = classMap().keySet();
+            aliasMap();
+            cache();
         }
         return new Iterator<Charset>() {
 
-                Iterator<String> i = classMap.keySet().iterator();
+                Iterator<String> i = charsetNames.iterator();
 
                 public boolean hasNext() {
                     return i.hasNext();
@@ -181,6 +209,8 @@
 
         String map = GetPropertyAction.privilegedGetProperty("sun.nio.cs.map");
         if (map != null) {
+            Map<String,String> aliasMap = aliasMap();
+            Map<String,String> classMap = classMap();
             String[] maps = map.split(",");
             for (int i = 0; i < maps.length; i++) {
                 if (maps[i].equalsIgnoreCase("Windows-31J/Shift_JIS")) {
@@ -207,7 +237,7 @@
                     for (String alias : aliases_MS932) {
                         aliasMap.put(toLower(alias), "windows-31j");
                     }
-                    cache.put("shift_jis", null);
+                    cache().put("shift_jis", null);
                     break;
                 }
             }
--- a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java	Wed Aug 30 20:12:53 2017 +0200
@@ -36,9 +36,10 @@
     extends Charset
     implements HistoricallyNamedCharset
 {
+    public static final US_ASCII INSTANCE = new US_ASCII();
 
     public US_ASCII() {
-        super(StandardCharsets.US_ASCII, StandardCharsets.aliases_US_ASCII);
+        super("US-ASCII", StandardCharsets.aliases_US_ASCII());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_16.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_16.java	Wed Aug 30 20:12:53 2017 +0200
@@ -33,7 +33,7 @@
 {
 
     public UTF_16() {
-        super("UTF-16", StandardCharsets.aliases_UTF_16);
+        super("UTF-16", StandardCharsets.aliases_UTF_16());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_16BE.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_16BE.java	Wed Aug 30 20:12:53 2017 +0200
@@ -33,7 +33,7 @@
 {
 
     public UTF_16BE() {
-        super("UTF-16BE", StandardCharsets.aliases_UTF_16BE);
+        super("UTF-16BE", StandardCharsets.aliases_UTF_16BE());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_16LE.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_16LE.java	Wed Aug 30 20:12:53 2017 +0200
@@ -33,7 +33,7 @@
 {
 
     public UTF_16LE() {
-        super("UTF-16LE", StandardCharsets.aliases_UTF_16LE);
+        super("UTF-16LE", StandardCharsets.aliases_UTF_16LE());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_16LE_BOM.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_16LE_BOM.java	Wed Aug 30 20:12:53 2017 +0200
@@ -33,7 +33,7 @@
 {
 
     public UTF_16LE_BOM() {
-        super("x-UTF-16LE-BOM", StandardCharsets.aliases_UTF_16LE_BOM);
+        super("x-UTF-16LE-BOM", StandardCharsets.aliases_UTF_16LE_BOM());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_32.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_32.java	Wed Aug 30 20:12:53 2017 +0200
@@ -31,7 +31,7 @@
 public class UTF_32 extends Unicode
 {
     public UTF_32() {
-        super("UTF-32", StandardCharsets.aliases_UTF_32);
+        super("UTF-32", StandardCharsets.aliases_UTF_32());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_32BE.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_32BE.java	Wed Aug 30 20:12:53 2017 +0200
@@ -31,7 +31,7 @@
 public class UTF_32BE extends Unicode
 {
     public UTF_32BE() {
-        super("UTF-32BE", StandardCharsets.aliases_UTF_32BE);
+        super("UTF-32BE", StandardCharsets.aliases_UTF_32BE());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_32BE_BOM.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_32BE_BOM.java	Wed Aug 30 20:12:53 2017 +0200
@@ -31,7 +31,7 @@
 public class UTF_32BE_BOM extends Unicode
 {
     public UTF_32BE_BOM() {
-        super("X-UTF-32BE-BOM", StandardCharsets.aliases_UTF_32BE_BOM);
+        super("X-UTF-32BE-BOM", StandardCharsets.aliases_UTF_32BE_BOM());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_32LE.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_32LE.java	Wed Aug 30 20:12:53 2017 +0200
@@ -32,7 +32,7 @@
 public class UTF_32LE extends Unicode
 {
     public UTF_32LE() {
-        super("UTF-32LE", StandardCharsets.aliases_UTF_32LE);
+        super("UTF-32LE", StandardCharsets.aliases_UTF_32LE());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_32LE_BOM.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_32LE_BOM.java	Wed Aug 30 20:12:53 2017 +0200
@@ -31,7 +31,7 @@
 public class UTF_32LE_BOM extends Unicode
 {
     public UTF_32LE_BOM() {
-        super("X-UTF-32LE-BOM", StandardCharsets.aliases_UTF_32LE_BOM);
+        super("X-UTF-32LE-BOM", StandardCharsets.aliases_UTF_32LE_BOM());
     }
 
     public String historicalName() {
--- a/src/java.base/share/classes/sun/nio/cs/UTF_8.java	Wed Aug 30 10:09:13 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_8.java	Wed Aug 30 20:12:53 2017 +0200
@@ -54,10 +54,12 @@
  *
  */
 
-class UTF_8 extends Unicode
-{
+public final class UTF_8 extends Unicode {
+
+    public static final UTF_8 INSTANCE = new UTF_8();
+
     public UTF_8() {
-        super(StandardCharsets.UTF_8, StandardCharsets.aliases_UTF_8);
+        super("UTF-8", StandardCharsets.aliases_UTF_8());
     }
 
     public String historicalName() {
@@ -72,7 +74,7 @@
         return new Encoder(this);
     }
 
-    private static final void updatePositions(Buffer src, int sp,
+    static final void updatePositions(Buffer src, int sp,
                                               Buffer dst, int dp) {
         src.position(sp - src.arrayOffset());
         dst.position(dp - dst.arrayOffset());