8198418: Invoke LambdaMetafactory::metafactory exactly from the BootstrapMethodInvoker
authorredestad
Tue, 20 Feb 2018 17:49:15 +0100
changeset 48921 576e024f10b6
parent 48920 916690b5edc9
child 48922 906025796009
8198418: Invoke LambdaMetafactory::metafactory exactly from the BootstrapMethodInvoker Reviewed-by: briangoetz, forax, vlivanov
src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java
src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java
--- a/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java	Tue Feb 20 11:45:16 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java	Tue Feb 20 17:49:15 2018 +0100
@@ -116,8 +116,24 @@
                                                         argv[0], argv[1]);
                         break;
                     case 3:
-                        result = bootstrapMethod.invoke(caller, name, type,
-                                                        argv[0], argv[1], argv[2]);
+                        // Special case the LambdaMetafactory::metafactory BSM
+                        //
+                        // By invoking exactly, we can avoid generating a number of
+                        // classes on first (and subsequent) lambda initialization,
+                        // most of which won't be shared with other invoke uses.
+                        MethodType bsmType = bootstrapMethod.type();
+                        if (isLambdaMetafactoryIndyBSM(bsmType)) {
+                            result = (CallSite)bootstrapMethod
+                                    .invokeExact(caller, name, (MethodType)type, (MethodType)argv[0],
+                                                 (MethodHandle)argv[1], (MethodType)argv[2]);
+                        } else if (isLambdaMetafactoryCondyBSM(bsmType)) {
+                            result = bootstrapMethod
+                                    .invokeExact(caller, name, (Class<?>)type, (MethodType)argv[0],
+                                                 (MethodHandle)argv[1], (MethodType)argv[2]);
+                        } else {
+                            result = bootstrapMethod.invoke(caller, name, type,
+                                                            argv[0], argv[1], argv[2]);
+                        }
                         break;
                     case 4:
                         result = bootstrapMethod.invoke(caller, name, type,
@@ -175,6 +191,30 @@
         }
     }
 
+    private static final MethodType LMF_INDY_MT = MethodType.methodType(CallSite.class,
+            Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class);
+
+    private static final MethodType LMF_CONDY_MT = MethodType.methodType(Object.class,
+            Lookup.class, String.class, Class.class, MethodType.class, MethodHandle.class, MethodType.class);
+
+    /**
+     * @return true iff the BSM method type exactly matches
+     *         {@see java.lang.invoke.LambdaMetafactory#metafactory(
+     *          MethodHandles.Lookup,String,Class,MethodType,MethodHandle,MethodType)}
+     */
+    private static boolean isLambdaMetafactoryCondyBSM(MethodType bsmType) {
+        return bsmType == LMF_CONDY_MT;
+    }
+
+    /**
+     * @return true iff the BSM method type exactly matches
+     *         {@see java.lang.invoke.LambdaMetafactory#metafactory(
+     *          MethodHandles.Lookup,String,MethodType,MethodType,MethodHandle,MethodType)}
+     */
+    private static boolean isLambdaMetafactoryIndyBSM(MethodType bsmType) {
+        return bsmType == LMF_INDY_MT;
+    }
+
     /** The JVM produces java.lang.Integer values to box
      *  CONSTANT_Integer boxes but does not intern them.
      *  Let's intern them.  This is slightly wrong for
--- a/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java	Tue Feb 20 11:45:16 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java	Tue Feb 20 17:49:15 2018 +0100
@@ -242,6 +242,12 @@
     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
     private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
 
+    // LambdaMetafactory bootstrap methods are startup sensitive, and may be
+    // special cased in java.lang.invokeBootstrapMethodInvoker to ensure
+    // methods are invoked with exact type information to avoid generating
+    // code for runtime checks. Take care any changes or additions here are
+    // reflected there as appropriate.
+
     /**
      * Facilitates the creation of simple "function objects" that implement one
      * or more interfaces by delegation to a provided {@link MethodHandle},