1 cananian 1.1.2.4 // ClassFile.java, created Mon Jan 18 22:44:36 1999 by cananian
  2 cananian 1.1.2.1 // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1 package harpoon.IR.RawClass;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 /**
  7 cananian 1.1.2.1  * Represents a java bytecode class file.
  8 cananian 1.1.2.1  * <p>Drawn from <i>The Java Virtual Machine Specification</i>.
  9 cananian 1.1.2.1  *
 10 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 11 cananian 1.3      * @version $Id: ClassFile.java,v 1.3 2002/02/26 08:02:29 cananian Exp $
 12 cananian 1.1.2.1  * @see harpoon.ClassFile.HClass
 13 cananian 1.1.2.1  */
 14 cananian 1.1.2.1 public class ClassFile {
 15 cananian 1.1.2.1   // descriptions taken from The Java Virtual Machine Specification, sect 4.1
 16 cananian 1.1.2.1   /** The magic item supplies the magic number identifying the
 17 cananian 1.1.2.1       <code>class</code> file format; it has the value 0xCAFEBABE. */
 18 cananian 1.1.2.1   static final long MAGIC=0xcafebabeL;
 19 cananian 1.1.2.1 
 20 cananian 1.1.2.1   /** The minor version number of the compiler that produced this
 21 cananian 1.1.2.1       <code>class</code> file. */
 22 cananian 1.1.2.1   public int minor_version;
 23 cananian 1.1.2.1   /** The major version number of the compiler that produced this
 24 cananian 1.1.2.1       <code>class</code> file. */
 25 cananian 1.1.2.1   public int major_version;
 26 cananian 1.1.2.1 
 27 cananian 1.1.2.1   /** The <code>constant_pool</code> is a table of variable-length
 28 cananian 1.1.2.1       structures representing various string constants, class names,
 29 cananian 1.1.2.1       field names, and other constants that are referred to within the
 30 cananian 1.1.2.1       <code>ClassFile</code> structure and its substructures.
 31 cananian 1.1.2.1       
 32 cananian 1.1.2.1       The first entry of the <code>constant_pool</code> table,
 33 cananian 1.1.2.1       <code>constant_pool[0]</code>, is reserved for internal use by a
 34 cananian 1.1.2.1       Java Virtual Machine Implementation.  That entry is <i>not</i>
 35 cananian 1.1.2.1       present in the <code>class</code> file. */
 36 cananian 1.1.2.1   public Constant constant_pool[];
 37 cananian 1.1.2.1   /** The value of the <code>access_flags</code> item is a mask of
 38 cananian 1.1.2.1       modifiers used with class and interface declarations. */
 39 cananian 1.1.2.1   public AccessFlags access_flags;
 40 cananian 1.1.2.1 
 41 cananian 1.1.2.1   /** The value of the <code>this_class</code> item must be a valid
 42 cananian 1.1.2.1       index into the <code>constant_pool</code> table.  The
 43 cananian 1.1.2.1       <code>constant_pool</code> entry at that index must be a
 44 cananian 1.1.2.1       <code>CONSTANT_Class_info</code> structure representing the
 45 cananian 1.1.2.1       class or interface defined by this <code>class</code> file. */
 46 cananian 1.1.2.1   public int this_class;
 47 cananian 1.1.2.1   /** For a class, the value of the <code>super_class</code> item
 48 cananian 1.1.2.1       either must be zero or must be a valid index into the
 49 cananian 1.1.2.1       <code>constant_pool</code> table.  If the value of the
 50 cananian 1.1.2.1       <code>super_class</code> item is nonzero, the
 51 cananian 1.1.2.1       <code>constant_pool</code> entry at that index must be a
 52 cananian 1.1.2.1       <code>CONSTANT_Class_info</code> structure representing the
 53 cananian 1.1.2.1       superclass of the class defined by this <code>class</code>
 54 cananian 1.1.2.1       file.  Neither the superclass nor any of its superclasses may be
 55 cananian 1.1.2.1       a <code>final</code> class.
 56 cananian 1.1.2.1       <p>
 57 cananian 1.1.2.1       If the value of <code>super_class</code> is zero, then this
 58 cananian 1.1.2.1       <code>class</code> file must represent that class
 59 cananian 1.1.2.1       <code>java.lang.Object</code>, the only class or interface
 60 cananian 1.1.2.1       without a superclass.
 61 cananian 1.1.2.1       <p>
 62 cananian 1.1.2.1       For an interface, the value of <code>super_class</code> must
 63 cananian 1.1.2.1       always be a valid index into the <code>constant_pool</code>
 64 cananian 1.1.2.1       table.  The <code>constant_pool</code> entry at that index must
 65 cananian 1.1.2.1       be a <code>CONSTANT_Class_info</code> structure representing the
 66 cananian 1.1.2.1       class <code>java.lang.Object</code>. */
 67 cananian 1.1.2.1   public int super_class;
 68 cananian 1.1.2.1 
 69 cananian 1.1.2.1   /** Each value in the <code>interfaces</code> array must be a valid
 70 cananian 1.1.2.1       index into the <code>constant_pool</code> table.  The
 71 cananian 1.1.2.1       <code>constant_pool</code> entry at each value of
 72 cananian 1.1.2.1       <code>interfaces[i]</code> must be a
 73 cananian 1.1.2.1       <code>CONSTANT_Class_info</code> structure representing an
 74 cananian 1.1.2.1       interface which is a direct superinterface of this class or
 75 cananian 1.1.2.1       interface type, in the left-to-right order given in the source
 76 cananian 1.1.2.1       for the type. */
 77 cananian 1.1.2.1   public int interfaces[];
 78 cananian 1.1.2.1 
 79 cananian 1.1.2.1   /** Each value in the <code>fields</code> table must be a
 80 cananian 1.1.2.1       variable-length <code>field_info</code> structure giving a
 81 cananian 1.1.2.1       complete description of a field in the class or interface type.
 82 cananian 1.1.2.1       The <code>fields</code> table includes only those fields that
 83 cananian 1.1.2.1       are declared by this class or interface.  It does not include
 84 cananian 1.1.2.1       items representing fields that are inherited from superclasses
 85 cananian 1.1.2.1       or superinterfaces. */
 86 cananian 1.1.2.1   public FieldInfo fields[];
 87 cananian 1.1.2.1   /** Each value in the <code>methods</code> table must be a
 88 cananian 1.1.2.1       variable-length <code>method_info</code> structure giving a
 89 cananian 1.1.2.1       complete description of and Java Virtual Machine code for a
 90 cananian 1.1.2.1       method in the class or interface.
 91 cananian 1.1.2.1       <p>
 92 cananian 1.1.2.1       The <code>method_info</code> structures represent all methods,
 93 cananian 1.1.2.1       both instance methods and, for classes, class
 94 cananian 1.1.2.1       (<code>static</code>) methods, declared by this class or
 95 cananian 1.1.2.1       interface type.  The <code>methods</code> table only includes
 96 cananian 1.1.2.1       those items that are explicitly declared by this class.
 97 cananian 1.1.2.1       Interfaces have only the single method
 98 cananian 1.1.2.1       <code>&lt;clinit&gt;</code>, the interface initialization
 99 cananian 1.1.2.1       method.  The <code>methods</code> table does not include items
100 cananian 1.1.2.1       representing methods that are inherited from superclasses or
101 cananian 1.1.2.1       superinterfaces. */
102 cananian 1.1.2.1   public MethodInfo methods[];
103 cananian 1.1.2.1   /** Each value of the <code>attributes</code> table must be a
104 cananian 1.1.2.1       variable-length attribute structure. A <code>ClassFile</code>
105 cananian 1.1.2.1       structure can have any number of attributes associated with it.
106 cananian 1.1.2.1       <p>
107 cananian 1.1.2.1       The only attribute defined by this specification for the
108 cananian 1.1.2.1       <code>attributes</code> table of a <code>ClassFile</code>
109 cananian 1.1.2.1       structure is the <code>SourceFile</code> attribute. */
110 cananian 1.1.2.1   public Attribute attributes[];
111 cananian 1.1.2.1 
112 cananian 1.1.2.1   public void read(ClassDataInputStream in) throws java.io.IOException {
113 cananian 1.1.2.1     int constant_pool_count;
114 cananian 1.1.2.1     int interfaces_count;
115 cananian 1.1.2.1     int fields_count;
116 cananian 1.1.2.1     int methods_count;
117 cananian 1.1.2.1     int attributes_count;
118 cananian 1.1.2.1 
119 cananian 1.1.2.1     long magic = in.read_u4();
120 cananian 1.1.2.1     if (magic != MAGIC)
121 cananian 1.1.2.1       throw new ClassDataException("Bad magic: " + Long.toHexString(magic));
122 cananian 1.1.2.1     
123 cananian 1.1.2.1     minor_version = in.read_u2();
124 cananian 1.1.2.1     major_version = in.read_u2();
125 cananian 1.1.2.1 
126 cananian 1.1.2.1     constant_pool_count = in.read_u2();
127 cananian 1.1.2.1     constant_pool = new Constant[constant_pool_count];
128 cananian 1.1.2.2     // constant_pool[0] is jvm dependent; ignore it.
129 cananian 1.1.2.3     for (int i=1; i<constant_pool_count; ) {
130 cananian 1.1.2.1       constant_pool[i] = Constant.read(this, in);
131 cananian 1.1.2.3       // Long and Double constants take up two entries.
132 cananian 1.1.2.3       i+=constant_pool[i].entrySize();
133 cananian 1.1.2.1     }
134 cananian 1.1.2.1 
135 cananian 1.1.2.1     access_flags = new AccessFlags(in);
136 cananian 1.1.2.1 
137 cananian 1.1.2.1     this_class   = in.read_u2();
138 cananian 1.1.2.1     super_class  = in.read_u2();
139 cananian 1.1.2.1 
140 cananian 1.1.2.1     interfaces_count = in.read_u2();
141 cananian 1.1.2.1     interfaces = new int[interfaces_count];
142 cananian 1.1.2.1     for (int i=0; i<interfaces_count; i++)
143 cananian 1.1.2.1       interfaces[i] = in.read_u2();
144 cananian 1.1.2.1 
145 cananian 1.1.2.1     fields_count = in.read_u2();
146 cananian 1.1.2.1     fields = new FieldInfo[fields_count];
147 cananian 1.1.2.1     for (int i=0; i<fields_count; i++)
148 cananian 1.1.2.1       fields[i] = new FieldInfo(this, in);
149 cananian 1.1.2.1 
150 cananian 1.1.2.1     methods_count = in.read_u2();
151 cananian 1.1.2.1     methods = new MethodInfo[methods_count];
152 cananian 1.1.2.1     for (int i=0; i<methods_count; i++)
153 cananian 1.1.2.1       methods[i] = new MethodInfo(this, in);
154 cananian 1.1.2.1 
155 cananian 1.1.2.1     attributes_count = in.read_u2();
156 cananian 1.1.2.1     attributes = new Attribute[attributes_count];
157 cananian 1.1.2.1     for (int i=0; i<attributes_count; i++)
158 cananian 1.1.2.1       attributes[i] = Attribute.read(this, in);
159 cananian 1.1.2.1   }
160 cananian 1.1.2.1 
161 cananian 1.1.2.1   /** Write a class file object out to a java bytecode file. */
162 cananian 1.1.2.1   public void write(ClassDataOutputStream out)
163 cananian 1.1.2.1     throws java.io.IOException 
164 cananian 1.1.2.1   {
165 cananian 1.1.2.1     out.write_u4(MAGIC);
166 cananian 1.1.2.1     out.write_u2(minor_version);
167 cananian 1.1.2.1     out.write_u2(major_version);
168 cananian 1.1.2.1     if (constant_pool.length > 0xFFFF)
169 cananian 1.1.2.1       throw new ClassDataException("Constant Pool too large: " +
170 cananian 1.1.2.1                                    constant_pool.length);
171 cananian 1.1.2.1     out.write_u2(constant_pool.length);
172 cananian 1.1.2.3     for (int i=1; i<constant_pool.length; ) {
173 cananian 1.1.2.1       constant_pool[i].write(out);
174 cananian 1.1.2.3       // Long and Double constants take up two entries.
175 cananian 1.1.2.3       i+=constant_pool[i].entrySize();
176 cananian 1.1.2.1     }
177 cananian 1.1.2.1 
178 cananian 1.1.2.1     access_flags.write(out);
179 cananian 1.1.2.1 
180 cananian 1.1.2.1     out.write_u2(this_class);
181 cananian 1.1.2.1     out.write_u2(super_class);
182 cananian 1.1.2.1 
183 cananian 1.1.2.1     if (interfaces.length > 0xFFFF)
184 cananian 1.1.2.1       throw new ClassDataException("Interfaces list too long: " +
185 cananian 1.1.2.1                                    interfaces.length);
186 cananian 1.1.2.1     out.write_u2(interfaces.length);
187 cananian 1.1.2.1     for (int i=0; i< interfaces.length; i++)
188 cananian 1.1.2.1       out.write_u2(interfaces[i]);
189 cananian 1.1.2.1 
190 cananian 1.1.2.1     if (fields.length > 0xFFFF)
191 cananian 1.1.2.1       throw new ClassDataException("Fields list too long: " + fields.length);
192 cananian 1.1.2.1     out.write_u2(fields.length);
193 cananian 1.1.2.1     for (int i=0; i< fields.length; i++)
194 cananian 1.1.2.1       fields[i].write(out);
195 cananian 1.1.2.1 
196 cananian 1.1.2.1     if (methods.length > 0xFFFF)
197 cananian 1.1.2.1       throw new ClassDataException("Methods list too long: " + methods.length);
198 cananian 1.1.2.1     out.write_u2(methods.length);
199 cananian 1.1.2.1     for (int i=0; i< methods.length; i++)
200 cananian 1.1.2.1       methods[i].write(out);
201 cananian 1.1.2.1 
202 cananian 1.1.2.1     if (attributes.length > 0xFFFF)
203 cananian 1.1.2.1       throw new ClassDataException("Attributes list too long: " +
204 cananian 1.1.2.1                                    attributes.length);
205 cananian 1.1.2.1     out.write_u2(attributes.length);
206 cananian 1.1.2.1     for (int i=0; i<attributes.length; i++)
207 cananian 1.1.2.1       attributes[i].write(out);
208 cananian 1.1.2.1     //done.
209 cananian 1.1.2.1   }
210 cananian 1.1.2.1   /** Write a class file object out to a java bytecode file. */
211 cananian 1.1.2.1   public void write(java.io.OutputStream out) throws java.io.IOException {
212 cananian 1.1.2.1     write(new ClassDataOutputStream(out));
213 cananian 1.1.2.1   }
214 cananian 1.1.2.1 
215 cananian 1.1.2.1   /** Create a <code>ClassFile</code> object by reading data from a
216 cananian 1.1.2.1       bytecode file. */
217 cananian 1.1.2.1   public ClassFile(ClassDataInputStream in) {
218 cananian 1.1.2.1     try {
219 cananian 1.1.2.1       read(in);
220 cananian 1.1.2.1     } catch (java.io.IOException e) {
221 cananian 1.1.2.1       throw new ClassFormatError(e.toString());
222 cananian 1.1.2.1     }
223 cananian 1.1.2.1   }
224 cananian 1.1.2.1   /** Create a <code>ClassFile</code> object by reading data from a
225 cananian 1.1.2.1       bytecode file. */
226 cananian 1.1.2.1   public ClassFile(java.io.InputStream in) {
227 cananian 1.1.2.1     try {
228 cananian 1.1.2.1       read(new ClassDataInputStream(in));
229 cananian 1.1.2.1     } catch (java.io.IOException e) {
230 cananian 1.1.2.1       throw new ClassFormatError(e.toString());
231 cananian 1.1.2.1     }
232 cananian 1.1.2.1   }
233 cananian 1.1.2.1 
234 cananian 1.1.2.1   // Interrogate the data structures. (convenience functions)
235 cananian 1.1.2.1 
236 cananian 1.1.2.1   /** Return the <code>CONSTANT_Class_info</code> entry in the
237 cananian 1.1.2.1       <code>constant_pool</code> corresponding to the value of
238 cananian 1.1.2.1       <code>this_class</code>. */
239 cananian 1.1.2.1   public ConstantClass this_class() 
240 cananian 1.1.2.1   { return (ConstantClass) constant_pool[this_class]; }
241 cananian 1.1.2.1   /** Return the <code>CONSTANT_Class_info</code> entry in the
242 cananian 1.1.2.1       <code>constant_pool</code> corresponding to the value of
243 cananian 1.1.2.1       <code>super_class</code>, or <code>null</code> if
244 cananian 1.1.2.1       <code>super_class</code> == 0. */
245 cananian 1.1.2.1   public ConstantClass super_class()
246 cananian 1.1.2.1   { return (super_class==0)?null:(ConstantClass) constant_pool[super_class]; }
247 cananian 1.1.2.1   /** Return the <code>CONSTANT_Class_info</code> entry in the
248 cananian 1.1.2.1       <code>constant_pool</code> corresponding to the value in
249 cananian 1.1.2.1       <code>interfaces[i]</code>. */
250 cananian 1.1.2.1   public ConstantClass interfaces(int i)
251 cananian 1.1.2.1   { return (ConstantClass) constant_pool[interfaces[i]]; }
252 cananian 1.1.2.1 
253 cananian 1.1.2.1   // more conveniences.
254 cananian 1.1.2.1   public int constant_pool_count() { return constant_pool.length; }
255 cananian 1.1.2.1   public int interfaces_count() { return interfaces.length; }
256 cananian 1.1.2.1   public int fields_count() { return fields.length; }
257 cananian 1.1.2.1   public int methods_count() { return methods.length; }
258 cananian 1.1.2.1   public int attributes_count() { return attributes.length; }
259 cananian 1.1.2.1 
260 cananian 1.1.2.1   /** Pretty print this classfile structure. */
261 cananian 1.1.2.1   public void print(java.io.PrintWriter pw) { print(pw,0); }
262 cananian 1.1.2.1   public void print(java.io.PrintWriter pw, int indent) {
263 cananian 1.1.2.1     int in=indent;
264 cananian 1.1.2.1     indent(pw, in+0, "ClassFile {");
265 cananian 1.1.2.1     indent(pw, in+1, "Magic: 0x" + Long.toHexString(MAGIC).toUpperCase());
266 cananian 1.1.2.1     indent(pw, in+1, "Minor Version: " + minor_version);
267 cananian 1.1.2.1     indent(pw, in+1, "Major Version: " + major_version);
268 cananian 1.1.2.1     // constant pool.
269 cananian 1.1.2.1     indent(pw, in+1, "Constant Pool ["+constant_pool.length+"]:");
270 cananian 1.1.2.1     for (int i=1; i<constant_pool.length; i++) {
271 cananian 1.1.2.1       indent(pw, in+2, "Constant {"+i+"}:");
272 cananian 1.1.2.1       constant_pool[i].print(pw, in+3);
273 cananian 1.1.2.3       // some constants take more than one entry.
274 cananian 1.1.2.3       for (int j=1; j<constant_pool[i].entrySize(); j++)
275 cananian 1.3             indent(pw, in+2, "Constant {"+ (i+j) +"} is invalid.");
276 cananian 1.3           i+=constant_pool[i].entrySize()-1;
277 cananian 1.1.2.1     }
278 cananian 1.1.2.1     // this class information
279 cananian 1.1.2.1     indent(pw, in+1, "Access Flags: " + access_flags);
280 cananian 1.1.2.1     indent(pw, in+1, "This class:  " + this_class().name() + 
281 cananian 1.1.2.1            " {"+this_class+"}");
282 cananian 1.1.2.1     indent(pw, in+1, "Super class: " + super_class().name() +
283 cananian 1.1.2.1            " {"+super_class+"}");
284 cananian 1.1.2.1     // interfaces
285 cananian 1.1.2.1     indent(pw, in+1, "Interfaces ["+interfaces.length+"]:");
286 cananian 1.1.2.1     for (int i=0; i<interfaces.length; i++) {
287 cananian 1.1.2.1       indent(pw, in+2, "#"+i+": " + interfaces(i).name() + 
288 cananian 1.1.2.1              " {"+interfaces[i]+"}");
289 cananian 1.1.2.1     }
290 cananian 1.1.2.1     // fields
291 cananian 1.1.2.1     indent(pw, in+1, "Fields ["+fields.length+"]:");
292 cananian 1.1.2.1     for (int i=0; i<fields.length; i++) {
293 cananian 1.1.2.1       indent(pw, in+2, "#"+i+": ");
294 cananian 1.1.2.1       fields[i].print(pw, in+3);
295 cananian 1.1.2.1     }
296 cananian 1.1.2.1     // methods
297 cananian 1.1.2.1     indent(pw, in+1, "Methods ["+methods.length+"]:");
298 cananian 1.1.2.1     for (int i=0; i<methods.length; i++) {
299 cananian 1.1.2.1       indent(pw, in+2, "#"+i+": ");
300 cananian 1.1.2.1       methods[i].print(pw, in+3);
301 cananian 1.1.2.1     }
302 cananian 1.1.2.1     // attributes
303 cananian 1.1.2.1     indent(pw, in+1, "Attributes ["+attributes.length+"]:");
304 cananian 1.1.2.1     for (int i=0; i<attributes.length; i++) {
305 cananian 1.1.2.1       indent(pw, in+2, "#"+i+": ");
306 cananian 1.1.2.1       attributes[i].print(pw, in+3);
307 cananian 1.1.2.1     }
308 cananian 1.1.2.1     indent(pw, in+0, "}");
309 cananian 1.1.2.1   }
310 cananian 1.1.2.1   /** Output string <code>s</code> to PrintWriter <code>pw</code> at
311 cananian 1.1.2.1    *  the given indentation level <code>indent</code>.
312 cananian 1.1.2.1    *  @param pw the output destination.
313 cananian 1.1.2.1    *  @param indent the indentation level to use.
314 cananian 1.1.2.1    *  @param s the string to write.
315 cananian 1.1.2.1    */
316 cananian 1.1.2.1   public static void indent(java.io.PrintWriter pw, int indent, String s) {
317 cananian 1.1.2.1     for (int i=0; i<indent; i++)
318 cananian 1.1.2.1       pw.print("  ");
319 cananian 1.1.2.1     pw.println(s);
320 cananian 1.1.2.1   }
321 cananian 1.2     }