KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jbet > ClassInfo


1 /*
2  * JBET - Java Binary Enhancement Tool
3  * Copyright (c) 2003 Networks Associates Technology, Inc.
4  *
5  * This software was developed under DARPA/SPAWAR contract
6  * N66001-00-C-8602 "SPMA" as part of the
7  * DARPA OASIS research program.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */

30
31 package jbet;
32 import java.io.*;
33 import java.util.*;
34
35 /**
36   * Represent a Java class file in memory, using data structures that
37   * are closely related to the physical layout of a class file on disk,
38   * but are more convenient for manipulation. The ClassInfo object
39   * knows how to read itself in from disk and to write itself out to
40   * disk. This is a central building block for JBET.
41   *
42   * Abstractly, a JBET operation consists of:
43   * 1) Read in one or more ClassInfo objects.
44   * 2) Query or modify them (possibly translating them to more
45   * abstract data structures).
46   * 3) Optionally write out one more more ClassInfo objects.
47   *
48   *
49   * This file contains fields that hold a ClassInfo, and code that:
50   * 1) initializes the fields
51   * 2) does file i/o
52   * 3) follows links to read in inner classes to separate ClassInfos.
53   * 4) assembly/disassembly.
54   * 5) printout code to display ClassInfo data.
55   *
56   * Note that, if a class has an inner class, the inner class has its
57   * own class file, and thus its own ClassInfo object.
58   *
59   * @author Lee Badger
60   * @author Larry D'Anna
61   * @version 0.1 @since JDK 1.1.8
62   */

