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 }