--- old/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java 2015-10-29 15:39:24.000000000 +0100 +++ new/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java 2015-10-29 15:39:24.000000000 +0100 @@ -374,6 +374,7 @@ private boolean isPlaceholder() { return clazz == null; } private static final HashMap CACHE = new HashMap<>(); + private static final HashMap FAILED_SPECIES_CACHE = new HashMap<>(); static { CACHE.put("", EMPTY); } // make bootstrap predictable private static final boolean INIT_DONE; // set after finishes... @@ -395,20 +396,33 @@ 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 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 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); @@ -426,9 +440,13 @@ return d; } - static { - // pre-fill the BMH speciesdata cache with BMH's inner classes - final Class 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 rootCls = BoundMethodHandle.class; try { for (Class c : rootCls.getDeclaredClasses()) { if (rootCls.isAssignableFrom(c)) { @@ -436,16 +454,26 @@ 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; @@ -586,9 +614,7 @@ mv.visitVarInsn(ALOAD, 0); // this mv.visitVarInsn(ALOAD, 1); // type mv.visitVarInsn(ALOAD, 2); // form - mv.visitMethodInsn(INVOKESPECIAL, BMH, "", 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); @@ -599,7 +625,6 @@ ++j; // adjust argument register access } } - mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); @@ -624,6 +649,7 @@ 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(); @@ -642,7 +668,6 @@ ++j; // adjust argument register access } } - // finally, invoke the constructor and return mv.visitMethodInsn(INVOKESPECIAL, className, "", makeSignature(types, true), false); mv.visitInsn(ARETURN);