63
64 public final class ClassInfo {
65
66     public static String JavaDoc JbetLogFacility = "class";
67
68     private int sourceFileIndex; // an integer value
69
private Vector attributes; // GenericAttribute
70
private Vector attrHints; // GenericAttribute
71
private int [] interfaceInts;
72     private int thisClassIndex, superClassIndex;
73
74     /* File this ClassInfo was read from, if it was read from a class file. */
75     String JavaDoc filename = null;
76     public ClassPathElement classPathElement = null;
77     public boolean dirty = false;
78
79     /* Components of the class file, slightly abstracted. */
80     int magic;
81     int minorVersion;
82     int majorVersion;
83     public ConstantPool constantPool;
84     public int accessFlags;
85     public String JavaDoc thisClass;
86     public String JavaDoc superClass;
87     public Vector interfaces; // CpClass
88
public Vector fields; // FieldInfo
89
public Vector methods; // MethodInfo
90

91     /* The last component of a class file is a table of variable
92      * length attribute records. The attributes that can appear in
93      * this table are: InnerClasses, synthetic, deprecated, and
94      * SourceFile. For convenience, we split this table by attribute
95      * type. */

96     Vector innerClasses; // InnerClassInfo
97
//int nextAnon = 1;
98
public boolean synthetic, deprecated;
99     public String JavaDoc sourceFile;
100
101     /*
102     public Vector children = new Vector();
103     ClassInfo parent;
104     */

105
106     /**
107      * Construct a new, empty ClassInfo object. The object is
108      * initialized only with empty or default values. To be
109      * meaningful, the initialization must be finalized.
110      *
111      * @param cpElement Input/Output streams for the new object.
112      * @param thisClass The name of the new class.
113      */

114     public ClassInfo(ClassPathElement cpElement, String JavaDoc thisClass) {
115     init(cpElement, thisClass);
116     }
117
118     public void setOutdir (ClassPathElement cpe) {
119     if (classPathElement == null)
120         classPathElement = cpe;
121     }
122
123     /**
124      * Create either a single ClassInfo, or a tree of ClassInfo objects.
125      *
126      * A single ClassInfo represents a single .class file. A tree of
127      * ClassInfo objects represents a .class file, along with all of
128      * its inner classes. When inner classes are read, additional
129      * ClassInfo objects are created and pointed to from the root
130      * object.
131      *
132      * @param in The data stream from which to read the root ClassInfo.
133      * @param cpElement Input/Output streams for the new object.
134      * @param parent Should be set to null if this is the root.
135      */

136     public ClassInfo(InputStream in) throws ClassFileException, IOException {
137     this(in,null,null);
138     }
139     public ClassInfo(InputStream in, ClassPathElement cpElement)
140     throws ClassFileException, IOException {
141     this(in,cpElement,null);
142     }
143     public ClassInfo(InputStream in, ClassPathElement cpElement,
144             String JavaDoc filename)
145     throws ClassFileException, IOException {
146     this.classPathElement = cpElement;
147     this.filename = filename;
148     DataInputStream dataIn = in instanceof DataInputStream ?
149         (DataInputStream) in : new DataInputStream(in);
150     readFile(dataIn);
151     }
152
153     /**
154      * Create a new ClassInfo by copying from another. The data
155      * structures comprising the new object (e.g., Vectors) are
156      * created independently so that subsequent changes to the
157      * original object will _not_ affect the new object.
158      *
159      * @param cr The original ClassInfo.
160      */

161     public ClassInfo(ClassInfo cr) {
162     magic = cr.magic;
163     minorVersion = cr.minorVersion;
164     majorVersion = cr.majorVersion;
165     constantPool = null;
166     accessFlags = cr.accessFlags;
167     thisClass = cr.thisClass;
168     superClass = cr.superClass;
169
170     interfaces = new Vector( cr.interfaces.size() );
171     for (int i = 0; i < cr.interfaces.size(); i++)
172         interfaces.addElement( cr.interfaces.elementAt(i) );
173
174     fields = new Vector( cr.fields.size() );
175     for (int i = 0; i < cr.fields.size(); i++)
176         addField (new FieldInfo ((FieldInfo)cr.fields.elementAt(i)));
177
178     methods = new Vector( cr.methods.size() );
179     for (int i = 0; i < cr.methods.size(); i++)
180         addMethod
181         ((new MethodInfo ((MethodInfo)cr.methods.elementAt(i))));
182
183     innerClasses = new Vector( cr.innerClasses.size() );
184     for (int i = 0; i < cr.innerClasses.size(); i++)
185         innerClasses.addElement
186         (((InnerClassInfo)cr.innerClasses.elementAt(i)).dup());
187     
188     attrHints = new Vector();
189     
190     synthetic = cr.synthetic;
191     deprecated = cr.deprecated;
192     sourceFile = cr.sourceFile;
193
194     newPool();
195     }
196
197     
198     public FieldInfo getField(String JavaDoc name) throws ElementNotFoundException {
199     FieldInfo ret = null;
200     for (int i = 0; i < fields.size(); i++) {
201         FieldInfo mi = (FieldInfo) fields.elementAt(i);
202         if (mi.name.equals(name))
203         if (ret == null)
204             ret = mi;
205         else
206             throw new ElementNotFoundException
207             (name(), name, null, "Can not disambiguate");
208     }
209     if (ret == null) {
210         throw new ElementNotFoundException (name(), name, null);
211     }
212     return ret;
213     }
214
215
216     /**
217      * Supports the JBET assembler/disassembler feature. Creates a
218      * ClassInfo object tree by reading tokens from the lexer. The
219      * lexer is reading text written in the JBET Assembler Language,
220      * which is described TBD.
221      *
222      * @param cpElement Input/Output streams for the new object.
223      * @param lexer A lexer whose tokens drive the object's
224      * construction.
225      */

226     public ClassInfo(ClassPathElement cpElement, Lexer lexer) throws ClassFileException {
227     lexer.push(Lexer.ST_ASM);
228     if (!lexer.match(Token.TAG).text.equals(".class")) {
229         lexer.unexpected(lexer.justread());
230     }
231     int af = lexer.parse_flags(ACC_ALL_CFLAGS | ACC_ALL_INNER_CFLAGS);
232     String JavaDoc name = lexer.match(Token.TAG).text;
233     init(cpElement, name);
234     accessFlags = af;
235     lexer.match('{');
236     while (true) {
237         lexer.state = Lexer.ST_ASM;
238         while (lexer.peek().type == ';') {
239         lexer.read();
240         }
241         Token tok = lexer.peek();
242         lexer.state = Lexer.ST_ASM_ARG;
243         if (tok.type == Token.TAG) {
244         if (tok.text.equals(".inner")) {
245             InnerClassInfo ici = new InnerClassInfo(lexer);
246             innerClasses.addElement(ici);
247             continue;
248         }
249         /*if (tok.text.equals(".class")) {
250             ClassInfo child = new ClassInfo(cpElement, lexer);
251             child.parent = this;
252             children.addElement(child);
253             continue;
254             }*/

255         if (tok.text.equals(".field")) {
256             FieldInfo fi = new FieldInfo(lexer);
257             addField(fi);
258             continue;
259         }
260         if (tok.text.equals(".method")) {
261             MethodInfo mi = new MethodInfo(lexer);
262             addMethod(mi);
263             continue;
264         }
265         lexer.read();
266         if (tok.text.equals(".synthetic")) {
267             lexer.term();
268             synthetic = true;
269             continue;
270         }
271         if (tok.text.equals(".deprecated")) {
272             lexer.term();
273             deprecated = true;
274             continue;
275         }
276         if (tok.text.equals(".flags")) {
277             int flags = lexer.parse_flags(ACC_ALL_CFLAGS);
278             lexer.term();
279             accessFlags = flags;
280             continue;
281         }
282         if (tok.text.equals(".extends")) {
283             superClass = lexer.parse_name();
284             lexer.term();
285             continue;
286         }
287         if (tok.text.equals(".implements")) {
288             interfaces.addElement( lexer.parse_name() );
289             lexer.term();
290             continue;
291         }
292         if (tok.text.equals(".sourcefile")) {
293             sourceFile = lexer.parse_string();
294             lexer.term();
295             continue;
296         }
297         lexer.unexpected(tok);
298         }
299         if (tok.type == '}') {
300         break;
301         }
302         lexer.unexpected(tok);
303     }
304     lexer.match('}');
305     lexer.pop();
306     //mergeFlags();
307
}
308
309     /**
310      * Initialize a new ClassInfo object with empty or default values.
311      * It performs no I/O. The resulting object should be finalized by
312      * other code.
313      *
314      * @param cpElement Input/Output streams for the new object.
315      * @param thisClass The name of the class being represented.
316      */

317     private void init(ClassPathElement cpElement, String JavaDoc thisClass) {
318     constantPool = new ConstantPool();
319     classPathElement = cpElement;
320     dirty = true;
321     magic = 0xCAFEBABE;
322     minorVersion = 3;
323     majorVersion = 45;
324     accessFlags = ACC_PUBLIC & ACC_FINAL;
325     this.thisClass = thisClass;
326     superClass = "java/lang/Object";
327     interfaces = new Vector();
328     fields = new Vector();
329     methods = new Vector();
330     innerClasses = new Vector();
331     synthetic = true;
332     deprecated = false;
333     sourceFile = null;
334     //children = new Vector();
335
//parent = null;
336
attrHints = new Vector();
337     }
338
339     /*
340      * Top-level read-in/write-out functions.
341      */

342
343     /**
344      * Fill in this (assumed) empty ClassInfo object by reading the
345      * class file format from an open input stream. Reads the entire
346      * class file. The class file format is documented in Chapter 4
347      * of the Java Virtual Machine Specification.
348      *
349      * This is very straight-forward except for the handling of
350      * attributes, where we split out the attributes into fields that
351      * are more convenient to reference than array entries. Also,
352      * attribute handling is complicated by the "hint" information we
353      * maintain. We maintain hints about the arbitrary order in which
354      * attributes were stored in the class file so that we can write
355      * them out in the same arbitrary order. The ability to duplicate
356      * the arbitrary order is not needed for correctness, but enables
357      * regression tests that compare JBET-generated class files to
358      * originals, using checksums.
359      *
360      * @param dataIn The stream to read from.
361      */

362     private void readFile(DataInputStream dataIn)
363     throws IOException, ClassFileException {
364
365     synthetic = deprecated = false;
366     sourceFile = null;
367     innerClasses = new Vector();
368     
369     magic = dataIn.readInt();
370     minorVersion = dataIn.readUnsignedShort();
371     majorVersion = dataIn.readUnsignedShort();
372
373     constantPool = new ConstantPool(dataIn);
374
375     accessFlags = dataIn.readUnsignedShort();
376
377     thisClassIndex = dataIn.readUnsignedShort();
378     thisClass = constantPool.cpClassAt(thisClassIndex).string();
379
380     superClassIndex = dataIn.readUnsignedShort();
381     superClass = (superClassIndex == 0) ? null :
382         constantPool.cpClassAt(superClassIndex).string();
383
384     int interfacesCount = dataIn.readUnsignedShort();
385     interfaces = new Vector (interfacesCount);
386     interfaceInts = new int [ interfacesCount ];
387     for (int i = 0; i < interfacesCount; i++) {
388         int index = dataIn.readUnsignedShort();
389         interfaceInts[i] = index;
390         interfaces.addElement
391         ( constantPool.cpClassAt(index).string() );
392     }
393     
394     int fieldsCount = dataIn.readUnsignedShort();
395     fields = new Vector (fieldsCount);
396     for (int i = 0; i < fieldsCount; i++) {
397         FieldInfo f = new FieldInfo(dataIn, constantPool);
398         addField(f);
399     }
400
401     int methodsCount = dataIn.readUnsignedShort();
402     methods = new Vector (methodsCount);
403     for (int i = 0; i < methodsCount; i++) {
404         MethodInfo m = new MethodInfo(dataIn, constantPool);
405         addMethod(m);
406     }
407
408     /*
409      * Read the attributes of the .class file. Attributes are
410      * variable-length. For each attribute, create an object and
411      * point it to the method that should be used to write out
412      * that attribute later.
413      *
414      * Note: the JVM spec states that only the SourceFile and
415      * Deprecated attributes should appear here, but the
416      * InnerClasss attribute is generated by Jikes (and maybe
417      * other compilers).
418      */

419     int attributesCount = dataIn.readUnsignedShort();
420     attrHints = new Vector (attributesCount);
421     for (int i = 0; i < attributesCount; i++) {
422         int nameindex = dataIn.readUnsignedShort();
423         String JavaDoc attrname = constantPool.utf8At(nameindex);
424         int length = dataIn.readInt();
425         
426         GenericAttribute item = new GenericAttribute (attrname, nameindex);
427     
428         if (attrname.equals("InnerClasses")) {
429         int numClasses = dataIn.readUnsignedShort();
430         innerClasses.ensureCapacity(numClasses);
431         for (int j = 0; j < numClasses; j++) {
432             InnerClassInfo ic = new InnerClassInfo(dataIn,
433                                constantPool);
434             if (ic.inner.equals(thisClass))
435             accessFlags |= ic.accessFlags;
436             innerClasses.addElement(ic);
437         }
438         item.writer = innerClassesWriter();
439         } else if (attrname.equals("Synthetic")) {
440         synthetic = true;
441         item.nodata();
442         } else if (attrname.equals("Deprecated")) {
443         deprecated = true;
444         item.nodata();
445         } else if (attrname.equals("SourceFile")) {
446         sourceFileIndex = dataIn.readUnsignedShort();
447         sourceFile = constantPool.utf8At(sourceFileIndex);
448         item.writer = sourceFileWriter();
449         } else {
450         Jbet.warn.println("Warning: unrecognised class attribute " +
451                   attrname);
452         item.read(length, dataIn);
453         }
454         attrHints.addElement(item);
455     }
456     attributes = attrHints;
457
458     }
459
460     /**
461      * Called by Jbet. Write this object out in a .class file in the
462      * correct directory. Reconstructs the constant pool before
463      * writing.
464      */

465     public void write() throws Exception JavaDoc {
466     resolveConstants();
467
468     String JavaDoc filename = this.filename;
469     if (filename == null) filename = name() + ".class";
470     ClassPathElement cpe = classPathElement;
471     if (cpe == null) cpe = new ClassInfoLoader.DirectoryCPE(Jbet.outputdir);
472     OutputStream out = cpe.put(filename);
473     Jbet.info.println("wrote " + name() + " TO " + filename + " IN " +
474               cpe);
475     DataOutputStream dataOut = new DataOutputStream (out);
476
477     writeFile(dataOut);
478     dirty = false;
479     }
480
481     /**
482      * These two functions write this CpClass object to the named (1)
483      * file or (2) open output stream.
484      *
485      * Note: if the CpClass has been modified, resolveConstants() should
486      * be called before calling writeFile. TBD - perhaps writeFile should
487      * call resolveConstants().
488      *
489      * @param filename The file to write to.
490      * @throws IOException.
491      */

492     void writeFile(String JavaDoc filename) throws IOException {
493     FileOutputStream fout = new FileOutputStream(filename);
494     DataOutputStream dataOut = new DataOutputStream(fout);
495     writeFile(dataOut);
496     }
497     public void writeFile(OutputStream out) throws IOException {
498     DataOutputStream dataOut = new DataOutputStream(out);
499     writeFile(dataOut);
500     }
501     public void writeFile (DataOutputStream dataOut) throws IOException {
502     dataOut.writeInt( magic );
503     dataOut.writeShort( minorVersion );
504     dataOut.writeShort( majorVersion );
505
506     constantPool.writeFile (dataOut);
507
508     //clear out private, protected and static
509
dataOut.writeShort( accessFlags & ACC_ALL_CFLAGS );
510     dataOut.writeShort( thisClassIndex );
511     dataOut.writeShort( superClassIndex );
512
513     dataOut.writeShort( interfaceInts.length ) ;
514     for (int i = 0; i < interfaceInts.length; i++)
515         dataOut.writeShort( interfaceInts[i] );
516
517     dataOut.writeShort( fields.size() );
518     for (int i = 0; i < fields.size(); i++)
519         ((FieldInfo)fields.elementAt(i)).writeFile( dataOut );
520     
521     dataOut.writeShort( methods.size() );
522     for (int i = 0; i < methods.size(); i++)
523         ((MethodInfo)methods.elementAt(i)).writeFile( dataOut );
524
525     dataOut.writeShort( attributes.size() );
526     for (int i = 0; i < attributes.size(); i++)
527         ((GenericAttribute)attributes.elementAt(i)).writeAll( dataOut );
528     }
529
530     /**
531      * These two anonymous classes, which implement the
532      * AttributeWriter interface, provide code to the GenericAttribute
533      * class to write out the InnerClasses or a SourceFile attribute
534      * types. Effectively, this code is called indirectly by
535      * writeFile().
536      */

537     private AttributeWriter innerClassesWriter() {
538     final int icsize = innerClasses.size();
539     return new AttributeWriter() {
540         public void write (DataOutputStream dataOut)
541             throws IOException, RuntimeException JavaDoc {
542             dataOut.writeShort( icsize );
543             for (int i = 0; i < icsize; i++)
544             ((InnerClassInfo)
545              innerClasses.elementAt(i)).writeFile(dataOut);
546         }
547         public int size() { return 2 + 8*icsize; }
548         };
549     }
550     private AttributeWriter sourceFileWriter() {
551     return new AttributeWriter() {
552         public void write(DataOutputStream dataOut)
553             throws IOException, RuntimeException JavaDoc {
554             dataOut.writeShort( sourceFileIndex );
555         }
556         public int size() { return 2; }
557         };
558     }
559
560     /**
561      * This method is the top level of a name-changing mechanism that
562      * spans a number of the core JBET abstractions. This mechanism
563      * is needed because some operations, like class renaming, have
564      * ripple effects. For example, a change to a class's name will
565      * affect the class's inner class names, possibly the contents of
566      * Java descriptor strings, etc.
567      *
568      * This method drives appropriate substitutions throughout the
569      * JBET system.
570      *
571      * @param subs A table of string substitution pairs. The key
572      * values should be the old names, and the values
573      * associated with the keys in the table should be the
574      * replacement values. For example, call
575      * subs.put(name, newname) prior to calling relocate.
576      */

577     public void relocate (Hashtable subs) {
578     thisClass = Util.relocate(thisClass, subs);
579     superClass = Util.relocate(superClass, subs);
580     for (int i = 0; i < interfaces.size(); i++) {
581         String JavaDoc cp = interfaceAt(i);
582         cp = Util.relocate(cp, subs);
583         interfaces.setElementAt(cp, i);
584     }
585     for (int i = 0; i < fields.size(); i++)
586         fieldAt(i).relocate(subs);
587     for (int i = 0; i < methods.size(); i++)
588         methodAt(i).relocate(subs);
589     for (int i = 0; i < innerClasses.size(); i++)
590         innerClassAt(i).relocate(subs);
591     }
592
593     /**
594      * Return this class's name.
595      */

596     public String JavaDoc toString() {
597     return thisClass;
598     }
599
600     public String JavaDoc name() {
601     return thisClass;
602     }
603
604     public ClassPathElement getPathElement () {
605     return classPathElement;
606     }
607
608     /**
609      * Returns true if the class is an anonymous inner class of either
610      * flavor.
611      *
612      * TBD - explain the differences among the different kinds of
613      * inner class names. */

614     public boolean isAnon() {
615     return Util.isAnon(thisClass);
616     }
617
618     /**
619      * Construct a new constant pool and initialize it by traversing
620      * the core CpClass data structures. This traversal descends as
621      * needed to lower-level structures such as Snippit and
622      * Instruction objects.
623      */

624     private void newPool() {
625     constantPool = new ConstantPool();
626     }
627
628     /**
629      * JBET assembler support that isn't in a constructor.
630      * Dissassemble an entire class.
631      *
632      * @param out
633      * @param prefix
634      */

635     public void disassemble(LineWriter out, String JavaDoc prefix) {
636     out.println (prefix + ".class " +
637              Util.flags2str(accessFlags, true) + " " +
638              thisClass + " {");
639     String JavaDoc p = prefix + " ";
640     if (!superClass.equals("java/lang/Object"))
641         out.println(p + ".extends " + superClass);
642     for (int i = 0; i < interfaces.size(); i++)
643         out.println(p + ".implements " + interfaceAt(i));
644     if (sourceFile != null)
645         out.println(p + ".sourcefile \"" +
646             Util.quoteString(sourceFile) + "\"");
647     if (synthetic)
648         out.println(p + ".synthetic");
649     if (deprecated)
650         out.println(p + ".deprecated");
651     out.println(prefix);
652     for (int i = 0; i < fields.size(); i++)
653         fieldAt(i).disassemble(out, p);
654     out.println(prefix);
655     for (int i = 0; i < methods.size(); i++) {
656         methodAt(i).disassemble(out, p);
657         out.println(prefix);
658     }
659     for (int i = 0; i < innerClasses.size(); i++)
660         innerClassAt(i).disassemble(out, p);
661     out.println(prefix);
662     out.println (prefix + "}");
663     }
664
665     /**
666      * The purpose of this method, and the methods it calls, is to
667      * reconstruct a valid, unique ConstantPool. The class file
668      * format defines the constant pool records to be unique.
669      * Maintaining centralized, unique, data structures to represent
670      * simple constant values (such as int, float, and String) during
671      * JBET modifications of a binary would complicate JBET. Instead
672      * of doing that, we represent simple constants where most
673      * convenient within the JBET data structures, and traverse them
674      * to construct a valid ConstantPool before writing it out to
675      * disk.
676      */

677     public void resolveConstants() {
678
679     thisClassIndex = constantPool.internClass(thisClass);
680     superClassIndex = constantPool.internClass(superClass);
681
682     interfaceInts = new int [ interfaces.size() ];
683     for (int i = 0; i < interfaces.size(); i++)
684         interfaceInts[i] = constantPool.internClass(interfaceAt(i));
685
686     for (int i = 0; i < fields.size(); i++)
687         ((FieldInfo)fields.elementAt(i)).resolveConstants(constantPool);
688
689     for (int i = 0; i < methods.size(); i++)
690         ((MethodInfo)methods.elementAt(i)).resolveConstants(constantPool);
691     
692     Vector outAttrs = new Vector();
693     
694     for (int i = 0; i < innerClasses.size(); i++)
695         innerClassAt(i).resolveConstants(constantPool);
696
697     if (innerClasses.size() != 0) {
698         GenericAttribute attr = new GenericAttribute("InnerClasses",
699                              constantPool);
700         attr.writer = innerClassesWriter();
701         outAttrs.addElement( attr );
702     }
703
704     if (synthetic)
705         outAttrs.addElement(new GenericAttribute("Synthetic",
706                              constantPool).nodata());
707
708     if (deprecated)
709         outAttrs.addElement(new GenericAttribute("Deprecated",
710                              constantPool).nodata());
711
712     if (sourceFile != null) {
713         GenericAttribute attr = new GenericAttribute("SourceFile",
714                              constantPool);
715         sourceFileIndex = constantPool.internUtf8 ( sourceFile );
716         attr.writer = sourceFileWriter();
717         outAttrs.addElement( attr );
718     }
719     attributes = new Vector();
720     GenericAttribute.permute (attrHints, outAttrs, attributes);
721     }
722
723     /*
724      * Convenience members.
725      */

726     public String JavaDoc getSuperName() {
727     return superClass;
728     }
729
730     public ConstantPool constantPool () {
731     return constantPool;
732     }
733
734     public int numMethods () {
735     return methods.size();
736     }
737     public int numFields () {
738     return fields.size();
739     }
740     public int numInterfaces () {
741     return interfaces.size();
742     }
743
744     public String JavaDoc interfaceAt(int i) {
745     return (String JavaDoc) interfaces.elementAt(i);
746     }
747     public FieldInfo fieldAt(int i) {
748     return (FieldInfo) fields.elementAt(i);
749     }
750     public MethodInfo methodAt(int i) {
751     return (MethodInfo) methods.elementAt(i);
752     }
753     public void addMethod(MethodInfo mi) {
754     mi.cr = this;
755     methods.addElement(mi);
756     }
757     public void addField(FieldInfo fi) {
758     fi.cr = this;
759     fields.addElement(fi);
760     }
761     public void removeField (FieldInfo fi) {
762     fields.remove (fi);
763     }
764     public void removeMethod (MethodInfo fi) {
765     methods.remove (fi);
766     }
767
768     public InnerClassInfo innerClassAt(int i) {
769     return (InnerClassInfo) innerClasses.elementAt(i);
770     }
771
772     /* find the method with name name and type type. if type is null
773        and there is only one method with name name then return it.*/

774     public MethodInfo findMethod (String JavaDoc name, String JavaDoc type) {
775     MethodInfo ret = null;
776     for (int i = 0; i < methods.size(); i++) {
777         MethodInfo mi = (MethodInfo) methods.elementAt(i);
778         if (mi.name.equals(name) &&
779         (type==null || type.equals(mi.descriptor.toString())))
780         if (ret == null)
781             ret = mi;
782         else
783             return null;
784     }
785     return ret;
786     }
787     public MethodInfo findMethod(String JavaDoc name) {
788     return findMethod(name, (Descriptor) null);
789     }
790     public MethodInfo findMethod (String JavaDoc name, Descriptor type) {
791     MethodInfo ret = null;
792     for (int i = 0; i < methods.size(); i++) {
793         MethodInfo mi = (MethodInfo) methods.elementAt(i);
794         if (mi.name.equals(name) &&
795         (type==null || type.equals(mi.descriptor)))
796         if (ret == null)
797             ret = mi;
798         else
799             return null;
800     }
801     return ret;
802     }
803     public FieldInfo findField (String JavaDoc name) {
804     for (int i = 0; i < fields.size(); i++) {
805         FieldInfo fi = (FieldInfo) fields.elementAt(i);
806         if (fi.name.equals(name))
807         return fi;
808     }
809     return null;
810     }
811
812     public int findMethodIndex (String JavaDoc name, Descriptor type) {
813     int ret = -1;
814     for (int i = 0; i < methods.size(); i++) {
815         MethodInfo mi = (MethodInfo) methods.elementAt(i);
816         if (mi.name.equals(name) &&
817         (type==null || type.equals(mi.descriptor)))
818         if (ret == -1)
819             ret = i;
820         else
821             return -1;
822     }
823     return ret;
824     }
825
826     /**
827      * Functions to print portions of this ClassInfo object.
828      */

829     public void printout(LineWriter out, int v) {
830     if (v == 1)
831         out.println("CLASS");
832     if (v == 2)
833         out.println("CLASS " + thisClass );
834     out.println( "Magic: " + Integer.toHexString(magic));
835     out.println( "Version: " + majorVersion + "." + minorVersion);
836     out.println( "Pool Count: " + constantPool.poolCount() );
837     out.println( "Flags: " + Util.flags2str(accessFlags, true) +
838              (synthetic?" synthetic":"") +
839              (deprecated?" deprecated":"") );
840     out.println( "This Class: " + thisClass );
841     out.println( "Super Class: " + superClass );
842     out.print ( "Interfaces: " );
843     for (int i = 0; i < interfaces.size(); i++)
844         out.print( (interfaceAt(i)) + " " );
845     out.println();
846     out.println( "Fields Count: " + fields.size() );
847     out.println( "Methods Count: " + methods.size() );
848     if (attributes != null) {
849         out.print ( "Attributes: " );
850         for (int i = 0; i < attributes.size(); i++)
851         out.print( ((GenericAttribute)attributes.elementAt(i)).name +
852                " " );
853         out.println();
854     }
855     if (sourceFile != null)
856         out.println("SourceFile: " + sourceFile);
857     for (int i = 0; i < innerClasses.size(); i++)
858         out.println("InnerClass: " +
859             ((InnerClassInfo)
860              innerClasses.elementAt(i)).recString());
861
862     out.println();
863
864     if (v > 0)
865         out.println();
866     }
867     public void printFields(LineWriter out, int v) {
868     if (v == 1)
869         out.println("FIELDS");
870     if (v == 2)
871         out.println("FIELDS " + thisClass );
872     for (int i = 0; i < fields.size(); i++)
873         out.println ( ((FieldInfo)fields.elementAt(i)).recString() );
874     if (v > 0)
875         out.println();
876     }
877     public void printFields(LineWriter out, boolean header) {
878     if (header)
879         out.println("FIELDS");
880     for (int i = 0; i < fields.size(); i++)
881         out.println ( ((FieldInfo)fields.elementAt(i)).recString() );
882     }
883     public void printMethodNames (LineWriter out) {
884     for (int i = 0; i < methods.size(); i++)
885         out.println(methodAt(i).name + " " +
886             methodAt(i).descriptor);
887     }
888     public void printMethods(LineWriter out, int v) {
889     if (v == 1)
890         out.println("METHODS");
891     if (v == 2)
892         out.println("METHODS " + thisClass);
893     for (int i = 0; i < methods.size(); i++) {
894         ((MethodInfo)methods.elementAt(i)).printout(out, false);
895         out.println();
896     }
897     if (v > 0)
898         out.println();
899     }
900     public void printcp(LineWriter out, int v) {
901     if (v == 1)
902         out.println("CONSTANT POOL");
903     if (v == 2)
904         out.println("CONSTANT POOL " + thisClass);
905     constantPool.printout(out);
906     if (v > 0)
907         out.println();
908     }
909     public void printAll(LineWriter out) {
910     printout(out, 1);
911     printFields(out, 1);
912     printMethods(out, 1);
913     }
914
915     static public final int ACC_PUBLIC = Util.ACC_PUBLIC;
916     static public final int ACC_FINAL = Util.ACC_FINAL;
917     static public final int ACC_SUPER = Util.ACC_SUPER;
918     static public final int ACC_INTERFACE = Util.ACC_INTERFACE;
919     static public final int ACC_ABSTRACT = Util.ACC_ABSTRACT;
920
921     //these only appear in InnerClassInfo
922
static private final int ACC_PRIVATE = Util.ACC_PRIVATE;
923     static private final int ACC_PROTECTED = Util.ACC_PROTECTED;
924     static private final int ACC_STATIC = Util.ACC_STATIC;
925     static private final int ACC_ALL_CFLAGS = ACC_PUBLIC |ACC_FINAL |
926     ACC_SUPER | ACC_INTERFACE | ACC_ABSTRACT;
927
928     static public final int ACC_ALL_INNER_CFLAGS = ACC_PUBLIC |
929     ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT | ACC_PRIVATE
930     | ACC_PROTECTED | ACC_STATIC;
931      
932
933     public boolean isInterface () {
934     return (accessFlags & ACC_INTERFACE) != 0;
935     }
936
937     public boolean isFinal () {
938     return (accessFlags & ACC_FINAL) != 0;
939     }
940
941
942     /**
943      * Return a vector of class names that are the ancestors of the
944      * indicated class.
945      *
946      * @param cname class whose ancestors are returned
947      */

948     static private Vector lineage (String JavaDoc cname) throws ClassFileException {
949     ClassInfo cr = Jbet.loader.getClass(cname);
950     Vector ret = (cr.superClass == null) ?
951         new Vector() : lineage(cr.superClass);
952     ret.addElement(cname);
953     return ret;
954     }
955
956     /**
957      * Return a vector of class names that are the ancestors of the
958      * indicated class (including interfaces).
959      */

960
961     private static class InhInfo
962     {
963     String JavaDoc cname;
964     int depth;
965
966     InhInfo (String JavaDoc cn, int i) { cname = cn; depth = i; }
967
968     public boolean equals (Object JavaDoc o) {
969         if (!(o instanceof InhInfo))
970         return false;
971         InhInfo oo = (InhInfo) o;
972         return oo.cname.equals (cname);
973     }
974
975     public int hashCode () {
976         return cname.hashCode();
977     }
978
979     public String JavaDoc toString () {
980         return cname;
981     }
982     };
983
984     static private Vector lineage2 (String JavaDoc cname) throws ClassFileException {
985     ClassInfo cr = Jbet.loader.getClass(cname);
986
987     Vector out = new Vector();
988
989     if (cr.superClass == null) {
990         out.addElement (cname);
991         return out;
992     }
993
994     for (int i = 0; i < cr.numInterfaces(); i++)
995         out.addAll (lineage2 (cr.interfaceAt (i)));
996
997     out.addAll (lineage2 (cr.superClass));
998
999     out.addElement(cname);
1000    return out;
1001    }
1002
1003    /**
1004     * This should really be in Util.
1005     *
1006     * Used by Type. returns true if child inherits from parent?
1007     * Supports interfaces.
1008     *
1009     * @param child
1010     * @param parent
1011     */

1012    public static boolean isAncestor (String JavaDoc child, String JavaDoc parent) throws ClassFileException {
1013    if (child.equals(parent))
1014        return true;
1015    ClassInfo cr = Jbet.loader.getClass(child);
1016
1017    for (int i = 0; i < cr.interfaces.size(); i++)
1018        if ( isAncestor(cr.interfaceAt(i), parent) )
1019        return true;
1020    if (cr.superClass == null)
1021        return false;
1022    if (cr.superClass.equals(parent))
1023        return true;
1024    return isAncestor(cr.superClass, parent);
1025    }
1026
1027    /**
1028     * this should be in Util as well
1029     *
1030     * Used by Type. Return the nearest (in the inheritance tree)
1031     * common ancestor of two classes. Note that all classes have,
1032     * java/lang/Object as their common ancestor, but they may share a
1033     * closer common ancestor.
1034     *
1035     * When interfaces are involved, there may be more than one closest common
1036     * ancestor. In that case, this function returns one of them. allCommonAncestors
1037     * will return all the closest common ancestors.
1038     */

1039    public static String JavaDoc common_ancestor(String JavaDoc classA, String JavaDoc classB) throws ClassFileException {
1040
1041    /*
1042    Vector al = lineage(classA);
1043    Vector bl = lineage(classB);
1044    if (!al.elementAt(0).equals(bl.elementAt(0)))
1045        throw new ClassFileException ("java/lang/Object not unique");
1046    int i;
1047    for (i = 1;; i++) {
1048        if (i == al.size() || i == bl.size()) break;
1049        if (!al.elementAt(i).equals(bl.elementAt(i))) break;
1050    }
1051    return (String) al.elementAt(i-1);
1052    */

1053
1054    Vector al = lineage2(classA);
1055    Vector bl = lineage2(classB);
1056
1057    String JavaDoc ca = "java/lang/Object";
1058
1059    loop: for (int i = al.size() - 1; i >= 0; i--)
1060        for (int j = bl.size() - 1; j >= 0; j--)
1061        if (al.elementAt (i).equals (bl.elementAt (j))) {
1062            ca = al.elementAt (i).toString();
1063            break loop;
1064        }
1065
1066    if (!isAncestor (classA, ca))
1067        throw new IllegalStateException JavaDoc ("common_ancestor failed! " + ca + " is not an ancestor of " + classA);
1068    if (!isAncestor (classB, ca))
1069        throw new IllegalStateException JavaDoc ("common_ancestor failed! " + ca + " is not an ancestor of " + classB);
1070    Jbet.output.println ("CA " + classA + " and " + classB + " is " + ca);
1071    return ca;
1072    }
1073
1074    /* Return true if all the class names in PARENTS are ancestors of CHILD. */
1075
1076    public static boolean hasAncestors (String JavaDoc child, Vector parents) throws ClassFileException {
1077    for (Iterator i = parents.iterator(); i.hasNext(); ) {
1078        if (!isAncestor (child, i.next().toString()))
1079        return false;
1080    }
1081    return true;
1082    }
1083
1084    private static boolean checkDerived (Vector ca, String JavaDoc newclass) throws ClassFileException
1085    {
1086    for (Iterator i = ca.iterator(); i.hasNext(); ) {
1087        String JavaDoc cname = i.next().toString();
1088
1089        if (isAncestor (cname, newclass))
1090        return false;
1091    }
1092    return true;
1093    }
1094
1095    /* Return all closest common ancestors of CLASSA and CLASSB. If there is only one, returns an ordinary class name
1096       (same as common_ancestor). Otherwise, returns a name of the form "-/$class1$class2...", where class1 and
1097       class2 are closest common ancestors. (One of those will be a non-interface, the others will be interfaces.)
1098       A ClassInfo for this combination is created with that name and superclass/interface references, and made
1099       available in Jbet.loader.
1100
1101       Since a ClassInfo is created for the list of common ancestors, it can be merged with other types exactly as
1102       if it was a real class.
1103    */

1104
1105    public static String JavaDoc allCommonAncestors (String JavaDoc classA, String JavaDoc classB) throws ClassFileException
1106    {
1107    Vector al = lineage2(classA);
1108    Vector bl = lineage2(classB);
1109
1110    Vector ca = new Vector();
1111
1112    for (int i = al.size() - 1; i >= 0; i--)
1113        for (int j = bl.size() - 1; j >= 0; j--)
1114        if (al.elementAt (i).equals (bl.elementAt (j)) && checkDerived (ca, al.elementAt (i).toString()))
1115            ca.addElement (al.elementAt (i).toString());
1116
1117    if (ca.size() == 0)
1118        ca.addElement ("java/lang/Object");
1119
1120    if (!hasAncestors (classA, ca))
1121        throw new IllegalStateException JavaDoc ("common_ancestor failed! " + ca + " is not an ancestor of " + classA);
1122    if (!hasAncestors (classB, ca))
1123        throw new IllegalStateException JavaDoc ("common_ancestor failed! " + ca + " is not an ancestor of " + classB);
1124
1125    String JavaDoc caname;
1126    if (ca.size() == 1)
1127        caname = ca.elementAt (0).toString();
1128    else {
1129        StringBuffer JavaDoc canb = new StringBuffer JavaDoc ("-/");
1130        for (Iterator i = ca.iterator(); i.hasNext(); ) {
1131        canb.append ("$");
1132        canb.append (i.next().toString());
1133        }
1134        caname = canb.toString();
1135
1136        ClassInfo cacr = new ClassInfo (null, caname);
1137        cacr.superClass = null;
1138
1139        for (Iterator i = ca.iterator(); i.hasNext(); ) {
1140        ClassInfo cr = Jbet.loader.getClass (i.next().toString());
1141        if (cr.isInterface())
1142            cacr.interfaces.addElement (cr.name());
1143        else if (cacr.superClass != null)
1144            throw new IllegalStateException JavaDoc ("can't have two common non-interface superclasses ("
1145                             + cacr.superClass + " and " + cr.name() +")");
1146        else
1147            cacr.superClass = cr.name();
1148        }
1149
1150        cacr.dirty = false; // prevent fake class from being written
1151
Jbet.loader.putClass (cacr);
1152    }
1153
1154    return caname;
1155    }
1156
1157    public boolean isDirty() {
1158    return dirty;
1159    }
1160
1161    public void setDirty () {
1162    dirty = true;
1163    }
1164
1165    public boolean inPackage(String JavaDoc packname) {
1166    return name().startsWith(packname + "/");
1167    }
1168
1169    public String JavaDoc getPackageName () {
1170    int li = name().lastIndexOf ('/');
1171    if (li == -1)
1172        return "";
1173    return name().substring (0, li);
1174    }
1175
1176    public boolean checkAccess (String JavaDoc fromPackage) {
1177    if ((accessFlags & ACC_PUBLIC) != 0)
1178        return true;
1179    if ((accessFlags & ACC_PRIVATE) != 0)
1180        return false;
1181    if ((accessFlags & ACC_PROTECTED) != 0)
1182        return false;
1183    return fromPackage.equals (getPackageName());
1184    }
1185}
1186
Popular Tags