8359119: Change Charset to use StableValue

Reviewed-by: alanb, rriggs
This commit is contained in:
Per Minborg 2025-08-18 05:32:03 +00:00
parent bd65d483df
commit f364fcab79

View File

@ -37,13 +37,16 @@ import java.nio.charset.spi.CharsetProvider;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.function.Supplier;
/**
@ -381,17 +384,7 @@ public abstract class Charset
};
}
private static class ThreadTrackHolder {
static final ThreadTracker TRACKER = new ThreadTracker();
}
private static Object tryBeginLookup() {
return ThreadTrackHolder.TRACKER.tryBegin();
}
private static void endLookup(Object key) {
ThreadTrackHolder.TRACKER.end(key);
}
private static final ScopedValue<Boolean> IN_LOOKUP = ScopedValue.newInstance();
private static Charset lookupViaProviders(final String charsetName) {
@ -406,48 +399,54 @@ public abstract class Charset
if (!VM.isBooted())
return null;
Object key = tryBeginLookup();
if (key == null) {
if (IN_LOOKUP.isBound()) {
// Avoid recursive provider lookups
return null;
}
try {
for (Iterator<CharsetProvider> i = providers(); i.hasNext();) {
CharsetProvider cp = i.next();
Charset cs = cp.charsetForName(charsetName);
if (cs != null)
return cs;
}
return null;
} finally {
endLookup(key);
return ScopedValue.where(IN_LOOKUP, true).call(
new ScopedValue.CallableOp<Charset, Exception>() {
@Override
public Charset call() {
for (Iterator<CharsetProvider> i = providers(); i.hasNext(); ) {
CharsetProvider cp = i.next();
Charset cs = cp.charsetForName(charsetName);
if (cs != null)
return cs;
}
return null;
}
}
);
} catch (Exception t) {
// Should not happen
throw new RuntimeException(t);
}
}
/* The extended set of charsets */
private static class ExtendedProviderHolder {
static final CharsetProvider[] extendedProviders = extendedProviders();
// returns ExtendedProvider, if installed
private static CharsetProvider[] extendedProviders() {
CharsetProvider[] cps = new CharsetProvider[1];
int n = 0;
ServiceLoader<CharsetProvider> sl =
private static final Supplier<List<CharsetProvider>> EXTENDED_PROVIDERS = StableValue.supplier(
new Supplier<>() { public List<CharsetProvider> get() { return extendedProviders0(); }});
private static List<CharsetProvider> extendedProviders0() {
CharsetProvider[] cps = new CharsetProvider[1];
int n = 0;
final ServiceLoader<CharsetProvider> sl =
ServiceLoader.loadInstalled(CharsetProvider.class);
for (CharsetProvider cp : sl) {
if (n + 1 > cps.length) {
cps = Arrays.copyOf(cps, cps.length << 1);
}
cps[n++] = cp;
for (CharsetProvider cp : sl) {
if (n + 1 > cps.length) {
cps = Arrays.copyOf(cps, cps.length << 1);
}
return n == cps.length ? cps : Arrays.copyOf(cps, n);
cps[n++] = cp;
}
return List.of(n == cps.length ? cps : Arrays.copyOf(cps, n));
}
private static Charset lookupExtendedCharset(String charsetName) {
if (!VM.isBooted()) // see lookupViaProviders()
return null;
CharsetProvider[] ecps = ExtendedProviderHolder.extendedProviders;
for (CharsetProvider cp : ecps) {
for (CharsetProvider cp : EXTENDED_PROVIDERS.get()) {
Charset cs = cp.charsetForName(charsetName);
if (cs != null)
return cs;
@ -608,8 +607,7 @@ public abstract class Charset
new TreeMap<>(
String.CASE_INSENSITIVE_ORDER);
put(standardProvider.charsets(), m);
CharsetProvider[] ecps = ExtendedProviderHolder.extendedProviders;
for (CharsetProvider ecp :ecps) {
for (CharsetProvider ecp : EXTENDED_PROVIDERS.get()) {
put(ecp.charsets(), m);
}
for (Iterator<CharsetProvider> i = providers(); i.hasNext();) {
@ -619,7 +617,16 @@ public abstract class Charset
return Collections.unmodifiableSortedMap(m);
}
private @Stable static Charset defaultCharset;
private static final Supplier<Charset> defaultCharset = StableValue.supplier(
new Supplier<>() { public Charset get() { return defaultCharset0(); }});
private static Charset defaultCharset0() {
// do not look for providers other than the standard one
final Charset cs = standardProvider.charsetForName(StaticProperty.fileEncoding());
return (cs == null)
? sun.nio.cs.UTF_8.INSTANCE
: cs;
}
/**
* Returns the default charset of this Java virtual machine.
@ -640,25 +647,19 @@ public abstract class Charset
* @since 1.5
*/
public static Charset defaultCharset() {
if (defaultCharset == null) {
synchronized (Charset.class) {
// do not look for providers other than the standard one
Charset cs = standardProvider.charsetForName(StaticProperty.fileEncoding());
if (cs != null)
defaultCharset = cs;
else
defaultCharset = sun.nio.cs.UTF_8.INSTANCE;
}
}
return defaultCharset;
return defaultCharset.get();
}
/* -- Instance fields and methods -- */
private final String name; // tickles a bug in oldjavac
private final String[] aliases; // tickles a bug in oldjavac
private Set<String> aliasSet;
@Stable
private final String name;
@Stable
private final String[] aliases;
@Stable
private final Supplier<Set<String>> aliasSet = StableValue.supplier(
new Supplier<>() { public Set<String> get() { return Set.of(aliases); }});
/**
* Initializes a new charset with the given canonical name and alias
@ -710,12 +711,7 @@ public abstract class Charset
* @return An immutable set of this charset's aliases
*/
public final Set<String> aliases() {
Set<String> set = this.aliasSet;
if (set == null) {
set = Set.of(aliases);
this.aliasSet = set;
}
return set;
return aliasSet.get();
}
/**