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