sun/misc/ProxyGenerator.java

Mercurial
jdk7/jdk7/jdk / file revision
summary | shortlog | changelog | tags | manifest | changeset | file | revisions | annotate | diff | raw
src/share/classes/sun/misc/ProxyGenerator.java
author ohair

Tue May 25 15:58:33 2010 -0700 (3 years ago)
changeset 2362 00cd9dc3c2b5
parent 381 b6d6877c1155
permissions -rw-r--r--
6943119: Rebrand source copyright notices
Reviewed-by: darcy, weijun
 1 /*
 2 * Copyright (c) 1999, 2008, 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 sun.misc;
 27
 28 import java.io.ByteArrayOutputStream;
 29 import java.io.DataOutputStream;
 30 import java.io.FileOutputStream;
 31 import java.io.IOException;
 32 import java.io.OutputStream;
 33 import java.lang.reflect.Array;
 34 import java.lang.reflect.Method;
 35 import java.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 public 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 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) {
 449
 450 // add static field for method's Method object
 451 fields.add(new FieldInfo(pm.methodFieldName,
 452 "Ljava/lang/reflect/Method;",
 453 ACC_PRIVATE | ACC_STATIC));
 454
 455 // generate code for proxy method and add it
 456 methods.add(pm.generateMethod());
 457 }
 458 }
 459
 460 methods.add(generateStaticInitializer());
 461
 462 } catch (IOException e) {
 463 throw new InternalError("unexpected I/O Exception");
 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) {
 543 throw new InternalError("unexpected I/O Exception");
 544 }
 545
 546 return bout.toByteArray();
 547 }
 548
 549 /**
 550 * Add another method to be proxied, either by creating a new
 551 * ProxyMethod object or augmenting an old one for a duplicate
 552 * method.
 553 *
 554 * "fromClass" indicates the proxy interface that the method was
 555 * found through, which may be different from (a subinterface of)
 556 * the method's "declaring class".  Note that the first Method
 557 * object passed for a given name and descriptor identifies the
 558 * Method object (and thus the declaring class) that will be
 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()) {
 642 Class<?> uncoveredReturnType = liter.next();
 643
 644 /*
 645 * If an existing uncovered return type is assignable
 646 * to this new one, then we can forget the new one.
 647 */
 648 if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
 649 assert !added;
 650 continue nextNewReturnType;
 651 }
 652
 653 /*
 654 * If the new return type is assignable to an existing
 655 * uncovered one, then should replace the existing one
 656 * with the new one (or just forget the existing one,
 657 * if the new one has already be put in the list).
 658 */
 659 if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
 660 // (we can assume that each return type is unique)
 661 if (!added) {
 662 liter.set(newReturnType);
 663 added = true;
 664 } else {
 665 liter.remove();
 666 }
 667 }
 668 }
 669
 670 /*
 671 * If we got through the list of existing uncovered return
 672 * types without an assignability relationship, then add
 673 * the new return type to the list of uncovered ones.
 674 */
 675 if (!added) {
 676 uncoveredReturnTypes.add(newReturnType);
 677 }
 678 }
 679
 680 /*
 681 * We shouldn't end up with more than one return type that is
 682 * not assignable from any of the others.
 683 */
 684 if (uncoveredReturnTypes.size() > 1) {
 685 ProxyMethod pm = methods.get(0);
 686 throw new IllegalArgumentException(
 687 "methods with same signature " +
 688 getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) +
 689 " but incompatible return types: " + uncoveredReturnTypes);
 690 }
 691 }
 692
 693 /**
 694 * A FieldInfo object contains information about a particular field
 695 * in the class being generated.  The class mirrors the data items of
 696 * the "field_info" structure of the class file format (see JVMS 4.5).
 697 */
 698 private class FieldInfo {
 699 public int accessFlags;
 700 public String name;
 701 public String descriptor;
 702
 703 public FieldInfo(String name, String descriptor, int accessFlags) {
 704 this.name = name;
 705 this.descriptor = descriptor;
 706 this.accessFlags = accessFlags;
 707
 708 /*
 709 * Make sure that constant pool indexes are reserved for the
 710 * following items before starting to write the final class file.
 711 */
 712 cp.getUtf8(name);
 713 cp.getUtf8(descriptor);
 714 }
 715
 716 public void write(DataOutputStream out) throws IOException {
 717 /*
 718 * Write all the items of the "field_info" structure.
 719 * See JVMS section 4.5.
 720 */
 721 // u2 access_flags;
 722 out.writeShort(accessFlags);
 723 // u2 name_index;
 724 out.writeShort(cp.getUtf8(name));
 725 // u2 descriptor_index;
 726 out.writeShort(cp.getUtf8(descriptor));
 727 // u2 attributes_count;
 728 out.writeShort(0);  // (no field_info attributes for proxy classes)
 729 }
 730 }
 731
 732 /**
 733 * An ExceptionTableEntry object holds values for the data items of
 734 * an entry in the "exception_table" item of the "Code" attribute of
 735 * "method_info" structures (see JVMS 4.7.3).
 736 */
 737 private static class ExceptionTableEntry {
 738 public short startPc;
 739 public short endPc;
 740 public short handlerPc;
 741 public short catchType;
 742
 743 public ExceptionTableEntry(short startPc, short endPc,
 744 short handlerPc, short catchType)
 745 {
 746 this.startPc = startPc;
 747 this.endPc = endPc;
 748 this.handlerPc = handlerPc;
 749 this.catchType = catchType;
 750 }
 751 };
 752
 753 /**
 754 * A MethodInfo object contains information about a particular method
 755 * in the class being generated.  This class mirrors the data items of
 756 * the "method_info" structure of the class file format (see JVMS 4.6).
 757 */
 758 private class MethodInfo {
 759 public int accessFlags;
 760 public String name;
 761 public String descriptor;
 762 public short maxStack;
 763 public short maxLocals;
 764 public ByteArrayOutputStream code = new ByteArrayOutputStream();
 765 public List<ExceptionTableEntry> exceptionTable =
 766 new ArrayList<ExceptionTableEntry>();
 767 public short[] declaredExceptions;
 768
 769 public MethodInfo(String name, String descriptor, int accessFlags) {
 770 this.name = name;
 771 this.descriptor = descriptor;
 772 this.accessFlags = accessFlags;
 773
 774 /*
 775 * Make sure that constant pool indexes are reserved for the
 776 * following items before starting to write the final class file.
 777 */
 778 cp.getUtf8(name);
 779 cp.getUtf8(descriptor);
 780 cp.getUtf8("Code");
 781 cp.getUtf8("Exceptions");
 782 }
 783
 784 public void write(DataOutputStream out) throws IOException {
 785 /*
 786 * Write all the items of the "method_info" structure.
 787 * See JVMS section 4.6.
 788 */
 789 // u2 access_flags;
 790 out.writeShort(accessFlags);
 791 // u2 name_index;
 792 out.writeShort(cp.getUtf8(name));
 793 // u2 descriptor_index;
 794 out.writeShort(cp.getUtf8(descriptor));
 795 // u2 attributes_count;
 796 out.writeShort(2);  // (two method_info attributes:)
 797
 798 // Write "Code" attribute. See JVMS section 4.7.3.
 799
 800 // u2 attribute_name_index;
 801 out.writeShort(cp.getUtf8("Code"));
 802 // u4 attribute_length;
 803 out.writeInt(12 + code.size() + 8 * exceptionTable.size());
 804 // u2 max_stack;
 805 out.writeShort(maxStack);
 806 // u2 max_locals;
 807 out.writeShort(maxLocals);
 808 // u2 code_length;
 809 out.writeInt(code.size());
 810 // u1 code[code_length];
 811 code.writeTo(out);
 812 // u2 exception_table_length;
 813 out.writeShort(exceptionTable.size());
 814 for (ExceptionTableEntry e : exceptionTable) {
 815 // u2 start_pc;
 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,
 858 Class returnType, Class[] exceptionTypes,
 859 Class fromClass)
 860 {
 861 this.methodName = methodName;
 862 this.parameterTypes = parameterTypes;
 863 this.returnType = returnType;
 864 this.exceptionTypes = exceptionTypes;
 865 this.fromClass = fromClass;
 866 this.methodFieldName = "m" + proxyMethodCount++;
 867 }
 868
 869 /**
 870 * Return a MethodInfo object for this method, including generating
 871 * the code and exception table entry.
 872 */
 873 private MethodInfo generateMethod() throws IOException {
 874 String desc = getMethodDescriptor(parameterTypes, returnType);
 875 MethodInfo minfo = new MethodInfo(methodName, desc,
 876 ACC_PUBLIC | ACC_FINAL);
 877
 878 int[] parameterSlot = new int[parameterTypes.length];
 879 int nextSlot = 1;
 880 for (int i = 0; i < parameterSlot.length; i++) {
 881 parameterSlot[i] = nextSlot;
 882 nextSlot += getWordsPerType(parameterTypes[i]);
 883 }
 884 int localSlot0 = nextSlot;
 885 short pc, tryBegin = 0, tryEnd;
 886
 887 DataOutputStream out = new DataOutputStream(minfo.code);
 888
 889 code_aload(0, out);
 890
 891 out.writeByte(opc_getfield);
 892 out.writeShort(cp.getFieldRef(
 893 superclassName,
 894 handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));
 895
 896 code_aload(0, out);
 897
 898 out.writeByte(opc_getstatic);
 899 out.writeShort(cp.getFieldRef(
 900 dotToSlash(className),
 901 methodFieldName, "Ljava/lang/reflect/Method;"));
 902
 903 if (parameterTypes.length > 0) {
 904
 905 code_ipush(parameterTypes.length, out);
 906
 907 out.writeByte(opc_anewarray);
 908 out.writeShort(cp.getClass("java/lang/Object"));
 909
 910 for (int i = 0; i < parameterTypes.length; i++) {
 911
 912 out.writeByte(opc_dup);
 913
 914 code_ipush(i, out);
 915
 916 codeWrapArgument(parameterTypes[i], parameterSlot[i], out);
 917
 918 out.writeByte(opc_aastore);
 919 }
 920 } else {
 921
 922 out.writeByte(opc_aconst_null);
 923 }
 924
 925 out.writeByte(opc_invokeinterface);
 926 out.writeShort(cp.getInterfaceMethodRef(
 927 "java/lang/reflect/InvocationHandler",
 928 "invoke",
 929 "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
 930 "[Ljava/lang/Object;)Ljava/lang/Object;"));
 931 out.writeByte(4);
 932 out.writeByte(0);
 933
 934 if (returnType == void.class) {
 935
 936 out.writeByte(opc_pop);
 937
 938 out.writeByte(opc_return);
 939
 940 } else {
 941
 942 codeUnwrapReturnValue(returnType, out);
 943 }
 944
 945 tryEnd = pc = (short) minfo.code.size();
 946
 947 List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes);
 948 if (catchList.size() > 0) {
 949
 950 for (Class<?> ex : catchList) {
 951 minfo.exceptionTable.add(new ExceptionTableEntry(
 952 tryBegin, tryEnd, pc,
 953 cp.getClass(dotToSlash(ex.getName()))));
 954 }
 955
 956 out.writeByte(opc_athrow);
 957
 958 pc = (short) minfo.code.size();
 959
 960 minfo.exceptionTable.add(new ExceptionTableEntry(
 961 tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable")));
 962
 963 code_astore(localSlot0, out);
 964
 965 out.writeByte(opc_new);
 966 out.writeShort(cp.getClass(
 967 "java/lang/reflect/UndeclaredThrowableException"));
 968
 969 out.writeByte(opc_dup);
 970
 971 code_aload(localSlot0, out);
 972
 973 out.writeByte(opc_invokespecial);
 974
 975 out.writeShort(cp.getMethodRef(
 976 "java/lang/reflect/UndeclaredThrowableException",
 977 "<init>", "(Ljava/lang/Throwable;)V"));
 978
 979 out.writeByte(opc_athrow);
 980 }
 981
 982 if (minfo.code.size() > 65535) {
 983 throw new IllegalArgumentException("code size limit exceeded");
 984 }
 985
 986 minfo.maxStack = 10;
 987 minfo.maxLocals = (short) (localSlot0 + 1);
 988 minfo.declaredExceptions = new short[exceptionTypes.length];
 989 for (int i = 0; i < exceptionTypes.length; i++) {
 990 minfo.declaredExceptions[i] = cp.getClass(
 991 dotToSlash(exceptionTypes[i].getName()));
 992 }
 993
 994 return minfo;
 995 }
 996
 997 /**
 998 * Generate code for wrapping an argument of the given type
 999 * whose value can be found at the specified local variable
 1000 * index, in order for it to be passed (as an Object) to the
 1001 * invocation handler's "invoke" method.  The code is written
 1002 * to the supplied stream.
 1003 */
 1004 private void codeWrapArgument(Class type, int slot,
 1005 DataOutputStream out)
 1006 throws IOException
 1007 {
 1008 if (type.isPrimitive()) {
 1009 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
 1010
 1011 if (type == int.class ||
 1012 type == boolean.class ||
 1013 type == byte.class ||
 1014 type == char.class ||
 1015 type == short.class)
 1016 {
 1017 code_iload(slot, out);
 1018 } else if (type == long.class) {
 1019 code_lload(slot, out);
 1020 } else if (type == float.class) {
 1021 code_fload(slot, out);
 1022 } else if (type == double.class) {
 1023 code_dload(slot, out);
 1024 } else {
 1025 throw new AssertionError();
 1026 }
 1027
 1028 out.writeByte(opc_invokestatic);
 1029 out.writeShort(cp.getMethodRef(
 1030 prim.wrapperClassName,
 1031 "valueOf", prim.wrapperValueOfDesc));
 1032
 1033 } else {
 1034
 1035 code_aload(slot, out);
 1036 }
 1037 }
 1038
 1039 /**
 1040 * Generate code for unwrapping a return value of the given
 1041 * type from the invocation handler's "invoke" method (as type
 1042 * Object) to its correct type.  The code is written to the
 1043 * supplied stream.
 1044 */
 1045 private void codeUnwrapReturnValue(Class type, DataOutputStream out)
 1046 throws IOException
 1047 {
 1048 if (type.isPrimitive()) {
 1049 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
 1050
 1051 out.writeByte(opc_checkcast);
 1052 out.writeShort(cp.getClass(prim.wrapperClassName));
 1053
 1054 out.writeByte(opc_invokevirtual);
 1055 out.writeShort(cp.getMethodRef(
 1056 prim.wrapperClassName,
 1057 prim.unwrapMethodName, prim.unwrapMethodDesc));
 1058
 1059 if (type == int.class ||
 1060 type == boolean.class ||
 1061 type == byte.class ||
 1062 type == char.class ||
 1063 type == short.class)
 1064 {
 1065 out.writeByte(opc_ireturn);
 1066 } else if (type == long.class) {
 1067 out.writeByte(opc_lreturn);
 1068 } else if (type == float.class) {
 1069 out.writeByte(opc_freturn);
 1070 } else if (type == double.class) {
 1071 out.writeByte(opc_dreturn);
 1072 } else {
 1073 throw new AssertionError();
 1074 }
 1075
 1076 } else {
 1077
 1078 out.writeByte(opc_checkcast);
 1079 out.writeShort(cp.getClass(dotToSlash(type.getName())));
 1080
 1081 out.writeByte(opc_areturn);
 1082 }
 1083 }
 1084
 1085 /**
 1086 * Generate code for initializing the static field that stores
 1087 * the Method object for this proxy method.  The code is written
 1088 * to the supplied stream.
 1089 */
 1090 private void codeFieldInitialization(DataOutputStream out)
 1091 throws IOException
 1092 {
 1093 codeClassForName(fromClass, out);
 1094
 1095 code_ldc(cp.getString(methodName), out);
 1096
 1097 code_ipush(parameterTypes.length, out);
 1098
 1099 out.writeByte(opc_anewarray);
 1100 out.writeShort(cp.getClass("java/lang/Class"));
 1101
 1102 for (int i = 0; i < parameterTypes.length; i++) {
 1103
 1104 out.writeByte(opc_dup);
 1105
 1106 code_ipush(i, out);
 1107
 1108 if (parameterTypes[i].isPrimitive()) {
 1109 PrimitiveTypeInfo prim =
 1110 PrimitiveTypeInfo.get(parameterTypes[i]);
 1111
 1112 out.writeByte(opc_getstatic);
 1113 out.writeShort(cp.getFieldRef(
 1114 prim.wrapperClassName, "TYPE", "Ljava/lang/Class;"));
 1115
 1116 } else {
 1117 codeClassForName(parameterTypes[i], out);
 1118 }
 1119
 1120 out.writeByte(opc_aastore);
 1121 }
 1122
 1123 out.writeByte(opc_invokevirtual);
 1124 out.writeShort(cp.getMethodRef(
 1125 "java/lang/Class",
 1126 "getMethod",
 1127 "(Ljava/lang/String;[Ljava/lang/Class;)" +
 1128 "Ljava/lang/reflect/Method;"));
 1129
 1130 out.writeByte(opc_putstatic);
 1131 out.writeShort(cp.getFieldRef(
 1132 dotToSlash(className),
 1133 methodFieldName, "Ljava/lang/reflect/Method;"));
 1134 }
 1135 }
 1136
 1137 /**
 1138 * Generate the constructor method for the proxy class.
 1139 */
 1140 private MethodInfo generateConstructor() throws IOException {
 1141 MethodInfo minfo = new MethodInfo(
 1142 "<init>", "(Ljava/lang/reflect/InvocationHandler;)V",
 1143 ACC_PUBLIC);
 1144
 1145 DataOutputStream out = new DataOutputStream(minfo.code);
 1146
 1147 code_aload(0, out);
 1148
 1149 code_aload(1, out);
 1150
 1151 out.writeByte(opc_invokespecial);
 1152 out.writeShort(cp.getMethodRef(
 1153 superclassName,
 1154 "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
 1155
 1156 out.writeByte(opc_return);
 1157
 1158 minfo.maxStack = 10;
 1159 minfo.maxLocals = 2;
 1160 minfo.declaredExceptions = new short[0];
 1161
 1162 return minfo;
 1163 }
 1164
 1165 /**
 1166 * Generate the static initializer method for the proxy class.
 1167 */
 1168 private MethodInfo generateStaticInitializer() throws IOException {
 1169 MethodInfo minfo = new MethodInfo(
 1170 "<clinit>", "()V", ACC_STATIC);
 1171
 1172 int localSlot0 = 1;
 1173 short pc, tryBegin = 0, tryEnd;
 1174
 1175 DataOutputStream out = new DataOutputStream(minfo.code);
 1176
 1177 for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 1178 for (ProxyMethod pm : sigmethods) {
 1179 pm.codeFieldInitialization(out);
 1180 }
 1181 }
 1182
 1183 out.writeByte(opc_return);
 1184
 1185 tryEnd = pc = (short) minfo.code.size();
 1186
 1187 minfo.exceptionTable.add(new ExceptionTableEntry(
 1188 tryBegin, tryEnd, pc,
 1189 cp.getClass("java/lang/NoSuchMethodException")));
 1190
 1191 code_astore(localSlot0, out);
 1192
 1193 out.writeByte(opc_new);
 1194 out.writeShort(cp.getClass("java/lang/NoSuchMethodError"));
 1195
 1196 out.writeByte(opc_dup);
 1197
 1198 code_aload(localSlot0, out);
 1199
 1200 out.writeByte(opc_invokevirtual);
 1201 out.writeShort(cp.getMethodRef(
 1202 "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
 1203
 1204 out.writeByte(opc_invokespecial);
 1205 out.writeShort(cp.getMethodRef(
 1206 "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V"));
 1207
 1208 out.writeByte(opc_athrow);
 1209
 1210 pc = (short) minfo.code.size();
 1211
 1212 minfo.exceptionTable.add(new ExceptionTableEntry(
 1213 tryBegin, tryEnd, pc,
 1214 cp.getClass("java/lang/ClassNotFoundException")));
 1215
 1216 code_astore(localSlot0, out);
 1217
 1218 out.writeByte(opc_new);
 1219 out.writeShort(cp.getClass("java/lang/NoClassDefFoundError"));
 1220
 1221 out.writeByte(opc_dup);
 1222
 1223 code_aload(localSlot0, out);
 1224
 1225 out.writeByte(opc_invokevirtual);
 1226 out.writeShort(cp.getMethodRef(
 1227 "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
 1228
 1229 out.writeByte(opc_invokespecial);
 1230 out.writeShort(cp.getMethodRef(
 1231 "java/lang/NoClassDefFoundError",
 1232 "<init>", "(Ljava/lang/String;)V"));
 1233
 1234 out.writeByte(opc_athrow);
 1235
 1236 if (minfo.code.size() > 65535) {
 1237 throw new IllegalArgumentException("code size limit exceeded");
 1238 }
 1239
 1240 minfo.maxStack = 10;
 1241 minfo.maxLocals = (short) (localSlot0 + 1);
 1242 minfo.declaredExceptions = new short[0];
 1243
 1244 return minfo;
 1245 }
 1246
 1247
 1248 /*
 1249 * =============== Code Generation Utility Methods ===============
 1250 */
 1251
 1252 /*
 1253 * The following methods generate code for the load or store operation
 1254 * indicated by their name for the given local variable.  The code is
 1255 * written to the supplied stream.
 1256 */
 1257
 1258 private void code_iload(int lvar, DataOutputStream out)
 1259 throws IOException
 1260 {
 1261 codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out);
 1262 }
 1263
 1264 private void code_lload(int lvar, DataOutputStream out)
 1265 throws IOException
 1266 {
 1267 codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out);
 1268 }
 1269
 1270 private void code_fload(int lvar, DataOutputStream out)
 1271 throws IOException
 1272 {
 1273 codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out);
 1274 }
 1275
 1276 private void code_dload(int lvar, DataOutputStream out)
 1277 throws IOException
 1278 {
 1279 codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out);
 1280 }
 1281
 1282 private void code_aload(int lvar, DataOutputStream out)
 1283 throws IOException
 1284 {
 1285 codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out);
 1286 }
 1287
 1288 //  private void code_istore(int lvar, DataOutputStream out)
 1289 //      throws IOException
 1290 //  {
 1291 //      codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out);
 1292 //  }
 1293
 1294 //  private void code_lstore(int lvar, DataOutputStream out)
 1295 //      throws IOException
 1296 //  {
 1297 //      codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out);
 1298 //  }
 1299
 1300 //  private void code_fstore(int lvar, DataOutputStream out)
 1301 //      throws IOException
 1302 //  {
 1303 //      codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out);
 1304 //  }
 1305
 1306 //  private void code_dstore(int lvar, DataOutputStream out)
 1307 //      throws IOException
 1308 //  {
 1309 //      codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out);
 1310 //  }
 1311
 1312 private void code_astore(int lvar, DataOutputStream out)
 1313 throws IOException
 1314 {
 1315 codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out);
 1316 }
 1317
 1318 /**
 1319 * Generate code for a load or store instruction for the given local
 1320 * variable.  The code is written to the supplied stream.
 1321 *
 1322 * "opcode" indicates the opcode form of the desired load or store
 1323 * instruction that takes an explicit local variable index, and
 1324 * "opcode_0" indicates the corresponding form of the instruction
 1325 * with the implicit index 0.
 1326 */
 1327 private void codeLocalLoadStore(int lvar, int opcode, int opcode_0,
 1328 DataOutputStream out)
 1329 throws IOException
 1330 {
 1331 assert lvar >= 0 && lvar <= 0xFFFF;
 1332 if (lvar <= 3) {
 1333 out.writeByte(opcode_0 + lvar);
 1334 } else if (lvar <= 0xFF) {
 1335 out.writeByte(opcode);
 1336 out.writeByte(lvar & 0xFF);
 1337 } else {
 1338 /*
 1339 * Use the "wide" instruction modifier for local variable
 1340 * indexes that do not fit into an unsigned byte.
 1341 */
 1342 out.writeByte(opc_wide);
 1343 out.writeByte(opcode);
 1344 out.writeShort(lvar & 0xFFFF);
 1345 }
 1346 }
 1347
 1348 /**
 1349 * Generate code for an "ldc" instruction for the given constant pool
 1350 * index (the "ldc_w" instruction is used if the index does not fit
 1351 * into an unsigned byte).  The code is written to the supplied stream.
 1352 */
 1353 private void code_ldc(int index, DataOutputStream out)
 1354 throws IOException
 1355 {
 1356 assert index >= 0 && index <= 0xFFFF;
 1357 if (index <= 0xFF) {
 1358 out.writeByte(opc_ldc);
 1359 out.writeByte(index & 0xFF);
 1360 } else {
 1361 out.writeByte(opc_ldc_w);
 1362 out.writeShort(index & 0xFFFF);
 1363 }
 1364 }
 1365
 1366 /**
 1367 * Generate code to push a constant integer value on to the operand
 1368 * stack, using the "iconst_<i>", "bipush", or "sipush" instructions
 1369 * depending on the size of the value.  The code is written to the
 1370 * supplied stream.
 1371 */
 1372 private void code_ipush(int value, DataOutputStream out)
 1373 throws IOException
 1374 {
 1375 if (value >= -1 && value <= 5) {
 1376 out.writeByte(opc_iconst_0 + value);
 1377 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
 1378 out.writeByte(opc_bipush);
 1379 out.writeByte(value & 0xFF);
 1380 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
 1381 out.writeByte(opc_sipush);
 1382 out.writeShort(value & 0xFFFF);
 1383 } else {
 1384 throw new AssertionError();
 1385 }
 1386 }
 1387
 1388 /**
 1389 * Generate code to invoke the Class.forName with the name of the given
 1390 * class to get its Class object at runtime.  The code is written to
 1391 * the supplied stream.  Note that the code generated by this method
 1392 * may caused the checked ClassNotFoundException to be thrown.
 1393 */
 1394 private void codeClassForName(Class cl, DataOutputStream out)
 1395 throws IOException
 1396 {
 1397 code_ldc(cp.getString(cl.getName()), out);
 1398
 1399 out.writeByte(opc_invokestatic);
 1400 out.writeShort(cp.getMethodRef(
 1401 "java/lang/Class",
 1402 "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));
 1403 }
 1404
 1405
 1406 /*
 1407 * ==================== General Utility Methods ====================
 1408 */
 1409
 1410 /**
 1411 * Convert a fully qualified class name that uses '.' as the package
 1412 * separator, the external representation used by the Java language
 1413 * and APIs, to a fully qualified class name that uses '/' as the
 1414 * package separator, the representation used in the class file
 1415 * format (see JVMS section 4.2).
 1416 */
 1417 private static String dotToSlash(String name) {
 1418 return name.replace('.', '/');
 1419 }
 1420
 1421 /**
 1422 * Return the "method descriptor" string for a method with the given
 1423 * parameter types and return type.  See JVMS section 4.3.3.
 1424 */
 1425 private static String getMethodDescriptor(Class[] parameterTypes,
 1426 Class returnType)
 1427 {
 1428 return getParameterDescriptors(parameterTypes) +
 1429 ((returnType == void.class) ? "V" : getFieldType(returnType));
 1430 }
 1431
 1432 /**
 1433 * Return the list of "parameter descriptor" strings enclosed in
 1434 * parentheses corresponding to the given parameter types (in other
 1435 * words, a method descriptor without a return descriptor).  This
 1436 * string is useful for constructing string keys for methods without
 1437 * regard to their return type.
 1438 */
 1439 private static String getParameterDescriptors(Class[] parameterTypes) {
 1440 StringBuilder desc = new StringBuilder("(");
 1441 for (int i = 0; i < parameterTypes.length; i++) {
 1442 desc.append(getFieldType(parameterTypes[i]));
 1443 }
 1444 desc.append(')');
 1445 return desc.toString();
 1446 }
 1447
 1448 /**
 1449 * Return the "field type" string for the given type, appropriate for
 1450 * a field descriptor, a parameter descriptor, or a return descriptor
 1451 * other than "void".  See JVMS section 4.3.2.
 1452 */
 1453 private static String getFieldType(Class type) {
 1454 if (type.isPrimitive()) {
 1455 return PrimitiveTypeInfo.get(type).baseTypeString;
 1456 } else if (type.isArray()) {
 1457 /*
 1458 * According to JLS 20.3.2, the getName() method on Class does
 1459 * return the VM type descriptor format for array classes (only);
 1460 * using that should be quicker than the otherwise obvious code:
 1461 *
 1462 *     return "[" + getTypeDescriptor(type.getComponentType());
 1463 */
 1464 return type.getName().replace('.', '/');
 1465 } else {
 1466 return "L" + dotToSlash(type.getName()) + ";";
 1467 }
 1468 }
 1469
 1470 /**
 1471 * Returns a human-readable string representing the signature of a
 1472 * method with the given name and parameter types.
 1473 */
 1474 private static String getFriendlyMethodSignature(String name,
 1475 Class[] parameterTypes)
 1476 {
 1477 StringBuilder sig = new StringBuilder(name);
 1478 sig.append('(');
 1479 for (int i = 0; i < parameterTypes.length; i++) {
 1480 if (i > 0) {
 1481 sig.append(',');
 1482 }
 1483 Class parameterType = parameterTypes[i];
 1484 int dimensions = 0;
 1485 while (parameterType.isArray()) {
 1486 parameterType = parameterType.getComponentType();
 1487 dimensions++;
 1488 }
 1489 sig.append(parameterType.getName());
 1490 while (dimensions-- > 0) {
 1491 sig.append("[]");
 1492 }
 1493 }
 1494 sig.append(')');
 1495 return sig.toString();
 1496 }
 1497
 1498 /**
 1499 * Return the number of abstract "words", or consecutive local variable
 1500 * indexes, required to contain a value of the given type.  See JVMS
 1501 * section 3.6.1.
 1502 *
 1503 * Note that the original version of the JVMS contained a definition of
 1504 * this abstract notion of a "word" in section 3.4, but that definition
 1505 * was removed for the second edition.
 1506 */
 1507 private static int getWordsPerType(Class type) {
 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);
 1591 if (ex2.isAssignableFrom(ex)) {
 1592 /*
 1593 * if a superclass of this exception is already on
 1594 * the list to catch, then ignore this one and continue;
 1595 */
 1596 continue nextException;
 1597 } else if (ex.isAssignableFrom(ex2)) {
 1598 /*
 1599 * if a subclass of this exception is on the list
 1600 * to catch, then remove it;
 1601 */
 1602 uniqueList.remove(j);
 1603 } else {
 1604 j++;        // else continue comparing.
 1605 }
 1606 }
 1607 // This exception is unique (so far): add it to the list to catch.
 1608 uniqueList.add(ex);
 1609 }
 1610 return uniqueList;
 1611 }
 1612
 1613 /**
 1614 * A PrimitiveTypeInfo object contains assorted information about
 1615 * a primitive type in its public fields.  The struct for a particular
 1616 * primitive type can be obtained using the static "get" method.
 1617 */
 1618 private static class PrimitiveTypeInfo {
 1619
 1620 /** "base type" used in various descriptors (see JVMS section 4.3.2) */
 1621 public String baseTypeString;
 1622
 1623 /** name of corresponding wrapper class */
 1624 public String wrapperClassName;
 1625
 1626 /** method descriptor for wrapper class "valueOf" factory method */
 1627 public String wrapperValueOfDesc;
 1628
 1629 /** name of wrapper class method for retrieving primitive value */
 1630 public String unwrapMethodName;
 1631
 1632 /** descriptor of same method */
 1633 public String unwrapMethodDesc;
 1634
 1635 private static Map<Class,PrimitiveTypeInfo> table =
 1636 new HashMap<Class,PrimitiveTypeInfo>();
 1637 static {
 1638 add(byte.class, Byte.class);
 1639 add(char.class, Character.class);
 1640 add(double.class, Double.class);
 1641 add(float.class, Float.class);
 1642 add(int.class, Integer.class);
 1643 add(long.class, Long.class);
 1644 add(short.class, Short.class);
 1645 add(boolean.class, Boolean.class);
 1646 }
 1647
 1648 private static void add(Class primitiveClass, Class wrapperClass) {
 1649 table.put(primitiveClass,
 1650 new PrimitiveTypeInfo(primitiveClass, wrapperClass));
 1651 }
 1652
 1653 private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) {
 1654 assert primitiveClass.isPrimitive();
 1655
 1656 baseTypeString =
 1657 Array.newInstance(primitiveClass, 0)
 1658 .getClass().getName().substring(1);
 1659 wrapperClassName = dotToSlash(wrapperClass.getName());
 1660 wrapperValueOfDesc =
 1661 "(" + baseTypeString + ")L" + wrapperClassName + ";";
 1662 unwrapMethodName = primitiveClass.getName() + "Value";
 1663 unwrapMethodDesc = "()" + baseTypeString;
 1664 }
 1665
 1666 public static PrimitiveTypeInfo get(Class cl) {
 1667 return table.get(cl);
 1668 }
 1669 }
 1670
 1671
 1672 /**
 1673 * A ConstantPool object represents the constant pool of a class file
 1674 * being generated.  This representation of a constant pool is designed
 1675 * specifically for use by ProxyGenerator; in particular, it assumes
 1676 * that constant pool entries will not need to be resorted (for example,
 1677 * by their type, as the Java compiler does), so that the final index
 1678 * value can be assigned and used when an entry is first created.
 1679 *
 1680 * Note that new entries cannot be created after the constant pool has
 1681 * been written to a class file.  To prevent such logic errors, a
 1682 * ConstantPool instance can be marked "read only", so that further
 1683 * attempts to add new entries will fail with a runtime exception.
 1684 *
 1685 * See JVMS section 4.4 for more information about the constant pool
 1686 * of a class file.
 1687 */
 1688 private static class ConstantPool {
 1689
 1690 /**
 1691 * list of constant pool entries, in constant pool index order.
 1692 *
 1693 * This list is used when writing the constant pool to a stream
 1694 * and for assigning the next index value.  Note that element 0
 1695 * of this list corresponds to constant pool index 1.
 1696 */
 1697 private List<Entry> pool = new ArrayList<Entry>(32);
 1698
 1699 /**
 1700 * maps constant pool data of all types to constant pool indexes.
 1701 *
 1702 * This map is used to look up the index of an existing entry for
 1703 * values of all types.
 1704 */
 1705 private Map<Object,Short> map = new HashMap<Object,Short>(16);
 1706
 1707 /** true if no new constant pool entries may be added */
 1708 private boolean readOnly = false;
 1709
 1710 /**
 1711 * Get or assign the index for a CONSTANT_Utf8 entry.
 1712 */
 1713 public short getUtf8(String s) {
 1714 if (s == null) {
 1715 throw new NullPointerException();
 1716 }
 1717 return getValue(s);
 1718 }
 1719
 1720 /**
 1721 * Get or assign the index for a CONSTANT_Integer entry.
 1722 */
 1723 public short getInteger(int i) {
 1724 return getValue(new Integer(i));
 1725 }
 1726
 1727 /**
 1728 * Get or assign the index for a CONSTANT_Float entry.
 1729 */
 1730 public short getFloat(float f) {
 1731 return getValue(new Float(f));
 1732 }
 1733
 1734 /**
 1735 * Get or assign the index for a CONSTANT_Class entry.
 1736 */
 1737 public short getClass(String name) {
 1738 short utf8Index = getUtf8(name);
 1739 return getIndirect(new IndirectEntry(
 1740 CONSTANT_CLASS, utf8Index));
 1741 }
 1742
 1743 /**
 1744 * Get or assign the index for a CONSTANT_String entry.
 1745 */
 1746 public short getString(String s) {
 1747 short utf8Index = getUtf8(s);
 1748 return getIndirect(new IndirectEntry(
 1749 CONSTANT_STRING, utf8Index));
 1750 }
 1751
 1752 /**
 1753 * Get or assign the index for a CONSTANT_FieldRef entry.
 1754 */
 1755 public short getFieldRef(String className,
 1756 String name, String descriptor)
 1757 {
 1758 short classIndex = getClass(className);
 1759 short nameAndTypeIndex = getNameAndType(name, descriptor);
 1760 return getIndirect(new IndirectEntry(
 1761 CONSTANT_FIELD, classIndex, nameAndTypeIndex));
 1762 }
 1763
 1764 /**
 1765 * Get or assign the index for a CONSTANT_MethodRef entry.
 1766 */
 1767 public short getMethodRef(String className,
 1768 String name, String descriptor)
 1769 {
 1770 short classIndex = getClass(className);
 1771 short nameAndTypeIndex = getNameAndType(name, descriptor);
 1772 return getIndirect(new IndirectEntry(
 1773 CONSTANT_METHOD, classIndex, nameAndTypeIndex));
 1774 }
 1775
 1776 /**
 1777 * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
 1778 */
 1779 public short getInterfaceMethodRef(String className, String name,
 1780 String descriptor)
 1781 {
 1782 short classIndex = getClass(className);
 1783 short nameAndTypeIndex = getNameAndType(name, descriptor);
 1784 return getIndirect(new IndirectEntry(
 1785 CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
 1786 }
 1787
 1788 /**
 1789 * Get or assign the index for a CONSTANT_NameAndType entry.
 1790 */
 1791 public short getNameAndType(String name, String descriptor) {
 1792 short nameIndex = getUtf8(name);
 1793 short descriptorIndex = getUtf8(descriptor);
 1794 return getIndirect(new IndirectEntry(
 1795 CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
 1796 }
 1797
 1798 /**
 1799 * Set this ConstantPool instance to be "read only".
 1800 *
 1801 * After this method has been called, further requests to get
 1802 * an index for a non-existent entry will cause an InternalError
 1803 * to be thrown instead of creating of the entry.
 1804 */
 1805 public void setReadOnly() {
 1806 readOnly = true;
 1807 }
 1808
 1809 /**
 1810 * Write this constant pool to a stream as part of
 1811 * the class file format.
 1812 *
 1813 * This consists of writing the "constant_pool_count" and
 1814 * "constant_pool[]" items of the "ClassFile" structure, as
 1815 * described in JVMS section 4.1.
 1816 */
 1817 public void write(OutputStream out) throws IOException {
 1818 DataOutputStream dataOut = new DataOutputStream(out);
 1819
 1820 // constant_pool_count: number of entries plus one
 1821 dataOut.writeShort(pool.size() + 1);
 1822
 1823 for (Entry e : pool) {
 1824 e.write(dataOut);
 1825 }
 1826 }
 1827
 1828 /**
 1829 * Add a new constant pool entry and return its index.
 1830 */
 1831 private short addEntry(Entry entry) {
 1832 pool.add(entry);
 1833 /*
 1834 * Note that this way of determining the index of the
 1835 * added entry is wrong if this pool supports
 1836 * CONSTANT_Long or CONSTANT_Double entries.
 1837 */
 1838 if (pool.size() >= 65535) {
 1839 throw new IllegalArgumentException(
 1840 "constant pool size limit exceeded");
 1841 }
 1842 return (short) pool.size();
 1843 }
 1844
 1845 /**
 1846 * Get or assign the index for an entry of a type that contains
 1847 * a direct value.  The type of the given object determines the
 1848 * type of the desired entry as follows:
 1849 *
 1850 *      java.lang.String        CONSTANT_Utf8
 1851 *      java.lang.Integer       CONSTANT_Integer
 1852 *      java.lang.Float         CONSTANT_Float
 1853 *      java.lang.Long          CONSTANT_Long
 1854 *      java.lang.Double        CONSTANT_DOUBLE
 1855 */
 1856 private short getValue(Object key) {
 1857 Short index = map.get(key);
 1858 if (index != null) {
 1859 return index.shortValue();
 1860 } else {
 1861 if (readOnly) {
 1862 throw new InternalError(
 1863 "late constant pool addition: " + key);
 1864 }
 1865 short i = addEntry(new ValueEntry(key));
 1866 map.put(key, new Short(i));
 1867 return i;
 1868 }
 1869 }
 1870
 1871 /**
 1872 * Get or assign the index for an entry of a type that contains
 1873 * references to other constant pool entries.
 1874 */
 1875 private short getIndirect(IndirectEntry e) {
 1876 Short index = map.get(e);
 1877 if (index != null) {
 1878 return index.shortValue();
 1879 } else {
 1880 if (readOnly) {
 1881 throw new InternalError("late constant pool addition");
 1882 }
 1883 short i = addEntry(e);
 1884 map.put(e, new Short(i));
 1885 return i;
 1886 }
 1887 }
 1888
 1889 /**
 1890 * Entry is the abstact superclass of all constant pool entry types
 1891 * that can be stored in the "pool" list; its purpose is to define a
 1892 * common method for writing constant pool entries to a class file.
 1893 */
 1894 private static abstract class Entry {
 1895 public abstract void write(DataOutputStream out)
 1896 throws IOException;
 1897 }
 1898
 1899 /**
 1900 * ValueEntry represents a constant pool entry of a type that
 1901 * contains a direct value (see the comments for the "getValue"
 1902 * method for a list of such types).
 1903 *
 1904 * ValueEntry objects are not used as keys for their entries in the
 1905 * Map "map", so no useful hashCode or equals methods are defined.
 1906 */
 1907 private static class ValueEntry extends Entry {
 1908 private Object value;
 1909
 1910 public ValueEntry(Object value) {
 1911 this.value = value;
 1912 }
 1913
 1914 public void write(DataOutputStream out) throws IOException {
 1915 if (value instanceof String) {
 1916 out.writeByte(CONSTANT_UTF8);
 1917 out.writeUTF((String) value);
 1918 } else if (value instanceof Integer) {
 1919 out.writeByte(CONSTANT_INTEGER);
 1920 out.writeInt(((Integer) value).intValue());
 1921 } else if (value instanceof Float) {
 1922 out.writeByte(CONSTANT_FLOAT);
 1923 out.writeFloat(((Float) value).floatValue());
 1924 } else if (value instanceof Long) {
 1925 out.writeByte(CONSTANT_LONG);
 1926 out.writeLong(((Long) value).longValue());
 1927 } else if (value instanceof Double) {
 1928 out.writeDouble(CONSTANT_DOUBLE);
 1929 out.writeDouble(((Double) value).doubleValue());
 1930 } else {
 1931 throw new InternalError("bogus value entry: " + value);
 1932 }
 1933 }
 1934 }
 1935
 1936 /**
 1937 * IndirectEntry represents a constant pool entry of a type that
 1938 * references other constant pool entries, i.e., the following types:
 1939 *
 1940 *      CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
 1941 *      CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
 1942 *      CONSTANT_NameAndType.
 1943 *
 1944 * Each of these entry types contains either one or two indexes of
 1945 * other constant pool entries.
 1946 *
 1947 * IndirectEntry objects are used as the keys for their entries in
 1948 * the Map "map", so the hashCode and equals methods are overridden
 1949 * to allow matching.
 1950 */
 1951 private static class IndirectEntry extends Entry {
 1952 private int tag;
 1953 private short index0;
 1954 private short index1;
 1955
 1956 /**
 1957 * Construct an IndirectEntry for a constant pool entry type
 1958 * that contains one index of another entry.
 1959 */
 1960 public IndirectEntry(int tag, short index) {
 1961 this.tag = tag;
 1962 this.index0 = index;
 1963 this.index1 = 0;
 1964 }
 1965
 1966 /**
 1967 * Construct an IndirectEntry for a constant pool entry type
 1968 * that contains two indexes for other entries.
 1969 */
 1970 public IndirectEntry(int tag, short index0, short index1) {
 1971 this.tag = tag;
 1972 this.index0 = index0;
 1973 this.index1 = index1;
 1974 }
 1975
 1976 public void write(DataOutputStream out) throws IOException {
 1977 out.writeByte(tag);
 1978 out.writeShort(index0);
 1979 /*
 1980 * If this entry type contains two indexes, write
 1981 * out the second, too.
 1982 */
 1983 if (tag == CONSTANT_FIELD ||
 1984 tag == CONSTANT_METHOD ||
 1985 tag == CONSTANT_INTERFACEMETHOD ||
 1986 tag == CONSTANT_NAMEANDTYPE)
 1987 {
 1988 out.writeShort(index1);
 1989 }
 1990 }
 1991
 1992 public int hashCode() {
 1993 return tag + index0 + index1;
 1994 }
 1995
 1996 public boolean equals(Object obj) {
 1997 if (obj instanceof IndirectEntry) {
 1998 IndirectEntry other = (IndirectEntry) obj;
 1999 if (tag == other.tag &&
 2000 index0 == other.index0 && index1 == other.index1)
 2001 {
 2002 return true;
 2003 }
 2004 }
 2005 return false;
 2006 }
 2007 }
 2008 }
 2009 }
jdk7/jdk7/jdk
RSS
© 2010 Oracle Corporation and/or its affiliates
Terms of Use · Privacy · Trademarks

你可能感兴趣的:(sun/misc/ProxyGenerator.java)