KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > coffi > ClassFile


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 1997 Clark Verbrugge
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */

19
20 /*
21  * Modified by the Sable Research Group and others 1997-1999.
22  * See the 'credits' file distributed with Soot for the complete list of
23  * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
24  */

25
26
27
28
29
30
31
32 package soot.coffi;
33 import soot.*;
34
35 import java.io.*;
36 import java.util.*;
37 import java.util.Enumeration JavaDoc;
38 import java.util.Vector JavaDoc;
39 import java.util.*;
40 import soot.*;
41
42 /**
43  * A ClassFile object represents the contents of a <tt>.class</tt> file.
44  * <p>
45  * A ClassFile contains code for manipulation of its constituents.
46  * @author Clark Verbrugge
47  */

48 public class ClassFile {
49
50    /** Magic number. */
51     static final long MAGIC = 0xCAFEBABEL;
52
53    /** Access bit flag. */
54     static final short ACC_PUBLIC = 0x0001;
55    /** Access bit flag. */
56     static final short ACC_PRIVATE = 0x0002;
57    /** Access bit flag. */
58     static final short ACC_PROTECTED = 0x0004;
59    /** Access bit flag. */
60     static final short ACC_STATIC = 0x0008;
61    /** Access bit flag. */
62     static final short ACC_FINAL = 0x0010;
63    /** Access bit flag. */
64     static final short ACC_SUPER = 0x0020;
65    /** Access bit flag. */
66     static final short ACC_VOLATILE = 0x0040;
67    /** Access bit flag. */
68     static final short ACC_TRANSIENT = 0x0080;
69    /** Access bit flag. */
70     static final short ACC_INTERFACE = 0x0200;
71    /** Access bit flag. */
72     static final short ACC_ABSTRACT = 0x0400;
73    /** Access bit flag. */
74     static final short ACC_STRICT = 0x0800;
75    /** Access bit flag. */
76     static final short ACC_ANNOTATION = 0x2000;
77    /** Access bit flag. */
78     static final short ACC_ENUM = 0x4000;
79    /** Remaining bits in the access bit flag. */
80     static final short ACC_UNKNOWN = 0x7000;
81
82    /** Descriptor code string. */
83     static final String JavaDoc DESC_BYTE = "B";
84    /** Descriptor code string. */
85     static final String JavaDoc DESC_CHAR = "C";
86    /** Descriptor code string. */
87     static final String JavaDoc DESC_DOUBLE = "D";
88    /** Descriptor code string. */
89     static final String JavaDoc DESC_FLOAT= "F";
90    /** Descriptor code string. */
91     static final String JavaDoc DESC_INT = "I";
92    /** Descriptor code string. */
93     static final String JavaDoc DESC_LONG = "J";
94    /** Descriptor code string. */
95     static final String JavaDoc DESC_OBJECT = "L";
96    /** Descriptor code string. */
97     static final String JavaDoc DESC_SHORT = "S";
98    /** Descriptor code string. */
99     static final String JavaDoc DESC_BOOLEAN = "Z";
100    /** Descriptor code string. */
101     static final String JavaDoc DESC_VOID = "V";
102    /** Descriptor code string. */
103     static final String JavaDoc DESC_ARRAY = "[";
104
105    /** Debugging flag. */
106     boolean debug;
107
108    /** File name of the <tt>.class</tt> this represents. */
109     String JavaDoc fn;
110
111    /* For chaining ClassFiles into a list.
112       ClassFile next;*/

113
114    /** Magic number read in.
115     * @see ClassFile#MAGIC
116     */

117     long magic;
118    /** Minor version. */
119     int minor_version;
120    /** Major version. */
121     int major_version;
122    /** Number of items in the constant pool. */
123     public int constant_pool_count;
124    /** Array of constant pool items.
125     * @see cp_info
126     */

127     public cp_info constant_pool[];
128    /** Access flags for this Class.
129     */

130     public int access_flags;
131    /** Constant pool index of the Class constant describing <i>this</i>.
132     * @see CONSTANT_Class_info
133     */

134     public int this_class;
135    /** Constant pool index of the Class constant describing <i>super</i>.
136     * @see CONSTANT_Class_info
137     */

138     public int super_class;
139    /** Count of interfaces implemented. */
140     public int interfaces_count;
141    /** Array of constant pool indices of Class constants describing each
142     * interace implemented by this class, as given in the source for this
143     * class.
144     * @see CONSTANT_Class_info
145     */

146     public int interfaces[];
147    /** Count of fields this Class contains. */
148     public int fields_count;
149    /** Array of field_info objects describing each field.
150     * @see field_info
151     */

152     public field_info fields[];
153    /** Count of methods this Class contains. */
154     public int methods_count;
155    /** Array of method_info objects describing each field.
156     * @see method_info
157     */

158     public method_info methods[];
159    /** Count of attributes this class contains. */
160     public int attributes_count;
161    /** Array of attribute_info objects for this class.
162     * @see attribute_info
163     */

164     attribute_info attributes[];
165
166    /** Creates a new ClassFile object given the name of the file.
167     * @param nfn file name which this ClassFile will represent.
168     */

169     public ClassFile(String JavaDoc nfn) { fn = nfn; }
170
171     /** Returns the name of this Class. */
172     public String JavaDoc toString() {
173     return (constant_pool[this_class].toString(constant_pool));
174     }
175
176     public boolean loadClassFile(InputStream is)
177     {
178       InputStream f = null;
179       InputStream classFileStream;
180       DataInputStream d;
181       boolean b;
182
183       classFileStream = is;
184      
185       byte[] data;
186       
187       
188       Timers.v().readTimer.start();
189       
190       try
191       {
192         data = new byte[classFileStream.available()];
193         classFileStream.read(data);
194         f = new ByteArrayInputStream(data);
195          
196       } catch(IOException e)
197       {
198       }
199       
200       Timers.v().readTimer.end();
201       
202       d = new DataInputStream(f);
203       b = readClass(d);
204       
205       try {
206         classFileStream.close();
207         d.close();
208         f.close();
209       } catch(IOException e) {
210          G.v().out.println("IOException with " + fn + ": " + e.getMessage());
211          return false;
212       }
213       
214       if (!b) return false;
215       //parse(); // parse all methods & builds CFGs
216
//G.v().out.println("-- Read " + cf + " --");
217
return true;
218    }
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237    /** Main entry point for writing a class file.
238     * The file name is given in the constructor; this opens the
239     * file and writes the internal representation.
240     * @return <i>true</i> on success.
241     */

242     boolean saveClassFile() {
243       FileOutputStream f;
244       DataOutputStream d;
245       boolean b;
246       try {
247          f = new FileOutputStream(fn);
248       } catch(FileNotFoundException e) {
249          if (fn.indexOf(".class")>=0) {
250             G.v().out.println("Can't find " + fn);
251             return false;
252          }
253          fn = fn + ".class";
254          try {
255             f = new FileOutputStream(fn);
256          } catch(FileNotFoundException ee) {
257             G.v().out.println("Can't find " + fn);
258             return false;
259          } catch(IOException ee) {
260             G.v().out.println("IOException with " + fn + ": " + ee.getMessage());
261             return false;
262          }
263       } catch(IOException e) {
264          G.v().out.println("IOException with " + fn + ": " + e.getMessage());
265          return false;
266       }
267       d = new DataOutputStream(f);
268       if (d==null) {
269          try {
270             f.close();
271          } catch(IOException e) { }
272          return false;
273       }
274       b = writeClass(d);
275       try {
276          d.close();
277          f.close();
278       } catch(IOException e) {
279          G.v().out.println("IOException with " + fn + ": " + e.getMessage());
280          return false;
281       }
282       return b;
283    }
284
285    /** Returns a String constructed by parsing the bits in the given
286     * access code (as defined by the ACC_* constants).
287     * @param af access code.
288     * @param separator String used to separate words used for access bits.
289     * @see ClassFile#access_flags
290     * @see method_info#access_flags
291     * @see field_info#access_flags
292     */

293     static String JavaDoc access_string(int af,String JavaDoc separator) {
294       boolean hasone = false;
295       String JavaDoc s = "";
296       if ((af & ACC_PUBLIC) != 0) {
297          s = "public";
298          hasone = true;
299       }
300       if ((af & ACC_PRIVATE) != 0) {
301          if (hasone) s = s + separator;
302          else hasone = true;
303          s = s + "private";
304       }
305       if ((af & ACC_PROTECTED) != 0) {
306          if (hasone) s = s + separator;
307          else hasone = true;
308          s = s + "protected";
309       }
310       if ((af & ACC_STATIC) != 0) {
311          if (hasone) s = s + separator;
312          else hasone = true;
313          s = s + "static";
314       }
315       if ((af & ACC_FINAL) != 0) {
316          if (hasone) s = s + separator;
317          else hasone = true;
318          s = s + "final";
319       }
320       if ((af & ACC_SUPER) != 0) {
321          if (hasone) s = s + separator;
322          else hasone = true;
323          s = s + "super";
324       }
325       if ((af & ACC_VOLATILE) != 0) {
326          if (hasone) s = s + separator;
327          else hasone = true;
328          s = s + "volatile";
329       }
330       if ((af & ACC_TRANSIENT) != 0) {
331          if (hasone) s = s + separator;
332          else hasone = true;
333          s = s + "transient";
334       }
335       if ((af & ACC_INTERFACE) != 0) {
336          if (hasone) s = s + separator;
337          else hasone = true;
338          s = s + "interface";
339       }
340       if ((af & ACC_ABSTRACT) != 0) {
341          if (hasone) s = s + separator;
342          else hasone = true;
343          s = s + "abstract";
344       }
345       if ((af & ACC_STRICT) != 0) {
346          if (hasone) s = s + separator;
347          else hasone = true;
348          s = s + "strict";
349       }
350       if ((af & ACC_ANNOTATION) != 0) {
351          if (hasone) s = s + separator;
352          else hasone = true;
353          s = s + "annotation";
354       }
355       if ((af & ACC_ENUM) != 0) {
356          if (hasone) s = s + separator;
357          else hasone = true;
358          s = s + "enum";
359       }
360       if ((af & ACC_UNKNOWN) != 0) {
361          if (hasone) s = s + separator;
362          else hasone = true;
363          s = s + "unknown";
364       }
365       return s;
366    }
367
368    /** Builds the internal representation of this Class by reading in the
369     * given class file.
370     * @param d Stream forming the <tt>.class</tt> file.
371     * @return <i>true</i> if read was successful, <i>false</i> on some error.
372     */

373    public boolean readClass(DataInputStream d) {
374       try {
375          // first read in magic number
376
magic = d.readInt() & 0xFFFFFFFFL;
377          if (magic != MAGIC) {
378             G.v().out.println("Wrong magic number in " + fn + ": " + magic);
379             return false;
380          }
381          //G.v().out.println("Magic number ok");
382
minor_version = d.readUnsignedShort();
383          major_version = d.readUnsignedShort();
384         // G.v().out.println("Version: " + major_version + "." + minor_version);
385
constant_pool_count = d.readUnsignedShort();
386          //G.v().out.println("Constant pool count: " + constant_pool_count);
387

388          if (!readConstantPool(d))
389             return false;
390
391          access_flags = d.readUnsignedShort();
392          /*if (access_flags!=0)
393              G.v().out.println("Access flags: " + access_flags + " = " +
394                             access_string(access_flags,", "));*/

395
396          this_class = d.readUnsignedShort();
397          super_class = d.readUnsignedShort();
398          interfaces_count = d.readUnsignedShort();
399          if (interfaces_count>0) {
400             interfaces = new int[interfaces_count];
401             int j;
402             for (j=0; j<interfaces_count; j++)
403                interfaces[j] = d.readUnsignedShort();
404          }
405          //G.v().out.println("Implements " + interfaces_count + " interface(s)");
406

407          Timers.v().fieldTimer.start();
408          
409          fields_count = d.readUnsignedShort();
410          //G.v().out.println("Has " + fields_count + " field(s)");
411
readFields(d);
412          Timers.v().fieldTimer.end();
413         
414          Timers.v().methodTimer.start();
415          methods_count = d.readUnsignedShort();
416          //G.v().out.println("Has " + methods_count + " method(s)");
417
readMethods(d);
418          Timers.v().methodTimer.end();
419         
420          Timers.v().attributeTimer.start();
421          
422          attributes_count = d.readUnsignedShort();
423          //G.v().out.println("Has " + attributes_count + " attribute(s)");
424
if (attributes_count>0) {
425             attributes = new attribute_info[attributes_count];
426             readAttributes(d,attributes_count,attributes);
427          }
428          Timers.v().attributeTimer.end();
429          
430       } catch(IOException e) {
431          throw new RuntimeException JavaDoc("IOException with " + fn + ": " + e.getMessage());
432       }
433
434       /*inf.fields = fields_count;
435         inf.methods = methods_count;
436         inf.cp = constant_pool_count;*/

437
438       return true;
439    }
440
441    /** Reads in the constant pool from the given stream.
442     * @param d Stream forming the <tt>.class</tt> file.
443     * @return <i>true</i> if read was successful, <i>false</i> on some error.
444     * @exception java.io.IOException on error.
445     */

446    protected boolean readConstantPool(DataInputStream d) throws IOException {
447       byte tag;
448       cp_info cp;
449       int i;
450       boolean skipone; // set if next cp entry is to be skipped
451

452       constant_pool = new cp_info[constant_pool_count];
453       //Instruction.constant_pool = constant_pool;
454
skipone = false;
455
456       for (i=1;i<constant_pool_count;i++) {
457          if (skipone) {
458             skipone = false;
459             continue;
460          }
461          tag = (byte)d.readUnsignedByte();
462          switch(tag) {
463          case cp_info.CONSTANT_Class:
464             cp = new CONSTANT_Class_info();
465             ((CONSTANT_Class_info)cp).name_index = d.readUnsignedShort();
466             if (debug) G.v().out.println("Constant pool[" + i + "]: Class");
467             break;
468          case cp_info.CONSTANT_Fieldref:
469             cp = new CONSTANT_Fieldref_info();
470             ((CONSTANT_Fieldref_info)cp).class_index = d.readUnsignedShort();
471             ((CONSTANT_Fieldref_info)cp).name_and_type_index =
472                 d.readUnsignedShort();
473             if (debug) G.v().out.println("Constant pool[" + i + "]: Fieldref");
474             break;
475          case cp_info.CONSTANT_Methodref:
476             cp = new CONSTANT_Methodref_info();
477             ((CONSTANT_Methodref_info)cp).class_index = d.readUnsignedShort();
478             ((CONSTANT_Methodref_info)cp).name_and_type_index =
479                d.readUnsignedShort();
480             if (debug) G.v().out.println("Constant pool[" + i + "]: Methodref");
481             break;
482          case cp_info.CONSTANT_InterfaceMethodref:
483             cp = new CONSTANT_InterfaceMethodref_info();
484             ((CONSTANT_InterfaceMethodref_info)cp).class_index =
485                d.readUnsignedShort();
486             ((CONSTANT_InterfaceMethodref_info)cp).name_and_type_index =
487                d.readUnsignedShort();
488             if (debug)
489                G.v().out.println("Constant pool[" + i + "]: InterfaceMethodref");
490             break;
491          case cp_info.CONSTANT_String:
492             cp = new CONSTANT_String_info();
493             ((CONSTANT_String_info)cp).string_index =
494                 d.readUnsignedShort();
495             if (debug) G.v().out.println("Constant pool[" + i + "]: String");
496             break;
497          case cp_info.CONSTANT_Integer:
498             cp = new CONSTANT_Integer_info();
499             ((CONSTANT_Integer_info)cp).bytes = d.readInt();
500             if (debug) G.v().out.println("Constant pool[" + i + "]: Integer = " +
501                                           ((CONSTANT_Integer_info)cp).bytes);
502             break;
503          case cp_info.CONSTANT_Float:
504             cp = new CONSTANT_Float_info();
505             ((CONSTANT_Float_info)cp).bytes = d.readInt();
506             if (debug) G.v().out.println("Constant pool[" + i + "]: Float = " +
507                                           ((CONSTANT_Float_info)cp).convert());
508             break;
509          case cp_info.CONSTANT_Long:
510             cp = new CONSTANT_Long_info();
511             ((CONSTANT_Long_info)cp).high = d.readInt() & 0xFFFFFFFFL;
512             ((CONSTANT_Long_info)cp).low = d.readInt() & 0xFFFFFFFFL;
513             
514             if (debug) {
515                String JavaDoc temp = cp.toString(constant_pool);
516                G.v().out.println("Constant pool[" + i + "]: Long = " + temp);
517                /*G.v().out.println("Constant pool[" + i + "]: that's " +
518                  cp.printBits(((CONSTANT_Long_info)cp).high) + " <<32 + " +
519                  cp.printBits(((CONSTANT_Long_info)cp).low) + " = " +
520                  cp.printBits(((CONSTANT_Long_info)cp).convert()));*/

521             }
522             skipone = true; // next entry needs to be skipped
523
break;
524          case cp_info.CONSTANT_Double:
525             cp = new CONSTANT_Double_info();
526             ((CONSTANT_Double_info)cp).high = d.readInt() & 0xFFFFFFFFL;
527             ((CONSTANT_Double_info)cp).low = d.readInt() & 0xFFFFFFFFL;
528             if (debug) G.v().out.println("Constant pool[" + i + "]: Double = " +
529                                           ((CONSTANT_Double_info)cp).convert());
530             skipone = true; // next entry needs to be skipped
531
break;
532          case cp_info.CONSTANT_NameAndType:
533             cp = new CONSTANT_NameAndType_info();
534             ((CONSTANT_NameAndType_info)cp).name_index =
535                d.readUnsignedShort();
536             ((CONSTANT_NameAndType_info)cp).descriptor_index =
537                d.readUnsignedShort();
538             if (debug) G.v().out.println("Constant pool[" + i + "]: Name and Type");
539             break;
540          case cp_info.CONSTANT_Utf8:
541             CONSTANT_Utf8_info cputf8 = new CONSTANT_Utf8_info(d);
542             // If an equivalent CONSTANT_Utf8 already exists, we return
543
// the pre-existing one and allow cputf8 to be GC'd.
544
cp = (cp_info) CONSTANT_Utf8_collector.v().add(cputf8);
545             if (debug)
546                G.v().out.println("Constant pool[" + i + "]: Utf8 = \"" +
547                                   cputf8.convert() + "\"");
548             break;
549          default:
550             G.v().out.println("Unknown tag in constant pool: " +
551                                tag + " at entry " + i);
552             return false;
553          }
554          cp.tag = tag;
555          constant_pool[i] = cp;
556       }
557       return true;
558    }
559
560    /** Reads in the given number of attributes from the given stream.
561     * @param d Stream forming the <tt>.class</tt> file.
562     * @param attributes_count number of attributes to read in.
563     * @param ai pre-allocated array of attributes to be filled in.
564     * @return <i>true</i> if read was successful, <i>false</i> on some error.
565     * @exception java.io.IOException on error.
566     */

567    protected boolean readAttributes(DataInputStream d,int attributes_count,
568                                     attribute_info[] ai) throws IOException {
569       attribute_info a=null;
570       int i;
571       int j;
572       long len;
573       String JavaDoc s;
574
575       for (i=0;i<attributes_count;i++) {
576          
577          j = d.readUnsignedShort(); // read attribute name before allocating
578
len = d.readInt() & 0xFFFFFFFFL;
579          s = ((CONSTANT_Utf8_info)(constant_pool[j])).convert();
580          if (s.compareTo(attribute_info.SourceFile)==0)
581          {
582             SourceFile_attribute sa = new SourceFile_attribute();
583             sa.sourcefile_index = d.readUnsignedShort();
584             a = (attribute_info)sa;
585          } else if(s.compareTo(attribute_info.ConstantValue)==0)
586          {
587             ConstantValue_attribute ca = new ConstantValue_attribute();
588             ca.constantvalue_index = d.readUnsignedShort();
589             a = (attribute_info)ca;
590          } else if(s.compareTo(attribute_info.Code)==0)
591          {
592             Code_attribute ca = new Code_attribute();
593             ca.max_stack = d.readUnsignedShort();
594             ca.max_locals = d.readUnsignedShort();
595             ca.code_length = d.readInt() & 0xFFFFFFFFL;
596             ca.code = new byte[(int) ca.code_length];
597             d.read(ca.code);
598             ca.exception_table_length = d.readUnsignedShort();
599             ca.exception_table = new exception_table_entry[ca.exception_table_length];
600             int k;
601             exception_table_entry e;
602             for (k=0; k<ca.exception_table_length; k++) {
603                e = new exception_table_entry();
604                e.start_pc = d.readUnsignedShort();
605                e.end_pc = d.readUnsignedShort();
606                e.handler_pc = d.readUnsignedShort();
607                e.catch_type = d.readUnsignedShort();
608                ca.exception_table[k] = e;
609             }
610             ca.attributes_count = d.readUnsignedShort();
611             ca.attributes = new attribute_info[ca.attributes_count];
612             readAttributes(d,ca.attributes_count,ca.attributes);
613             a = (attribute_info)ca;
614             
615             
616          } else if(s.compareTo(attribute_info.Exceptions)==0)
617          {
618             Exception_attribute ea = new Exception_attribute();
619             ea.number_of_exceptions = d.readUnsignedShort();
620             if (ea.number_of_exceptions>0) {
621                int k;
622                ea.exception_index_table = new int[ea.number_of_exceptions];
623                for (k=0; k<ea.number_of_exceptions; k++)
624                   ea.exception_index_table[k] = d.readUnsignedShort();
625             }
626             a = (attribute_info)ea;
627          } else if(s.compareTo(attribute_info.LineNumberTable)==0)
628          {
629          LineNumberTable_attribute la = new LineNumberTable_attribute();
630          la.line_number_table_length = d.readUnsignedShort();
631          int k;
632          line_number_table_entry e;
633          la.line_number_table = new
634          line_number_table_entry[la.line_number_table_length];
635          for (k=0; k<la.line_number_table_length; k++) {
636          e = new line_number_table_entry();
637          e.start_pc = d.readUnsignedShort();
638          e.line_number = d.readUnsignedShort();
639          la.line_number_table[k] = e;
640          }
641          a = (attribute_info)la;
642          }
643          else if(s.compareTo(attribute_info.LocalVariableTable)==0)
644          {
645             LocalVariableTable_attribute la = new LocalVariableTable_attribute();
646             la.local_variable_table_length = d.readUnsignedShort();
647             int k;
648             local_variable_table_entry e;
649             la.local_variable_table =
650                new local_variable_table_entry[la.local_variable_table_length];
651             for (k=0; k<la.local_variable_table_length; k++) {
652                e = new local_variable_table_entry();
653                e.start_pc = d.readUnsignedShort();
654                e.length = d.readUnsignedShort();
655                e.name_index = d.readUnsignedShort();
656                e.descriptor_index = d.readUnsignedShort();
657                e.index = d.readUnsignedShort();
658                la.local_variable_table[k] = e;
659             }
660             a = (attribute_info)la;
661      }
662          else if(s.compareTo(attribute_info.LocalVariableTypeTable)==0)
663          {
664             LocalVariableTypeTable_attribute la = new LocalVariableTypeTable_attribute();
665             la.local_variable_type_table_length = d.readUnsignedShort();
666             int k;
667             local_variable_type_table_entry e;
668             la.local_variable_type_table =
669                new local_variable_type_table_entry[la.local_variable_type_table_length];
670             for (k=0; k<la.local_variable_type_table_length; k++) {
671                e = new local_variable_type_table_entry();
672                e.start_pc = d.readUnsignedShort();
673                e.length = d.readUnsignedShort();
674                e.name_index = d.readUnsignedShort();
675                e.signature_index = d.readUnsignedShort();
676                e.index = d.readUnsignedShort();
677                la.local_variable_type_table[k] = e;
678             }
679             a = (attribute_info)la;
680      }
681      else if (s.compareTo(attribute_info.Synthetic)==0){
682         Synthetic_attribute ia = new Synthetic_attribute();
683         a = (attribute_info)ia;
684      }
685      else if (s.compareTo(attribute_info.Signature)==0){
686         Signature_attribute ia = new Signature_attribute();
687         ia.signature_index = d.readUnsignedShort();
688         a = (attribute_info)ia;
689      }
690      else if (s.compareTo(attribute_info.Deprecated)==0){
691         Deprecated_attribute da = new Deprecated_attribute();
692         a = (attribute_info)da;
693      }
694      else if (s.compareTo(attribute_info.EnclosingMethod)==0){
695         EnclosingMethod_attribute ea = new EnclosingMethod_attribute();
696         ea.class_index = d.readUnsignedShort();
697         ea.method_index = d.readUnsignedShort();
698         a = (attribute_info)ea;
699      }
700          else if(s.compareTo(attribute_info.InnerClasses)==0)
701      {
702         InnerClasses_attribute ia = new InnerClasses_attribute();
703         ia.inner_classes_length = d.readUnsignedShort();
704         ia.inner_classes = new inner_class_entry[ia.inner_classes_length];
705         for (int k = 0; k < ia.inner_classes_length; k++) {
706            inner_class_entry e = new inner_class_entry();
707            e.inner_class_index = d.readUnsignedShort();
708            e.outer_class_index = d.readUnsignedShort();
709            e.name_index = d.readUnsignedShort();
710            e.access_flags = d.readUnsignedShort();
711            ia.inner_classes[k] = e;
712         }
713         a = (attribute_info)ia;
714         }
715         else if (s.compareTo(attribute_info.RuntimeVisibleAnnotations)==0)
716         {
717             RuntimeVisibleAnnotations_attribute ra = new RuntimeVisibleAnnotations_attribute();
718             ra.number_of_annotations = d.readUnsignedShort();
719             ra.annotations = new annotation[ra.number_of_annotations];
720             for (int k = 0; k < ra.number_of_annotations; k++){
721                 annotation annot = new annotation();
722                 annot.type_index = d.readUnsignedShort();
723                 annot.num_element_value_pairs = d.readUnsignedShort();
724                 annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0);
725                 ra.annotations[k] = annot;
726             }
727         
728             a = (attribute_info)ra;
729          }
730         else if (s.compareTo(attribute_info.RuntimeInvisibleAnnotations)==0)
731         {
732             RuntimeInvisibleAnnotations_attribute ra = new RuntimeInvisibleAnnotations_attribute();
733             ra.number_of_annotations = d.readUnsignedShort();
734             ra.annotations = new annotation[ra.number_of_annotations];
735             for (int k = 0; k < ra.number_of_annotations; k++){
736                 annotation annot = new annotation();
737                 annot.type_index = d.readUnsignedShort();
738                 annot.num_element_value_pairs = d.readUnsignedShort();
739                 annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0);
740                 ra.annotations[k] = annot;
741             }
742             a = (attribute_info)ra;
743          }
744         else if (s.compareTo(attribute_info.RuntimeVisibleParameterAnnotations)==0)
745         {
746             RuntimeVisibleParameterAnnotations_attribute ra = new RuntimeVisibleParameterAnnotations_attribute();
747             ra.num_parameters = d.readUnsignedByte();
748             ra.parameter_annotations = new parameter_annotation[ra.num_parameters];
749             for (int x = 0; x < ra.num_parameters; x++){
750                 parameter_annotation pAnnot = new parameter_annotation();
751                 pAnnot.num_annotations = d.readUnsignedShort();
752                 pAnnot.annotations = new annotation[pAnnot.num_annotations];
753                 for (int k = 0; k < pAnnot.num_annotations; k++){
754                     annotation annot = new annotation();
755                     annot.type_index = d.readUnsignedShort();
756                     annot.num_element_value_pairs = d.readUnsignedShort();
757                     annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0);
758                     pAnnot.annotations[k] = annot;
759                 }
760                 ra.parameter_annotations[x] = pAnnot;
761             }
762             a = (attribute_info)ra;
763          }
764         else if (s.compareTo(attribute_info.RuntimeInvisibleParameterAnnotations)==0)
765         {
766             RuntimeInvisibleParameterAnnotations_attribute ra = new RuntimeInvisibleParameterAnnotations_attribute();
767             ra.num_parameters = d.readUnsignedByte();
768             ra.parameter_annotations = new parameter_annotation[ra.num_parameters];
769             for (int x = 0; x < ra.num_parameters; x++){
770                 parameter_annotation pAnnot = new parameter_annotation();
771                 pAnnot.num_annotations = d.readUnsignedShort();
772                 pAnnot.annotations = new annotation[pAnnot.num_annotations];
773                 for (int k = 0; k < pAnnot.num_annotations; k++){
774                     annotation annot = new annotation();
775                     annot.type_index = d.readUnsignedShort();
776                     annot.num_element_value_pairs = d.readUnsignedShort();
777                     annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0);
778                     pAnnot.annotations[k] = annot;
779                 }
780                 ra.parameter_annotations[x] = pAnnot;
781             }
782             a = (attribute_info)ra;
783          }
784          else if (s.compareTo(attribute_info.AnnotationDefault)==0){
785              AnnotationDefault_attribute da = new AnnotationDefault_attribute();
786              element_value [] result = readElementValues(1, d, false, 0);
787              da.default_value = result[0];
788              a = (attribute_info)da;
789          }
790          else {
791             // unknown attribute
792
// G.v().out.println("Generic/Unknown Attribute: " + s);
793
Generic_attribute ga = new Generic_attribute();
794             if (len>0) {
795                ga.info = new byte[(int) len];
796                d.read(ga.info);
797             }
798             a = (attribute_info)ga;
799          }
800          a.attribute_name = j;
801          a.attribute_length = len;
802          ai[i] = a;
803       }
804       return true;
805    }
806
807     private element_value [] readElementValues(int count, DataInputStream d, boolean needName, int name_index)
808         throws IOException {
809         element_value [] list = new element_value[count];
810         for (int x = 0; x < count; x++){
811             if (needName){
812                 name_index = d.readUnsignedShort();
813             }
814             int tag = d.readUnsignedByte();
815             char kind = (char)tag;
816             if (kind == 'B' || kind == 'C' || kind == 'D' || kind == 'F' || kind == 'I' || kind == 'J' || kind == 'S' || kind == 'Z' || kind == 's'){
817                 constant_element_value elem = new constant_element_value();
818                 elem.name_index = name_index;
819                 elem.tag = kind;
820                 elem.constant_value_index = d.readUnsignedShort();
821                 list[x] = elem;
822             }
823             else if (kind == 'e'){
824                 enum_constant_element_value elem = new enum_constant_element_value();
825                 elem.name_index = name_index;
826                 elem.tag = kind;
827                 elem.type_name_index = d.readUnsignedShort();
828                 elem.constant_name_index = d.readUnsignedShort();
829                 list[x] = elem;
830             }
831             else if (kind == 'c'){
832                 class_element_value elem = new class_element_value();
833                 elem.name_index = name_index;
834                 elem.tag = kind;
835                 elem.class_info_index = d.readUnsignedShort();
836                 list[x] = elem;
837             }
838             else if (kind == '['){
839                 array_element_value elem = new array_element_value();
840                 elem.name_index = name_index;
841                 elem.tag = kind;
842                 elem.num_values = d.readUnsignedShort();
843                 elem.values = readElementValues(elem.num_values, d, false, name_index);
844                 list[x] = elem;
845             }
846             else if (kind == '@'){
847                 annotation_element_value elem = new annotation_element_value();
848                 elem.name_index = name_index;
849                 elem.tag = kind;
850                 annotation annot = new annotation();
851                 annot.type_index = d.readUnsignedShort();
852                 annot.num_element_value_pairs = d.readUnsignedShort();
853                 annot.element_value_pairs = readElementValues(annot.num_element_value_pairs, d, true, 0);
854                 elem.annotation_value = annot;
855                 list[x] = elem;
856             }
857             else {
858                 throw new RuntimeException JavaDoc("Unknown element value pair kind: "+kind);
859             }
860         }
861         return list;
862     }
863
864    /** Reads in the fields from the given stream.
865     * @param d Stream forming the <tt>.class</tt> file.
866     * @return <i>true</i> if read was successful, <i>false</i> on some error.
867     * @exception java.io.IOException on error.
868     */

