/src/kilim/tools/DumpClass.java

http://github.com/kilim/kilim · Java · 428 lines · 360 code · 51 blank · 17 comment · 44 complexity · 9977bba56d7808df0549545d969fc852 MD5 · raw file

  1. /* Copyright (c) 2006, Sriram Srinivasan
  2. *
  3. * You may distribute this software under the terms of the license
  4. * specified in the file "License"
  5. */
  6. package kilim.tools;
  7. import static kilim.analysis.Utils.dedent;
  8. import static kilim.analysis.Utils.indent;
  9. import static kilim.analysis.Utils.p;
  10. import static kilim.analysis.Utils.pn;
  11. import static kilim.analysis.Utils.resetIndentation;
  12. import java.io.FileInputStream;
  13. import java.io.IOException;
  14. import java.io.InputStream;
  15. import java.lang.reflect.Modifier;
  16. import java.util.Enumeration;
  17. import java.util.Formatter;
  18. import java.util.HashMap;
  19. import java.util.jar.JarEntry;
  20. import java.util.jar.JarFile;
  21. import java.util.zip.ZipEntry;
  22. import kilim.Constants;
  23. import kilim.analysis.TypeDesc;
  24. import org.objectweb.asm.AnnotationVisitor;
  25. import org.objectweb.asm.Attribute;
  26. import org.objectweb.asm.ClassReader;
  27. import org.objectweb.asm.ClassVisitor;
  28. import org.objectweb.asm.FieldVisitor;
  29. import org.objectweb.asm.Handle;
  30. import org.objectweb.asm.Label;
  31. import org.objectweb.asm.MethodVisitor;
  32. import org.objectweb.asm.Opcodes;
  33. /**
  34. * Equivalent to javap -c -l -private, but the output is in jasmin's format
  35. * meant to be parseable by Asm.
  36. * @author sriram
  37. */
  38. public class DumpClass extends ClassVisitor implements Opcodes {
  39. static boolean lineNumbers = true;
  40. public static void main(String[] args) throws IOException {
  41. String name = args.length == 2 ? args[1] : args[0];
  42. if (name.endsWith(".jar")) {
  43. try {
  44. Enumeration<JarEntry> e = new JarFile(name).entries();
  45. while (e.hasMoreElements()) {
  46. ZipEntry en = (ZipEntry) e.nextElement();
  47. String n = en.getName();
  48. if (!n.endsWith(".class")) continue;
  49. n = n.substring(0, n.length() - 6).replace('/','.');
  50. new DumpClass(n);
  51. }
  52. } catch (Exception e) {
  53. e.printStackTrace();
  54. }
  55. } else {
  56. new DumpClass(name);
  57. }
  58. }
  59. public DumpClass(InputStream is) throws IOException {
  60. super(Constants.KILIM_ASM);
  61. ClassReader cr = new ClassReader(is);
  62. cr.accept(this, /*flags*/ 0);
  63. }
  64. public DumpClass(String className) throws IOException {
  65. super(Constants.KILIM_ASM);
  66. ClassReader cr;
  67. if (className.endsWith(".class")) {
  68. FileInputStream fis = new FileInputStream(className);
  69. cr = new ClassReader(fis);
  70. } else {
  71. cr = new ClassReader(className);
  72. }
  73. cr.accept(this, /*flags*/ClassReader.EXPAND_FRAMES);
  74. }
  75. public void visit(int version, int access, String name, String signature,
  76. String superName, String[] interfaces)
  77. {
  78. p(".class ");
  79. p(Modifier.toString(access));
  80. p(" ");
  81. pn(name);
  82. if (superName != null)
  83. pn(".super " + superName);
  84. if (interfaces != null) {
  85. for (int i = 0; i < interfaces.length; i++) {
  86. p(".implements ");
  87. pn(interfaces[i]);
  88. }
  89. }
  90. }
  91. public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
  92. pn(".annotation " + (visible ? "visible " : "") + desc);
  93. pn(".end annotation");
  94. return new DummyAnnotationVisitor();
  95. }
  96. public void visitAttribute(Attribute attr) {}
  97. public void visitEnd() {}
  98. public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
  99. p(".field ");
  100. p(Modifier.toString(access));
  101. p(" ");
  102. p(name);
  103. p(" ");
  104. p(desc);
  105. if (value != null) {
  106. p(" = ");
  107. if (value instanceof String) {
  108. pn("\"" + value + "\"");
  109. } else {
  110. pn(value.toString());
  111. }
  112. } else {
  113. pn();
  114. }
  115. return null;
  116. }
  117. public void visitInnerClass(String name, String outerName, String innerName, int access) {
  118. }
  119. public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
  120. pn("");
  121. pn("; -------------------------------------------------------------");
  122. p(".method ");
  123. p(Modifier.toString(access));
  124. p(" ");
  125. p(name);
  126. pn(desc);
  127. pn("; signature = " + signature);
  128. pn("; -------------------------------------------------------------\n");
  129. if (exceptions != null) {
  130. for (int i = 0; i < exceptions.length; i++) {
  131. p(".throws ");
  132. pn(exceptions[i]);
  133. }
  134. }
  135. return new DumpMethodVisitor();
  136. }
  137. public void visitOuterClass(String owner, String name, String desc) {
  138. }
  139. // fixme - if jasmin supports nestmates, then these should output the correct syntax
  140. public void visitNestMember(String nestMember) {}
  141. public void visitNestHost(String nestHost) {}
  142. public void visitSource(String source, String debug) {}
  143. }
  144. class DummyAnnotationVisitor extends AnnotationVisitor {
  145. public DummyAnnotationVisitor() {
  146. super(Constants.KILIM_ASM);
  147. // TODO Auto-generated constructor stub
  148. }
  149. public void visit(String name, Object value) {
  150. // System.out.println("visit: name = " + name + ", value = " + value);
  151. }
  152. public AnnotationVisitor visitAnnotation(String name, String desc) {
  153. // System.out.println("visitAnnotation: name = " + name + ", desc = " + desc);
  154. return this;
  155. }
  156. public AnnotationVisitor visitArray(String name) {
  157. // System.out.println("visitArray: name = " + name);
  158. return this;
  159. }
  160. public void visitEnd() {
  161. // System.out.println("visitEnd");
  162. }
  163. public void visitEnum(String name, String desc, String value) {
  164. // System.out.println("visitEnum: " + name + ", desc = " + desc + ", value = " + value);
  165. }
  166. }
  167. class DumpMethodVisitor extends MethodVisitor implements Opcodes {
  168. public DumpMethodVisitor() {
  169. super(Constants.KILIM_ASM);
  170. }
  171. static String[] os = {
  172. "nop","aconst_null","iconst_m1","iconst_0","iconst_1","iconst_2",
  173. "iconst_3","iconst_4","iconst_5","lconst_0","lconst_1","fconst_0",
  174. "fconst_1","fconst_2","dconst_0","dconst_1","bipush","sipush",
  175. "ldc","ldc_w","ldc_w","iload","lload","fload","dload","aload",
  176. "iload_0","iload_1","iload_2","iload_3","lload_0","lload_1","lload_2",
  177. "lload_3","fload_0","fload_1","fload_2","fload_3","dload_0","dload_1",
  178. "dload_2","dload_3","aload_0","aload_1","aload_2","aload_3","iaload",
  179. "laload","faload","daload","aaload","baload","caload","saload",
  180. "istore","lstore","fstore","dstore","astore","istore_0","istore_1",
  181. "istore_2","istore_3","lstore_0","lstore_1","lstore_2","lstore_3",
  182. "fstore_0","fstore_1","fstore_2","fstore_3","dstore_0","dstore_1",
  183. "dstore_2","dstore_3","astore_0","astore_1","astore_2","astore_3",
  184. "iastore","lastore","fastore","dastore","aastore","bastore",
  185. "castore","sastore","pop","pop2","dup","dup_x1","dup_x2","dup2",
  186. "dup2_x1","dup2_x2","swap","iadd","ladd","fadd","dadd","isub",
  187. "lsub","fsub","dsub","imul","lmul","fmul","dmul","idiv","ldiv",
  188. "fdiv","ddiv","irem","lrem","frem","drem","ineg","lneg","fneg","dneg",
  189. "ishl","lshl","ishr","lshr","iushr","lushr","iand","land","ior","lor",
  190. "ixor","lxor","iinc","i2l","i2f","i2d","l2i","l2f","l2d","f2i","f2l",
  191. "f2d","d2i","d2l","d2f","i2b","i2c","i2s","lcmp","fcmpl","fcmpg",
  192. "dcmpl","dcmpg","ifeq","ifne","iflt","ifge","ifgt","ifle","if_icmpeq",
  193. "if_icmpne","if_icmplt","if_icmpge","if_icmpgt","if_icmple","if_acmpeq",
  194. "if_acmpne","goto","jsr","ret","tableswitch","lookupswitch","ireturn",
  195. "lreturn","freturn","dreturn","areturn","return","getstatic",
  196. "putstatic","getfield","putfield","invokevirtual","invokespecial",
  197. "invokestatic","invokeinterface","unused","new","newarray","anewarray",
  198. "arraylength","athrow","checkcast","instanceof","monitorenter",
  199. "monitorexit","wide","multianewarray","ifnull","ifnonnull","goto_w","jsr_w"
  200. };
  201. int line = 0;
  202. static StringBuilder fsb = new StringBuilder(100);
  203. static Formatter formatter = new Formatter(fsb);
  204. public void ppn(String s) {
  205. if (DumpClass.lineNumbers) {
  206. fsb.setLength(0);
  207. formatter.format("%-70s ; %d", s, (line++));
  208. pn(fsb.toString());
  209. } else {
  210. pn(s);
  211. }
  212. }
  213. public void visitFieldInsn(int opcode, String owner, String name, String desc) {
  214. ppn(os[opcode] + " " + owner + "/" + name + " " + desc);
  215. }
  216. public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
  217. pn("; Frame " + type);
  218. p ("; Locals - ");
  219. for(int i = 0; i < nLocal; i++) {
  220. Object o = local[i];
  221. System.out.print("#" + i + "." + type(o) + " ");
  222. }
  223. System.out.println();
  224. p("; Stack - ");
  225. for(int i = 0; i < nStack; i++) {
  226. Object o = stack[i];
  227. System.out.print("#" + i + "." + type(o) + " ");
  228. }
  229. System.out.println("");
  230. }
  231. private String type(Object o) {
  232. if (o == null) {
  233. return "null";
  234. } else if (o instanceof Integer) {
  235. switch (((Integer)o).intValue()) {
  236. case 0: return "Top";
  237. case 1: return "Integer";
  238. case 2: return "Float";
  239. case 3: return "Double";
  240. case 4: return "Long";
  241. case 5: return "Null";
  242. case 6: return "Uninitialized_This"; }
  243. } else if (o instanceof String) {
  244. return (String)o;
  245. }
  246. return "??UNKNOWN??" + o.getClass() + ":" + o;
  247. }
  248. public void visitIincInsn(int var, int increment) {
  249. ppn("iinc " + var + " " + increment);
  250. }
  251. public void visitInsn(int opcode) {
  252. ppn(os[opcode]);
  253. }
  254. public void visitIntInsn(int opcode, int operand) {
  255. if (opcode == NEWARRAY) {
  256. String t = "UNDEFINED";
  257. switch (operand) {
  258. case T_BOOLEAN: t = " boolean"; break;
  259. case T_CHAR: t = " char"; break;
  260. case T_FLOAT: t = " float"; break;
  261. case T_DOUBLE: t = " double"; break;
  262. case T_BYTE: t = " byte"; break;
  263. case T_SHORT: t = " short"; break;
  264. case T_INT: t = " int"; break;
  265. case T_LONG: t = " long"; break;
  266. }
  267. ppn(os[opcode] + t);
  268. } else {
  269. ppn(os[opcode] + " " +operand);
  270. }
  271. }
  272. public void visitJumpInsn(int opcode, Label label) {
  273. ppn(os[opcode] + " " + lab(label));
  274. }
  275. public void visitLabel(Label label) {
  276. dedent(2);
  277. pn(lab(label) + ":");
  278. indent(2);
  279. }
  280. public void visitLdcInsn(Object cst) {
  281. String op = (cst instanceof Double) || (cst instanceof Long) ? "ldc2_w " : "ldc ";
  282. String type = (cst instanceof String) ? "\"" + esc((String)cst) + "\"" : cst.toString();
  283. ppn(op + type);
  284. }
  285. public void visitLineNumber(int line, Label start) {
  286. pn(".line " + line);
  287. }
  288. public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
  289. pn(".var " + index + " is "+ name + " " + desc + " from " + lab(start) + " to " + lab(end));
  290. }
  291. public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
  292. ppn("lookupswitch");
  293. indent(4);
  294. for (int i= 0; i < keys.length; i++) {
  295. pn(keys[i] + ": " + lab(labels[i]));
  296. }
  297. pn("default: " + lab(dflt));
  298. dedent(4);
  299. }
  300. public void visitMethodInsn(int opcode, String owner, String name, String desc,boolean itf) {
  301. String str = os[opcode] + " " + owner + "/" + name + desc;
  302. if (opcode == INVOKEINTERFACE) {
  303. ppn(str + ", " + (TypeDesc.getNumArgumentTypes(desc)+1));
  304. } else {
  305. ppn(str);
  306. }
  307. }
  308. public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
  309. Object... bsmArgs) {
  310. ppn("invokedynamic " + name + desc);
  311. indent(4);
  312. pn("; bootstrap = " + bsm.getOwner() + "." + bsm.getName() + bsm.getDesc());
  313. for (int i = 0; i < bsmArgs.length; i++) {
  314. pn("; arg[" + i + "] = " + bsmArgs[0]);
  315. }
  316. dedent(4);
  317. }
  318. public void visitMultiANewArrayInsn(String desc, int dims) {
  319. ppn("multinewarray " + desc + " " + dims) ;
  320. }
  321. public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
  322. ppn("tableswitch " + min);
  323. indent(4);
  324. for (int i = min; i <= max; i++) {
  325. pn(lab(labels[i - min]));
  326. }
  327. pn("default: " + lab(dflt));
  328. dedent(4);
  329. }
  330. public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
  331. pn(".catch " + type + " from " + lab(start) + " to " + lab(end) +
  332. " using " + lab(handler));
  333. }
  334. public void visitTypeInsn(int opcode, String desc) {
  335. ppn(os[opcode] + " " +desc);
  336. }
  337. public void visitVarInsn(int opcode, int var) {
  338. ppn(os[opcode] + " " + var);
  339. }
  340. HashMap<Label,String> labels = new HashMap<Label, String>();
  341. int labCount = 1;
  342. private String lab(Label label) {
  343. String ret = labels.get(label);
  344. if (ret == null) {
  345. ret = "L"+ labCount++;
  346. labels.put(label, ret);
  347. }
  348. return ret;
  349. }
  350. public AnnotationVisitor visitAnnotationDefault() {
  351. return new DummyAnnotationVisitor();
  352. }
  353. public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
  354. pn(".annotation " + (visible ? "visible " : "") + desc);
  355. pn(".end annotation");
  356. return new DummyAnnotationVisitor();
  357. }
  358. public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
  359. return new DummyAnnotationVisitor();
  360. }
  361. public void visitAttribute(Attribute attr) {
  362. }
  363. public void visitCode() {
  364. indent(4);
  365. }
  366. public void visitMaxs(int maxStack, int maxLocals) {
  367. pn(".limit stack " + maxStack);
  368. pn(".limit locals " + maxLocals);
  369. }
  370. public void visitEnd() {
  371. resetIndentation();
  372. pn(".end method");
  373. }
  374. private static String esc(String s) {
  375. return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n");
  376. }
  377. }