297 // private static final int opc_ifnull = 198; 298 // private static final int opc_ifnonnull = 199; 299 // private static final int opc_goto_w = 200; 300 // private static final int opc_jsr_w = 201; 301 302 // end of constants copied from sun.tools.java.RuntimeConstants 303 304 /** name of the superclass of proxy classes */ 305 private final static String superclassName = "java/lang/reflect/Proxy"; 306 307 /** name of field for storing a proxy instance's invocation handler */ 308 private final static String handlerFieldName = "h"; 309 310 /** debugging flag for saving generated class files */ 311 private final static boolean saveGeneratedFiles = 312 java.security.AccessController.doPrivileged( 313 new GetBooleanAction( 314 "sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue(); 315 316 /** 317 * Generate a proxy class given a name and a list of proxy interfaces. 318 */ 319 public static byte[] generateProxyClass(final String name, 320 Class[] interfaces) 321 { 322 ProxyGenerator gen = new ProxyGenerator(name, interfaces); 323 final byte[] classFile = gen.generateClassFile(); 324 325 if (saveGeneratedFiles) { 326 java.security.AccessController.doPrivileged( 327 new java.security.PrivilegedAction<Void>() { 328 public Void run() { 329 try { 330 FileOutputStream file = 331 new FileOutputStream(dotToSlash(name) + ".class"); 332 file.write(classFile); 333 file.close(); 334 return null; 335 } catch (IOException e) { 336 throw new InternalError( 337 "I/O exception saving generated file: " + e); 338 } 339 } 340 }); 341 } 342 343 return classFile; 344 } 345 346 /* preloaded Method objects for methods in java.lang.Object */ 347 private static Method hashCodeMethod; 348 private static Method equalsMethod; 349 private static Method toStringMethod; 350 static { 351 try { 352 hashCodeMethod = Object.class.getMethod("hashCode"); 353 equalsMethod = 354 Object.class.getMethod("equals", new Class<?>[] { Object.class }); 355 toStringMethod = Object.class.getMethod("toString"); 356 } catch (NoSuchMethodException e) { 357 throw new NoSuchMethodError(e.getMessage()); 358 } 359 } 360 361 /** name of proxy class */ 362 private String className; 363 364 /** proxy interfaces */ 365 private Class[] interfaces; 366 367 /** constant pool of class being generated */ 368 private ConstantPool cp = new ConstantPool(); 369 370 /** FieldInfo struct for each field of generated class */ 371 private List<FieldInfo> fields = new ArrayList<FieldInfo>(); 372 373 /** MethodInfo struct for each method of generated class */ 374 private List<MethodInfo> methods = new ArrayList<MethodInfo>(); 375 376 /** 377 * maps method signature string to list of ProxyMethod objects for 378 * proxy methods with that signature 379 */ 380 private Map<String, List<ProxyMethod>> proxyMethods = 381 new HashMap<String,List<ProxyMethod>>(); 382 383 /** count of ProxyMethod objects added to proxyMethods */ 384 private int proxyMethodCount = 0; 385 386 /** 387 * Construct a ProxyGenerator to generate a proxy class with the 388 * specified name and for the given interfaces. 389 * 390 * A ProxyGenerator object contains the state for the ongoing 391 * generation of a particular proxy class. 392 */ 393 private ProxyGenerator(String className, Class[] interfaces) { 394 this.className = className; 395 this.interfaces = interfaces; 396 } 397 398 /** 399 * Generate a class file for the proxy class. This method drives the 400 * class file generation process. 401 */ 402 private byte[] generateClassFile() { 403 404 /* ============================================================ 405 * Step 1: Assemble ProxyMethod objects for all methods to 406 * generate proxy dispatching code for. 407 */ 408 409 /* 410 * Record that proxy methods are needed for the hashCode, equals, 411 * and toString methods of java.lang.Object. This is done before 412 * the methods from the proxy interfaces so that the methods from 413 * java.lang.Object take precedence over duplicate methods in the 414 * proxy interfaces. 415 */ 416 addProxyMethod(hashCodeMethod, Object.class); 417 addProxyMethod(equalsMethod, Object.class); 418 addProxyMethod(toStringMethod, Object.class); 419 420 /* 421 * Now record all of the methods from the proxy interfaces, giving 422 * earlier interfaces precedence over later ones with duplicate 423 * methods. 424 */ 425 for (int i = 0; i < interfaces.length; i++) { 426 Method[] methods = interfaces[i].getMethods(); 427 for (int j = 0; j < methods.length; j++) { 428 addProxyMethod(methods[j], interfaces[i]); 429 } 430 } 431 432 /* 433 * For each set of proxy methods with the same signature, 434 * verify that the methods' return types are compatible. 435 */ 436 for (List<ProxyMethod> sigmethods : proxyMethods.values()) { 437 checkReturnTypes(sigmethods); 438 } 439 440 /* ============================================================ 441 * Step 2: Assemble FieldInfo and MethodInfo structs for all of 442 * fields and methods in the class we are generating. 443 */ 444 try { 445 methods.add(generateConstructor()); 446 447 for (List<ProxyMethod> sigmethods : proxyMethods.values()) { 448 for (ProxyMethod pm : sigmethods) { 463 throw new InternalError("unexpected I/O Exception", e); 464 } 465 466 if (methods.size() > 65535) { 467 throw new IllegalArgumentException("method limit exceeded"); 468 } 469 if (fields.size() > 65535) { 470 throw new IllegalArgumentException("field limit exceeded"); 471 } 472 473 /* ============================================================ 474 * Step 3: Write the final class file. 475 */ 476 477 /* 478 * Make sure that constant pool indexes are reserved for the 479 * following items before starting to write the final class file. 480 */ 481 cp.getClass(dotToSlash(className)); 482 cp.getClass(superclassName); 483 for (int i = 0; i < interfaces.length; i++) { 484 cp.getClass(dotToSlash(interfaces[i].getName())); 485 } 486 487 /* 488 * Disallow new constant pool additions beyond this point, since 489 * we are about to write the final constant pool table. 490 */ 491 cp.setReadOnly(); 492 493 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 494 DataOutputStream dout = new DataOutputStream(bout); 495 496 try { 497 /* 498 * Write all the items of the "ClassFile" structure. 499 * See JVMS section 4.1. 500 */ 501 // u4 magic; 502 dout.writeInt(0xCAFEBABE); 503 // u2 minor_version; 504 dout.writeShort(CLASSFILE_MINOR_VERSION); 505 // u2 major_version; 506 dout.writeShort(CLASSFILE_MAJOR_VERSION); 507 508 cp.write(dout); // (write constant pool) 509 510 // u2 access_flags; 511 dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER); 512 // u2 this_class; 513 dout.writeShort(cp.getClass(dotToSlash(className))); 514 // u2 super_class; 515 dout.writeShort(cp.getClass(superclassName)); 516 517 // u2 interfaces_count; 518 dout.writeShort(interfaces.length); 519 // u2 interfaces[interfaces_count]; 520 for (int i = 0; i < interfaces.length; i++) { 521 dout.writeShort(cp.getClass( 522 dotToSlash(interfaces[i].getName()))); 523 } 524 525 // u2 fields_count; 526 dout.writeShort(fields.size()); 527 // field_info fields[fields_count]; 528 for (FieldInfo f : fields) { 529 f.write(dout); 530 } 531 532 // u2 methods_count; 533 dout.writeShort(methods.size()); 534 // method_info methods[methods_count]; 535 for (MethodInfo m : methods) { 536 m.write(dout); 537 } 538 539 // u2 attributes_count; 540 dout.writeShort(0); // (no ClassFile attributes for proxy classes) 541 542 } catch (IOException e) { 559 * passed to the invocation handler's "invoke" method for a given 560 * set of duplicate methods. 561 */ 562 private void addProxyMethod(Method m, Class<?> fromClass) { 563 String name = m.getName(); 564 Class<?>[] parameterTypes = m.getParameterTypes(); 565 Class<?> returnType = m.getReturnType(); 566 Class<?>[] exceptionTypes = m.getExceptionTypes(); 567 568 String sig = name + getParameterDescriptors(parameterTypes); 569 List<ProxyMethod> sigmethods = proxyMethods.get(sig); 570 if (sigmethods != null) { 571 for (ProxyMethod pm : sigmethods) { 572 if (returnType == pm.returnType) { 573 /* 574 * Found a match: reduce exception types to the 575 * greatest set of exceptions that can thrown 576 * compatibly with the throws clauses of both 577 * overridden methods. 578 */ 579 List<Class<?>> legalExceptions = new ArrayList<Class<?>>(); 580 collectCompatibleTypes( 581 exceptionTypes, pm.exceptionTypes, legalExceptions); 582 collectCompatibleTypes( 583 pm.exceptionTypes, exceptionTypes, legalExceptions); 584 pm.exceptionTypes = new Class<?>[legalExceptions.size()]; 585 pm.exceptionTypes = 586 legalExceptions.toArray(pm.exceptionTypes); 587 return; 588 } 589 } 590 } else { 591 sigmethods = new ArrayList<ProxyMethod>(3); 592 proxyMethods.put(sig, sigmethods); 593 } 594 sigmethods.add(new ProxyMethod(name, parameterTypes, returnType, 595 exceptionTypes, fromClass)); 596 } 597 598 /** 599 * For a given set of proxy methods with the same signature, check 600 * that their return types are compatible according to the Proxy 601 * specification. 602 * 603 * Specifically, if there is more than one such method, then all 604 * of the return types must be reference types, and there must be 605 * one return type that is assignable to each of the rest of them. 606 */ 607 private static void checkReturnTypes(List<ProxyMethod> methods) { 608 /* 609 * If there is only one method with a given signature, there 610 * cannot be a conflict. This is the only case in which a 611 * primitive (or void) return type is allowed. 612 */ 613 if (methods.size() < 2) { 614 return; 615 } 616 617 /* 618 * List of return types that are not yet known to be 619 * assignable from ("covered" by) any of the others. 620 */ 621 LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>(); 622 623 nextNewReturnType: 624 for (ProxyMethod pm : methods) { 625 Class<?> newReturnType = pm.returnType; 626 if (newReturnType.isPrimitive()) { 627 throw new IllegalArgumentException( 628 "methods with same signature " + 629 getFriendlyMethodSignature(pm.methodName, 630 pm.parameterTypes) + 631 " but incompatible return types: " + 632 newReturnType.getName() + " and others"); 633 } 634 boolean added = false; 635 636 /* 637 * Compare the new return type to the existing uncovered 638 * return types. 639 */ 640 ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator(); 641 while (liter.hasNext()) { 816 out.writeShort(e.startPc); 817 // u2 end_pc; 818 out.writeShort(e.endPc); 819 // u2 handler_pc; 820 out.writeShort(e.handlerPc); 821 // u2 catch_type; 822 out.writeShort(e.catchType); 823 } 824 // u2 attributes_count; 825 out.writeShort(0); 826 827 // write "Exceptions" attribute. See JVMS section 4.7.4. 828 829 // u2 attribute_name_index; 830 out.writeShort(cp.getUtf8("Exceptions")); 831 // u4 attributes_length; 832 out.writeInt(2 + 2 * declaredExceptions.length); 833 // u2 number_of_exceptions; 834 out.writeShort(declaredExceptions.length); 835 // u2 exception_index_table[number_of_exceptions]; 836 for (int i = 0; i < declaredExceptions.length; i++) { 837 out.writeShort(declaredExceptions[i]); 838 } 839 } 840 841 } 842 843 /** 844 * A ProxyMethod object represents a proxy method in the proxy class 845 * being generated: a method whose implementation will encode and 846 * dispatch invocations to the proxy instance's invocation handler. 847 */ 848 private class ProxyMethod { 849 850 public String methodName; 851 public Class<?>[] parameterTypes; 852 public Class<?> returnType; 853 public Class<?>[] exceptionTypes; 854 public Class<?> fromClass; 855 public String methodFieldName; 856 857 private ProxyMethod(String methodName, Class<?>[] parameterTypes, 1508 if (type == long.class || type == double.class) { 1509 return 2; 1510 } else { 1511 return 1; 1512 } 1513 } 1514 1515 /** 1516 * Add to the given list all of the types in the "from" array that 1517 * are not already contained in the list and are assignable to at 1518 * least one of the types in the "with" array. 1519 * 1520 * This method is useful for computing the greatest common set of 1521 * declared exceptions from duplicate methods inherited from 1522 * different interfaces. 1523 */ 1524 private static void collectCompatibleTypes(Class<?>[] from, 1525 Class<?>[] with, 1526 List<Class<?>> list) 1527 { 1528 for (int i = 0; i < from.length; i++) { 1529 if (!list.contains(from[i])) { 1530 for (int j = 0; j < with.length; j++) { 1531 if (with[j].isAssignableFrom(from[i])) { 1532 list.add(from[i]); 1533 break; 1534 } 1535 } 1536 } 1537 } 1538 } 1539 1540 /** 1541 * Given the exceptions declared in the throws clause of a proxy method, 1542 * compute the exceptions that need to be caught from the invocation 1543 * handler's invoke method and rethrown intact in the method's 1544 * implementation before catching other Throwables and wrapping them 1545 * in UndeclaredThrowableExceptions. 1546 * 1547 * The exceptions to be caught are returned in a List object. Each 1548 * exception in the returned list is guaranteed to not be a subclass of 1549 * any of the other exceptions in the list, so the catch blocks for 1550 * these exceptions may be generated in any order relative to each other. 1551 * 1552 * Error and RuntimeException are each always contained by the returned 1553 * list (if none of their superclasses are contained), since those 1554 * unchecked exceptions should always be rethrown intact, and thus their 1555 * subclasses will never appear in the returned list. 1556 * 1557 * The returned List will be empty if java.lang.Throwable is in the 1558 * given list of declared exceptions, indicating that no exceptions 1559 * need to be caught. 1560 */ 1561 private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) { 1562 List<Class<?>> uniqueList = new ArrayList<Class<?>>(); 1563 // unique exceptions to catch 1564 1565 uniqueList.add(Error.class); // always catch/rethrow these 1566 uniqueList.add(RuntimeException.class); 1567 1568 nextException: 1569 for (int i = 0; i < exceptions.length; i++) { 1570 Class<?> ex = exceptions[i]; 1571 if (ex.isAssignableFrom(Throwable.class)) { 1572 /* 1573 * If Throwable is declared to be thrown by the proxy method, 1574 * then no catch blocks are necessary, because the invoke 1575 * can, at most, throw Throwable anyway. 1576 */ 1577 uniqueList.clear(); 1578 break; 1579 } else if (!Throwable.class.isAssignableFrom(ex)) { 1580 /* 1581 * Ignore types that cannot be thrown by the invoke method. 1582 */ 1583 continue; 1584 } 1585 /* 1586 * Compare this exception against the current list of 1587 * exceptions that need to be caught: 1588 */ 1589 for (int j = 0; j < uniqueList.size();) { 1590 Class<?> ex2 = uniqueList.get(j); | 297 // private static final int opc_ifnull = 198; 298 // private static final int opc_ifnonnull = 199; 299 // private static final int opc_goto_w = 200; 300 // private static final int opc_jsr_w = 201; 301 302 // end of constants copied from sun.tools.java.RuntimeConstants 303 304 /** name of the superclass of proxy classes */ 305 private final static String superclassName = "java/lang/reflect/Proxy"; 306 307 /** name of field for storing a proxy instance's invocation handler */ 308 private final static String handlerFieldName = "h"; 309 310 /** debugging flag for saving generated class files */ 311 private final static boolean saveGeneratedFiles = 312 java.security.AccessController.doPrivileged( 313 new GetBooleanAction( 314 "sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue(); 315 316 /** 317 * Generate a public proxy class given a name and a list of proxy interfaces. 318 */ 319 public static byte[] generateProxyClass(final String name, 320 Class<?>[] interfaces) { 321 return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER)); 322 } 323 324 /** 325 * Generate a proxy class given a name and a list of proxy interfaces. 326 * 327 * @param name the class name of the proxy class 328 * @param interfaces proxy interfaces 329 * @param accessFlags access flags of the proxy class 330 */ 331 public static byte[] generateProxyClass(final String name, 332 Class<?>[] interfaces, 333 int accessFlags) 334 { 335 ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags); 336 final byte[] classFile = gen.generateClassFile(); 337 338 if (saveGeneratedFiles) { 339 java.security.AccessController.doPrivileged( 340 new java.security.PrivilegedAction<Void>() { 341 public Void run() { 342 try (FileOutputStream file = 343 new FileOutputStream(dotToSlash(name) + ".class")) { 344 file.write(classFile); 345 return null; 346 } catch (IOException e) { 347 throw new InternalError( 348 "I/O exception saving generated file: " + e); 349 } 350 } 351 }); 352 } 353 354 return classFile; 355 } 356 357 /* preloaded Method objects for methods in java.lang.Object */ 358 private static Method hashCodeMethod; 359 private static Method equalsMethod; 360 private static Method toStringMethod; 361 static { 362 try { 363 hashCodeMethod = Object.class.getMethod("hashCode"); 364 equalsMethod = 365 Object.class.getMethod("equals", new Class<?>[] { Object.class }); 366 toStringMethod = Object.class.getMethod("toString"); 367 } catch (NoSuchMethodException e) { 368 throw new NoSuchMethodError(e.getMessage()); 369 } 370 } 371 372 /** name of proxy class */ 373 private String className; 374 375 /** proxy interfaces */ 376 private Class[] interfaces; 377 378 /** proxy class access flags */ 379 private int accessFlags; 380 381 /** constant pool of class being generated */ 382 private ConstantPool cp = new ConstantPool(); 383 384 /** FieldInfo struct for each field of generated class */ 385 private List<FieldInfo> fields = new ArrayList<>(); 386 387 /** MethodInfo struct for each method of generated class */ 388 private List<MethodInfo> methods = new ArrayList<>(); 389 390 /** 391 * maps method signature string to list of ProxyMethod objects for 392 * proxy methods with that signature 393 */ 394 private Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>(); 395 396 /** count of ProxyMethod objects added to proxyMethods */ 397 private int proxyMethodCount = 0; 398 399 /** 400 * Construct a ProxyGenerator to generate a proxy class with the 401 * specified name and for the given interfaces. 402 * 403 * A ProxyGenerator object contains the state for the ongoing 404 * generation of a particular proxy class. 405 */ 406 private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) { 407 this.className = className; 408 this.interfaces = interfaces; 409 this.accessFlags = accessFlags; 410 } 411 412 /** 413 * Generate a class file for the proxy class. This method drives the 414 * class file generation process. 415 */ 416 private byte[] generateClassFile() { 417 418 /* ============================================================ 419 * Step 1: Assemble ProxyMethod objects for all methods to 420 * generate proxy dispatching code for. 421 */ 422 423 /* 424 * Record that proxy methods are needed for the hashCode, equals, 425 * and toString methods of java.lang.Object. This is done before 426 * the methods from the proxy interfaces so that the methods from 427 * java.lang.Object take precedence over duplicate methods in the 428 * proxy interfaces. 429 */ 430 addProxyMethod(hashCodeMethod, Object.class); 431 addProxyMethod(equalsMethod, Object.class); 432 addProxyMethod(toStringMethod, Object.class); 433 434 /* 435 * Now record all of the methods from the proxy interfaces, giving 436 * earlier interfaces precedence over later ones with duplicate 437 * methods. 438 */ 439 for (Class<?> intf : interfaces) { 440 for (Method m : intf.getMethods()) { 441 addProxyMethod(m, intf); 442 } 443 } 444 445 /* 446 * For each set of proxy methods with the same signature, 447 * verify that the methods' return types are compatible. 448 */ 449 for (List<ProxyMethod> sigmethods : proxyMethods.values()) { 450 checkReturnTypes(sigmethods); 451 } 452 453 /* ============================================================ 454 * Step 2: Assemble FieldInfo and MethodInfo structs for all of 455 * fields and methods in the class we are generating. 456 */ 457 try { 458 methods.add(generateConstructor()); 459 460 for (List<ProxyMethod> sigmethods : proxyMethods.values()) { 461 for (ProxyMethod pm : sigmethods) { 476 throw new InternalError("unexpected I/O Exception", e); 477 } 478 479 if (methods.size() > 65535) { 480 throw new IllegalArgumentException("method limit exceeded"); 481 } 482 if (fields.size() > 65535) { 483 throw new IllegalArgumentException("field limit exceeded"); 484 } 485 486 /* ============================================================ 487 * Step 3: Write the final class file. 488 */ 489 490 /* 491 * Make sure that constant pool indexes are reserved for the 492 * following items before starting to write the final class file. 493 */ 494 cp.getClass(dotToSlash(className)); 495 cp.getClass(superclassName); 496 for (Class<?> intf: interfaces) { 497 cp.getClass(dotToSlash(intf.getName())); 498 } 499 500 /* 501 * Disallow new constant pool additions beyond this point, since 502 * we are about to write the final constant pool table. 503 */ 504 cp.setReadOnly(); 505 506 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 507 DataOutputStream dout = new DataOutputStream(bout); 508 509 try { 510 /* 511 * Write all the items of the "ClassFile" structure. 512 * See JVMS section 4.1. 513 */ 514 // u4 magic; 515 dout.writeInt(0xCAFEBABE); 516 // u2 minor_version; 517 dout.writeShort(CLASSFILE_MINOR_VERSION); 518 // u2 major_version; 519 dout.writeShort(CLASSFILE_MAJOR_VERSION); 520 521 cp.write(dout); // (write constant pool) 522 523 // u2 access_flags; 524 dout.writeShort(accessFlags); 525 // u2 this_class; 526 dout.writeShort(cp.getClass(dotToSlash(className))); 527 // u2 super_class; 528 dout.writeShort(cp.getClass(superclassName)); 529 530 // u2 interfaces_count; 531 dout.writeShort(interfaces.length); 532 // u2 interfaces[interfaces_count]; 533 for (Class<?> intf : interfaces) { 534 dout.writeShort(cp.getClass( 535 dotToSlash(intf.getName()))); 536 } 537 538 // u2 fields_count; 539 dout.writeShort(fields.size()); 540 // field_info fields[fields_count]; 541 for (FieldInfo f : fields) { 542 f.write(dout); 543 } 544 545 // u2 methods_count; 546 dout.writeShort(methods.size()); 547 // method_info methods[methods_count]; 548 for (MethodInfo m : methods) { 549 m.write(dout); 550 } 551 552 // u2 attributes_count; 553 dout.writeShort(0); // (no ClassFile attributes for proxy classes) 554 555 } catch (IOException e) { 572 * passed to the invocation handler's "invoke" method for a given 573 * set of duplicate methods. 574 */ 575 private void addProxyMethod(Method m, Class<?> fromClass) { 576 String name = m.getName(); 577 Class<?>[] parameterTypes = m.getParameterTypes(); 578 Class<?> returnType = m.getReturnType(); 579 Class<?>[] exceptionTypes = m.getExceptionTypes(); 580 581 String sig = name + getParameterDescriptors(parameterTypes); 582 List<ProxyMethod> sigmethods = proxyMethods.get(sig); 583 if (sigmethods != null) { 584 for (ProxyMethod pm : sigmethods) { 585 if (returnType == pm.returnType) { 586 /* 587 * Found a match: reduce exception types to the 588 * greatest set of exceptions that can thrown 589 * compatibly with the throws clauses of both 590 * overridden methods. 591 */ 592 List<Class<?>> legalExceptions = new ArrayList<>(); 593 collectCompatibleTypes( 594 exceptionTypes, pm.exceptionTypes, legalExceptions); 595 collectCompatibleTypes( 596 pm.exceptionTypes, exceptionTypes, legalExceptions); 597 pm.exceptionTypes = new Class<?>[legalExceptions.size()]; 598 pm.exceptionTypes = 599 legalExceptions.toArray(pm.exceptionTypes); 600 return; 601 } 602 } 603 } else { 604 sigmethods = new ArrayList<>(3); 605 proxyMethods.put(sig, sigmethods); 606 } 607 sigmethods.add(new ProxyMethod(name, parameterTypes, returnType, 608 exceptionTypes, fromClass)); 609 } 610 611 /** 612 * For a given set of proxy methods with the same signature, check 613 * that their return types are compatible according to the Proxy 614 * specification. 615 * 616 * Specifically, if there is more than one such method, then all 617 * of the return types must be reference types, and there must be 618 * one return type that is assignable to each of the rest of them. 619 */ 620 private static void checkReturnTypes(List<ProxyMethod> methods) { 621 /* 622 * If there is only one method with a given signature, there 623 * cannot be a conflict. This is the only case in which a 624 * primitive (or void) return type is allowed. 625 */ 626 if (methods.size() < 2) { 627 return; 628 } 629 630 /* 631 * List of return types that are not yet known to be 632 * assignable from ("covered" by) any of the others. 633 */ 634 LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>(); 635 636 nextNewReturnType: 637 for (ProxyMethod pm : methods) { 638 Class<?> newReturnType = pm.returnType; 639 if (newReturnType.isPrimitive()) { 640 throw new IllegalArgumentException( 641 "methods with same signature " + 642 getFriendlyMethodSignature(pm.methodName, 643 pm.parameterTypes) + 644 " but incompatible return types: " + 645 newReturnType.getName() + " and others"); 646 } 647 boolean added = false; 648 649 /* 650 * Compare the new return type to the existing uncovered 651 * return types. 652 */ 653 ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator(); 654 while (liter.hasNext()) { 829 out.writeShort(e.startPc); 830 // u2 end_pc; 831 out.writeShort(e.endPc); 832 // u2 handler_pc; 833 out.writeShort(e.handlerPc); 834 // u2 catch_type; 835 out.writeShort(e.catchType); 836 } 837 // u2 attributes_count; 838 out.writeShort(0); 839 840 // write "Exceptions" attribute. See JVMS section 4.7.4. 841 842 // u2 attribute_name_index; 843 out.writeShort(cp.getUtf8("Exceptions")); 844 // u4 attributes_length; 845 out.writeInt(2 + 2 * declaredExceptions.length); 846 // u2 number_of_exceptions; 847 out.writeShort(declaredExceptions.length); 848 // u2 exception_index_table[number_of_exceptions]; 849 for (short value : declaredExceptions) { 850 out.writeShort(value); 851 } 852 } 853 854 } 855 856 /** 857 * A ProxyMethod object represents a proxy method in the proxy class 858 * being generated: a method whose implementation will encode and 859 * dispatch invocations to the proxy instance's invocation handler. 860 */ 861 private class ProxyMethod { 862 863 public String methodName; 864 public Class<?>[] parameterTypes; 865 public Class<?> returnType; 866 public Class<?>[] exceptionTypes; 867 public Class<?> fromClass; 868 public String methodFieldName; 869 870 private ProxyMethod(String methodName, Class<?>[] parameterTypes, 1521 if (type == long.class || type == double.class) { 1522 return 2; 1523 } else { 1524 return 1; 1525 } 1526 } 1527 1528 /** 1529 * Add to the given list all of the types in the "from" array that 1530 * are not already contained in the list and are assignable to at 1531 * least one of the types in the "with" array. 1532 * 1533 * This method is useful for computing the greatest common set of 1534 * declared exceptions from duplicate methods inherited from 1535 * different interfaces. 1536 */ 1537 private static void collectCompatibleTypes(Class<?>[] from, 1538 Class<?>[] with, 1539 List<Class<?>> list) 1540 { 1541 for (Class<?> fc: from) { 1542 if (!list.contains(fc)) { 1543 for (Class<?> wc: with) { 1544 if (wc.isAssignableFrom(fc)) { 1545 list.add(fc); 1546 break; 1547 } 1548 } 1549 } 1550 } 1551 } 1552 1553 /** 1554 * Given the exceptions declared in the throws clause of a proxy method, 1555 * compute the exceptions that need to be caught from the invocation 1556 * handler's invoke method and rethrown intact in the method's 1557 * implementation before catching other Throwables and wrapping them 1558 * in UndeclaredThrowableExceptions. 1559 * 1560 * The exceptions to be caught are returned in a List object. Each 1561 * exception in the returned list is guaranteed to not be a subclass of 1562 * any of the other exceptions in the list, so the catch blocks for 1563 * these exceptions may be generated in any order relative to each other. 1564 * 1565 * Error and RuntimeException are each always contained by the returned 1566 * list (if none of their superclasses are contained), since those 1567 * unchecked exceptions should always be rethrown intact, and thus their 1568 * subclasses will never appear in the returned list. 1569 * 1570 * The returned List will be empty if java.lang.Throwable is in the 1571 * given list of declared exceptions, indicating that no exceptions 1572 * need to be caught. 1573 */ 1574 private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) { 1575 List<Class<?>> uniqueList = new ArrayList<>(); 1576 // unique exceptions to catch 1577 1578 uniqueList.add(Error.class); // always catch/rethrow these 1579 uniqueList.add(RuntimeException.class); 1580 1581 nextException: 1582 for (Class<?> ex: exceptions) { 1583 if (ex.isAssignableFrom(Throwable.class)) { 1584 /* 1585 * If Throwable is declared to be thrown by the proxy method, 1586 * then no catch blocks are necessary, because the invoke 1587 * can, at most, throw Throwable anyway. 1588 */ 1589 uniqueList.clear(); 1590 break; 1591 } else if (!Throwable.class.isAssignableFrom(ex)) { 1592 /* 1593 * Ignore types that cannot be thrown by the invoke method. 1594 */ 1595 continue; 1596 } 1597 /* 1598 * Compare this exception against the current list of 1599 * exceptions that need to be caught: 1600 */ 1601 for (int j = 0; j < uniqueList.size();) { 1602 Class<?> ex2 = uniqueList.get(j); |