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