< 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, vlivanov, jrose
*** 23,32 ****
--- 23,33 ----
* 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;
*** 34,43 ****
--- 35,45 ----
import java.lang.invoke.LambdaForm.NamedFunction;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field;
import java.util.Arrays;
+ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import static java.lang.invoke.LambdaForm.BasicType;
*** 461,470 ****
--- 463,473 ----
static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
static final String STABLE_SIG = "Ljdk/internal/vm/annotation/Stable;";
static final String SPECIES_PREFIX_NAME = "Species_";
static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
+ static final String SPECIES_CLASS_PREFIX = SPECIES_PREFIX_PATH.replace('/', '.');
static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
static final String VOID_SIG = "()V";
*** 487,497 ****
// 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);
}
});
}
/**
--- 490,508 ----
// only once per key.
return CLASS_CACHE.computeIfAbsent(
types, new Function<String, Class<? extends BoundMethodHandle>>() {
@Override
public Class<? extends BoundMethodHandle> apply(String types) {
! String shortTypes = LambdaForm.shortenSignature(types);
! String className = SPECIES_CLASS_PREFIX + shortTypes;
! Class<?> c = BootLoader.loadClassOrNull(className);
! if (c != null) {
! return c.asSubclass(BoundMethodHandle.class);
! } else {
! // Not pregenerated, generate the class
! return generateConcreteBMHClass(shortTypes, types);
! }
}
});
}
/**
*** 556,571 ****
* </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);
! final String className = SPECIES_PREFIX_PATH + shortTypes;
final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
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
--- 567,619 ----
* </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 shortTypes,
! String types) {
! final String className = speciesInternalClassName(shortTypes);
! byte[] classFile = generateConcreteBMHClassBytes(shortTypes, types, className);
!
! // load class
! InvokerBytecodeGenerator.maybeDump(className, classFile);
! Class<? extends BoundMethodHandle> bmhClass =
! UNSAFE.defineClass(className, classFile, 0, classFile.length,
! BoundMethodHandle.class.getClassLoader(), null)
! .asSubclass(BoundMethodHandle.class);
!
! return bmhClass;
! }
+ /**
+ * @implNote this method is used by GenerateBMHClassesPlugin to enable
+ * ahead-of-time generation of BMH classes at link time. It does
+ * added validation since this string may be user provided.
+ */
+ static Map.Entry<String, byte[]> generateConcreteBMHClassBytes(
+ final String types) {
+ for (char c : types.toCharArray()) {
+ if ("LIJFD".indexOf(c) < 0) {
+ throw new IllegalArgumentException("All characters must "
+ + "correspond to a basic field type: LIJFD");
+ }
+ }
String shortTypes = LambdaForm.shortenSignature(types);
! final String className = speciesInternalClassName(shortTypes);
! return Map.entry(className,
! generateConcreteBMHClassBytes(shortTypes, types, className));
! }
!
! private static String speciesInternalClassName(String shortTypes) {
! return SPECIES_PREFIX_PATH + shortTypes;
! }
!
! static byte[] generateConcreteBMHClassBytes(final String shortTypes,
! final String types, final String className) {
final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
+
+ 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
*** 697,716 ****
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;
}
private static int typeLoadOp(char t) {
switch (t) {
case 'L': return ALOAD;
--- 745,755 ----
mv.visitEnd();
}
cw.visitEnd();
! return cw.toByteArray();
}
private static int typeLoadOp(char t) {
switch (t) {
case 'L': return ALOAD;
< prev index next >