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