< prev index next >
src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java
Print this page
*** 36,47 ****
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.ConcurrentMap;
- import java.util.function.Function;
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_getStatic;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_putStatic;
import static java.lang.invoke.MethodHandleStatics.*;
--- 36,45 ----
*** 62,72 ****
private final MemberName sdAccessor;
private final String sdFieldName;
private final List<MemberName> transformMethods;
private final MethodType baseConstructorType;
private final S topSpecies;
! private final ConcurrentMap<K, S> cache = new ConcurrentHashMap<>();
private final Factory factory;
private @Stable boolean topClassIsSuper;
/** Return the top type mirror, for type {@code T} */
public final Class<T> topClass() { return topClass; }
--- 60,70 ----
private final MemberName sdAccessor;
private final String sdFieldName;
private final List<MemberName> transformMethods;
private final MethodType baseConstructorType;
private final S topSpecies;
! private final ConcurrentHashMap<K, Object> cache = new ConcurrentHashMap<>();
private final Factory factory;
private @Stable boolean topClassIsSuper;
/** Return the top type mirror, for type {@code T} */
public final Class<T> topClass() { return topClass; }
*** 111,122 ****
List<MemberName> transformMethods) {
this.topClass = topClass;
this.keyType = keyType;
this.metaType = metaType;
this.sdAccessor = sdAccessor;
! // FIXME: use List.copyOf once 8177290 is in
! this.transformMethods = List.of(transformMethods.toArray(new MemberName[transformMethods.size()]));
this.sdFieldName = sdFieldName;
this.baseConstructorType = baseConstructorType.changeReturnType(void.class);
this.factory = makeFactory();
K tsk = topSpeciesKey();
S topSpecies = null;
--- 109,119 ----
List<MemberName> transformMethods) {
this.topClass = topClass;
this.keyType = keyType;
this.metaType = metaType;
this.sdAccessor = sdAccessor;
! this.transformMethods = List.copyOf(transformMethods);
this.sdFieldName = sdFieldName;
this.baseConstructorType = baseConstructorType.changeReturnType(void.class);
this.factory = makeFactory();
K tsk = topSpeciesKey();
S topSpecies = null;
*** 146,167 ****
private static RuntimeException newIAE(String message, Throwable cause) {
return new IllegalArgumentException(message, cause);
}
public final S findSpecies(K key) {
- S speciesData = cache.computeIfAbsent(key, new Function<>() {
- @Override
- public S apply(K key1) {
- return factory.loadSpecies(newSpeciesData(key1));
- }
- });
// Note: Species instantiation may throw VirtualMachineError because of
// code cache overflow. If this happens the species bytecode may be
// loaded but not linked to its species metadata (with MH's etc).
! // That will cause a throw out of CHM.computeIfAbsent,
! // which will shut down the caller thread.
//
// In a latter attempt to get the same species, the already-loaded
// class will be present in the system dictionary, causing an
// error when the species generator tries to reload it.
// We try to detect this case and link the pre-existing code.
--- 143,159 ----
private static RuntimeException newIAE(String message, Throwable cause) {
return new IllegalArgumentException(message, cause);
}
+ @SuppressWarnings("unchecked")
public final S findSpecies(K key) {
// Note: Species instantiation may throw VirtualMachineError because of
// code cache overflow. If this happens the species bytecode may be
// loaded but not linked to its species metadata (with MH's etc).
! // That will cause a throw out of this method with a reservation object
! // installed in the cache.
//
// In a latter attempt to get the same species, the already-loaded
// class will be present in the system dictionary, causing an
// error when the species generator tries to reload it.
// We try to detect this case and link the pre-existing code.
*** 169,184 ****
// Although it would be better to start fresh by loading a new
// copy, we have to salvage the previously loaded but broken code.
// (As an alternative, we might spin a new class with a new name,
// or use the anonymous class mechanism.)
//
! // In the end, as long as everybody goes through the same CHM,
! // CHM.computeIfAbsent will ensure only one SpeciesData will be set
// successfully on a concrete class if ever.
// The concrete class is published via SpeciesData instance
// returned here only after the class and species data are linked together.
! assert(speciesData != null);
return speciesData;
}
/**
* Meta-data wrapper for concrete subtypes of the top class.
--- 161,208 ----
// Although it would be better to start fresh by loading a new
// copy, we have to salvage the previously loaded but broken code.
// (As an alternative, we might spin a new class with a new name,
// or use the anonymous class mechanism.)
//
! // In the end, as long as everybody goes through this method,
! // its initialization logic will ensure only one SpeciesData will be set
// successfully on a concrete class if ever.
// The concrete class is published via SpeciesData instance
// returned here only after the class and species data are linked together.
! Object reservation = new Object();
! S speciesData;
! Object speciesDataOrReservation = cache.putIfAbsent(key, reservation);
! if (speciesDataOrReservation instanceof ClassSpecializer<?, ?, ?>.SpeciesData) {
! // already cached
! speciesData = (S) speciesDataOrReservation;
! } else {
! // resolve the race for reservation
! if (speciesDataOrReservation != null) {
! reservation = speciesDataOrReservation;
! }
! synchronized (reservation) {
! // re-check under lock
! speciesDataOrReservation = cache.get(key);
! if (speciesDataOrReservation == reservation) {
! // the thread that enters synchronized (reservation) and finds
! // reservation still in cache, tries to (re)initialize species data.
! // if the initialization fails, the reservation object is left in CHM
! // for next thread to pick it up and retry...
! speciesData = factory.loadSpecies(newSpeciesData(key));
! if (!cache.replace(key, reservation, speciesData)) {
! throw new AssertionError("Thought this was unreachable");
! }
! } else {
! // the thread that enters synchronized (reservation) and finds
! // a reference that is not a reservation, has found the initialized
! // species data...
! assert speciesDataOrReservation instanceof ClassSpecializer<?, ?, ?>.SpeciesData;
! speciesData = (S) speciesDataOrReservation;
! }
! }
! }
! assert(speciesData != null && speciesData.isResolved());
return speciesData;
}
/**
* Meta-data wrapper for concrete subtypes of the top class.
*** 206,218 ****
@Stable private final MethodHandle[] transformHelpers = new MethodHandle[transformMethods.size()];
protected SpeciesData(K key) {
this.key = keyType.cast(Objects.requireNonNull(key));
List<Class<?>> types = deriveFieldTypes(key);
! // TODO: List.copyOf
! int arity = types.size();
! this.fieldTypes = List.of(types.toArray(new Class<?>[arity]));
}
public final K key() {
return key;
}
--- 230,240 ----
@Stable private final MethodHandle[] transformHelpers = new MethodHandle[transformMethods.size()];
protected SpeciesData(K key) {
this.key = keyType.cast(Objects.requireNonNull(key));
List<Class<?>> types = deriveFieldTypes(key);
! this.fieldTypes = List.copyOf(types);
}
public final K key() {
return key;
}
*** 456,467 ****
}
}
final Class<? extends T> speciesCode;
if (salvage != null) {
speciesCode = salvage.asSubclass(topClass());
! factory.linkSpeciesDataToCode(speciesData, speciesCode);
! factory.linkCodeToSpeciesData(speciesCode, speciesData, true);
} else {
// Not pregenerated, generate the class
try {
speciesCode = generateConcreteSpeciesCode(className, speciesData);
if (TRACE_RESOLVE) {
--- 478,489 ----
}
}
final Class<? extends T> speciesCode;
if (salvage != null) {
speciesCode = salvage.asSubclass(topClass());
! linkSpeciesDataToCode(speciesData, speciesCode);
! linkCodeToSpeciesData(speciesCode, speciesData, true);
} else {
// Not pregenerated, generate the class
try {
speciesCode = generateConcreteSpeciesCode(className, speciesData);
if (TRACE_RESOLVE) {
*** 484,494 ****
}
if (!speciesData.isResolved()) {
throw newInternalError("bad species class linkage for " + className + ": " + speciesData);
}
! assert(speciesData == factory.loadSpeciesDataFromCode(speciesCode));
return speciesData;
}
/**
* Generate a concrete subclass of the top class for a given combination of bound types.
--- 506,516 ----
}
if (!speciesData.isResolved()) {
throw newInternalError("bad species class linkage for " + className + ": " + speciesData);
}
! assert(speciesData == loadSpeciesDataFromCode(speciesCode));
return speciesData;
}
/**
* Generate a concrete subclass of the top class for a given combination of bound types.
< prev index next >