869    protected boolean readFields(DataInputStream d) throws IOException {
870       field_info fi;
871       int i;
872
873       fields = new field_info[fields_count];
874
875       for (i=0;i<fields_count;i++) {
876          fi = new field_info();
877          fi.access_flags = d.readUnsignedShort();
878          fi.name_index = d.readUnsignedShort();
879          fi.descriptor_index = d.readUnsignedShort();
880          fi.attributes_count = d.readUnsignedShort();
881          if (fi.attributes_count>0) {
882             fi.attributes = new attribute_info[fi.attributes_count];
883             readAttributes(d,fi.attributes_count,fi.attributes);
884          }
885          /*CONSTANT_Utf8_info ci;
886            ci = (CONSTANT_Utf8_info)(constant_pool[fi.name_index]);
887            G.v().out.println("Field: " + ci.convert());*/

888          fields[i] = fi;
889       }
890
891       return true;
892    }
893
894    /** Reads in the methods from the given stream.
895     * @param d Stream forming the <tt>.class</tt> file.
896     * @return <i>true</i> if read was successful, <i>false</i> on some error.
897     * @exception java.io.IOException on error.
898     */

899    protected boolean readMethods(DataInputStream d) throws IOException {
900       method_info mi;
901       int i;
902
903       methods = new method_info[methods_count];
904
905       for (i=0;i<methods_count;i++) {
906          mi = new method_info();
907          mi.access_flags = d.readUnsignedShort();
908          
909          mi.name_index = d.readUnsignedShort();
910          
911          mi.descriptor_index = d.readUnsignedShort();
912          
913          mi.attributes_count = d.readUnsignedShort();
914
915          CONSTANT_Utf8_info ci;
916            ci = (CONSTANT_Utf8_info)(constant_pool[mi.name_index]);
917           //G.v().out.println("Has " + mi.attributes_count + " attribute(s)");
918

919          if (mi.attributes_count>0) {
920             mi.attributes = new attribute_info[mi.attributes_count];
921             readAttributes(d,mi.attributes_count,mi.attributes);
922
923         for (int j=0; j<mi.attributes_count; j++)
924         {
925         if (mi.attributes[j] instanceof Code_attribute)
926         {
927             mi.code_attr = (Code_attribute)mi.attributes[j];
928             break;
929         }
930         }
931          }
932
933          /*if ("main".compareTo(ci.convert())==0) {
934            decompile(mi);
935            }*/

936
937          methods[i] = mi;
938       }
939
940       return true;
941    }
942
943    /* DEPRECATED
944       public void showByteCode(Code_attribute ca) {
945       int i=0,j;
946
947       G.v().out.println("Code bytes follow...");
948       while(i<ca.code_length) {
949       j = (int)(ca.code[i]);
950       j &= 0xff;
951       G.v().out.print(Integer.toString(j) + " ");
952       i++;
953       }
954       G.v().out.println("");
955       }*/

