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 void) return 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