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