8202548: Use reservation Object when creating SpeciesData
Co-authored-by: Peter Levart <peter.levart@gmail.com> Reviewed-by: psandoz, plevart
This commit is contained in:
parent
035d0190a3
commit
b329be2b75
@ -68,7 +68,7 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
|
|||||||
private final List<MemberName> transformMethods;
|
private final List<MemberName> transformMethods;
|
||||||
private final MethodType baseConstructorType;
|
private final MethodType baseConstructorType;
|
||||||
private final S topSpecies;
|
private final S topSpecies;
|
||||||
private final ConcurrentHashMap<K, S> cache = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<K, Object> cache = new ConcurrentHashMap<>();
|
||||||
private final Factory factory;
|
private final Factory factory;
|
||||||
private @Stable boolean topClassIsSuper;
|
private @Stable boolean topClassIsSuper;
|
||||||
|
|
||||||
@ -151,14 +151,20 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
|
|||||||
return new IllegalArgumentException(message, cause);
|
return new IllegalArgumentException(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Function<Object, Object> CREATE_RESERVATION = new Function<>() {
|
||||||
|
@Override
|
||||||
|
public Object apply(Object key) {
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public final S findSpecies(K key) {
|
public final S findSpecies(K key) {
|
||||||
// Note: Species instantiation may throw VirtualMachineError because of
|
// Note: Species instantiation may throw VirtualMachineError because of
|
||||||
// code cache overflow. If this happens the species bytecode may be
|
// code cache overflow. If this happens the species bytecode may be
|
||||||
// loaded but not linked to its species metadata (with MH's etc).
|
// loaded but not linked to its species metadata (with MH's etc).
|
||||||
// That will cause a throw out of CHM.computeIfAbsent,
|
// That will cause a throw out of Factory.loadSpecies.
|
||||||
// which will shut down the caller thread.
|
|
||||||
//
|
//
|
||||||
// In a latter attempt to get the same species, the already-loaded
|
// In a later attempt to get the same species, the already-loaded
|
||||||
// class will be present in the system dictionary, causing an
|
// class will be present in the system dictionary, causing an
|
||||||
// error when the species generator tries to reload it.
|
// error when the species generator tries to reload it.
|
||||||
// We try to detect this case and link the pre-existing code.
|
// We try to detect this case and link the pre-existing code.
|
||||||
@ -168,25 +174,20 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
|
|||||||
// (As an alternative, we might spin a new class with a new name,
|
// (As an alternative, we might spin a new class with a new name,
|
||||||
// or use the anonymous class mechanism.)
|
// or use the anonymous class mechanism.)
|
||||||
//
|
//
|
||||||
// In the end, as long as everybody goes through the same CHM,
|
// In the end, as long as everybody goes through this findSpecies method,
|
||||||
// CHM.computeIfAbsent will ensure only one SpeciesData will be set
|
// it will ensure only one SpeciesData will be set successfully on a
|
||||||
// successfully on a concrete class if ever.
|
// concrete class if ever.
|
||||||
// The concrete class is published via SpeciesData instance
|
// The concrete class is published via SpeciesData instance
|
||||||
// returned here only after the class and species data are linked together.
|
// returned here only after the class and species data are linked together.
|
||||||
S speciesData = cache.computeIfAbsent(key, new Function<>() {
|
Object speciesDataOrReservation = cache.computeIfAbsent(key, CREATE_RESERVATION);
|
||||||
@Override
|
|
||||||
public S apply(K key1) {
|
|
||||||
return newSpeciesData(key1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Separating the creation of a placeholder SpeciesData instance above
|
// Separating the creation of a placeholder SpeciesData instance above
|
||||||
// from the loading and linking a real one below ensures we can never
|
// from the loading and linking a real one below ensures we can never
|
||||||
// accidentally call computeIfAbsent recursively. Replacing rather than
|
// accidentally call computeIfAbsent recursively.
|
||||||
// updating the placeholder is done to ensure safe publication.
|
S speciesData;
|
||||||
if (!speciesData.isResolved()) {
|
if (speciesDataOrReservation.getClass() == Object.class) {
|
||||||
synchronized (speciesData) {
|
synchronized (speciesDataOrReservation) {
|
||||||
S existingSpeciesData = cache.get(key);
|
Object existingSpeciesData = cache.get(key);
|
||||||
if (existingSpeciesData == speciesData) { // won the race
|
if (existingSpeciesData == speciesDataOrReservation) { // won the race
|
||||||
// create a new SpeciesData...
|
// create a new SpeciesData...
|
||||||
speciesData = newSpeciesData(key);
|
speciesData = newSpeciesData(key);
|
||||||
// load and link it...
|
// load and link it...
|
||||||
@ -195,9 +196,11 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
|
|||||||
throw newInternalError("Concurrent loadSpecies");
|
throw newInternalError("Concurrent loadSpecies");
|
||||||
}
|
}
|
||||||
} else { // lost the race; the retrieved existingSpeciesData is the final
|
} else { // lost the race; the retrieved existingSpeciesData is the final
|
||||||
speciesData = existingSpeciesData;
|
speciesData = metaType.cast(existingSpeciesData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
speciesData = metaType.cast(speciesDataOrReservation);
|
||||||
}
|
}
|
||||||
assert(speciesData != null && speciesData.isResolved());
|
assert(speciesData != null && speciesData.isResolved());
|
||||||
return speciesData;
|
return speciesData;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user