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