8186517: sun.nio.cs.StandardCharsets$Aliases and Classes can be lazily loaded
Reviewed-by: sherman, martin, plevart
--- a/jdk/make/src/classes/build/tools/charsetmapping/DBCS.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/make/src/classes/build/tools/charsetmapping/SBCS.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/make/src/classes/build/tools/charsetmapping/SPI.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/make/src/classes/build/tools/charsetmapping/SRC.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/java/lang/StringCoding.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/java/nio/charset/Charset.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/java/nio/charset/StandardCharsets.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/CESU_8.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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;
- // Maps canonical names to cached instances
- private final Map<String,Charset> cache;
+ private @Stable Map<String,String> aliasMap;
- private static final String packagePrefix = "sun.nio.cs";
-
- public static final String US_ASCII = "US-ASCII";
+ // Maps canonical names to cached instances
+ private @Stable Map<String,Charset> cache;
- 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/jdk/src/java.base/share/classes/sun/nio/cs/US_ASCII.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_16.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_16BE.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_16LE.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_16LE_BOM.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_32.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_32BE.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_32BE_BOM.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_32LE.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_32LE_BOM.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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/jdk/src/java.base/share/classes/sun/nio/cs/UTF_8.java Wed Aug 30 10:09:13 2017 -0700
+++ b/jdk/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());