import java.io.IOException; import java.io.InputStream; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.util.Printer; public class Analyzer { private static long instructionCount = 0L; private static long invokeInstructionCount = 0L; private static long branchInstructionCount = 0L; private static final Map instructionCounts = new HashMap<>(); private static long classCount = 0L; private static long methodCount = 0L; public static void main(final String[] args) throws IOException { // initialize instruction map for (int i = 0; i < 256; i++) instructionCounts.put(i, 0L); final String jarFileName = args[0]; System.out.println("Analyzing " + jarFileName); final JarFile jar = new JarFile(jarFileName); analyzeJar(jar); printStats(); } private static void printStats() { System.out.println("=== STATISTICS ==="); System.out.println("classes:\t" + classCount); System.out.println("methods:\t" + methodCount); System.out.println("instructions:\t" + instructionCount); System.out.println("invoke instructions:\t" + invokeInstructionCount); System.out.println("branch instructions:\t" + branchInstructionCount); System.out.println("OPCODE\tMNEMONIC\tCOUNT"); instructionCounts.entrySet().stream().sorted(Comparator.comparingInt(Map.Entry::getKey)) .forEach(e -> System.out.printf("%d\t%s\t%d\n", e.getKey(), e.getKey() >= Printer.OPCODES.length ? "" : Printer.OPCODES[e.getKey()], e.getValue())); } private static void analyzeJar(final JarFile jar) throws IOException { final Enumeration entries = jar.entries(); while (entries.hasMoreElements()) { final JarEntry entry = entries.nextElement(); analyzeJarEntry(entry, jar); } } private static void analyzeJarEntry(final JarEntry entry, final JarFile jar) throws IOException { if (!entry.isDirectory() && entry.getName().endsWith(".class")) { System.out.println(" File " + entry.getName()); final InputStream is = jar.getInputStream(entry); final ClassReader classReader = new ClassReader(is); final ClassNode classNode = new ClassNode(); classReader.accept(classNode, ClassReader.SKIP_FRAMES); analyzeClass(classNode); } } private static void analyzeClass(final ClassNode classNode) { System.out.println(" Class " + classNode.name); classCount++; final List methods = classNode.methods; for (final MethodNode methodNode : methods) { analyzeMethod(methodNode); } } private static void analyzeMethod(final MethodNode methodNode) { System.out.println(" Method " + methodNode.name + methodNode.desc); methodCount++; for (int i = 0; i < methodNode.instructions.size(); i++) { final AbstractInsnNode ins = methodNode.instructions.get(i); if (ins.getOpcode() == -1) continue; instructionCount++; switch (ins.getType()) { case AbstractInsnNode.LOOKUPSWITCH_INSN: case AbstractInsnNode.TABLESWITCH_INSN: branchInstructionCount++; break; case AbstractInsnNode.JUMP_INSN: if (ins.getOpcode() != Opcodes.GOTO) branchInstructionCount++; break; case AbstractInsnNode.METHOD_INSN: case AbstractInsnNode.INVOKE_DYNAMIC_INSN: invokeInstructionCount++; } instructionCounts.compute(ins.getOpcode(), (k, v) -> v == null ? 1 : (v + 1)); } } }