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) return null; // No pre-generated version for customized LF
616 MethodType invokerType = form.methodType();
617 String name = form.kind.methodName;
618 switch (form.kind) {
619 case BOUND_REINVOKER: {
620 name = name + "_" + BoundMethodHandle.speciesData(form).fieldSignature();
621 return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
622 }
623 case DELEGATE: return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
624 case DIRECT_INVOKE_INTERFACE: // fall-through
625 case DIRECT_INVOKE_SPECIAL: // fall-through
626 case DIRECT_INVOKE_STATIC: // fall-through
627 case DIRECT_INVOKE_STATIC_INIT: // fall-through
628 case DIRECT_INVOKE_VIRTUAL: return resolveFrom(name, invokerType, DirectMethodHandle.Holder.class);
629 }
630 return null;
631 }
632
633 /**
634 * Generate customized bytecode for a given LambdaForm.
635 */
636 static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
637 MemberName pregenerated = lookupPregenerated(form);
638 if (pregenerated != null) return pregenerated; // pre-generated bytecode
639
640 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
641 return g.loadMethod(g.generateCustomizedCodeBytes());
642 }
643
644 /** Generates code to check that actual receiver and LambdaForm matches */
645 private boolean checkActualReceiver() {
646 // Expects MethodHandle on the stack and actual receiver MethodHandle in slot #0
647 mv.visitInsn(Opcodes.DUP);
648 mv.visitVarInsn(Opcodes.ALOAD, localsMap[0]);
649 mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "assertSame", LLV_SIG, false);
650 return true;
651 }
652
653 static String className(String cn) {
654 assert checkClassName(cn): "Class not found: " + cn;
655 return cn;
656 }
657
658 static boolean checkClassName(String cn) {
659 Type tp = Type.getType(cn);
|