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