< prev index next >

src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java

Print this page

   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 
< prev index next >