8149459: StringConcatFactory should be synced up with LambdaMetafactory
Reviewed-by: psandoz, vlivanov, forax
--- a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java Wed Jan 27 10:35:49 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java Wed Feb 10 16:36:25 2016 +0300
@@ -182,22 +182,30 @@
private static final ConcurrentMap<Key, MethodHandle> CACHE;
+ /**
+ * Dump generated classes to disk, for debugging purposes.
+ */
+ private static final ProxyClassesDumper DUMPER;
+
static {
// Poke the privileged block once, taking everything we need:
- final Object[] values = new Object[3];
+ final Object[] values = new Object[4];
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
values[0] = System.getProperty("java.lang.invoke.stringConcat");
values[1] = Boolean.getBoolean("java.lang.invoke.stringConcat.cache");
values[2] = Boolean.getBoolean("java.lang.invoke.stringConcat.debug");
+ values[3] = System.getProperty("java.lang.invoke.stringConcat.dumpClasses");
return null;
});
final String strategy = (String) values[0];
CACHE_ENABLE = (Boolean) values[1];
DEBUG = (Boolean) values[2];
+ final String dumpPath = (String) values[3];
STRATEGY = (strategy == null) ? DEFAULT_STRATEGY : Strategy.valueOf(strategy);
CACHE = CACHE_ENABLE ? new ConcurrentHashMap<>() : null;
+ DUMPER = (dumpPath == null) ? null : ProxyClassesDumper.getInstance(dumpPath);
}
private static final class Key {
@@ -552,6 +560,12 @@
Objects.requireNonNull(o, "Cannot accept null constants");
}
+ if ((lookup.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) {
+ throw new StringConcatException(String.format(
+ "Invalid caller: %s",
+ lookup.lookupClass().getName()));
+ }
+
int cCount = 0;
int oCount = 0;
if (generateRecipe) {
@@ -1035,6 +1049,10 @@
final byte[] classBytes = cw.toByteArray();
final Class<?> innerClass = UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
+ if (DUMPER != null) {
+ DUMPER.dumpClass(innerClass.getName(), classBytes);
+ }
+
try {
UNSAFE.ensureClassInitialized(innerClass);
return lookup.findStatic(innerClass, NAME_FACTORY, args);
--- a/jdk/test/java/lang/String/concat/StringConcatFactoryInvariants.java Wed Jan 27 10:35:49 2016 +0100
+++ b/jdk/test/java/lang/String/concat/StringConcatFactoryInvariants.java Wed Feb 10 16:36:25 2016 +0300
@@ -66,7 +66,7 @@
private static final char TAG_CONST = '\u0002';
public static void main(String[] args) throws Throwable {
- MethodHandles.Lookup lookup = MethodHandles.publicLookup();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
String methodName = "foo";
MethodType mt = MethodType.methodType(String.class, String.class, int.class);
String recipe = "" + TAG_ARG + TAG_ARG + TAG_CONST;
@@ -236,6 +236,14 @@
// Advanced factory: test empty arguments
ok("Ok to pass empty arguments",
() -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtEmpty, recipeEmpty));
+
+ // Simple factory: public Lookup is rejected
+ fail("Passing public Lookup",
+ () -> StringConcatFactory.makeConcat(MethodHandles.publicLookup(), methodName, mtEmpty));
+
+ // Advanced factory: public Lookup is rejected
+ fail("Passing public Lookup",
+ () -> StringConcatFactory.makeConcatWithConstants(MethodHandles.publicLookup(), methodName, mtEmpty, recipeEmpty));
}
public static void ok(String msg, Callable runnable) {