FileDocCategorySizeDatePackage
CodeObserver.javaAPI DocAndroid 1.5 API9745Wed May 06 22:41:02 BST 2009com.android.dx.cf.direct

CodeObserver

public class CodeObserver extends Object implements BytecodeArray.Visitor
Bytecode visitor to use when "observing" bytecode getting parsed.

Fields Summary
private final com.android.dx.util.ByteArray
bytes
non-null; actual array of bytecode
private final com.android.dx.cf.iface.ParseObserver
observer
non-null; observer to inform of parsing
Constructors Summary
public CodeObserver(com.android.dx.util.ByteArray bytes, com.android.dx.cf.iface.ParseObserver observer)
Constructs an instance.

param
bytes non-null; actual array of bytecode
param
observer non-null; observer to inform of parsing

        if (bytes == null) {
            throw new NullPointerException("bytes == null");
        }

        if (observer == null) {
            throw new NullPointerException("observer == null");
        }

        this.bytes = bytes;
        this.observer = observer;
    
Methods Summary
public intgetPreviousOffset()
{@inheritDoc}

        return -1;
    
private java.lang.Stringheader(int offset)
Helper to produce the first bit of output for each instruction.

param
offset the offset to the start of the instruction

        /*
         * Note: This uses the original bytecode, not the
         * possibly-transformed one.
         */
        int opcode = bytes.getUnsignedByte(offset);
        String name = ByteOps.opName(opcode);

        if (opcode == ByteOps.WIDE) {
            opcode = bytes.getUnsignedByte(offset + 1);
            name += " " + ByteOps.opName(opcode);
        }

        return Hex.u2(offset) + ": " + name;
    
public voidsetPreviousOffset(int offset)
{@inheritDoc}

        // Do nothing
    
public voidvisitBranch(int opcode, int offset, int length, int target)
{@inheritDoc}

        String targetStr = (length <= 3) ? Hex.u2(target) : Hex.u4(target);
        observer.parsed(bytes, offset, length,
                        header(offset) + " " + targetStr);
    
public voidvisitConstant(int opcode, int offset, int length, com.android.dx.rop.cst.Constant cst, int value)
{@inheritDoc}

        if (cst instanceof CstKnownNull) {
            // This is aconst_null.
            visitNoArgs(opcode, offset, length, null);
            return;
        }

        if (cst instanceof CstInteger) {
            visitLiteralInt(opcode, offset, length, value);
            return;
        }

        if (cst instanceof CstLong) {
            visitLiteralLong(opcode, offset, length,
                             ((CstLong) cst).getValue());
            return;
        }

        if (cst instanceof CstFloat) {
            visitLiteralFloat(opcode, offset, length,
                              ((CstFloat) cst).getIntBits());
            return;
        }

        if (cst instanceof CstDouble) {
            visitLiteralDouble(opcode, offset, length,
                             ((CstDouble) cst).getLongBits());
            return;
        }

        String valueStr = "";
        if (value != 0) {
            valueStr = ", ";
            if (opcode == ByteOps.MULTIANEWARRAY) {
                valueStr += Hex.u1(value);
            } else {
                valueStr += Hex.u2(value);
            }
        }

        observer.parsed(bytes, offset, length,
                        header(offset) + " " + cst + valueStr);
    
public voidvisitInvalid(int opcode, int offset, int length)
{@inheritDoc}

        observer.parsed(bytes, offset, length, header(offset));
    
