KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > mdr > util > ImplGenerator


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.mdr.util;
20
21 import java.io.ByteArrayOutputStream JavaDoc;
22 import java.io.DataOutputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.util.*;
27
28 /**
29  * @author Martin Matula
30  * @version 0.1
31  */

32 public abstract class ImplGenerator {
33
34     /* Class File Constants */
35     public static final int JAVA_MAGIC = 0xcafebabe;
36
37     /* Generate class file version for 1.1 by default */
38     public static final int JAVA_DEFAULT_VERSION = 45;
39     public static final int JAVA_DEFAULT_MINOR_VERSION = 3;
40
41     /* Constant table */
42     public static final int CONSTANT_UTF8 = 1;
43     public static final int CONSTANT_INTEGER = 3;
44     public static final int CONSTANT_FLOAT = 4;
45     public static final int CONSTANT_LONG = 5;
46     public static final int CONSTANT_DOUBLE = 6;
47     public static final int CONSTANT_CLASS = 7;
48     public static final int CONSTANT_STRING = 8;
49     public static final int CONSTANT_FIELD = 9;
50     public static final int CONSTANT_METHOD = 10;
51     public static final int CONSTANT_INTERFACEMETHOD = 11;
52     public static final int CONSTANT_NAMEANDTYPE = 12;
53
54     /* Access and modifier flags */
55     public static final int ACC_PUBLIC = 0x00000001;
56     public static final int ACC_PRIVATE = 0x00000002;
57     public static final int ACC_PROTECTED = 0x00000004;
58     public static final int ACC_STATIC = 0x00000008;
59     public static final int ACC_FINAL = 0x00000010;
60     public static final int ACC_SUPER = 0x00000020;
61     
62     /* Type codes */
63     int T_BYTE = 0x00000008;
64
65     /* Opcodes */
66     public static final int opc_aconst_null = 1;
67     public static final int opc_iconst_0 = 3;
68     public static final int opc_lconst_0 = 9;
69     public static final int opc_fconst_0 = 11;
70     public static final int opc_dconst_0 = 14;
71     public static final int opc_bipush = 16;
72     public static final int opc_sipush = 17;
73     public static final int opc_ldc = 18;
74     public static final int opc_ldc_w = 19;
75     public static final int opc_iload = 21;
76     public static final int opc_lload = 22;
77     public static final int opc_fload = 23;
78     public static final int opc_dload = 24;
79     public static final int opc_aload = 25;
80     public static final int opc_iload_0 = 26;
81     public static final int opc_lload_0 = 30;
82     public static final int opc_fload_0 = 34;
83     public static final int opc_dload_0 = 38;
84     public static final int opc_aload_0 = 42;
85     public static final int opc_aaload = 50;
86     public static final int opc_istore = 54;
87     public static final int opc_lstore = 55;
88     public static final int opc_fstore = 56;
89     public static final int opc_dstore = 57;
90     public static final int opc_astore = 58;
91     public static final int opc_istore_0 = 59;
92     public static final int opc_lstore_0 = 63;
93     public static final int opc_fstore_0 = 67;
94     public static final int opc_dstore_0 = 71;
95     public static final int opc_astore_0 = 75;
96     public static final int opc_aastore = 83;
97     public static final int opc_bastore = 84;
98     public static final int opc_pop = 87;
99     public static final int opc_dup = 89;
100     public static final int opc_ifeq = 153;
101     public static final int opc_jsr = 168;
102     public static final int opc_ret = 169;
103     public static final int opc_ireturn = 172;
104     public static final int opc_lreturn = 173;
105     public static final int opc_freturn = 174;
106     public static final int opc_dreturn = 175;
107     public static final int opc_areturn = 176;
108     public static final int opc_return = 177;
109     public static final int opc_getstatic = 178;
110     public static final int opc_putstatic = 179;
111     public static final int opc_invokevirtual = 182;
112     public static final int opc_invokespecial = 183;
113     public static final int opc_invokestatic = 184;
114     public static final int opc_new = 187;
115     public static final int opc_newarray = 188;
116     public static final int opc_anewarray = 189;
117     public static final int opc_athrow = 191;
118     public static final int opc_checkcast = 192;
119     public static final int opc_wide = 196;
120     public static final int opc_ifnull = 198;
121
122     /** prefix for field names */
123     protected static final String JavaDoc FIELD_PREFIX = "field$";
124
125     /** superclass of generated class */
126     protected Class JavaDoc superclass;
127     
128     /** superclass dotToSlash name */
129     protected String JavaDoc superclassName;
130
131     /** name of generated class */
132     protected String JavaDoc className;
133
134     /** JMI generated interface */
135     protected Class JavaDoc ifc;
136
137     /** constant pool of class being generated */
138     protected ConstantPool cp = new ConstantPool();
139
140     /** FieldInfo struct for each field of generated class */
141     protected HashSet fields = new HashSet();
142
143     /** MethodInfo struct for each method of generated class */
144     protected List methods = new ArrayList();
145
146     /**
147      * for each method to be generated, maps method name and parameter
148      * descriptor to HandlerMethod object
149      */

150     protected Map classMethods = new HashMap(11);
151
152     /**
153      * Construct a HandlerGenerator to generate a handler class with the
154      * specified name and for the given interfaces.
155      */

156     protected ImplGenerator(String JavaDoc className,Class JavaDoc ifc,Class JavaDoc handlerClass) {
157     this.className = className;
158     this.ifc = ifc;
159         this.superclass = handlerClass;
160         this.superclassName = dotToSlash(superclass.getName());
161     }
162
163     /**
164      * Generate a class file for the handler. This method drives the
165      * class file generation process.
166      */

167     final protected byte[] generateClassFile() {
168 // HashSet methodSet = new HashSet();
169
// Method[] allMethods = superclass.getMethods();
170

171         // collect all methods from the ancestor
172
/* for (int i = 0; i < allMethods.length; i++) {
173             methodSet.add(allMethods[i].getName() + getMethodDescriptor(allMethods[i].getParameterTypes(), allMethods[i].getReturnType()));
174         }
175 */

176         // add the methods of interface which are not implemented in ancestor to the list of methods we should generate
177
{
178             // collect methods from descedant implementations of ImplGenerator
179
Method JavaDoc[] methods = getMethodsToImplement();
180             for (int i = 0; i < methods.length; i++) {
181 // if (!methodSet.contains(methods[i].getName() + getMethodDescriptor(methods[i].getParameterTypes(), methods[i].getReturnType()))) {
182
addClassMethod(methods[i], ifc);
183 // }
184
}
185         }
186
187         // collect field info and method info structs
188
try {
189             // generate MethodInfo for constructor
190
methods.add(generateConstructor());
191
192             // generate MethodInfo and FieldInfo for all methods
193
for (Iterator it = classMethods.values().iterator(); it.hasNext();) {
194         ClassMethod cm = (ClassMethod) it.next();
195
196         // generate MethodInfo for handler method
197
methods.add(cm.generateMethod());
198         }
199
200             // generate MethodInfo for static initializer
201
methods.add(generateStaticInitializer());
202     } catch (IOException JavaDoc e) {
203         throw new InternalError JavaDoc("unexpected I/O Exception");
204     }
205
206         // make sure these classes are in the constant pool
207
cp.getClass(dotToSlash(className));
208     cp.getClass(dotToSlash(superclass.getName()));
209         cp.getClass(dotToSlash(ifc.getName()));
210     cp.setReadOnly();
211
212         // write the class file
213
ByteArrayOutputStream JavaDoc bout = new ByteArrayOutputStream JavaDoc();
214     DataOutputStream JavaDoc dout = new DataOutputStream JavaDoc(bout);
215
216     try {
217             // u4 magic;
218
dout.writeInt(JAVA_MAGIC);
219             // u2 major_version;
220
dout.writeShort(JAVA_DEFAULT_MINOR_VERSION);
221             // u2 minor_version;
222
dout.writeShort(JAVA_DEFAULT_VERSION);
223
224         // constant pool
225
cp.write(dout);
226
227             // u2 access_flags;
228
dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
229             // u2 this_class;
230
dout.writeShort(cp.getClass(dotToSlash(className)));
231             // u2 super_class;
232
dout.writeShort(cp.getClass(dotToSlash(superclass.getName())));
233
234             // u2 interfaces_count;
235
dout.writeShort(1);
236             // u2 interfaces[interfaces_count];
237
dout.writeShort(cp.getClass(dotToSlash(ifc.getName())));
238
239             // u2 fields_count;
240
dout.writeShort(fields.size());
241             // field_info fields[fields_count];
242
for (Iterator it = fields.iterator(); it.hasNext();) {
243         FieldInfo f = (FieldInfo) it.next();
244         f.write(dout);
245         }
246
247             // u2 methods_count;
248
dout.writeShort(methods.size());
249             // method_info methods[methods_count];
250
for (Iterator it = methods.iterator(); it.hasNext();) {
251         MethodInfo m = (MethodInfo) it.next();
252         m.write(dout);
253         }
254
255             // u2 attributes_count;
256
dout.writeShort(0);
257     } catch (IOException JavaDoc e) {
258         throw new InternalError JavaDoc("unexpected I/O Exception");
259     }
260
261     return bout.toByteArray();
262     }
263
264     /**
265      * Add a method to be generated
266      */

267     protected void addClassMethod(Method JavaDoc m, Class JavaDoc fromClass) {
268         String JavaDoc name = m.getName();
269         Class JavaDoc[] parameterTypes = m.getParameterTypes();
270         String JavaDoc key = name + getParameterDescriptors(parameterTypes);
271         
272         if (classMethods.get(key) == null) {
273             ClassMethod cm = getClassMethod(m, fromClass);
274             classMethods.put(key, cm);
275         }
276     }
277     
278     protected abstract Method JavaDoc[] getMethodsToImplement();
279
280     protected ClassMethod getClassMethod(Method JavaDoc m, Class JavaDoc fromClass) {
281         // this method should never be called (it is called only if descedant cannot recognize the method)
282
throw new InternalError JavaDoc("Unrecognized method: " + m.getName() + " from class: " + fromClass.getName());
283     }
284
285     /**
286      * A FieldInfo object contains information about a particular field
287      * in the class being generated. The class mirrors the data items of
288      * the "field_info" structure of the class file format (see JVMS 4.5).
289      */

290     final protected class FieldInfo {
291     public int accessFlags;
292     public String JavaDoc name;
293     public String JavaDoc descriptor;
294
295     public FieldInfo(String JavaDoc name, String JavaDoc descriptor, int accessFlags) {
296         this.name = name;
297         this.descriptor = descriptor;
298         this.accessFlags = accessFlags;
299
300         /*
301          * Make sure that constant pool indexes are reserved for the
302          * following items before starting to write the final class file.
303          */

304         cp.getUtf8(name);
305         cp.getUtf8(descriptor);
306     }
307
308     final public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
309         /*
310          * Write all the items of the "field_info" structure.
311          * See JVMS section 4.5.
312          */

313                     // u2 access_flags;
314
out.writeShort(accessFlags);
315                     // u2 name_index;
316
out.writeShort(cp.getUtf8(name));
317                     // u2 descriptor_index;
318
out.writeShort(cp.getUtf8(descriptor));
319                     // u2 attributes_count;
320
out.writeShort(0); // (no field_info attributes for proxy classes)
321
}
322
323         public boolean equals(Object JavaDoc o) {
324             if (o instanceof FieldInfo) {
325                 return ((FieldInfo) o).name.equalsIgnoreCase(name);
326             } else {
327                 return false;
328             }
329         }
330
331         public int hashCode() {
332             return name.toUpperCase(Locale.US).hashCode();
333         }
334     }
335
336     /**
337      * An ExceptionTableEntry object holds values for the data items of
338      * an entry in the "exception_table" item of the "Code" attribute of
339      * "method_info" structures (see JVMS 4.7.3).
340      */

