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