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:
Claes Redestad 2018-05-08 10:49:59 +02:00
parent 035d0190a3
commit b329be2b75

View File

@ -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;