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