FileDocCategorySizeDatePackage
InsnFormat.javaAPI DocAndroid 5.1 API22935Thu Mar 12 22:18:30 GMT 2015com.android.dx.dex.code

InsnFormat

public abstract class InsnFormat extends Object
Base class for all instruction format handlers. Instruction format handlers know how to translate {@link DalvInsn} instances into streams of code units, as well as human-oriented listing strings representing such translations.

Fields Summary
public static boolean
ALLOW_EXTENDED_OPCODES
flag to enable/disable the new extended opcode formats; meant as a temporary measure until VM support for the salient opcodes is added. TODO: Remove this declaration when the VM can deal.
Constructors Summary
Methods Summary
protected static intargIndex(DalvInsn insn)
Helper method to extract the callout-argument index from an appropriate instruction.

param
insn {@code non-null;} the instruction
return
{@code >= 0;} the callout argument index

        int arg = ((CstInteger) ((CstInsn) insn).getConstant()).getValue();

        if (arg < 0) {
            throw new IllegalArgumentException("bogus insn");
        }

        return arg;
    
protected static java.lang.StringbranchComment(DalvInsn insn)
Helper method to return the comment for a branch.

param
insn {@code non-null;} the instruction in question
return
{@code non-null;} the comment

        TargetInsn ti = (TargetInsn) insn;
        int offset = ti.getTargetOffset();

        return (offset == (short) offset) ? Hex.s2(offset) : Hex.s4(offset);
    
public booleanbranchFits(TargetInsn insn)
Returns whether or not the given instruction's branch offset will fit in this instance's format. This always returns {@code false} for formats that don't include a branch offset.

The default implementation of this method always returns {@code false}. Subclasses must override this method if they include branch offsets.

param
insn {@code non-null;} the instruction to check
return
{@code true} iff the instruction's branch offset is appropriate for this instance, or {@code false} if not

        return false;
    
protected static java.lang.StringbranchString(DalvInsn insn)
Helper method to return a branch address string.

param
insn {@code non-null;} the instruction in question
return
{@code non-null;} the string form of the instruction's branch target

        TargetInsn ti = (TargetInsn) insn;
        int address = ti.getTargetAddress();

        return (address == (char) address) ? Hex.u2(address) : Hex.u4(address);
    
public abstract intcodeSize()
Gets the code size of instructions that use this format. The size is a number of 16-bit code units, not bytes. This should throw an exception if this format is of variable size.

return
{@code >= 0;} the instruction length in 16-bit code units

protected static shortcodeUnit(int low, int high)
Helper method to combine two bytes into a code unit.

param
low {@code 0..255;} low byte
param
high {@code 0..255;} high byte
return
combined value

        if ((low & 0xff) != low) {
            throw new IllegalArgumentException("low out of range 0..255");
        }

        if ((high & 0xff) != high) {
            throw new IllegalArgumentException("high out of range 0..255");
        }

        return (short) (low | (high << 8));
    
protected static shortcodeUnit(int n0, int n1, int n2, int n3)
Helper method to combine four nibbles into a code unit.

param
n0 {@code 0..15;} low nibble
param
n1 {@code 0..15;} medium-low nibble
param
n2 {@code 0..15;} medium-high nibble
param
n3 {@code 0..15;} high nibble
return
combined value

        if ((n0 & 0xf) != n0) {
            throw new IllegalArgumentException("n0 out of range 0..15");
        }

        if ((n1 & 0xf) != n1) {
            throw new IllegalArgumentException("n1 out of range 0..15");
        }

        if ((n2 & 0xf) != n2) {
            throw new IllegalArgumentException("n2 out of range 0..15");
        }

        if ((n3 & 0xf) != n3) {
            throw new IllegalArgumentException("n3 out of range 0..15");
        }

        return (short) (n0 | (n1 << 4) | (n2 << 8) | (n3 << 12));
    
public java.util.BitSetcompatibleRegs(DalvInsn insn)
Returns which of a given instruction's registers will fit in this instance's format.

The default implementation of this method always returns an empty BitSet. Subclasses must override this method if they have registers.

param
insn {@code non-null;} the instruction to check
return
{@code non-null;} a BitSet flagging registers in the register list that are compatible to this format

        return new BitSet();
    
