< prev index next >

src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java

Print this page
rev 49851 : 8202184: Reduce time blocking the ClassSpecializer cache creating SpeciesData
Reviewed-by: jrose, psandoz

*** 30,46 **** import jdk.internal.org.objectweb.asm.FieldVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.vm.annotation.Stable; import sun.invoke.util.BytecodeName; ! import java.lang.reflect.*; 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; --- 30,50 ---- import jdk.internal.org.objectweb.asm.FieldVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.vm.annotation.Stable; import sun.invoke.util.BytecodeName; ! import java.lang.reflect.Constructor; ! import java.lang.reflect.Field; ! import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.ProtectionDomain; ! import java.util.ArrayList; ! import java.util.Collections; ! import java.util.List; ! import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; 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;
*** 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; } --- 66,76 ---- 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, 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; }
*** 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; --- 115,125 ---- 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;
*** 147,162 **** 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. --- 150,159 ----
*** 174,184 **** // 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. --- 171,207 ---- // 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. ! S speciesData = cache.computeIfAbsent(key, new Function<>() { ! @Override ! public S apply(K key1) { ! return newSpeciesData(key1); ! } ! }); ! // Separating the creation of a placeholder SpeciesData instance above ! // from the loading and linking a real one below ensures we can never ! // accidentally call computeIfAbsent recursively. Replacing rather than ! // updating the placeholder is done to ensure safe publication. ! if (!speciesData.isResolved()) { ! synchronized (speciesData) { ! S existingSpeciesData = cache.get(key); ! if (existingSpeciesData == speciesData) { // won the race ! // create a new SpeciesData... ! speciesData = newSpeciesData(key); ! // load and link it... ! speciesData = factory.loadSpecies(speciesData); ! if (!cache.replace(key, existingSpeciesData, speciesData)) { ! throw newInternalError("Concurrent loadSpecies"); ! } ! } else { // lost the race; the retrieved existingSpeciesData is the final ! speciesData = existingSpeciesData; ! } ! } ! } ! 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; } --- 229,239 ---- @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) { --- 477,488 ---- } } 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. --- 505,515 ---- } 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 >