1 /*
2  * Copyright (c) 1999, 2018, 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
26 package java.lang.reflect;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.DataOutputStream;
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.OutputStream;
33 import java.lang.reflect.Array;
34 import java.lang.reflect.Method;
35 import java.nio.file.Files;
36 import java.nio.file.Path;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.ListIterator;
42 import java.util.Map;
43 import sun.security.action.GetBooleanAction;
44
45 /**
46  * ProxyGenerator contains the code to generate a dynamic proxy class
47  * for the java.lang.reflect.Proxy API.
48  *
49  * The external interfaces to ProxyGenerator is the static
50  * "generateProxyClass" method.
51  *
52  * @author      Peter Jones
53  * @since       1.3
54  */

55 class ProxyGenerator {
56     /*
57      * In the comments below, "JVMS" refers to The Java Virtual Machine
58      * Specification Second Edition and "JLS" refers to the original
59      * version of The Java Language Specification, unless otherwise
60      * specified.
61      */

62
63     /* generate 1.5-era class file version */
64     private static final int CLASSFILE_MAJOR_VERSION = 49;
65     private static final int CLASSFILE_MINOR_VERSION = 0;
66
67     /*
68      * beginning of constants copied from
69      * sun.tools.java.RuntimeConstants (which no longer exists):
70      */

71
72     /* constant pool tags */
73     private static final int CONSTANT_UTF8              = 1;
74     private static final int CONSTANT_UNICODE           = 2;
75     private static final int CONSTANT_INTEGER           = 3;
76     private static final int CONSTANT_FLOAT             = 4;
77     private static final int CONSTANT_LONG              = 5;
78     private static final int CONSTANT_DOUBLE            = 6;
79     private static final int CONSTANT_CLASS             = 7;
80     private static final int CONSTANT_STRING            = 8;
81     private static final int CONSTANT_FIELD             = 9;
82     private static final int CONSTANT_METHOD            = 10;
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";
311
312     /** debugging flag for saving generated class files */
313     private static final boolean saveGeneratedFiles =
314         java.security.AccessController.doPrivileged(
315             new GetBooleanAction(
316                 "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();
317
318     /**
319      * Generate a public proxy class given a name and a list of proxy interfaces.
320      */

321     static byte[] generateProxyClass(final String name,
322                                      Class<?>[] interfaces) {
323         return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER));
324     }
325
326     /**
327      * Generate a proxy class given a name and a list of proxy interfaces.
328      *
329      * @param name        the class name of the proxy class
330      * @param interfaces  proxy interfaces
331      * @param accessFlags access flags of the proxy class
332     */

333     static byte[] generateProxyClass(final String name,
334                                      Class<?>[] interfaces,
335                                      int accessFlags)
336     {
337         ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
338         final byte[] classFile = gen.generateClassFile();
339
340         if (saveGeneratedFiles) {
341             java.security.AccessController.doPrivileged(
342             new java.security.PrivilegedAction<Void>() {
343                 public Void run() {
344                     try {
345                         int i = name.lastIndexOf('.');
346                         Path path;
347                         if (i > 0) {
348                             Path dir = Path.of(name.substring(0, i).replace('.', File.separatorChar));
349                             Files.createDirectories(dir);
350                             path = dir.resolve(name.substring(i+1, name.length()) + ".class");
351                         } else {
352                             path = Path.of(name + ".class");
353                         }
354                         Files.write(path, classFile);
355                         return null;
356                     } catch (IOException e) {
357                         throw new InternalError(
358                             "I/O exception saving generated file: " + e);
359                     }
360                 }
361             });
362         }
363
364         return classFile;
365     }
366
367     /* preloaded Method objects for methods in java.lang.Object */
368     private static Method hashCodeMethod;
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      *
413      * A ProxyGenerator object contains the state for the ongoing
414      * generation of a particular proxy class.
415      */

416     private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) {
417         this.className = className;
418         this.interfaces = interfaces;
419         this.accessFlags = accessFlags;
420     }
421
422     /**
423      * Generate a class file for the proxy class.  This method drives the
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     }
622
623     /**
624      * For a given set of proxy methods with the same signature, check
625      * that their return types are compatible according to the Proxy
626      * specification.
627      *
628      * Specifically, if there is more than one such method, then all
629      * of the return types must be reference types, and there must be
630      * one return type that is assignable to each of the rest of them.
631      */