341     final protected static class ExceptionTableEntry {
342     public short startPc;
343     public short endPc;
344     public short handlerPc;
345     public short catchType;
346
347     public ExceptionTableEntry(short startPc, short endPc,
348                    short handlerPc, short catchType)
349     {
350         this.startPc = startPc;
351         this.endPc = endPc;
352         this.handlerPc = handlerPc;
353         this.catchType = catchType;
354     }
355     };
356
357     /**
358      * A MethodInfo object contains information about a particular method
359      * in the class being generated. This class mirrors the data items of
360      * the "method_info" structure of the class file format (see JVMS 4.6).
361      */

362     final protected class MethodInfo {
363     public int accessFlags;
364     public String JavaDoc name;
365     public String JavaDoc descriptor;
366     public short maxStack;
367     public short maxLocals;
368     public ByteArrayOutputStream JavaDoc code = new ByteArrayOutputStream JavaDoc();
369     public List exceptionTable = new ArrayList();
370     public short[] declaredExceptions;
371
372     public MethodInfo(String JavaDoc name, String JavaDoc descriptor, int accessFlags) {
373         this.name = name;
374         this.descriptor = descriptor;
375         this.accessFlags = accessFlags;
376
377         /*
378          * Make sure that constant pool indexes are reserved for the
379          * following items before starting to write the final class file.
380          */

381         cp.getUtf8(name);
382         cp.getUtf8(descriptor);
383         cp.getUtf8("Code");
384         cp.getUtf8("Exceptions");
385     }
386
387     public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
388         /*
389          * Write all the items of the "method_info" structure.
390          * See JVMS section 4.6.
391          */

392                     // u2 access_flags;
393
out.writeShort(accessFlags);
394                     // u2 name_index;
395
out.writeShort(cp.getUtf8(name));
396                     // u2 descriptor_index;
397
out.writeShort(cp.getUtf8(descriptor));
398                     // u2 attributes_count;
399
out.writeShort(2); // (two method_info attributes:)
400

401         // Write "Code" attribute. See JVMS section 4.7.3.
402

403                     // u2 attribute_name_index;
404
out.writeShort(cp.getUtf8("Code"));
405                     // u4 attribute_length;
406
out.writeInt(12 + code.size() + 8 * exceptionTable.size());
407                     // u2 max_stack;
408
out.writeShort(maxStack);
409                     // u2 max_locals;
410
out.writeShort(maxLocals);
411                     // u2 code_length;
412
out.writeInt(code.size());
413                     // u1 code[code_length];
414
code.writeTo(out);
415                     // u2 exception_table_length;
416
out.writeShort(exceptionTable.size());
417         for (Iterator iter = exceptionTable.iterator(); iter.hasNext();) {
418         ExceptionTableEntry e = (ExceptionTableEntry) iter.next();
419                     // u2 start_pc;
420
out.writeShort(e.startPc);
421                     // u2 end_pc;
422
out.writeShort(e.endPc);
423                     // u2 handler_pc;
424
out.writeShort(e.handlerPc);
425                     // u2 catch_type;
426
out.writeShort(e.catchType);
427         }
428                     // u2 attributes_count;
429
out.writeShort(0);
430
431         // write "Exceptions" attribute. See JVMS section 4.7.4.
432

433                     // u2 attribute_name_index;
434
out.writeShort(cp.getUtf8("Exceptions"));
435                     // u4 attributes_length;
436
out.writeInt(2 + 2 * declaredExceptions.length);
437                     // u2 number_of_exceptions;
438
out.writeShort(declaredExceptions.length);
439             // u2 exception_index_table[number_of_exceptions];
440
for (int i = 0; i < declaredExceptions.length; i++) {
441         out.writeShort(declaredExceptions[i]);
442         }
443     }
444
445     }
446
447     /**
448      * A HandlerMethod object represents a proxy method in the proxy class
449      * being generated: a method whose implementation will encode and
450      * dispatch invocations to the proxy instance's invocation handler.
451      */

