1 /* 2 * Copyright (c) 1999, 2008, 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 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 }