< prev index next >
src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java
Print this page
@@ -32,11 +32,13 @@
import java.lang.invoke.LambdaForm.NamedFunction;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field;
import java.util.Arrays;
-import java.util.HashMap;
+import java.util.function.Function;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.Wrapper;
import jdk.internal.org.objectweb.asm.ClassWriter;
@@ -353,30 +355,18 @@
private void initForBootstrap() {
assert(!INIT_DONE);
if (constructor() == null) {
String types = typeChars;
+ CACHE.put(types, this);
Factory.makeCtors(clazz, types, this.constructor);
Factory.makeGetters(clazz, types, this.getters);
Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
}
}
- private SpeciesData(String typeChars) {
- // Placeholder only.
- this.typeChars = typeChars;
- this.typeCodes = basicTypes(typeChars);
- this.clazz = null;
- this.constructor = null;
- this.getters = null;
- this.nominalGetters = null;
- this.extensions = null;
- }
- private boolean isPlaceholder() { return clazz == null; }
-
- private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
- static { CACHE.put("", EMPTY); } // make bootstrap predictable
+ private static final ConcurrentMap<String, SpeciesData> CACHE = new ConcurrentHashMap<>();
private static final boolean INIT_DONE; // set after <clinit> finishes...
SpeciesData extendWith(byte type) {
return extendWith(BasicType.basicType(type));
}
@@ -388,66 +378,57 @@
extensions[ord] = d = get(typeChars+type.basicTypeChar());
return d;
}
private static SpeciesData get(String types) {
- // Acquire cache lock for query.
- SpeciesData d = lookupCache(types);
- if (!d.isPlaceholder())
- return d;
- synchronized (d) {
- // Use synch. on the placeholder to prevent multiple instantiation of one species.
- // Creating this class forces a recursive call to getForClass.
- if (lookupCache(types).isPlaceholder())
- Factory.generateConcreteBMHClass(types);
- }
- // Reacquire cache lock.
- d = lookupCache(types);
- // Class loading must have upgraded the cache.
- assert(d != null && !d.isPlaceholder());
+ SpeciesData d = CACHE.get(types);
+ if (d == null) {
+ Class<? extends BoundMethodHandle> bmhcl = Factory.getConcreteBMHClass(types);
+ // obtain value of SPECIES_DATA static field.
+ // This triggers class initialization which might fail!
+ d = Factory.speciesDataFromConcreteBMHClass(bmhcl);
+ SpeciesData d2 = CACHE.putIfAbsent(types, d);
+ assert d2 == null || d2 == d;
+ }
return d;
}
+
+ // a call-back from generated BMH subclass' <clinit>
static SpeciesData getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
// clazz is a new class which is initializing its SPECIES_DATA field
- return updateCache(types, new SpeciesData(types, clazz));
- }
- private static synchronized SpeciesData lookupCache(String types) {
- SpeciesData d = CACHE.get(types);
- if (d != null) return d;
- d = new SpeciesData(types);
- assert(d.isPlaceholder());
- CACHE.put(types, d);
- return d;
- }
- private static synchronized SpeciesData updateCache(String types, SpeciesData d) {
- SpeciesData d2;
- assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
- assert(!d.isPlaceholder());
- CACHE.put(types, d);
- return d;
+ return new SpeciesData(types, clazz);
}
- static {
- // pre-fill the BMH speciesdata cache with BMH's inner classes
- final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
+ /**
+ * This is to be called when assertions are enabled. It checks whether SpeciesData for all of the statically
+ * defined species subclasses of BoundMethodHandle has been added to the SpeciesData cache. See below in the
+ * static initializer for
+ */
+ static boolean speciesDataCachePopulated() {
+ Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
try {
for (Class<?> c : rootCls.getDeclaredClasses()) {
if (rootCls.isAssignableFrom(c)) {
final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
assert(d != null) : cbmh.getName();
assert(d.clazz == cbmh);
- assert(d == lookupCache(d.typeChars));
+ assert(CACHE.get(d.typeChars) == d);
}
}
} catch (Throwable e) {
throw newInternalError(e);
}
-
- for (SpeciesData d : CACHE.values()) {
- d.initForBootstrap();
+ return true;
}
+
+ static {
+ // Pre-fill the BMH species-data cache with EMPTY and all BMH's inner subclasses.
+ EMPTY.initForBootstrap();
+ Species_L.SPECIES_DATA.initForBootstrap();
+ // check that all static SpeciesData instances have been initialized
+ assert speciesDataCachePopulated();
// Note: Do not simplify this, because INIT_DONE must not be
// a compile-time constant during bootstrapping.
INIT_DONE = Boolean.TRUE;
}
}
@@ -491,10 +472,30 @@
static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
+ static final ConcurrentMap<String, Class<? extends BoundMethodHandle>> CLASS_CACHE = new ConcurrentHashMap<>();
+
+ /**
+ * Get a concrete subclass of BMH for a given combination of bound types.
+ *
+ * @param types the type signature, wherein reference types are erased to 'L'
+ * @return the concrete BMH class
+ */
+ static Class<? extends BoundMethodHandle> getConcreteBMHClass(String types) {
+ // CHM.computeIfAbsent ensures generateConcreteBMHClass is called
+ // only once per key.
+ return CLASS_CACHE.computeIfAbsent(
+ types, new Function<String, Class<? extends BoundMethodHandle>>() {
+ @Override
+ public Class<? extends BoundMethodHandle> apply(String types) {
+ return generateConcreteBMHClass(types);
+ }
+ });
+ }
+
/**
* Generate a concrete subclass of BMH for a given combination of bound types.
*
* A concrete BMH species adheres to the following schema:
*
@@ -713,11 +714,10 @@
Class<? extends BoundMethodHandle> bmhClass =
//UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
UNSAFE.defineClass(className, classFile, 0, classFile.length,
BoundMethodHandle.class.getClassLoader(), null)
.asSubclass(BoundMethodHandle.class);
- UNSAFE.ensureClassInitialized(bmhClass);
return bmhClass;
}
private static int typeLoadOp(char t) {
< prev index next >