kilim.tools.DumpClass.java Source code

Java tutorial

Introduction

Here is the source code for kilim.tools.DumpClass.java

Source

/* Copyright (c) 2006, Sriram Srinivasan
 *
 * You may distribute this software under the terms of the license 
 * specified in the file "License"
 */

package kilim.tools;

import static kilim.analysis.Utils.dedent;
import static kilim.analysis.Utils.indent;
import static kilim.analysis.Utils.p;
import static kilim.analysis.Utils.pn;
import static kilim.analysis.Utils.resetIndentation;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.Formatter;
import java.util.HashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import kilim.analysis.TypeDesc;
import me.jor.util.Log4jUtil;

import org.apache.commons.logging.Log;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * Equivalent to javap -c -l -private, but the output is in jasmin's format 
 * meant to be parseable by Asm.
 * @author sriram
 */
public class DumpClass extends ClassVisitor implements Opcodes {
    static boolean lineNumbers = true;

    public static void main(String[] args) throws IOException {
        String name = args.length == 2 ? args[1] : args[0];

        if (name.endsWith(".jar")) {
            try {
                Enumeration<JarEntry> e = new JarFile(name).entries();
                while (e.hasMoreElements()) {
                    ZipEntry en = (ZipEntry) e.nextElement();
                    String n = en.getName();
                    if (!n.endsWith(".class"))
                        continue;
                    n = n.substring(0, n.length() - 6).replace('/', '.');
                    new DumpClass(n);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            new DumpClass(name);
        }
    }

    public DumpClass(InputStream is) throws IOException {
        super(ASM4);
        ClassReader cr = new ClassReader(is);
        cr.accept(this, /*flags*/ 0);
    }

    public DumpClass(String className) throws IOException {
        super(ASM4);
        ClassReader cr;
        if (className.endsWith(".class")) {
            FileInputStream fis = new FileInputStream(className);
            cr = new ClassReader(fis);
        } else {
            cr = new ClassReader(className);
        }
        cr.accept(this, /*flags*/ClassReader.EXPAND_FRAMES);
    }

    public void visit(int version, int access, String name, String signature, String superName,
            String[] interfaces) {
        p(".class ");
        p(Modifier.toString(access));
        p(" ");
        pn(name);
        if (superName != null)
            pn(".super " + superName);

        if (interfaces != null) {
            for (int i = 0; i < interfaces.length; i++) {
                p(".implements ");
                pn(interfaces[i]);
            }
        }
    }

    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        pn(".annotation " + (visible ? "visible " : "") + desc);
        pn(".end annotation");
        return new DummyAnnotationVisitor();
    }

    public void visitAttribute(Attribute attr) {
    }

    public void visitEnd() {
    }

    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
        p(".field ");
        p(Modifier.toString(access));
        p(" ");
        p(name);
        p(" ");
        p(desc);
        if (value != null) {
            p(" = ");
            if (value instanceof String) {
                pn("\"" + value + "\"");
            } else {
                pn(value.toString());
            }
        } else {
            pn();
        }
        return null;
    }

    public void visitInnerClass(String name, String outerName, String innerName, int access) {
    }

    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        pn("");
        pn("; -------------------------------------------------------------");
        p(".method ");
        p(Modifier.toString(access));
        p(" ");
        p(name);
        pn(desc);
        pn("; signature = " + signature);
        pn("; -------------------------------------------------------------\n");
        if (exceptions != null) {
            for (int i = 0; i < exceptions.length; i++) {
                p(".throws ");
                pn(exceptions[i]);
            }
        }
        return new DumpMethodVisitor();
    }

    public void visitOuterClass(String owner, String name, String desc) {
    }

    public void visitSource(String source, String debug) {
    }
}

class DummyAnnotationVisitor extends AnnotationVisitor {
    public DummyAnnotationVisitor() {
        super(Opcodes.ASM4);
        // TODO Auto-generated constructor stub
    }

    public void visit(String name, Object value) {
        //        System.out.println("visit: name = " + name + ", value = "  + value);
    }

    public AnnotationVisitor visitAnnotation(String name, String desc) {
        //        System.out.println("visitAnnotation: name = " + name + ", desc = " + desc);
        return this;
    }

    public AnnotationVisitor visitArray(String name) {
        //        System.out.println("visitArray: name = " + name);
        return this;
    }

    public void visitEnd() {
        //        System.out.println("visitEnd");
    }

    public void visitEnum(String name, String desc, String value) {
        //        System.out.println("visitEnum: " + name + ", desc = "  + desc + ", value = " + value);
    }
}

class DumpMethodVisitor extends MethodVisitor implements Opcodes {
    private static final Log log = Log4jUtil.getLog(DumpMethodVisitor.class);

    public DumpMethodVisitor() {
        super(Opcodes.ASM4);
    }

    static String[] os = { "nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", "iconst_2", "iconst_3",
            "iconst_4", "iconst_5", "lconst_0", "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0",
            "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc_w", "iload", "lload", "fload", "dload", "aload",
            "iload_0", "iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0",
            "fload_1", "fload_2", "fload_3", "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1",
            "aload_2", "aload_3", "iaload", "laload", "faload", "daload", "aaload", "baload", "caload", "saload",
            "istore", "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3",
            "lstore_0", "lstore_1", "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3",
            "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1", "astore_2", "astore_3",
            "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2",
            "dup", "dup_x1", "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub",
            "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", "ldiv", "fdiv", "ddiv", "irem", "lrem",
            "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr",
            "iand", "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i",
            "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s", "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg",
            "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge",
            "if_icmpgt", "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch",
            "ireturn", "lreturn", "freturn", "dreturn", "areturn", "return", "getstatic", "putstatic", "getfield",
            "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface", "unused", "new",
            "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter",
            "monitorexit", "wide", "multianewarray", "ifnull", "ifnonnull", "goto_w", "jsr_w" };
    int line = 0;
    static StringBuilder fsb = new StringBuilder(100);
    static Formatter formatter = new Formatter(fsb);