956
957    /** Writes the current constant pool to the given stream.
958     * @param dd output stream.
959     * @return <i>true</i> if write was successful, <i>false</i> on some error.
960     * @exception java.io.IOException on error.
961     */

962    protected boolean writeConstantPool(DataOutputStream dd) throws IOException {
963       byte tag;
964       cp_info cp;
965       int i;
966       boolean skipone = false;
967
968       for (i=1;i<constant_pool_count;i++) {
969          if (skipone) {
970             skipone = false;
971             continue;
972          }
973          cp = constant_pool[i];
974          dd.writeByte(cp.tag);
975          switch(cp.tag) {
976          case cp_info.CONSTANT_Class:
977             dd.writeShort(((CONSTANT_Class_info)cp).name_index);
978             break;
979          case cp_info.CONSTANT_Fieldref:
980             dd.writeShort(((CONSTANT_Fieldref_info)cp).class_index);
981             dd.writeShort(((CONSTANT_Fieldref_info)cp).name_and_type_index);
982             break;
983          case cp_info.CONSTANT_Methodref:
984             dd.writeShort(((CONSTANT_Methodref_info)cp).class_index);
985             dd.writeShort(((CONSTANT_Methodref_info)cp).name_and_type_index);
986             break;
987          case cp_info.CONSTANT_InterfaceMethodref:
988             dd.writeShort(((CONSTANT_InterfaceMethodref_info)cp).class_index);
989             dd.writeShort(((CONSTANT_InterfaceMethodref_info)cp).name_and_type_index);
990             break;
991          case cp_info.CONSTANT_String:
992             dd.writeShort(((CONSTANT_String_info)cp).string_index);
993             break;
994          case cp_info.CONSTANT_Integer:
995             dd.writeInt((int) ((CONSTANT_Integer_info)cp).bytes);
996             break;
997          case cp_info.CONSTANT_Float:
998             dd.writeInt((int) ((CONSTANT_Float_info)cp).bytes);
999             break;
1000         case cp_info.CONSTANT_Long:
1001            dd.writeInt((int) ((CONSTANT_Long_info)cp).high);
1002            dd.writeInt((int) ((CONSTANT_Long_info)cp).low);
1003            skipone = true;
1004            break;
1005         case cp_info.CONSTANT_Double:
1006            dd.writeInt((int) ((CONSTANT_Double_info)cp).high);
1007            dd.writeInt((int) ((CONSTANT_Double_info)cp).low);
1008            skipone = true;
1009            break;
1010         case cp_info.CONSTANT_NameAndType:
1011            dd.writeShort(((CONSTANT_NameAndType_info)cp).name_index);
1012            dd.writeShort(((CONSTANT_NameAndType_info)cp).descriptor_index);
1013            break;
1014         case cp_info.CONSTANT_Utf8:
1015            ((CONSTANT_Utf8_info)cp).writeBytes(dd);
1016            break;
1017         default:
1018            G.v().out.println("Unknown tag in constant pool: " + cp.tag);
1019            return false;
1020         }
1021      }
1022      return true;
1023   }
1024
1025   /** Writes the given array of attributes to the given stream.
1026    * @param dd output stream.
1027    * @param attributes_count number of attributes to write.
1028    * @param ai array of attributes to write.
1029    * @return <i>true</i> if write was successful, <i>false</i> on some error.
1030    * @exception java.io.IOException on error.
1031    */

