src/share/classes/sun/misc/ProxyGenerator.java

Print this page




 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);