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