452     protected class ClassMethod {
453
454     public String JavaDoc methodName;
455     public Class JavaDoc[] parameterTypes;
456     public Class JavaDoc returnType;
457     public Class JavaDoc[] exceptionTypes;
458     public Class JavaDoc fromClass;
459     public String JavaDoc methodFieldName;
460         public short delegateMethod;
461         private boolean hasField;
462
463     public ClassMethod(Method JavaDoc method, short delegate, String JavaDoc methodFieldName)
464     {
465         this.methodName = method.getName();
466         this.parameterTypes = method.getParameterTypes();
467         this.returnType = method.getReturnType();
468         this.exceptionTypes = method.getExceptionTypes();
469         this.fromClass = method.getDeclaringClass();
470             if (methodFieldName == null) {
471                 this.methodFieldName = null;
472                 hasField = false;
473             } else {
474                 this.methodFieldName = FIELD_PREFIX + methodFieldName;
475                 // add static field for feature name method operates with
476
hasField = fields.add(new FieldInfo(this.methodFieldName, "Ljava/lang/String;", ACC_PRIVATE | ACC_STATIC));
477             }
478             delegateMethod = delegate;
479     }
480
481     /**
482      * Return a MethodInfo object for this method, including generating
483      * the code.
484      */

485     public MethodInfo generateMethod() throws IOException JavaDoc {
486         String JavaDoc desc = getMethodDescriptor(parameterTypes, returnType);
487         MethodInfo minfo = new MethodInfo(methodName, desc, ACC_PUBLIC | ACC_FINAL);
488         int[] parameterSlot = new int[parameterTypes.length];
489         int nextSlot = 1;
490         for (int i = 0; i < parameterSlot.length; i++) {
491         parameterSlot[i] = nextSlot;
492         nextSlot += getWordsPerType(parameterTypes[i]);
493         }
494         int localSlot0 = nextSlot;
495
496         DataOutputStream JavaDoc out = new DataOutputStream JavaDoc(minfo.code);
497
498             // I'll pass this instance as the first parameter
499
code_aload(0, out);
500
501             if (methodFieldName != null) {
502                 // feature name stored in the static variable as the second parameter
503
out.writeByte(opc_dup);
504                 out.writeByte(opc_getstatic);
505                 out.writeShort(cp.getFieldRef(dotToSlash(className), methodFieldName, "Ljava/lang/String;"));
506             }
507
508             // The rest of parameters follows
509
for (int i = 0; i < parameterTypes.length; i++) {
510                 codeWrapArgument(parameterTypes[i], parameterSlot[i], out);
511             }
512
513             // call the delegate method
514
out.writeByte(opc_invokespecial);
515         out.writeShort(delegateMethod);
516
517         if (returnType == void.class) {
518 // out.writeByte(opc_pop);
519
out.writeByte(opc_return);
520         } else {
521         codeUnwrapReturnValue(returnType, out);
522         }
523
524         minfo.maxStack = 10;
525         minfo.maxLocals = (short) (localSlot0 + 1);
526         minfo.declaredExceptions = new short[0];
527
528         return minfo;
529     }
530
531         /**
532          * Generate code for wrapping a parameter of the given type and whose
533          * value can be found at the specified local variable index to be
534          * passed to the invocation handler's "invoke" method (as an Object).
535          * The code is written to the supplied stream.
536          */

537         public void codeWrapArgument(Class JavaDoc type, int slot, DataOutputStream JavaDoc out) throws IOException JavaDoc {
538             if (type.isPrimitive()) {
539                 if (type == boolean.class) {
540                     code_iload(slot, out);
541                     out.writeByte(opc_invokestatic);
542                     out.writeShort(cp.getMethodRef("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"));
543                 } else {
544                     PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
545
546                     out.writeByte(opc_new);
547                     out.writeShort(cp.getClass(prim.wrapperClassName));
548
549                     out.writeByte(opc_dup);
550
551                     if (type == int.class || type == byte.class || type == char.class || type == short.class) {
552                         code_iload(slot, out);
553                     } else if (type == long.class) {
554                         code_lload(slot, out);
555                     } else if (type == float.class) {
556                         code_fload(slot, out);
557                     } else if (type == double.class) {
558                         code_dload(slot, out);
559                     } else {
560                         assertTrue(false);
561                     }
562
563                     out.writeByte(opc_invokespecial);
564                     out.writeShort(cp.getMethodRef(prim.wrapperClassName, "<init>", prim.wrapperConstructorDesc));
565                 }
566             } else {
567                 code_aload(slot, out);
568             }
569         }
570
571     /**
572      * Generate code for unwrapping the return value of the given type
573      * from the invocation handler's "invoke" method (of type Object) to
574      * its correct type. The code is written to the supplied stream.
575      */

576     public void codeUnwrapReturnValue(Class JavaDoc type, DataOutputStream JavaDoc out) throws IOException JavaDoc {
577         if (type.isPrimitive()) {
578         PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
579                 
580                 out.writeByte(opc_dup);
581                 out.writeByte(opc_ifnull);
582                 out.writeShort(10);
583
584         out.writeByte(opc_checkcast);
585         out.writeShort(cp.getClass(prim.wrapperClassName));
586
587         out.writeByte(opc_invokevirtual);
588         out.writeShort(cp.getMethodRef(
589             prim.wrapperClassName,
590             prim.unwrapMethodName, prim.unwrapMethodDesc));
591
592         if (type == int.class ||
593             type == boolean.class ||
594             type == byte.class ||
595             type == char.class ||
596             type == short.class)
597         {
598             out.writeByte(opc_ireturn);
599                     out.writeByte(opc_iconst_0);
600                     out.writeByte(opc_ireturn);
601         } else if (type == long.class) {
602             out.writeByte(opc_lreturn);
603                     out.writeByte(opc_lconst_0);
604             out.writeByte(opc_lreturn);
605         } else if (type == float.class) {
606             out.writeByte(opc_freturn);
607                     out.writeByte(opc_fconst_0);
608             out.writeByte(opc_freturn);
609         } else if (type == double.class) {
610             out.writeByte(opc_dreturn);
611                     out.writeByte(opc_dconst_0);
612             out.writeByte(opc_dreturn);
613         } else {
614             assertTrue(false);
615         }
616
617         } else {
618
619         out.writeByte(opc_checkcast);
620         out.writeShort(cp.getClass(dotToSlash(type.getName())));
621
622         out.writeByte(opc_areturn);
623         }
624     }
625         
626         public int getBytesForUnwrapReturn(Class JavaDoc type) {
627         if (type.isPrimitive()) {
628                 return 13;
629         } else {
630                 return 4;
631             }
632         }
633
634         /**
635          * Generate code for initializing the static field that stores
636          * the Method object for this proxy method. The code is written
637          * to the supplied stream.
638          */

639         public void codeFieldInitialization(DataOutputStream JavaDoc out) throws IOException JavaDoc {
640             if (hasField) {
641                 out.writeByte(opc_new); // new
642
out.writeShort(cp.getClass("java/lang/String")); // java.lang.String
643
out.writeByte(opc_dup); // dup
644

645                 // get the string bytes to pass to the string constructor
646
byte[] bytes = strip(methodFieldName, FIELD_PREFIX).getBytes();
647
648                 code_ipush(bytes.length, out); // \
649
out.writeByte(opc_newarray); // - array = new byte[bytes.length]
650
out.writeByte(T_BYTE); // /
651

652                 // populate array with bytes
653
for (int i = 0; i < bytes.length; i++) {
654                     out.writeByte(opc_dup); // \
655
code_ipush(i, out); // - array[i] = bytes[i]
656
code_ipush(bytes[i], out); // /
657
out.writeByte(opc_bastore); // /
658
}
659
660                 // now the stack content is: reference to new String,
661
// reference to new String, reference to array of bytes
662
// we'll call the String(byte[]) constructor
663
out.writeByte(opc_invokespecial);
664                 out.writeShort(cp.getMethodRef("java/lang/String", "<init>", "([B)V"));
665
666                 // stack content: reference to new String
667
// I'll assign this reference to the field
668
out.writeByte(opc_putstatic);
669                 out.writeShort(cp.getFieldRef(dotToSlash(className), methodFieldName, "Ljava/lang/String;"));
670             }
671         }
672     }
673
674     /**
675      * Generate the constructor method for the proxy class.
676      */