protected static java.lang.StringcstComment(DalvInsn insn)
Helper method to return an instruction comment for a constant.

param
insn {@code non-null;} a constant-bearing instruction
return
{@code non-null;} comment string representing the constant

        CstInsn ci = (CstInsn) insn;

        if (! ci.hasIndex()) {
            return "";
        }

        StringBuilder sb = new StringBuilder(20);
        int index = ci.getIndex();

        sb.append(ci.getConstant().typeName());
        sb.append('@");

        if (index < 65536) {
            sb.append(Hex.u2(index));
        } else {
            sb.append(Hex.u4(index));
        }

        return sb.toString();
    
protected static java.lang.StringcstString(DalvInsn insn)
Helper method to return the constant string for a {@link CstInsn} in human form.

param
insn {@code non-null;} a constant-bearing instruction
return
{@code non-null;} the human string form of the contained constant

        CstInsn ci = (CstInsn) insn;
        Constant cst = ci.getConstant();

        return cst instanceof CstString ? ((CstString) cst).toQuoted() : cst.toHuman();
    
public abstract java.lang.StringinsnArgString(DalvInsn insn)
Returns the string form of the arguments to the given instruction. The instruction must be of this instance's format. If the instruction has no arguments, then the result should be {@code ""}, not {@code null}.

Subclasses must override this method.

param
insn {@code non-null;} the instruction
return
{@code non-null;} the string form

public abstract java.lang.StringinsnCommentString(DalvInsn insn, boolean noteIndices)
Returns the associated comment for the given instruction, if any. The instruction must be of this instance's format. If the instruction has no comment, then the result should be {@code ""}, not {@code null}.

Subclasses must override this method.

param
insn {@code non-null;} the instruction
param
noteIndices whether to include an explicit notation of constant pool indices
return
{@code non-null;} the string form

public abstract booleanisCompatible(DalvInsn insn)
Returns whether or not the given instruction's arguments will fit in this instance's format. This includes such things as counting register arguments, checking register ranges, and making sure that additional arguments are of appropriate types and are in-range. If this format has a branch target but the instruction's branch offset is unknown, this method will simply not check the offset.

Subclasses must override this method.

param
insn {@code non-null;} the instruction to check
return
{@code true} iff the instruction's arguments are appropriate for this instance, or {@code false} if not

protected static booleanisRegListSequential(com.android.dx.rop.code.RegisterSpecList list)
Helper method to determine if a list of registers are sequential, including degenerate cases for empty or single-element lists.

param
list {@code non-null;} the list of registers
return
{@code true} iff the list is sequentially ordered

        int sz = list.size();

        if (sz < 2) {
            return true;
        }

        int first = list.get(0).getReg();
        int next = first;

        for (int i = 0; i < sz; i++) {
            RegisterSpec one = list.get(i);
            if (one.getReg() != next) {
                return false;
            }
            next += one.getCategory();
        }

        return true;
    
public final java.lang.StringlistingString(DalvInsn insn, boolean noteIndices)
Returns the string form, suitable for inclusion in a listing dump, of the given instruction. The instruction must be of this instance's format for proper operation.

param
insn {@code non-null;} the instruction
param
noteIndices whether to include an explicit notation of constant pool indices
return
{@code non-null;} the string form


                                                           
           
        String op = insn.getOpcode().getName();
        String arg = insnArgString(insn);
        String comment = insnCommentString(insn, noteIndices);
        StringBuilder sb = new StringBuilder(100);

        sb.append(op);

        if (arg.length() != 0) {
            sb.append(' ");
            sb.append(arg);
        }

        if (comment.length() != 0) {
            sb.append(" // ");
            sb.append(comment);
        }

        return sb.toString();
    
protected static java.lang.StringliteralBitsComment(com.android.dx.rop.cst.CstLiteralBits value, int width)
Helper method to return a literal bits comment string.

param
value the value
param
width the width of the constant, in bits (used for displaying the uninterpreted bits; one of: {@code 4 8 16 32 64}
return
{@code non-null;} the comment

        StringBuffer sb = new StringBuffer(20);

        sb.append("#");

        long bits;

        if (value instanceof CstLiteral64) {
            bits = ((CstLiteral64) value).getLongBits();
        } else {
            bits = value.getIntBits();
        }

        switch (width) {
            case 4:  sb.append(Hex.uNibble((int) bits)); break;
            case 8:  sb.append(Hex.u1((int) bits));      break;
            case 16: sb.append(Hex.u2((int) bits));      break;
            case 32: sb.append(Hex.u4((int) bits));      break;
            case 64: sb.append(Hex.u8(bits));            break;
            default: {
                throw new RuntimeException("shouldn't happen");
            }
        }

        return sb.toString();
    
protected static java.lang.StringliteralBitsString(com.android.dx.rop.cst.CstLiteralBits value)
Helper method to return a literal bits argument string.

param
value the value
return
{@code non-null;} the string form

        StringBuffer sb = new StringBuffer(100);

        sb.append('#");

        if (value instanceof CstKnownNull) {
            sb.append("null");
        } else {
            sb.append(value.typeName());
            sb.append(' ");
            sb.append(value.toHuman());
        }

        return sb.toString();
    
protected static intmakeByte(int low, int high)
Helper method to combine two nibbles into a byte.

param
low {@code 0..15;} low nibble
param
high {@code 0..15;} high nibble
return
{@code 0..255;} combined value

        if ((low & 0xf) != low) {
            throw new IllegalArgumentException("low out of range 0..15");
        }

        if ((high & 0xf) != high) {
            throw new IllegalArgumentException("high out of range 0..15");
        }

        return low | (high << 4);
    
protected static shortopcodeUnit(DalvInsn insn, int arg)
Helper method to combine an opcode and a second byte of data into the appropriate form for emitting into a code buffer.

param
insn {@code non-null;} the instruction containing the opcode
param
arg {@code 0..255;} arbitrary other byte value
return
combined value

        if ((arg & 0xff) != arg) {
            throw new IllegalArgumentException("arg out of range 0..255");
        }

        int opcode = insn.getOpcode().getOpcode();

        if ((opcode & 0xff) != opcode) {
            throw new IllegalArgumentException("opcode out of range 0..255");
        }

        return (short) (opcode | (arg << 8));
    
protected static shortopcodeUnit(DalvInsn insn)
Helper method to get an extended (16-bit) opcode out of an instruction, returning it as a code unit. The opcode must be an extended opcode.

param
insn {@code non-null;} the instruction containing the extended opcode
return
the opcode as a code unit

        int opcode = insn.getOpcode().getOpcode();

        if ((opcode < 0x100) || (opcode > 0xffff)) {
            throw new IllegalArgumentException("opcode out of range 0..65535");
        }

        return (short) opcode;
    
protected static java.lang.StringregListString(com.android.dx.rop.code.RegisterSpecList list)
Helper method to return a register list string.

param
list {@code non-null;} the list of registers
return
{@code non-null;} the string form

        int sz = list.size();
        StringBuffer sb = new StringBuffer(sz * 5 + 2);

        sb.append('{");

        for (int i = 0; i < sz; i++) {
            if (i != 0) {
                sb.append(", ");
            }
            sb.append(list.get(i).regString());
        }

        sb.append('}");

        return sb.toString();
    
protected static java.lang.StringregRangeString(com.android.dx.rop.code.RegisterSpecList list)
Helper method to return a register range string.

param
list {@code non-null;} the list of registers (which must be sequential)
return
{@code non-null;} the string form

        int size = list.size();
        StringBuilder sb = new StringBuilder(30);

        sb.append("{");

        switch (size) {
            case 0: {
                // Nothing to do.
                break;
            }
            case 1: {
                sb.append(list.get(0).regString());
                break;
            }
            default: {
                RegisterSpec lastReg = list.get(size - 1);
                if (lastReg.getCategory() == 2) {
                    /*
                     * Add one to properly represent a list-final
                     * category-2 register.
                     */
                    lastReg = lastReg.withOffset(1);
                }

                sb.append(list.get(0).regString());
                sb.append("..");
                sb.append(lastReg.regString());
            }
        }

        sb.append("}");

        return sb.toString();
    
protected static booleansignedFitsInByte(int value)
Helper method to determine if a signed int value fits in a byte.

param
value the value in question
return
{@code true} iff it's in the range -0x80..+0x7f

        return (byte) value == value;
    
protected static booleansignedFitsInNibble(int value)
Helper method to determine if a signed int value fits in a nibble.

param
value the value in question
return
{@code true} iff it's in the range -8..+7

        return (value >= -8) && (value <= 7);
    
protected static booleansignedFitsInShort(int value)
Helper method to determine if a signed int value fits in a short.

param
value the value in question
return
{@code true} iff it's in the range -0x8000..+0x7fff

        return (short) value == value;
    
protected static booleanunsignedFitsInByte(int value)
Helper method to determine if an unsigned int value fits in a byte.

param
value the value in question
return
{@code true} iff it's in the range 0..0xff

        return value == (value & 0xff);
    
protected static booleanunsignedFitsInNibble(int value)
Helper method to determine if an unsigned int value fits in a nibble.

param
value the value in question
return
{@code true} iff it's in the range 0..0xf

        return value == (value & 0xf);
    
protected static booleanunsignedFitsInShort(int value)
Helper method to determine if an unsigned int value fits in a short.

param
value the value in question
return
{@code true} iff it's in the range 0..0xffff

        return value == (value & 0xffff);
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0)
Writes one code unit to the given output destination.

param
out {@code non-null;} where to write to
param
c0 code unit to write

        out.writeShort(c0);
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0, short c1)
Writes two code units to the given output destination.

param
out {@code non-null;} where to write to
param
c0 code unit to write
param
c1 code unit to write

        out.writeShort(c0);
        out.writeShort(c1);
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0, short c1, short c2)
Writes three code units to the given output destination.

param
out {@code non-null;} where to write to
param
c0 code unit to write
param
c1 code unit to write
param
c2 code unit to write

        out.writeShort(c0);
        out.writeShort(c1);
        out.writeShort(c2);
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0, short c1, short c2, short c3)
Writes four code units to the given output destination.

param
out {@code non-null;} where to write to
param
c0 code unit to write
param
c1 code unit to write
param
c2 code unit to write
param
c3 code unit to write

        out.writeShort(c0);
        out.writeShort(c1);
        out.writeShort(c2);
        out.writeShort(c3);
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0, short c1, short c2, short c3, short c4)
Writes five code units to the given output destination.

param
out {@code non-null;} where to write to
param
c0 code unit to write
param
c1 code unit to write
param
c2 code unit to write
param
c3 code unit to write
param
c4 code unit to write

        out.writeShort(c0);
        out.writeShort(c1);
        out.writeShort(c2);
        out.writeShort(c3);
        out.writeShort(c4);
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0, int c1c2)
Writes three code units to the given output destination, where the second and third are represented as single int and emitted in little-endian order.

param
out {@code non-null;} where to write to
param
c0 code unit to write
param
c1c2 code unit pair to write

        write(out, c0, (short) c1c2, (short) (c1c2 >> 16));
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0, int c1c2, short c3)
Writes four code units to the given output destination, where the second and third are represented as single int and emitted in little-endian order.

