FileDocCategorySizeDatePackage
BlockDumper.javaAPI DocAndroid 1.5 API11410Wed May 06 22:41:02 BST 2009com.android.dx.command.dump

BlockDumper

public class BlockDumper extends BaseDumper
Utility to dump basic block info from methods in a human-friendly form.

Fields Summary
private boolean
rop
whether or not to registerize (make rop blocks)
protected com.android.dx.cf.direct.DirectClassFile
classFile
null-ok; the class file object being constructed; becomes non-null during {@link #dump}
private com.android.dx.cf.attrib.AttCode
codeAtt
null-ok; most recently parsed code attribute
protected boolean
suppressDump
whether or not to suppress dumping
private boolean
first
whether this is the first method being dumped
private boolean
optimize
whether or not to run the ssa optimziations
Constructors Summary
BlockDumper(byte[] bytes, PrintStream out, String filePath, boolean rop, Args args)
Constructs an instance. This class is not publicly instantiable. Use {@link #dump}.

        super(bytes, out, filePath, args);

        this.rop = rop;
        this.classFile = null;
        this.codeAtt = null;
        this.suppressDump = true;
        this.first = true;
        this.optimize = args.optimize;
    
Methods Summary
public voidchangeIndent(int indentDelta)
{@inheritDoc}

        if (!suppressDump) {
            super.changeIndent(indentDelta);
        }
    
public static voiddump(byte[] bytes, java.io.PrintStream out, java.lang.String filePath, boolean rop, Args args)
Dumps the given array, interpreting it as a class file and dumping methods with indications of block-level stuff.

param
bytes non-null; bytes of the (alleged) class file
param
out non-null; where to dump to passed in as <= 0
param
filePath the file path for the class, excluding any base directory specification
param
rop whether or not to registerize (make rop blocks)
param
args commandline parsedArgs

        BlockDumper bd =
            new BlockDumper(bytes, out, filePath,
                            rop, args);
        bd.dump();
    
public voiddump()
Does the dumping.

        byte[] bytes = getBytes();
        ByteArray ba = new ByteArray(bytes);

        /*
         * First, parse the file completely, so we can safely refer to
         * attributes, etc.
         */
        classFile = new DirectClassFile(ba, getFilePath(), getStrictParse());
        classFile.setAttributeFactory(StdAttributeFactory.THE_ONE);
        classFile.getMagic(); // Force parsing to happen.

        // Next, reparse it and observe the process.
        DirectClassFile liveCf =
            new DirectClassFile(ba, getFilePath(), getStrictParse());
        liveCf.setAttributeFactory(StdAttributeFactory.THE_ONE);
        liveCf.setObserver(this);
        liveCf.getMagic(); // Force parsing to happen.
    
public voidendParsingMember(com.android.dx.util.ByteArray bytes, int offset, java.lang.String name, java.lang.String descriptor, com.android.dx.cf.iface.Member member)
{@inheritDoc}

        if (!(member instanceof Method)) {
            return;
        }

        if (!shouldDumpMethod(name)) {
            return;
        }
        
        ConcreteMethod meth = new ConcreteMethod((Method) member, classFile,
                                                 true, true);

        if (rop) {
            ropDump(meth);
        } else {
            regularDump(meth);
        }
    
public voidparsed(com.android.dx.util.ByteArray bytes, int offset, int len, java.lang.String human)
{@inheritDoc}

        if (!suppressDump) {
            super.parsed(bytes, offset, len, human);
        }
    
private voidregularDump(com.android.dx.cf.code.ConcreteMethod meth)
Does a regular basic block dump.

param
meth non-null; method data to dump

        BytecodeArray code = meth.getCode();
        ByteArray bytes = code.getBytes();
        ByteBlockList list = BasicBlocker.identifyBlocks(meth);
        int sz = list.size();
        CodeObserver codeObserver = new CodeObserver(bytes, BlockDumper.this);

        // Reset the dump cursor to the start of the bytecode
        setAt(bytes, 0);

        suppressDump = false;

        int byteAt = 0;
        for (int i = 0; i < sz; i++) {
            ByteBlock bb = list.get(i);
            int start = bb.getStart();
            int end = bb.getEnd();

            if (byteAt < start) {
                parsed(bytes, byteAt, start - byteAt,
                       "dead code " + Hex.u2(byteAt) + ".." + Hex.u2(start));
            }

            parsed(bytes, start, 0,
                   "block " + Hex.u2(bb.getLabel()) + ": " +
                   Hex.u2(start) + ".." + Hex.u2(end));
            changeIndent(1);

            int len;
            for (int j = start; j < end; j += len) {
                len = code.parseInstruction(j, codeObserver);
                codeObserver.setPreviousOffset(j);
            }

            IntList successors = bb.getSuccessors();
            int ssz = successors.size();
            if (ssz == 0) {
                parsed(bytes, end, 0, "returns");
            } else {
                for (int j = 0; j < ssz; j++) {
                    int succ = successors.get(j);
                    parsed(bytes, end, 0, "next " + Hex.u2(succ));
                }
            }

            ByteCatchList catches = bb.getCatches();
            int csz = catches.size();
            for (int j = 0; j < csz; j++) {
                ByteCatchList.Item one = catches.get(j);
                CstType exceptionClass = one.getExceptionClass();
                parsed(bytes, end, 0,
                       "catch " +
                       ((exceptionClass == CstType.OBJECT) ? "<any>" : 
                        exceptionClass.toHuman()) + " -> " +
                       Hex.u2(one.getHandlerPc()));
            }

            changeIndent(-1);
            byteAt = end;
        }

        int end = bytes.size();
        if (byteAt < end) {
            parsed(bytes, byteAt, end - byteAt,
                   "dead code " + Hex.u2(byteAt) + ".." + Hex.u2(end));
        }

        suppressDump = true;
    
private voidropDump(com.android.dx.cf.code.ConcreteMethod meth)
Does a registerizing dump.

param
meth non-null; method data to dump

        BytecodeArray code = meth.getCode();
        ByteArray bytes = code.getBytes();

        TranslationAdvice advice = DexTranslationAdvice.THE_ONE;

        RopMethod rmeth =
            Ropper.convert(meth, advice);
        StringBuffer sb = new StringBuffer(2000);

        if (optimize) {
            boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags());

            int paramWidth = computeParamWidth(meth, isStatic);
            rmeth = Optimizer.optimize(rmeth, paramWidth, isStatic, true,
                    advice);
        }

        BasicBlockList blocks = rmeth.getBlocks();

        sb.append("first " + Hex.u2(rmeth.getFirstLabel()) + "\n");

        int sz = blocks.size();
        for (int i = 0; i < sz; i++) {
            BasicBlock bb = blocks.get(i);
            int label = bb.getLabel();
            sb.append("block ");
            sb.append(Hex.u2(label));
            sb.append("\n");

            IntList preds = rmeth.labelToPredecessors(label);
            int psz = preds.size();
            for (int j = 0; j < psz; j++) {
                sb.append("  pred ");
                sb.append(Hex.u2(preds.get(j)));
                sb.append("\n");
            }

            InsnList il = bb.getInsns();
            int ilsz = il.size();
            for (int j = 0; j < ilsz; j++) {
                Insn one = il.get(j);
                sb.append("  ");
                sb.append(il.get(j).toHuman());
                sb.append("\n");
            }

            IntList successors = bb.getSuccessors();
            int ssz = successors.size();
            if (ssz == 0) {
                sb.append("  returns\n");
            } else {
                int primary = bb.getPrimarySuccessor();
                for (int j = 0; j < ssz; j++) {
                    int succ = successors.get(j);
                    sb.append("  next ");
                    sb.append(Hex.u2(succ));

                    if ((ssz != 1) && (succ == primary)) {
                        sb.append(" *");
                    }

                    sb.append("\n");
                }
            }
        }

        suppressDump = false;
        setAt(bytes, 0);
        parsed(bytes, 0, bytes.size(), sb.toString());
        suppressDump = true;
    
protected booleanshouldDumpMethod(java.lang.String name)

param
name method name
return
true if this method should be dumped

        return args.method == null || args.method.equals(name);
    
public voidstartParsingMember(com.android.dx.util.ByteArray bytes, int offset, java.lang.String name, java.lang.String descriptor)
{@inheritDoc}

        if (descriptor.indexOf('(") < 0) {
            // It's a field, not a method
            return;
        }

        if (!shouldDumpMethod(name)) {
            return;
        }

        // Reset the dump cursor to the start of the method.
        setAt(bytes, offset);

        suppressDump = false;

        if (first) {
            first = false;
        } else {
            parsed(bytes, offset, 0, "\n");
        }

        parsed(bytes, offset, 0, "method " + name + " " + descriptor);
        suppressDump = true;