< prev index next >

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

Print this page
rev 13971 : 8152641: Plugin to generate BMH$Species classes ahead-of-time
Reviewed-by: plevart, mchung, forax

@@ -23,10 +23,11 @@
  * questions.
  */
 
 package java.lang.invoke;
 
+import jdk.internal.loader.BootLoader;
 import jdk.internal.vm.annotation.Stable;
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.FieldVisitor;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import sun.invoke.util.ValueConversions;

@@ -487,11 +488,19 @@
             // 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);
+                        String shortTypes = LambdaForm.shortenSignature(types);
+                        Class<?> c = BootLoader.loadClassOrNull(
+                                "java.lang.invoke.BoundMethodHandle$Species_" + shortTypes);
+                        if (c != null) {
+                            return c.asSubclass(BoundMethodHandle.class);
+                        } else {
+                            // Not pregenerated, generate the class
+                            return generateConcreteBMHClass(shortTypes, types);
+                        }
                     }
                 });
         }
 
         /**

@@ -556,67 +565,71 @@
          * </pre>
          *
          * @param types the type signature, wherein reference types are erased to 'L'
          * @return the generated concrete BMH class
          */
-        static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
-            final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
-
-            String shortTypes = LambdaForm.shortenSignature(types);
+        static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String shortTypes, String types) {
             final String className  = SPECIES_PREFIX_PATH + shortTypes;
             final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
+
+            byte[] classFile = generateConcreteBMHClassBytes(className, sourceFile, types);
+
+            // load class
+            InvokerBytecodeGenerator.maybeDump(className, classFile);
+            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);
+
+            return bmhClass;
+        }
+
+        static byte[] generateConcreteBMHClassBytes(final String className, final String sourceFile, final String types) {
+            final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
             final int NOT_ACC_PUBLIC = 0;  // not ACC_PUBLIC
             cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
             cw.visitSource(sourceFile, null);
-
             // emit static types and SPECIES_DATA fields
             FieldVisitor fw = cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null);
             fw.visitAnnotation(STABLE_SIG, true);
             fw.visitEnd();
-
             // emit bound argument fields
             for (int i = 0; i < types.length(); ++i) {
                 final char t = types.charAt(i);
                 final String fieldName = makeFieldName(types, i);
                 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
                 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
             }
-
             MethodVisitor mv;
-
             // emit constructor
             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()
             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
             mv.visitCode();
             mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
             mv.visitInsn(ARETURN);
             mv.visitMaxs(0, 0);
             mv.visitEnd();
-
             // emit implementation of fieldCount()
             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
             mv.visitCode();
             int fc = types.length();
             if (fc <= (ICONST_5 - ICONST_0)) {

@@ -643,17 +656,15 @@
                 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();
-
             // emit copyWith()
             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
             mv.visitCode();
             // make instance
             mv.visitTypeInsn(NEW, className);

@@ -666,11 +677,10 @@
             // finally, invoke the constructor and return
             mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
             mv.visitInsn(ARETURN);
             mv.visitMaxs(0, 0);
             mv.visitEnd();
-
             // for each type, emit copyWithExtendT()
             for (BasicType type : BasicType.ARG_TYPES) {
                 int ord = type.ordinal();
                 char btChar = type.basicTypeChar();
                 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);

@@ -694,23 +704,12 @@
                 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
                 mv.visitInsn(ARETURN);
                 mv.visitMaxs(0, 0);
                 mv.visitEnd();
             }
-
             cw.visitEnd();
-
-            // load class
-            final byte[] classFile = cw.toByteArray();
-            InvokerBytecodeGenerator.maybeDump(className, classFile);
-            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);
-
-            return bmhClass;
+            return cw.toByteArray();
         }
 
         private static int typeLoadOp(char t) {
             switch (t) {
             case 'L': return ALOAD;
< prev index next >