1032   protected boolean writeAttributes(DataOutputStream dd, int attributes_count,
1033                                     attribute_info[] ai) throws IOException {
1034      attribute_info a=null;
1035      int i,len;
1036      short j;
1037      String JavaDoc s;
1038
1039      for (i=0;i<attributes_count;i++) {
1040         a = ai[i];
1041         dd.writeShort(a.attribute_name);
1042         dd.writeInt((int) a.attribute_length);
1043         if (a instanceof SourceFile_attribute) {
1044            SourceFile_attribute sa = (SourceFile_attribute)a;
1045            dd.writeShort(sa.sourcefile_index);
1046         } else if(a instanceof ConstantValue_attribute) {
1047            ConstantValue_attribute ca = (ConstantValue_attribute)a;
1048            dd.writeShort(ca.constantvalue_index);
1049         } else if(a instanceof Code_attribute) {
1050            Code_attribute ca = (Code_attribute)a;
1051            dd.writeShort(ca.max_stack);
1052            dd.writeShort(ca.max_locals);
1053            dd.writeInt((int) ca.code_length);
1054            dd.write(ca.code,0, (int) ca.code_length);
1055            dd.writeShort(ca.exception_table_length);
1056            int k;
1057            exception_table_entry e;
1058            for (k=0; k<ca.exception_table_length; k++) {
1059               e = ca.exception_table[k];
1060               dd.writeShort(e.start_pc);
1061               dd.writeShort(e.end_pc);
1062               dd.writeShort(e.handler_pc);
1063               dd.writeShort(e.catch_type);
1064            }
1065            dd.writeShort(ca.attributes_count);
1066            if (ca.attributes_count>0)
1067               writeAttributes(dd,ca.attributes_count,ca.attributes);
1068         } else if(a instanceof Exception_attribute) {
1069            Exception_attribute ea = (Exception_attribute)a;
1070            dd.writeShort(ea.number_of_exceptions);
1071            if (ea.number_of_exceptions>0) {
1072               int k;
1073               for (k=0; k<ea.number_of_exceptions; k++)
1074                  dd.writeShort(ea.exception_index_table[k]);
1075            }
1076         } else if(a instanceof LineNumberTable_attribute) {
1077            LineNumberTable_attribute la = (LineNumberTable_attribute)a;
1078            dd.writeShort(la.line_number_table_length);
1079            int k;
1080            line_number_table_entry e;
1081            for (k=0; k<la.line_number_table_length; k++) {
1082               e = la.line_number_table[k];
1083               dd.writeShort(e.start_pc);
1084               dd.writeShort(e.line_number);
1085            }
1086         } else if(a instanceof LocalVariableTable_attribute) {
1087            LocalVariableTable_attribute la = (LocalVariableTable_attribute)a;
1088            dd.writeShort(la.local_variable_table_length);
1089            int k;
1090            local_variable_table_entry e;
1091            for (k=0; k<la.local_variable_table_length; k++) {
1092               e = la.local_variable_table[k];
1093               dd.writeShort(e.start_pc);
1094               dd.writeShort(e.length);
1095               dd.writeShort(e.name_index);
1096               dd.writeShort(e.descriptor_index);
1097               dd.writeShort(e.index);
1098            }
1099         } else {
1100            // unknown attribute
1101
G.v().out.println("Generic/Unknown Attribute in output");
1102            Generic_attribute ga = (Generic_attribute)a;
1103            if (ga.attribute_length>0) {
1104               dd.write(ga.info,0,(int) ga.attribute_length);
1105            }
1106         }
1107      }
1108      return true;
1109   }
1110
1111   /** Writes the fields to the given stream.
1112    * @param dd output stream.
1113    * @return <i>true</i> if write was successful, <i>false</i> on some error.
1114    * @exception java.io.IOException on error.
1115    */

