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