< 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

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