1116   protected boolean writeFields(DataOutputStream dd) throws IOException {
1117      field_info fi;
1118      int i;
1119
1120      for (i=0;i<fields_count;i++) {
1121         fi = fields[i];
1122         dd.writeShort(fi.access_flags);
1123         dd.writeShort(fi.name_index);
1124         dd.writeShort(fi.descriptor_index);
1125         dd.writeShort(fi.attributes_count);
1126         if (fi.attributes_count>0) {
1127            writeAttributes(dd,fi.attributes_count,fi.attributes);
1128         }
1129      }
1130      return true;
1131   }
1132
1133   /** Writes the methods to the given stream.
1134    * @param dd output stream.
1135    * @return <i>true</i> if write was successful, <i>false</i> on some error.
1136    * @exception java.io.IOException on error.
1137    */

1138   protected boolean writeMethods(DataOutputStream dd) throws IOException {
1139      method_info mi;
1140      int i;
1141
1142      for (i=0;i<methods_count;i++) {
1143         mi = methods[i];
1144         dd.writeShort(mi.access_flags);
1145         dd.writeShort(mi.name_index);
1146         dd.writeShort(mi.descriptor_index);
1147         dd.writeShort(mi.attributes_count);
1148         if (mi.attributes_count>0) {
1149            writeAttributes(dd,mi.attributes_count,mi.attributes);
1150         }
1151      }
1152      return true;
1153   }
1154
1155   /** Writes this entire ClassFile object to the given stream.
1156    * @param dd output stream.
1157    * @return <i>true</i> if write was successful, <i>false</i> on some error.
1158    */

