--- old/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java 2019-12-03 19:37:29.000000000 -0800 +++ new/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java 2019-12-03 19:37:29.000000000 -0800 @@ -25,7 +25,8 @@ package java.lang.invoke; -import jdk.internal.misc.Unsafe; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.misc.VM; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Label; @@ -42,6 +43,9 @@ import java.util.concurrent.ConcurrentMap; import java.util.function.Function; +import static java.lang.invoke.MethodHandles.lookup; +import static java.lang.invoke.MethodType.methodType; +import static java.lang.invoke.MethodHandleNatives.Constants.*; import static jdk.internal.org.objectweb.asm.Opcodes.*; /** @@ -133,6 +137,8 @@ */ private static final Strategy DEFAULT_STRATEGY = Strategy.MH_INLINE_SIZED_EXACT; + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private enum Strategy { /** * Bytecode generator, calling into {@link java.lang.StringBuilder}. @@ -189,8 +195,6 @@ */ private static final ProxyClassesDumper DUMPER; - private static final Class> STRING_HELPER; - static { // In case we need to double-back onto the StringConcatFactory during this // static initialization, make sure we have the reasonable defaults to complete @@ -202,12 +206,6 @@ // DEBUG = false; // implied // DUMPER = null; // implied - try { - STRING_HELPER = Class.forName("java.lang.StringConcatHelper"); - } catch (Throwable e) { - throw new AssertionError(e); - } - final String strategy = VM.getSavedProperty("java.lang.invoke.stringConcat"); CACHE_ENABLE = Boolean.parseBoolean( @@ -723,8 +721,7 @@ However, there are two peculiarities: a) The generated class should stay within the same package as the - host class, to allow Unsafe.defineAnonymousClass access controls - to work properly. JDK may choose to fail with IllegalAccessException + host class. JDK may choose to fail with IllegalAccessException when accessing a VM anonymous class with non-privileged callers, see JDK-8058575. @@ -747,7 +744,9 @@ String pkgName = hostClass.getPackageName(); return (pkgName != null && !pkgName.isEmpty() ? pkgName.replace('.', '/') + "/" : "") + "Stubs$$StringConcat"; } else { - return hostClass.getName().replace('.', '/') + "$$StringConcat"; + String name = hostClass.isHiddenClass() ? hostClass.getName().replace('/', '_') + : hostClass.getName(); + return name.replace('.', '/') + "$$StringConcat"; } } case MH_SB_SIZED: @@ -819,7 +818,7 @@ * chain javac would otherwise emit. This strategy uses only the public API, * and comes as the baseline for the current JDK behavior. On other words, * this strategy moves the javac generated bytecode to runtime. The - * generated bytecode is loaded via Unsafe.defineAnonymousClass, but with + * generated bytecode is loaded via Lookup::defineClass, but with * the caller class coming from the BSM -- in other words, the protection * guarantees are inherited from the method where invokedynamic was * originally called. This means, among other things, that the bytecode is @@ -848,7 +847,6 @@ * private String API. */ private static final class BytecodeStringBuilderStrategy { - static final Unsafe UNSAFE = Unsafe.getUnsafe(); static final int CLASSFILE_VERSION = 52; static final String METHOD_NAME = "concat"; @@ -861,7 +859,7 @@ cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_PUBLIC + ACC_FINAL + ACC_SYNTHETIC, - className, // Unsafe.defineAnonymousClass would append an unique ID + className, null, "java/lang/Object", null @@ -874,6 +872,7 @@ null, null); + // use of @ForceInline no longer has any effect mv.visitAnnotation("Ljdk/internal/vm/annotation/ForceInline;", true); mv.visitCode(); @@ -1143,11 +1142,9 @@ byte[] classBytes = cw.toByteArray(); try { - Class> hostClass = lookup.lookupClass(); - Class> innerClass = UNSAFE.defineAnonymousClass(hostClass, classBytes, null); - UNSAFE.ensureClassInitialized(innerClass); - dumpIfEnabled(innerClass.getName(), classBytes); - return Lookup.IMPL_LOOKUP.findStatic(innerClass, METHOD_NAME, args); + Class> innerClass = lookup.defineHiddenClass(classBytes,true).lookupClass(); + dumpIfEnabled(className, classBytes); + return lookup.findStatic(innerClass, METHOD_NAME, args); } catch (Exception e) { dumpIfEnabled(className + "$$FAILED", classBytes); throw new StringConcatException("Exception while spinning the class", e); @@ -1270,8 +1267,8 @@ * computation on MethodHandle combinators. The computation is built with * public MethodHandle APIs, resolved from a public Lookup sequence, and * ends up calling the public StringBuilder API. Therefore, this strategy - * does not use any private API at all, even the Unsafe.defineAnonymousClass, - * since everything is handled under cover by java.lang.invoke APIs. + * does not use any private API at all since everything is handled under + * cover by java.lang.invoke APIs. * *
{@link Strategy#MH_SB_SIZED_EXACT}: "MethodHandles StringBuilder,
* sized exactly".
@@ -1283,7 +1280,6 @@
* private String API.
*/
private static final class MethodHandleStringBuilderStrategy {
-
private MethodHandleStringBuilderStrategy() {
// no instantiation
}
@@ -1461,6 +1457,8 @@
return sum;
}
+ private static final Lookup MHSBS_LOOKUP = lookup();
+
private static final ConcurrentMap