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