1159    boolean writeClass(DataOutputStream dd) {
1160      // outputs the .class file from the loaded one
1161
try {
1162         // first write magic number
1163
dd.writeInt((int) magic);
1164
1165         dd.writeShort(minor_version);
1166         dd.writeShort(major_version);
1167         dd.writeShort(constant_pool_count);
1168
1169         if (!writeConstantPool(dd))
1170            return false;
1171
1172         dd.writeShort(access_flags);
1173         dd.writeShort(this_class);
1174         dd.writeShort(super_class);
1175         dd.writeShort(interfaces_count);
1176         if (interfaces_count>0) {
1177            int j;
1178            for (j=0; j<interfaces_count; j++)
1179               dd.writeShort(interfaces[j]);
1180         }
1181
1182         dd.writeShort(fields_count);
1183         writeFields(dd);
1184
1185         dd.writeShort(methods_count);
1186         writeMethods(dd);
1187
1188         dd.writeShort(attributes_count);
1189         if (attributes_count>0) {
1190            writeAttributes(dd,attributes_count,attributes);
1191         }
1192      } catch(IOException e) {
1193         G.v().out.println("IOException with " + fn + ": " + e.getMessage());
1194         return false;
1195      }
1196      return true;
1197   }
1198
1199   /** Parses the given method, converting its bytecode array into a list
1200    * of Instruction objects.
1201    * @param m method to parse.
1202    * @return head of a list of Instructions.
1203    * @see Instruction
1204    * @see ByteCode
1205    * @see ByteCode#disassemble_bytecode
1206    */

1207    public Instruction parseMethod(method_info m) {
1208      // first task, look through attributes for a code attribute
1209
int j;
1210      Code_attribute ca;
1211      ByteCode bc;
1212      Instruction inst,head,tail;
1213      exception_table_entry e;
1214
1215      head = null;
1216      tail = null;
1217      bc = new ByteCode();
1218
1219      ca = m.locate_code_attribute();
1220      if (ca==null) return null;
1221
1222      j = 0;
1223      while(j<ca.code_length) {
1224         inst = bc.disassemble_bytecode(ca.code,j);
1225         inst.originalIndex = j;
1226         // G.v().out.println(inst + ": " + (((int)(inst.code))&0xff));
1227
// G.v().out.println(j + " : " + inst);
1228

1229         if (inst instanceof Instruction_Unknown) {
1230            G.v().out.println("Unknown instruction in \"" + m.toName(constant_pool) +
1231                               "\" at offset " + j);
1232            G.v().out.println(" bytecode = " + (((int)(inst.code))&0xff));
1233         }
1234         // G.v().out.println("before: " + j);
1235
j = inst.nextOffset(j);
1236         // G.v().out.println("after: " + j);
1237

1238         if ( head==null )
1239         head = inst;
1240         else
1241     {
1242         tail.next = inst;
1243         inst.prev = tail;
1244     }
1245         tail = inst;
1246      }
1247
1248      // bytecode converted into instructions, now build pointers
1249
bc.build(head);
1250
1251      // also change exception table to use pointers instead of absolute addresses
1252
for (j=0;j<ca.exception_table_length;j++) {
1253         e = ca.exception_table[j];
1254         e.start_inst = bc.locateInst(e.start_pc);
1255         if (e.end_pc == ca.code_length)
1256            e.end_inst = null;
1257         else
1258            e.end_inst = bc.locateInst(e.end_pc);
1259         e.handler_inst = bc.locateInst(e.handler_pc);
1260         if (e.handler_inst!=null)
1261            e.handler_inst.labelled = true;
1262      }
1263
1264      m.instructions = head;
1265
1266      // now also update LineNumberTable attribute by pointers instead of absolute addresses
1267
for (int k=0; k<ca.attributes.length; k++)
1268      {
1269      if (ca.attributes[k] instanceof LineNumberTable_attribute)
1270      {
1271          LineNumberTable_attribute lntattr =
1272          (LineNumberTable_attribute)ca.attributes[k];
1273
1274          for (int l=0; l<lntattr.line_number_table.length; l++)
1275          {
1276          lntattr.line_number_table[l].start_inst =
1277              bc.locateInst(lntattr.line_number_table[l].start_pc);
1278          }
1279      }
1280      }
1281
1282      return head;
1283   }
1284
1285   /** For every method, this calls parseMethod, storing the list of Instructions
1286    * in the method_info object, and also constructs the corresponding CFG.
1287    * @see ClassFile#parseMethod
1288    * @see CFG
1289    */

1290    public void parse() {
1291      method_info mi;
1292      int i;
1293
1294      for (i=0;i<methods_count;i++) {
1295         mi = methods[i];
1296         mi.instructions = parseMethod(mi);
1297         //new CFG(mi);
1298
// don't build it right away for now
1299
}
1300   }
1301
1302   /** Recomputes the offset of each Instruction starting from 0;
1303    * used when converting references back to offsets.
1304    * @param i list of Instructions to process.
1305    * @return length of corresponding bytecode.
1306    * @see Instruction#nextOffset
1307    */

1308    int relabel(Instruction i) {
1309      int index = 0;
1310      while (i!=null) {
1311         i.label = index;
1312         index = i.nextOffset(index);
1313         i = i.next;
1314      }
1315      return index;
1316   }
1317
1318   /** Inversive to parseMethod, this converts the list of
1319    * Instructions stored in a method_info object back to an
1320    * array of bytecode.
1321    * @param m method to unparse.
1322    * @return array of bytecode, or <i>null</i> on error.
1323    * @see CFG#reconstructInstructions
1324    * @see ClassFile#parseMethod
1325    * @see ClassFile#relabel
1326    * @see Instruction#compile
1327    */

1328    byte[] unparseMethod(method_info m) {
1329      int codesize;
1330      byte bc[];
1331      Instruction i;
1332
1333      // Rebuild instruction sequence
1334
m.cfg.reconstructInstructions();
1335
1336      // relabel instructions and get size of code array
1337
codesize = relabel(m.instructions);
1338
1339      // construct a new array for the byte-code
1340
bc = new byte[codesize];
1341      if (bc==null) {
1342         G.v().out.println("Warning: can't allocate memory for recompile");
1343         return null;
1344      }
1345
1346      // then recompile the instructions into byte-code
1347
i = m.instructions;
1348      codesize = 0;
1349      while (i!=null) {
1350         codesize = i.compile(bc,codesize);
1351         i = i.next;
1352      }
1353      if (codesize != bc.length)
1354         G.v().out.println("Warning: code size doesn't match array length!");
1355
1356      return bc;
1357   }
1358
1359   /** Inversive to parse, this method calls unparseMethod for each
1360    * method, storing the resulting bytecode in the method's code
1361    * attribute, and recomputing offsets for exception handlers.
1362    * @see ClassFile#unparseMethod
1363    */

1364    void unparse() {
1365      int i,j;
1366      Code_attribute ca;
1367      byte bc[];
1368      method_info mi;
1369      exception_table_entry e;
1370
1371      for (i=0;i<methods_count;i++) {
1372         mi = methods[i];
1373         // locate code attribute
1374
ca = mi.locate_code_attribute();
1375         if (ca==null) continue;
1376         bc = unparseMethod(mi);
1377         if (bc==null) {
1378            G.v().out.println("Recompile of " + mi.toName(constant_pool) + " failed!");
1379         } else {
1380            ca.code_length = bc.length;
1381            ca.code = bc;
1382            // also recompile exception table
1383
for (j=0;j<ca.exception_table_length;j++) {
1384               e = ca.exception_table[j];
1385               e.start_pc = (e.start_inst.label);
1386               if (e.end_inst!=null)
1387                  e.end_pc = (e.end_inst.label);
1388               else
1389                  e.end_pc = (int) (ca.code_length);
1390               e.handler_pc = (e.handler_inst.label);
1391            }
1392         }
1393      }
1394   }
1395
1396   /** Static utility method to parse the given method descriptor string.
1397    * @param s descriptor string.
1398    * @return return type of method.
1399    * @see ClassFile#parseDesc
1400    * @see ClassFile#parseMethodDesc_params
1401    */

1402    static String JavaDoc parseMethodDesc_return(String JavaDoc s) {
1403      int j;
1404      j = s.lastIndexOf(')');
1405      if (j>=0) {
1406         return parseDesc(s.substring(j+1),",");
1407      }
1408      return parseDesc(s,",");
1409   }
1410
1411   /** Static utility method to parse the given method descriptor string.
1412    * @param s descriptor string.
1413    * @return comma-separated ordered list of parameter types
1414    * @see ClassFile#parseDesc
1415    * @see ClassFile#parseMethodDesc_return
1416    */

