< prev index next >
src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java
Print this page
rev 12975 : 8131129: Attempt to define a duplicate BMH$Species class
Contributed-by: peter.levart@gmail.com
@@ -372,10 +372,11 @@
this.extensions = null;
}
private boolean isPlaceholder() { return clazz == null; }
private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
+ private static final HashMap<String, VirtualMachineError> FAILED_SPECIES_CACHE = new HashMap<>();
static { CACHE.put("", EMPTY); } // make bootstrap predictable
private static final boolean INIT_DONE; // set after <clinit> finishes...
SpeciesData extendWith(byte type) {
return extendWith(BasicType.basicType(type));
@@ -393,24 +394,37 @@
// Acquire cache lock for query.
SpeciesData d = lookupCache(types);
if (!d.isPlaceholder())
return d;
synchronized (d) {
+ VirtualMachineError previousFailure;
+ if ((previousFailure = FAILED_SPECIES_CACHE.get(types)) != null) {
+ throw new InternalError("species creation for " + types + " failed previously", previousFailure);
+ }
// 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 d2 = lookupCache(types);
+ if (d2.isPlaceholder()) {
+ try {
+ Class<? extends BoundMethodHandle> bmhcl = Factory.generateConcreteBMHClass(types);
+ // install new SpeciesData into cache
+ d2 = Factory.speciesDataFromConcreteBMHClass(bmhcl);
+ assert(!d2.isPlaceholder());
+ updateCache(d2.typeChars, d2);
+ } catch (VirtualMachineError vme) {
+ // The species is not registered in the cache if something went wrong during class definition or
+ // initialization. Register it in the failure cache for future reference, and throw the VME.
+ FAILED_SPECIES_CACHE.put(types, vme);
+ throw vme;
+ }
+ }
+ d = d2;
+ }
return d;
}
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));
+ return 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);
@@ -424,30 +438,44 @@
assert(!d.isPlaceholder());
CACHE.put(types, d);
return d;
}
- 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);
}
+ return true;
+ }
+ static {
+ // Pre-fill the BMH species-data cache with BMH's inner subclasses. All of these classes' SPECIES_DATA
+ // fields must be added to the staticSpeciesData array to ensure proper cache population.
+ SpeciesData[] staticSpeciesData = new SpeciesData[]{Species_L.SPECIES_DATA};
+ for (SpeciesData d : staticSpeciesData) {
+ updateCache(d.typeChars, d);
+ }
for (SpeciesData d : CACHE.values()) {
d.initForBootstrap();
}
+ assert speciesDataCachePopulated();
// Note: Do not simplify this, because INIT_DONE must not be
// a compile-time constant during bootstrapping.
INIT_DONE = Boolean.TRUE;
}
}
@@ -584,24 +612,21 @@
mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0); // this
mv.visitVarInsn(ALOAD, 1); // type
mv.visitVarInsn(ALOAD, 2); // form
-
mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
-
for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
// i counts the arguments, j counts corresponding argument slots
char t = types.charAt(i);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
if (t == 'J' || t == 'D') {
++j; // adjust argument register access
}
}
-
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// emit implementation of speciesData()
@@ -622,10 +647,11 @@
mv.visitIntInsn(SIPUSH, fc);
}
mv.visitInsn(IRETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
+
// emit make() ...factory method wrapping constructor
mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
mv.visitCode();
// make instance
mv.visitTypeInsn(NEW, className);
@@ -640,11 +666,10 @@
mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
if (t == 'J' || t == 'D') {
++j; // adjust argument register access
}
}
-
// finally, invoke the constructor and return
mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
< prev index next >