9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import sun.invoke.util.VerifyAccess;
29 import java.lang.invoke.LambdaForm.Name;
30
31 import sun.invoke.util.Wrapper;
32
33 import java.io.*;
34 import java.util.*;
35
36 import jdk.internal.org.objectweb.asm.*;
37
38 import java.lang.reflect.*;
39 import static java.lang.invoke.MethodHandleStatics.*;
40 import static java.lang.invoke.MethodHandleNatives.Constants.*;
41 import sun.invoke.util.VerifyType;
42
43 /**
44 * Code generation backend for LambdaForm.
45 * <p>
46 * @author John Rose, JSR 292 EG
47 */
48 class InvokerBytecodeGenerator {
49 /** Define class names for convenience. */
50 private static final String MH = "java/lang/invoke/MethodHandle";
51 private static final String MHI = "java/lang/invoke/MethodHandleImpl";
52 private static final String LF = "java/lang/invoke/LambdaForm";
53 private static final String LFN = "java/lang/invoke/LambdaForm$Name";
54 private static final String CLS = "java/lang/Class";
55 private static final String OBJ = "java/lang/Object";
56 private static final String OBJARY = "[Ljava/lang/Object;";
57
58 private static final String LF_SIG = "L" + LF + ";";
59 private static final String LFN_SIG = "L" + LFN + ";";
60 private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";";
98 this.invokerType = invokerType;
99 this.localsMap = new int[localsMapSize];
100 }
101
102 private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
103 this(null, invokerType.parameterCount(),
104 className, invokerName, invokerType);
105 // Create an array to map name indexes to locals indexes.
106 for (int i = 0; i < localsMap.length; i++) {
107 localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
108 }
109 }
110
111 private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
112 this(form, form.names.length,
113 className, form.debugName, invokerType);
114 // Create an array to map name indexes to locals indexes.
115 Name[] names = form.names;
116 for (int i = 0, index = 0; i < localsMap.length; i++) {
117 localsMap[i] = index;
118 index += Wrapper.forBasicType(names[i].type).stackSlots();
119 }
120 }
121
122
123 /** instance counters for dumped classes */
124 private final static HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
125 /** debugging flag for saving generated class files */
126 private final static File DUMP_CLASS_FILES_DIR;
127
128 static {
129 if (DUMP_CLASS_FILES) {
130 DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
131 try {
132 File dumpDir = new File("DUMP_CLASS_FILES");
133 if (!dumpDir.exists()) {
134 dumpDir.mkdirs();
135 }
136 DUMP_CLASS_FILES_DIR = dumpDir;
137 System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/...");
138 } catch (Exception e) {
340 case 2: opcode = Opcodes.ICONST_2; break;
341 case 3: opcode = Opcodes.ICONST_3; break;
342 case 4: opcode = Opcodes.ICONST_4; break;
343 case 5: opcode = Opcodes.ICONST_5; break;
344 default:
345 if (i == (byte) i) {
346 mv.visitIntInsn(Opcodes.BIPUSH, i & 0xFF);
347 } else if (i == (short) i) {
348 mv.visitIntInsn(Opcodes.SIPUSH, (char) i);
349 } else {
350 mv.visitLdcInsn(i);
351 }
352 return;
353 }
354 mv.visitInsn(opcode);
355 }
356
357 /*
358 * NOTE: These load/store methods use the localsMap to find the correct index!
359 */
360 private void emitLoadInsn(char type, int index) {
361 int opcode;
362 switch (type) {
363 case 'I': opcode = Opcodes.ILOAD; break;
364 case 'J': opcode = Opcodes.LLOAD; break;
365 case 'F': opcode = Opcodes.FLOAD; break;
366 case 'D': opcode = Opcodes.DLOAD; break;
367 case 'L': opcode = Opcodes.ALOAD; break;
368 default:
369 throw new InternalError("unknown type: " + type);
370 }
371 mv.visitVarInsn(opcode, localsMap[index]);
372 }
373 private void emitAloadInsn(int index) {
374 emitLoadInsn('L', index);
375 }
376
377 private void emitStoreInsn(char type, int index) {
378 int opcode;
379 switch (type) {
380 case 'I': opcode = Opcodes.ISTORE; break;
381 case 'J': opcode = Opcodes.LSTORE; break;
382 case 'F': opcode = Opcodes.FSTORE; break;
383 case 'D': opcode = Opcodes.DSTORE; break;
384 case 'L': opcode = Opcodes.ASTORE; break;
385 default:
386 throw new InternalError("unknown type: " + type);
387 }
388 mv.visitVarInsn(opcode, localsMap[index]);
389 }
390 private void emitAstoreInsn(int index) {
391 emitStoreInsn('L', index);
392 }
393
394 /**
395 * Emit a boxing call.
396 *
397 * @param type primitive type class to box.
398 */
399 private void emitBoxing(Class<?> type) {
400 Wrapper wrapper = Wrapper.forPrimitiveType(type);
401 String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
402 String name = "valueOf";
403 String desc = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
404 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
405 }
406
407 /**
408 * Emit an unboxing call (plus preceding checkcast).
409 *
410 * @param type wrapper type class to unbox.
411 */
412 private void emitUnboxing(Class<?> type) {
413 Wrapper wrapper = Wrapper.forWrapperType(type);
414 String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
415 String name = wrapper.primitiveSimpleName() + "Value";
416 String desc = "()" + wrapper.basicTypeChar();
417 mv.visitTypeInsn(Opcodes.CHECKCAST, owner);
418 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
419 }
420
421 /**
422 * Emit an implicit conversion.
423 *
424 * @param ptype type of value present on stack
425 * @param pclass type of value required on stack
426 */
427 private void emitImplicitConversion(char ptype, Class<?> pclass) {
428 switch (ptype) {
429 case 'L':
430 if (VerifyType.isNullConversion(Object.class, pclass))
431 return;
432 if (isStaticallyNameable(pclass)) {
433 mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
434 } else {
435 mv.visitLdcInsn(constantPlaceholder(pclass));
436 mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
437 mv.visitInsn(Opcodes.SWAP);
438 mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false);
439 if (pclass.isArray())
440 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
441 }
442 return;
443 case 'I':
444 if (!VerifyType.isNullConversion(int.class, pclass))
445 emitPrimCast(ptype, Wrapper.basicTypeChar(pclass));
446 return;
447 case 'J':
448 assert(pclass == long.class);
449 return;
450 case 'F':
451 assert(pclass == float.class);
452 return;
453 case 'D':
454 assert(pclass == double.class);
455 return;
456 }
457 throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
458 }
459
460 /**
461 * Emits an actual return instruction conforming to the given return type.
462 */
463 private void emitReturnInsn(Class<?> type) {
464 int opcode;
465 switch (Wrapper.basicTypeChar(type)) {
466 case 'I': opcode = Opcodes.IRETURN; break;
467 case 'J': opcode = Opcodes.LRETURN; break;
468 case 'F': opcode = Opcodes.FRETURN; break;
469 case 'D': opcode = Opcodes.DRETURN; break;
470 case 'L': opcode = Opcodes.ARETURN; break;
471 case 'V': opcode = Opcodes.RETURN; break;
472 default:
473 throw new InternalError("unknown return type: " + type);
474 }
475 mv.visitInsn(opcode);
476 }
477
478 private static String getInternalName(Class<?> c) {
479 assert(VerifyAccess.isTypeVisible(c, Object.class));
480 return c.getName().replace('.', '/');
481 }
482
483 /**
484 * Generate customized bytecode for a given LambdaForm.
485 */
486 static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
487 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
488 return g.loadMethod(g.generateCustomizedCodeBytes());
489 }
490
491 /**
513 emitSelectAlternative(name, lambdaForm.names[i + 1]);
514 i++; // skip MH.invokeBasic of the selectAlternative result
515 } else if (isGuardWithCatch(i)) {
516 emitGuardWithCatch(i);
517 i = i+2; // Jump to the end of GWC idiom
518 } else if (isStaticallyInvocable(member)) {
519 emitStaticInvoke(member, name);
520 } else {
521 emitInvoke(name);
522 }
523
524 // Update cached form name's info in case an intrinsic spanning multiple names was encountered.
525 name = lambdaForm.names[i];
526 member = name.function.member();
527
528 // store the result from evaluating to the target name in a local if required
529 // (if this is the last value, i.e., the one that is going to be returned,
530 // avoid store/load/return and just return)
531 if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
532 // return value - do nothing
533 } else if (name.type != 'V') {
534 // non-void: actually assign
535 emitStoreInsn(name.type, name.index());
536 }
537 }
538
539 // return statement
540 emitReturn();
541
542 classFileEpilogue();
543 bogusMethod(lambdaForm);
544
545 final byte[] classFile = cw.toByteArray();
546 maybeDump(className, classFile);
547 return classFile;
548 }
549
550 /**
551 * Emit an invoke for the given name.
552 */
553 void emitInvoke(Name name) {
847 mv.visitInsn(Opcodes.SWAP);
848 emitPushArguments(args, 1); // skip 1st argument: method handle
849 MethodType catcherType = type.insertParameterTypes(0, Throwable.class);
850 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", catcherType.basicType().toMethodDescriptorString(), false);
851 mv.visitJumpInsn(Opcodes.GOTO, L_done);
852
853 mv.visitLabel(L_rethrow);
854 mv.visitInsn(Opcodes.ATHROW);
855
856 mv.visitLabel(L_done);
857 }
858
859 private void emitPushArguments(Name args, int start) {
860 for (int i = start; i < args.arguments.length; i++) {
861 emitPushArgument(args, i);
862 }
863 }
864
865 private void emitPushArgument(Name name, int paramIndex) {
866 Object arg = name.arguments[paramIndex];
867 char ptype = name.function.parameterType(paramIndex);
868 MethodType mtype = name.function.methodType();
869 if (arg instanceof Name) {
870 Name n = (Name) arg;
871 emitLoadInsn(n.type, n.index());
872 emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
873 } else if ((arg == null || arg instanceof String) && ptype == 'L') {
874 emitConst(arg);
875 } else {
876 if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
877 emitConst(arg);
878 } else {
879 mv.visitLdcInsn(constantPlaceholder(arg));
880 emitImplicitConversion('L', mtype.parameterType(paramIndex));
881 }
882 }
883 }
884
885 /**
886 * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
887 */
888 private void emitReturn() {
889 // return statement
890 if (lambdaForm.result == -1) {
891 // void
892 mv.visitInsn(Opcodes.RETURN);
893 } else {
894 LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
895 char rtype = Wrapper.basicTypeChar(invokerType.returnType());
896
897 // put return value on the stack if it is not already there
898 if (lambdaForm.result != lambdaForm.names.length - 1) {
899 emitLoadInsn(rn.type, lambdaForm.result);
900 }
901
902 // potentially generate cast
903 // rtype is the return type of the invoker - generated code must conform to this
904 // rn.type is the type of the result Name in the LF
905 if (rtype != rn.type) {
906 // need cast
907 if (rtype == 'L') {
908 // possibly cast the primitive to the correct type for boxing
909 char boxedType = Wrapper.forWrapperType(invokerType.returnType()).basicTypeChar();
910 if (boxedType != rn.type) {
911 emitPrimCast(rn.type, boxedType);
912 }
913 // cast primitive to reference ("boxing")
914 emitBoxing(invokerType.returnType());
915 } else {
916 // to-primitive cast
917 if (rn.type != 'L') {
918 // prim-to-prim cast
919 emitPrimCast(rn.type, rtype);
920 } else {
921 // ref-to-prim cast ("unboxing")
922 throw new InternalError("no ref-to-prim (unboxing) casts supported right now");
923 }
924 }
925 }
926
927 // generate actual return statement
928 emitReturnInsn(invokerType.returnType());
929 }
930 }
931
932 /**
933 * Emit a type conversion bytecode casting from "from" to "to".
934 */
935 private void emitPrimCast(char from, char to) {
936 // Here's how.
937 // - indicates forbidden
938 // <-> indicates implicit
939 // to ----> boolean byte short char int long float double
940 // from boolean <-> - - - - - - -
941 // byte - <-> i2s i2c <-> i2l i2f i2d
942 // short - i2b <-> i2c <-> i2l i2f i2d
943 // char - i2b i2s <-> <-> i2l i2f i2d
944 // int - i2b i2s i2c <-> i2l i2f i2d
945 // long - l2i,i2b l2i,i2s l2i,i2c l2i <-> l2f l2d
946 // float - f2i,i2b f2i,i2s f2i,i2c f2i f2l <-> f2d
947 // double - d2i,i2b d2i,i2s d2i,i2c d2i d2l d2f <->
948 if (from == to) {
949 // no cast required, should be dead code anyway
950 return;
951 }
952 Wrapper wfrom = Wrapper.forBasicType(from);
953 Wrapper wto = Wrapper.forBasicType(to);
954 if (wfrom.isSubwordOrInt()) {
955 // cast from {byte,short,char,int} to anything
956 emitI2X(to);
957 } else {
958 // cast from {long,float,double} to anything
959 if (wto.isSubwordOrInt()) {
960 // cast to {byte,short,char,int}
961 emitX2I(from);
962 if (wto.bitWidth() < 32) {
963 // targets other than int require another conversion
964 emitI2X(to);
965 }
966 } else {
967 // cast to {long,float,double} - this is verbose
968 boolean error = false;
969 switch (from) {
970 case 'J':
971 if (to == 'F') { mv.visitInsn(Opcodes.L2F); }
972 else if (to == 'D') { mv.visitInsn(Opcodes.L2D); }
973 else error = true;
974 break;
975 case 'F':
976 if (to == 'J') { mv.visitInsn(Opcodes.F2L); }
977 else if (to == 'D') { mv.visitInsn(Opcodes.F2D); }
978 else error = true;
979 break;
980 case 'D':
981 if (to == 'J') { mv.visitInsn(Opcodes.D2L); }
982 else if (to == 'F') { mv.visitInsn(Opcodes.D2F); }
983 else error = true;
984 break;
985 default:
986 error = true;
987 break;
988 }
989 if (error) {
990 throw new IllegalStateException("unhandled prim cast: " + from + "2" + to);
991 }
992 }
993 }
994 }
995
996 private void emitI2X(char type) {
997 switch (type) {
998 case 'B': mv.visitInsn(Opcodes.I2B); break;
999 case 'S': mv.visitInsn(Opcodes.I2S); break;
1000 case 'C': mv.visitInsn(Opcodes.I2C); break;
1001 case 'I': /* naught */ break;
1002 case 'J': mv.visitInsn(Opcodes.I2L); break;
1003 case 'F': mv.visitInsn(Opcodes.I2F); break;
1004 case 'D': mv.visitInsn(Opcodes.I2D); break;
1005 case 'Z':
1006 // For compatibility with ValueConversions and explicitCastArguments:
1007 mv.visitInsn(Opcodes.ICONST_1);
1008 mv.visitInsn(Opcodes.IAND);
1009 break;
1010 default: throw new InternalError("unknown type: " + type);
1011 }
1012 }
1013
1014 private void emitX2I(char type) {
1015 switch (type) {
1016 case 'J': mv.visitInsn(Opcodes.L2I); break;
1017 case 'F': mv.visitInsn(Opcodes.F2I); break;
1018 case 'D': mv.visitInsn(Opcodes.D2I); break;
1019 default: throw new InternalError("unknown type: " + type);
1020 }
1021 }
1022
1023 private static String basicTypeCharSignature(String prefix, MethodType type) {
1024 StringBuilder buf = new StringBuilder(prefix);
1025 for (Class<?> ptype : type.parameterList())
1026 buf.append(Wrapper.forBasicType(ptype).basicTypeChar());
1027 buf.append('_').append(Wrapper.forBasicType(type.returnType()).basicTypeChar());
1028 return buf.toString();
1029 }
1030
1031 /**
1032 * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
1033 */
1034 static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
1035 assert(LambdaForm.isValidSignature(sig));
1036 //System.out.println("generateExactInvoker "+sig);
1037 // compute method type
1038 // first parameter and return type
1039 char tret = LambdaForm.signatureReturn(sig);
1040 MethodType type = MethodType.methodType(LambdaForm.typeClass(tret), MethodHandle.class);
1041 // other parameter types
1042 int arity = LambdaForm.signatureArity(sig);
1043 for (int i = 1; i < arity; i++) {
1044 type = type.appendParameterTypes(LambdaForm.typeClass(sig.charAt(i)));
1045 }
1046 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", "interpret_"+tret, type);
1047 return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
1048 }
1049
1050 private byte[] generateLambdaFormInterpreterEntryPointBytes() {
1051 classFilePrologue();
1052
1053 // Suppress this method in backtraces displayed to the user.
1054 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
1055
1056 // Don't inline the interpreter entry.
1057 mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
1058
1059 // create parameter array
1060 emitIconstInsn(invokerType.parameterCount());
1061 mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
1062
1063 // fill parameter array
1064 for (int i = 0; i < invokerType.parameterCount(); i++) {
1065 Class<?> ptype = invokerType.parameterType(i);
1066 mv.visitInsn(Opcodes.DUP);
1067 emitIconstInsn(i);
1068 emitLoadInsn(Wrapper.basicTypeChar(ptype), i);
1069 // box if primitive type
1070 if (ptype.isPrimitive()) {
1071 emitBoxing(ptype);
1072 }
1073 mv.visitInsn(Opcodes.AASTORE);
1074 }
1075 // invoke
1076 emitAloadInsn(0);
1077 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
1078 mv.visitInsn(Opcodes.SWAP); // swap form and array; avoid local variable
1079 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
1080
1081 // maybe unbox
1082 Class<?> rtype = invokerType.returnType();
1083 if (rtype.isPrimitive() && rtype != void.class) {
1084 emitUnboxing(Wrapper.asWrapperType(rtype));
1085 }
1086
1087 // return statement
1088 emitReturnInsn(rtype);
1089
1090 classFileEpilogue();
1091 bogusMethod(invokerType);
1092
1093 final byte[] classFile = cw.toByteArray();
1094 maybeDump(className, classFile);
1095 return classFile;
1096 }
1097
1098 /**
1099 * Generate bytecode for a NamedFunction invoker.
1100 */
1101 static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
1102 MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
1103 String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType());
1104 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
1105 return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
1106 }
1107
1108 static int nfi = 0;
1109
1110 private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
1111 MethodType dstType = typeForm.erasedType();
1112 classFilePrologue();
1113
1114 // Suppress this method in backtraces displayed to the user.
1115 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
1116
1117 // Force inlining of this invoker method.
1118 mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
1119
1120 // Load receiver
1121 emitAloadInsn(0);
1122
1123 // Load arguments from array
1124 for (int i = 0; i < dstType.parameterCount(); i++) {
1125 emitAloadInsn(1);
1126 emitIconstInsn(i);
1127 mv.visitInsn(Opcodes.AALOAD);
1128
1129 // Maybe unbox
1130 Class<?> dptype = dstType.parameterType(i);
1131 if (dptype.isPrimitive()) {
1132 Class<?> sptype = dstType.basicType().wrap().parameterType(i);
1133 Wrapper dstWrapper = Wrapper.forBasicType(dptype);
1134 Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper; // narrow subword from int
1135 emitUnboxing(srcWrapper.wrapperType());
1136 emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
1137 }
1138 }
1139
1140 // Invoke
1141 String targetDesc = dstType.basicType().toMethodDescriptorString();
1142 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc, false);
1143
1144 // Box primitive types
1145 Class<?> rtype = dstType.returnType();
1146 if (rtype != void.class && rtype.isPrimitive()) {
1147 Wrapper srcWrapper = Wrapper.forBasicType(rtype);
1148 Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
1149 // boolean casts not allowed
1150 emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
1151 emitBoxing(dstWrapper.primitiveType());
1152 }
1153
1154 // If the return type is void we return a null reference.
1155 if (rtype == void.class) {
1156 mv.visitInsn(Opcodes.ACONST_NULL);
1157 }
1158 emitReturnInsn(Object.class); // NOTE: NamedFunction invokers always return a reference value.
1159
1160 classFileEpilogue();
1161 bogusMethod(dstType);
1162
1163 final byte[] classFile = cw.toByteArray();
1164 maybeDump(className, classFile);
1165 return classFile;
1166 }
1167
1168 /**
1169 * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
1170 * for debugging purposes.
1171 */
1172 private void bogusMethod(Object... os) {
1173 if (DUMP_CLASS_FILES) {
1174 mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
1175 for (Object o : os) {
1176 mv.visitLdcInsn(o.toString());
1177 mv.visitInsn(Opcodes.POP);
1178 }
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import sun.invoke.util.VerifyAccess;
29 import static java.lang.invoke.LambdaForm.*;
30
31 import sun.invoke.util.Wrapper;
32
33 import java.io.*;
34 import java.util.*;
35
36 import jdk.internal.org.objectweb.asm.*;
37
38 import java.lang.reflect.*;
39 import static java.lang.invoke.MethodHandleStatics.*;
40 import static java.lang.invoke.MethodHandleNatives.Constants.*;
41 import static java.lang.invoke.LambdaForm.BasicType.*;
42 import sun.invoke.util.VerifyType;
43
44 /**
45 * Code generation backend for LambdaForm.
46 * <p>
47 * @author John Rose, JSR 292 EG
48 */
49 class InvokerBytecodeGenerator {
50 /** Define class names for convenience. */
51 private static final String MH = "java/lang/invoke/MethodHandle";
52 private static final String MHI = "java/lang/invoke/MethodHandleImpl";
53 private static final String LF = "java/lang/invoke/LambdaForm";
54 private static final String LFN = "java/lang/invoke/LambdaForm$Name";
55 private static final String CLS = "java/lang/Class";
56 private static final String OBJ = "java/lang/Object";
57 private static final String OBJARY = "[Ljava/lang/Object;";
58
59 private static final String LF_SIG = "L" + LF + ";";
60 private static final String LFN_SIG = "L" + LFN + ";";
61 private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";";
99 this.invokerType = invokerType;
100 this.localsMap = new int[localsMapSize];
101 }
102
103 private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
104 this(null, invokerType.parameterCount(),
105 className, invokerName, invokerType);
106 // Create an array to map name indexes to locals indexes.
107 for (int i = 0; i < localsMap.length; i++) {
108 localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
109 }
110 }
111
112 private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
113 this(form, form.names.length,
114 className, form.debugName, invokerType);
115 // Create an array to map name indexes to locals indexes.
116 Name[] names = form.names;
117 for (int i = 0, index = 0; i < localsMap.length; i++) {
118 localsMap[i] = index;
119 index += names[i].type.basicTypeSlots();
120 }
121 }
122
123
124 /** instance counters for dumped classes */
125 private final static HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
126 /** debugging flag for saving generated class files */
127 private final static File DUMP_CLASS_FILES_DIR;
128
129 static {
130 if (DUMP_CLASS_FILES) {
131 DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
132 try {
133 File dumpDir = new File("DUMP_CLASS_FILES");
134 if (!dumpDir.exists()) {
135 dumpDir.mkdirs();
136 }
137 DUMP_CLASS_FILES_DIR = dumpDir;
138 System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/...");
139 } catch (Exception e) {
341 case 2: opcode = Opcodes.ICONST_2; break;
342 case 3: opcode = Opcodes.ICONST_3; break;
343 case 4: opcode = Opcodes.ICONST_4; break;
344 case 5: opcode = Opcodes.ICONST_5; break;
345 default:
346 if (i == (byte) i) {
347 mv.visitIntInsn(Opcodes.BIPUSH, i & 0xFF);
348 } else if (i == (short) i) {
349 mv.visitIntInsn(Opcodes.SIPUSH, (char) i);
350 } else {
351 mv.visitLdcInsn(i);
352 }
353 return;
354 }
355 mv.visitInsn(opcode);
356 }
357
358 /*
359 * NOTE: These load/store methods use the localsMap to find the correct index!
360 */
361 private void emitLoadInsn(BasicType type, int index) {
362 int opcode = loadInsnOpcode(type);
363 mv.visitVarInsn(opcode, localsMap[index]);
364 }
365
366 private int loadInsnOpcode(BasicType type) throws InternalError {
367 switch (type) {
368 case I_TYPE: return Opcodes.ILOAD;
369 case J_TYPE: return Opcodes.LLOAD;
370 case F_TYPE: return Opcodes.FLOAD;
371 case D_TYPE: return Opcodes.DLOAD;
372 case L_TYPE: return Opcodes.ALOAD;
373 default:
374 throw new InternalError("unknown type: " + type);
375 }
376 }
377 private void emitAloadInsn(int index) {
378 emitLoadInsn(L_TYPE, index);
379 }
380
381 private void emitStoreInsn(BasicType type, int index) {
382 int opcode = storeInsnOpcode(type);
383 mv.visitVarInsn(opcode, localsMap[index]);
384 }
385
386 private int storeInsnOpcode(BasicType type) throws InternalError {
387 switch (type) {
388 case I_TYPE: return Opcodes.ISTORE;
389 case J_TYPE: return Opcodes.LSTORE;
390 case F_TYPE: return Opcodes.FSTORE;
391 case D_TYPE: return Opcodes.DSTORE;
392 case L_TYPE: return Opcodes.ASTORE;
393 default:
394 throw new InternalError("unknown type: " + type);
395 }
396 }
397 private void emitAstoreInsn(int index) {
398 emitStoreInsn(L_TYPE, index);
399 }
400
401 /**
402 * Emit a boxing call.
403 *
404 * @param wrapper primitive type class to box.
405 */
406 private void emitBoxing(Wrapper wrapper) {
407 String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
408 String name = "valueOf";
409 String desc = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
410 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
411 }
412
413 /**
414 * Emit an unboxing call (plus preceding checkcast).
415 *
416 * @param wrapper wrapper type class to unbox.
417 */
418 private void emitUnboxing(Wrapper wrapper) {
419 String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
420 String name = wrapper.primitiveSimpleName() + "Value";
421 String desc = "()" + wrapper.basicTypeChar();
422 mv.visitTypeInsn(Opcodes.CHECKCAST, owner);
423 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
424 }
425
426 /**
427 * Emit an implicit conversion.
428 *
429 * @param ptype type of value present on stack
430 * @param pclass type of value required on stack
431 */
432 private void emitImplicitConversion(BasicType ptype, Class<?> pclass) {
433 assert(basicType(pclass) == ptype); // boxing/unboxing handled by caller
434 if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
435 return; // nothing to do
436 switch (ptype) {
437 case L_TYPE:
438 if (VerifyType.isNullConversion(Object.class, pclass))
439 return;
440 if (isStaticallyNameable(pclass)) {
441 mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
442 } else {
443 mv.visitLdcInsn(constantPlaceholder(pclass));
444 mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
445 mv.visitInsn(Opcodes.SWAP);
446 mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false);
447 if (pclass.isArray())
448 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
449 }
450 return;
451 case I_TYPE:
452 if (!VerifyType.isNullConversion(int.class, pclass))
453 emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
454 return;
455 }
456 throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
457 }
458
459 /**
460 * Emits an actual return instruction conforming to the given return type.
461 */
462 private void emitReturnInsn(BasicType type) {
463 int opcode;
464 switch (type) {
465 case I_TYPE: opcode = Opcodes.IRETURN; break;
466 case J_TYPE: opcode = Opcodes.LRETURN; break;
467 case F_TYPE: opcode = Opcodes.FRETURN; break;
468 case D_TYPE: opcode = Opcodes.DRETURN; break;
469 case L_TYPE: opcode = Opcodes.ARETURN; break;
470 case V_TYPE: opcode = Opcodes.RETURN; break;
471 default:
472 throw new InternalError("unknown return type: " + type);
473 }
474 mv.visitInsn(opcode);
475 }
476
477 private static String getInternalName(Class<?> c) {
478 assert(VerifyAccess.isTypeVisible(c, Object.class));
479 return c.getName().replace('.', '/');
480 }
481
482 /**
483 * Generate customized bytecode for a given LambdaForm.
484 */
485 static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
486 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
487 return g.loadMethod(g.generateCustomizedCodeBytes());
488 }
489
490 /**
512 emitSelectAlternative(name, lambdaForm.names[i + 1]);
513 i++; // skip MH.invokeBasic of the selectAlternative result
514 } else if (isGuardWithCatch(i)) {
515 emitGuardWithCatch(i);
516 i = i+2; // Jump to the end of GWC idiom
517 } else if (isStaticallyInvocable(member)) {
518 emitStaticInvoke(member, name);
519 } else {
520 emitInvoke(name);
521 }
522
523 // Update cached form name's info in case an intrinsic spanning multiple names was encountered.
524 name = lambdaForm.names[i];
525 member = name.function.member();
526
527 // store the result from evaluating to the target name in a local if required
528 // (if this is the last value, i.e., the one that is going to be returned,
529 // avoid store/load/return and just return)
530 if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
531 // return value - do nothing
532 } else if (name.type != V_TYPE) {
533 // non-void: actually assign
534 emitStoreInsn(name.type, name.index());
535 }
536 }
537
538 // return statement
539 emitReturn();
540
541 classFileEpilogue();
542 bogusMethod(lambdaForm);
543
544 final byte[] classFile = cw.toByteArray();
545 maybeDump(className, classFile);
546 return classFile;
547 }
548
549 /**
550 * Emit an invoke for the given name.
551 */
552 void emitInvoke(Name name) {
846 mv.visitInsn(Opcodes.SWAP);
847 emitPushArguments(args, 1); // skip 1st argument: method handle
848 MethodType catcherType = type.insertParameterTypes(0, Throwable.class);
849 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", catcherType.basicType().toMethodDescriptorString(), false);
850 mv.visitJumpInsn(Opcodes.GOTO, L_done);
851
852 mv.visitLabel(L_rethrow);
853 mv.visitInsn(Opcodes.ATHROW);
854
855 mv.visitLabel(L_done);
856 }
857
858 private void emitPushArguments(Name args, int start) {
859 for (int i = start; i < args.arguments.length; i++) {
860 emitPushArgument(args, i);
861 }
862 }
863
864 private void emitPushArgument(Name name, int paramIndex) {
865 Object arg = name.arguments[paramIndex];
866 Class<?> ptype = name.function.methodType().parameterType(paramIndex);
867 emitPushArgument(ptype, arg);
868 }
869
870 private void emitPushArgument(Class<?> ptype, Object arg) {
871 BasicType bptype = basicType(ptype);
872 if (arg instanceof Name) {
873 Name n = (Name) arg;
874 emitLoadInsn(n.type, n.index());
875 emitImplicitConversion(n.type, ptype);
876 } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
877 emitConst(arg);
878 } else {
879 if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
880 emitConst(arg);
881 } else {
882 mv.visitLdcInsn(constantPlaceholder(arg));
883 emitImplicitConversion(L_TYPE, ptype);
884 }
885 }
886 }
887
888 /**
889 * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
890 */
891 private void emitReturn() {
892 // return statement
893 Class<?> rclass = invokerType.returnType();
894 BasicType rtype = lambdaForm.returnType();
895 assert(rtype == basicType(rclass)); // must agree
896 if (rtype == V_TYPE) {
897 // void
898 mv.visitInsn(Opcodes.RETURN);
899 // it doesn't matter what rclass is; the JVM will discard any value
900 } else {
901 LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
902
903 // put return value on the stack if it is not already there
904 if (lambdaForm.result != lambdaForm.names.length - 1 ||
905 lambdaForm.result < lambdaForm.arity) {
906 emitLoadInsn(rn.type, lambdaForm.result);
907 }
908
909 emitImplicitConversion(rtype, rclass);
910
911 // generate actual return statement
912 emitReturnInsn(rtype);
913 }
914 }
915
916 /**
917 * Emit a type conversion bytecode casting from "from" to "to".
918 */
919 private void emitPrimCast(Wrapper from, Wrapper to) {
920 // Here's how.
921 // - indicates forbidden
922 // <-> indicates implicit
923 // to ----> boolean byte short char int long float double
924 // from boolean <-> - - - - - - -
925 // byte - <-> i2s i2c <-> i2l i2f i2d
926 // short - i2b <-> i2c <-> i2l i2f i2d
927 // char - i2b i2s <-> <-> i2l i2f i2d
928 // int - i2b i2s i2c <-> i2l i2f i2d
929 // long - l2i,i2b l2i,i2s l2i,i2c l2i <-> l2f l2d
930 // float - f2i,i2b f2i,i2s f2i,i2c f2i f2l <-> f2d
931 // double - d2i,i2b d2i,i2s d2i,i2c d2i d2l d2f <->
932 if (from == to) {
933 // no cast required, should be dead code anyway
934 return;
935 }
936 if (from.isSubwordOrInt()) {
937 // cast from {byte,short,char,int} to anything
938 emitI2X(to);
939 } else {
940 // cast from {long,float,double} to anything
941 if (to.isSubwordOrInt()) {
942 // cast to {byte,short,char,int}
943 emitX2I(from);
944 if (to.bitWidth() < 32) {
945 // targets other than int require another conversion
946 emitI2X(to);
947 }
948 } else {
949 // cast to {long,float,double} - this is verbose
950 boolean error = false;
951 switch (from) {
952 case LONG:
953 switch (to) {
954 case FLOAT: mv.visitInsn(Opcodes.L2F); break;
955 case DOUBLE: mv.visitInsn(Opcodes.L2D); break;
956 default: error = true; break;
957 }
958 break;
959 case FLOAT:
960 switch (to) {
961 case LONG : mv.visitInsn(Opcodes.F2L); break;
962 case DOUBLE: mv.visitInsn(Opcodes.F2D); break;
963 default: error = true; break;
964 }
965 break;
966 case DOUBLE:
967 switch (to) {
968 case LONG : mv.visitInsn(Opcodes.D2L); break;
969 case FLOAT: mv.visitInsn(Opcodes.D2F); break;
970 default: error = true; break;
971 }
972 break;
973 default:
974 error = true;
975 break;
976 }
977 if (error) {
978 throw new IllegalStateException("unhandled prim cast: " + from + "2" + to);
979 }
980 }
981 }
982 }
983
984 private void emitI2X(Wrapper type) {
985 switch (type) {
986 case BYTE: mv.visitInsn(Opcodes.I2B); break;
987 case SHORT: mv.visitInsn(Opcodes.I2S); break;
988 case CHAR: mv.visitInsn(Opcodes.I2C); break;
989 case INT: /* naught */ break;
990 case LONG: mv.visitInsn(Opcodes.I2L); break;
991 case FLOAT: mv.visitInsn(Opcodes.I2F); break;
992 case DOUBLE: mv.visitInsn(Opcodes.I2D); break;
993 case BOOLEAN:
994 // For compatibility with ValueConversions and explicitCastArguments:
995 mv.visitInsn(Opcodes.ICONST_1);
996 mv.visitInsn(Opcodes.IAND);
997 break;
998 default: throw new InternalError("unknown type: " + type);
999 }
1000 }
1001
1002 private void emitX2I(Wrapper type) {
1003 switch (type) {
1004 case LONG: mv.visitInsn(Opcodes.L2I); break;
1005 case FLOAT: mv.visitInsn(Opcodes.F2I); break;
1006 case DOUBLE: mv.visitInsn(Opcodes.D2I); break;
1007 default: throw new InternalError("unknown type: " + type);
1008 }
1009 }
1010
1011 /**
1012 * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
1013 */
1014 static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
1015 assert(isValidSignature(sig));
1016 String name = "interpret_"+signatureReturn(sig).basicTypeChar();
1017 MethodType type = signatureType(sig); // sig includes leading argument
1018 type = type.changeParameterType(0, MethodHandle.class);
1019 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", name, type);
1020 return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
1021 }
1022
1023 private byte[] generateLambdaFormInterpreterEntryPointBytes() {
1024 classFilePrologue();
1025
1026 // Suppress this method in backtraces displayed to the user.
1027 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
1028
1029 // Don't inline the interpreter entry.
1030 mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
1031
1032 // create parameter array
1033 emitIconstInsn(invokerType.parameterCount());
1034 mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
1035
1036 // fill parameter array
1037 for (int i = 0; i < invokerType.parameterCount(); i++) {
1038 Class<?> ptype = invokerType.parameterType(i);
1039 mv.visitInsn(Opcodes.DUP);
1040 emitIconstInsn(i);
1041 emitLoadInsn(basicType(ptype), i);
1042 // box if primitive type
1043 if (ptype.isPrimitive()) {
1044 emitBoxing(Wrapper.forPrimitiveType(ptype));
1045 }
1046 mv.visitInsn(Opcodes.AASTORE);
1047 }
1048 // invoke
1049 emitAloadInsn(0);
1050 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
1051 mv.visitInsn(Opcodes.SWAP); // swap form and array; avoid local variable
1052 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
1053
1054 // maybe unbox
1055 Class<?> rtype = invokerType.returnType();
1056 if (rtype.isPrimitive() && rtype != void.class) {
1057 emitUnboxing(Wrapper.forPrimitiveType(rtype));
1058 }
1059
1060 // return statement
1061 emitReturnInsn(basicType(rtype));
1062
1063 classFileEpilogue();
1064 bogusMethod(invokerType);
1065
1066 final byte[] classFile = cw.toByteArray();
1067 maybeDump(className, classFile);
1068 return classFile;
1069 }
1070
1071 /**
1072 * Generate bytecode for a NamedFunction invoker.
1073 */
1074 static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
1075 MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
1076 String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
1077 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
1078 return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
1079 }
1080
1081 private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
1082 MethodType dstType = typeForm.erasedType();
1083 classFilePrologue();
1084
1085 // Suppress this method in backtraces displayed to the user.
1086 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
1087
1088 // Force inlining of this invoker method.
1089 mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
1090
1091 // Load receiver
1092 emitAloadInsn(0);
1093
1094 // Load arguments from array
1095 for (int i = 0; i < dstType.parameterCount(); i++) {
1096 emitAloadInsn(1);
1097 emitIconstInsn(i);
1098 mv.visitInsn(Opcodes.AALOAD);
1099
1100 // Maybe unbox
1101 Class<?> dptype = dstType.parameterType(i);
1102 if (dptype.isPrimitive()) {
1103 Class<?> sptype = dstType.basicType().wrap().parameterType(i);
1104 Wrapper dstWrapper = Wrapper.forBasicType(dptype);
1105 Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper; // narrow subword from int
1106 emitUnboxing(srcWrapper);
1107 emitPrimCast(srcWrapper, dstWrapper);
1108 }
1109 }
1110
1111 // Invoke
1112 String targetDesc = dstType.basicType().toMethodDescriptorString();
1113 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc, false);
1114
1115 // Box primitive types
1116 Class<?> rtype = dstType.returnType();
1117 if (rtype != void.class && rtype.isPrimitive()) {
1118 Wrapper srcWrapper = Wrapper.forBasicType(rtype);
1119 Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
1120 // boolean casts not allowed
1121 emitPrimCast(srcWrapper, dstWrapper);
1122 emitBoxing(dstWrapper);
1123 }
1124
1125 // If the return type is void we return a null reference.
1126 if (rtype == void.class) {
1127 mv.visitInsn(Opcodes.ACONST_NULL);
1128 }
1129 emitReturnInsn(L_TYPE); // NOTE: NamedFunction invokers always return a reference value.
1130
1131 classFileEpilogue();
1132 bogusMethod(dstType);
1133
1134 final byte[] classFile = cw.toByteArray();
1135 maybeDump(className, classFile);
1136 return classFile;
1137 }
1138
1139 /**
1140 * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
1141 * for debugging purposes.
1142 */
1143 private void bogusMethod(Object... os) {
1144 if (DUMP_CLASS_FILES) {
1145 mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
1146 for (Object o : os) {
1147 mv.visitLdcInsn(o.toString());
1148 mv.visitInsn(Opcodes.POP);
1149 }
|