733
734 void emitArrayOp(Name name, int arrayOpcode) {
735 assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE;
736 Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
737 assert elementType != null;
738 emitPushArguments(name);
739 if (elementType.isPrimitive()) {
740 Wrapper w = Wrapper.forPrimitiveType(elementType);
741 arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
742 }
743 mv.visitInsn(arrayOpcode);
744 }
745
746 /**
747 * Emit an invoke for the given name.
748 */
749 void emitInvoke(Name name) {
750 assert(!isLinkerMethodInvoke(name)); // should use the static path for these
751 if (true) {
752 // push receiver
753 MethodHandle target = name.function.resolvedHandle;
754 assert(target != null) : name.exprString();
755 mv.visitLdcInsn(constantPlaceholder(target));
756 emitReferenceCast(MethodHandle.class, target);
757 } else {
758 // load receiver
759 emitAloadInsn(0);
760 emitReferenceCast(MethodHandle.class, null);
761 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
762 mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
763 // TODO more to come
764 }
765
766 // push arguments
767 emitPushArguments(name);
768
769 // invocation
770 MethodType type = name.function.methodType();
771 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
772 }
773
774 private static Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
775 // Sample classes from each package we are willing to bind to statically:
776 java.lang.Object.class,
777 java.util.Arrays.class,
778 jdk.internal.misc.Unsafe.class
779 //MethodHandle.class already covered
780 };
781
782 static boolean isStaticallyInvocable(Name name) {
783 return isStaticallyInvocable(name.function.member());
784 }
785
786 static boolean isStaticallyInvocable(MemberName member) {
787 if (member == null) return false;
788 if (member.isConstructor()) return false;
789 Class<?> cls = member.getDeclaringClass();
790 if (cls.isArray() || cls.isPrimitive())
791 return false; // FIXME
792 if (cls.isAnonymousClass() || cls.isLocalClass())
793 return false; // inner class of some sort
794 if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
795 return false; // not on BCP
796 if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
797 return false;
798 MethodType mtype = member.getMethodOrFieldType();
799 if (!isStaticallyNameable(mtype.returnType()))
800 return false;
801 for (Class<?> ptype : mtype.parameterArray())
864 } else {
865 mtype = MethodType.toFieldDescriptorString(member.getFieldType());
866 mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
867 }
868 // Issue a type assertion for the result, so we can avoid casts later.
869 if (name.type == L_TYPE) {
870 Class<?> rtype = member.getInvocationType().returnType();
871 assert(!rtype.isPrimitive());
872 if (rtype != Object.class && !rtype.isInterface()) {
873 assertStaticType(rtype, name);
874 }
875 }
876 }
877
878 void emitNewArray(Name name) throws InternalError {
879 Class<?> rtype = name.function.methodType().returnType();
880 if (name.arguments.length == 0) {
881 // The array will be a constant.
882 Object emptyArray;
883 try {
884 emptyArray = name.function.resolvedHandle.invoke();
885 } catch (Throwable ex) {
886 throw newInternalError(ex);
887 }
888 assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
889 assert(emptyArray.getClass() == rtype); // exact typing
890 mv.visitLdcInsn(constantPlaceholder(emptyArray));
891 emitReferenceCast(rtype, emptyArray);
892 return;
893 }
894 Class<?> arrayElementType = rtype.getComponentType();
895 assert(arrayElementType != null);
896 emitIconstInsn(name.arguments.length);
897 int xas = Opcodes.AASTORE;
898 if (!arrayElementType.isPrimitive()) {
899 mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
900 } else {
901 byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
902 xas = arrayInsnOpcode(tc, xas);
903 mv.visitIntInsn(Opcodes.NEWARRAY, tc);
904 }
1068 *
1069 * It is compiled into bytecode equivalent of the following code:
1070 * <blockquote><pre>{@code
1071 * try {
1072 * return a1.invokeBasic(a6, a7);
1073 * } catch (Throwable e) {
1074 * if (!a2.isInstance(e)) throw e;
1075 * return a3.invokeBasic(ex, a6, a7);
1076 * }}
1077 */
1078 private Name emitGuardWithCatch(int pos) {
1079 Name args = lambdaForm.names[pos];
1080 Name invoker = lambdaForm.names[pos+1];
1081 Name result = lambdaForm.names[pos+2];
1082
1083 Label L_startBlock = new Label();
1084 Label L_endBlock = new Label();
1085 Label L_handler = new Label();
1086 Label L_done = new Label();
1087
1088 Class<?> returnType = result.function.resolvedHandle.type().returnType();
1089 MethodType type = args.function.resolvedHandle.type()
1090 .dropParameterTypes(0,1)
1091 .changeReturnType(returnType);
1092
1093 mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_handler, "java/lang/Throwable");
1094
1095 // Normal case
1096 mv.visitLabel(L_startBlock);
1097 // load target
1098 emitPushArgument(invoker, 0);
1099 emitPushArguments(args, 1); // skip 1st argument: method handle
1100 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
1101 mv.visitLabel(L_endBlock);
1102 mv.visitJumpInsn(Opcodes.GOTO, L_done);
1103
1104 // Exceptional case
1105 mv.visitLabel(L_handler);
1106
1107 // Check exception's type
1108 mv.visitInsn(Opcodes.DUP);
1109 // load exception class
|
733
734 void emitArrayOp(Name name, int arrayOpcode) {
735 assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE;
736 Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
737 assert elementType != null;
738 emitPushArguments(name);
739 if (elementType.isPrimitive()) {
740 Wrapper w = Wrapper.forPrimitiveType(elementType);
741 arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
742 }
743 mv.visitInsn(arrayOpcode);
744 }
745
746 /**
747 * Emit an invoke for the given name.
748 */
749 void emitInvoke(Name name) {
750 assert(!isLinkerMethodInvoke(name)); // should use the static path for these
751 if (true) {
752 // push receiver
753 MethodHandle target = name.function.resolvedHandle();
754 assert(target != null) : name.exprString();
755 mv.visitLdcInsn(constantPlaceholder(target));
756 emitReferenceCast(MethodHandle.class, target);
757 } else {
758 // load receiver
759 emitAloadInsn(0);
760 emitReferenceCast(MethodHandle.class, null);
761 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
762 mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
763 // TODO more to come
764 }
765
766 // push arguments
767 emitPushArguments(name);
768
769 // invocation
770 MethodType type = name.function.methodType();
771 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
772 }
773
774 private static Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
775 // Sample classes from each package we are willing to bind to statically:
776 java.lang.Object.class,
777 java.util.Arrays.class,
778 jdk.internal.misc.Unsafe.class
779 //MethodHandle.class already covered
780 };
781
782 static boolean isStaticallyInvocable(NamedFunction[] functions) {
783 for (NamedFunction nf : functions) {
784 if (!isStaticallyInvocable(nf.member)) {
785 return false;
786 }
787 }
788 return true;
789 }
790
791 static boolean isStaticallyInvocable(Name name) {
792 return isStaticallyInvocable(name.function.member());
793 }
794
795 static boolean isStaticallyInvocable(MemberName member) {
796 if (member == null) return false;
797 if (member.isConstructor()) return false;
798 Class<?> cls = member.getDeclaringClass();
799 if (cls.isArray() || cls.isPrimitive())
800 return false; // FIXME
801 if (cls.isAnonymousClass() || cls.isLocalClass())
802 return false; // inner class of some sort
803 if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
804 return false; // not on BCP
805 if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
806 return false;
807 MethodType mtype = member.getMethodOrFieldType();
808 if (!isStaticallyNameable(mtype.returnType()))
809 return false;
810 for (Class<?> ptype : mtype.parameterArray())
873 } else {
874 mtype = MethodType.toFieldDescriptorString(member.getFieldType());
875 mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
876 }
877 // Issue a type assertion for the result, so we can avoid casts later.
878 if (name.type == L_TYPE) {
879 Class<?> rtype = member.getInvocationType().returnType();
880 assert(!rtype.isPrimitive());
881 if (rtype != Object.class && !rtype.isInterface()) {
882 assertStaticType(rtype, name);
883 }
884 }
885 }
886
887 void emitNewArray(Name name) throws InternalError {
888 Class<?> rtype = name.function.methodType().returnType();
889 if (name.arguments.length == 0) {
890 // The array will be a constant.
891 Object emptyArray;
892 try {
893 emptyArray = name.function.resolvedHandle().invoke();
894 } catch (Throwable ex) {
895 throw newInternalError(ex);
896 }
897 assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
898 assert(emptyArray.getClass() == rtype); // exact typing
899 mv.visitLdcInsn(constantPlaceholder(emptyArray));
900 emitReferenceCast(rtype, emptyArray);
901 return;
902 }
903 Class<?> arrayElementType = rtype.getComponentType();
904 assert(arrayElementType != null);
905 emitIconstInsn(name.arguments.length);
906 int xas = Opcodes.AASTORE;
907 if (!arrayElementType.isPrimitive()) {
908 mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
909 } else {
910 byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
911 xas = arrayInsnOpcode(tc, xas);
912 mv.visitIntInsn(Opcodes.NEWARRAY, tc);
913 }
1077 *
1078 * It is compiled into bytecode equivalent of the following code:
1079 * <blockquote><pre>{@code
1080 * try {
1081 * return a1.invokeBasic(a6, a7);
1082 * } catch (Throwable e) {
1083 * if (!a2.isInstance(e)) throw e;
1084 * return a3.invokeBasic(ex, a6, a7);
1085 * }}
1086 */
1087 private Name emitGuardWithCatch(int pos) {
1088 Name args = lambdaForm.names[pos];
1089 Name invoker = lambdaForm.names[pos+1];
1090 Name result = lambdaForm.names[pos+2];
1091
1092 Label L_startBlock = new Label();
1093 Label L_endBlock = new Label();
1094 Label L_handler = new Label();
1095 Label L_done = new Label();
1096
1097 Class<?> returnType = result.function.resolvedHandle().type().returnType();
1098 MethodType type = args.function.resolvedHandle().type()
1099 .dropParameterTypes(0,1)
1100 .changeReturnType(returnType);
1101
1102 mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_handler, "java/lang/Throwable");
1103
1104 // Normal case
1105 mv.visitLabel(L_startBlock);
1106 // load target
1107 emitPushArgument(invoker, 0);
1108 emitPushArguments(args, 1); // skip 1st argument: method handle
1109 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
1110 mv.visitLabel(L_endBlock);
1111 mv.visitJumpInsn(Opcodes.GOTO, L_done);
1112
1113 // Exceptional case
1114 mv.visitLabel(L_handler);
1115
1116 // Check exception's type
1117 mv.visitInsn(Opcodes.DUP);
1118 // load exception class
|