1417    static String JavaDoc parseMethodDesc_params(String JavaDoc s) {
1418      int i,j;
1419      i = s.indexOf('(');
1420      if (i>=0) {
1421         j = s.indexOf(')',i+1);
1422         if (j>=0) {
1423            return parseDesc(s.substring(i+1,j),",");
1424         }
1425      }
1426      return "<parse error>";
1427   }
1428
1429   /** Static utility method to parse the given method descriptor string.
1430    * @param desc descriptor string.
1431    * @param sep String to use as a separator between types.
1432    * @return String of types parsed.
1433    * @see ClassFile#parseDesc
1434    * @see ClassFile#parseMethodDesc_return
1435    */

1436    static String JavaDoc parseDesc(String JavaDoc desc,String JavaDoc sep) {
1437      String JavaDoc params = "",param;
1438      char c;
1439      int i,len,arraylevel=0;
1440      boolean didone = false;
1441
1442      len = desc.length();
1443      for (i=0;i<len;i++) {
1444         c = desc.charAt(i);
1445         if (c==DESC_BYTE.charAt(0)) {
1446            param = "byte";
1447         } else if (c==DESC_CHAR.charAt(0)) {
1448            param = "char";
1449         } else if (c==DESC_DOUBLE.charAt(0)) {
1450            param = "double";
1451         } else if (c==DESC_FLOAT.charAt(0)) {
1452            param = "float";
1453         } else if (c==DESC_INT.charAt(0)) {
1454            param = "int";
1455         } else if (c==DESC_LONG.charAt(0)) {
1456            param = "long";
1457         } else if (c==DESC_SHORT.charAt(0)) {
1458            param = "short";
1459         } else if (c==DESC_BOOLEAN.charAt(0)) {
1460            param = "boolean";
1461         } else if (c==DESC_VOID.charAt(0)) {
1462            param = "void";
1463         } else if (c==DESC_ARRAY.charAt(0)) {
1464            arraylevel++;
1465            continue;
1466         } else if (c==DESC_OBJECT.charAt(0)) {
1467            int j;
1468            j = desc.indexOf(';',i+1);
1469            if (j<0) {
1470               G.v().out.println("Warning: Parse error -- can't find a ; in " +
1471                                  desc.substring(i+1));
1472               param = "<error>";
1473            } else {
1474               if (j-i>10 && desc.substring(i+1,i+11).compareTo("java/lang/")==0)
1475                  i = i+10;
1476               param = desc.substring(i+1,j);
1477               // replace '/'s with '.'s
1478
param = param.replace('/','.');
1479               i = j;
1480            }
1481         } else {
1482            param = "???";
1483         }
1484         if (didone) params = params + sep;
1485         params = params + param;
1486         while (arraylevel>0) {
1487            params = params + "[]";
1488            arraylevel--;
1489         }
1490         didone = true;
1491      }
1492      return params;
1493   }
1494
1495
1496   /** Locates a method by name.
1497    * @param s name of method.
1498    * @return method_info object representing method, or <i>null</i> if not found.
1499    * @see method_info#toName
1500    */

1501    method_info findMethod(String JavaDoc s) {
1502      method_info m;
1503      int i;
1504
1505      for (i=0;i<methods_count;i++) {
1506         m = methods[i];
1507         if (s.equals(m.toName(constant_pool))) {
1508            return m;
1509         }
1510      }
1511      return null;
1512   }
1513
1514   /** Displays a the prototypes for all the methods defined in this ClassFile.
1515    * @see ClassFile#methods
1516    * @see ClassFile#methods_count
1517    * @see method_info#prototype
1518    */

1519    void listMethods() {
1520      int i;
1521
1522      for (i=0;i<methods_count;i++) {
1523         G.v().out.println(methods[i].prototype(constant_pool));
1524      }
1525   }
1526
1527   /** Displays the entire constant pool.
1528    * @see ClassFile#constant_pool
1529    * @see ClassFile#constant_pool_count
1530    * @see cp_info#toString
1531    */

1532    void listConstantPool() {
1533      cp_info c;
1534      int i;
1535
1536      // note that we start at 1 in the constant pool
1537
for (i=1;i<constant_pool_count;i++) {
1538         c = constant_pool[i];
1539         G.v().out.println("[" + i + "] " + c.typeName() +
1540                            "=" + c.toString(constant_pool));
1541         if ((constant_pool[i]).tag==cp_info.CONSTANT_Long ||
1542             (constant_pool[i]).tag==cp_info.CONSTANT_Double) {
1543            // must skip an entry after a long or double constant
1544
i++;
1545         }
1546      }
1547   }
1548
1549   /** Displays the list of fields defined in this ClassFile, including
1550    * any static initializers (constants).
1551    * @see ClassFile#fields
1552    * @see ClassFile#fields_count
1553    * @see field_info#prototype
1554    * @see ConstantValue_attribute
1555    */

1556    void listFields() {
1557      field_info fi;
1558      ConstantValue_attribute cva;
1559      CONSTANT_Utf8_info cm;
1560      int i,j;
1561
1562      for (i=0;i<fields_count;i++) {
1563         fi = fields[i];
1564         G.v().out.print(fi.prototype(constant_pool));
1565         // see if has a constant value attribute
1566
for (j=0;j<fi.attributes_count;j++) {
1567            cm = (CONSTANT_Utf8_info)(constant_pool[fi.attributes[j].attribute_name]);
1568            if (cm.convert().compareTo(attribute_info.ConstantValue)==0) {
1569               cva = (ConstantValue_attribute)(fi.attributes[j]);
1570               //dm = (CONSTANT_Utf8_info)(constant_pool[cva.constantvalue_index]);
1571
G.v().out.print(" = " +
1572                                constant_pool[cva.constantvalue_index].
1573                                toString(constant_pool));
1574               break;
1575            }
1576         }
1577         G.v().out.println(";");
1578      }
1579   }
1580
1581   /** Moves a method to a different index in the methods array.
1582    * @param m name of method to move.
1583    * @param pos desired index.
1584    * @see ClassFile#methods
1585    */

1586    void moveMethod(String JavaDoc m,int pos) {
1587      int i,j;
1588      method_info mthd;
1589      G.v().out.println("Moving " + m + " to position " + pos +
1590                         " of " + methods_count);
1591
1592      for (i=0;i<methods_count;i++) {
1593         if (m.compareTo(methods[i].toName(constant_pool))==0) {
1594            mthd = methods[i];
1595            if (i>pos) {
1596               for (j=i;j>pos && j>0;j--)
1597                  methods[j] = methods[j-1];
1598               methods[pos] = mthd;
1599            } else if (i<pos) {
1600               for (j=i;j<pos && j<methods_count-1;j++)
1601                  methods[j] = methods[j+1];
1602               methods[pos] = mthd;
1603            }
1604            return;
1605         }
1606      }
1607   }
1608
1609   /** Answers whether this class is an immediate descendant (as subclass or
1610    * as an implementation of an interface) of the given class.
1611    * @param cf ClassFile of supposed parent.
1612    * @return <i>true</i> if it is a parent, <i>false</i> otherwise.
1613    * @see ClassFile#descendsFrom(String)
1614    */

1615    boolean descendsFrom(ClassFile cf) { return descendsFrom(cf.toString()); }
1616
1617   /** Answers whether this class is an immediate descendant (as subclass or
1618    * as an implementation of an interface) of the given class.
1619    * @param cname name of supposed parent.
1620    * @return <i>true</i> if it is a parent, <i>false</i> otherwise.
1621    * @see ClassFile#descendsFrom(ClassFile)
1622    */

1623    boolean descendsFrom(String JavaDoc cname) {
1624      cp_info cf;
1625      int i;
1626      cf = constant_pool[super_class];
1627      if (cf.toString(constant_pool).compareTo(cname)==0) return true;
1628      for (i=0;i<interfaces_count;i++) {
1629         cf = constant_pool[interfaces[i]];
1630         if (cf.toString(constant_pool).compareTo(cname)==0) return true;
1631      }
1632      return false;
1633   }
1634
1635   /** Answers whether this class can have subclasses outside its package.
1636    * @return <i>true</i> if it cannot, <i>false</i> if it might.
1637    */

1638    boolean isSterile() {
1639      if ((access_flags&ACC_PUBLIC)!=0 && (access_flags&ACC_FINAL)==0) return false;
1640      return true;
1641   }
1642
1643   /** Given the name of a class --- possibly with <tt>.class</tt> after it,
1644    * this answers whether the class might refer to this ClassFile object.
1645    * @return <i>true</i> if it does, <i>false</i> if it doesn't.
1646    */

1647    boolean sameClass(String JavaDoc cfn) {
1648      String JavaDoc s = cfn;
1649      int i = s.lastIndexOf(".class");
1650      if (i>0) { // has .class after it
1651
s = s.substring(0,i); // cut off the .class
1652
}
1653      if (s.compareTo(toString())==0)
1654         return true;
1655      return false;
1656   }
1657
1658   /** Returns the name of a specific field in the field array.
1659    * @param i index of field in field array.
1660    * @return name of field.
1661    */

