< prev index next >

src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java

Print this page

        

*** 32,42 **** 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 sun.invoke.util.ValueConversions; import sun.invoke.util.Wrapper; import jdk.internal.org.objectweb.asm.ClassWriter; --- 32,44 ---- import java.lang.invoke.LambdaForm.NamedFunction; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Field; import java.util.Arrays; ! 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,382 **** private void initForBootstrap() { assert(!INIT_DONE); if (constructor() == null) { String types = typeChars; 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 boolean INIT_DONE; // set after <clinit> finishes... SpeciesData extendWith(byte type) { return extendWith(BasicType.basicType(type)); } --- 355,372 ---- 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 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,453 **** 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()); 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)); ! } ! 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; } ! static { ! // pre-fill the BMH speciesdata cache with BMH's inner classes ! final 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)); } } } catch (Throwable e) { throw newInternalError(e); } ! ! for (SpeciesData d : CACHE.values()) { ! d.initForBootstrap(); } // Note: Do not simplify this, because INIT_DONE must not be // a compile-time constant during bootstrapping. INIT_DONE = Boolean.TRUE; } } --- 378,434 ---- extensions[ord] = d = get(typeChars+type.basicTypeChar()); return d; } private static SpeciesData get(String types) { ! 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 new SpeciesData(types, clazz); } ! /** ! * 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(CACHE.get(d.typeChars) == d); } } } catch (Throwable e) { throw newInternalError(e); } ! 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,500 **** --- 472,501 ---- 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,723 **** 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) { --- 714,723 ----
< prev index next >