< prev index next >

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java

Print this page
rev 13064 : 8142334: Improve lazy initialization of java.lang.invoke
Reviewed-by: psandoz, vlivanov, mhaupt


 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


< prev index next >