1662    String JavaDoc fieldName(int i) {
1663      return fields[i].toName(constant_pool);
1664   }
1665
1666   /* DEPRECATED
1667   // Locates the given classfile, and extracts it from the list.
1668   // It cannot be the first one in the list, and this returns null
1669   // or the classfile.
1670    static ClassFile removeClassFile(ClassFile cfhead,String cfn) {
1671      ClassFile cf,cfprev;
1672      cf = cfhead;
1673      cfprev = null;
1674      while (cf!=null) {
1675         if (cf.sameClass(cfn)) {
1676            if (cfprev==null) return null; // this shouldn't happen
1677            cfprev.next = cf.next;
1678            cf.next = null;
1679            return cf;
1680         }
1681         cfprev = cf;
1682         cf = cf.next;
1683      }
1684      return null;
1685   }
1686
1687   // returns true if this class contains any references to the given
1688   // cuClass.cuName, which is of type cuDesc. Searches for methods if
1689   // ismethod is true, fields otherwise.
1690   boolean refersTo(boolean ismethod,CONSTANT_Utf8_info cuClass,
1691                    CONSTANT_Utf8_info cuName,CONSTANT_Utf8_info cuDesc) {
1692      int i;
1693      CONSTANT_Utf8_info cu;
1694      // note that we start at 1 in the constant pool
1695      if (ismethod) {
1696         for (i=1;i<constant_pool_count;i++) {
1697            if ((constant_pool[i]).tag==cp_info.CONSTANT_Methodref) {
1698               CONSTANT_Methodref_info cf = (CONSTANT_Methodref_info)(constant_pool[i]);
1699               CONSTANT_Class_info cc = (CONSTANT_Class_info)
1700                  (constant_pool[cf.class_index]);
1701               if (cuClass.equals((CONSTANT_Utf8_info)
1702                                  (constant_pool[cc.name_index]))) {
1703                  CONSTANT_NameAndType_info cn = (CONSTANT_NameAndType_info)
1704                     (constant_pool[cf.name_and_type_index]);
1705                  if (cuName.equals((CONSTANT_Utf8_info)
1706                                    (constant_pool[cn.name_index])) &&
1707                      cuDesc.equals((CONSTANT_Utf8_info)
1708                                    (constant_pool[cn.descriptor_index])))
1709                     return true;
1710               }
1711            } else if ((constant_pool[i]).tag==
1712                       cp_info.CONSTANT_InterfaceMethodref) {
1713               CONSTANT_InterfaceMethodref_info cf =
1714                  (CONSTANT_InterfaceMethodref_info)(constant_pool[i]);
1715               CONSTANT_Class_info cc = (CONSTANT_Class_info)
1716                  (constant_pool[cf.class_index]);
1717               if (cuClass.equals((CONSTANT_Utf8_info)
1718                                  (constant_pool[cc.name_index]))) {
1719                  CONSTANT_NameAndType_info cn = (CONSTANT_NameAndType_info)
1720                     (constant_pool[cf.name_and_type_index]);
1721                  if (cuName.equals((CONSTANT_Utf8_info)
1722                                    (constant_pool[cn.name_index])) &&
1723                      cuDesc.equals((CONSTANT_Utf8_info)
1724                                    (constant_pool[cn.descriptor_index])))
1725                     return true;
1726               }
1727            } else if ((constant_pool[i]).tag==cp_info.CONSTANT_Long ||
1728                       (constant_pool[i]).tag==cp_info.CONSTANT_Double) {
1729               // must skip an entry after a long or double constant
1730               i++;
1731            }
1732         }
1733      } else {
1734         for (i=1;i<constant_pool_count;i++) {
1735            if ((constant_pool[i]).tag==cp_info.CONSTANT_Fieldref) {
1736               CONSTANT_Fieldref_info cf = (CONSTANT_Fieldref_info)(constant_pool[i]);
1737               CONSTANT_Class_info cc = (CONSTANT_Class_info)
1738                  (constant_pool[cf.class_index]);
1739               if (cuClass.equals((CONSTANT_Utf8_info)
1740                                  (constant_pool[cc.name_index]))) {
1741                  CONSTANT_NameAndType_info cn = (CONSTANT_NameAndType_info)
1742                     (constant_pool[cf.name_and_type_index]);
1743                  if (cuName.equals((CONSTANT_Utf8_info)
1744                                    (constant_pool[cn.name_index])) &&
1745                      cuDesc.equals((CONSTANT_Utf8_info)
1746                                    (constant_pool[cn.descriptor_index])))
1747                     return true;
1748               }
1749            } else if ((constant_pool[i]).tag==cp_info.CONSTANT_Long ||
1750                       (constant_pool[i]).tag==cp_info.CONSTANT_Double) {
1751               // must skip an entry after a long or double constant
1752               i++;
1753            }
1754         }
1755      }
1756      return false;
1757   }
1758
1759   // produces a sorted array of constant pool indices, one for each Utf8 entry used
1760   // by any field
1761   short[] forbiddenFields() {
1762      short fFields[] = new short[fields_count];
1763      for (int i=0;i<fields_count;i++) {
1764         fFields[i] = fields[i].name_index;
1765      }
1766      // now to sort the array
1767      return sortShorts(fFields);
1768   }
1769
1770   // sorts an array of shorts using selection sort. It's assumed no valid
1771   // entry is 0.
1772   static short[] sortShorts(short a[]) {
1773      int i,largest;
1774      short s;
1775      for(largest = a.length-1;largest>=1;largest--) {
1776         for (i=0;i<largest;i++) {
1777            if (a[i]>a[largest]) {
1778               s = a[i];
1779               a[i] = a[largest];
1780               a[largest] = s;
1781            }
1782         }
1783      }
1784      return a;
1785   }
1786
1787   // Given a new constant pool, and a list of redirections
1788   // (new index = redirect[old index]), this changes all constant
1789   // pool entries, and installs the new constant pool of size size
1790   void changeConstantPool(short redirect[],cp_info newCP[],short size) {
1791      Debig d = new Debig(this);
1792      d.redirectCPRefs(redirect);
1793      constant_pool = newCP;
1794      constant_pool_count = size;
1795   }
1796
1797   // the constant pool is typically a few hundred entries in size, and so
1798   // is just a bit too big to make use of insertion/selection sort.
1799   // However, the variable size of the entries makes using a heapsort
1800   // or quicksort rather cumbersome, so since it is quite close to the
1801   // limits of efficient insertion/selection sort, we'll use that anyway.
1802    void sortConstantPool() {
1803      cp_info newcp[] = new cp_info[constant_pool_count];
1804      short redirect[] = new short[constant_pool_count];
1805      newcp[0] = constant_pool[0]; // the 0-entry stays put
1806      redirect[0] = (short)0;
1807      int smallest,j;
1808      for (int i=1;i<constant_pool_count;i++) redirect[i] = (short)0;
1809      for (int i=1;i<constant_pool_count;i++) {
1810         for (smallest = 1;smallest<constant_pool_count;smallest++)
1811            if (redirect[smallest]==(short)0) break;
1812         //G.v().out.println(" smallest = " + smallest);
1813         j = (constant_pool[smallest].tag==cp_info.CONSTANT_Double ||
1814              constant_pool[smallest].tag==cp_info.CONSTANT_Long) ? smallest+2 : smallest+1;
1815         for (;j<constant_pool_count;j++) {
1816            if ((redirect[j]==(short)0) && constant_pool[j].
1817                compareTo(constant_pool,constant_pool[smallest],constant_pool)<0) {
1818               smallest = j;
1819            }
1820            if (constant_pool[j].tag==cp_info.CONSTANT_Double ||
1821                constant_pool[j].tag==cp_info.CONSTANT_Long) j++;
1822         }
1823         redirect[smallest] = (short)i;
1824         newcp[i] = constant_pool[smallest];
1825         //G.v().out.println(" Smallest cp entry is [" + smallest + "] = " + constant_pool[smallest]
1826         // + " -> " + i);
1827
1828         if (constant_pool[smallest].tag==cp_info.CONSTANT_Double ||
1829             constant_pool[smallest].tag==cp_info.CONSTANT_Long) {
1830            redirect[++smallest] = (short)(++i);
1831            newcp[i] = constant_pool[smallest];
1832         }
1833      }
1834      // constant pool is now sorted into newcp
1835      changeConstantPool(redirect,newcp,constant_pool_count);
1836      G.v().out.println("Finished sorting constant pool");
1837   }
1838
1839   // just a wrapper for the debigulation, so we can elegantly allocate
1840   // a new debigulator, debigualte and then produce some output
1841    void debigulate(boolean attribs,boolean privates) {
1842      Debig debigulator = new Debig(this);
1843      debigulator.debigulate(attribs,privates);
1844      debigulator.setCF(null);
1845
1846      inf.verboseReport(G.v().out);
1847   }*/

1848
1849
1850}
1851
1852
1853
1854
1855
1856
1857
Popular Tags