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