677     protected abstract MethodInfo generateConstructor() throws IOException JavaDoc;
678
679     /**
680      * Generate the static initializer method for the proxy class.
681      */

682     protected MethodInfo generateStaticInitializer() throws IOException JavaDoc {
683     MethodInfo minfo = new MethodInfo(
684         "<clinit>", "()V", ACC_STATIC);
685
686     int localSlot0 = 1;
687
688     DataOutputStream JavaDoc out = new DataOutputStream JavaDoc(minfo.code);
689
690     for (Iterator it = classMethods.values().iterator(); it.hasNext();) {
691         ClassMethod cm = (ClassMethod) it.next();
692         cm.codeFieldInitialization(out);
693     }
694
695     out.writeByte(opc_return);
696
697     minfo.maxStack = 10;
698     minfo.maxLocals = (short) (localSlot0 + 1);
699     minfo.declaredExceptions = new short[0];
700
701     return minfo;
702     }
703
704     /*
705      * =============== Code Generation Utility Methods ===============
706      */

707
708     /*
709      * The following methods generate code for the load or store operation
710      * indicated by their name for the given local variable. The code is
711      * written to the supplied stream.
712      */

713
714     protected void code_iload(int lvar, DataOutputStream JavaDoc out)
715     throws IOException JavaDoc
716     {
717     codeLocalLoadStore(lvar,
718         opc_iload, opc_iload_0, out);
719     }
720
721     protected void code_lload(int lvar, DataOutputStream JavaDoc out)
722     throws IOException JavaDoc
723     {
724     codeLocalLoadStore(lvar,
725         opc_lload, opc_lload_0, out);
726     }
727
728     protected void code_fload(int lvar, DataOutputStream JavaDoc out)
729     throws IOException JavaDoc
730     {
731     codeLocalLoadStore(lvar,
732         opc_fload, opc_fload_0, out);
733     }
734     
735     protected void code_dload(int lvar, DataOutputStream JavaDoc out)
736     throws IOException JavaDoc
737     {
738     codeLocalLoadStore(lvar,
739         opc_dload, opc_dload_0, out);
740     }
741
742     protected void code_aload(int lvar, DataOutputStream JavaDoc out)
743     throws IOException JavaDoc
744     {
745     codeLocalLoadStore(lvar,
746         opc_aload, opc_aload_0, out);
747     }
748
749     protected void code_istore(int lvar, DataOutputStream JavaDoc out)
750     throws IOException JavaDoc
751     {
752     codeLocalLoadStore(lvar,
753         opc_istore, opc_istore_0, out);
754     }
755
756     protected void code_lstore(int lvar, DataOutputStream JavaDoc out)
757     throws IOException JavaDoc
758     {
759     codeLocalLoadStore(lvar,
760         opc_lstore, opc_lstore_0, out);
761     }
762
763     protected void code_fstore(int lvar, DataOutputStream JavaDoc out)
764     throws IOException JavaDoc
765     {
766     codeLocalLoadStore(lvar,
767         opc_fstore, opc_fstore_0, out);
768     }
769
770     protected void code_dstore(int lvar, DataOutputStream JavaDoc out)
771     throws IOException JavaDoc
772     {
773     codeLocalLoadStore(lvar,
774         opc_dstore, opc_dstore_0, out);
775     }
776
777     protected void code_astore(int lvar, DataOutputStream JavaDoc out)
778     throws IOException JavaDoc
779     {
780     codeLocalLoadStore(lvar,
781         opc_astore, opc_astore_0, out);
782     }
783
784     /**
785      * Generate code for a load or store instruction for the given local
786      * variable. The code is written to the supplied stream.
787      *
788      * "opcode" indicates the opcode form of the desired load or store
789      * instruction that takes an explicit local variable index, and
790      * "opcode_0" indicates the corresponding form of the instruction
791      * with the implicit index 0.
792      */

