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