< prev index next >

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java

Print this page
rev 15353 : 8164044: Generate corresponding simple DelegatingMethodHandles when generating a DirectMethodHandle at link time
Reviewed-by: vlivanov, mhaupt, shade


  29 import jdk.internal.org.objectweb.asm.Label;
  30 import jdk.internal.org.objectweb.asm.MethodVisitor;
  31 import jdk.internal.org.objectweb.asm.Opcodes;
  32 import jdk.internal.org.objectweb.asm.Type;
  33 import sun.invoke.util.VerifyAccess;
  34 import sun.invoke.util.VerifyType;
  35 import sun.invoke.util.Wrapper;
  36 import sun.reflect.misc.ReflectUtil;
  37 
  38 import java.io.File;
  39 import java.io.FileOutputStream;
  40 import java.io.IOException;
  41 import java.lang.reflect.Modifier;
  42 import java.util.Arrays;
  43 import java.util.ArrayList;
  44 import java.util.HashMap;
  45 import java.util.stream.Stream;
  46 
  47 import static java.lang.invoke.LambdaForm.*;
  48 import static java.lang.invoke.LambdaForm.BasicType.*;

  49 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  50 import static java.lang.invoke.MethodHandleStatics.*;
  51 
  52 /**
  53  * Code generation backend for LambdaForm.
  54  * <p>
  55  * @author John Rose, JSR 292 EG
  56  */
  57 class InvokerBytecodeGenerator {
  58     /** Define class names for convenience. */
  59     private static final String MH      = "java/lang/invoke/MethodHandle";
  60     private static final String MHI     = "java/lang/invoke/MethodHandleImpl";
  61     private static final String LF      = "java/lang/invoke/LambdaForm";
  62     private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
  63     private static final String CLS     = "java/lang/Class";
  64     private static final String OBJ     = "java/lang/Object";
  65     private static final String OBJARY  = "[Ljava/lang/Object;";
  66 
  67     private static final String LF_SIG  = "L" + LF + ";";
  68     private static final String LFN_SIG = "L" + LFN + ";";


 108         this.className  = CLASS_PREFIX + className;
 109         this.sourceFile = "LambdaForm$" + className;
 110         this.lambdaForm = lambdaForm;
 111         this.invokerName = invokerName;
 112         this.invokerType = invokerType;
 113         this.localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
 114         this.localClasses = new Class<?>[localsMapSize+1];
 115     }
 116 
 117     /** For generating LambdaForm interpreter entry points. */
 118     private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
 119         this(null, invokerType.parameterCount(),
 120              className, invokerName, invokerType);
 121         // Create an array to map name indexes to locals indexes.
 122         for (int i = 0; i < localsMap.length; i++) {
 123             localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
 124         }
 125     }
 126 
 127     /** For generating customized code for a single LambdaForm. */
 128     InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {






 129         this(form, form.names.length,
 130              className, form.debugName, invokerType);
 131         // Create an array to map name indexes to locals indexes.
 132         Name[] names = form.names;
 133         for (int i = 0, index = 0; i < localsMap.length; i++) {
 134             localsMap[i] = index;
 135             if (i < names.length) {
 136                 BasicType type = names[i].type();
 137                 index += type.basicTypeSlots();
 138             }
 139         }
 140     }
 141 
 142     /** instance counters for dumped classes */
 143     private static final HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
 144     /** debugging flag for saving generated class files */
 145     private static final File DUMP_CLASS_FILES_DIR;
 146 
 147     static {
 148         if (DUMP_CLASS_FILES) {
 149             DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
 150             try {


 580         case J_TYPE:  opcode = Opcodes.LRETURN;  break;
 581         case F_TYPE:  opcode = Opcodes.FRETURN;  break;
 582         case D_TYPE:  opcode = Opcodes.DRETURN;  break;
 583         case L_TYPE:  opcode = Opcodes.ARETURN;  break;
 584         case V_TYPE:  opcode = Opcodes.RETURN;   break;
 585         default:
 586             throw new InternalError("unknown return type: " + type);
 587         }
 588         mv.visitInsn(opcode);
 589     }
 590 
 591     private static String getInternalName(Class<?> c) {
 592         if (c == Object.class)             return OBJ;
 593         else if (c == Object[].class)      return OBJARY;
 594         else if (c == Class.class)         return CLS;
 595         else if (c == MethodHandle.class)  return MH;
 596         assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName();
 597         return c.getName().replace('.', '/');
 598     }
 599 





























 600     /**
 601      * Generate customized bytecode for a given LambdaForm.
 602      */
 603     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {



 604         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
 605         return g.loadMethod(g.generateCustomizedCodeBytes());
 606     }
 607 
 608     /** Generates code to check that actual receiver and LambdaForm matches */
 609     private boolean checkActualReceiver() {
 610         // Expects MethodHandle on the stack and actual receiver MethodHandle in slot #0
 611         mv.visitInsn(Opcodes.DUP);
 612         mv.visitVarInsn(Opcodes.ALOAD, localsMap[0]);
 613         mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "assertSame", LLV_SIG, false);
 614         return true;
 615     }
 616 
 617     static String className(String cn) {
 618         assert checkClassName(cn): "Class not found: " + cn;
 619         return cn;
 620     }
 621 
 622     static boolean checkClassName(String cn) {
 623         Type tp = Type.getType(cn);




  29 import jdk.internal.org.objectweb.asm.Label;
  30 import jdk.internal.org.objectweb.asm.MethodVisitor;
  31 import jdk.internal.org.objectweb.asm.Opcodes;
  32 import jdk.internal.org.objectweb.asm.Type;
  33 import sun.invoke.util.VerifyAccess;
  34 import sun.invoke.util.VerifyType;
  35 import sun.invoke.util.Wrapper;
  36 import sun.reflect.misc.ReflectUtil;
  37 
  38 import java.io.File;
  39 import java.io.FileOutputStream;
  40 import java.io.IOException;
  41 import java.lang.reflect.Modifier;
  42 import java.util.Arrays;
  43 import java.util.ArrayList;
  44 import java.util.HashMap;
  45 import java.util.stream.Stream;
  46 
  47 import static java.lang.invoke.LambdaForm.*;
  48 import static java.lang.invoke.LambdaForm.BasicType.*;
  49 import static java.lang.invoke.LambdaForm.Kind.*;
  50 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  51 import static java.lang.invoke.MethodHandleStatics.*;
  52 
  53 /**
  54  * Code generation backend for LambdaForm.
  55  * <p>
  56  * @author John Rose, JSR 292 EG
  57  */
  58 class InvokerBytecodeGenerator {
  59     /** Define class names for convenience. */
  60     private static final String MH      = "java/lang/invoke/MethodHandle";
  61     private static final String MHI     = "java/lang/invoke/MethodHandleImpl";
  62     private static final String LF      = "java/lang/invoke/LambdaForm";
  63     private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
  64     private static final String CLS     = "java/lang/Class";
  65     private static final String OBJ     = "java/lang/Object";
  66     private static final String OBJARY  = "[Ljava/lang/Object;";
  67 
  68     private static final String LF_SIG  = "L" + LF + ";";
  69     private static final String LFN_SIG = "L" + LFN + ";";


 109         this.className  = CLASS_PREFIX + className;
 110         this.sourceFile = "LambdaForm$" + className;
 111         this.lambdaForm = lambdaForm;
 112         this.invokerName = invokerName;
 113         this.invokerType = invokerType;
 114         this.localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
 115         this.localClasses = new Class<?>[localsMapSize+1];
 116     }
 117 
 118     /** For generating LambdaForm interpreter entry points. */
 119     private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
 120         this(null, invokerType.parameterCount(),
 121              className, invokerName, invokerType);
 122         // Create an array to map name indexes to locals indexes.
 123         for (int i = 0; i < localsMap.length; i++) {
 124             localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
 125         }
 126     }
 127 
 128     /** For generating customized code for a single LambdaForm. */
 129     private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
 130         this(className, form.debugName, form, invokerType);
 131     }
 132 
 133     /** For generating customized code for a single LambdaForm. */
 134     InvokerBytecodeGenerator(String className, String invokerName,
 135             LambdaForm form, MethodType invokerType) {
 136         this(form, form.names.length,
 137              className, invokerName, invokerType);
 138         // Create an array to map name indexes to locals indexes.
 139         Name[] names = form.names;
 140         for (int i = 0, index = 0; i < localsMap.length; i++) {
 141             localsMap[i] = index;
 142             if (i < names.length) {
 143                 BasicType type = names[i].type();
 144                 index += type.basicTypeSlots();
 145             }
 146         }
 147     }
 148 
 149     /** instance counters for dumped classes */
 150     private static final HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
 151     /** debugging flag for saving generated class files */
 152     private static final File DUMP_CLASS_FILES_DIR;
 153 
 154     static {
 155         if (DUMP_CLASS_FILES) {
 156             DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
 157             try {


 587         case J_TYPE:  opcode = Opcodes.LRETURN;  break;
 588         case F_TYPE:  opcode = Opcodes.FRETURN;  break;
 589         case D_TYPE:  opcode = Opcodes.DRETURN;  break;
 590         case L_TYPE:  opcode = Opcodes.ARETURN;  break;
 591         case V_TYPE:  opcode = Opcodes.RETURN;   break;
 592         default:
 593             throw new InternalError("unknown return type: " + type);
 594         }
 595         mv.visitInsn(opcode);
 596     }
 597 
 598     private static String getInternalName(Class<?> c) {
 599         if (c == Object.class)             return OBJ;
 600         else if (c == Object[].class)      return OBJARY;
 601         else if (c == Class.class)         return CLS;
 602         else if (c == MethodHandle.class)  return MH;
 603         assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName();
 604         return c.getName().replace('.', '/');
 605     }
 606 
 607     private static MemberName resolveFrom(String name, MethodType type, Class<?> holder) {
 608         MemberName member = new MemberName(holder, name, type, REF_invokeStatic);
 609         MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder);
 610 
 611         return resolvedMember;
 612     }
 613 
 614     private static MemberName lookupPregenerated(LambdaForm form) {
 615         if (form.customized != null) {
 616             // No pre-generated version for customized LF
 617             return null;
 618         }
 619         MethodType invokerType = form.methodType();
 620         String name = form.kind.methodName;
 621         switch (form.kind) {
 622             case BOUND_REINVOKER: {
 623                 name = name + "_" + BoundMethodHandle.speciesData(form).fieldSignature();
 624                 return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
 625             }
 626             case DELEGATE:                  return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
 627             case DIRECT_INVOKE_INTERFACE:   // fall-through
 628             case DIRECT_INVOKE_SPECIAL:     // fall-through
 629             case DIRECT_INVOKE_STATIC:      // fall-through
 630             case DIRECT_INVOKE_STATIC_INIT: // fall-through
 631             case DIRECT_INVOKE_VIRTUAL:     return resolveFrom(name, invokerType, DirectMethodHandle.Holder.class);
 632         }
 633         return null;
 634     }
 635 
 636     /**
 637      * Generate customized bytecode for a given LambdaForm.
 638      */
 639     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
 640         MemberName pregenerated = lookupPregenerated(form);
 641         if (pregenerated != null)  return pregenerated; // pre-generated bytecode
 642 
 643         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
 644         return g.loadMethod(g.generateCustomizedCodeBytes());
 645     }
 646 
 647     /** Generates code to check that actual receiver and LambdaForm matches */
 648     private boolean checkActualReceiver() {
 649         // Expects MethodHandle on the stack and actual receiver MethodHandle in slot #0
 650         mv.visitInsn(Opcodes.DUP);
 651         mv.visitVarInsn(Opcodes.ALOAD, localsMap[0]);
 652         mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "assertSame", LLV_SIG, false);
 653         return true;
 654     }
 655 
 656     static String className(String cn) {
 657         assert checkClassName(cn): "Class not found: " + cn;
 658         return cn;
 659     }
 660 
 661     static boolean checkClassName(String cn) {
 662         Type tp = Type.getType(cn);


< prev index next >