com.android.dx.io.instructions.DecodedInstruction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.io.instructions;
import com.android.dex.DexException;
import com.android.dx.io.IndexType;
import com.android.dx.io.OpcodeInfo;
import com.android.dx.io.Opcodes;
import com.android.dx.util.Hex;
import java.io.EOFException;
/**
* A decoded Dalvik instruction. This consists of a format codec, a
* numeric opcode, an optional index type, and any additional
* arguments of the instruction. The additional arguments (if any) are
* represented as uninterpreted data.
*
* Note: The names of the arguments are not meant to
* match the names given in the Dalvik instruction format
* specification, specification which just names fields (somewhat)
* arbitrarily alphabetically from A. In this class, non-register
* fields are given descriptive names and register fields are
* consistently named alphabetically.
*/
public abstract class DecodedInstruction {
/** non-null; instruction format / codec */
private final InstructionCodec format;
/** opcode number */
private final int opcode;
/** constant index argument */
private final int index;
/** null-ok; index type */
private final IndexType indexType;
/**
* target address argument. This is an absolute address, not just
* a signed offset. Note: The address is unsigned, even
* though it is stored in an {@code int}.
*/
private final int target;
/**
* literal value argument; also used for special verification error
* constants (format 20bc) as well as should-be-zero values
* (formats 10x, 20t, 30t, and 32x)
*/
private final long literal;
/**
* Decodes an instruction from the given input source.
*/
public static DecodedInstruction decode(CodeInput in) throws EOFException {
int opcodeUnit = in.read();
int opcode = Opcodes.extractOpcodeFromUnit(opcodeUnit);
InstructionCodec format = OpcodeInfo.getFormat(opcode);
return format.decode(opcodeUnit, in);
}
/**
* Decodes an array of instructions. The result has non-null
* elements at each offset that represents the start of an
* instruction.
*/
public static DecodedInstruction[] decodeAll(short[] encodedInstructions) {
int size = encodedInstructions.length;
DecodedInstruction[] decoded = new DecodedInstruction[size];
ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);
try {
while (in.hasMore()) {
decoded[in.cursor()] = DecodedInstruction.decode(in);
}
} catch (EOFException ex) {
throw new DexException(ex);
}
return decoded;
}
/**
* Constructs an instance.
*/
public DecodedInstruction(InstructionCodec format, int opcode,
int index, IndexType indexType, int target, long literal) {
if (format == null) {
throw new NullPointerException("format == null");
}
if (!Opcodes.isValidShape(opcode)) {
throw new IllegalArgumentException("invalid opcode");
}
this.format = format;
this.opcode = opcode;
this.index = index;
this.indexType = indexType;
this.target = target;
this.literal = literal;
}
public final InstructionCodec getFormat() {
return format;
}
public final int getOpcode() {
return opcode;
}
/**
* Gets the opcode, as a code unit.
*/
public final short getOpcodeUnit() {
return (short) opcode;
}
public final int getIndex() {
return index;
}
/**
* Gets the index, as a code unit.
*/
public final short getIndexUnit() {
return (short) index;
}
public final IndexType getIndexType() {
return indexType;
}
/**
* Gets the raw target.
*/
public final int getTarget() {
return target;
}
/**
* Gets the target as a relative offset from the given address.
*/
public final int getTarget(int baseAddress) {
return target - baseAddress;
}
/**
* Gets the target as a relative offset from the given base
* address, as a code unit. This will throw if the value is out of
* the range of a signed code unit.
*/
public final short getTargetUnit(int baseAddress) {
int relativeTarget = getTarget(baseAddress);
if (relativeTarget != (short) relativeTarget) {
throw new DexException("Target out of range: "
+ Hex.s4(relativeTarget));
}
return (short) relativeTarget;
}
/**
* Gets the target as a relative offset from the given base
* address, masked to be a byte in size. This will throw if the
* value is out of the range of a signed byte.
*/
public final int getTargetByte(int baseAddress) {
int relativeTarget = getTarget(baseAddress);
if (relativeTarget != (byte) relativeTarget) {
throw new DexException("Target out of range: "
+ Hex.s4(relativeTarget));
}
return relativeTarget & 0xff;
}
public final long getLiteral() {
return literal;
}
/**
* Gets the literal value, masked to be an int in size. This will
* throw if the value is out of the range of a signed int.
*/
public final int getLiteralInt() {
if (literal != (int) literal) {
throw new DexException("Literal out of range: " + Hex.u8(literal));
}
return (int) literal;
}
/**
* Gets the literal value, as a code unit. This will throw if the
* value is out of the range of a signed code unit.
*/
public final short getLiteralUnit() {
if (literal != (short) literal) {
throw new DexException("Literal out of range: " + Hex.u8(literal));
}
return (short) literal;
}
/**
* Gets the literal value, masked to be a byte in size. This will
* throw if the value is out of the range of a signed byte.
*/
public final int getLiteralByte() {
if (literal != (byte) literal) {
throw new DexException("Literal out of range: " + Hex.u8(literal));
}
return (int) literal & 0xff;
}
/**
* Gets the literal value, masked to be a nibble in size. This
* will throw if the value is out of the range of a signed nibble.
*/
public final int getLiteralNibble() {
if ((literal < -8) || (literal > 7)) {
throw new DexException("Literal out of range: " + Hex.u8(literal));
}
return (int) literal & 0xf;
}
public abstract int getRegisterCount();
public int getA() {
return 0;
}
public int getB() {
return 0;
}
public int getC() {
return 0;
}
public int getD() {
return 0;
}
public int getE() {
return 0;
}
/**
* Gets the register count, as a code unit. This will throw if the
* value is out of the range of an unsigned code unit.
*/
public final short getRegisterCountUnit() {
int registerCount = getRegisterCount();
if ((registerCount & ~0xffff) != 0) {
throw new DexException("Register count out of range: "
+ Hex.u8(registerCount));
}
return (short) registerCount;
}
/**
* Gets the A register number, as a code unit. This will throw if the
* value is out of the range of an unsigned code unit.
*/
public final short getAUnit() {
int a = getA();
if ((a & ~0xffff) != 0) {
throw new DexException("Register A out of range: " + Hex.u8(a));
}
return (short) a;
}
/**
* Gets the A register number, as a byte. This will throw if the
* value is out of the range of an unsigned byte.
*/
public final short getAByte() {
int a = getA();
if ((a & ~0xff) != 0) {
throw new DexException("Register A out of range: " + Hex.u8(a));
}
return (short) a;
}
/**
* Gets the A register number, as a nibble. This will throw if the
* value is out of the range of an unsigned nibble.
*/
public final short getANibble() {
int a = getA();
if ((a & ~0xf) != 0) {
throw new DexException("Register A out of range: " + Hex.u8(a));
}
return (short) a;
}
/**
* Gets the B register number, as a code unit. This will throw if the
* value is out of the range of an unsigned code unit.
*/
public final short getBUnit() {
int b = getB();
if ((b & ~0xffff) != 0) {
throw new DexException("Register B out of range: " + Hex.u8(b));
}
return (short) b;
}
/**
* Gets the B register number, as a byte. This will throw if the
* value is out of the range of an unsigned byte.
*/
public final short getBByte() {
int b = getB();
if ((b & ~0xff) != 0) {
throw new DexException("Register B out of range: " + Hex.u8(b));
}
return (short) b;
}
/**
* Gets the B register number, as a nibble. This will throw if the
* value is out of the range of an unsigned nibble.
*/
public final short getBNibble() {
int b = getB();
if ((b & ~0xf) != 0) {
throw new DexException("Register B out of range: " + Hex.u8(b));
}
return (short) b;
}
/**
* Gets the C register number, as a code unit. This will throw if the
* value is out of the range of an unsigned code unit.
*/
public final short getCUnit() {
int c = getC();
if ((c & ~0xffff) != 0) {
throw new DexException("Register C out of range: " + Hex.u8(c));
}
return (short) c;
}
/**
* Gets the C register number, as a byte. This will throw if the
* value is out of the range of an unsigned byte.
*/
public final short getCByte() {
int c = getC();
if ((c & ~0xff) != 0) {
throw new DexException("Register C out of range: " + Hex.u8(c));
}
return (short) c;
}
/**
* Gets the C register number, as a nibble. This will throw if the
* value is out of the range of an unsigned nibble.
*/
public final short getCNibble() {
int c = getC();
if ((c & ~0xf) != 0) {
throw new DexException("Register C out of range: " + Hex.u8(c));
}
return (short) c;
}
/**
* Gets the D register number, as a code unit. This will throw if the
* value is out of the range of an unsigned code unit.
*/
public final short getDUnit() {
int d = getD();
if ((d & ~0xffff) != 0) {
throw new DexException("Register D out of range: " + Hex.u8(d));
}
return (short) d;
}
/**
* Gets the D register number, as a byte. This will throw if the
* value is out of the range of an unsigned byte.
*/
public final short getDByte() {
int d = getD();
if ((d & ~0xff) != 0) {
throw new DexException("Register D out of range: " + Hex.u8(d));
}
return (short) d;
}
/**
* Gets the D register number, as a nibble. This will throw if the
* value is out of the range of an unsigned nibble.
*/
public final short getDNibble() {
int d = getD();
if ((d & ~0xf) != 0) {
throw new DexException("Register D out of range: " + Hex.u8(d));
}
return (short) d;
}
/**
* Gets the E register number, as a nibble. This will throw if the
* value is out of the range of an unsigned nibble.
*/
public final short getENibble() {
int e = getE();
if ((e & ~0xf) != 0) {
throw new DexException("Register E out of range: " + Hex.u8(e));
}
return (short) e;
}
/**
* Encodes this instance to the given output.
*/
public final void encode(CodeOutput out) {
format.encode(this, out);
}
/**
* Returns an instance just like this one, except with the index replaced
* with the given one.
*/
public abstract DecodedInstruction withIndex(int newIndex);
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy