8 * particular file as subject to the "Classpath" exception as provided
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.reflect;
27
28 import jdk.internal.org.objectweb.asm.ClassWriter;
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.Wrapper;
34 import sun.security.action.GetBooleanAction;
35
36 import java.io.IOException;
37 import java.lang.invoke.MethodType;
38 import java.nio.file.Files;
39 import java.nio.file.Path;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.LinkedHashMap;
43 import java.util.List;
44 import java.util.ListIterator;
45 import java.util.Map;
46
47 import static jdk.internal.org.objectweb.asm.Opcodes.*;
48
49 /**
50 * ProxyGenerator contains the code to generate a dynamic proxy class
51 * for the java.lang.reflect.Proxy API.
52 * <p>
53 * The external interface to ProxyGenerator is the static
54 * "generateProxyClass" method.
55 */
56 final class ProxyGenerator extends ClassWriter {
57 private static final int CLASSFILE_VERSION = ClassFileFormatVersion.latest().major();
58 private static final String JL_CLASS = "java/lang/Class";
59 private static final String JL_OBJECT = "java/lang/Object";
60 private static final String JL_THROWABLE = "java/lang/Throwable";
61 private static final String JL_CLASS_NOT_FOUND_EX = "java/lang/ClassNotFoundException";
62 private static final String JL_ILLEGAL_ACCESS_EX = "java/lang/IllegalAccessException";
63
64 private static final String JL_NO_CLASS_DEF_FOUND_ERROR = "java/lang/NoClassDefFoundError";
65 private static final String JL_NO_SUCH_METHOD_EX = "java/lang/NoSuchMethodException";
438 }
439 }
440 }
441
442 /**
443 * Returns the {@link ClassLoader} to be used by the default implementation of {@link
444 * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
445 * default.
446 *
447 * @return ClassLoader
448 */
449 protected ClassLoader getClassLoader() {
450 return loader;
451 }
452
453 /**
454 * Generate a class file for the proxy class. This method drives the
455 * class file generation process.
456 */
457 private byte[] generateClassFile() {
458 visit(CLASSFILE_VERSION, accessFlags, dotToSlash(className), null,
459 JLR_PROXY, typeNames(interfaces));
460
461 /*
462 * Add proxy methods for the hashCode, equals,
463 * and toString methods of java.lang.Object. This is done before
464 * the methods from the proxy interfaces so that the methods from
465 * java.lang.Object take precedence over duplicate methods in the
466 * proxy interfaces.
467 */
468 addProxyMethod(hashCodeMethod);
469 addProxyMethod(equalsMethod);
470 addProxyMethod(toStringMethod);
471
472 /*
473 * Accumulate all of the methods from the proxy interfaces.
474 */
475 for (Class<?> intf : interfaces) {
476 for (Method m : intf.getMethods()) {
477 if (!Modifier.isStatic(m.getModifiers())) {
478 addProxyMethod(m, intf);
479 }
480 }
481 }
482
483 /*
484 * For each set of proxy methods with the same signature,
485 * verify that the methods' return types are compatible.
486 */
487 for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
488 checkReturnTypes(sigmethods);
489 }
490
491 generateConstructor();
492
493 for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
494 for (ProxyMethod pm : sigmethods) {
495 // add static field for the Method object
496 visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
497 LJLR_METHOD, null, null);
498
499 // Generate code for proxy method
500 pm.generateMethod(this, className);
501 }
502 }
503
504 generateStaticInitializer();
505 generateLookupAccessor();
506 return toByteArray();
507 }
508
509 /**
510 * Add another method to be proxied, either by creating a new
511 * ProxyMethod object or augmenting an old one for a duplicate
512 * method.
513 *
514 * "fromClass" indicates the proxy interface that the method was
515 * found through, which may be different from (a subinterface of)
516 * the method's "declaring class". Note that the first Method
517 * object passed for a given name and descriptor identifies the
518 * Method object (and thus the declaring class) that will be
519 * passed to the invocation handler's "invoke" method for a given
520 * set of duplicate methods.
521 */
522 private void addProxyMethod(Method m, Class<?> fromClass) {
664 mv.visitJumpInsn(IFEQ, L_illegalAccess);
665 mv.visitMethodInsn(INVOKESTATIC, JLI_METHODHANDLES, "lookup",
666 "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
667 mv.visitInsn(ARETURN);
668
669 mv.visitLabel(L_illegalAccess);
670 mv.visitTypeInsn(Opcodes.NEW, JL_ILLEGAL_ACCESS_EX);
671 mv.visitInsn(DUP);
672 mv.visitVarInsn(ALOAD, 0);
673 mv.visitMethodInsn(INVOKEVIRTUAL, JLI_LOOKUP, "toString",
674 "()Ljava/lang/String;", false);
675 mv.visitMethodInsn(INVOKESPECIAL, JL_ILLEGAL_ACCESS_EX,
676 "<init>", "(Ljava/lang/String;)V", false);
677 mv.visitInsn(ATHROW);
678
679 // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
680 mv.visitMaxs(-1, -1);
681 mv.visitEnd();
682 }
683
684 /**
685 * A ProxyMethod object represents a proxy method in the proxy class
686 * being generated: a method whose implementation will encode and
687 * dispatch invocations to the proxy instance's invocation handler.
688 */
689 private static class ProxyMethod {
690
691 private final Method method;
692 private final String shortSignature;
693 private final Class<?> fromClass;
694 private final Class<?>[] parameterTypes;
695 private final Class<?> returnType;
696 private final String methodFieldName;
697 private Class<?>[] exceptionTypes;
698
699 private ProxyMethod(Method method, String sig, Class<?>[] parameterTypes,
700 Class<?> returnType, Class<?>[] exceptionTypes,
701 Class<?> fromClass, String methodFieldName) {
702 this.method = method;
703 this.shortSignature = sig;
793
794 mv.visitLabel(L_endBlock);
795
796 // Generate exception handler
797 mv.visitLabel(L_RuntimeHandler);
798 mv.visitInsn(ATHROW); // just rethrow the exception
799
800 mv.visitLabel(L_ThrowableHandler);
801 mv.visitVarInsn(ASTORE, 1);
802 mv.visitTypeInsn(Opcodes.NEW, JLR_UNDECLARED_THROWABLE_EX);
803 mv.visitInsn(DUP);
804 mv.visitVarInsn(ALOAD, 1);
805 mv.visitMethodInsn(INVOKESPECIAL, JLR_UNDECLARED_THROWABLE_EX,
806 "<init>", "(Ljava/lang/Throwable;)V", false);
807 mv.visitInsn(ATHROW);
808 // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
809 mv.visitMaxs(-1, -1);
810 mv.visitEnd();
811 }
812
813 /**
814 * Generate code for wrapping an argument of the given type
815 * whose value can be found at the specified local variable
816 * index, in order for it to be passed (as an Object) to the
817 * invocation handler's "invoke" method.
818 */
819 private void codeWrapArgument(MethodVisitor mv, Class<?> type, int slot) {
820 if (type.isPrimitive()) {
821 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
822
823 mv.visitVarInsn(prim.loadOpcode, slot);
824 mv.visitMethodInsn(INVOKESTATIC, prim.wrapperClassName, "valueOf",
825 prim.wrapperValueOfDesc, false);
826 } else {
827 mv.visitVarInsn(ALOAD, slot);
828 }
829 }
830
831 /**
832 * Generate code for unwrapping a return value of the given
833 * type from the invocation handler's "invoke" method (as type
834 * Object) to its correct type.
835 */
836 private void codeUnwrapReturnValue(MethodVisitor mv, Class<?> type) {
837 if (type.isPrimitive()) {
838 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
839
840 mv.visitTypeInsn(CHECKCAST, prim.wrapperClassName);
841 mv.visitMethodInsn(INVOKEVIRTUAL,
842 prim.wrapperClassName,
843 prim.unwrapMethodName, prim.unwrapMethodDesc, false);
844
845 mv.visitInsn(prim.returnOpcode);
846 } else {
847 mv.visitTypeInsn(CHECKCAST, dotToSlash(type.getName()));
848 mv.visitInsn(ARETURN);
849 }
850 }
851
852 /**
853 * Generate code for initializing the static field that stores
854 * the Method object for this proxy method. A class loader is
855 * anticipated at local variable index 0.
856 */
857 private void codeFieldInitialization(MethodVisitor mv, String className) {
858 codeClassForName(mv, fromClass);
859
860 mv.visitLdcInsn(method.getName());
861
862 emitIconstInsn(mv, parameterTypes.length);
863
864 mv.visitTypeInsn(Opcodes.ANEWARRAY, JL_CLASS);
865
866 // Construct an array with the parameter types mapping primitives to Wrapper types
867 for (int i = 0; i < parameterTypes.length; i++) {
879 mv.visitInsn(Opcodes.AASTORE);
880 }
881 // lookup the method
882 mv.visitMethodInsn(INVOKEVIRTUAL,
883 JL_CLASS,
884 "getMethod",
885 "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
886 false);
887
888 mv.visitFieldInsn(PUTSTATIC,
889 dotToSlash(className),
890 methodFieldName, LJLR_METHOD);
891 }
892
893 /*
894 * =============== Code Generation Utility Methods ===============
895 */
896
897 /**
898 * Generate code to invoke the Class.forName with the name of the given
899 * class to get its Class object at runtime. The code is written to
900 * the supplied stream. Note that the code generated by this method
901 * may cause the checked ClassNotFoundException to be thrown. A class
902 * loader is anticipated at local variable index 0.
903 */
904 private void codeClassForName(MethodVisitor mv, Class<?> cl) {
905 mv.visitLdcInsn(cl.getName());
906 mv.visitInsn(ICONST_0); // false
907 mv.visitVarInsn(ALOAD, 0); // classLoader
908 mv.visitMethodInsn(INVOKESTATIC,
909 JL_CLASS,
910 "forName",
911 "(Ljava/lang/String;Z" + LJL_CLASSLOADER + ")Ljava/lang/Class;",
912 false);
913 }
914
915 /**
916 * Visit a bytecode for a constant.
917 *
918 * @param mv The MethodVisitor
919 * @param cst The constant value
920 */
921 private void emitIconstInsn(MethodVisitor mv, final int cst) {
922 if (cst >= -1 && cst <= 5) {
923 mv.visitInsn(Opcodes.ICONST_0 + cst);
924 } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
925 mv.visitIntInsn(Opcodes.BIPUSH, cst);
926 } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
927 mv.visitIntInsn(Opcodes.SIPUSH, cst);
928 } else {
929 mv.visitLdcInsn(cst);
930 }
931 }
932
|
8 * particular file as subject to the "Classpath" exception as provided
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.reflect;
27
28 import jdk.internal.misc.PreviewFeatures;
29 import jdk.internal.value.PrimitiveClass;
30 import jdk.internal.org.objectweb.asm.Attribute;
31 import jdk.internal.org.objectweb.asm.ByteVector;
32 import jdk.internal.org.objectweb.asm.ClassWriter;
33 import jdk.internal.org.objectweb.asm.Label;
34 import jdk.internal.org.objectweb.asm.MethodVisitor;
35 import jdk.internal.org.objectweb.asm.Opcodes;
36 import jdk.internal.org.objectweb.asm.Type;
37 import sun.invoke.util.Wrapper;
38 import sun.security.action.GetBooleanAction;
39
40 import java.io.IOException;
41 import java.lang.invoke.MethodType;
42 import java.nio.file.Files;
43 import java.nio.file.Path;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.HashSet;
47 import java.util.LinkedHashMap;
48 import java.util.List;
49 import java.util.ListIterator;
50 import java.util.Map;
51 import java.util.Set;
52
53 import static jdk.internal.org.objectweb.asm.Opcodes.*;
54
55 /**
56 * ProxyGenerator contains the code to generate a dynamic proxy class
57 * for the java.lang.reflect.Proxy API.
58 * <p>
59 * The external interface to ProxyGenerator is the static
60 * "generateProxyClass" method.
61 */
62 final class ProxyGenerator extends ClassWriter {
63 private static final int CLASSFILE_VERSION = ClassFileFormatVersion.latest().major();
64 private static final String JL_CLASS = "java/lang/Class";
65 private static final String JL_OBJECT = "java/lang/Object";
66 private static final String JL_THROWABLE = "java/lang/Throwable";
67 private static final String JL_CLASS_NOT_FOUND_EX = "java/lang/ClassNotFoundException";
68 private static final String JL_ILLEGAL_ACCESS_EX = "java/lang/IllegalAccessException";
69
70 private static final String JL_NO_CLASS_DEF_FOUND_ERROR = "java/lang/NoClassDefFoundError";
71 private static final String JL_NO_SUCH_METHOD_EX = "java/lang/NoSuchMethodException";
444 }
445 }
446 }
447
448 /**
449 * Returns the {@link ClassLoader} to be used by the default implementation of {@link
450 * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
451 * default.
452 *
453 * @return ClassLoader
454 */
455 protected ClassLoader getClassLoader() {
456 return loader;
457 }
458
459 /**
460 * Generate a class file for the proxy class. This method drives the
461 * class file generation process.
462 */
463 private byte[] generateClassFile() {
464 int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
465 visit(version, accessFlags, dotToSlash(className), null,
466 JLR_PROXY, typeNames(interfaces));
467
468 /*
469 * Add proxy methods for the hashCode, equals,
470 * and toString methods of java.lang.Object. This is done before
471 * the methods from the proxy interfaces so that the methods from
472 * java.lang.Object take precedence over duplicate methods in the
473 * proxy interfaces.
474 */
475 addProxyMethod(hashCodeMethod);
476 addProxyMethod(equalsMethod);
477 addProxyMethod(toStringMethod);
478
479 /*
480 * Accumulate all of the methods from the proxy interfaces.
481 */
482 for (Class<?> intf : interfaces) {
483 for (Method m : intf.getMethods()) {
484 if (!Modifier.isStatic(m.getModifiers())) {
485 addProxyMethod(m, intf);
486 }
487 }
488 }
489
490 /*
491 * For each set of proxy methods with the same signature,
492 * verify that the methods' return types are compatible.
493 *
494 * Determine if any value classes to be preloaded.
495 */
496 Set<Class<?>> preloadClasses = new HashSet<>();
497 for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
498 checkReturnTypes(sigmethods);
499 for (ProxyMethod pm : sigmethods) {
500 preloadClasses.addAll(pm.preloadClasses());
501 }
502 }
503
504 generateConstructor();
505
506 for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
507 for (ProxyMethod pm : sigmethods) {
508 // add static field for the Method object
509 visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
510 LJLR_METHOD, null, null);
511
512 // Generate code for proxy method
513 pm.generateMethod(this, className);
514 }
515 }
516 if (preloadClasses.size() > 0) {
517 generatePreloadAttribute(preloadClasses);
518 }
519
520 generateStaticInitializer();
521 generateLookupAccessor();
522 return toByteArray();
523 }
524
525 /**
526 * Add another method to be proxied, either by creating a new
527 * ProxyMethod object or augmenting an old one for a duplicate
528 * method.
529 *
530 * "fromClass" indicates the proxy interface that the method was
531 * found through, which may be different from (a subinterface of)
532 * the method's "declaring class". Note that the first Method
533 * object passed for a given name and descriptor identifies the
534 * Method object (and thus the declaring class) that will be
535 * passed to the invocation handler's "invoke" method for a given
536 * set of duplicate methods.
537 */
538 private void addProxyMethod(Method m, Class<?> fromClass) {
680 mv.visitJumpInsn(IFEQ, L_illegalAccess);
681 mv.visitMethodInsn(INVOKESTATIC, JLI_METHODHANDLES, "lookup",
682 "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
683 mv.visitInsn(ARETURN);
684
685 mv.visitLabel(L_illegalAccess);
686 mv.visitTypeInsn(Opcodes.NEW, JL_ILLEGAL_ACCESS_EX);
687 mv.visitInsn(DUP);
688 mv.visitVarInsn(ALOAD, 0);
689 mv.visitMethodInsn(INVOKEVIRTUAL, JLI_LOOKUP, "toString",
690 "()Ljava/lang/String;", false);
691 mv.visitMethodInsn(INVOKESPECIAL, JL_ILLEGAL_ACCESS_EX,
692 "<init>", "(Ljava/lang/String;)V", false);
693 mv.visitInsn(ATHROW);
694
695 // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
696 mv.visitMaxs(-1, -1);
697 mv.visitEnd();
698 }
699
700 private void generatePreloadAttribute(Set<Class<?>> preloadClasses) {
701 Attribute attr = new Attribute("Preload") {
702 @Override
703 protected ByteVector write(ClassWriter cw,
704 byte[] code,
705 int len,
706 int maxStack,
707 int maxLocals) {
708 ByteVector attr = new ByteVector();
709 attr.putShort(preloadClasses.size());
710 for (Class<?> c : preloadClasses) {
711 attr.putShort(cw.newClass(Type.getInternalName(c)));
712 }
713 return attr;
714 }
715 };
716 visitAttribute(attr);
717 }
718 /**
719 * A ProxyMethod object represents a proxy method in the proxy class
720 * being generated: a method whose implementation will encode and
721 * dispatch invocations to the proxy instance's invocation handler.
722 */
723 private static class ProxyMethod {
724
725 private final Method method;
726 private final String shortSignature;
727 private final Class<?> fromClass;
728 private final Class<?>[] parameterTypes;
729 private final Class<?> returnType;
730 private final String methodFieldName;
731 private Class<?>[] exceptionTypes;
732
733 private ProxyMethod(Method method, String sig, Class<?>[] parameterTypes,
734 Class<?> returnType, Class<?>[] exceptionTypes,
735 Class<?> fromClass, String methodFieldName) {
736 this.method = method;
737 this.shortSignature = sig;
827
828 mv.visitLabel(L_endBlock);
829
830 // Generate exception handler
831 mv.visitLabel(L_RuntimeHandler);
832 mv.visitInsn(ATHROW); // just rethrow the exception
833
834 mv.visitLabel(L_ThrowableHandler);
835 mv.visitVarInsn(ASTORE, 1);
836 mv.visitTypeInsn(Opcodes.NEW, JLR_UNDECLARED_THROWABLE_EX);
837 mv.visitInsn(DUP);
838 mv.visitVarInsn(ALOAD, 1);
839 mv.visitMethodInsn(INVOKESPECIAL, JLR_UNDECLARED_THROWABLE_EX,
840 "<init>", "(Ljava/lang/Throwable;)V", false);
841 mv.visitInsn(ATHROW);
842 // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
843 mv.visitMaxs(-1, -1);
844 mv.visitEnd();
845 }
846
847 Set<Class<?>> preloadClasses() {
848 Set<Class<?>> preloadClasses = new HashSet<>();
849 for (Class<?> type : parameterTypes) {
850 if (requiresPreload(type)) {
851 preloadClasses.add(type);
852 }
853 }
854 if (requiresPreload(returnType)) {
855 preloadClasses.add(returnType);
856 }
857 return preloadClasses;
858 }
859
860 boolean requiresPreload(Class<?> cls) {
861 Class<?> c = cls;
862 while (c.isArray()) {
863 c = c.getComponentType();
864 }
865 return c.isValue();
866 }
867
868 /**
869 * Generate code for wrapping an argument of the given type
870 * whose value can be found at the specified local variable
871 * index, in order for it to be passed (as an Object) to the
872 * invocation handler's "invoke" method.
873 */
874 private void codeWrapArgument(MethodVisitor mv, Class<?> type, int slot) {
875 if (type.isPrimitive()) {
876 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
877
878 mv.visitVarInsn(prim.loadOpcode, slot);
879 mv.visitMethodInsn(INVOKESTATIC, prim.wrapperClassName, "valueOf",
880 prim.wrapperValueOfDesc, false);
881 } else {
882 mv.visitVarInsn(ALOAD, slot);
883 }
884 }
885
886 /**
887 * Generate code for unwrapping a return value of the given
888 * type from the invocation handler's "invoke" method (as type
889 * Object) to its correct type.
890 */
891 private void codeUnwrapReturnValue(MethodVisitor mv, Class<?> type) {
892 if (type.isPrimitive()) {
893 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
894
895 mv.visitTypeInsn(CHECKCAST, prim.wrapperClassName);
896 mv.visitMethodInsn(INVOKEVIRTUAL,
897 prim.wrapperClassName,
898 prim.unwrapMethodName, prim.unwrapMethodDesc, false);
899
900 mv.visitInsn(prim.returnOpcode);
901 } else {
902 String internalName = dotToSlash(type.getName());
903 if (PrimitiveClass.isPrimitiveValueType(type)) {
904 internalName = 'Q' + internalName + ";";
905 }
906 mv.visitTypeInsn(CHECKCAST, internalName);
907 mv.visitInsn(ARETURN);
908 }
909 }
910
911 /**
912 * Generate code for initializing the static field that stores
913 * the Method object for this proxy method. A class loader is
914 * anticipated at local variable index 0.
915 */
916 private void codeFieldInitialization(MethodVisitor mv, String className) {
917 codeClassForName(mv, fromClass);
918
919 mv.visitLdcInsn(method.getName());
920
921 emitIconstInsn(mv, parameterTypes.length);
922
923 mv.visitTypeInsn(Opcodes.ANEWARRAY, JL_CLASS);
924
925 // Construct an array with the parameter types mapping primitives to Wrapper types
926 for (int i = 0; i < parameterTypes.length; i++) {
938 mv.visitInsn(Opcodes.AASTORE);
939 }
940 // lookup the method
941 mv.visitMethodInsn(INVOKEVIRTUAL,
942 JL_CLASS,
943 "getMethod",
944 "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
945 false);
946
947 mv.visitFieldInsn(PUTSTATIC,
948 dotToSlash(className),
949 methodFieldName, LJLR_METHOD);
950 }
951
952 /*
953 * =============== Code Generation Utility Methods ===============
954 */
955
956 /**
957 * Generate code to invoke the Class.forName with the name of the given
958 * class to get its Class object at runtime. And also generate code
959 * to invoke Class::asValueType if the class is a primitive value type.
960 *
961 * The code is written to the supplied stream. Note that the code generated
962 * by this method may caused the checked ClassNotFoundException to be thrown.
963 * A class loader is anticipated at local variable index 0.
964 */
965 private void codeClassForName(MethodVisitor mv, Class<?> cl) {
966 mv.visitLdcInsn(cl.getName());
967 mv.visitInsn(ICONST_0); // false
968 mv.visitVarInsn(ALOAD, 0); // classLoader
969 mv.visitMethodInsn(INVOKESTATIC,
970 JL_CLASS,
971 "forName",
972 "(Ljava/lang/String;Z" + LJL_CLASSLOADER + ")Ljava/lang/Class;",
973 false);
974 if (PrimitiveClass.isPrimitiveValueType(cl)) {
975 mv.visitMethodInsn(INVOKESTATIC,
976 "jdk/internal/value/PrimitiveClass",
977 "asValueType", "(Ljava/lang/Class;)Ljava/lang/Class;",
978 false);
979 }
980
981 }
982
983 /**
984 * Visit a bytecode for a constant.
985 *
986 * @param mv The MethodVisitor
987 * @param cst The constant value
988 */
989 private void emitIconstInsn(MethodVisitor mv, final int cst) {
990 if (cst >= -1 && cst <= 5) {
991 mv.visitInsn(Opcodes.ICONST_0 + cst);
992 } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
993 mv.visitIntInsn(Opcodes.BIPUSH, cst);
994 } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
995 mv.visitIntInsn(Opcodes.SIPUSH, cst);
996 } else {
997 mv.visitLdcInsn(cst);
998 }
999 }
1000
|