src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
changeset 57827 425412369353
parent 51986 c1db377f6300
equal deleted inserted replaced
57826:bf4c808a4488 57827:425412369353
     1 /*
     1 /*
     2  * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package java.lang.reflect;
    26 package java.lang.reflect;
    27 
    27 
    28 import java.io.ByteArrayOutputStream;
    28 import jdk.internal.org.objectweb.asm.ClassWriter;
    29 import java.io.DataOutputStream;
    29 import jdk.internal.org.objectweb.asm.Label;
    30 import java.io.File;
    30 import jdk.internal.org.objectweb.asm.MethodVisitor;
       
    31 import jdk.internal.org.objectweb.asm.Opcodes;
       
    32 import sun.security.action.GetBooleanAction;
       
    33 
    31 import java.io.IOException;
    34 import java.io.IOException;
    32 import java.io.OutputStream;
    35 import java.lang.invoke.MethodType;
    33 import java.lang.reflect.Array;
       
    34 import java.lang.reflect.Method;
       
    35 import java.nio.file.Files;
    36 import java.nio.file.Files;
    36 import java.nio.file.Path;
    37 import java.nio.file.Path;
    37 import java.util.ArrayList;
    38 import java.util.ArrayList;
       
    39 import java.util.Arrays;
    38 import java.util.HashMap;
    40 import java.util.HashMap;
       
    41 import java.util.LinkedHashMap;
    39 import java.util.LinkedList;
    42 import java.util.LinkedList;
    40 import java.util.List;
    43 import java.util.List;
    41 import java.util.ListIterator;
    44 import java.util.ListIterator;
    42 import java.util.Map;
    45 import java.util.Map;
    43 import sun.security.action.GetBooleanAction;
    46 
       
    47 import static jdk.internal.org.objectweb.asm.Opcodes.*;
    44 
    48 
    45 /**
    49 /**
    46  * ProxyGenerator contains the code to generate a dynamic proxy class
    50  * ProxyGenerator contains the code to generate a dynamic proxy class
    47  * for the java.lang.reflect.Proxy API.
    51  * for the java.lang.reflect.Proxy API.
    48  *
    52  * <p>
    49  * The external interfaces to ProxyGenerator is the static
    53  * The external interface to ProxyGenerator is the static
    50  * "generateProxyClass" method.
    54  * "generateProxyClass" method.
    51  *
       
    52  * @author      Peter Jones
       
    53  * @since       1.3
       
    54  */
    55  */
    55 class ProxyGenerator {
    56 final class ProxyGenerator extends ClassWriter {
    56     /*
    57 
    57      * In the comments below, "JVMS" refers to The Java Virtual Machine
    58     private static final String JL_CLASS = "java/lang/Class";
    58      * Specification Second Edition and "JLS" refers to the original
    59     private static final String JL_OBJECT = "java/lang/Object";
    59      * version of The Java Language Specification, unless otherwise
    60     private static final String JL_THROWABLE = "java/lang/Throwable";
    60      * specified.
    61     private static final String JL_CLASS_NOT_FOUND_EX = "java/lang/ClassNotFoundException";
    61      */
    62     private static final String JL_NO_CLASS_DEF_FOUND_ERROR = "java/lang/NoClassDefFoundError";
    62 
    63     private static final String JL_NO_SUCH_METHOD_EX = "java/lang/NoSuchMethodException";
    63     /* generate 1.5-era class file version */
    64     private static final String JL_NO_SUCH_METHOD_ERROR = "java/lang/NoSuchMethodError";
    64     private static final int CLASSFILE_MAJOR_VERSION = 49;
    65 
    65     private static final int CLASSFILE_MINOR_VERSION = 0;
    66     private static final String JLR_INVOCATION_HANDLER = "java/lang/reflect/InvocationHandler";
    66 
    67     private static final String JLR_PROXY = "java/lang/reflect/Proxy";
    67     /*
    68     private static final String JLR_UNDECLARED_THROWABLE_EX = "java/lang/reflect/UndeclaredThrowableException";
    68      * beginning of constants copied from
    69 
    69      * sun.tools.java.RuntimeConstants (which no longer exists):
    70     private static final String LJL_CLASS = "Ljava/lang/Class;";
    70      */
    71     private static final String LJLR_METHOD = "Ljava/lang/reflect/Method;";
    71 
    72     private static final String LJLR_INVOCATION_HANDLER = "Ljava/lang/reflect/InvocationHandler;";
    72     /* constant pool tags */
    73 
    73     private static final int CONSTANT_UTF8              = 1;
    74     private static final String MJLR_INVOCATIONHANDLER = "(Ljava/lang/reflect/InvocationHandler;)V";
    74     private static final int CONSTANT_UNICODE           = 2;
    75 
    75     private static final int CONSTANT_INTEGER           = 3;
    76     private static final String NAME_CTOR = "<init>";
    76     private static final int CONSTANT_FLOAT             = 4;
    77     private static final String NAME_CLINIT = "<clinit>";
    77     private static final int CONSTANT_LONG              = 5;
    78 
    78     private static final int CONSTANT_DOUBLE            = 6;
    79     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
    79     private static final int CONSTANT_CLASS             = 7;
    80 
    80     private static final int CONSTANT_STRING            = 8;
    81     /**
    81     private static final int CONSTANT_FIELD             = 9;
    82      * name of field for storing a proxy instance's invocation handler
    82     private static final int CONSTANT_METHOD            = 10;
    83      */
    83     private static final int CONSTANT_INTERFACEMETHOD   = 11;
       
    84     private static final int CONSTANT_NAMEANDTYPE       = 12;
       
    85 
       
    86     /* access and modifier flags */
       
    87     private static final int ACC_PUBLIC                 = 0x00000001;
       
    88     private static final int ACC_PRIVATE                = 0x00000002;
       
    89 //  private static final int ACC_PROTECTED              = 0x00000004;
       
    90     private static final int ACC_STATIC                 = 0x00000008;
       
    91     private static final int ACC_FINAL                  = 0x00000010;
       
    92 //  private static final int ACC_SYNCHRONIZED           = 0x00000020;
       
    93 //  private static final int ACC_VOLATILE               = 0x00000040;
       
    94 //  private static final int ACC_TRANSIENT              = 0x00000080;
       
    95 //  private static final int ACC_NATIVE                 = 0x00000100;
       
    96 //  private static final int ACC_INTERFACE              = 0x00000200;
       
    97 //  private static final int ACC_ABSTRACT               = 0x00000400;
       
    98     private static final int ACC_SUPER                  = 0x00000020;
       
    99 //  private static final int ACC_STRICT                 = 0x00000800;
       
   100 
       
   101     /* opcodes */
       
   102 //  private static final int opc_nop                    = 0;
       
   103     private static final int opc_aconst_null            = 1;
       
   104 //  private static final int opc_iconst_m1              = 2;
       
   105     private static final int opc_iconst_0               = 3;
       
   106 //  private static final int opc_iconst_1               = 4;
       
   107 //  private static final int opc_iconst_2               = 5;
       
   108 //  private static final int opc_iconst_3               = 6;
       
   109 //  private static final int opc_iconst_4               = 7;
       
   110 //  private static final int opc_iconst_5               = 8;
       
   111 //  private static final int opc_lconst_0               = 9;
       
   112 //  private static final int opc_lconst_1               = 10;
       
   113 //  private static final int opc_fconst_0               = 11;
       
   114 //  private static final int opc_fconst_1               = 12;
       
   115 //  private static final int opc_fconst_2               = 13;
       
   116 //  private static final int opc_dconst_0               = 14;
       
   117 //  private static final int opc_dconst_1               = 15;
       
   118     private static final int opc_bipush                 = 16;
       
   119     private static final int opc_sipush                 = 17;
       
   120     private static final int opc_ldc                    = 18;
       
   121     private static final int opc_ldc_w                  = 19;
       
   122 //  private static final int opc_ldc2_w                 = 20;
       
   123     private static final int opc_iload                  = 21;
       
   124     private static final int opc_lload                  = 22;
       
   125     private static final int opc_fload                  = 23;
       
   126     private static final int opc_dload                  = 24;
       
   127     private static final int opc_aload                  = 25;
       
   128     private static final int opc_iload_0                = 26;
       
   129 //  private static final int opc_iload_1                = 27;
       
   130 //  private static final int opc_iload_2                = 28;
       
   131 //  private static final int opc_iload_3                = 29;
       
   132     private static final int opc_lload_0                = 30;
       
   133 //  private static final int opc_lload_1                = 31;
       
   134 //  private static final int opc_lload_2                = 32;
       
   135 //  private static final int opc_lload_3                = 33;
       
   136     private static final int opc_fload_0                = 34;
       
   137 //  private static final int opc_fload_1                = 35;
       
   138 //  private static final int opc_fload_2                = 36;
       
   139 //  private static final int opc_fload_3                = 37;
       
   140     private static final int opc_dload_0                = 38;
       
   141 //  private static final int opc_dload_1                = 39;
       
   142 //  private static final int opc_dload_2                = 40;
       
   143 //  private static final int opc_dload_3                = 41;
       
   144     private static final int opc_aload_0                = 42;
       
   145 //  private static final int opc_aload_1                = 43;
       
   146 //  private static final int opc_aload_2                = 44;
       
   147 //  private static final int opc_aload_3                = 45;
       
   148 //  private static final int opc_iaload                 = 46;
       
   149 //  private static final int opc_laload                 = 47;
       
   150 //  private static final int opc_faload                 = 48;
       
   151 //  private static final int opc_daload                 = 49;
       
   152 //  private static final int opc_aaload                 = 50;
       
   153 //  private static final int opc_baload                 = 51;
       
   154 //  private static final int opc_caload                 = 52;
       
   155 //  private static final int opc_saload                 = 53;
       
   156 //  private static final int opc_istore                 = 54;
       
   157 //  private static final int opc_lstore                 = 55;
       
   158 //  private static final int opc_fstore                 = 56;
       
   159 //  private static final int opc_dstore                 = 57;
       
   160     private static final int opc_astore                 = 58;
       
   161 //  private static final int opc_istore_0               = 59;
       
   162 //  private static final int opc_istore_1               = 60;
       
   163 //  private static final int opc_istore_2               = 61;
       
   164 //  private static final int opc_istore_3               = 62;
       
   165 //  private static final int opc_lstore_0               = 63;
       
   166 //  private static final int opc_lstore_1               = 64;
       
   167 //  private static final int opc_lstore_2               = 65;
       
   168 //  private static final int opc_lstore_3               = 66;
       
   169 //  private static final int opc_fstore_0               = 67;
       
   170 //  private static final int opc_fstore_1               = 68;
       
   171 //  private static final int opc_fstore_2               = 69;
       
   172 //  private static final int opc_fstore_3               = 70;
       
   173 //  private static final int opc_dstore_0               = 71;
       
   174 //  private static final int opc_dstore_1               = 72;
       
   175 //  private static final int opc_dstore_2               = 73;
       
   176 //  private static final int opc_dstore_3               = 74;
       
   177     private static final int opc_astore_0               = 75;
       
   178 //  private static final int opc_astore_1               = 76;
       
   179 //  private static final int opc_astore_2               = 77;
       
   180 //  private static final int opc_astore_3               = 78;
       
   181 //  private static final int opc_iastore                = 79;
       
   182 //  private static final int opc_lastore                = 80;
       
   183 //  private static final int opc_fastore                = 81;
       
   184 //  private static final int opc_dastore                = 82;
       
   185     private static final int opc_aastore                = 83;
       
   186 //  private static final int opc_bastore                = 84;
       
   187 //  private static final int opc_castore                = 85;
       
   188 //  private static final int opc_sastore                = 86;
       
   189     private static final int opc_pop                    = 87;
       
   190 //  private static final int opc_pop2                   = 88;
       
   191     private static final int opc_dup                    = 89;
       
   192 //  private static final int opc_dup_x1                 = 90;
       
   193 //  private static final int opc_dup_x2                 = 91;
       
   194 //  private static final int opc_dup2                   = 92;
       
   195 //  private static final int opc_dup2_x1                = 93;
       
   196 //  private static final int opc_dup2_x2                = 94;
       
   197 //  private static final int opc_swap                   = 95;
       
   198 //  private static final int opc_iadd                   = 96;
       
   199 //  private static final int opc_ladd                   = 97;
       
   200 //  private static final int opc_fadd                   = 98;
       
   201 //  private static final int opc_dadd                   = 99;
       
   202 //  private static final int opc_isub                   = 100;
       
   203 //  private static final int opc_lsub                   = 101;
       
   204 //  private static final int opc_fsub                   = 102;
       
   205 //  private static final int opc_dsub                   = 103;
       
   206 //  private static final int opc_imul                   = 104;
       
   207 //  private static final int opc_lmul                   = 105;
       
   208 //  private static final int opc_fmul                   = 106;
       
   209 //  private static final int opc_dmul                   = 107;
       
   210 //  private static final int opc_idiv                   = 108;
       
   211 //  private static final int opc_ldiv                   = 109;
       
   212 //  private static final int opc_fdiv                   = 110;
       
   213 //  private static final int opc_ddiv                   = 111;
       
   214 //  private static final int opc_irem                   = 112;
       
   215 //  private static final int opc_lrem                   = 113;
       
   216 //  private static final int opc_frem                   = 114;
       
   217 //  private static final int opc_drem                   = 115;
       
   218 //  private static final int opc_ineg                   = 116;
       
   219 //  private static final int opc_lneg                   = 117;
       
   220 //  private static final int opc_fneg                   = 118;
       
   221 //  private static final int opc_dneg                   = 119;
       
   222 //  private static final int opc_ishl                   = 120;
       
   223 //  private static final int opc_lshl                   = 121;
       
   224 //  private static final int opc_ishr                   = 122;
       
   225 //  private static final int opc_lshr                   = 123;
       
   226 //  private static final int opc_iushr                  = 124;
       
   227 //  private static final int opc_lushr                  = 125;
       
   228 //  private static final int opc_iand                   = 126;
       
   229 //  private static final int opc_land                   = 127;
       
   230 //  private static final int opc_ior                    = 128;
       
   231 //  private static final int opc_lor                    = 129;
       
   232 //  private static final int opc_ixor                   = 130;
       
   233 //  private static final int opc_lxor                   = 131;
       
   234 //  private static final int opc_iinc                   = 132;
       
   235 //  private static final int opc_i2l                    = 133;
       
   236 //  private static final int opc_i2f                    = 134;
       
   237 //  private static final int opc_i2d                    = 135;
       
   238 //  private static final int opc_l2i                    = 136;
       
   239 //  private static final int opc_l2f                    = 137;
       
   240 //  private static final int opc_l2d                    = 138;
       
   241 //  private static final int opc_f2i                    = 139;
       
   242 //  private static final int opc_f2l                    = 140;
       
   243 //  private static final int opc_f2d                    = 141;
       
   244 //  private static final int opc_d2i                    = 142;
       
   245 //  private static final int opc_d2l                    = 143;
       
   246 //  private static final int opc_d2f                    = 144;
       
   247 //  private static final int opc_i2b                    = 145;
       
   248 //  private static final int opc_i2c                    = 146;
       
   249 //  private static final int opc_i2s                    = 147;
       
   250 //  private static final int opc_lcmp                   = 148;
       
   251 //  private static final int opc_fcmpl                  = 149;
       
   252 //  private static final int opc_fcmpg                  = 150;
       
   253 //  private static final int opc_dcmpl                  = 151;
       
   254 //  private static final int opc_dcmpg                  = 152;
       
   255 //  private static final int opc_ifeq                   = 153;
       
   256 //  private static final int opc_ifne                   = 154;
       
   257 //  private static final int opc_iflt                   = 155;
       
   258 //  private static final int opc_ifge                   = 156;
       
   259 //  private static final int opc_ifgt                   = 157;
       
   260 //  private static final int opc_ifle                   = 158;
       
   261 //  private static final int opc_if_icmpeq              = 159;
       
   262 //  private static final int opc_if_icmpne              = 160;
       
   263 //  private static final int opc_if_icmplt              = 161;
       
   264 //  private static final int opc_if_icmpge              = 162;
       
   265 //  private static final int opc_if_icmpgt              = 163;
       
   266 //  private static final int opc_if_icmple              = 164;
       
   267 //  private static final int opc_if_acmpeq              = 165;
       
   268 //  private static final int opc_if_acmpne              = 166;
       
   269 //  private static final int opc_goto                   = 167;
       
   270 //  private static final int opc_jsr                    = 168;
       
   271 //  private static final int opc_ret                    = 169;
       
   272 //  private static final int opc_tableswitch            = 170;
       
   273 //  private static final int opc_lookupswitch           = 171;
       
   274     private static final int opc_ireturn                = 172;
       
   275     private static final int opc_lreturn                = 173;
       
   276     private static final int opc_freturn                = 174;
       
   277     private static final int opc_dreturn                = 175;
       
   278     private static final int opc_areturn                = 176;
       
   279     private static final int opc_return                 = 177;
       
   280     private static final int opc_getstatic              = 178;
       
   281     private static final int opc_putstatic              = 179;
       
   282     private static final int opc_getfield               = 180;
       
   283 //  private static final int opc_putfield               = 181;
       
   284     private static final int opc_invokevirtual          = 182;
       
   285     private static final int opc_invokespecial          = 183;
       
   286     private static final int opc_invokestatic           = 184;
       
   287     private static final int opc_invokeinterface        = 185;
       
   288     private static final int opc_new                    = 187;
       
   289 //  private static final int opc_newarray               = 188;
       
   290     private static final int opc_anewarray              = 189;
       
   291 //  private static final int opc_arraylength            = 190;
       
   292     private static final int opc_athrow                 = 191;
       
   293     private static final int opc_checkcast              = 192;
       
   294 //  private static final int opc_instanceof             = 193;
       
   295 //  private static final int opc_monitorenter           = 194;
       
   296 //  private static final int opc_monitorexit            = 195;
       
   297     private static final int opc_wide                   = 196;
       
   298 //  private static final int opc_multianewarray         = 197;
       
   299 //  private static final int opc_ifnull                 = 198;
       
   300 //  private static final int opc_ifnonnull              = 199;
       
   301 //  private static final int opc_goto_w                 = 200;
       
   302 //  private static final int opc_jsr_w                  = 201;
       
   303 
       
   304     // end of constants copied from sun.tools.java.RuntimeConstants
       
   305 
       
   306     /** name of the superclass of proxy classes */
       
   307     private static final String superclassName = "java/lang/reflect/Proxy";
       
   308 
       
   309     /** name of field for storing a proxy instance's invocation handler */
       
   310     private static final String handlerFieldName = "h";
    84     private static final String handlerFieldName = "h";
   311 
    85 
   312     /** debugging flag for saving generated class files */
    86     /**
       
    87      * debugging flag for saving generated class files
       
    88      */
   313     private static final boolean saveGeneratedFiles =
    89     private static final boolean saveGeneratedFiles =
   314         java.security.AccessController.doPrivileged(
    90             java.security.AccessController.doPrivileged(
   315             new GetBooleanAction(
    91                     new GetBooleanAction(
   316                 "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();
    92                             "jdk.proxy.ProxyGenerator.saveGeneratedFiles"));
   317 
    93 
   318     /**
    94     /* Preloaded ProxyMethod objects for methods in java.lang.Object */
   319      * Generate a public proxy class given a name and a list of proxy interfaces.
    95     private final static ProxyMethod hashCodeMethod;
   320      */
    96     private final static ProxyMethod equalsMethod;
   321     static byte[] generateProxyClass(final String name,
    97     private final static ProxyMethod toStringMethod;
   322                                      Class<?>[] interfaces) {
    98 
   323         return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER));
    99     static {
       
   100         try {
       
   101             hashCodeMethod = new ProxyMethod(Object.class.getMethod("hashCode"), "m0");
       
   102             equalsMethod = new ProxyMethod(Object.class.getMethod("equals", Object.class), "m1");
       
   103             toStringMethod = new ProxyMethod(Object.class.getMethod("toString"), "m2");
       
   104         } catch (NoSuchMethodException e) {
       
   105             throw new NoSuchMethodError(e.getMessage());
       
   106         }
       
   107     }
       
   108 
       
   109     /**
       
   110      * Class loader
       
   111      */
       
   112     private final ClassLoader loader;
       
   113 
       
   114     /**
       
   115      * Name of proxy class
       
   116      */
       
   117     private final String className;
       
   118 
       
   119     /**
       
   120      * Proxy interfaces
       
   121      */
       
   122     private final List<Class<?>> interfaces;
       
   123 
       
   124     /**
       
   125      * Proxy class access flags
       
   126      */
       
   127     private final int accessFlags;
       
   128 
       
   129     /**
       
   130      * Maps method signature string to list of ProxyMethod objects for
       
   131      * proxy methods with that signature.
       
   132      * Kept in insertion order to make it easier to compare old and new.
       
   133      */
       
   134     private final Map<String, List<ProxyMethod>> proxyMethods = new LinkedHashMap<>();
       
   135 
       
   136     /**
       
   137      * Ordinal of next ProxyMethod object added to proxyMethods.
       
   138      * Indexes are reserved for hashcode(0), equals(1), toString(2).
       
   139      */
       
   140     private int proxyMethodCount = 3;
       
   141 
       
   142     /**
       
   143      * Construct a ProxyGenerator to generate a proxy class with the
       
   144      * specified name and for the given interfaces.
       
   145      * <p>
       
   146      * A ProxyGenerator object contains the state for the ongoing
       
   147      * generation of a particular proxy class.
       
   148      */
       
   149     private ProxyGenerator(ClassLoader loader, String className, List<Class<?>> interfaces,
       
   150                            int accessFlags) {
       
   151         super(ClassWriter.COMPUTE_FRAMES);
       
   152         this.loader = loader;
       
   153         this.className = className;
       
   154         this.interfaces = interfaces;
       
   155         this.accessFlags = accessFlags;
   324     }
   156     }
   325 
   157 
   326     /**
   158     /**
   327      * Generate a proxy class given a name and a list of proxy interfaces.
   159      * Generate a proxy class given a name and a list of proxy interfaces.
   328      *
   160      *
   329      * @param name        the class name of the proxy class
   161      * @param name        the class name of the proxy class
   330      * @param interfaces  proxy interfaces
   162      * @param interfaces  proxy interfaces
   331      * @param accessFlags access flags of the proxy class
   163      * @param accessFlags access flags of the proxy class
   332     */
   164      */
   333     static byte[] generateProxyClass(final String name,
   165     static byte[] generateProxyClass(ClassLoader loader,
   334                                      Class<?>[] interfaces,
   166                                      final String name,
   335                                      int accessFlags)
   167                                      List<Class<?>> interfaces,
   336     {
   168                                      int accessFlags) {
   337         ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
   169         ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags);
   338         final byte[] classFile = gen.generateClassFile();
   170         final byte[] classFile = gen.generateClassFile();
   339 
   171 
   340         if (saveGeneratedFiles) {
   172         if (saveGeneratedFiles) {
   341             java.security.AccessController.doPrivileged(
   173             java.security.AccessController.doPrivileged(
   342             new java.security.PrivilegedAction<Void>() {
   174                     new java.security.PrivilegedAction<Void>() {
   343                 public Void run() {
   175                         public Void run() {
   344                     try {
   176                             try {
   345                         int i = name.lastIndexOf('.');
   177                                 int i = name.lastIndexOf('.');
   346                         Path path;
   178                                 Path path;
   347                         if (i > 0) {
   179                                 if (i > 0) {
   348                             Path dir = Path.of(name.substring(0, i).replace('.', File.separatorChar));
   180                                     Path dir = Path.of(dotToSlash(name.substring(0, i)));
   349                             Files.createDirectories(dir);
   181                                     Files.createDirectories(dir);
   350                             path = dir.resolve(name.substring(i+1, name.length()) + ".class");
   182                                     path = dir.resolve(name.substring(i + 1) + ".class");
   351                         } else {
   183                                 } else {
   352                             path = Path.of(name + ".class");
   184                                     path = Path.of(name + ".class");
       
   185                                 }
       
   186                                 Files.write(path, classFile);
       
   187                                 return null;
       
   188                             } catch (IOException e) {
       
   189                                 throw new InternalError(
       
   190                                         "I/O exception saving generated file: " + e);
       
   191                             }
   353                         }
   192                         }
   354                         Files.write(path, classFile);
   193                     });
   355                         return null;
       
   356                     } catch (IOException e) {
       
   357                         throw new InternalError(
       
   358                             "I/O exception saving generated file: " + e);
       
   359                     }
       
   360                 }
       
   361             });
       
   362         }
   194         }
   363 
   195 
   364         return classFile;
   196         return classFile;
   365     }
   197     }
   366 
   198 
   367     /* preloaded Method objects for methods in java.lang.Object */
   199     /**
   368     private static Method hashCodeMethod;
   200      * Return an array of the type names from an array of Classes.
   369     private static Method equalsMethod;
       
   370     private static Method toStringMethod;
       
   371     static {
       
   372         try {
       
   373             hashCodeMethod = Object.class.getMethod("hashCode");
       
   374             equalsMethod =
       
   375                 Object.class.getMethod("equals", new Class<?>[] { Object.class });
       
   376             toStringMethod = Object.class.getMethod("toString");
       
   377         } catch (NoSuchMethodException e) {
       
   378             throw new NoSuchMethodError(e.getMessage());
       
   379         }
       
   380     }
       
   381 
       
   382     /** name of proxy class */
       
   383     private String className;
       
   384 
       
   385     /** proxy interfaces */
       
   386     private Class<?>[] interfaces;
       
   387 
       
   388     /** proxy class access flags */
       
   389     private int accessFlags;
       
   390 
       
   391     /** constant pool of class being generated */
       
   392     private ConstantPool cp = new ConstantPool();
       
   393 
       
   394     /** FieldInfo struct for each field of generated class */
       
   395     private List<FieldInfo> fields = new ArrayList<>();
       
   396 
       
   397     /** MethodInfo struct for each method of generated class */
       
   398     private List<MethodInfo> methods = new ArrayList<>();
       
   399 
       
   400     /**
       
   401      * maps method signature string to list of ProxyMethod objects for
       
   402      * proxy methods with that signature
       
   403      */
       
   404     private Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>();
       
   405 
       
   406     /** count of ProxyMethod objects added to proxyMethods */
       
   407     private int proxyMethodCount = 0;
       
   408 
       
   409     /**
       
   410      * Construct a ProxyGenerator to generate a proxy class with the
       
   411      * specified name and for the given interfaces.
       
   412      *
   201      *
   413      * A ProxyGenerator object contains the state for the ongoing
   202      * @param classes an array of classes or interfaces
   414      * generation of a particular proxy class.
   203      * @return the array of class names; or null if there are no classes
   415      */
   204      */
   416     private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) {
   205     private static String[] typeNames(List<Class<?>> classes) {
   417         this.className = className;
   206         if (classes == null || classes.size() == 0)
   418         this.interfaces = interfaces;
   207             return null;
   419         this.accessFlags = accessFlags;
   208         int size = classes.size();
   420     }
   209         String[] ifaces = new String[size];
   421 
   210         for (int i = 0; i < size; i++)
   422     /**
   211             ifaces[i] = dotToSlash(classes.get(i).getName());
   423      * Generate a class file for the proxy class.  This method drives the
   212         return ifaces;
   424      * class file generation process.
       
   425      */
       
   426     private byte[] generateClassFile() {
       
   427 
       
   428         /* ============================================================
       
   429          * Step 1: Assemble ProxyMethod objects for all methods to
       
   430          * generate proxy dispatching code for.
       
   431          */
       
   432 
       
   433         /*
       
   434          * Record that proxy methods are needed for the hashCode, equals,
       
   435          * and toString methods of java.lang.Object.  This is done before
       
   436          * the methods from the proxy interfaces so that the methods from
       
   437          * java.lang.Object take precedence over duplicate methods in the
       
   438          * proxy interfaces.
       
   439          */
       
   440         addProxyMethod(hashCodeMethod, Object.class);
       
   441         addProxyMethod(equalsMethod, Object.class);
       
   442         addProxyMethod(toStringMethod, Object.class);
       
   443 
       
   444         /*
       
   445          * Now record all of the methods from the proxy interfaces, giving
       
   446          * earlier interfaces precedence over later ones with duplicate
       
   447          * methods.
       
   448          */
       
   449         for (Class<?> intf : interfaces) {
       
   450             for (Method m : intf.getMethods()) {
       
   451                 if (!Modifier.isStatic(m.getModifiers())) {
       
   452                     addProxyMethod(m, intf);
       
   453                 }
       
   454             }
       
   455         }
       
   456 
       
   457         /*
       
   458          * For each set of proxy methods with the same signature,
       
   459          * verify that the methods' return types are compatible.
       
   460          */
       
   461         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
       
   462             checkReturnTypes(sigmethods);
       
   463         }
       
   464 
       
   465         /* ============================================================
       
   466          * Step 2: Assemble FieldInfo and MethodInfo structs for all of
       
   467          * fields and methods in the class we are generating.
       
   468          */
       
   469         try {
       
   470             methods.add(generateConstructor());
       
   471 
       
   472             for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
       
   473                 for (ProxyMethod pm : sigmethods) {
       
   474 
       
   475                     // add static field for method's Method object
       
   476                     fields.add(new FieldInfo(pm.methodFieldName,
       
   477                         "Ljava/lang/reflect/Method;",
       
   478                          ACC_PRIVATE | ACC_STATIC));
       
   479 
       
   480                     // generate code for proxy method and add it
       
   481                     methods.add(pm.generateMethod());
       
   482                 }
       
   483             }
       
   484 
       
   485             methods.add(generateStaticInitializer());
       
   486 
       
   487         } catch (IOException e) {
       
   488             throw new InternalError("unexpected I/O Exception", e);
       
   489         }
       
   490 
       
   491         if (methods.size() > 65535) {
       
   492             throw new IllegalArgumentException("method limit exceeded");
       
   493         }
       
   494         if (fields.size() > 65535) {
       
   495             throw new IllegalArgumentException("field limit exceeded");
       
   496         }
       
   497 
       
   498         /* ============================================================
       
   499          * Step 3: Write the final class file.
       
   500          */
       
   501 
       
   502         /*
       
   503          * Make sure that constant pool indexes are reserved for the
       
   504          * following items before starting to write the final class file.
       
   505          */
       
   506         cp.getClass(dotToSlash(className));
       
   507         cp.getClass(superclassName);
       
   508         for (Class<?> intf: interfaces) {
       
   509             cp.getClass(dotToSlash(intf.getName()));
       
   510         }
       
   511 
       
   512         /*
       
   513          * Disallow new constant pool additions beyond this point, since
       
   514          * we are about to write the final constant pool table.
       
   515          */
       
   516         cp.setReadOnly();
       
   517 
       
   518         ByteArrayOutputStream bout = new ByteArrayOutputStream();
       
   519         DataOutputStream dout = new DataOutputStream(bout);
       
   520 
       
   521         try {
       
   522             /*
       
   523              * Write all the items of the "ClassFile" structure.
       
   524              * See JVMS section 4.1.
       
   525              */
       
   526                                         // u4 magic;
       
   527             dout.writeInt(0xCAFEBABE);
       
   528                                         // u2 minor_version;
       
   529             dout.writeShort(CLASSFILE_MINOR_VERSION);
       
   530                                         // u2 major_version;
       
   531             dout.writeShort(CLASSFILE_MAJOR_VERSION);
       
   532 
       
   533             cp.write(dout);             // (write constant pool)
       
   534 
       
   535                                         // u2 access_flags;
       
   536             dout.writeShort(accessFlags);
       
   537                                         // u2 this_class;
       
   538             dout.writeShort(cp.getClass(dotToSlash(className)));
       
   539                                         // u2 super_class;
       
   540             dout.writeShort(cp.getClass(superclassName));
       
   541 
       
   542                                         // u2 interfaces_count;
       
   543             dout.writeShort(interfaces.length);
       
   544                                         // u2 interfaces[interfaces_count];
       
   545             for (Class<?> intf : interfaces) {
       
   546                 dout.writeShort(cp.getClass(
       
   547                     dotToSlash(intf.getName())));
       
   548             }
       
   549 
       
   550                                         // u2 fields_count;
       
   551             dout.writeShort(fields.size());
       
   552                                         // field_info fields[fields_count];
       
   553             for (FieldInfo f : fields) {
       
   554                 f.write(dout);
       
   555             }
       
   556 
       
   557                                         // u2 methods_count;
       
   558             dout.writeShort(methods.size());
       
   559                                         // method_info methods[methods_count];
       
   560             for (MethodInfo m : methods) {
       
   561                 m.write(dout);
       
   562             }
       
   563 
       
   564                                          // u2 attributes_count;
       
   565             dout.writeShort(0); // (no ClassFile attributes for proxy classes)
       
   566 
       
   567         } catch (IOException e) {
       
   568             throw new InternalError("unexpected I/O Exception", e);
       
   569         }
       
   570 
       
   571         return bout.toByteArray();
       
   572     }
       
   573 
       
   574     /**
       
   575      * Add another method to be proxied, either by creating a new
       
   576      * ProxyMethod object or augmenting an old one for a duplicate
       
   577      * method.
       
   578      *
       
   579      * "fromClass" indicates the proxy interface that the method was
       
   580      * found through, which may be different from (a subinterface of)
       
   581      * the method's "declaring class".  Note that the first Method
       
   582      * object passed for a given name and descriptor identifies the
       
   583      * Method object (and thus the declaring class) that will be
       
   584      * passed to the invocation handler's "invoke" method for a given
       
   585      * set of duplicate methods.
       
   586      */
       
   587     private void addProxyMethod(Method m, Class<?> fromClass) {
       
   588         String name = m.getName();
       
   589         Class<?>[] parameterTypes = m.getParameterTypes();
       
   590         Class<?> returnType = m.getReturnType();
       
   591         Class<?>[] exceptionTypes = m.getExceptionTypes();
       
   592 
       
   593         String sig = name + getParameterDescriptors(parameterTypes);
       
   594         List<ProxyMethod> sigmethods = proxyMethods.get(sig);
       
   595         if (sigmethods != null) {
       
   596             for (ProxyMethod pm : sigmethods) {
       
   597                 if (returnType == pm.returnType) {
       
   598                     /*
       
   599                      * Found a match: reduce exception types to the
       
   600                      * greatest set of exceptions that can thrown
       
   601                      * compatibly with the throws clauses of both
       
   602                      * overridden methods.
       
   603                      */
       
   604                     List<Class<?>> legalExceptions = new ArrayList<>();
       
   605                     collectCompatibleTypes(
       
   606                         exceptionTypes, pm.exceptionTypes, legalExceptions);
       
   607                     collectCompatibleTypes(
       
   608                         pm.exceptionTypes, exceptionTypes, legalExceptions);
       
   609                     pm.exceptionTypes = new Class<?>[legalExceptions.size()];
       
   610                     pm.exceptionTypes =
       
   611                         legalExceptions.toArray(pm.exceptionTypes);
       
   612                     return;
       
   613                 }
       
   614             }
       
   615         } else {
       
   616             sigmethods = new ArrayList<>(3);
       
   617             proxyMethods.put(sig, sigmethods);
       
   618         }
       
   619         sigmethods.add(new ProxyMethod(name, parameterTypes, returnType,
       
   620                                        exceptionTypes, fromClass));
       
   621     }
   213     }
   622 
   214 
   623     /**
   215     /**
   624      * For a given set of proxy methods with the same signature, check
   216      * For a given set of proxy methods with the same signature, check
   625      * that their return types are compatible according to the Proxy
   217      * that their return types are compatible according to the Proxy
   643          * List of return types that are not yet known to be
   235          * List of return types that are not yet known to be
   644          * assignable from ("covered" by) any of the others.
   236          * assignable from ("covered" by) any of the others.
   645          */
   237          */
   646         LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>();
   238         LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>();
   647 
   239 
   648     nextNewReturnType:
   240         nextNewReturnType:
   649         for (ProxyMethod pm : methods) {
   241         for (ProxyMethod pm : methods) {
   650             Class<?> newReturnType = pm.returnType;
   242             Class<?> newReturnType = pm.returnType;
   651             if (newReturnType.isPrimitive()) {
   243             if (newReturnType.isPrimitive()) {
   652                 throw new IllegalArgumentException(
   244                 throw new IllegalArgumentException(
   653                     "methods with same signature " +
   245                         "methods with same signature " +
   654                     getFriendlyMethodSignature(pm.methodName,
   246                                 pm.shortSignature +
   655                                                pm.parameterTypes) +
   247                                 " but incompatible return types: " +
   656                     " but incompatible return types: " +
   248                                 newReturnType.getName() + " and others");
   657                     newReturnType.getName() + " and others");
       
   658             }
   249             }
   659             boolean added = false;
   250             boolean added = false;
   660 
   251 
   661             /*
   252             /*
   662              * Compare the new return type to the existing uncovered
   253              * Compare the new return type to the existing uncovered
   707          * not assignable from any of the others.
   298          * not assignable from any of the others.
   708          */
   299          */
   709         if (uncoveredReturnTypes.size() > 1) {
   300         if (uncoveredReturnTypes.size() > 1) {
   710             ProxyMethod pm = methods.get(0);
   301             ProxyMethod pm = methods.get(0);
   711             throw new IllegalArgumentException(
   302             throw new IllegalArgumentException(
   712                 "methods with same signature " +
   303                     "methods with same signature " +
   713                 getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) +
   304                             pm.shortSignature +
   714                 " but incompatible return types: " + uncoveredReturnTypes);
   305                             " but incompatible return types: " + uncoveredReturnTypes);
   715         }
       
   716     }
       
   717 
       
   718     /**
       
   719      * A FieldInfo object contains information about a particular field
       
   720      * in the class being generated.  The class mirrors the data items of
       
   721      * the "field_info" structure of the class file format (see JVMS 4.5).
       
   722      */
       
   723     private class FieldInfo {
       
   724         public int accessFlags;
       
   725         public String name;
       
   726         public String descriptor;
       
   727 
       
   728         public FieldInfo(String name, String descriptor, int accessFlags) {
       
   729             this.name = name;
       
   730             this.descriptor = descriptor;
       
   731             this.accessFlags = accessFlags;
       
   732 
       
   733             /*
       
   734              * Make sure that constant pool indexes are reserved for the
       
   735              * following items before starting to write the final class file.
       
   736              */
       
   737             cp.getUtf8(name);
       
   738             cp.getUtf8(descriptor);
       
   739         }
       
   740 
       
   741         public void write(DataOutputStream out) throws IOException {
       
   742             /*
       
   743              * Write all the items of the "field_info" structure.
       
   744              * See JVMS section 4.5.
       
   745              */
       
   746                                         // u2 access_flags;
       
   747             out.writeShort(accessFlags);
       
   748                                         // u2 name_index;
       
   749             out.writeShort(cp.getUtf8(name));
       
   750                                         // u2 descriptor_index;
       
   751             out.writeShort(cp.getUtf8(descriptor));
       
   752                                         // u2 attributes_count;
       
   753             out.writeShort(0);  // (no field_info attributes for proxy classes)
       
   754         }
       
   755     }
       
   756 
       
   757     /**
       
   758      * An ExceptionTableEntry object holds values for the data items of
       
   759      * an entry in the "exception_table" item of the "Code" attribute of
       
   760      * "method_info" structures (see JVMS 4.7.3).
       
   761      */
       
   762     private static class ExceptionTableEntry {
       
   763         public short startPc;
       
   764         public short endPc;
       
   765         public short handlerPc;
       
   766         public short catchType;
       
   767 
       
   768         public ExceptionTableEntry(short startPc, short endPc,
       
   769                                    short handlerPc, short catchType)
       
   770         {
       
   771             this.startPc = startPc;
       
   772             this.endPc = endPc;
       
   773             this.handlerPc = handlerPc;
       
   774             this.catchType = catchType;
       
   775         }
       
   776     };
       
   777 
       
   778     /**
       
   779      * A MethodInfo object contains information about a particular method
       
   780      * in the class being generated.  This class mirrors the data items of
       
   781      * the "method_info" structure of the class file format (see JVMS 4.6).
       
   782      */
       
   783     private class MethodInfo {
       
   784         public int accessFlags;
       
   785         public String name;
       
   786         public String descriptor;
       
   787         public short maxStack;
       
   788         public short maxLocals;
       
   789         public ByteArrayOutputStream code = new ByteArrayOutputStream();
       
   790         public List<ExceptionTableEntry> exceptionTable =
       
   791             new ArrayList<ExceptionTableEntry>();
       
   792         public short[] declaredExceptions;
       
   793 
       
   794         public MethodInfo(String name, String descriptor, int accessFlags) {
       
   795             this.name = name;
       
   796             this.descriptor = descriptor;
       
   797             this.accessFlags = accessFlags;
       
   798 
       
   799             /*
       
   800              * Make sure that constant pool indexes are reserved for the
       
   801              * following items before starting to write the final class file.
       
   802              */
       
   803             cp.getUtf8(name);
       
   804             cp.getUtf8(descriptor);
       
   805             cp.getUtf8("Code");
       
   806             cp.getUtf8("Exceptions");
       
   807         }
       
   808 
       
   809         public void write(DataOutputStream out) throws IOException {
       
   810             /*
       
   811              * Write all the items of the "method_info" structure.
       
   812              * See JVMS section 4.6.
       
   813              */
       
   814                                         // u2 access_flags;
       
   815             out.writeShort(accessFlags);
       
   816                                         // u2 name_index;
       
   817             out.writeShort(cp.getUtf8(name));
       
   818                                         // u2 descriptor_index;
       
   819             out.writeShort(cp.getUtf8(descriptor));
       
   820                                         // u2 attributes_count;
       
   821             out.writeShort(2);  // (two method_info attributes:)
       
   822 
       
   823             // Write "Code" attribute. See JVMS section 4.7.3.
       
   824 
       
   825                                         // u2 attribute_name_index;
       
   826             out.writeShort(cp.getUtf8("Code"));
       
   827                                         // u4 attribute_length;
       
   828             out.writeInt(12 + code.size() + 8 * exceptionTable.size());
       
   829                                         // u2 max_stack;
       
   830             out.writeShort(maxStack);
       
   831                                         // u2 max_locals;
       
   832             out.writeShort(maxLocals);
       
   833                                         // u2 code_length;
       
   834             out.writeInt(code.size());
       
   835                                         // u1 code[code_length];
       
   836             code.writeTo(out);
       
   837                                         // u2 exception_table_length;
       
   838             out.writeShort(exceptionTable.size());
       
   839             for (ExceptionTableEntry e : exceptionTable) {
       
   840                                         // u2 start_pc;
       
   841                 out.writeShort(e.startPc);
       
   842                                         // u2 end_pc;
       
   843                 out.writeShort(e.endPc);
       
   844                                         // u2 handler_pc;
       
   845                 out.writeShort(e.handlerPc);
       
   846                                         // u2 catch_type;
       
   847                 out.writeShort(e.catchType);
       
   848             }
       
   849                                         // u2 attributes_count;
       
   850             out.writeShort(0);
       
   851 
       
   852             // write "Exceptions" attribute.  See JVMS section 4.7.4.
       
   853 
       
   854                                         // u2 attribute_name_index;
       
   855             out.writeShort(cp.getUtf8("Exceptions"));
       
   856                                         // u4 attributes_length;
       
   857             out.writeInt(2 + 2 * declaredExceptions.length);
       
   858                                         // u2 number_of_exceptions;
       
   859             out.writeShort(declaredExceptions.length);
       
   860                         // u2 exception_index_table[number_of_exceptions];
       
   861             for (short value : declaredExceptions) {
       
   862                 out.writeShort(value);
       
   863             }
       
   864         }
       
   865 
       
   866     }
       
   867 
       
   868     /**
       
   869      * A ProxyMethod object represents a proxy method in the proxy class
       
   870      * being generated: a method whose implementation will encode and
       
   871      * dispatch invocations to the proxy instance's invocation handler.
       
   872      */
       
   873     private class ProxyMethod {
       
   874 
       
   875         public String methodName;
       
   876         public Class<?>[] parameterTypes;
       
   877         public Class<?> returnType;
       
   878         public Class<?>[] exceptionTypes;
       
   879         public Class<?> fromClass;
       
   880         public String methodFieldName;
       
   881 
       
   882         private ProxyMethod(String methodName, Class<?>[] parameterTypes,
       
   883                             Class<?> returnType, Class<?>[] exceptionTypes,
       
   884                             Class<?> fromClass)
       
   885         {
       
   886             this.methodName = methodName;
       
   887             this.parameterTypes = parameterTypes;
       
   888             this.returnType = returnType;
       
   889             this.exceptionTypes = exceptionTypes;
       
   890             this.fromClass = fromClass;
       
   891             this.methodFieldName = "m" + proxyMethodCount++;
       
   892         }
       
   893 
       
   894         /**
       
   895          * Return a MethodInfo object for this method, including generating
       
   896          * the code and exception table entry.
       
   897          */
       
   898         private MethodInfo generateMethod() throws IOException {
       
   899             String desc = getMethodDescriptor(parameterTypes, returnType);
       
   900             MethodInfo minfo = new MethodInfo(methodName, desc,
       
   901                 ACC_PUBLIC | ACC_FINAL);
       
   902 
       
   903             int[] parameterSlot = new int[parameterTypes.length];
       
   904             int nextSlot = 1;
       
   905             for (int i = 0; i < parameterSlot.length; i++) {
       
   906                 parameterSlot[i] = nextSlot;
       
   907                 nextSlot += getWordsPerType(parameterTypes[i]);
       
   908             }
       
   909             int localSlot0 = nextSlot;
       
   910             short pc, tryBegin = 0, tryEnd;
       
   911 
       
   912             DataOutputStream out = new DataOutputStream(minfo.code);
       
   913 
       
   914             code_aload(0, out);
       
   915 
       
   916             out.writeByte(opc_getfield);
       
   917             out.writeShort(cp.getFieldRef(
       
   918                 superclassName,
       
   919                 handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));
       
   920 
       
   921             code_aload(0, out);
       
   922 
       
   923             out.writeByte(opc_getstatic);
       
   924             out.writeShort(cp.getFieldRef(
       
   925                 dotToSlash(className),
       
   926                 methodFieldName, "Ljava/lang/reflect/Method;"));
       
   927 
       
   928             if (parameterTypes.length > 0) {
       
   929 
       
   930                 code_ipush(parameterTypes.length, out);
       
   931 
       
   932                 out.writeByte(opc_anewarray);
       
   933                 out.writeShort(cp.getClass("java/lang/Object"));
       
   934 
       
   935                 for (int i = 0; i < parameterTypes.length; i++) {
       
   936 
       
   937                     out.writeByte(opc_dup);
       
   938 
       
   939                     code_ipush(i, out);
       
   940 
       
   941                     codeWrapArgument(parameterTypes[i], parameterSlot[i], out);
       
   942 
       
   943                     out.writeByte(opc_aastore);
       
   944                 }
       
   945             } else {
       
   946 
       
   947                 out.writeByte(opc_aconst_null);
       
   948             }
       
   949 
       
   950             out.writeByte(opc_invokeinterface);
       
   951             out.writeShort(cp.getInterfaceMethodRef(
       
   952                 "java/lang/reflect/InvocationHandler",
       
   953                 "invoke",
       
   954                 "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
       
   955                     "[Ljava/lang/Object;)Ljava/lang/Object;"));
       
   956             out.writeByte(4);
       
   957             out.writeByte(0);
       
   958 
       
   959             if (returnType == void.class) {
       
   960 
       
   961                 out.writeByte(opc_pop);
       
   962 
       
   963                 out.writeByte(opc_return);
       
   964 
       
   965             } else {
       
   966 
       
   967                 codeUnwrapReturnValue(returnType, out);
       
   968             }
       
   969 
       
   970             tryEnd = pc = (short) minfo.code.size();
       
   971 
       
   972             List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes);
       
   973             if (catchList.size() > 0) {
       
   974 
       
   975                 for (Class<?> ex : catchList) {
       
   976                     minfo.exceptionTable.add(new ExceptionTableEntry(
       
   977                         tryBegin, tryEnd, pc,
       
   978                         cp.getClass(dotToSlash(ex.getName()))));
       
   979                 }
       
   980 
       
   981                 out.writeByte(opc_athrow);
       
   982 
       
   983                 pc = (short) minfo.code.size();
       
   984 
       
   985                 minfo.exceptionTable.add(new ExceptionTableEntry(
       
   986                     tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable")));
       
   987 
       
   988                 code_astore(localSlot0, out);
       
   989 
       
   990                 out.writeByte(opc_new);
       
   991                 out.writeShort(cp.getClass(
       
   992                     "java/lang/reflect/UndeclaredThrowableException"));
       
   993 
       
   994                 out.writeByte(opc_dup);
       
   995 
       
   996                 code_aload(localSlot0, out);
       
   997 
       
   998                 out.writeByte(opc_invokespecial);
       
   999 
       
  1000                 out.writeShort(cp.getMethodRef(
       
  1001                     "java/lang/reflect/UndeclaredThrowableException",
       
  1002                     "<init>", "(Ljava/lang/Throwable;)V"));
       
  1003 
       
  1004                 out.writeByte(opc_athrow);
       
  1005             }
       
  1006 
       
  1007             if (minfo.code.size() > 65535) {
       
  1008                 throw new IllegalArgumentException("code size limit exceeded");
       
  1009             }
       
  1010 
       
  1011             minfo.maxStack = 10;
       
  1012             minfo.maxLocals = (short) (localSlot0 + 1);
       
  1013             minfo.declaredExceptions = new short[exceptionTypes.length];
       
  1014             for (int i = 0; i < exceptionTypes.length; i++) {
       
  1015                 minfo.declaredExceptions[i] = cp.getClass(
       
  1016                     dotToSlash(exceptionTypes[i].getName()));
       
  1017             }
       
  1018 
       
  1019             return minfo;
       
  1020         }
       
  1021 
       
  1022         /**
       
  1023          * Generate code for wrapping an argument of the given type
       
  1024          * whose value can be found at the specified local variable
       
  1025          * index, in order for it to be passed (as an Object) to the
       
  1026          * invocation handler's "invoke" method.  The code is written
       
  1027          * to the supplied stream.
       
  1028          */
       
  1029         private void codeWrapArgument(Class<?> type, int slot,
       
  1030                                       DataOutputStream out)
       
  1031             throws IOException
       
  1032         {
       
  1033             if (type.isPrimitive()) {
       
  1034                 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
       
  1035 
       
  1036                 if (type == int.class ||
       
  1037                     type == boolean.class ||
       
  1038                     type == byte.class ||
       
  1039                     type == char.class ||
       
  1040                     type == short.class)
       
  1041                 {
       
  1042                     code_iload(slot, out);
       
  1043                 } else if (type == long.class) {
       
  1044                     code_lload(slot, out);
       
  1045                 } else if (type == float.class) {
       
  1046                     code_fload(slot, out);
       
  1047                 } else if (type == double.class) {
       
  1048                     code_dload(slot, out);
       
  1049                 } else {
       
  1050                     throw new AssertionError();
       
  1051                 }
       
  1052 
       
  1053                 out.writeByte(opc_invokestatic);
       
  1054                 out.writeShort(cp.getMethodRef(
       
  1055                     prim.wrapperClassName,
       
  1056                     "valueOf", prim.wrapperValueOfDesc));
       
  1057 
       
  1058             } else {
       
  1059 
       
  1060                 code_aload(slot, out);
       
  1061             }
       
  1062         }
       
  1063 
       
  1064         /**
       
  1065          * Generate code for unwrapping a return value of the given
       
  1066          * type from the invocation handler's "invoke" method (as type
       
  1067          * Object) to its correct type.  The code is written to the
       
  1068          * supplied stream.
       
  1069          */
       
  1070         private void codeUnwrapReturnValue(Class<?> type, DataOutputStream out)
       
  1071             throws IOException
       
  1072         {
       
  1073             if (type.isPrimitive()) {
       
  1074                 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
       
  1075 
       
  1076                 out.writeByte(opc_checkcast);
       
  1077                 out.writeShort(cp.getClass(prim.wrapperClassName));
       
  1078 
       
  1079                 out.writeByte(opc_invokevirtual);
       
  1080                 out.writeShort(cp.getMethodRef(
       
  1081                     prim.wrapperClassName,
       
  1082                     prim.unwrapMethodName, prim.unwrapMethodDesc));
       
  1083 
       
  1084                 if (type == int.class ||
       
  1085                     type == boolean.class ||
       
  1086                     type == byte.class ||
       
  1087                     type == char.class ||
       
  1088                     type == short.class)
       
  1089                 {
       
  1090                     out.writeByte(opc_ireturn);
       
  1091                 } else if (type == long.class) {
       
  1092                     out.writeByte(opc_lreturn);
       
  1093                 } else if (type == float.class) {
       
  1094                     out.writeByte(opc_freturn);
       
  1095                 } else if (type == double.class) {
       
  1096                     out.writeByte(opc_dreturn);
       
  1097                 } else {
       
  1098                     throw new AssertionError();
       
  1099                 }
       
  1100 
       
  1101             } else {
       
  1102 
       
  1103                 out.writeByte(opc_checkcast);
       
  1104                 out.writeShort(cp.getClass(dotToSlash(type.getName())));
       
  1105 
       
  1106                 out.writeByte(opc_areturn);
       
  1107             }
       
  1108         }
       
  1109 
       
  1110         /**
       
  1111          * Generate code for initializing the static field that stores
       
  1112          * the Method object for this proxy method.  The code is written
       
  1113          * to the supplied stream.
       
  1114          */
       
  1115         private void codeFieldInitialization(DataOutputStream out)
       
  1116             throws IOException
       
  1117         {
       
  1118             codeClassForName(fromClass, out);
       
  1119 
       
  1120             code_ldc(cp.getString(methodName), out);
       
  1121 
       
  1122             code_ipush(parameterTypes.length, out);
       
  1123 
       
  1124             out.writeByte(opc_anewarray);
       
  1125             out.writeShort(cp.getClass("java/lang/Class"));
       
  1126 
       
  1127             for (int i = 0; i < parameterTypes.length; i++) {
       
  1128 
       
  1129                 out.writeByte(opc_dup);
       
  1130 
       
  1131                 code_ipush(i, out);
       
  1132 
       
  1133                 if (parameterTypes[i].isPrimitive()) {
       
  1134                     PrimitiveTypeInfo prim =
       
  1135                         PrimitiveTypeInfo.get(parameterTypes[i]);
       
  1136 
       
  1137                     out.writeByte(opc_getstatic);
       
  1138                     out.writeShort(cp.getFieldRef(
       
  1139                         prim.wrapperClassName, "TYPE", "Ljava/lang/Class;"));
       
  1140 
       
  1141                 } else {
       
  1142                     codeClassForName(parameterTypes[i], out);
       
  1143                 }
       
  1144 
       
  1145                 out.writeByte(opc_aastore);
       
  1146             }
       
  1147 
       
  1148             out.writeByte(opc_invokevirtual);
       
  1149             out.writeShort(cp.getMethodRef(
       
  1150                 "java/lang/Class",
       
  1151                 "getMethod",
       
  1152                 "(Ljava/lang/String;[Ljava/lang/Class;)" +
       
  1153                 "Ljava/lang/reflect/Method;"));
       
  1154 
       
  1155             out.writeByte(opc_putstatic);
       
  1156             out.writeShort(cp.getFieldRef(
       
  1157                 dotToSlash(className),
       
  1158                 methodFieldName, "Ljava/lang/reflect/Method;"));
       
  1159         }
       
  1160     }
       
  1161 
       
  1162     /**
       
  1163      * Generate the constructor method for the proxy class.
       
  1164      */
       
  1165     private MethodInfo generateConstructor() throws IOException {
       
  1166         MethodInfo minfo = new MethodInfo(
       
  1167             "<init>", "(Ljava/lang/reflect/InvocationHandler;)V",
       
  1168             ACC_PUBLIC);
       
  1169 
       
  1170         DataOutputStream out = new DataOutputStream(minfo.code);
       
  1171 
       
  1172         code_aload(0, out);
       
  1173 
       
  1174         code_aload(1, out);
       
  1175 
       
  1176         out.writeByte(opc_invokespecial);
       
  1177         out.writeShort(cp.getMethodRef(
       
  1178             superclassName,
       
  1179             "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
       
  1180 
       
  1181         out.writeByte(opc_return);
       
  1182 
       
  1183         minfo.maxStack = 10;
       
  1184         minfo.maxLocals = 2;
       
  1185         minfo.declaredExceptions = new short[0];
       
  1186 
       
  1187         return minfo;
       
  1188     }
       
  1189 
       
  1190     /**
       
  1191      * Generate the static initializer method for the proxy class.
       
  1192      */
       
  1193     private MethodInfo generateStaticInitializer() throws IOException {
       
  1194         MethodInfo minfo = new MethodInfo(
       
  1195             "<clinit>", "()V", ACC_STATIC);
       
  1196 
       
  1197         int localSlot0 = 1;
       
  1198         short pc, tryBegin = 0, tryEnd;
       
  1199 
       
  1200         DataOutputStream out = new DataOutputStream(minfo.code);
       
  1201 
       
  1202         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
       
  1203             for (ProxyMethod pm : sigmethods) {
       
  1204                 pm.codeFieldInitialization(out);
       
  1205             }
       
  1206         }
       
  1207 
       
  1208         out.writeByte(opc_return);
       
  1209 
       
  1210         tryEnd = pc = (short) minfo.code.size();
       
  1211 
       
  1212         minfo.exceptionTable.add(new ExceptionTableEntry(
       
  1213             tryBegin, tryEnd, pc,
       
  1214             cp.getClass("java/lang/NoSuchMethodException")));
       
  1215 
       
  1216         code_astore(localSlot0, out);
       
  1217 
       
  1218         out.writeByte(opc_new);
       
  1219         out.writeShort(cp.getClass("java/lang/NoSuchMethodError"));
       
  1220 
       
  1221         out.writeByte(opc_dup);
       
  1222 
       
  1223         code_aload(localSlot0, out);
       
  1224 
       
  1225         out.writeByte(opc_invokevirtual);
       
  1226         out.writeShort(cp.getMethodRef(
       
  1227             "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
       
  1228 
       
  1229         out.writeByte(opc_invokespecial);
       
  1230         out.writeShort(cp.getMethodRef(
       
  1231             "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V"));
       
  1232 
       
  1233         out.writeByte(opc_athrow);
       
  1234 
       
  1235         pc = (short) minfo.code.size();
       
  1236 
       
  1237         minfo.exceptionTable.add(new ExceptionTableEntry(
       
  1238             tryBegin, tryEnd, pc,
       
  1239             cp.getClass("java/lang/ClassNotFoundException")));
       
  1240 
       
  1241         code_astore(localSlot0, out);
       
  1242 
       
  1243         out.writeByte(opc_new);
       
  1244         out.writeShort(cp.getClass("java/lang/NoClassDefFoundError"));
       
  1245 
       
  1246         out.writeByte(opc_dup);
       
  1247 
       
  1248         code_aload(localSlot0, out);
       
  1249 
       
  1250         out.writeByte(opc_invokevirtual);
       
  1251         out.writeShort(cp.getMethodRef(
       
  1252             "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
       
  1253 
       
  1254         out.writeByte(opc_invokespecial);
       
  1255         out.writeShort(cp.getMethodRef(
       
  1256             "java/lang/NoClassDefFoundError",
       
  1257             "<init>", "(Ljava/lang/String;)V"));
       
  1258 
       
  1259         out.writeByte(opc_athrow);
       
  1260 
       
  1261         if (minfo.code.size() > 65535) {
       
  1262             throw new IllegalArgumentException("code size limit exceeded");
       
  1263         }
       
  1264 
       
  1265         minfo.maxStack = 10;
       
  1266         minfo.maxLocals = (short) (localSlot0 + 1);
       
  1267         minfo.declaredExceptions = new short[0];
       
  1268 
       
  1269         return minfo;
       
  1270     }
       
  1271 
       
  1272 
       
  1273     /*
       
  1274      * =============== Code Generation Utility Methods ===============
       
  1275      */
       
  1276 
       
  1277     /*
       
  1278      * The following methods generate code for the load or store operation
       
  1279      * indicated by their name for the given local variable.  The code is
       
  1280      * written to the supplied stream.
       
  1281      */
       
  1282 
       
  1283     private void code_iload(int lvar, DataOutputStream out)
       
  1284         throws IOException
       
  1285     {
       
  1286         codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out);
       
  1287     }
       
  1288 
       
  1289     private void code_lload(int lvar, DataOutputStream out)
       
  1290         throws IOException
       
  1291     {
       
  1292         codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out);
       
  1293     }
       
  1294 
       
  1295     private void code_fload(int lvar, DataOutputStream out)
       
  1296         throws IOException
       
  1297     {
       
  1298         codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out);
       
  1299     }
       
  1300 
       
  1301     private void code_dload(int lvar, DataOutputStream out)
       
  1302         throws IOException
       
  1303     {
       
  1304         codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out);
       
  1305     }
       
  1306 
       
  1307     private void code_aload(int lvar, DataOutputStream out)
       
  1308         throws IOException
       
  1309     {
       
  1310         codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out);
       
  1311     }
       
  1312 
       
  1313 //  private void code_istore(int lvar, DataOutputStream out)
       
  1314 //      throws IOException
       
  1315 //  {
       
  1316 //      codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out);
       
  1317 //  }
       
  1318 
       
  1319 //  private void code_lstore(int lvar, DataOutputStream out)
       
  1320 //      throws IOException
       
  1321 //  {
       
  1322 //      codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out);
       
  1323 //  }
       
  1324 
       
  1325 //  private void code_fstore(int lvar, DataOutputStream out)
       
  1326 //      throws IOException
       
  1327 //  {
       
  1328 //      codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out);
       
  1329 //  }
       
  1330 
       
  1331 //  private void code_dstore(int lvar, DataOutputStream out)
       
  1332 //      throws IOException
       
  1333 //  {
       
  1334 //      codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out);
       
  1335 //  }
       
  1336 
       
  1337     private void code_astore(int lvar, DataOutputStream out)
       
  1338         throws IOException
       
  1339     {
       
  1340         codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out);
       
  1341     }
       
  1342 
       
  1343     /**
       
  1344      * Generate code for a load or store instruction for the given local
       
  1345      * variable.  The code is written to the supplied stream.
       
  1346      *
       
  1347      * "opcode" indicates the opcode form of the desired load or store
       
  1348      * instruction that takes an explicit local variable index, and
       
  1349      * "opcode_0" indicates the corresponding form of the instruction
       
  1350      * with the implicit index 0.
       
  1351      */
       
  1352     private void codeLocalLoadStore(int lvar, int opcode, int opcode_0,
       
  1353                                     DataOutputStream out)
       
  1354         throws IOException
       
  1355     {
       
  1356         assert lvar >= 0 && lvar <= 0xFFFF;
       
  1357         if (lvar <= 3) {
       
  1358             out.writeByte(opcode_0 + lvar);
       
  1359         } else if (lvar <= 0xFF) {
       
  1360             out.writeByte(opcode);
       
  1361             out.writeByte(lvar & 0xFF);
       
  1362         } else {
       
  1363             /*
       
  1364              * Use the "wide" instruction modifier for local variable
       
  1365              * indexes that do not fit into an unsigned byte.
       
  1366              */
       
  1367             out.writeByte(opc_wide);
       
  1368             out.writeByte(opcode);
       
  1369             out.writeShort(lvar & 0xFFFF);
       
  1370         }
       
  1371     }
       
  1372 
       
  1373     /**
       
  1374      * Generate code for an "ldc" instruction for the given constant pool
       
  1375      * index (the "ldc_w" instruction is used if the index does not fit
       
  1376      * into an unsigned byte).  The code is written to the supplied stream.
       
  1377      */
       
  1378     private void code_ldc(int index, DataOutputStream out)
       
  1379         throws IOException
       
  1380     {
       
  1381         assert index >= 0 && index <= 0xFFFF;
       
  1382         if (index <= 0xFF) {
       
  1383             out.writeByte(opc_ldc);
       
  1384             out.writeByte(index & 0xFF);
       
  1385         } else {
       
  1386             out.writeByte(opc_ldc_w);
       
  1387             out.writeShort(index & 0xFFFF);
       
  1388         }
       
  1389     }
       
  1390 
       
  1391     /**
       
  1392      * Generate code to push a constant integer value on to the operand
       
  1393      * stack, using the "iconst_<i>", "bipush", or "sipush" instructions
       
  1394      * depending on the size of the value.  The code is written to the
       
  1395      * supplied stream.
       
  1396      */
       
  1397     private void code_ipush(int value, DataOutputStream out)
       
  1398         throws IOException
       
  1399     {
       
  1400         if (value >= -1 && value <= 5) {
       
  1401             out.writeByte(opc_iconst_0 + value);
       
  1402         } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
       
  1403             out.writeByte(opc_bipush);
       
  1404             out.writeByte(value & 0xFF);
       
  1405         } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
       
  1406             out.writeByte(opc_sipush);
       
  1407             out.writeShort(value & 0xFFFF);
       
  1408         } else {
       
  1409             throw new AssertionError();
       
  1410         }
       
  1411     }
       
  1412 
       
  1413     /**
       
  1414      * Generate code to invoke the Class.forName with the name of the given
       
  1415      * class to get its Class object at runtime.  The code is written to
       
  1416      * the supplied stream.  Note that the code generated by this method
       
  1417      * may cause the checked ClassNotFoundException to be thrown.
       
  1418      */
       
  1419     private void codeClassForName(Class<?> cl, DataOutputStream out)
       
  1420         throws IOException
       
  1421     {
       
  1422         code_ldc(cp.getString(cl.getName()), out);
       
  1423 
       
  1424         out.writeByte(opc_invokestatic);
       
  1425         out.writeShort(cp.getMethodRef(
       
  1426             "java/lang/Class",
       
  1427             "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));
       
  1428     }
       
  1429 
       
  1430 
       
  1431     /*
       
  1432      * ==================== General Utility Methods ====================
       
  1433      */
       
  1434 
       
  1435     /**
       
  1436      * Convert a fully qualified class name that uses '.' as the package
       
  1437      * separator, the external representation used by the Java language
       
  1438      * and APIs, to a fully qualified class name that uses '/' as the
       
  1439      * package separator, the representation used in the class file
       
  1440      * format (see JVMS section 4.2).
       
  1441      */
       
  1442     private static String dotToSlash(String name) {
       
  1443         return name.replace('.', '/');
       
  1444     }
       
  1445 
       
  1446     /**
       
  1447      * Return the "method descriptor" string for a method with the given
       
  1448      * parameter types and return type.  See JVMS section 4.3.3.
       
  1449      */
       
  1450     private static String getMethodDescriptor(Class<?>[] parameterTypes,
       
  1451                                               Class<?> returnType)
       
  1452     {
       
  1453         return getParameterDescriptors(parameterTypes) +
       
  1454             ((returnType == void.class) ? "V" : getFieldType(returnType));
       
  1455     }
       
  1456 
       
  1457     /**
       
  1458      * Return the list of "parameter descriptor" strings enclosed in
       
  1459      * parentheses corresponding to the given parameter types (in other
       
  1460      * words, a method descriptor without a return descriptor).  This
       
  1461      * string is useful for constructing string keys for methods without
       
  1462      * regard to their return type.
       
  1463      */
       
  1464     private static String getParameterDescriptors(Class<?>[] parameterTypes) {
       
  1465         StringBuilder desc = new StringBuilder("(");
       
  1466         for (int i = 0; i < parameterTypes.length; i++) {
       
  1467             desc.append(getFieldType(parameterTypes[i]));
       
  1468         }
       
  1469         desc.append(')');
       
  1470         return desc.toString();
       
  1471     }
       
  1472 
       
  1473     /**
       
  1474      * Return the "field type" string for the given type, appropriate for
       
  1475      * a field descriptor, a parameter descriptor, or a return descriptor
       
  1476      * other than "void".  See JVMS section 4.3.2.
       
  1477      */
       
  1478     private static String getFieldType(Class<?> type) {
       
  1479         if (type.isPrimitive()) {
       
  1480             return PrimitiveTypeInfo.get(type).baseTypeString;
       
  1481         } else if (type.isArray()) {
       
  1482             /*
       
  1483              * According to JLS 20.3.2, the getName() method on Class does
       
  1484              * return the VM type descriptor format for array classes (only);
       
  1485              * using that should be quicker than the otherwise obvious code:
       
  1486              *
       
  1487              *     return "[" + getTypeDescriptor(type.getComponentType());
       
  1488              */
       
  1489             return type.getName().replace('.', '/');
       
  1490         } else {
       
  1491             return "L" + dotToSlash(type.getName()) + ";";
       
  1492         }
       
  1493     }
       
  1494 
       
  1495     /**
       
  1496      * Returns a human-readable string representing the signature of a
       
  1497      * method with the given name and parameter types.
       
  1498      */
       
  1499     private static String getFriendlyMethodSignature(String name,
       
  1500                                                      Class<?>[] parameterTypes)
       
  1501     {
       
  1502         StringBuilder sig = new StringBuilder(name);
       
  1503         sig.append('(');
       
  1504         for (int i = 0; i < parameterTypes.length; i++) {
       
  1505             if (i > 0) {
       
  1506                 sig.append(',');
       
  1507             }
       
  1508             Class<?> parameterType = parameterTypes[i];
       
  1509             int dimensions = 0;
       
  1510             while (parameterType.isArray()) {
       
  1511                 parameterType = parameterType.getComponentType();
       
  1512                 dimensions++;
       
  1513             }
       
  1514             sig.append(parameterType.getName());
       
  1515             while (dimensions-- > 0) {
       
  1516                 sig.append("[]");
       
  1517             }
       
  1518         }
       
  1519         sig.append(')');
       
  1520         return sig.toString();
       
  1521     }
       
  1522 
       
  1523     /**
       
  1524      * Return the number of abstract "words", or consecutive local variable
       
  1525      * indexes, required to contain a value of the given type.  See JVMS
       
  1526      * section 3.6.1.
       
  1527      *
       
  1528      * Note that the original version of the JVMS contained a definition of
       
  1529      * this abstract notion of a "word" in section 3.4, but that definition
       
  1530      * was removed for the second edition.
       
  1531      */
       
  1532     private static int getWordsPerType(Class<?> type) {
       
  1533         if (type == long.class || type == double.class) {
       
  1534             return 2;
       
  1535         } else {
       
  1536             return 1;
       
  1537         }
       
  1538     }
       
  1539 
       
  1540     /**
       
  1541      * Add to the given list all of the types in the "from" array that
       
  1542      * are not already contained in the list and are assignable to at
       
  1543      * least one of the types in the "with" array.
       
  1544      *
       
  1545      * This method is useful for computing the greatest common set of
       
  1546      * declared exceptions from duplicate methods inherited from
       
  1547      * different interfaces.
       
  1548      */
       
  1549     private static void collectCompatibleTypes(Class<?>[] from,
       
  1550                                                Class<?>[] with,
       
  1551                                                List<Class<?>> list)
       
  1552     {
       
  1553         for (Class<?> fc: from) {
       
  1554             if (!list.contains(fc)) {
       
  1555                 for (Class<?> wc: with) {
       
  1556                     if (wc.isAssignableFrom(fc)) {
       
  1557                         list.add(fc);
       
  1558                         break;
       
  1559                     }
       
  1560                 }
       
  1561             }
       
  1562         }
   306         }
  1563     }
   307     }
  1564 
   308 
  1565     /**
   309     /**
  1566      * Given the exceptions declared in the throws clause of a proxy method,
   310      * Given the exceptions declared in the throws clause of a proxy method,
  1583      * given list of declared exceptions, indicating that no exceptions
   327      * given list of declared exceptions, indicating that no exceptions
  1584      * need to be caught.
   328      * need to be caught.
  1585      */
   329      */
  1586     private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {
   330     private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {
  1587         List<Class<?>> uniqueList = new ArrayList<>();
   331         List<Class<?>> uniqueList = new ArrayList<>();
  1588                                                 // unique exceptions to catch
   332         // unique exceptions to catch
  1589 
   333 
  1590         uniqueList.add(Error.class);            // always catch/rethrow these
   334         uniqueList.add(Error.class);            // always catch/rethrow these
  1591         uniqueList.add(RuntimeException.class);
   335         uniqueList.add(RuntimeException.class);
  1592 
   336 
  1593     nextException:
   337         nextException:
  1594         for (Class<?> ex: exceptions) {
   338         for (Class<?> ex : exceptions) {
  1595             if (ex.isAssignableFrom(Throwable.class)) {
   339             if (ex.isAssignableFrom(Throwable.class)) {
  1596                 /*
   340                 /*
  1597                  * If Throwable is declared to be thrown by the proxy method,
   341                  * If Throwable is declared to be thrown by the proxy method,
  1598                  * then no catch blocks are necessary, because the invoke
   342                  * then no catch blocks are necessary, because the invoke
  1599                  * can, at most, throw Throwable anyway.
   343                  * can, at most, throw Throwable anyway.
  1608             }
   352             }
  1609             /*
   353             /*
  1610              * Compare this exception against the current list of
   354              * Compare this exception against the current list of
  1611              * exceptions that need to be caught:
   355              * exceptions that need to be caught:
  1612              */
   356              */
  1613             for (int j = 0; j < uniqueList.size();) {
   357             for (int j = 0; j < uniqueList.size(); ) {
  1614                 Class<?> ex2 = uniqueList.get(j);
   358                 Class<?> ex2 = uniqueList.get(j);
  1615                 if (ex2.isAssignableFrom(ex)) {
   359                 if (ex2.isAssignableFrom(ex)) {
  1616                     /*
   360                     /*
  1617                      * if a superclass of this exception is already on
   361                      * if a superclass of this exception is already on
  1618                      * the list to catch, then ignore this one and continue;
   362                      * the list to catch, then ignore this one and continue;
  1633         }
   377         }
  1634         return uniqueList;
   378         return uniqueList;
  1635     }
   379     }
  1636 
   380 
  1637     /**
   381     /**
       
   382      * Convert a fully qualified class name that uses '.' as the package
       
   383      * separator, the external representation used by the Java language
       
   384      * and APIs, to a fully qualified class name that uses '/' as the
       
   385      * package separator, the representation used in the class file
       
   386      * format (see JVMS section 4.2).
       
   387      */
       
   388     private static String dotToSlash(String name) {
       
   389         return name.replace('.', '/');
       
   390     }
       
   391 
       
   392     /**
       
   393      * Return the number of abstract "words", or consecutive local variable
       
   394      * indexes, required to contain a value of the given type.  See JVMS
       
   395      * section 3.6.1.
       
   396      * <p>
       
   397      * Note that the original version of the JVMS contained a definition of
       
   398      * this abstract notion of a "word" in section 3.4, but that definition
       
   399      * was removed for the second edition.
       
   400      */
       
   401     private static int getWordsPerType(Class<?> type) {
       
   402         if (type == long.class || type == double.class) {
       
   403             return 2;
       
   404         } else {
       
   405             return 1;
       
   406         }
       
   407     }
       
   408 
       
   409     /**
       
   410      * Add to the given list all of the types in the "from" array that
       
   411      * are not already contained in the list and are assignable to at
       
   412      * least one of the types in the "with" array.
       
   413      * <p>
       
   414      * This method is useful for computing the greatest common set of
       
   415      * declared exceptions from duplicate methods inherited from
       
   416      * different interfaces.
       
   417      */
       
   418     private static void collectCompatibleTypes(Class<?>[] from,
       
   419                                                Class<?>[] with,
       
   420                                                List<Class<?>> list) {
       
   421         for (Class<?> fc : from) {
       
   422             if (!list.contains(fc)) {
       
   423                 for (Class<?> wc : with) {
       
   424                     if (wc.isAssignableFrom(fc)) {
       
   425                         list.add(fc);
       
   426                         break;
       
   427                     }
       
   428                 }
       
   429             }
       
   430         }
       
   431     }
       
   432 
       
   433     /**
       
   434      * Returns the {@link ClassLoader} to be used by the default implementation of {@link
       
   435      * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
       
   436      * default.
       
   437      *
       
   438      * @return ClassLoader
       
   439      */
       
   440     protected ClassLoader getClassLoader() {
       
   441         return loader;
       
   442     }
       
   443 
       
   444     /**
       
   445      * Generate a class file for the proxy class.  This method drives the
       
   446      * class file generation process.
       
   447      */
       
   448     private byte[] generateClassFile() {
       
   449         visit(V14, accessFlags, dotToSlash(className), null,
       
   450                 JLR_PROXY, typeNames(interfaces));
       
   451 
       
   452         /*
       
   453          * Add proxy methods for the hashCode, equals,
       
   454          * and toString methods of java.lang.Object.  This is done before
       
   455          * the methods from the proxy interfaces so that the methods from
       
   456          * java.lang.Object take precedence over duplicate methods in the
       
   457          * proxy interfaces.
       
   458          */
       
   459         addProxyMethod(hashCodeMethod);
       
   460         addProxyMethod(equalsMethod);
       
   461         addProxyMethod(toStringMethod);
       
   462 
       
   463         /*
       
   464          * Accumulate all of the methods from the proxy interfaces.
       
   465          */
       
   466         for (Class<?> intf : interfaces) {
       
   467             for (Method m : intf.getMethods()) {
       
   468                 if (!Modifier.isStatic(m.getModifiers())) {
       
   469                     addProxyMethod(m, intf);
       
   470                 }
       
   471             }
       
   472         }
       
   473 
       
   474         /*
       
   475          * For each set of proxy methods with the same signature,
       
   476          * verify that the methods' return types are compatible.
       
   477          */
       
   478         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
       
   479             checkReturnTypes(sigmethods);
       
   480         }
       
   481 
       
   482         generateConstructor();
       
   483 
       
   484         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
       
   485             for (ProxyMethod pm : sigmethods) {
       
   486                 // add static field for the Method object
       
   487                 visitField(Modifier.PRIVATE | Modifier.STATIC, pm.methodFieldName,
       
   488                         LJLR_METHOD, null, null);
       
   489 
       
   490                 // Generate code for proxy method
       
   491                 pm.generateMethod(this, className);
       
   492             }
       
   493         }
       
   494 
       
   495         generateStaticInitializer();
       
   496 
       
   497         return toByteArray();
       
   498     }
       
   499 
       
   500     /**
       
   501      * Add another method to be proxied, either by creating a new
       
   502      * ProxyMethod object or augmenting an old one for a duplicate
       
   503      * method.
       
   504      *
       
   505      * "fromClass" indicates the proxy interface that the method was
       
   506      * found through, which may be different from (a subinterface of)
       
   507      * the method's "declaring class".  Note that the first Method
       
   508      * object passed for a given name and descriptor identifies the
       
   509      * Method object (and thus the declaring class) that will be
       
   510      * passed to the invocation handler's "invoke" method for a given
       
   511      * set of duplicate methods.
       
   512      */
       
   513     private void addProxyMethod(Method m, Class<?> fromClass) {
       
   514         Class<?> returnType = m.getReturnType();
       
   515         Class<?>[] exceptionTypes = m.getExceptionTypes();
       
   516 
       
   517         String sig = m.toShortSignature();
       
   518         List<ProxyMethod> sigmethods = proxyMethods.computeIfAbsent(sig,
       
   519                 (f) -> new ArrayList<>(3));
       
   520         for (ProxyMethod pm : sigmethods) {
       
   521             if (returnType == pm.returnType) {
       
   522                 /*
       
   523                  * Found a match: reduce exception types to the
       
   524                  * greatest set of exceptions that can be thrown
       
   525                  * compatibly with the throws clauses of both
       
   526                  * overridden methods.
       
   527                  */
       
   528                 List<Class<?>> legalExceptions = new ArrayList<>();
       
   529                 collectCompatibleTypes(
       
   530                         exceptionTypes, pm.exceptionTypes, legalExceptions);
       
   531                 collectCompatibleTypes(
       
   532                         pm.exceptionTypes, exceptionTypes, legalExceptions);
       
   533                 pm.exceptionTypes = legalExceptions.toArray(EMPTY_CLASS_ARRAY);
       
   534                 return;
       
   535             }
       
   536         }
       
   537         sigmethods.add(new ProxyMethod(m, sig, m.getParameterTypes(), returnType,
       
   538                 exceptionTypes, fromClass,
       
   539                 "m" + proxyMethodCount++));
       
   540     }
       
   541 
       
   542     /**
       
   543      * Add an existing ProxyMethod (hashcode, equals, toString).
       
   544      *
       
   545      * @param pm an existing ProxyMethod
       
   546      */
       
   547     private void addProxyMethod(ProxyMethod pm) {
       
   548         String sig = pm.shortSignature;
       
   549         List<ProxyMethod> sigmethods = proxyMethods.computeIfAbsent(sig,
       
   550                 (f) -> new ArrayList<>(3));
       
   551         sigmethods.add(pm);
       
   552     }
       
   553 
       
   554     /**
       
   555      * Generate the constructor method for the proxy class.
       
   556      */
       
   557     private void generateConstructor() {
       
   558         MethodVisitor ctor = visitMethod(Modifier.PUBLIC, NAME_CTOR,
       
   559                 MJLR_INVOCATIONHANDLER, null, null);
       
   560         ctor.visitParameter(null, 0);
       
   561         ctor.visitCode();
       
   562         ctor.visitVarInsn(ALOAD, 0);
       
   563         ctor.visitVarInsn(ALOAD, 1);
       
   564         ctor.visitMethodInsn(INVOKESPECIAL, JLR_PROXY, NAME_CTOR,
       
   565                 MJLR_INVOCATIONHANDLER, false);
       
   566         ctor.visitInsn(RETURN);
       
   567 
       
   568         // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
       
   569         ctor.visitMaxs(-1, -1);
       
   570         ctor.visitEnd();
       
   571     }
       
   572 
       
   573     /**
       
   574      * Generate the static initializer method for the proxy class.
       
   575      */
       
   576     private void generateStaticInitializer() {
       
   577 
       
   578         MethodVisitor mv = visitMethod(Modifier.STATIC, NAME_CLINIT,
       
   579                 "()V", null, null);
       
   580         mv.visitCode();
       
   581         Label L_startBlock = new Label();
       
   582         Label L_endBlock = new Label();
       
   583         Label L_NoMethodHandler = new Label();
       
   584         Label L_NoClassHandler = new Label();
       
   585 
       
   586         mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_NoMethodHandler,
       
   587                 JL_NO_SUCH_METHOD_EX);
       
   588         mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_NoClassHandler,
       
   589                 JL_CLASS_NOT_FOUND_EX);
       
   590 
       
   591         mv.visitLabel(L_startBlock);
       
   592         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
       
   593             for (ProxyMethod pm : sigmethods) {
       
   594                 pm.codeFieldInitialization(mv, className);
       
   595             }
       
   596         }
       
   597         mv.visitInsn(RETURN);
       
   598         mv.visitLabel(L_endBlock);
       
   599         // Generate exception handler
       
   600 
       
   601         mv.visitLabel(L_NoMethodHandler);
       
   602         mv.visitVarInsn(ASTORE, 1);
       
   603         mv.visitTypeInsn(Opcodes.NEW, JL_NO_SUCH_METHOD_ERROR);
       
   604         mv.visitInsn(DUP);
       
   605         mv.visitVarInsn(ALOAD, 1);
       
   606         mv.visitMethodInsn(INVOKEVIRTUAL, JL_THROWABLE,
       
   607                 "getMessage", "()Ljava/lang/String;", false);
       
   608         mv.visitMethodInsn(INVOKESPECIAL, JL_NO_SUCH_METHOD_ERROR,
       
   609                 "<init>", "(Ljava/lang/String;)V", false);
       
   610         mv.visitInsn(ATHROW);
       
   611 
       
   612         mv.visitLabel(L_NoClassHandler);
       
   613         mv.visitVarInsn(ASTORE, 1);
       
   614         mv.visitTypeInsn(Opcodes.NEW, JL_NO_CLASS_DEF_FOUND_ERROR);
       
   615         mv.visitInsn(DUP);
       
   616         mv.visitVarInsn(ALOAD, 1);
       
   617         mv.visitMethodInsn(INVOKEVIRTUAL, JL_THROWABLE,
       
   618                 "getMessage", "()Ljava/lang/String;", false);
       
   619         mv.visitMethodInsn(INVOKESPECIAL, JL_NO_CLASS_DEF_FOUND_ERROR,
       
   620                 "<init>", "(Ljava/lang/String;)V", false);
       
   621         mv.visitInsn(ATHROW);
       
   622 
       
   623         // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
       
   624         mv.visitMaxs(-1, -1);
       
   625         mv.visitEnd();
       
   626     }
       
   627 
       
   628     /**
       
   629      * A ProxyMethod object represents a proxy method in the proxy class
       
   630      * being generated: a method whose implementation will encode and
       
   631      * dispatch invocations to the proxy instance's invocation handler.
       
   632      */
       
   633     private static class ProxyMethod {
       
   634 
       
   635         private final Method method;
       
   636         private final String shortSignature;
       
   637         private final Class<?> fromClass;
       
   638         private final Class<?>[] parameterTypes;
       
   639         private final Class<?> returnType;
       
   640         private final String methodFieldName;
       
   641         private Class<?>[] exceptionTypes;
       
   642 
       
   643         private ProxyMethod(Method method, String sig, Class<?>[] parameterTypes,
       
   644                             Class<?> returnType, Class<?>[] exceptionTypes,
       
   645                             Class<?> fromClass, String methodFieldName) {
       
   646             this.method = method;
       
   647             this.shortSignature = sig;
       
   648             this.parameterTypes = parameterTypes;
       
   649             this.returnType = returnType;
       
   650             this.exceptionTypes = exceptionTypes;
       
   651             this.fromClass = fromClass;
       
   652             this.methodFieldName = methodFieldName;
       
   653         }
       
   654 
       
   655         /**
       
   656          * Create a new specific ProxyMethod with a specific field name
       
   657          *
       
   658          * @param method          The method for which to create a proxy
       
   659          * @param methodFieldName the fieldName to generate
       
   660          */
       
   661         private ProxyMethod(Method method, String methodFieldName) {
       
   662             this(method, method.toShortSignature(),
       
   663                     method.getParameterTypes(), method.getReturnType(),
       
   664                     method.getExceptionTypes(), method.getDeclaringClass(), methodFieldName);
       
   665         }
       
   666 
       
   667         /**
       
   668          * Generate this method, including the code and exception table entry.
       
   669          */
       
   670         private void generateMethod(ClassWriter cw, String className) {
       
   671             MethodType mt = MethodType.methodType(returnType, parameterTypes);
       
   672             String desc = mt.toMethodDescriptorString();
       
   673             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL,
       
   674                     method.getName(), desc, null,
       
   675                     typeNames(Arrays.asList(exceptionTypes)));
       
   676 
       
   677             int[] parameterSlot = new int[parameterTypes.length];
       
   678             int nextSlot = 1;
       
   679             for (int i = 0; i < parameterSlot.length; i++) {
       
   680                 parameterSlot[i] = nextSlot;
       
   681                 nextSlot += getWordsPerType(parameterTypes[i]);
       
   682             }
       
   683 
       
   684             mv.visitCode();
       
   685             Label L_startBlock = new Label();
       
   686             Label L_endBlock = new Label();
       
   687             Label L_RuntimeHandler = new Label();
       
   688             Label L_ThrowableHandler = new Label();
       
   689 
       
   690             List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes);
       
   691             if (catchList.size() > 0) {
       
   692                 for (Class<?> ex : catchList) {
       
   693                     mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_RuntimeHandler,
       
   694                             dotToSlash(ex.getName()));
       
   695                 }
       
   696 
       
   697                 mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_ThrowableHandler,
       
   698                         JL_THROWABLE);
       
   699             }
       
   700             mv.visitLabel(L_startBlock);
       
   701 
       
   702             mv.visitVarInsn(ALOAD, 0);
       
   703             mv.visitFieldInsn(GETFIELD, JLR_PROXY, handlerFieldName,
       
   704                     LJLR_INVOCATION_HANDLER);
       
   705             mv.visitVarInsn(ALOAD, 0);
       
   706             mv.visitFieldInsn(GETSTATIC, dotToSlash(className), methodFieldName,
       
   707                     LJLR_METHOD);
       
   708 
       
   709             if (parameterTypes.length > 0) {
       
   710                 // Create an array and fill with the parameters converting primitives to wrappers
       
   711                 emitIconstInsn(mv, parameterTypes.length);
       
   712                 mv.visitTypeInsn(Opcodes.ANEWARRAY, JL_OBJECT);
       
   713                 for (int i = 0; i < parameterTypes.length; i++) {
       
   714                     mv.visitInsn(DUP);
       
   715                     emitIconstInsn(mv, i);
       
   716                     codeWrapArgument(mv, parameterTypes[i], parameterSlot[i]);
       
   717                     mv.visitInsn(Opcodes.AASTORE);
       
   718                 }
       
   719             } else {
       
   720                 mv.visitInsn(Opcodes.ACONST_NULL);
       
   721             }
       
   722 
       
   723             mv.visitMethodInsn(INVOKEINTERFACE, JLR_INVOCATION_HANDLER,
       
   724                     "invoke",
       
   725                     "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
       
   726                             "[Ljava/lang/Object;)Ljava/lang/Object;", true);
       
   727 
       
   728             if (returnType == void.class) {
       
   729                 mv.visitInsn(POP);
       
   730                 mv.visitInsn(RETURN);
       
   731             } else {
       
   732                 codeUnwrapReturnValue(mv, returnType);
       
   733             }
       
   734 
       
   735             mv.visitLabel(L_endBlock);
       
   736 
       
   737             // Generate exception handler
       
   738             mv.visitLabel(L_RuntimeHandler);
       
   739             mv.visitInsn(ATHROW);   // just rethrow the exception
       
   740 
       
   741             mv.visitLabel(L_ThrowableHandler);
       
   742             mv.visitVarInsn(ASTORE, 1);
       
   743             mv.visitTypeInsn(Opcodes.NEW, JLR_UNDECLARED_THROWABLE_EX);
       
   744             mv.visitInsn(DUP);
       
   745             mv.visitVarInsn(ALOAD, 1);
       
   746             mv.visitMethodInsn(INVOKESPECIAL, JLR_UNDECLARED_THROWABLE_EX,
       
   747                     "<init>", "(Ljava/lang/Throwable;)V", false);
       
   748             mv.visitInsn(ATHROW);
       
   749             // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
       
   750             mv.visitMaxs(-1, -1);
       
   751             mv.visitEnd();
       
   752         }
       
   753 
       
   754         /**
       
   755          * Generate code for wrapping an argument of the given type
       
   756          * whose value can be found at the specified local variable
       
   757          * index, in order for it to be passed (as an Object) to the
       
   758          * invocation handler's "invoke" method.
       
   759          */
       
   760         private void codeWrapArgument(MethodVisitor mv, Class<?> type, int slot) {
       
   761             if (type.isPrimitive()) {
       
   762                 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
       
   763 
       
   764                 if (type == int.class ||
       
   765                         type == boolean.class ||
       
   766                         type == byte.class ||
       
   767                         type == char.class ||
       
   768                         type == short.class) {
       
   769                     mv.visitVarInsn(ILOAD, slot);
       
   770                 } else if (type == long.class) {
       
   771                     mv.visitVarInsn(LLOAD, slot);
       
   772                 } else if (type == float.class) {
       
   773                     mv.visitVarInsn(FLOAD, slot);
       
   774                 } else if (type == double.class) {
       
   775                     mv.visitVarInsn(DLOAD, slot);
       
   776                 } else {
       
   777                     throw new AssertionError();
       
   778                 }
       
   779                 mv.visitMethodInsn(INVOKESTATIC, prim.wrapperClassName, "valueOf",
       
   780                         prim.wrapperValueOfDesc, false);
       
   781             } else {
       
   782                 mv.visitVarInsn(ALOAD, slot);
       
   783             }
       
   784         }
       
   785 
       
   786         /**
       
   787          * Generate code for unwrapping a return value of the given
       
   788          * type from the invocation handler's "invoke" method (as type
       
   789          * Object) to its correct type.
       
   790          */
       
   791         private void codeUnwrapReturnValue(MethodVisitor mv, Class<?> type) {
       
   792             if (type.isPrimitive()) {
       
   793                 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
       
   794 
       
   795                 mv.visitTypeInsn(CHECKCAST, prim.wrapperClassName);
       
   796                 mv.visitMethodInsn(INVOKEVIRTUAL,
       
   797                         prim.wrapperClassName,
       
   798                         prim.unwrapMethodName, prim.unwrapMethodDesc, false);
       
   799 
       
   800                 if (type == int.class ||
       
   801                         type == boolean.class ||
       
   802                         type == byte.class ||
       
   803                         type == char.class ||
       
   804                         type == short.class) {
       
   805                     mv.visitInsn(IRETURN);
       
   806                 } else if (type == long.class) {
       
   807                     mv.visitInsn(LRETURN);
       
   808                 } else if (type == float.class) {
       
   809                     mv.visitInsn(FRETURN);
       
   810                 } else if (type == double.class) {
       
   811                     mv.visitInsn(DRETURN);
       
   812                 } else {
       
   813                     throw new AssertionError();
       
   814                 }
       
   815             } else {
       
   816                 mv.visitTypeInsn(CHECKCAST, dotToSlash(type.getName()));
       
   817                 mv.visitInsn(ARETURN);
       
   818             }
       
   819         }
       
   820 
       
   821         /**
       
   822          * Generate code for initializing the static field that stores
       
   823          * the Method object for this proxy method.
       
   824          */
       
   825         private void codeFieldInitialization(MethodVisitor mv, String className) {
       
   826             codeClassForName(mv, fromClass);
       
   827 
       
   828             mv.visitLdcInsn(method.getName());
       
   829 
       
   830             emitIconstInsn(mv, parameterTypes.length);
       
   831 
       
   832             mv.visitTypeInsn(Opcodes.ANEWARRAY, JL_CLASS);
       
   833 
       
   834             // Construct an array with the parameter types mapping primitives to Wrapper types
       
   835             for (int i = 0; i < parameterTypes.length; i++) {
       
   836                 mv.visitInsn(DUP);
       
   837                 emitIconstInsn(mv, i);
       
   838 
       
   839                 if (parameterTypes[i].isPrimitive()) {
       
   840                     PrimitiveTypeInfo prim =
       
   841                             PrimitiveTypeInfo.get(parameterTypes[i]);
       
   842                     mv.visitFieldInsn(GETSTATIC,
       
   843                             prim.wrapperClassName, "TYPE", LJL_CLASS);
       
   844                 } else {
       
   845                     codeClassForName(mv, parameterTypes[i]);
       
   846                 }
       
   847                 mv.visitInsn(Opcodes.AASTORE);
       
   848             }
       
   849             // lookup the method
       
   850             mv.visitMethodInsn(INVOKEVIRTUAL,
       
   851                     JL_CLASS,
       
   852                     "getMethod",
       
   853                     "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
       
   854                     false);
       
   855 
       
   856             mv.visitFieldInsn(PUTSTATIC,
       
   857                     dotToSlash(className),
       
   858                     methodFieldName, LJLR_METHOD);
       
   859         }
       
   860 
       
   861         /*
       
   862          * =============== Code Generation Utility Methods ===============
       
   863          */
       
   864 
       
   865         /**
       
   866          * Generate code to invoke the Class.forName with the name of the given
       
   867          * class to get its Class object at runtime.  The code is written to
       
   868          * the supplied stream.  Note that the code generated by this method
       
   869          * may cause the checked ClassNotFoundException to be thrown.
       
   870          */
       
   871         private void codeClassForName(MethodVisitor mv, Class<?> cl) {
       
   872             mv.visitLdcInsn(cl.getName());
       
   873             mv.visitMethodInsn(INVOKESTATIC,
       
   874                     JL_CLASS,
       
   875                     "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
       
   876         }
       
   877 
       
   878         /**
       
   879          * Visit a bytecode for a constant.
       
   880          *
       
   881          * @param mv  The MethodVisitor
       
   882          * @param cst The constant value
       
   883          */
       
   884         private void emitIconstInsn(MethodVisitor mv, final int cst) {
       
   885             if (cst >= -1 && cst <= 5) {
       
   886                 mv.visitInsn(Opcodes.ICONST_0 + cst);
       
   887             } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
       
   888                 mv.visitIntInsn(Opcodes.BIPUSH, cst);
       
   889             } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
       
   890                 mv.visitIntInsn(Opcodes.SIPUSH, cst);
       
   891             } else {
       
   892                 mv.visitLdcInsn(cst);
       
   893             }
       
   894         }
       
   895 
       
   896         @Override
       
   897         public String toString() {
       
   898             return method.toShortString();
       
   899         }
       
   900     }
       
   901 
       
   902     /**
  1638      * A PrimitiveTypeInfo object contains assorted information about
   903      * A PrimitiveTypeInfo object contains assorted information about
  1639      * a primitive type in its public fields.  The struct for a particular
   904      * a primitive type in its public fields.  The struct for a particular
  1640      * primitive type can be obtained using the static "get" method.
   905      * primitive type can be obtained using the static "get" method.
  1641      */
   906      */
  1642     private static class PrimitiveTypeInfo {
   907     private static class PrimitiveTypeInfo {
  1643 
   908 
  1644         /** "base type" used in various descriptors (see JVMS section 4.3.2) */
   909         private static Map<Class<?>, PrimitiveTypeInfo> table = new HashMap<>();
  1645         public String baseTypeString;
   910 
  1646 
       
  1647         /** name of corresponding wrapper class */
       
  1648         public String wrapperClassName;
       
  1649 
       
  1650         /** method descriptor for wrapper class "valueOf" factory method */
       
  1651         public String wrapperValueOfDesc;
       
  1652 
       
  1653         /** name of wrapper class method for retrieving primitive value */
       
  1654         public String unwrapMethodName;
       
  1655 
       
  1656         /** descriptor of same method */
       
  1657         public String unwrapMethodDesc;
       
  1658 
       
  1659         private static Map<Class<?>,PrimitiveTypeInfo> table = new HashMap<>();
       
  1660         static {
   911         static {
  1661             add(byte.class, Byte.class);
   912             add(byte.class, Byte.class);
  1662             add(char.class, Character.class);
   913             add(char.class, Character.class);
  1663             add(double.class, Double.class);
   914             add(double.class, Double.class);
  1664             add(float.class, Float.class);
   915             add(float.class, Float.class);
  1666             add(long.class, Long.class);
   917             add(long.class, Long.class);
  1667             add(short.class, Short.class);
   918             add(short.class, Short.class);
  1668             add(boolean.class, Boolean.class);
   919             add(boolean.class, Boolean.class);
  1669         }
   920         }
  1670 
   921 
       
   922         /**
       
   923          * name of corresponding wrapper class
       
   924          */
       
   925         private String wrapperClassName;
       
   926         /**
       
   927          * method descriptor for wrapper class "valueOf" factory method
       
   928          */
       
   929         private String wrapperValueOfDesc;
       
   930         /**
       
   931          * name of wrapper class method for retrieving primitive value
       
   932          */
       
   933         private String unwrapMethodName;
       
   934         /**
       
   935          * descriptor of same method
       
   936          */
       
   937         private String unwrapMethodDesc;
       
   938 
       
   939         private PrimitiveTypeInfo(Class<?> primitiveClass, Class<?> wrapperClass) {
       
   940             assert primitiveClass.isPrimitive();
       
   941 
       
   942             /**
       
   943              * "base type" used in various descriptors (see JVMS section 4.3.2)
       
   944              */
       
   945             String baseTypeString =
       
   946                     Array.newInstance(primitiveClass, 0)
       
   947                             .getClass().getName().substring(1);
       
   948             wrapperClassName = dotToSlash(wrapperClass.getName());
       
   949             wrapperValueOfDesc =
       
   950                     "(" + baseTypeString + ")L" + wrapperClassName + ";";
       
   951             unwrapMethodName = primitiveClass.getName() + "Value";
       
   952             unwrapMethodDesc = "()" + baseTypeString;
       
   953         }
       
   954 
  1671         private static void add(Class<?> primitiveClass, Class<?> wrapperClass) {
   955         private static void add(Class<?> primitiveClass, Class<?> wrapperClass) {
  1672             table.put(primitiveClass,
   956             table.put(primitiveClass,
  1673                       new PrimitiveTypeInfo(primitiveClass, wrapperClass));
   957                     new PrimitiveTypeInfo(primitiveClass, wrapperClass));
  1674         }
       
  1675 
       
  1676         private PrimitiveTypeInfo(Class<?> primitiveClass, Class<?> wrapperClass) {
       
  1677             assert primitiveClass.isPrimitive();
       
  1678 
       
  1679             baseTypeString =
       
  1680                 Array.newInstance(primitiveClass, 0)
       
  1681                 .getClass().getName().substring(1);
       
  1682             wrapperClassName = dotToSlash(wrapperClass.getName());
       
  1683             wrapperValueOfDesc =
       
  1684                 "(" + baseTypeString + ")L" + wrapperClassName + ";";
       
  1685             unwrapMethodName = primitiveClass.getName() + "Value";
       
  1686             unwrapMethodDesc = "()" + baseTypeString;
       
  1687         }
   958         }
  1688 
   959 
  1689         public static PrimitiveTypeInfo get(Class<?> cl) {
   960         public static PrimitiveTypeInfo get(Class<?> cl) {
  1690             return table.get(cl);
   961             return table.get(cl);
  1691         }
   962         }
  1692     }
   963     }
  1693 
       
  1694 
       
  1695     /**
       
  1696      * A ConstantPool object represents the constant pool of a class file
       
  1697      * being generated.  This representation of a constant pool is designed
       
  1698      * specifically for use by ProxyGenerator; in particular, it assumes
       
  1699      * that constant pool entries will not need to be resorted (for example,
       
  1700      * by their type, as the Java compiler does), so that the final index
       
  1701      * value can be assigned and used when an entry is first created.
       
  1702      *
       
  1703      * Note that new entries cannot be created after the constant pool has
       
  1704      * been written to a class file.  To prevent such logic errors, a
       
  1705      * ConstantPool instance can be marked "read only", so that further
       
  1706      * attempts to add new entries will fail with a runtime exception.
       
  1707      *
       
  1708      * See JVMS section 4.4 for more information about the constant pool
       
  1709      * of a class file.
       
  1710      */
       
  1711     private static class ConstantPool {
       
  1712 
       
  1713         /**
       
  1714          * list of constant pool entries, in constant pool index order.
       
  1715          *
       
  1716          * This list is used when writing the constant pool to a stream
       
  1717          * and for assigning the next index value.  Note that element 0
       
  1718          * of this list corresponds to constant pool index 1.
       
  1719          */
       
  1720         private List<Entry> pool = new ArrayList<>(32);
       
  1721 
       
  1722         /**
       
  1723          * maps constant pool data of all types to constant pool indexes.
       
  1724          *
       
  1725          * This map is used to look up the index of an existing entry for
       
  1726          * values of all types.
       
  1727          */
       
  1728         private Map<Object,Integer> map = new HashMap<>(16);
       
  1729 
       
  1730         /** true if no new constant pool entries may be added */
       
  1731         private boolean readOnly = false;
       
  1732 
       
  1733         /**
       
  1734          * Get or assign the index for a CONSTANT_Utf8 entry.
       
  1735          */
       
  1736         public short getUtf8(String s) {
       
  1737             if (s == null) {
       
  1738                 throw new NullPointerException();
       
  1739             }
       
  1740             return getValue(s);
       
  1741         }
       
  1742 
       
  1743         /**
       
  1744          * Get or assign the index for a CONSTANT_Integer entry.
       
  1745          */
       
  1746         public short getInteger(int i) {
       
  1747             return getValue(i);
       
  1748         }
       
  1749 
       
  1750         /**
       
  1751          * Get or assign the index for a CONSTANT_Float entry.
       
  1752          */
       
  1753         public short getFloat(float f) {
       
  1754             return getValue(f);
       
  1755         }
       
  1756 
       
  1757         /**
       
  1758          * Get or assign the index for a CONSTANT_Class entry.
       
  1759          */
       
  1760         public short getClass(String name) {
       
  1761             short utf8Index = getUtf8(name);
       
  1762             return getIndirect(new IndirectEntry(
       
  1763                 CONSTANT_CLASS, utf8Index));
       
  1764         }
       
  1765 
       
  1766         /**
       
  1767          * Get or assign the index for a CONSTANT_String entry.
       
  1768          */
       
  1769         public short getString(String s) {
       
  1770             short utf8Index = getUtf8(s);
       
  1771             return getIndirect(new IndirectEntry(
       
  1772                 CONSTANT_STRING, utf8Index));
       
  1773         }
       
  1774 
       
  1775         /**
       
  1776          * Get or assign the index for a CONSTANT_FieldRef entry.
       
  1777          */
       
  1778         public short getFieldRef(String className,
       
  1779                                  String name, String descriptor)
       
  1780         {
       
  1781             short classIndex = getClass(className);
       
  1782             short nameAndTypeIndex = getNameAndType(name, descriptor);
       
  1783             return getIndirect(new IndirectEntry(
       
  1784                 CONSTANT_FIELD, classIndex, nameAndTypeIndex));
       
  1785         }
       
  1786 
       
  1787         /**
       
  1788          * Get or assign the index for a CONSTANT_MethodRef entry.
       
  1789          */
       
  1790         public short getMethodRef(String className,
       
  1791                                   String name, String descriptor)
       
  1792         {
       
  1793             short classIndex = getClass(className);
       
  1794             short nameAndTypeIndex = getNameAndType(name, descriptor);
       
  1795             return getIndirect(new IndirectEntry(
       
  1796                 CONSTANT_METHOD, classIndex, nameAndTypeIndex));
       
  1797         }
       
  1798 
       
  1799         /**
       
  1800          * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
       
  1801          */
       
  1802         public short getInterfaceMethodRef(String className, String name,
       
  1803                                            String descriptor)
       
  1804         {
       
  1805             short classIndex = getClass(className);
       
  1806             short nameAndTypeIndex = getNameAndType(name, descriptor);
       
  1807             return getIndirect(new IndirectEntry(
       
  1808                 CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
       
  1809         }
       
  1810 
       
  1811         /**
       
  1812          * Get or assign the index for a CONSTANT_NameAndType entry.
       
  1813          */
       
  1814         public short getNameAndType(String name, String descriptor) {
       
  1815             short nameIndex = getUtf8(name);
       
  1816             short descriptorIndex = getUtf8(descriptor);
       
  1817             return getIndirect(new IndirectEntry(
       
  1818                 CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
       
  1819         }
       
  1820 
       
  1821         /**
       
  1822          * Set this ConstantPool instance to be "read only".
       
  1823          *
       
  1824          * After this method has been called, further requests to get
       
  1825          * an index for a non-existent entry will cause an InternalError
       
  1826          * to be thrown instead of creating of the entry.
       
  1827          */
       
  1828         public void setReadOnly() {
       
  1829             readOnly = true;
       
  1830         }
       
  1831 
       
  1832         /**
       
  1833          * Write this constant pool to a stream as part of
       
  1834          * the class file format.
       
  1835          *
       
  1836          * This consists of writing the "constant_pool_count" and
       
  1837          * "constant_pool[]" items of the "ClassFile" structure, as
       
  1838          * described in JVMS section 4.1.
       
  1839          */
       
  1840         public void write(OutputStream out) throws IOException {
       
  1841             DataOutputStream dataOut = new DataOutputStream(out);
       
  1842 
       
  1843             // constant_pool_count: number of entries plus one
       
  1844             dataOut.writeShort(pool.size() + 1);
       
  1845 
       
  1846             for (Entry e : pool) {
       
  1847                 e.write(dataOut);
       
  1848             }
       
  1849         }
       
  1850 
       
  1851         /**
       
  1852          * Add a new constant pool entry and return its index.
       
  1853          */
       
  1854         private short addEntry(Entry entry) {
       
  1855             pool.add(entry);
       
  1856             /*
       
  1857              * Note that this way of determining the index of the
       
  1858              * added entry is wrong if this pool supports
       
  1859              * CONSTANT_Long or CONSTANT_Double entries.
       
  1860              */
       
  1861             if (pool.size() >= 65535) {
       
  1862                 throw new IllegalArgumentException(
       
  1863                     "constant pool size limit exceeded");
       
  1864             }
       
  1865             return (short) pool.size();
       
  1866         }
       
  1867 
       
  1868         /**
       
  1869          * Get or assign the index for an entry of a type that contains
       
  1870          * a direct value.  The type of the given object determines the
       
  1871          * type of the desired entry as follows:
       
  1872          *
       
  1873          *      java.lang.String        CONSTANT_Utf8
       
  1874          *      java.lang.Integer       CONSTANT_Integer
       
  1875          *      java.lang.Float         CONSTANT_Float
       
  1876          *      java.lang.Long          CONSTANT_Long
       
  1877          *      java.lang.Double        CONSTANT_DOUBLE
       
  1878          */
       
  1879         private short getValue(Object key) {
       
  1880             Integer index = map.get(key);
       
  1881             if (index != null) {
       
  1882                 return index.shortValue();
       
  1883             } else {
       
  1884                 if (readOnly) {
       
  1885                     throw new InternalError(
       
  1886                         "late constant pool addition: " + key);
       
  1887                 }
       
  1888                 short i = addEntry(new ValueEntry(key));
       
  1889                 map.put(key, (int)i);
       
  1890                 return i;
       
  1891             }
       
  1892         }
       
  1893 
       
  1894         /**
       
  1895          * Get or assign the index for an entry of a type that contains
       
  1896          * references to other constant pool entries.
       
  1897          */
       
  1898         private short getIndirect(IndirectEntry e) {
       
  1899             Integer index = map.get(e);
       
  1900             if (index != null) {
       
  1901                 return index.shortValue();
       
  1902             } else {
       
  1903                 if (readOnly) {
       
  1904                     throw new InternalError("late constant pool addition");
       
  1905                 }
       
  1906                 short i = addEntry(e);
       
  1907                 map.put(e, (int)i);
       
  1908                 return i;
       
  1909             }
       
  1910         }
       
  1911 
       
  1912         /**
       
  1913          * Entry is the abstact superclass of all constant pool entry types
       
  1914          * that can be stored in the "pool" list; its purpose is to define a
       
  1915          * common method for writing constant pool entries to a class file.
       
  1916          */
       
  1917         private abstract static class Entry {
       
  1918             public abstract void write(DataOutputStream out)
       
  1919                 throws IOException;
       
  1920         }
       
  1921 
       
  1922         /**
       
  1923          * ValueEntry represents a constant pool entry of a type that
       
  1924          * contains a direct value (see the comments for the "getValue"
       
  1925          * method for a list of such types).
       
  1926          *
       
  1927          * ValueEntry objects are not used as keys for their entries in the
       
  1928          * Map "map", so no useful hashCode or equals methods are defined.
       
  1929          */
       
  1930         private static class ValueEntry extends Entry {
       
  1931             private Object value;
       
  1932 
       
  1933             public ValueEntry(Object value) {
       
  1934                 this.value = value;
       
  1935             }
       
  1936 
       
  1937             public void write(DataOutputStream out) throws IOException {
       
  1938                 if (value instanceof String) {
       
  1939                     out.writeByte(CONSTANT_UTF8);
       
  1940                     out.writeUTF((String) value);
       
  1941                 } else if (value instanceof Integer) {
       
  1942                     out.writeByte(CONSTANT_INTEGER);
       
  1943                     out.writeInt(((Integer) value).intValue());
       
  1944                 } else if (value instanceof Float) {
       
  1945                     out.writeByte(CONSTANT_FLOAT);
       
  1946                     out.writeFloat(((Float) value).floatValue());
       
  1947                 } else if (value instanceof Long) {
       
  1948                     out.writeByte(CONSTANT_LONG);
       
  1949                     out.writeLong(((Long) value).longValue());
       
  1950                 } else if (value instanceof Double) {
       
  1951                     out.writeDouble(CONSTANT_DOUBLE);
       
  1952                     out.writeDouble(((Double) value).doubleValue());
       
  1953                 } else {
       
  1954                     throw new InternalError("bogus value entry: " + value);
       
  1955                 }
       
  1956             }
       
  1957         }
       
  1958 
       
  1959         /**
       
  1960          * IndirectEntry represents a constant pool entry of a type that
       
  1961          * references other constant pool entries, i.e., the following types:
       
  1962          *
       
  1963          *      CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
       
  1964          *      CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
       
  1965          *      CONSTANT_NameAndType.
       
  1966          *
       
  1967          * Each of these entry types contains either one or two indexes of
       
  1968          * other constant pool entries.
       
  1969          *
       
  1970          * IndirectEntry objects are used as the keys for their entries in
       
  1971          * the Map "map", so the hashCode and equals methods are overridden
       
  1972          * to allow matching.
       
  1973          */
       
  1974         private static class IndirectEntry extends Entry {
       
  1975             private int tag;
       
  1976             private short index0;
       
  1977             private short index1;
       
  1978 
       
  1979             /**
       
  1980              * Construct an IndirectEntry for a constant pool entry type
       
  1981              * that contains one index of another entry.
       
  1982              */
       
  1983             public IndirectEntry(int tag, short index) {
       
  1984                 this.tag = tag;
       
  1985                 this.index0 = index;
       
  1986                 this.index1 = 0;
       
  1987             }
       
  1988 
       
  1989             /**
       
  1990              * Construct an IndirectEntry for a constant pool entry type
       
  1991              * that contains two indexes for other entries.
       
  1992              */
       
  1993             public IndirectEntry(int tag, short index0, short index1) {
       
  1994                 this.tag = tag;
       
  1995                 this.index0 = index0;
       
  1996                 this.index1 = index1;
       
  1997             }
       
  1998 
       
  1999             public void write(DataOutputStream out) throws IOException {
       
  2000                 out.writeByte(tag);
       
  2001                 out.writeShort(index0);
       
  2002                 /*
       
  2003                  * If this entry type contains two indexes, write
       
  2004                  * out the second, too.
       
  2005                  */
       
  2006                 if (tag == CONSTANT_FIELD ||
       
  2007                     tag == CONSTANT_METHOD ||
       
  2008                     tag == CONSTANT_INTERFACEMETHOD ||
       
  2009                     tag == CONSTANT_NAMEANDTYPE)
       
  2010                 {
       
  2011                     out.writeShort(index1);
       
  2012                 }
       
  2013             }
       
  2014 
       
  2015             public int hashCode() {
       
  2016                 return tag + index0 + index1;
       
  2017             }
       
  2018 
       
  2019             public boolean equals(Object obj) {
       
  2020                 if (obj instanceof IndirectEntry) {
       
  2021                     IndirectEntry other = (IndirectEntry) obj;
       
  2022                     if (tag == other.tag &&
       
  2023                         index0 == other.index0 && index1 == other.index1)
       
  2024                     {
       
  2025                         return true;
       
  2026                     }
       
  2027                 }
       
  2028                 return false;
       
  2029             }
       
  2030         }
       
  2031     }
       
  2032 }
   964 }