793     protected void codeLocalLoadStore(int lvar, int opcode, int opcode_0,
794                     DataOutputStream JavaDoc out)
795     throws IOException JavaDoc
796     {
797     assertTrue(lvar >= 0 && lvar <= 0xFFFF);
798     if (lvar <= 3) {
799         out.writeByte(opcode_0 + lvar);
800     } else if (lvar <= 0xFF) {
801         out.writeByte(opcode);
802         out.writeByte(lvar & 0xFF);
803     } else {
804         /*
805          * Use the "wide" instruction modifier for local variable
806          * indexes that do not fit into an unsigned byte.
807          */

808         out.writeByte(opc_wide);
809         out.writeByte(opcode);
810         out.writeShort(lvar & 0xFFFF);
811     }
812     }
813
814     /**
815      * Generate code for an "ldc" instruction for the given constant pool
816      * index (the "ldc_w" instruction is used if the index does not fit
817      * into an unsigned byte). The code is written to the supplied stream.
818      */

819     protected void code_ldc(int index, DataOutputStream JavaDoc out)
820     throws IOException JavaDoc
821     {
822     assertTrue(index >= 0 && index <= 0xFFFF);
823     if (index <= 0xFF) {
824         out.writeByte(opc_ldc);
825         out.writeByte(index & 0xFF);
826     } else {
827         out.writeByte(opc_ldc_w);
828         out.writeShort(index & 0xFFFF);
829     }
830     }
831
832     /**
833      * Generate code to push a constant integer value on to the operand
834      * stack, using the "iconst_<i>", "bipush", or "sipush" instructions
835      * depending on the size of the value. The code is written to the
836      * supplied stream.
837      */

838     protected void code_ipush(int value, DataOutputStream JavaDoc out)
839     throws IOException JavaDoc
840     {
841     if (value >= -1 && value <= 5) {
842         out.writeByte(opc_iconst_0 + value);
843     } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
844         out.writeByte(opc_bipush);
845         out.writeByte(value & 0xFF);
846     } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
847         out.writeByte(opc_sipush);
848         out.writeShort(value & 0xFFFF);
849     } else {
850         assertTrue(false);
851     }
852     }
853
854     /**
855      * Generate code to invoke the Class.forName with the name of the given
856      * class to get its Class object at runtime. The code is written to
857      * the supplied stream. Note that the code generated by this method
858      * may caused the checked ClassNotFoundException to be thrown.
859      */

