8198418: Invoke LambdaMetafactory::metafactory exactly from the BootstrapMethodInvoker
Reviewed-by: briangoetz, forax, vlivanov
--- 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},