1 cananian 1.1.2.1 // RawP.java, created by cananian
  2 cananian 1.1.2.1 // Copyright (C) 2002 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1 package harpoon.Main;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.ClassFile.Loader;
  7 cananian 1.1.2.1 import harpoon.IR.RawClass.AccessFlags;
  8 cananian 1.1.2.1 import harpoon.IR.RawClass.Attribute;
  9 cananian 1.14    import harpoon.IR.RawClass.AttributeCode;
 10 cananian 1.1.2.1 import harpoon.IR.RawClass.AttributeExceptions;
 11 cananian 1.14    import harpoon.IR.RawClass.AttributeLineNumberTable;
 12 cananian 1.14    import harpoon.IR.RawClass.AttributeLocalVariableTable;
 13 cananian 1.1.2.1 import harpoon.IR.RawClass.AttributeSignature;
 14 cananian 1.1.2.1 import harpoon.IR.RawClass.AttributeSourceFile;
 15 cananian 1.1.2.1 import harpoon.IR.RawClass.ClassFile;
 16 cananian 1.1.2.1 import harpoon.IR.RawClass.ConstantClass;
 17 cananian 1.1.2.1 import harpoon.IR.RawClass.FieldInfo;
 18 cananian 1.14    import harpoon.IR.RawClass.LineNumberTable;
 19 cananian 1.14    import harpoon.IR.RawClass.LocalVariableTable;
 20 cananian 1.1.2.1 import harpoon.IR.RawClass.MethodInfo;
 21 cananian 1.1.2.1 import harpoon.Util.Util;
 22 cananian 1.1.2.1 
 23 cananian 1.1.2.1 import java.io.InputStream;
 24 cananian 1.1.2.1 /**
 25 cananian 1.1.2.1  * <code>Javap</code> is a low-level clone of javap that supports
 26 cananian 1.1.2.1  * GJ signatures.
 27 cananian 1.1.2.1  * 
 28 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@lesser-magoo.lcs.mit.edu>
 29 cananian 1.16     * @version $Id: Javap.java,v 1.16 2003/09/05 22:38:08 cananian Exp $
 30 cananian 1.1.2.1  */
 31 cananian 1.1.2.1 public abstract class Javap /*extends harpoon.IR.Registration*/ {
 32 cananian 1.11        /** Print out disassembled code. */
 33 cananian 1.11        public static boolean DISASSEMBLE=false;
 34 cananian 1.11        /** Print out help message. */
 35 cananian 1.11        public static boolean HELP=false;
 36 cananian 1.13        /** Indent members (fields/methods). */
 37 cananian 1.13        public static boolean INDENT=true;
 38 cananian 1.11        /** Print out line number tables. */
 39 cananian 1.11        public static boolean LINE_NUMBER_TABLE=false;
 40 cananian 1.11        /** Print out local variable tables. */
 41 cananian 1.11        public static boolean LOCAL_VARIABLE_TABLE=false;
 42 cananian 1.11        /** Show only public classes and members. */
 43 cananian 1.11        public static boolean PUBLIC_ONLY=false;
 44 cananian 1.11        /** Show protected/public classes and members. */
 45 cananian 1.11        public static boolean PUBLIC_PROTECTED_ONLY=false;
 46 cananian 1.11        /** Show package/protected/public classes and members. */
 47 cananian 1.11        public static boolean PUBLIC_PROTECTED_PACKAGE_ONLY=false;//default
 48 cananian 1.11        /** Show all classes and members. */
 49 cananian 1.11        public static boolean PUBLIC_PROTECTED_PACKAGE_PRIVATE=false;
 50 cananian 1.11        /** Print internal type signatures. */
 51 cananian 1.11        public static boolean SIGNATURES=false;
 52 cananian 1.11        /** Print stack size, number of locals, and number of method args. */
 53 cananian 1.11        public static boolean MORE_INFO=false;
 54 cananian 1.1.2.1 
 55 cananian 1.11        public static final void main(String[] args) {
 56 cananian 1.11            String[] classes = parseOpts(args);
 57 cananian 1.11            for (int i=0; i<classes.length; i++)
 58 cananian 1.11                doClass(classes[i]);
 59 cananian 1.11        }
 60 cananian 1.11    
 61 cananian 1.11        public static String[] parseOpts(String[] opts) {
 62 cananian 1.11            int optNum = 0;
 63 cananian 1.11            while (optNum < opts.length && opts[optNum].startsWith("-")) {
 64 cananian 1.11                String opt = opts[optNum++].intern();
 65 cananian 1.11                if (false) ;
 66 cananian 1.11                else if (opt=="-c") DISASSEMBLE=true;
 67 cananian 1.11                else if (opt=="-help") HELP=true;
 68 cananian 1.11                else if (opt=="-l") { LINE_NUMBER_TABLE=LOCAL_VARIABLE_TABLE=true;}
 69 cananian 1.11                else if (opt=="-public") PUBLIC_ONLY=true;
 70 cananian 1.11                else if (opt=="-protected") PUBLIC_PROTECTED_ONLY=true;
 71 cananian 1.11                else if (opt=="-package") PUBLIC_PROTECTED_PACKAGE_ONLY=true;
 72 cananian 1.11                else if (opt=="-private") PUBLIC_PROTECTED_PACKAGE_PRIVATE=true;
 73 cananian 1.11                else if (opt=="-s") SIGNATURES=true;
 74 cananian 1.13                else if (opt=="-verbose") {
 75 cananian 1.13                    DISASSEMBLE=true;
 76 cananian 1.13                    LINE_NUMBER_TABLE=LOCAL_VARIABLE_TABLE=true;
 77 cananian 1.13                    SIGNATURES=true;
 78 cananian 1.13                    MORE_INFO=true;
 79 cananian 1.13                } else {
 80 cananian 1.11                    System.err.println("Unrecognized option: "+opt);
 81 cananian 1.11                    HELP=true;
 82 cananian 1.11                }
 83 cananian 1.11            }
 84 cananian 1.13            // don't indent if we're printing out additional per-member info:
 85 cananian 1.13            INDENT = !
 86 cananian 1.13                (DISASSEMBLE || LINE_NUMBER_TABLE || LOCAL_VARIABLE_TABLE ||
 87 cananian 1.13                 SIGNATURES || MORE_INFO);
 88 cananian 1.11            // normalize public/protected/package/private
 89 cananian 1.11            if (PUBLIC_ONLY)
 90 cananian 1.11                PUBLIC_PROTECTED_ONLY=false;
 91 cananian 1.11            if (PUBLIC_ONLY||PUBLIC_PROTECTED_ONLY)
 92 cananian 1.11                PUBLIC_PROTECTED_PACKAGE_ONLY=false;
 93 cananian 1.11            if (PUBLIC_ONLY||PUBLIC_PROTECTED_ONLY||PUBLIC_PROTECTED_PACKAGE_ONLY)
 94 cananian 1.11                PUBLIC_PROTECTED_PACKAGE_PRIVATE=false;
 95 cananian 1.11            if (!(PUBLIC_ONLY||PUBLIC_PROTECTED_ONLY||
 96 cananian 1.11                  PUBLIC_PROTECTED_PACKAGE_ONLY||PUBLIC_PROTECTED_PACKAGE_PRIVATE))
 97 cananian 1.11                PUBLIC_PROTECTED_PACKAGE_ONLY=true; // default.
 98 cananian 1.11            // handle 'help' option.
 99 cananian 1.11            if (HELP) {
100 cananian 1.11                System.out.println
101 cananian 1.11                    ("Usage: java "+Javap.class+" <options> <classes>...\n"+
102 cananian 1.11                     "\n"+
103 cananian 1.11                     "where options include:\n"+
104 cananian 1.11                     /*
105 cananian 1.11                     "   -c         Disassemble the code\n"+
106 cananian 1.11                     */
107 cananian 1.11                     "   -help      Print this usage message\n"+
108 cananian 1.11                     "   -l         Print line number and local variable tables\n"+
109 cananian 1.11                     "   -public    Show only public classes and members\n"+
110 cananian 1.11                     "   -protected Show protected/public classes and members\n"+
111 cananian 1.11                     "   -package   Show package/protected/public classes\n"+
112 cananian 1.11                     "              and members (default)\n"+
113 cananian 1.11                     "   -private   Show all classes and members\n"+
114 cananian 1.11                     "   -s         Print internal type signatures\n"+
115 cananian 1.11                     /*
116 cananian 1.11                     "   -verbose   Print stack size, number of locals and args\n"+
117 cananian 1.11                     "              for methods\n"+
118 cananian 1.11                     */
119 cananian 1.11                     "");
120 cananian 1.11                return new String[0];
121 cananian 1.11            }
122 cananian 1.11            // okay, return the non-option arguments.
123 cananian 1.11            String[] classes = new String[opts.length-optNum];
124 cananian 1.11            System.arraycopy(opts, optNum, classes, 0, opts.length - optNum);
125 cananian 1.11            return classes;
126 cananian 1.11        }
127 cananian 1.11    
128 cananian 1.11        public static void doClass(String classname) {
129 cananian 1.1.2.1         InputStream is = 
130 cananian 1.1.2.1             Loader.getResourceAsStream(Loader.classToResource(classname));
131 cananian 1.1.2.1         if (is==null) throw new NoClassDefFoundError(classname);
132 cananian 1.1.2.1         ClassFile raw = new ClassFile(is);
133 cananian 1.11            try { is.close(); } catch (java.io.IOException ex) { /* ignore */ }
134 cananian 1.1.2.1 
135 cananian 1.1.2.1         // print "Compiled from"
136 cananian 1.1.2.1         AttributeSourceFile asf = (AttributeSourceFile)
137 cananian 1.14                findAttribute(raw, AttributeSourceFile.ATTRIBUTE_NAME);
138 cananian 1.1.2.1         if (asf!=null)
139 cananian 1.5                 System.out.println("Compiled from \""+asf.sourcefile()+"\"");
140 cananian 1.1.2.1         // get generic signature.
141 cananian 1.1.2.1         AttributeSignature asig = (AttributeSignature)
142 cananian 1.14                findAttribute(raw, AttributeSignature.ATTRIBUTE_NAME);
143 cananian 1.1.2.1         String gjsig = (asig==null) ? null : asig.signature();
144 cananian 1.1.2.1         // print class modifiers.
145 cananian 1.1.2.1         System.out.print(modString(raw.access_flags, true));
146 cananian 1.1.2.1         // now print class name
147 cananian 1.1.2.1         System.out.print(desc2name("L"+raw.this_class().name()+";"));
148 cananian 1.1.2.1         // print formal type parameters.
149 cananian 1.1.2.1         if (gjsig!=null && gjsig.charAt(0)=='<') {
150 cananian 1.1.2.1             OffsetAndString oas = munchParamPart(gjsig);
151 cananian 1.1.2.1             System.out.print(oas.string);
152 cananian 1.1.2.1             gjsig = gjsig.substring(oas.offset);
153 cananian 1.1.2.1         }
154 cananian 1.1.2.1         // supertype.
155 cananian 1.1.2.1         if (raw.super_class()!=null) { // only null for java.lang.Object.
156 cananian 1.1.2.1             System.out.print(" extends ");
157 cananian 1.1.2.1             if (gjsig==null)
158 cananian 1.1.2.1                 System.out.print(desc2name("L"+raw.super_class().name()+";"));
159 cananian 1.1.2.1             else {
160 cananian 1.1.2.1                 OffsetAndString oas = munchClassTypeSig(gjsig);
161 cananian 1.1.2.1                 System.out.print(oas.string);
162 cananian 1.1.2.1                 gjsig = gjsig.substring(oas.offset);
163 cananian 1.1.2.1             }
164 cananian 1.1.2.1         }
165 cananian 1.1.2.1         // interfaces
166 cananian 1.1.2.1         if (raw.interfaces_count() > 0) {
167 cananian 1.1.2.1             System.out.print(" implements ");
168 cananian 1.1.2.1             for (int i=0; i<raw.interfaces_count(); i++) {
169 cananian 1.1.2.1                 if (gjsig==null)
170 cananian 1.1.2.1                     System.out.print
171 cananian 1.1.2.1                         (desc2name("L"+raw.interfaces(i).name()+";"));
172 cananian 1.1.2.1                 else {
173 cananian 1.1.2.1                     OffsetAndString oas = munchClassTypeSig(gjsig);
174 cananian 1.1.2.1                     System.out.print(oas.string);
175 cananian 1.1.2.1                     gjsig = gjsig.substring(oas.offset);
176 cananian 1.1.2.1                 }
177 cananian 1.1.2.1                 if (i+1 < raw.interfaces_count())
178 cananian 1.1.2.1                     System.out.print(", ");
179 cananian 1.1.2.1             }
180 cananian 1.1.2.1         }
181 cananian 1.1.2.1         System.out.println();
182 cananian 1.13            if (MORE_INFO) {
183 cananian 1.14                if (asf!=null)
184 cananian 1.14                    System.out.println("  SourceFile: \""+asf.sourcefile()+"\"");
185 cananian 1.14                System.out.println("  minor version: "+raw.minor_version);
186 cananian 1.14                System.out.println("  major version: "+raw.major_version);
187 cananian 1.13                System.out.println("  Constant pool:");
188 cananian 1.14                for (int i=1; i<raw.constant_pool.length; ) {
189 cananian 1.14                    System.out.println("const #"+i+" = "+raw.constant_pool[i]);
190 cananian 1.14                    i+=raw.constant_pool[i].entrySize();
191 cananian 1.14                }
192 cananian 1.13            }
193 cananian 1.1.2.1         System.out.println("{");
194 cananian 1.1.2.1         // fields.
195 cananian 1.1.2.1         for (int i=0; i<raw.fields_count(); i++) {
196 cananian 1.1.2.1             FieldInfo fi = raw.fields[i];
197 cananian 1.1.2.1             AttributeSignature fis = (AttributeSignature)
198 cananian 1.14                    findAttribute(fi.attributes,AttributeSignature.ATTRIBUTE_NAME);
199 cananian 1.12                if (!access_flags_okay(fi.access_flags)) continue; // skip
200 cananian 1.13                if (INDENT) System.out.print("    "); // indent.
201 cananian 1.1.2.1             // access flags
202 cananian 1.1.2.1             System.out.print(modString(fi.access_flags, false));
203 cananian 1.1.2.1             // type/signature.
204 cananian 1.1.2.1             if (fis==null)
205 cananian 1.1.2.1                 System.out.print(desc2name(fi.descriptor()));
206 cananian 1.1.2.1             else
207 cananian 1.1.2.1                 System.out.print(munchTypeSig(fis.signature()).string);
208 cananian 1.1.2.1             System.out.print(" ");
209 cananian 1.1.2.1             // field name.
210 cananian 1.1.2.1             System.out.print(fi.name());
211 cananian 1.1.2.1             System.out.print(";");
212 cananian 1.1.2.1             System.out.println();
213 cananian 1.11                if (SIGNATURES) {
214 cananian 1.11                    System.out.println("  Signature: "+fi.descriptor());
215 cananian 1.11                    if (fis!=null)
216 cananian 1.11                        System.out.println("  Generic Signature: "+fis.signature());
217 cananian 1.11                }
218 cananian 1.14                if (!INDENT) System.out.println(); // match Sun javap spacing
219 cananian 1.1.2.1         }
220 cananian 1.1.2.1         // methods.
221 cananian 1.1.2.1         for (int i=0; i<raw.methods_count(); i++) {
222 cananian 1.1.2.1             MethodInfo mi = raw.methods[i];
223 cananian 1.1.2.1             AttributeSignature mis = (AttributeSignature)
224 cananian 1.14                    findAttribute(mi.attributes,AttributeSignature.ATTRIBUTE_NAME);
225 cananian 1.12                if (!access_flags_okay(mi.access_flags)) continue; // skip
226 cananian 1.1.2.1             // assign descriptor.
227 cananian 1.1.2.1             String md;
228 cananian 1.1.2.1             if (mis!=null) md = mis.signature();
229 cananian 1.1.2.1             else {
230 cananian 1.1.2.1                 md = mi.descriptor();
231 cananian 1.1.2.1                 // add throws clauses.
232 cananian 1.1.2.1                 AttributeExceptions ae = (AttributeExceptions)
233 cananian 1.14                        findAttribute(mi.attributes,
234 cananian 1.14                                      AttributeExceptions.ATTRIBUTE_NAME);
235 cananian 1.1.2.1                 for (int j=0; ae!=null && j<ae.number_of_exceptions(); j++) {
236 cananian 1.1.2.1                     ConstantClass cc = ae.exception_index_table(j);
237 cananian 1.1.2.1                     if (cc==null) continue;
238 cananian 1.1.2.1                     md+="^L"+cc.name()+";";
239 cananian 1.1.2.1                 }
240 cananian 1.1.2.1             }
241 cananian 1.9                 // is this a varargs method?
242 cananian 1.10                // XXX the "Varargs" attribute is just temporary for the
243 cananian 1.10                // prototype compilers.  Java 1.5 will introduce a mask bit of
244 cananian 1.10                // some kind to indicate varargs.
245 cananian 1.9                 boolean isVarArgs= (null!=findAttribute(mi.attributes, "Varargs"));
246 cananian 1.15                // is this a static initializer?
247 cananian 1.15                boolean isStaticInit = mi.name().equals("<clinit>");
248 cananian 1.15                // is this a constructor?
249 cananian 1.15                boolean isConstructor = mi.name().equals("<init>");
250 cananian 1.1.2.1             // indent.
251 cananian 1.13                if (INDENT) System.out.print("    ");
252 cananian 1.1.2.1             // access flags
253 cananian 1.1.2.1             System.out.print(modString(mi.access_flags, false));
254 cananian 1.1.2.1             // type formal parameters
255 cananian 1.1.2.1             if (md.charAt(0)=='<') {
256 cananian 1.1.2.1                 OffsetAndString oas = munchParamPart(md);
257 cananian 1.1.2.1                 System.out.print(oas.string);
258 cananian 1.1.2.1                 System.out.print(" ");
259 cananian 1.1.2.1                 md = md.substring(oas.offset);
260 cananian 1.1.2.1             }
261 cananian 1.1.2.1             // return type (skip to the end...)
262 cananian 1.1.2.1             OffsetAndString ret_oas = munchTypeSig
263 cananian 1.1.2.1                 (md.substring(md.indexOf(')')+1));
264 cananian 1.15                if (!(isStaticInit || isConstructor)) {
265 cananian 1.15                    System.out.print(ret_oas.string);
266 cananian 1.15                    System.out.print(" ");
267 cananian 1.15                }
268 cananian 1.1.2.1             // method name!
269 cananian 1.15                if (isStaticInit)
270 cananian 1.15                    System.out.print("{}");
271 cananian 1.15                else if (isConstructor)
272 cananian 1.15                    System.out.print(desc2name("L"+raw.this_class().name()+";"));
273 cananian 1.15                else
274 cananian 1.15                    System.out.print(mi.name());
275 cananian 1.1.2.1             // parameters.
276 cananian 1.16                int argCount=0;
277 cananian 1.15                if (!isStaticInit) {
278 cananian 1.15                    System.out.print('(');
279 cananian 1.15                    assert md.charAt(0)=='(';
280 cananian 1.15                    for (int off=1; md.charAt(off)!=')'; ) {
281 cananian 1.15                        OffsetAndString param_oas = munchTypeSig(md.substring(off));
282 cananian 1.15                        if (off!=1) System.out.print(", ");
283 cananian 1.15                        if (isVarArgs &&
284 cananian 1.15                            md.charAt(off+param_oas.offset)==')' /* last arg */) {
285 cananian 1.15                            // print var arg parameter, omitting outermost array spec
286 cananian 1.15                            assert md.charAt(off)=='[';
287 cananian 1.15                            System.out.print(munchTypeSig(md.substring(off+1)).string);
288 cananian 1.15                            System.out.print("...");
289 cananian 1.15                        } else // ordinary, non-vararg parameter
290 cananian 1.15                            System.out.print(param_oas.string);
291 cananian 1.15                        off += param_oas.offset;
292 cananian 1.16                        argCount++;
293 cananian 1.15                    }
294 cananian 1.15                    System.out.print(')');
295 cananian 1.15                    // 'throws' list.
296 cananian 1.15                    md = md.substring(md.indexOf(')')+1+ret_oas.offset);
297 cananian 1.15                    for (int off=0; off < md.length() && md.charAt(off)=='^'; ) {
298 cananian 1.15                        off++;
299 cananian 1.15                        OffsetAndString thr_oas = munchTypeSig(md.substring(off));
300 cananian 1.15                        if (off==1) System.out.print(" throws ");
301 cananian 1.15                        else System.out.print(", ");
302 cananian 1.15                        System.out.print(thr_oas.string);
303 cananian 1.15                        off += thr_oas.offset;
304 cananian 1.15                    }
305 cananian 1.1.2.1             }
306 cananian 1.1.2.1             // done!
307 cananian 1.1.2.1             System.out.print(';');
308 cananian 1.1.2.1             System.out.println();
309 cananian 1.13                // print signatures
310 cananian 1.11                if (SIGNATURES) {
311 cananian 1.11                    System.out.println("  Signature: "+mi.descriptor());
312 cananian 1.11                    if (mis!=null)
313 cananian 1.11                        System.out.println("  Generic Signature: "+mis.signature());
314 cananian 1.13                }
315 cananian 1.13                // print code
316 cananian 1.14                AttributeCode ac = (AttributeCode)
317 cananian 1.14                    findAttribute(mi.attributes, AttributeCode.ATTRIBUTE_NAME);
318 cananian 1.14                if (DISASSEMBLE && ac!=null) {
319 cananian 1.13                    System.out.println("  Code:");
320 cananian 1.13                    if (MORE_INFO) {
321 cananian 1.16                        // Args_size doesn't seem to count 'long' and 'double'
322 cananian 1.16                        // entries twice.
323 cananian 1.16                        int args = argCount + (mi.access_flags.isStatic()?0:1);
324 cananian 1.16                        System.out.println("   "+
325 cananian 1.16                                           "Stack="+ac.max_stack+", "+
326 cananian 1.14                                           "Locals="+ac.max_locals+", "+
327 cananian 1.16                                           "Args_size="+args);
328 cananian 1.13                    }
329 cananian 1.16                    disassemble(ac);
330 cananian 1.13                }
331 cananian 1.13                // print line number table
332 cananian 1.14                AttributeLineNumberTable alnt = (AttributeLineNumberTable)
333 cananian 1.14                    (ac==null ? null :
334 cananian 1.14                     findAttribute(ac.attributes,
335 cananian 1.14                                   AttributeLineNumberTable.ATTRIBUTE_NAME));
336 cananian 1.14                if (LINE_NUMBER_TABLE && alnt!=null) {      
337 cananian 1.14                    LineNumberTable[] lnt = alnt.line_number_table;
338 cananian 1.13                    System.out.println("  LineNumberTable:");
339 cananian 1.14                    for (int j=0; j<lnt.length; j++)
340 cananian 1.14                        System.out.println("   line "+lnt[j].line_number+": "+
341 cananian 1.14                                           lnt[j].start_pc);
342 cananian 1.13                }
343 cananian 1.13                // print local variable table
344 cananian 1.14                AttributeLocalVariableTable alvt = (AttributeLocalVariableTable)
345 cananian 1.14                    (ac==null ? null :
346 cananian 1.14                     findAttribute(ac.attributes,
347 cananian 1.14                                   AttributeLocalVariableTable.ATTRIBUTE_NAME));
348 cananian 1.14                if (LOCAL_VARIABLE_TABLE && alvt!=null) {
349 cananian 1.14                    LocalVariableTable[] lvt = alvt.local_variable_table;
350 cananian 1.13                    System.out.println("  LocalVariableTable:");
351 cananian 1.13                    System.out.println("   Start  Length  Slot  Name   Signature");
352 cananian 1.14                    for (int j=0; j<lvt.length; j++)
353 cananian 1.14                        System.out.println("   "+lvt[j].start_pc+
354 cananian 1.14                                           "      "+lvt[j].length+
355 cananian 1.14                                           "      "+lvt[j].index+
356 cananian 1.14                                           "    "+lvt[j].name()+
357 cananian 1.14                                           "       "+lvt[j].descriptor());
358 cananian 1.11                }
359 cananian 1.14                if (!INDENT) System.out.println(); // match Sun javap spacing
360 cananian 1.1.2.1         }
361 cananian 1.1.2.1         System.out.println("}");
362 cananian 1.1.2.1     }
363 cananian 1.1.2.1 
364 cananian 1.1.2.1     static Attribute findAttribute(ClassFile cf, String name) {
365 cananian 1.1.2.1         return findAttribute(cf.attributes, name);
366 cananian 1.1.2.1     }
367 cananian 1.1.2.1     static Attribute findAttribute(Attribute[] attributes, String name) {
368 cananian 1.1.2.1         for (int i=0; i<attributes.length; i++)
369 cananian 1.1.2.1             if (attributes[i].attribute_name().equals(name))
370 cananian 1.1.2.1                 return attributes[i];
371 cananian 1.1.2.1         return null;
372 cananian 1.1.2.1     }
373 cananian 1.1.2.1 
374 cananian 1.12        static boolean access_flags_okay(AccessFlags af) {
375 cananian 1.12            if (PUBLIC_ONLY)
376 cananian 1.12                return af.isPublic();
377 cananian 1.12            else if (PUBLIC_PROTECTED_ONLY)
378 cananian 1.12                return af.isPublic() || af.isProtected();
379 cananian 1.12            else if (PUBLIC_PROTECTED_PACKAGE_PRIVATE)
380 cananian 1.12                return true;
381 cananian 1.12            else assert PUBLIC_PROTECTED_PACKAGE_ONLY;
382 cananian 1.12            return !af.isPrivate();
383 cananian 1.12        }
384 cananian 1.1.2.1     static String modString(AccessFlags af, boolean isClass) {
385 cananian 1.1.2.1         StringBuffer sb = new StringBuffer();
386 cananian 1.1.2.1         if (af.isPrivate()) sb.append("private ");
387 cananian 1.1.2.1         if (af.isProtected()) sb.append("protected ");
388 cananian 1.1.2.1         if (af.isPublic()) sb.append("public ");
389 cananian 1.1.2.1         if (af.isAbstract() && !af.isInterface())
390 cananian 1.1.2.1             sb.append("abstract ");
391 cananian 1.1.2.1         if (af.isStatic()) sb.append("static ");
392 cananian 1.1.2.1         if (af.isFinal()) sb.append("final ");
393 cananian 1.1.2.1         if (af.isTransient()) sb.append("transient ");
394 cananian 1.1.2.1         if (af.isVolatile()) sb.append("volatile ");
395 cananian 1.1.2.1         if (af.isSynchronized() && !isClass) sb.append("synchronized ");
396 cananian 1.1.2.1         if (af.isNative()) sb.append("native ");
397 cananian 1.1.2.1         if (af.isStrict()) sb.append("strict ");
398 cananian 1.1.2.1         if (af.isInterface()) sb.append("interface ");
399 cananian 1.1.2.1         else if (isClass) sb.append("class ");
400 cananian 1.1.2.1         return sb.toString();
401 cananian 1.1.2.1     }
402 cananian 1.1.2.1     static String desc2name(String descriptor) {
403 cananian 1.1.2.1         switch(descriptor.charAt(0)) {
404 cananian 1.1.2.1         case '[': // arrays
405 cananian 1.1.2.1             return desc2name(descriptor.substring(1))+"[]";
406 cananian 1.1.2.1          case 'L': // object type.
407 cananian 1.1.2.1              return descriptor
408 cananian 1.1.2.1                  .substring(1, descriptor.indexOf(';'))
409 cananian 1.1.2.1                  .replace('/','.');
410 cananian 1.1.2.1             // primitive types
411 cananian 1.1.2.1         case 'B': return "byte";
412 cananian 1.1.2.1         case 'C': return "char";
413 cananian 1.1.2.1         case 'D': return "double";
414 cananian 1.1.2.1         case 'F': return "float";
415 cananian 1.1.2.1         case 'I': return "int";
416 cananian 1.1.2.1         case 'J': return "long";
417 cananian 1.1.2.1         case 'S': return "short";
418 cananian 1.1.2.1         case 'Z': return "boolean";
419 cananian 1.1.2.1         case 'V': return "void";
420 cananian 1.1.2.1         default:
421 cananian 1.1.2.1             assert false : "bad descriptor: "+descriptor;
422 cananian 1.1.2.1             return "<unknown>";
423 cananian 1.1.2.1         }
424 cananian 1.1.2.1     }
425 cananian 1.1.2.1     // more sophisticated parser, for gj sigs.
426 cananian 1.1.2.1     static class OffsetAndString {
427 cananian 1.1.2.1         final String string;
428 cananian 1.1.2.1         final int offset;
429 cananian 1.1.2.1         OffsetAndString(String string, int offset) {
430 cananian 1.1.2.1             this.string = string; this.offset = offset;
431 cananian 1.1.2.1         }
432 cananian 1.1.2.1     }
433 cananian 1.1.2.1     static OffsetAndString munchParamPart(String psig) {
434 cananian 1.1.2.1         assert psig.charAt(0)=='<' && psig.indexOf('>')>0;
435 cananian 1.1.2.1         StringBuffer sb = new StringBuffer("<");
436 cananian 1.1.2.1         int off = 1;
437 cananian 1.1.2.1         boolean first = true;
438 cananian 1.1.2.1         while (psig.charAt(off)!='>') {
439 cananian 1.1.2.1             int colon = psig.indexOf(':', off);
440 cananian 1.1.2.1             String name = psig.substring(off, colon);
441 cananian 1.1.2.1             off = colon;
442 cananian 1.1.2.1             // make sb.
443 cananian 1.1.2.1             if (first) first=false;
444 cananian 1.1.2.1             else sb.append(", ");
445 cananian 1.1.2.1             sb.append(name);
446 cananian 1.1.2.1             // back to parsing.
447 cananian 1.1.2.1             boolean firstbound=true;
448 cananian 1.3                 // note that bounds of
449 cananian 1.3                 //    ':Ljava/lang/Object/Object;:Ljava/lang/Comparable;'
450 cananian 1.3                 // is different from (has a different erasure than)
451 cananian 1.3                 //    '::Ljava/lang/Comparable;'
452 cananian 1.3                 // [The first is declared as 'extends Object & Comparable'
453 cananian 1.3                 //  while the second is declared as 'extends Comparable' ]
454 cananian 1.1.2.1             while (psig.charAt(off)==':') {
455 cananian 1.1.2.1                 off++;
456 cananian 1.3                     if (psig.charAt(off)==':') {
457 cananian 1.3                         // no class type specified.
458 cananian 1.3                         continue;
459 cananian 1.3                     }
460 cananian 1.1.2.1                 OffsetAndString oas = munchTypeSig(psig.substring(off));
461 cananian 1.1.2.1                 off += oas.offset;
462 cananian 1.4                     // suppress 'extends java.lang.Object' with no other bounds.
463 cananian 1.4                     if (oas.string.equals("java.lang.Object") &&
464 cananian 1.4                         psig.charAt(off)!=':') continue;
465 cananian 1.1.2.1                 if (firstbound) { sb.append(" extends "); firstbound=false; }
466 cananian 1.1.2.1                 else sb.append(" & ");
467 cananian 1.1.2.1                 sb.append(oas.string);
468 cananian 1.1.2.1             }
469 cananian 1.1.2.1         }
470 cananian 1.1.2.1         off++;
471 cananian 1.1.2.1         sb.append(">");
472 cananian 1.1.2.1         return new OffsetAndString(sb.toString(), off);
473 cananian 1.1.2.1     }
474 cananian 1.1.2.1     static OffsetAndString munchClassTypeSig(String descriptor) {
475 cananian 1.1.2.1         assert descriptor.charAt(0)=='L';
476 cananian 1.1.2.1         StringBuffer sb = new StringBuffer();
477 cananian 1.1.2.1         int off;
478 cananian 1.1.2.1         int semi = descriptor.indexOf(';');
479 cananian 1.1.2.1         int brack= descriptor.indexOf('<');
480 cananian 1.6             if (brack > semi) brack=-1;
481 cananian 1.6             String id = ((brack!=-1) ?
482 cananian 1.6                          descriptor.substring(1, brack) :
483 cananian 1.6                          descriptor.substring(1, semi))
484 cananian 1.6                 .replace('/','.');
485 cananian 1.6             sb.append(id);
486 cananian 1.6             if (brack!=-1) {
487 cananian 1.1.2.1             // ooh, ooh, type parameters!
488 cananian 1.1.2.1             off = brack;
489 cananian 1.1.2.1             OffsetAndString oas = munchTypeArguments
490 cananian 1.1.2.1                 (descriptor.substring(off));
491 cananian 1.1.2.1             sb.append(oas.string);
492 cananian 1.1.2.1             off+=oas.offset;
493 cananian 1.1.2.1             assert descriptor.charAt(off)==';';
494 cananian 1.1.2.1             off++;
495 cananian 1.1.2.1         } else {
496 cananian 1.6                 off = semi+1;
497 cananian 1.1.2.1         }
498 cananian 1.6             // optional '.L ID<type args>;'
499 cananian 1.1.2.1         while (off < descriptor.length() && descriptor.charAt(off)=='.') {
500 cananian 1.6                 assert descriptor.charAt(off+1)=='L';
501 cananian 1.6                 off+=2;
502 cananian 1.6                 int semi2 = descriptor.indexOf(';', off);
503 cananian 1.6                 int brack2= descriptor.indexOf('<', off);
504 cananian 1.6                 // find the proper name.
505 cananian 1.6                 if (brack2 > semi2) brack2=-1;
506 cananian 1.6                 String id2 = ((brack2!=-1) ?
507 cananian 1.6                               descriptor.substring(off, brack2) :
508 cananian 1.6                               descriptor.substring(off, semi2))
509 cananian 1.6                     .replace('/','.');
510 cananian 1.6                 // remove bits we've already emitted & emit the rest.
511 cananian 1.6                 assert id2.startsWith(id);
512 cananian 1.6                 assert id2.substring(id.length()).startsWith("$");
513 cananian 1.6                 sb.append('.');
514 cananian 1.6                 sb.append(id2.substring(1+id.length()));
515 cananian 1.6                 id=id2;
516 cananian 1.6                 if (brack2!=-1) {
517 cananian 1.6                     // optional type parameters
518 cananian 1.6                     off = brack2;
519 cananian 1.1.2.1                 OffsetAndString oas = munchTypeArguments
520 cananian 1.1.2.1                     (descriptor.substring(off));
521 cananian 1.1.2.1                 sb.append(oas.string);
522 cananian 1.1.2.1                 off+=oas.offset;
523 cananian 1.6                     assert descriptor.charAt(off)==';';
524 cananian 1.6                     off++;
525 cananian 1.6                 } else {
526 cananian 1.6                     off = semi2+1;
527 cananian 1.1.2.1             }
528 cananian 1.1.2.1         }
529 cananian 1.1.2.1         // okay, finally done.
530 cananian 1.1.2.1         return new OffsetAndString(sb.toString(), off);
531 cananian 1.1.2.1     }
532 cananian 1.1.2.1     static OffsetAndString munchTypeArguments(String descriptor) {
533 cananian 1.1.2.1         assert descriptor.charAt(0)=='<';
534 cananian 1.1.2.1         assert descriptor.indexOf('>')!=-1;
535 cananian 1.1.2.1         StringBuffer sb = new StringBuffer();
536 cananian 1.1.2.1         int off = 1;
537 cananian 1.1.2.1         sb.append('<');
538 cananian 1.1.2.1         boolean first=true;
539 cananian 1.1.2.1         while (descriptor.charAt(off)!='>') {
540 cananian 1.1.2.1             OffsetAndString oas =
541 cananian 1.5                     munchVariantTypeSig(descriptor.substring(off));
542 cananian 1.1.2.1             if (first) first=false;
543 cananian 1.1.2.1             else sb.append(", ");
544 cananian 1.1.2.1             sb.append(oas.string);
545 cananian 1.1.2.1             off+=oas.offset;
546 cananian 1.1.2.1         }
547 cananian 1.6             assert descriptor.charAt(off)=='>';
548 cananian 1.1.2.1         sb.append('>');
549 cananian 1.1.2.1         off++;
550 cananian 1.1.2.1         return new OffsetAndString(sb.toString(), off);
551 cananian 1.1.2.1     }
552 cananian 1.1.2.1     static OffsetAndString munchMethodTypeSig(String descriptor) {
553 cananian 1.1.2.1         assert descriptor.charAt(0)=='<' || descriptor.charAt(0)=='(';
554 cananian 1.1.2.1         StringBuffer sb = new StringBuffer();
555 cananian 1.1.2.1         int off = 0;
556 cananian 1.1.2.1         if (descriptor.charAt(off)=='<') {
557 cananian 1.1.2.1             OffsetAndString oas = munchParamPart(descriptor);
558 cananian 1.1.2.1             sb.append(oas.string);
559 cananian 1.1.2.1             off+=oas.offset;
560 cananian 1.1.2.1         }
561 cananian 1.1.2.1         assert descriptor.charAt(off)=='(';
562 cananian 1.1.2.1         off++;
563 cananian 1.1.2.1         while (descriptor.charAt(off)!=')') {
564 cananian 1.1.2.1             // method parameters
565 cananian 1.1.2.1             OffsetAndString oas = munchTypeSig(descriptor.substring(off));
566 cananian 1.1.2.1             off+=oas.offset;
567 cananian 1.1.2.1         }
568 cananian 1.1.2.1         off++;
569 cananian 1.1.2.1         // return value type.
570 cananian 1.1.2.1         {
571 cananian 1.1.2.1             OffsetAndString oas = munchTypeSig(descriptor.substring(off));
572 cananian 1.1.2.1             off+=oas.offset;
573 cananian 1.1.2.1         }
574 cananian 1.1.2.1         // optional throws signatures.
575 cananian 1.1.2.1         while (off < descriptor.length() && descriptor.charAt(off)=='^') {
576 cananian 1.1.2.1             off++;
577 cananian 1.1.2.1             OffsetAndString oas = munchTypeSig(descriptor.substring(off));
578 cananian 1.1.2.1             off+=oas.offset;
579 cananian 1.1.2.1         }
580 cananian 1.1.2.1         // done.
581 cananian 1.1.2.1         return new OffsetAndString(sb.toString(), off);
582 cananian 1.1.2.1     }
583 cananian 1.5         static OffsetAndString munchVariantTypeSig(String descriptor) {
584 cananian 1.5             StringBuffer sb = new StringBuffer();
585 cananian 1.5             int off=0;
586 cananian 1.5             // first characters in signature could be variance specifiers -/+/=/*
587 cananian 1.5             switch(descriptor.charAt(off)) {
588 cananian 1.5             case '*':
589 cananian 1.8                 return new OffsetAndString("?", 1);
590 cananian 1.5             case '-':
591 cananian 1.8                 sb.append("? super "); off++; break;
592 cananian 1.5             case '+':
593 cananian 1.8                 sb.append("? extends "); off++; break;
594 cananian 1.5             case '=':
595 cananian 1.8                 assert false : "= is no longer supported in GJ prototype 2.2";
596 cananian 1.5                 sb.append(descriptor.charAt(off++));
597 cananian 1.5                 break;
598 cananian 1.5             }
599 cananian 1.5             // rest is a standard type signature
600 cananian 1.5             OffsetAndString oas = munchTypeSig(descriptor.substring(off));
601 cananian 1.5             sb.append(oas.string);
602 cananian 1.5             off+=oas.offset;
603 cananian 1.5             return new OffsetAndString(sb.toString(), off);
604 cananian 1.5         }
605 cananian 1.7         static OffsetAndString munchArrayTypeSig(String descriptor) {
606 cananian 1.7             assert descriptor.charAt(0)=='[';
607 cananian 1.7             StringBuffer sb = new StringBuffer();
608 cananian 1.7             int off=0;
609 cananian 1.7             while (descriptor.charAt(off)=='[') {
610 cananian 1.7                 sb.append('[');
611 cananian 1.7                 // there could be variance specifiers -/+/=
612 cananian 1.7                 switch(descriptor.charAt(++off)) { // no '*' allowed!
613 cananian 1.7                 case '-':
614 cananian 1.7                 case '+':
615 cananian 1.7                 case '=':
616 cananian 1.8                     assert false : "array variance no longer supported";
617 cananian 1.7                     sb.append(descriptor.charAt(off++));
618 cananian 1.7                     break;
619 cananian 1.7                 }
620 cananian 1.7                 sb.append(']');
621 cananian 1.7             }
622 cananian 1.7             // okay, parse the rest
623 cananian 1.7             OffsetAndString oas = munchTypeSig(descriptor.substring(off));
624 cananian 1.7             sb.insert(0, oas.string); // reverse the pieces.
625 cananian 1.7             off+=oas.offset;
626 cananian 1.7             // done!
627 cananian 1.7             return new OffsetAndString(sb.toString(), off);
628 cananian 1.7         }
629 cananian 1.1.2.1     static OffsetAndString munchTypeSig(String descriptor) {
630 cananian 1.1.2.1         switch(descriptor.charAt(0)) {
631 cananian 1.7             case '[': // arrays
632 cananian 1.7                 return munchArrayTypeSig(descriptor);
633 cananian 1.1.2.1          case 'L': // object type.
634 cananian 1.1.2.1              return munchClassTypeSig(descriptor);
635 cananian 1.1.2.1         case 'T': // type variable signature
636 cananian 1.1.2.1             return new OffsetAndString
637 cananian 1.1.2.1                 (descriptor.substring(1, descriptor.indexOf(';')),
638 cananian 1.1.2.1                  descriptor.indexOf(';')+1);
639 cananian 1.1.2.1         case '<':
640 cananian 1.1.2.1         case '(': // method type signature
641 cananian 1.1.2.1             return munchMethodTypeSig(descriptor);
642 cananian 1.1.2.1             // primitive types
643 cananian 1.1.2.1         case 'B': return new OffsetAndString("byte", 1);
644 cananian 1.1.2.1         case 'C': return new OffsetAndString("char", 1);
645 cananian 1.1.2.1         case 'D': return new OffsetAndString("double", 1);
646 cananian 1.1.2.1         case 'F': return new OffsetAndString("float", 1);
647 cananian 1.1.2.1         case 'I': return new OffsetAndString("int", 1);
648 cananian 1.1.2.1         case 'J': return new OffsetAndString("long", 1);
649 cananian 1.1.2.1         case 'S': return new OffsetAndString("short", 1);
650 cananian 1.1.2.1         case 'Z': return new OffsetAndString("boolean", 1);
651 cananian 1.1.2.1         case 'V': return new OffsetAndString("void", 1);
652 cananian 1.1.2.1         default:
653 cananian 1.1.2.1             assert false : "bad descriptor: "+descriptor;
654 cananian 1.1.2.1             return new OffsetAndString("<unknown>", 1);
655 cananian 1.1.2.1         }
656 cananian 1.16        }
657 cananian 1.16        static void disassemble(AttributeCode code) {
658 cananian 1.16            // use harpoon.IR.Bytecode.Op, etc.
659 cananian 1.16            //for (int pc=0; i<xxx; i++)
660 cananian 1.16            System.out.println("   0:   aload_0");
661 cananian 1.16            assert false : "unimplemented";
662 cananian 1.1.2.1     }
663 cananian 1.2     }