PageRenderTime 107ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/JavaInsight/javainsight/JasminVisitor.java

#
Java | 307 lines | 226 code | 61 blank | 20 comment | 42 complexity | 672b823d1e071d71d3f828662044ed1e MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. package javainsight;
  2. import java.io.*;
  3. import java.util.*;
  4. import org.apache.bcel.classfile.Attribute;
  5. import org.apache.bcel.classfile.ClassParser;
  6. import org.apache.bcel.classfile.Code;
  7. import org.apache.bcel.classfile.ConstantValue;
  8. import org.apache.bcel.classfile.Deprecated;
  9. import org.apache.bcel.classfile.ExceptionTable;
  10. import org.apache.bcel.classfile.Field;
  11. import org.apache.bcel.classfile.JavaClass;
  12. import org.apache.bcel.classfile.Method;
  13. import org.apache.bcel.classfile.Synthetic;
  14. import org.apache.bcel.classfile.Utility;
  15. import org.apache.bcel.generic.*;
  16. import org.apache.bcel.Constants;
  17. import org.apache.bcel.Repository;
  18. /**
  19. * Disassemble Java class object into the <A HREF="http://www.cat.nyu.edu/meyer/jasmin">
  20. * JASMIN</A> format.
  21. *
  22. * @version $Id: JasminVisitor.java 9456 2007-04-18 20:09:54Z dmoebius $
  23. * @author <A HREF="http://www.berlin.de/~markus.dahm/">M. Dahm</A>
  24. */
  25. public class JasminVisitor extends org.apache.bcel.classfile.EmptyVisitor
  26. {
  27. private JavaClass clazz;
  28. private PrintWriter out;
  29. private String class_name;
  30. private ConstantPoolGen cp;
  31. public JasminVisitor(JavaClass clazz, Writer out) {
  32. this.clazz = clazz;
  33. this.out = new PrintWriter(out);
  34. class_name = clazz.getClassName();
  35. cp = new ConstantPoolGen(clazz.getConstantPool());
  36. }
  37. /**
  38. * Start traversal using DefaultVisitor pattern.
  39. */
  40. public void disassemble() {
  41. new org.apache.bcel.classfile.DescendingVisitor(clazz, this).visit();
  42. out.close();
  43. }
  44. @Override
  45. public void visitJavaClass(JavaClass clazz) {
  46. out.println(";; Produced by JasminVisitor");
  47. out.println(";; http://jakarta.apache.org/bcel");
  48. out.println(";; " + new Date() + "\n");
  49. out.println(".source " + clazz.getSourceFileName());
  50. out.println("." + Utility.classOrInterface(clazz.getAccessFlags()) + " " +
  51. Utility.accessToString(clazz.getAccessFlags(), true) +
  52. " " + clazz.getClassName().replace('.', '/'));
  53. out.println(".super " + clazz.getSuperclassName().replace('.', '/'));
  54. String[] interfaces = clazz.getInterfaceNames();
  55. for(int i=0; i < interfaces.length; i++)
  56. out.println(".implements " + interfaces[i].replace('.', '/'));
  57. out.print("\n");
  58. }
  59. @Override
  60. public void visitField(Field field) {
  61. out.print(".field " + Utility.accessToString(field.getAccessFlags()) +
  62. " " + field.getName() + " " + field.getSignature());
  63. if(field.getAttributes().length == 0)
  64. out.print("\n");
  65. }
  66. @Override
  67. public void visitConstantValue(ConstantValue cv) {
  68. out.println(" = " + cv);
  69. }
  70. private Method method;
  71. /**
  72. * Unfortunately Jasmin expects ".end method" after each method. Thus we've to check
  73. * for every of the method's attributes if it's the last one and print ".end method"
  74. * then.
  75. */
  76. private final void printEndMethod(Attribute attr) {
  77. Attribute[] attributes = method.getAttributes();
  78. if(attr == attributes[attributes.length - 1])
  79. out.println(".end method");
  80. }
  81. @Override
  82. public void visitDeprecated(Deprecated attribute) {
  83. printEndMethod(attribute);
  84. }
  85. @Override
  86. public void visitSynthetic(Synthetic attribute) {
  87. printEndMethod(attribute);
  88. }
  89. @Override
  90. public void visitMethod(Method method) {
  91. out.println("\n.method " + Utility.accessToString(method.getAccessFlags()) +
  92. " " + method.getName() + method.getSignature());
  93. this.method = method; // Remember for use in subsequent visitXXX calls
  94. Attribute[] attributes = method.getAttributes();
  95. if((attributes == null) || (attributes.length == 0))
  96. out.println(".end method");
  97. }
  98. @Override
  99. public void visitExceptionTable(ExceptionTable e) {
  100. String[] names = e.getExceptionNames();
  101. for(int i=0; i < names.length; i++)
  102. out.println(".throws " + names[i].replace('.', '/'));
  103. printEndMethod(e);
  104. }
  105. private HashMap<InstructionHandle,String> map;
  106. @Override
  107. public void visitCode(Code code) {
  108. int label_counter = 0;
  109. out.println(".limit stack " + code.getMaxStack());
  110. out.println(".limit locals " + code.getMaxLocals());
  111. MethodGen mg = new MethodGen(method, class_name, cp);
  112. InstructionList il = mg.getInstructionList();
  113. InstructionHandle[] ihs = il.getInstructionHandles();
  114. /* Pass 1: Give all referenced instruction handles a symbolic name, i.e. a
  115. * label.
  116. */
  117. map = new HashMap<InstructionHandle,String>();
  118. for(int i=0; i < ihs.length; i++) {
  119. if(ihs[i] instanceof BranchHandle) {
  120. BranchInstruction bi = (BranchInstruction)ihs[i].getInstruction();
  121. if(bi instanceof Select) { // Special cases LOOKUPSWITCH and TABLESWITCH
  122. InstructionHandle[] targets = ((Select)bi).getTargets();
  123. for(int j=0; j < targets.length; j++)
  124. put(targets[j], "Label" + label_counter++ + ":");
  125. }
  126. InstructionHandle ih = bi.getTarget();
  127. put(ih, "Label" + label_counter++ + ":");
  128. }
  129. }
  130. LocalVariableGen[] lvs = mg.getLocalVariables();
  131. for(int i=0; i < lvs.length; i++) {
  132. InstructionHandle ih = lvs[i].getStart();
  133. put(ih, "Label" + label_counter++ + ":");
  134. ih = lvs[i].getEnd();
  135. put(ih, "Label" + label_counter++ + ":");
  136. }
  137. CodeExceptionGen[] ehs = mg.getExceptionHandlers();
  138. for(int i=0; i < ehs.length; i++) {
  139. CodeExceptionGen c = ehs[i];
  140. InstructionHandle ih = c.getStartPC();
  141. put(ih, "Label" + label_counter++ + ":");
  142. ih = c.getEndPC();
  143. put(ih, "Label" + label_counter++ + ":");
  144. ih = c.getHandlerPC();
  145. put(ih, "Label" + label_counter++ + ":");
  146. }
  147. LineNumberGen[] lns = mg.getLineNumbers();
  148. for(int i=0; i < lns.length; i++) {
  149. InstructionHandle ih = lns[i].getInstruction();
  150. put(ih, ".line " + lns[i].getSourceLine());
  151. }
  152. /* Pass 2: Output code.
  153. */
  154. for(int i=0; i < lvs.length; i++) {
  155. LocalVariableGen l = lvs[i];
  156. out.println(".var " + l.getIndex() + " is " + l.getName() + " " +
  157. l.getType().getSignature() +
  158. " from " + get(l.getStart()) +
  159. " to " + get(l.getEnd()));
  160. }
  161. out.print("\n");
  162. for(int i=0; i < ihs.length; i++) {
  163. InstructionHandle ih = ihs[i];
  164. Instruction inst = ih.getInstruction();
  165. String str = map.get(ih);
  166. if(str != null)
  167. out.println(str);
  168. if(inst instanceof BranchInstruction) {
  169. if(inst instanceof Select) { // Special cases LOOKUPSWITCH and TABLESWITCH
  170. Select s = (Select)inst;
  171. int[] matchs = s.getMatchs();
  172. InstructionHandle[] targets = s.getTargets();
  173. if(s instanceof TABLESWITCH) {
  174. out.println("\ttableswitch " + matchs[0] + " " +
  175. matchs[matchs.length - 1]);
  176. for(int j=0; j < targets.length; j++)
  177. out.println("\t\t" + get(targets[j]));
  178. } else { // LOOKUPSWITCH
  179. out.println("\tlookupswitch ");
  180. for(int j=0; j < targets.length; j++)
  181. out.println("\t\t" + matchs[j] + " : " + get(targets[j]));
  182. }
  183. out.println("\t\tdefault: " + get(s.getTarget())); // Applies for both
  184. } else {
  185. BranchInstruction bi = (BranchInstruction)inst;
  186. ih = bi.getTarget();
  187. str = get(ih);
  188. out.println("\t" + Constants.OPCODE_NAMES[bi.getOpcode()] + " " + str);
  189. }
  190. }
  191. else
  192. out.println("\t" + inst.toString(cp.getConstantPool()));
  193. }
  194. out.print("\n");
  195. for(int i=0; i < ehs.length; i++) {
  196. CodeExceptionGen c = ehs[i];
  197. ObjectType caught = c.getCatchType();
  198. String class_name = (caught == null)? // catch any exception, used when compiling finally
  199. "all" : caught.getClassName().replace('.', '/');
  200. out.println(".catch " + class_name + " from " +
  201. get(c.getStartPC()) + " to " + get(c.getEndPC()) +
  202. " using " + get(c.getHandlerPC()));
  203. }
  204. printEndMethod(code);
  205. }
  206. private final String get(InstructionHandle ih) {
  207. String str = new StringTokenizer(map.get(ih), "\n").nextToken();
  208. return str.substring(0, str.length() - 1);
  209. }
  210. private final void put(InstructionHandle ih, String line) {
  211. String str = map.get(ih);
  212. if(str == null)
  213. map.put(ih, line);
  214. else {
  215. if(line.startsWith("Label") || str.endsWith(line)) // Already have a label in the map
  216. return;
  217. map.put(ih, str + "\n" + line); // append
  218. }
  219. }
  220. public static void main(String[] argv) {
  221. JavaClass java_class;
  222. try {
  223. if(argv.length == 0) {
  224. System.err.println("disassemble: No input files specified");
  225. }
  226. else {
  227. for(int i=0; i < argv.length; i++) {
  228. if((java_class = Repository.lookupClass(argv[i])) == null)
  229. java_class = new ClassParser(argv[i]).parse();
  230. String class_name = java_class.getClassName();
  231. int index = class_name.lastIndexOf('.');
  232. String path = class_name.substring(0, index + 1).replace('.', File.separatorChar);
  233. class_name = class_name.substring(index + 1);
  234. if(!path.equals("")) {
  235. File f = new File(path);
  236. f.mkdirs();
  237. }
  238. FileWriter out = new FileWriter(path + class_name + ".j");
  239. new JasminVisitor(java_class, out).disassemble();
  240. }
  241. }
  242. } catch(Exception e) {
  243. e.printStackTrace();
  244. }
  245. }
  246. }