632     private static void checkReturnTypes(List<ProxyMethod> methods) {
633         /*
634          * If there is only one method with a given signature, there
635          * cannot be a conflict.  This is the only case in which a
636          * primitive (or voidreturn type is allowed.
637          */

638         if (methods.size() < 2) {
639             return;
640         }
641
642         /*
643          * List of return types that are not yet known to be
644          * assignable from ("covered" by) any of the others.
645          */

646         LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>();
647
648     nextNewReturnType:
649         for (ProxyMethod pm : methods) {
650             Class<?> newReturnType = pm.returnType;
651             if (newReturnType.isPrimitive()) {
652                 throw new IllegalArgumentException(
653                     "methods with same signature " +
654                     getFriendlyMethodSignature(pm.methodName,
655                                                pm.parameterTypes) +
656                     " but incompatible return types: " +
657                     newReturnType.getName() + " and others");
658             }
659             boolean added = false;
660
661             /*
662              * Compare the new return type to the existing uncovered
663              * return types.
664              */

665             ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
666             while (liter.hasNext()) {
667                 Class<?> uncoveredReturnType = liter.next();
668
669                 /*
670                  * If an existing uncovered return type is assignable
671                  * to this new one, then we can forget the new one.
672                  */

673                 if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
674                     assert !added;
675                     continue nextNewReturnType;
676                 }
677
678                 /*
679                  * If the new return type is assignable to an existing
680                  * uncovered one, then should replace the existing one
681                  * with the new one (or just forget the existing one,
682                  * if the new one has already be put in the list).
683                  */

684                 if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
685                     // (we can assume that each return type is unique)
686                     if (!added) {
687                         liter.set(newReturnType);
688                         added = true;
689                     } else {
690                         liter.remove();
691                     }
692                 }
693             }
694
695             /*
696              * If we got through the list of existing uncovered return
697              * types without an assignability relationship, then add
698              * the new return type to the list of uncovered ones.
699              */

700             if (!added) {
701                 uncoveredReturnTypes.add(newReturnType);
702             }
703         }
704
705         /*
706          * We shouldn't end up with more than one return type that is
707          * not assignable from any of the others.
708          */

709         if (uncoveredReturnTypes.size() > 1) {
710             ProxyMethod pm = methods.get(0);
711             throw new IllegalArgumentException(
712                 "methods with same signature " +
713                 getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) +
714                 " 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         }
1563     }
1564
1565     /**
1566      * Given the exceptions declared in the throws clause of a proxy method,
1567      * compute the exceptions that need to be caught from the invocation
1568      * handler's invoke method and rethrown intact in the method's
1569      * implementation before catching other Throwables and wrapping them
1570      * in UndeclaredThrowableExceptions.
1571      *
1572      * The exceptions to be caught are returned in a List object.  Each
1573      * exception in the returned list is guaranteed to not be a subclass of
1574      * any of the other exceptions in the list, so the catch blocks for
1575      * these exceptions may be generated in any order relative to each other.
1576      *
1577      * Error and RuntimeException are each always contained by the returned
1578      * list (if none of their superclasses are contained), since those
1579      * unchecked exceptions should always be rethrown intact, and thus their
1580      * subclasses will never appear in the returned list.
1581      *
1582      * The returned List will be empty if java.lang.Throwable is in the
1583      * given list of declared exceptions, indicating that no exceptions
1584      * need to be caught.
1585      */

1586     private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {
1587         List<Class<?>> uniqueList = new ArrayList<>();
1588                                                 // unique exceptions to catch
1589
1590         uniqueList.add(Error.class);            // always catch/rethrow these
1591         uniqueList.add(RuntimeException.class);
1592
1593     nextException:
1594         for (Class<?> ex: exceptions) {
1595             if (ex.isAssignableFrom(Throwable.class)) {
1596                 /*
1597                  * If Throwable is declared to be thrown by the proxy method,
1598                  * then no catch blocks are necessary, because the invoke
1599                  * can, at most, throw Throwable anyway.
1600                  */

1601                 uniqueList.clear();
1602                 break;
1603             } else if (!Throwable.class.isAssignableFrom(ex)) {
1604                 /*
1605                  * Ignore types that cannot be thrown by the invoke method.
1606                  */

1607                 continue;
1608             }
1609             /*
1610              * Compare this exception against the current list of
1611              * exceptions that need to be caught:
1612              */

1613             for (int j = 0; j < uniqueList.size();) {
1614                 Class<?> ex2 = uniqueList.get(j);
1615                 if (ex2.isAssignableFrom(ex)) {
1616                     /*
1617                      * if a superclass of this exception is already on
1618                      * the list to catch, then ignore this one and continue;
1619                      */

1620                     continue nextException;
1621                 } else if (ex.isAssignableFrom(ex2)) {
1622                     /*
1623                      * if a subclass of this exception is on the list
1624                      * to catch, then remove it;
1625                      */

1626                     uniqueList.remove(j);
1627                 } else {
1628                     j++;        // else continue comparing.
1629                 }
1630             }
1631             // This exception is unique (so far): add it to the list to catch.
1632             uniqueList.add(ex);
1633         }
1634         return uniqueList;
1635     }
1636
1637     /**
1638      * A PrimitiveTypeInfo object contains assorted information about
1639      * a primitive type in its public fields.  The struct for a particular
1640      * primitive type can be obtained using the static "get" method.
1641      */

1642     private static class PrimitiveTypeInfo {
1643
1644         /** "base type" used in various descriptors (see JVMS section 4.3.2) */
1645         public String baseTypeString;
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 {
1661             add(byte.class, Byte.class);
1662             add(char.class, Character.class);
1663             add(double.class, Double.class);
1664             add(float.class, Float.class);
1665             add(int.class, Integer.class);
1666             add(long.class, Long.class);
1667             add(short.class, Short.class);
1668             add(boolean.class, Boolean.class);
1669         }
1670
1671         private static void add(Class<?> primitiveClass, Class<?> wrapperClass) {
1672             table.put(primitiveClass,
1673                       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         }
1688
1689         public static PrimitiveTypeInfo get(Class<?> cl) {
1690             return table.get(cl);
1691         }
1692     }
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 }
2033