More progress on instruction coding.
* Redefine the target to be an absolute, not relative, offset.
* Add a cursor to the CodeInput API.
* Recognize payload opcodes as valid.
* Add codecs for the payload instructions.
Change-Id: I77f8e5a9e2b6b72f6a1f5ecc2eb4d701edd66837
diff --git a/dx/src/com/android/dx/io/CodeInput.java b/dx/src/com/android/dx/io/CodeInput.java
index a4f7306..c0fea78 100644
--- a/dx/src/com/android/dx/io/CodeInput.java
+++ b/dx/src/com/android/dx/io/CodeInput.java
@@ -23,6 +23,13 @@
*/
public interface CodeInput {
/**
+ * Gets the cursor. This is the offset of the next code unit to
+ * be read from the start of the input (which is generally the
+ * start of a method).
+ */
+ public int cursor();
+
+ /**
* Reads a code unit.
*/
public int read() throws EOFException;
diff --git a/dx/src/com/android/dx/io/CodeOutput.java b/dx/src/com/android/dx/io/CodeOutput.java
index c87d1b1..76ad3a2 100644
--- a/dx/src/com/android/dx/io/CodeOutput.java
+++ b/dx/src/com/android/dx/io/CodeOutput.java
@@ -44,4 +44,9 @@
* Writes five code units.
*/
public void write(short u0, short u1, short u2, short u3, short u4);
+
+ /**
+ * Writes the contents of the given array.
+ */
+ public void write(short[] data);
}
diff --git a/dx/src/com/android/dx/io/DecodedInstruction.java b/dx/src/com/android/dx/io/DecodedInstruction.java
index 4e5b337..24ea919 100644
--- a/dx/src/com/android/dx/io/DecodedInstruction.java
+++ b/dx/src/com/android/dx/io/DecodedInstruction.java
@@ -44,7 +44,10 @@
/** null-ok; index type */
private final IndexType indexType;
- /** target address offset argument */
+ /**
+ * target address argument. This is an absolute address, not just a
+ * signed offset.
+ */
private final int target;
/**
diff --git a/dx/src/com/android/dx/io/InstructionCodec.java b/dx/src/com/android/dx/io/InstructionCodec.java
index 45d955c..d2cb92e 100644
--- a/dx/src/com/android/dx/io/InstructionCodec.java
+++ b/dx/src/com/android/dx/io/InstructionCodec.java
@@ -105,10 +105,11 @@
FORMAT_10T() {
@Override public DecodedInstruction decode(int opcodeUnit,
CodeInput in) throws EOFException {
+ int baseOffset = in.cursor() - 1;
int opcode = byte0(opcodeUnit);
- int a = (byte) byte1(opcodeUnit); // sign-extend
+ int target = (byte) byte1(opcodeUnit); // sign-extend
return new DecodedInstruction(this, opcode, 0, null,
- a, 0L, null,
+ baseOffset + target, 0L, null,
0, 0, 0, 0, 0, 0);
}
@@ -120,11 +121,12 @@
FORMAT_20T() {
@Override public DecodedInstruction decode(int opcodeUnit,
CodeInput in) throws EOFException {
+ int baseOffset = in.cursor() - 1;
int opcode = byte0(opcodeUnit);
int literal = byte1(opcodeUnit); // should be zero
int target = (short) in.read(); // sign-extend
return new DecodedInstruction(this, opcode, 0, null,
- target, literal, null,
+ baseOffset + target, literal, null,
0, 0, 0, 0, 0, 0);
}
@@ -174,11 +176,12 @@
FORMAT_21T() {
@Override public DecodedInstruction decode(int opcodeUnit,
CodeInput in) throws EOFException {
+ int baseOffset = in.cursor() - 1;
int opcode = byte0(opcodeUnit);
int a = byte1(opcodeUnit);
int target = (short) in.read(); // sign-extend
return new DecodedInstruction(this, opcode, 0, null,
- target, 0L, null,
+ baseOffset + target, 0L, null,
1, a, 0, 0, 0, 0);
}
@@ -299,12 +302,13 @@
FORMAT_22T() {
@Override public DecodedInstruction decode(int opcodeUnit,
CodeInput in) throws EOFException {
+ int baseOffset = in.cursor() - 1;
int opcode = byte0(opcodeUnit);
int a = nibble2(opcodeUnit);
int b = nibble3(opcodeUnit);
int target = (short) in.read(); // sign-extend
return new DecodedInstruction(this, opcode, 0, null,
- target, 0L, null,
+ baseOffset + target, 0L, null,
2, a, b, 0, 0, 0);
}
@@ -381,11 +385,12 @@
FORMAT_30T() {
@Override public DecodedInstruction decode(int opcodeUnit,
CodeInput in) throws EOFException {
+ int baseOffset = in.cursor() - 1;
int opcode = byte0(opcodeUnit);
int literal = byte1(opcodeUnit); // should be zero
int target = in.readInt();
return new DecodedInstruction(this, opcode, 0, null,
- target, literal, null,
+ baseOffset + target, literal, null,
0, 0, 0, 0, 0, 0);
}
@@ -435,11 +440,12 @@
FORMAT_31T() {
@Override public DecodedInstruction decode(int opcodeUnit,
CodeInput in) throws EOFException {
+ int baseOffset = in.cursor() - 1;
int opcode = byte0(opcodeUnit);
int a = byte1(opcodeUnit);
int target = in.readInt();
return new DecodedInstruction(this, opcode, 0, null,
- target, 0L, null,
+ baseOffset + target, 0L, null,
1, a, 0, 0, 0, 0);
}
@@ -688,6 +694,84 @@
insn.getRegisterCountUnit(),
insn.getAUnit());
}
+ },
+
+ FORMAT_PACKED_SWITCH_PAYLOAD() {
+ @Override public DecodedInstruction decode(int opcodeUnit,
+ CodeInput in) throws EOFException {
+ int size = in.read();
+ int unitCount = (size * 2) + 3; // Doesn't count the opcode unit.
+ short[] data = new short[unitCount];
+
+ data[0] = (short) size;
+
+ for (int i = 1; i < unitCount; i++) {
+ data[i] = (short) in.read();
+ }
+
+ return new DecodedInstruction(this, opcodeUnit, 0, null,
+ 0, 0L, data,
+ 0, 0, 0, 0, 0, 0);
+ }
+
+ @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(insn.getOpcodeUnit());
+ out.write(insn.getData());
+ }
+ },
+
+ FORMAT_SPARSE_SWITCH_PAYLOAD() {
+ @Override public DecodedInstruction decode(int opcodeUnit,
+ CodeInput in) throws EOFException {
+ int size = in.read();
+ int unitCount = (size * 4) + 1; // Doesn't count the opcode unit.
+ short[] data = new short[unitCount];
+
+ data[0] = (short) size;
+
+ for (int i = 1; i < unitCount; i++) {
+ data[i] = (short) in.read();
+ }
+
+ return new DecodedInstruction(this, opcodeUnit, 0, null,
+ 0, 0L, data,
+ 0, 0, 0, 0, 0, 0);
+ }
+
+ @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(insn.getOpcodeUnit());
+ out.write(insn.getData());
+ }
+ },
+
+ FORMAT_FILL_ARRAY_DATA_PAYLOAD() {
+ @Override public DecodedInstruction decode(int opcodeUnit,
+ CodeInput in) throws EOFException {
+ int elementWidth = in.read();
+ int size = in.readInt();
+
+ // Doesn't count the opcode unit.
+ int unitCount = (size * elementWidth + 1) / 2 + 3;
+
+ short[] data = new short[unitCount];
+
+ data[0] = unit0(size);
+ data[1] = unit1(size);
+ data[2] = (short) elementWidth;
+
+ for (int i = 3; i < unitCount; i++) {
+ data[i] = (short) in.read();
+ }
+
+ return new DecodedInstruction(this, opcodeUnit, 0, null,
+ 0, 0L, data,
+ 0, 0, 0, 0, 0, 0);
+ }
+
+ @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(insn.getOpcodeUnit());
+ out.write(insn.getData());
+ }
};
/**
diff --git a/dx/src/com/android/dx/io/OpcodeInfo.java b/dx/src/com/android/dx/io/OpcodeInfo.java
index 133e943..4507d9b 100644
--- a/dx/src/com/android/dx/io/OpcodeInfo.java
+++ b/dx/src/com/android/dx/io/OpcodeInfo.java
@@ -30,6 +30,20 @@
/** non-null; array containing all the information */
private static final Info[] INFO;
+ // TODO: These payload opcodes should be generated by opcode-gen.
+
+ public static final Info PACKED_SWITCH_PAYLOAD =
+ new Info(Opcodes.PACKED_SWITCH_PAYLOAD,
+ InstructionCodec.FORMAT_PACKED_SWITCH_PAYLOAD, null);
+
+ public static final Info SPARSE_SWITCH_PAYLOAD =
+ new Info(Opcodes.SPARSE_SWITCH_PAYLOAD,
+ InstructionCodec.FORMAT_SPARSE_SWITCH_PAYLOAD, null);
+
+ public static final Info FILL_ARRAY_DATA_PAYLOAD =
+ new Info(Opcodes.FILL_ARRAY_DATA_PAYLOAD,
+ InstructionCodec.FORMAT_FILL_ARRAY_DATA_PAYLOAD, null);
+
// BEGIN(opcode-info-defs); GENERATED AUTOMATICALLY BY opcode-gen
public static final Info NOP =
new Info(Opcodes.NOP,
@@ -1065,6 +1079,11 @@
static {
INFO = new Info[Opcodes.MAX_VALUE - Opcodes.MIN_VALUE + 1];
+ // TODO: These payload opcodes should be generated by opcode-gen.
+ set(PACKED_SWITCH_PAYLOAD);
+ set(SPARSE_SWITCH_PAYLOAD);
+ set(FILL_ARRAY_DATA_PAYLOAD);
+
// BEGIN(opcode-info-init); GENERATED AUTOMATICALLY BY opcode-gen
set(NOP);
set(MOVE);
diff --git a/dx/src/com/android/dx/io/Opcodes.java b/dx/src/com/android/dx/io/Opcodes.java
index 51d92c2..bf0aa66 100644
--- a/dx/src/com/android/dx/io/Opcodes.java
+++ b/dx/src/com/android/dx/io/Opcodes.java
@@ -21,7 +21,11 @@
* document for the meaning and instruction format of each opcode.
*/
public final class Opcodes {
- /** pseudo-opcode used for nonstandard format "instructions" */
+ /**
+ * pseudo-opcode used for nonstandard format payload "instructions". TODO:
+ * Retire this concept, and start treating the payload instructions
+ * more like the rest.
+ */
public static final int SPECIAL_FORMAT = -1;
/**
@@ -296,6 +300,8 @@
public static final int INVOKE_INTERFACE_JUMBO = 0x26ff;
// END(opcodes)
+ // TODO: Generate these payload opcodes with opcode-gen.
+
/**
* special pseudo-opcode value for packed-switch data payload
* instructions
@@ -336,21 +342,23 @@
public static boolean isValidShape(int opcode) {
/*
* Note: This method bakes in knowledge that all opcodes are
- * either single-byte or of the form ((byteValue << 8) |
- * 0xff).
+ * either single-byte or of the forms (byteValue << 8) or
+ * ((byteValue << 8) 0xff).
*/
// Note: SPECIAL_FORMAT == NO_NEXT.
- if ((opcode >= SPECIAL_FORMAT) && (opcode <= 0xff)) {
+ if (opcode < SPECIAL_FORMAT) {
+ return false;
+ } else if (opcode == SPECIAL_FORMAT) {
return true;
}
- if ((opcode >= 0xff) && (opcode <= 0xffff)
- && ((opcode & 0xff) == 0xff)) {
+ int lowByte = opcode & 0xff;
+ if ((lowByte == 0) || (lowByte == 0xff)) {
return true;
}
- return false;
+ return (opcode & 0xff00) == 0;
}
/**
@@ -360,11 +368,11 @@
public static int extractOpcodeFromUnit(int opcodeUnit) {
/*
* Note: This method bakes in knowledge that all opcodes are
- * either single-byte or of the form ((byteValue << 8) |
- * 0xff).
+ * either single-byte or of the forms (byteValue << 8) or
+ * ((byteValue << 8) 0xff).
*/
int lowByte = opcodeUnit & 0xff;
- return (lowByte == 0xff) ? opcodeUnit : lowByte;
+ return ((lowByte == 0) || (lowByte == 0xff)) ? opcodeUnit : lowByte;
}
}
diff --git a/dx/src/com/android/dx/io/ShortArrayCodeInput.java b/dx/src/com/android/dx/io/ShortArrayCodeInput.java
index c0faf71..da80df6 100644
--- a/dx/src/com/android/dx/io/ShortArrayCodeInput.java
+++ b/dx/src/com/android/dx/io/ShortArrayCodeInput.java
@@ -41,6 +41,11 @@
}
/** @inheritDoc */
+ public int cursor() {
+ return cursor;
+ }
+
+ /** @inheritDoc */
public int read() throws EOFException {
try {
return array[cursor++];