param
out {@code non-null;} where to write to
param
c0 code unit to write
param
c1c2 code unit pair to write
param
c3 code unit to write

        write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3);
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0, int c1c2, short c3, short c4)
Writes five code units to the given output destination, where the second and third are represented as single int and emitted in little-endian order.

param
out {@code non-null;} where to write to
param
c0 code unit to write
param
c1c2 code unit pair to write
param
c3 code unit to write
param
c4 code unit to write

        write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3, c4);
    
protected static voidwrite(com.android.dx.util.AnnotatedOutput out, short c0, long c1c2c3c4)
Writes five code units to the given output destination, where the second through fifth are represented as single long and emitted in little-endian order.

param
out {@code non-null;} where to write to
param
c0 code unit to write
param
c1c2c3c4 code unit quad to write

        write(out, c0, (short) c1c2c3c4, (short) (c1c2c3c4 >> 16),
                (short) (c1c2c3c4 >> 32), (short) (c1c2c3c4 >> 48));
    
public abstract voidwriteTo(com.android.dx.util.AnnotatedOutput out, DalvInsn insn)
Writes the code units for the given instruction to the given output destination. The instruction must be of this instance's format.

Subclasses must override this method.

param
out {@code non-null;} the output destination to write to
param
insn {@code non-null;} the instruction to write