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