private voidvisitLiteralDouble(int opcode, int offset, int length, long bits)
Helper for {code #visitConstant} where the constant is a double.

param
opcode the opcode
param
offset offset to the instruction
param
length instruction length
param
bits constant value, as double-bits

        String optArg = (length != 1) ? " #" + Hex.u8(bits) : "";

        observer.parsed(bytes, offset, length,
                        header(offset) + optArg + " // " +
                        Double.longBitsToDouble(bits));
    
private voidvisitLiteralFloat(int opcode, int offset, int length, int bits)
Helper for {code #visitConstant} where the constant is a float.

param
opcode the opcode
param
offset offset to the instruction
param
length instruction length
param
bits constant value, as float-bits

        String optArg = (length != 1) ? " #" + Hex.u4(bits) : "";

        observer.parsed(bytes, offset, length,
                        header(offset) + optArg + " // " +
                        Float.intBitsToFloat(bits));
    
private voidvisitLiteralInt(int opcode, int offset, int length, int value)
Helper for {code #visitConstant} where the constant is an int.

param
opcode the opcode
param
offset offset to the instruction
param
length instruction length
param
value constant value

        String commentOrSpace = (length == 1) ? " // " : " ";
        String valueStr;

        opcode = bytes.getUnsignedByte(offset); // Compare with orig op below.
        if ((length == 1) || (opcode == ByteOps.BIPUSH)) {
            valueStr = "#" + Hex.s1(value);
        } else if (opcode == ByteOps.SIPUSH) {
            valueStr = "#" + Hex.s2(value);
        } else {
            valueStr = "#" + Hex.s4(value);
        }

        observer.parsed(bytes, offset, length,
                        header(offset) + commentOrSpace + valueStr);
    
private voidvisitLiteralLong(int opcode, int offset, int length, long value)
Helper for {code #visitConstant} where the constant is a long.

param
opcode the opcode
param
offset offset to the instruction
param
length instruction length
param
value constant value

        String commentOrLit = (length == 1) ? " // " : " #";
        String valueStr;

        if (length == 1) {
            valueStr = Hex.s1((int) value);
        } else {
            valueStr = Hex.s8(value);
        }

        observer.parsed(bytes, offset, length,
                        header(offset) + commentOrLit + valueStr);
    
public voidvisitLocal(int opcode, int offset, int length, int idx, com.android.dx.rop.type.Type type, int value)
{@inheritDoc}

        String idxStr = (length <= 3) ? Hex.u1(idx) : Hex.u2(idx);
        boolean argComment = (length == 1);
        String valueStr = "";

        if (opcode == ByteOps.IINC) {
            valueStr = ", #" +
                ((length <= 3) ? Hex.s1(value) : Hex.s2(value));
        }

        String catStr = "";
        if (type.isCategory2()) {
            catStr = (argComment ? "," : " //") + " category-2";
        }

        observer.parsed(bytes, offset, length,
                        header(offset) + (argComment ? " // " : " ") +
                        idxStr + valueStr + catStr);
    
public voidvisitNewarray(int offset, int length, com.android.dx.rop.cst.CstType cst, java.util.ArrayList intVals)
{@inheritDoc}

        String commentOrSpace = (length == 1) ? " // " : " ";
        String typeName = cst.getClassType().getComponentType().toHuman();

        observer.parsed(bytes, offset, length,
                        header(offset) + commentOrSpace + typeName);
    
public voidvisitNoArgs(int opcode, int offset, int length, com.android.dx.rop.type.Type type)
{@inheritDoc}

        observer.parsed(bytes, offset, length, header(offset));
    
public voidvisitSwitch(int opcode, int offset, int length, com.android.dx.cf.code.SwitchList cases, int padding)
{@inheritDoc}

        int sz = cases.size();
        StringBuffer sb = new StringBuffer(sz * 20 + 100);

        sb.append(header(offset));
        if (padding != 0) {
            sb.append(" // padding: " + Hex.u4(padding));
        }
        sb.append('\n");

        for (int i = 0; i < sz; i++) {
            sb.append("  ");
            sb.append(Hex.s4(cases.getValue(i)));
            sb.append(": ");
            sb.append(Hex.u2(cases.getTarget(i)));
            sb.append('\n");
        }

        sb.append("  default: ");
        sb.append(Hex.u2(cases.getDefaultTarget()));

        observer.parsed(bytes, offset, length, sb.toString());