All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kilim.tools.FlowAnalyzer Maven / Gradle / Ivy

Go to download

Coroutines, continuations, fibers, actors and message passing for the JVM

There is a newer version: 2.0.2-jdk7
Show newest version
/* 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.pn;
import static kilim.analysis.Utils.resetIndentation;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import kilim.analysis.BasicBlock;
import kilim.analysis.ClassFlow;
import kilim.analysis.Frame;
import kilim.analysis.KilimContext;
import kilim.analysis.MethodFlow;
import kilim.analysis.TypeDesc;
import kilim.analysis.Usage;
import kilim.analysis.Value;

import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;

/**
 * Used to dump the stack and locals at the beginning of each basic block
 * @author ram
 */
public class FlowAnalyzer {
    
    public static void main(String[] args) throws Exception {
        if (args.length == 0) {
            System.err.println("Usage  [methodName]");
            System.exit(1);
        }
        String name = args[0];
        if (name.endsWith(".jar")) {
            analyzeJar(name);
        } else {
            analyzeClass(name);
        }
    }
    
    private static void analyzeClass(String className) {
        try {
            pn("-------------------------------------------------");
            pn("Class: " + className);
            System.out.flush();
            ClassFlow cf = null;
            if (className.endsWith(".class")) {
                FileInputStream fis = null;
                try {
                    fis = new FileInputStream(className);
                    cf = new ClassFlow(KilimContext.DEFAULT,fis);
                } finally {
                    if (fis != null) {fis.close();}
                }
            }
            if (cf == null) {
                cf = new ClassFlow(KilimContext.DEFAULT,className);
            }
            ArrayList flows = cf.analyze(true);
            for (MethodFlow flow: flows) {
                reportFlow(flow, className);
            }
        } catch (IOException e) {
            pn("##################################################");
            stackTrace(e);
        } catch (Throwable ie) {
            pn("##################################################");
            stackTrace(ie);
        }
    }
    
    private static void stackTrace(Throwable t) {
        PrintStream ps = new PrintStream(System.out);
        t.printStackTrace(ps);
    }
    
    private static void reportFlow(MethodFlow method, String className) {
        resetIndentation();
        pn("Method : "+  className + '.' + method.name);
        
        pn("MaxStack: " + method.maxStack);
        pn("MaxLocals: " + method.maxLocals);
        ArrayList bbs = method.getBasicBlocks();
        Collections.sort(bbs);
        indent(2);
        for (BasicBlock bb: bbs) {
            AbstractInsnNode ainode = bb.getInstruction(bb.startPos);
            if (ainode instanceof MethodInsnNode) {
                MethodInsnNode m = (MethodInsnNode)ainode;
                int n = getNumArgs(m); // This many will get consumed from stack
                pn("Call(" + n + "): " + m.owner + "." + m.name + m.desc);
                indent(2);
                pn("Inframe: ");
                indent(2);
                Frame f = bb.startFrame;
                pn(f.toString());
                dedent(2);
                pn("Live locals:");
                indent(2);
                Usage u = bb.getVarUsage();
                pn(u.toString());
                dedent(2);
                pn("Actual usage: " + uniqueItems(bb, f, u, n));
                dedent(2);
            }
        }
        dedent(2);
    }
    
    private static String uniqueItems(BasicBlock bb, Frame f, Usage u, int nStack) {
        StringBuffer sb = new StringBuffer(80);
        int numNonConstants = 0;
        int numLive = 0;
        ArrayList set = new ArrayList(10);
        for (int i = 0; i < f.getMaxLocals(); i++) {
            if (u.isLiveIn(i)) {
                numLive++;
                Value v = f.getLocal(i);
                if (!set.contains(v)) set.add(v);
            }
        }
        nStack = f.getStackLen() - nStack;
        for (int i = 0; i < nStack; i++) {
            Value v = f.getStack(i);
            if (!set.contains(v)) set.add(v);
        }
        char[] sig = new char[set.size()];
        // create canonical sig. Convert types to one of 'O', 'I', 'F', 'L', 'D' and
        // put in sorted order
        // Also count non constants while we are iterating anyway.
        for (int i = 0; i < set.size(); i++) {
            Value v = set.get(i);
            char c = v.getTypeDesc().charAt(0);
            switch (c) {
                case 'L': case '[': case 'N': 
                    c = 'O'; break;
                case 'I': case 'B': case 'S': case 'Z': case 'C': 
                    c = 'I'; break;
                case 'J':
                    c = 'J'; break;
                case 'F': 
                    c = 'F'; break;
                case 'U': 
                    default: {
                    c = 'U';
                    System.err.println("***************************************");
                    System.err.println("Undefined/unrecognized value " + v);
                    System.err.println("BasicBlock:\n" + bb);
                    break;
                }
            }
            sig[i] = c;
            if (v.getConstVal() == Value.NO_VAL) {
                numNonConstants++;
            }
        }
        Arrays.sort(sig);
        numLive += nStack;
        sb.append("avail: ").append(nStack + f.getMaxLocals());
        sb.append(", live: " + numLive);
        sb.append(", unique: ").append(set.size());
        sb.append(", unique non-const: ").append(numNonConstants);
        sb.append("\nState signature: ").append(set.size() == 0 ? "None" : new String(sig));
        return sb.toString();
    }
    
    private static int getNumArgs(MethodInsnNode m) {
        int ret = TypeDesc.getNumArgumentTypes(m.desc);
        if (m.getOpcode() != INVOKESTATIC) ret++; 
        return ret;
    }
    
    public static void analyzeJar(String jarFile) {
        try {
            Enumeration e = new JarFile(jarFile).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('/','.');
                analyzeClass(n);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy