< 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 >