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 java.io.*;
29 import java.util.*;
30 import java.lang.reflect.Modifier;
31
32 import jdk.internal.org.objectweb.asm.*;
33
34 import static java.lang.invoke.LambdaForm.*;
35 import static java.lang.invoke.LambdaForm.BasicType.*;
36 import static java.lang.invoke.MethodHandleStatics.*;
37 import static java.lang.invoke.MethodHandleNatives.Constants.*;
38 import sun.invoke.util.ValueConversions;
39 import sun.invoke.util.VerifyAccess;
40 import sun.invoke.util.VerifyType;
41 import sun.invoke.util.Wrapper;
42 import sun.reflect.misc.ReflectUtil;
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;";
410 private void emitStoreInsn(BasicType type, int index) {
411 int opcode = storeInsnOpcode(type);
412 mv.visitVarInsn(opcode, localsMap[index]);
413 }
414
415 private int storeInsnOpcode(BasicType type) throws InternalError {
416 switch (type) {
417 case I_TYPE: return Opcodes.ISTORE;
418 case J_TYPE: return Opcodes.LSTORE;
419 case F_TYPE: return Opcodes.FSTORE;
420 case D_TYPE: return Opcodes.DSTORE;
421 case L_TYPE: return Opcodes.ASTORE;
422 default:
423 throw new InternalError("unknown type: " + type);
424 }
425 }
426 private void emitAstoreInsn(int index) {
427 emitStoreInsn(L_TYPE, index);
428 }
429
430 private void freeFrameLocal(int oldFrameLocal) {
431 int i = indexForFrameLocal(oldFrameLocal);
432 if (i < 0) return;
433 BasicType type = localTypes[i];
434 int newFrameLocal = makeLocalTemp(type);
435 mv.visitVarInsn(loadInsnOpcode(type), oldFrameLocal);
436 mv.visitVarInsn(storeInsnOpcode(type), newFrameLocal);
437 assert(localsMap[i] == oldFrameLocal);
438 localsMap[i] = newFrameLocal;
439 assert(indexForFrameLocal(oldFrameLocal) < 0);
440 }
441 private int indexForFrameLocal(int frameLocal) {
442 for (int i = 0; i < localsMap.length; i++) {
443 if (localsMap[i] == frameLocal && localTypes[i] != V_TYPE)
444 return i;
445 }
446 return -1;
447 }
448 private int makeLocalTemp(BasicType type) {
449 int frameLocal = localsMap[localsMap.length - 1];
599
600 // iterate over the form's names, generating bytecode instructions for each
601 // start iterating at the first name following the arguments
602 Name onStack = null;
603 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
604 Name name = lambdaForm.names[i];
605 MemberName member = name.function.member();
606 Class<?> rtype = name.function.methodType().returnType();
607
608 emitStoreResult(onStack);
609 onStack = name; // unless otherwise modified below
610
611 if (isSelectAlternative(i)) {
612 onStack = emitSelectAlternative(name, lambdaForm.names[i + 1]);
613 i++; // skip MH.invokeBasic of the selectAlternative result
614 } else if (isGuardWithCatch(i)) {
615 onStack = emitGuardWithCatch(i);
616 i = i+2; // Jump to the end of GWC idiom
617 } else if (isNewArray(rtype, name)) {
618 emitNewArray(rtype, name);
619 } else if (isStaticallyInvocable(member)) {
620 emitStaticInvoke(name);
621 } else {
622 emitInvoke(name);
623 }
624 }
625
626 // return statement
627 emitReturn(onStack);
628
629 classFileEpilogue();
630 bogusMethod(lambdaForm);
631
632 final byte[] classFile = cw.toByteArray();
633 maybeDump(className, classFile);
634 return classFile;
635 }
636
637 /**
638 * Emit an invoke for the given name.
639 */
640 void emitInvoke(Name name) {
641 assert(!isLinkerMethodInvoke(name)); // should use the static path for these
642 if (true) {
643 // push receiver
644 MethodHandle target = name.function.resolvedHandle;
645 assert(target != null) : name.exprString();
646 mv.visitLdcInsn(constantPlaceholder(target));
647 emitReferenceCast(MethodHandle.class, target);
648 } else {
649 // load receiver
650 emitAloadInsn(0);
651 emitReferenceCast(MethodHandle.class, null);
652 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
653 mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
654 // TODO more to come
655 }
656
824 }
825
826 static boolean isArrayBuilder(MethodHandle fn) {
827 if (fn == null)
828 return false;
829 MethodType mtype = fn.type();
830 Class<?> rtype = mtype.returnType();
831 Class<?> arrayElementType = rtype.getComponentType();
832 if (arrayElementType == null)
833 return false;
834 List<Class<?>> ptypes = mtype.parameterList();
835 int size = ptypes.size();
836 if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
837 return false;
838 // Assume varargsArray caches pointers.
839 if (fn != ValueConversions.varargsArray(rtype, size))
840 return false;
841 return true;
842 }
843
844 /**
845 * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
846 */
847 private boolean memberRefersTo(MemberName member, Class<?> declaringClass, String name) {
848 return member != null &&
849 member.getDeclaringClass() == declaringClass &&
850 member.getName().equals(name);
851 }
852 private boolean nameRefersTo(Name name, Class<?> declaringClass, String methodName) {
853 return name.function != null &&
854 memberRefersTo(name.function.member(), declaringClass, methodName);
855 }
856
857 /**
858 * Check if MemberName is a call to MethodHandle.invokeBasic.
859 */
860 private boolean isInvokeBasic(Name name) {
861 if (name.function == null)
862 return false;
863 if (name.arguments.length < 1)
|
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 java.io.*;
29 import java.util.*;
30 import java.lang.reflect.Modifier;
31
32 import jdk.internal.org.objectweb.asm.*;
33
34 import static java.lang.invoke.LambdaForm.*;
35 import static java.lang.invoke.LambdaForm.BasicType.*;
36 import static java.lang.invoke.MethodHandleStatics.*;
37 import static java.lang.invoke.MethodHandleNatives.Constants.*;
38 import java.lang.invoke.MethodHandleImpl.ArrayAccessor;
39 import sun.invoke.util.ValueConversions;
40 import sun.invoke.util.VerifyAccess;
41 import sun.invoke.util.VerifyType;
42 import sun.invoke.util.Wrapper;
43 import sun.reflect.misc.ReflectUtil;
44
45 /**
46 * Code generation backend for LambdaForm.
47 * <p>
48 * @author John Rose, JSR 292 EG
49 */
50 class InvokerBytecodeGenerator {
51 /** Define class names for convenience. */
52 private static final String MH = "java/lang/invoke/MethodHandle";
53 private static final String MHI = "java/lang/invoke/MethodHandleImpl";
54 private static final String LF = "java/lang/invoke/LambdaForm";
55 private static final String LFN = "java/lang/invoke/LambdaForm$Name";
56 private static final String CLS = "java/lang/Class";
57 private static final String OBJ = "java/lang/Object";
58 private static final String OBJARY = "[Ljava/lang/Object;";
411 private void emitStoreInsn(BasicType type, int index) {
412 int opcode = storeInsnOpcode(type);
413 mv.visitVarInsn(opcode, localsMap[index]);
414 }
415
416 private int storeInsnOpcode(BasicType type) throws InternalError {
417 switch (type) {
418 case I_TYPE: return Opcodes.ISTORE;
419 case J_TYPE: return Opcodes.LSTORE;
420 case F_TYPE: return Opcodes.FSTORE;
421 case D_TYPE: return Opcodes.DSTORE;
422 case L_TYPE: return Opcodes.ASTORE;
423 default:
424 throw new InternalError("unknown type: " + type);
425 }
426 }
427 private void emitAstoreInsn(int index) {
428 emitStoreInsn(L_TYPE, index);
429 }
430
431 private byte arrayTypeCode(Wrapper elementType) {
432 switch (elementType) {
433 case BOOLEAN: return Opcodes.T_BOOLEAN;
434 case BYTE: return Opcodes.T_BYTE;
435 case CHAR: return Opcodes.T_CHAR;
436 case SHORT: return Opcodes.T_SHORT;
437 case INT: return Opcodes.T_INT;
438 case LONG: return Opcodes.T_LONG;
439 case FLOAT: return Opcodes.T_FLOAT;
440 case DOUBLE: return Opcodes.T_DOUBLE;
441 case OBJECT: return 0; // in place of Opcodes.T_OBJECT
442 default: throw new InternalError();
443 }
444 }
445
446 private int arrayInsnOpcode(byte tcode, int aaop) throws InternalError {
447 assert(aaop == Opcodes.AASTORE || aaop == Opcodes.AALOAD);
448 int xas;
449 switch (tcode) {
450 case Opcodes.T_BOOLEAN: xas = Opcodes.BASTORE; break;
451 case Opcodes.T_BYTE: xas = Opcodes.BASTORE; break;
452 case Opcodes.T_CHAR: xas = Opcodes.CASTORE; break;
453 case Opcodes.T_SHORT: xas = Opcodes.SASTORE; break;
454 case Opcodes.T_INT: xas = Opcodes.IASTORE; break;
455 case Opcodes.T_LONG: xas = Opcodes.LASTORE; break;
456 case Opcodes.T_FLOAT: xas = Opcodes.FASTORE; break;
457 case Opcodes.T_DOUBLE: xas = Opcodes.DASTORE; break;
458 case 0: xas = Opcodes.AASTORE; break;
459 default: throw new InternalError();
460 }
461 return xas - Opcodes.AASTORE + aaop;
462 }
463
464
465 private void freeFrameLocal(int oldFrameLocal) {
466 int i = indexForFrameLocal(oldFrameLocal);
467 if (i < 0) return;
468 BasicType type = localTypes[i];
469 int newFrameLocal = makeLocalTemp(type);
470 mv.visitVarInsn(loadInsnOpcode(type), oldFrameLocal);
471 mv.visitVarInsn(storeInsnOpcode(type), newFrameLocal);
472 assert(localsMap[i] == oldFrameLocal);
473 localsMap[i] = newFrameLocal;
474 assert(indexForFrameLocal(oldFrameLocal) < 0);
475 }
476 private int indexForFrameLocal(int frameLocal) {
477 for (int i = 0; i < localsMap.length; i++) {
478 if (localsMap[i] == frameLocal && localTypes[i] != V_TYPE)
479 return i;
480 }
481 return -1;
482 }
483 private int makeLocalTemp(BasicType type) {
484 int frameLocal = localsMap[localsMap.length - 1];
634
635 // iterate over the form's names, generating bytecode instructions for each
636 // start iterating at the first name following the arguments
637 Name onStack = null;
638 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
639 Name name = lambdaForm.names[i];
640 MemberName member = name.function.member();
641 Class<?> rtype = name.function.methodType().returnType();
642
643 emitStoreResult(onStack);
644 onStack = name; // unless otherwise modified below
645
646 if (isSelectAlternative(i)) {
647 onStack = emitSelectAlternative(name, lambdaForm.names[i + 1]);
648 i++; // skip MH.invokeBasic of the selectAlternative result
649 } else if (isGuardWithCatch(i)) {
650 onStack = emitGuardWithCatch(i);
651 i = i+2; // Jump to the end of GWC idiom
652 } else if (isNewArray(rtype, name)) {
653 emitNewArray(rtype, name);
654 } else if (isArrayLoad(member)) {
655 emitArrayLoad(name);
656 } else if (isArrayStore(member)) {
657 emitArrayStore(name);
658 } else if (isStaticallyInvocable(member)) {
659 emitStaticInvoke(name);
660 } else {
661 emitInvoke(name);
662 }
663 }
664
665 // return statement
666 emitReturn(onStack);
667
668 classFileEpilogue();
669 bogusMethod(lambdaForm);
670
671 final byte[] classFile = cw.toByteArray();
672 maybeDump(className, classFile);
673 return classFile;
674 }
675
676 boolean isArrayLoad(MemberName member) {
677 return member != null &&
678 member.getDeclaringClass() == ArrayAccessor.class &&
679 member.getName() != null &&
680 member.getName().startsWith("getElement");
681 }
682
683 boolean isArrayStore(MemberName member) {
684 return member != null &&
685 member.getDeclaringClass() == ArrayAccessor.class &&
686 member.getName() != null &&
687 member.getName().startsWith("setElement");
688 }
689
690 void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); }
691 void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); }
692
693 void emitArrayOp(Name name, int arrayOpcode) {
694 assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE;
695 Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
696 assert elementType != null;
697 emitPushArguments(name);
698 if (elementType.isPrimitive()) {
699 Wrapper w = Wrapper.forPrimitiveType(elementType);
700 arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
701 }
702 mv.visitInsn(arrayOpcode);
703 }
704
705 /**
706 * Emit an invoke for the given name.
707 */
708 void emitInvoke(Name name) {
709 assert(!isLinkerMethodInvoke(name)); // should use the static path for these
710 if (true) {
711 // push receiver
712 MethodHandle target = name.function.resolvedHandle;
713 assert(target != null) : name.exprString();
714 mv.visitLdcInsn(constantPlaceholder(target));
715 emitReferenceCast(MethodHandle.class, target);
716 } else {
717 // load receiver
718 emitAloadInsn(0);
719 emitReferenceCast(MethodHandle.class, null);
720 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
721 mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
722 // TODO more to come
723 }
724
892 }
893
894 static boolean isArrayBuilder(MethodHandle fn) {
895 if (fn == null)
896 return false;
897 MethodType mtype = fn.type();
898 Class<?> rtype = mtype.returnType();
899 Class<?> arrayElementType = rtype.getComponentType();
900 if (arrayElementType == null)
901 return false;
902 List<Class<?>> ptypes = mtype.parameterList();
903 int size = ptypes.size();
904 if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
905 return false;
906 // Assume varargsArray caches pointers.
907 if (fn != ValueConversions.varargsArray(rtype, size))
908 return false;
909 return true;
910 }
911
912 static boolean match(MemberName member, MethodHandle fn) {
913 if (member == null || fn == null) return false;
914 return member.equals(fn.internalMemberName());
915 }
916
917 /**
918 * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
919 */
920 private boolean memberRefersTo(MemberName member, Class<?> declaringClass, String name) {
921 return member != null &&
922 member.getDeclaringClass() == declaringClass &&
923 member.getName().equals(name);
924 }
925 private boolean nameRefersTo(Name name, Class<?> declaringClass, String methodName) {
926 return name.function != null &&
927 memberRefersTo(name.function.member(), declaringClass, methodName);
928 }
929
930 /**
931 * Check if MemberName is a call to MethodHandle.invokeBasic.
932 */
933 private boolean isInvokeBasic(Name name) {
934 if (name.function == null)
935 return false;
936 if (name.arguments.length < 1)
|