    public void ppn(String s) {
        if (DumpClass.lineNumbers) {
            fsb.setLength(0);
            formatter.format("%-70s ; %d", s, (line++));
            pn(fsb.toString());
        } else {
            pn(s);
        }
    }

    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
        ppn(os[opcode] + " " + owner + "/" + name + " " + desc);
    }

    public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
        pn("; Frame " + type);

        p(";  Locals - ");
        StringBuilder print = new StringBuilder();
        for (int i = 0; i < nLocal; i++) {
            Object o = local[i];
            print.append("#" + i + "." + type(o) + "  ");
        }
        log.info(print);
        p(";  Stack - ");
        print.delete(0, print.length());
        for (int i = 0; i < nStack; i++) {
            Object o = stack[i];
            print.append("#" + i + "." + type(o) + "  ");
        }
        log.info(print);
    }

    private String type(Object o) {
        if (o == null) {
            return "null";
        } else if (o instanceof Integer) {
            switch (((Integer) o).intValue()) {
            case 0:
                return "Top";
            case 1:
                return "Integer";
            case 2:
                return "Float";
            case 3:
                return "Double";
            case 4:
                return "Long";
            case 5:
                return "Null";
            case 6:
                return "Uninitialized_This";
            }
        } else if (o instanceof String) {
            return (String) o;
        }
        return "??UNKNOWN??" + o.getClass() + ":" + o;
    }

    public void visitIincInsn(int var, int increment) {
        ppn("iinc " + var + " " + increment);
    }

    public void visitInsn(int opcode) {
        ppn(os[opcode]);
    }

    public void visitIntInsn(int opcode, int operand) {
        if (opcode == NEWARRAY) {
            String t = "UNDEFINED";
            switch (operand) {
            case T_BOOLEAN:
                t = " boolean";
                break;
            case T_CHAR:
                t = " char";
                break;
            case T_FLOAT:
                t = " float";
                break;
            case T_DOUBLE:
                t = " double";
                break;
            case T_BYTE:
                t = " byte";
                break;
            case T_SHORT:
                t = " short";
                break;
            case T_INT:
                t = " int";
                break;
            case T_LONG:
                t = " long";
                break;
            }
            ppn(os[opcode] + t);
        } else {
            ppn(os[opcode] + " " + operand);
        }
    }

    public void visitJumpInsn(int opcode, Label label) {
        ppn(os[opcode] + " " + lab(label));
    }

    public void visitLabel(Label label) {
        dedent(2);
        pn(lab(label) + ":");
        indent(2);
    }

    public void visitLdcInsn(Object cst) {
        String op = (cst instanceof Double) || (cst instanceof Long) ? "ldc2_w " : "ldc ";
        String type = (cst instanceof String) ? "\"" + esc((String) cst) + "\"" : cst.toString();
        ppn(op + type);
    }

    public void visitLineNumber(int line, Label start) {
        pn(".line " + line);
    }

    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
        pn(".var " + index + " is " + name + " " + desc + " from " + lab(start) + " to " + lab(end));
    }

    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
        ppn("lookupswitch");
        indent(4);
        for (int i = 0; i < keys.length; i++) {
            pn(keys[i] + ": " + lab(labels[i]));
        }
        pn("default: " + lab(dflt));
        dedent(4);
    }

    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
        String str = os[opcode] + " " + owner + "/" + name + desc;
        if (opcode == INVOKEINTERFACE) {
            ppn(str + ", " + (TypeDesc.getNumArgumentTypes(desc) + 1));
        } else {
            ppn(str);
        }
    }

    public void visitMultiANewArrayInsn(String desc, int dims) {
        ppn("multinewarray " + desc + " " + dims);
    }

    public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
        ppn("tableswitch  " + min);
        indent(4);
        for (int i = min; i <= max; i++) {
            pn(lab(labels[i - min]));
        }
        pn("default: " + lab(dflt));
        dedent(4);
    }

    public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
        pn(".catch " + type + " from " + lab(start) + " to " + lab(end) + " using " + lab(handler));
    }

    public void visitTypeInsn(int opcode, String desc) {
        ppn(os[opcode] + " " + desc);
    }

    public void visitVarInsn(int opcode, int var) {
        ppn(os[opcode] + " " + var);
    }

    HashMap<Label, String> labels = new HashMap<Label, String>();
    int labCount = 1;

    private String lab(Label label) {
        String ret = labels.get(label);
        if (ret == null) {
            ret = "L" + labCount++;
            labels.put(label, ret);
        }
        return ret;
    }

    public AnnotationVisitor visitAnnotationDefault() {
        return new DummyAnnotationVisitor();
    }

    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        pn(".annotation " + (visible ? "visible " : "") + desc);
        pn(".end annotation");
        return new DummyAnnotationVisitor();
    }

    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
        return new DummyAnnotationVisitor();
    }

    public void visitAttribute(Attribute attr) {
    }

    public void visitCode() {
        indent(4);
    }

    public void visitMaxs(int maxStack, int maxLocals) {
        pn(".limit stack " + maxStack);
        pn(".limit locals " + maxLocals);
    }

    public void visitEnd() {
        resetIndentation();
        pn(".end method");
    }

    private static String esc(String s) {
        return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n");
    }
}