860     protected void codeClassForName(Class JavaDoc cl, DataOutputStream JavaDoc out)
861     throws IOException JavaDoc
862     {
863     code_ldc(cp.getString(cl.getName()), out);
864
865     out.writeByte(opc_invokestatic);
866     out.writeShort(cp.getMethodRef(
867         "java/lang/Class",
868         "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));
869     }
870     /*
871      * ==================== General Utility Methods ====================
872      */

873
874     /** Strips prefix and returns the name of feature or proxy
875     */

876     protected static String JavaDoc strip( String JavaDoc methodName, String JavaDoc prefix ) {
877         return methodName.substring( prefix.length() );
878     }
879
880     /** Strips prefix and returns the name of feature or proxy
881     */

882     protected static String JavaDoc strip(String JavaDoc methodName, String JavaDoc prefix, String JavaDoc suffix) {
883         return methodName.substring(prefix.length(), methodName.length() - suffix.length());
884     }
885
886     protected static String JavaDoc firstUpper(String JavaDoc text) {
887         try {
888             return text.substring(0, 1).toUpperCase(Locale.US) + text.substring(1);
889         } catch (IndexOutOfBoundsException JavaDoc e) {
890             return "";
891         }
892     }
893
894     protected static String JavaDoc firstLower(String JavaDoc text) {
895         try {
896             return text.substring(0, 1).toLowerCase(Locale.US) + text.substring(1);
897         } catch (IndexOutOfBoundsException JavaDoc e) {
898             return "";
899         }
900     }
901
902     /**
903      * Assert that an assertion is true: throw InternalError if it is not.
904      */

905     protected static void assertTrue(boolean assertion) {
906     if (assertion != true) {
907         throw new InternalError JavaDoc("assertion failure");
908     }
909     }
910
911     /**
912      * Convert a fully qualified class name that uses '.' as the package
913      * separator, the external representation used by the Java language
914      * and APIs, to a fully qualified class name that uses '/' as the
915      * package separator, the representation used in the class file
916      * format (see JVMS section 4.2).
917      */

918     protected static String JavaDoc dotToSlash(String JavaDoc name) {
919     return name.replace('.', '/');
920     }
921
922     /**
923      * Return the "method descriptor" string for a method with the given
924      * parameter types and return type. See JVMS section 4.3.3.
925      */

926     protected static String JavaDoc getMethodDescriptor(Class JavaDoc[] parameterTypes,
927                           Class JavaDoc returnType)
928     {
929     return getParameterDescriptors(parameterTypes) +
930         ((returnType == void.class) ? "V" : getFieldType(returnType));
931     }
932
933     /**
934      * Return the list of "parameter descriptor" strings enclosed in
935      * parentheses corresponding to the given parameter types (in other
936      * words, a method descriptor without a return descriptor). This
937      * string is useful for constructing string keys for methods without
938      * regard to their return type.
939      */

940     protected static String JavaDoc getParameterDescriptors(Class JavaDoc[] parameterTypes) {
941     StringBuffer JavaDoc desc = new StringBuffer JavaDoc("(");
942     for (int i = 0; i < parameterTypes.length; i++) {
943         desc.append(getFieldType(parameterTypes[i]));
944     }
945     desc.append(')');
946     return desc.toString();
947     }
948
949     /**
950      * Return the "field type" string for the given type, appropriate for
951      * a field descriptor, a parameter descriptor, or a return descriptor
952      * other than "void". See JVMS section 4.3.2.
953      */

954     protected static String JavaDoc getFieldType(Class JavaDoc type) {
955     if (type.isPrimitive()) {
956         return PrimitiveTypeInfo.get(type).baseTypeString;
957     } else if (type.isArray()) {
958         /*
959          * According to JLS 20.3.2, the getName() method on Class does
960          * return the VM type descriptor format for array classes (only);
961          * using that should be quicker than the otherwise obvious code:
962          *
963          * return "[" + getTypeDescriptor(type.getComponentType());
964          */

965         return type.getName().replace('.', '/');
966     } else {
967         return "L" + dotToSlash(type.getName()) + ";";
968     }
969     }
970
971     /**
972      * Return the number of abstract "words", or consecutive local variable
973      * indexes, required to contain a value of the given type. See JVMS
974      * section 3.6.1.
975      *
976      * Note that the original version of the JVMS contained a definition of
977      * this abstract notion of a "word" in section 3.4, but that definition
978      * was removed for the second edition.
979      */

980     protected static int getWordsPerType(Class JavaDoc type) {
981     if (type == long.class || type == double.class) {
982         return 2;
983     } else {
984         return 1;
985     }
986     }
987
988     /**
989      * A PrimitiveTypeInfo object contains assorted information about
990      * a primitive type in its public fields. The struct for a particular
991      * primitive type can be obtained using the static "get" method.
992      */

993     protected static class PrimitiveTypeInfo {
994
995     /** "base type" used in various descriptors (see JVMS section 4.3.2) */
996     public String JavaDoc baseTypeString;
997
998     /** name of corresponding wrapper class */
999     public String JavaDoc wrapperClassName;
1000
1001    /** method descriptor for wrapper class constructor */
1002    public String JavaDoc wrapperConstructorDesc;
1003
1004    /** name of wrapper class method for retrieving primitive value */
1005    public String JavaDoc unwrapMethodName;
1006
1007    /** descriptor of same method */
1008    public String JavaDoc unwrapMethodDesc;
1009
1010    private static Map table = new HashMap(11);
1011    static {
1012        table.put(int.class, new PrimitiveTypeInfo(
1013        "I", "java/lang/Integer", "(I)V", "intValue", "()I"));
1014        table.put(boolean.class, new PrimitiveTypeInfo(
1015        "Z", "java/lang/Boolean", "(Z)V", "booleanValue", "()Z"));
1016        table.put(byte.class, new PrimitiveTypeInfo(
1017        "B", "java/lang/Byte", "(B)V", "byteValue", "()B"));
1018        table.put(char.class, new PrimitiveTypeInfo(
1019        "C", "java/lang/Char", "(C)V", "charValue", "()C"));
1020        table.put(short.class, new PrimitiveTypeInfo(
1021        "S", "java/lang/Short", "(S)V", "shortValue", "()S"));
1022        table.put(long.class, new PrimitiveTypeInfo(
1023        "J", "java/lang/Long", "(J)V", "longValue", "()J"));
1024        table.put(float.class, new PrimitiveTypeInfo(
1025        "F", "java/lang/Float", "(F)V", "floatValue", "()F"));
1026        table.put(double.class, new PrimitiveTypeInfo(
1027        "D", "java/lang/Double", "(D)V", "doubleValue", "()D"));
1028    }
1029
1030    private PrimitiveTypeInfo(String JavaDoc baseTypeString,
1031                  String JavaDoc wrapperClassName,
1032                  String JavaDoc wrapperConstructorDesc,
1033                  String JavaDoc unwrapMethodName,
1034                  String JavaDoc unwrapMethodDesc)
1035    {
1036        this.baseTypeString = baseTypeString;
1037        this.wrapperClassName = wrapperClassName;
1038        this.wrapperConstructorDesc = wrapperConstructorDesc;
1039        this.unwrapMethodName = unwrapMethodName;
1040        this.unwrapMethodDesc = unwrapMethodDesc;
1041    }
1042
1043    public static PrimitiveTypeInfo get(Class JavaDoc cl) {
1044        return (PrimitiveTypeInfo) table.get(cl);
1045    }
1046    }
1047
1048
1049    /**
1050     * A ConstantPool object represents the constant pool of a class file
1051     * being generated. This representation of a constant pool is designed
1052     * specifically for use by ProxyGenerator; in particular, it assumes
1053     * that constant pool entries will not need to be resorted (for example,
1054     * by their type, as the Java compiler does), so that the final index
1055     * value can be assigned and used when an entry is first created.
1056     *
1057     * Note that new entries cannot be created after the constant pool has
1058     * been written to a class file. To prevent such logic errors, a
1059     * ConstantPool instance can be marked "read only", so that further
1060     * attempts to add new entries will fail with a runtime exception.
1061     *
1062     * See JVMS section 4.4 for more information about the constant pool
1063     * of a class file.
1064     */

1065    protected static class ConstantPool {
1066
1067    /**
1068         * list of constant pool entries, in constant pool index order.
1069     *
1070     * This list is used when writing the constant pool to a stream
1071     * and for assigning the next index value. Note that element 0
1072     * of this list corresponds to constant pool index 1.
1073     */

1074    private List pool = new ArrayList(32);
1075
1076    /**
1077     * maps constant pool data of all types to constant pool indexes.
1078     *
1079     * This map is used to look up the index of an existing entry for
1080     * values of all types.
1081     */

1082    private Map map = new HashMap(16);
1083
1084        /** true if no new constant pool entries may be added */
1085    private boolean readOnly = false;
1086
1087    /**
1088     * Get or assign the index for a CONSTANT_Utf8 entry.
1089     */

1090    public short getUtf8(String JavaDoc s) {
1091        if (s == null) {
1092        throw new NullPointerException JavaDoc();
1093        }
1094        return getValue(s);
1095    }
1096
1097    /**
1098     * Get or assign the index for a CONSTANT_Integer entry.
1099     */

1100    public short getInteger(int i) {
1101        return getValue(new Integer JavaDoc(i));
1102    }
1103
1104    /**
1105     * Get or assign the index for a CONSTANT_Float entry.
1106     */

1107    public short getFloat(float f) {
1108        return getValue(new Float JavaDoc(f));
1109    }
1110
1111    /**
1112     * Get or assign the index for a CONSTANT_Long entry.
1113     */

1114    public short getLong(long l) {
1115        return getValue(new Long JavaDoc(l));
1116    }
1117
1118    /**
1119     * Get or assign the index for a CONSTANT_Double entry.
1120     */

1121    public short getDouble(double d) {
1122        return getValue(new Double JavaDoc(d));
1123    }
1124
1125    /**
1126     * Get or assign the index for a CONSTANT_Class entry.
1127     */

1128    public short getClass(String JavaDoc name) {
1129        short utf8Index = getUtf8(name);
1130        return getIndirect(new IndirectEntry(
1131        CONSTANT_CLASS, utf8Index));
1132    }
1133
1134    /**
1135     * Get or assign the index for a CONSTANT_String entry.
1136     */

1137    public short getString(String JavaDoc s) {
1138        short utf8Index = getUtf8(s);
1139        return getIndirect(new IndirectEntry(
1140        CONSTANT_STRING, utf8Index));
1141    }
1142
1143    /**
1144     * Get or assign the index for a CONSTANT_FieldRef entry.
1145     */

1146    public short getFieldRef(String JavaDoc className,
1147                 String JavaDoc name, String JavaDoc descriptor)
1148    {
1149        short classIndex = getClass(className);
1150        short nameAndTypeIndex = getNameAndType(name, descriptor);
1151        return getIndirect(new IndirectEntry(
1152            CONSTANT_FIELD,
1153        classIndex, nameAndTypeIndex));
1154    }
1155
1156    /**
1157     * Get or assign the index for a CONSTANT_MethodRef entry.
1158     */

1159    public short getMethodRef(String JavaDoc className,
1160                  String JavaDoc name, String JavaDoc descriptor)
1161    {
1162        short classIndex = getClass(className);
1163        short nameAndTypeIndex = getNameAndType(name, descriptor);
1164        return getIndirect(new IndirectEntry(
1165            CONSTANT_METHOD,
1166        classIndex, nameAndTypeIndex));
1167    }
1168
1169    /**
1170     * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
1171     */

1172    public short getInterfaceMethodRef(String JavaDoc className, String JavaDoc name,
1173                       String JavaDoc descriptor)
1174    {
1175        short classIndex = getClass(className);
1176        short nameAndTypeIndex = getNameAndType(name, descriptor);
1177        return getIndirect(new IndirectEntry(
1178                CONSTANT_INTERFACEMETHOD,
1179        classIndex, nameAndTypeIndex));
1180    }
1181
1182    /**
1183     * Get or assign the index for a CONSTANT_NameAndType entry.
1184     */

1185    public short getNameAndType(String JavaDoc name, String JavaDoc descriptor) {
1186        short nameIndex = getUtf8(name);
1187        short descriptorIndex = getUtf8(descriptor);
1188        return getIndirect(new IndirectEntry(
1189            CONSTANT_NAMEANDTYPE,
1190        nameIndex, descriptorIndex));
1191    }
1192
1193    /**
1194     * Set this ConstantPool instance to be "read only".
1195     *
1196     * After this method has been called, further requests to get
1197     * an index for a non-existent entry will cause an InternalError
1198     * to be thrown instead of creating of the entry.
1199     */

1200    public void setReadOnly() {
1201        readOnly = true;
1202    }
1203
1204    /**
1205     * Write this constant pool to a stream as part of
1206     * the class file format.
1207     *
1208     * This consists of writing the "constant_pool_count" and
1209     * "constant_pool[]" items of the "ClassFile" structure, as
1210     * described in JVMS section 4.1.
1211     */

1212    public void write(OutputStream JavaDoc out) throws IOException JavaDoc {
1213        DataOutputStream JavaDoc dataOut = new DataOutputStream JavaDoc(out);
1214
1215        // constant_pool_count: number of entries plus one
1216
dataOut.writeShort(pool.size() + 1);
1217
1218        for (Iterator iter = pool.iterator(); iter.hasNext();) {
1219        Entry e = (Entry) iter.next();
1220        e.write(dataOut);
1221        }
1222    }
1223
1224    /**
1225     * Add a new constant pool entry and return its index.
1226     */

1227    private short addEntry(Entry entry) {
1228        pool.add(entry);
1229        return (short) pool.size();
1230    }
1231
1232    /**
1233     * Get or assign the index for an entry of a type that contains
1234     * a direct value. The type of the given object determines the
1235     * type of the desired entry as follows:
1236     *
1237     * java.lang.String CONSTANT_Utf8
1238     * java.lang.Integer CONSTANT_Integer
1239     * java.lang.Float CONSTANT_Float
1240     * java.lang.Long CONSTANT_Long
1241     * java.lang.Double CONSTANT_DOUBLE
1242     */

1243    private short getValue(Object JavaDoc key) {
1244        Short JavaDoc index = (Short JavaDoc) map.get(key);
1245        if (index != null) {
1246        return index.shortValue();
1247        } else {
1248        if (readOnly) {
1249            throw new InternalError JavaDoc(
1250                        "late constant pool addition: " + key);
1251        }
1252        short i = addEntry(new ValueEntry(key));
1253        map.put(key, new Short JavaDoc(i));
1254        return i;
1255        }
1256    }
1257
1258    /**
1259     * Get or assign the index for an entry of a type that contains
1260     * references to other constant pool entries.
1261     */

1262    private short getIndirect(IndirectEntry e) {
1263        Short JavaDoc index = (Short JavaDoc) map.get(e);
1264        if (index != null) {
1265        return index.shortValue();
1266        } else {
1267        if (readOnly) {
1268            throw new InternalError JavaDoc("late constant pool addition");
1269        }
1270        short i = addEntry(e);
1271        map.put(e, new Short JavaDoc(i));
1272        return i;
1273        }
1274    }
1275
1276    /**
1277     * Entry is the abstact superclass of all constant pool entry types
1278     * that can be stored in the "pool" list; its purpose is to define a
1279     * common method for writing constant pool entries to a class file.
1280     */

1281    private static abstract class Entry {
1282        public abstract void write(DataOutputStream JavaDoc out)
1283            throws IOException JavaDoc;
1284    }
1285
1286    /**
1287     * ValueEntry represents a constant pool entry of a type that
1288     * contains a direct value (see the comments for the "getValue"
1289     * method for a list of such types).
1290     *
1291     * ValueEntry objects are not used as keys for their entries in the
1292     * Map "map", so no useful hashCode or equals methods are defined.
1293     */

1294    private static class ValueEntry extends Entry {
1295        private Object JavaDoc value;
1296
1297        public ValueEntry(Object JavaDoc value) {
1298        this.value = value;
1299        }
1300
1301        public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
1302        if (value instanceof String JavaDoc) {
1303            out.writeByte(CONSTANT_UTF8);
1304            out.writeUTF((String JavaDoc) value);
1305        } else if (value instanceof Integer JavaDoc) {
1306            out.writeByte(CONSTANT_INTEGER);
1307            out.writeInt(((Integer JavaDoc) value).intValue());
1308        } else if (value instanceof Float JavaDoc) {
1309            out.writeByte(CONSTANT_FLOAT);
1310            out.writeFloat(((Float JavaDoc) value).floatValue());
1311        } else if (value instanceof Long JavaDoc) {
1312            out.writeByte(CONSTANT_LONG);
1313            out.writeLong(((Long JavaDoc) value).longValue());
1314        } else if (value instanceof Double JavaDoc) {
1315            out.writeDouble(CONSTANT_DOUBLE);
1316            out.writeDouble(((Double JavaDoc) value).doubleValue());
1317        } else {
1318            throw new InternalError JavaDoc("bogus value entry: " + value);
1319        }
1320        }
1321    }
1322
1323    /**
1324     * IndirectEntry represents a constant pool entry of a type that
1325     * references other constant pool entries, i.e., the following types:
1326     *
1327     * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
1328     * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
1329     * CONSTANT_NameAndType.
1330     *
1331     * Each of these entry types contains either one or two indexes of
1332     * other constant pool entries.
1333     *
1334     * IndirectEntry objects are used as the keys for their entries in
1335     * the Map "map", so the hashCode and equals methods are overridden
1336     * to allow matching.
1337     */

1338    private static class IndirectEntry extends Entry {
1339        private int tag;
1340        private short index0;
1341        private short index1;
1342
1343        /**
1344         * Construct an IndirectEntry for a constant pool entry type
1345         * that contains one index of another entry.
1346         */

1347        public IndirectEntry(int tag, short index) {
1348        this.tag = tag;
1349        this.index0 = index;
1350        this.index1 = 0;
1351        }
1352
1353        /**
1354         * Construct an IndirectEntry for a constant pool entry type
1355         * that contains two indexes for other entries.
1356         */

1357        public IndirectEntry(int tag, short index0, short index1) {
1358        this.tag = tag;
1359        this.index0 = index0;
1360        this.index1 = index1;
1361        }
1362
1363        public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
1364        out.writeByte(tag);
1365        out.writeShort(index0);
1366        /*
1367         * If this entry type contains two indexes, write
1368         * out the second, too.
1369         */

1370        if (tag == CONSTANT_FIELD ||
1371            tag == CONSTANT_METHOD ||
1372            tag == CONSTANT_INTERFACEMETHOD ||
1373            tag == CONSTANT_NAMEANDTYPE)
1374        {
1375            out.writeShort(index1);
1376        }
1377        }
1378
1379        public int hashCode() {
1380        return tag + index0 + index1;
1381        }
1382
1383        public boolean equals(Object JavaDoc obj) {
1384        if (obj instanceof IndirectEntry) {
1385            IndirectEntry other = (IndirectEntry) obj;
1386            if (tag == other.tag &&
1387            index0 == other.index0 && index1 == other.index1)
1388            {
1389            return true;
1390            }
1391        }
1392        return false;
1393        }
1394    }
1395    }
1396}
1397
Popular Tags