8186517: sun.nio.cs.StandardCharsets$Aliases and Classes can be lazily loaded

Reviewed-by: sherman, martin, plevart
This commit is contained in:
Claes Redestad 2017-08-30 20:12:53 +02:00
parent cfe34ed89c
commit a0564d954d
21 changed files with 116 additions and 75 deletions

View file

@ -179,7 +179,7 @@ public class DBCS {
.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$",

View file

@ -161,7 +161,7 @@ public class SBCS {
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 + "\")");

View file

@ -93,21 +93,28 @@ public class SPI {
.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");
if (methodEnd) {
out.printf(" }%n%n");
}
out.printf(" };%n%n");
}
});
Charset cs = charsets.get("SJIS");

View file

@ -51,7 +51,7 @@ public class SRC {
} 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 + "\")"));

View file

@ -42,6 +42,7 @@ import jdk.internal.HotSpotIntrinsicCandidate;
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 @@ class StringCoding {
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;

View file

@ -609,7 +609,7 @@ public abstract class Charset
if (cs != null)
defaultCharset = cs;
else
defaultCharset = forName("UTF-8");
defaultCharset = sun.nio.cs.UTF_8.INSTANCE;
}
}
return defaultCharset;
@ -639,11 +639,10 @@ public abstract class Charset
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]);

View file

@ -41,15 +41,15 @@ public final class StandardCharsets {
* 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
*/

View file

@ -52,7 +52,7 @@ import java.nio.charset.CodingErrorAction;
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() {

View file

@ -31,18 +31,19 @@ import java.nio.charset.Charset;
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() {

View file

@ -33,6 +33,8 @@ import java.nio.charset.Charset;
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 @@ public class StandardCharsets extends CharsetProvider {
_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 @@ public class StandardCharsets extends CharsetProvider {
}
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 @@ public class StandardCharsets extends CharsetProvider {
}
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 @@ public class StandardCharsets extends CharsetProvider {
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 @@ public class StandardCharsets extends CharsetProvider {
for (String alias : aliases_MS932) {
aliasMap.put(toLower(alias), "windows-31j");
}
cache.put("shift_jis", null);
cache().put("shift_jis", null);
break;
}
}

View file

@ -36,9 +36,10 @@ public class US_ASCII
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() {

View file

@ -33,7 +33,7 @@ class UTF_16 extends Unicode
{
public UTF_16() {
super("UTF-16", StandardCharsets.aliases_UTF_16);
super("UTF-16", StandardCharsets.aliases_UTF_16());
}
public String historicalName() {

View file

@ -33,7 +33,7 @@ class UTF_16BE extends Unicode
{
public UTF_16BE() {
super("UTF-16BE", StandardCharsets.aliases_UTF_16BE);
super("UTF-16BE", StandardCharsets.aliases_UTF_16BE());
}
public String historicalName() {

View file

@ -33,7 +33,7 @@ class UTF_16LE extends Unicode
{
public UTF_16LE() {
super("UTF-16LE", StandardCharsets.aliases_UTF_16LE);
super("UTF-16LE", StandardCharsets.aliases_UTF_16LE());
}
public String historicalName() {

View file

@ -33,7 +33,7 @@ class UTF_16LE_BOM extends Unicode
{
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() {

View file

@ -31,7 +31,7 @@ import java.nio.charset.CharsetEncoder;
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() {

View file

@ -31,7 +31,7 @@ import java.nio.charset.CharsetEncoder;
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() {

View file

@ -31,7 +31,7 @@ import java.nio.charset.CharsetEncoder;
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() {

View file

@ -32,7 +32,7 @@ import java.nio.charset.CharsetEncoder;
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() {

View file

@ -31,7 +31,7 @@ import java.nio.charset.CharsetEncoder;
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() {

View file

@ -54,10 +54,12 @@ import java.nio.charset.CodingErrorAction;
*
*/
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 @@ class UTF_8 extends Unicode
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());