Changed the "from-scratch" constructor in the format classes to a static emit method

git-svn-id: https://smali.googlecode.com/svn/trunk@410 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-08-24 05:42:49 +00:00
parent f75a5c351c
commit 83e6f4bb60
29 changed files with 453 additions and 437 deletions

View File

@ -31,6 +31,7 @@ package org.jf.dexlib.Code.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
import org.jf.dexlib.DexFile;
import java.util.Iterator;
@ -44,27 +45,18 @@ public class ArrayDataPseudoInstruction extends Instruction {
return size + (size & 0x01) + 8;
}
public ArrayDataPseudoInstruction(int elementWidth, byte[] encodedValues) {
super(Opcode.NOP, encodedValues.length + (encodedValues.length & 1) + 8);
public static void emit(Output out, int elementWidth, byte[] encodedValues) {
if (encodedValues.length % elementWidth != 0) {
throw new RuntimeException("There are not a whole number of " + elementWidth + " byte elements");
}
int elementCount = buffer.length / elementWidth;
int elementCount = encodedValues.length / elementWidth;
buffer[0] = 0x00;
buffer[1] = 0x03; //fill-array-data psuedo-opcode
buffer[2] = (byte) elementWidth;
buffer[3] = (byte) (elementWidth >> 8);
buffer[4] = (byte) elementCount;
buffer[5] = (byte) (elementCount >> 8);
buffer[6] = (byte) (elementCount >> 16);
buffer[7] = (byte) (elementCount >> 24);
System.arraycopy(encodedValues, 0, buffer, 8, encodedValues.length);
out.writeByte(0x00);
out.writeShort(0x03);
out.writeShort(elementWidth);
out.writeInt(elementCount);
out.write(encodedValues);
}
public ArrayDataPseudoInstruction(byte[] buffer, int bufferIndex) {

View File

@ -31,19 +31,18 @@ package org.jf.dexlib.Code.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.Output;
public class Instruction10t extends Instruction {
public static final InstructionFactory Factory = new Factory();
public Instruction10t(Opcode opcode, byte offA) {
super(opcode);
public static void emit(Output out, Opcode opcode, byte offA) {
if (offA == 0) {
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead.");
}
buffer[0] = opcode.value;
buffer[1] = offA;
out.writeByte(opcode.value);
out.writeByte(offA);
}
private Instruction10t(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -31,14 +31,13 @@ package org.jf.dexlib.Code.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.Output;
public class Instruction10x extends Instruction {
public static final InstructionFactory Factory = new Factory();
public Instruction10x(Opcode opcode) {
super(opcode);
buffer[0] = opcode.value;
public static void emit(Output out, Opcode opcode) {
out.writeByte(opcode.value);
}
public Instruction10x(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,13 +32,12 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction11n extends Instruction {
public static final InstructionFactory Factory = new Factory();
public Instruction11n(Opcode opcode, byte regA, byte litB) {
super(opcode);
public static void emit(Output out, Opcode opcode, byte regA, byte litB) {
if (regA >= 1 << 4) {
throw new RuntimeException("The register number must be less than v16");
}
@ -48,8 +47,8 @@ public class Instruction11n extends Instruction {
throw new RuntimeException("The literal value must be between -8 and 7 inclusive");
}
buffer[0] = opcode.value;
buffer[1] = (byte) ((litB << 4) | regA);
out.writeByte(opcode.value);
out.writeByte((litB << 4) | regA);
}
private Instruction11n(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,19 +32,18 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction11x extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction11x(Opcode opcode, short regA) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
out.writeByte(opcode.value);
out.writeByte(regA);
}
private Instruction11x(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,20 +32,19 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction12x extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction12x(Opcode opcode, byte regA, byte regB) {
super(opcode);
public static void emit(Output out, Opcode opcode, byte regA, byte regB) {
if (regA >= 1 << 4 ||
regB >= 1 << 4) {
throw new RuntimeException("The register number must be less than v16");
}
buffer[0] = opcode.value;
buffer[1] = (byte) ((regB << 4) | regA);
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
}
private Instruction12x(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,20 +32,18 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction20t extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction20t(Opcode opcode, short offA) {
super(opcode);
public static void emit(Output out, Opcode opcode, short offA) {
if (offA == 0) {
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead.");
}
buffer[0] = opcode.value;
buffer[2] = (byte) offA;
buffer[3] = (byte) (offA >> 8);
out.writeByte(opcode.value);
out.writeShort(offA);
}
private Instruction20t(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -35,24 +35,26 @@ import org.jf.dexlib.DexFile;
import org.jf.dexlib.Item;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction21c extends InstructionWithReference {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction21c(Opcode opcode, short regA, Item referencedItem) {
super(opcode, referencedItem);
public static void emit(Output out, Opcode opcode, short regA, Item referencedItem) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
if (opcode == Opcode.NEW_INSTANCE && ((TypeIdItem) referencedItem).getTypeDescriptor().charAt(0) != 'L') {
throw new RuntimeException("Only class references can be used with the new-instance opcode");
if (opcode == Opcode.NEW_INSTANCE) {
assert referencedItem instanceof TypeIdItem;
if (((TypeIdItem)referencedItem).getTypeDescriptor().charAt(0) != 'L') {
throw new RuntimeException("Only class references can be used with the new-instance opcode");
}
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
//the item index will be set later, during placement/writing
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(0);
}
private Instruction21c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,21 +32,19 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction21h extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction21h(Opcode opcode, short regA, short litB) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, short litB) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) litB;
buffer[3] = (byte) (litB >> 8);
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(litB);
}
private Instruction21h(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,21 +32,19 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction21s extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction21s(Opcode opcode, short regA, short litB) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, short litB) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) litB;
buffer[3] = (byte) (litB >> 8);
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(litB);
}
private Instruction21s(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,13 +32,12 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction21t extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction21t(Opcode opcode, short regA, short offB) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, short offB) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
@ -47,10 +46,9 @@ public class Instruction21t extends Instruction {
throw new RuntimeException("The offset cannot be 0.");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) offB;
buffer[3] = (byte) (offB >> 8);
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(offB);
}
private Instruction21t(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,22 +32,21 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction22b extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction22b(Opcode opcode, short regA, short regB, byte litC) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, short regB, byte litC) {
if (regA >= 1 << 8 ||
regB >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) regB;
buffer[3] = litC;
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeByte(regB);
out.writeByte(litC);
}
private Instruction22b(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -34,21 +34,20 @@ import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Item;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction22c extends InstructionWithReference {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction22c(Opcode opcode, byte regA, byte regB, Item referencedItem) {
super(opcode, referencedItem);
public static void emit(Output out, Opcode opcode, byte regA, byte regB) {
if (regA >= 1 << 4 ||
regB >= 1 << 4) {
throw new RuntimeException("The register number must be less than v16");
}
buffer[0] = opcode.value;
buffer[1] = (byte) ((regB << 4) | regA);
//the item index will be set later, during placement/writing
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
out.writeShort(0);
}
private Instruction22c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,22 +32,20 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction22s extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction22s(Opcode opcode, byte regA, byte regB, short litC) {
super(opcode);
public static void emit(Output out, Opcode opcode, byte regA, byte regB, short litC) {
if (regA >= 1 << 4 ||
regB >= 1 << 4) {
throw new RuntimeException("The register number must be less than v16");
}
buffer[0] = opcode.value;
buffer[1] = (byte) ((regB << 4) | regA);
buffer[2] = (byte) litC;
buffer[3] = (byte) (litC >> 8);
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
out.writeShort(litC);
}
private Instruction22s(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,13 +32,12 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction22t extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction22t(Opcode opcode, byte regA, byte regB, short offC) {
super(opcode);
public static void emit(Output out, Opcode opcode, byte regA, byte regB, short offC) {
if (regA >= 1 << 4 ||
regB >= 1 << 4) {
throw new RuntimeException("The register number must be less than v16");
@ -48,10 +47,9 @@ public class Instruction22t extends Instruction {
throw new RuntimeException("The offset cannot be 0.");
}
buffer[0] = opcode.value;
buffer[1] = (byte) ((regB << 4) | regA);
buffer[2] = (byte) offC;
buffer[3] = (byte) (offC >> 8);
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
out.writeShort(offC);
}
private Instruction22t(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,13 +32,12 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction22x extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction22x(Opcode opcode, short regA, int regB) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, int regB) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v16");
}
@ -47,10 +46,9 @@ public class Instruction22x extends Instruction {
throw new RuntimeException("The register number must be less than v65536");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) regB;
buffer[3] = (byte) (regB >> 8);
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(regB);
}
private Instruction22x(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,23 +32,22 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction23x extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction23x(Opcode opcode, short regA, short regB, short regC) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, short regB, short regC) {
if (regA >= 1 << 8 ||
regB >= 1 << 8 ||
regC >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) regB;
buffer[3] = (byte) regC;
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeByte(regB);
out.writeByte(regC);
}
private Instruction23x(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,19 +32,15 @@ import org.jf.dexlib.DexFile;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction30t extends Instruction
{
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction30t(Opcode opcode, int offA) {
super(opcode);
buffer[0] = opcode.value;
buffer[2] = (byte)offA;
buffer[3] = (byte)(offA >> 8);
buffer[4] = (byte)(offA >> 16);
buffer[5] = (byte)(offA >> 24);
public static void emit(Output out, Opcode opcode, int offA) {
out.writeByte(opcode.value);
out.writeInt(offA);
}
private Instruction30t(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -34,20 +34,19 @@ import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Item;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction31c extends InstructionWithReference {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction31c(Opcode opcode, short regA, Item referencedItem) {
super(opcode, referencedItem);
public static void emit(Output out, Opcode opcode, short regA) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
//the item index will be set later, during placement/writing
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeInt(0);
}
private Instruction31c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,23 +32,19 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction31i extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction31i(Opcode opcode, short regA, int litB) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, int litB) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) litB;
buffer[3] = (byte) (litB >> 8);
buffer[4] = (byte) (litB >> 16);
buffer[5] = (byte) (litB >> 24);
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeInt(litB);
}
private Instruction31i(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,23 +32,19 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction31t extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction31t(Opcode opcode, short regA, int offB) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, int offB) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) offB;
buffer[3] = (byte) (offB >> 8);
buffer[4] = (byte) (offB >> 16);
buffer[5] = (byte) (offB >> 24);
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeInt(offB);
}
private Instruction31t(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -32,24 +32,22 @@ import org.jf.dexlib.DexFile;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction32x extends Instruction
{
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction32x(Opcode opcode, int regA, int regB) {
super(opcode);
public static void emit(Output out, Opcode opcode, int regA, int regB) {
if (regA >= 1<<16 ||
regB >= 1<<16) {
throw new RuntimeException("The register number must be less than v65536");
}
buffer[0] = opcode.value;
buffer[2] = (byte)regA;
buffer[3] = (byte)(regA >> 8);
buffer[4] = (byte)regB;
buffer[5] = (byte)(regB >> 8);
out.writeByte(opcode.value);
out.writeByte(0);
out.writeShort(regA);
out.writeShort(regB);
}
private Instruction32x(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -37,14 +37,13 @@ import org.jf.dexlib.Item;
import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction35c extends InstructionWithReference {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction35c(Opcode opcode, int regCount, byte regD, byte regE, byte regF, byte regG,
public static void emit(Output out, Opcode opcode, int regCount, byte regD, byte regE, byte regF, byte regG,
byte regA, Item referencedItem) {
super(opcode, referencedItem);
if (regCount > 5) {
throw new RuntimeException("regCount cannot be greater than 5");
}
@ -57,13 +56,13 @@ public class Instruction35c extends InstructionWithReference {
throw new RuntimeException("All register args must fit in 4 bits");
}
buffer[0] = opcode.value;
buffer[1] = (byte) ((regCount << 4) | regA);
//the item index will be set later, during placement/writing
buffer[4] = (byte) ((regE << 4) | regD);
buffer[5] = (byte) ((regG << 4) | regF);
out.writeByte(opcode.value);
out.writeByte((regCount << 4) | regA);
out.writeShort(0);
out.writeByte((regE << 4) | regD);
out.writeByte((regG << 4) | regF);
checkItem();
checkItem(opcode, referencedItem, regCount);
}
private Instruction35c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
@ -73,7 +72,7 @@ public class Instruction35c extends InstructionWithReference {
throw new RuntimeException("regCount cannot be greater than 5");
}
checkItem();
checkItem(opcode, getReferencedItem(), getRegCount());
}
public Format getFormat() {
@ -104,9 +103,7 @@ public class Instruction35c extends InstructionWithReference {
return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 5]);
}
private void checkItem() {
Item item = getReferencedItem();
private static void checkItem(Opcode opcode, Item item, int regCount) {
if (opcode == FILLED_NEW_ARRAY) {
//check data for filled-new-array opcode
String type = ((TypeIdItem) item).getTypeDescriptor();
@ -123,7 +120,7 @@ public class Instruction35c extends InstructionWithReference {
if (opcode != INVOKE_STATIC) {
parameterRegisterCount++;
}
if (parameterRegisterCount != getRegCount()) {
if (parameterRegisterCount != regCount) {
throw new RuntimeException("regCount does not match the number of arguments of the method");
}
}

View File

@ -37,13 +37,12 @@ import org.jf.dexlib.Item;
import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction3rc extends InstructionWithReference {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction3rc(Opcode opcode, short regCount, int startReg, Item referencedItem) {
super(opcode, referencedItem);
public static void emit(Output out, Opcode opcode, short regCount, int startReg, Item referencedItem) {
if (regCount >= 1 << 8) {
throw new RuntimeException("regCount must be less than 256");
}
@ -58,19 +57,18 @@ public class Instruction3rc extends InstructionWithReference {
throw new RuntimeException("The beginning register of the range cannot be negative");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regCount;
//the item index will be set later, during placement/writing
buffer[4] = (byte) startReg;
buffer[5] = (byte) (startReg >> 8);
out.writeByte(opcode.value);
out.writeByte(regCount);
out.writeShort(0);
out.writeShort(startReg);
checkItem();
checkItem(opcode, referencedItem, regCount);
}
private Instruction3rc(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
super(dexFile, opcode, buffer, bufferIndex);
checkItem();
checkItem(opcode, getReferencedItem(), getRegCount());
}
public Format getFormat() {
@ -85,9 +83,7 @@ public class Instruction3rc extends InstructionWithReference {
return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4);
}
private void checkItem() {
Item item = getReferencedItem();
private static void checkItem(Opcode opcode, Item item, int regCount) {
if (opcode == FILLED_NEW_ARRAY_RANGE) {
//check data for filled-new-array/range opcode
String type = ((TypeIdItem) item).getTypeDescriptor();
@ -104,7 +100,7 @@ public class Instruction3rc extends InstructionWithReference {
if (opcode != INVOKE_STATIC_RANGE) {
parameterRegisterCount++;
}
if (parameterRegisterCount != getRegCount()) {
if (parameterRegisterCount != regCount) {
throw new RuntimeException("regCount does not match the number of arguments of the method");
}
}

View File

@ -32,27 +32,19 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
public class Instruction51l extends Instruction {
public static final Instruction.InstructionFactory Factory = new Factory();
public Instruction51l(Opcode opcode, short regA, long litB) {
super(opcode);
public static void emit(Output out, Opcode opcode, short regA, long litB) {
if (regA >= 1 << 8) {
throw new RuntimeException("The register number must be less than v256");
}
buffer[0] = opcode.value;
buffer[1] = (byte) regA;
buffer[2] = (byte) litB;
buffer[3] = (byte) (litB >> 8);
buffer[4] = (byte) (litB >> 16);
buffer[5] = (byte) (litB >> 24);
buffer[6] = (byte) (litB >> 32);
buffer[7] = (byte) (litB >> 40);
buffer[8] = (byte) (litB >> 48);
buffer[9] = (byte) (litB >> 56);
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeLong(litB);
}
private Instruction51l(Opcode opcode, byte[] buffer, int bufferIndex) {

View File

@ -31,6 +31,7 @@ package org.jf.dexlib.Code.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
import org.jf.dexlib.DexFile;
import java.util.Iterator;
@ -43,34 +44,19 @@ public class PackedSwitchDataPseudoInstruction extends Instruction {
return getTargetCount() * 4 + 8;
}
public PackedSwitchDataPseudoInstruction(int firstKey, int[] targets) {
super(Opcode.NOP, targets.length * 4 + 8);
/*this.firstKey = firstKey;
this.targets = targets;*/
public static void emit(Output out, int firstKey, int[] targets) {
if (targets.length > 0xFFFF) {
throw new RuntimeException("The packed-switch data contains too many elements. " +
"The maximum number of switch elements is 65535");
}
buffer[0] = 0x00;
buffer[1] = 0x01; //packed-switch pseudo-opcode
buffer[2] = (byte) targets.length;
buffer[3] = (byte) (targets.length >> 8);
buffer[4] = (byte) firstKey;
buffer[5] = (byte) (firstKey >> 8);
buffer[6] = (byte) (firstKey >> 16);
buffer[7] = (byte) (firstKey >> 24);
int position = 8;
out.writeByte(0x00);
out.writeByte(0x01);
out.writeShort(targets.length);
out.writeInt(firstKey);
for (int target : targets) {
buffer[position++] = (byte) target;
buffer[position++] = (byte) (target >> 8);
buffer[position++] = (byte) (target >> 16);
buffer[position++] = (byte) (target >> 24);
out.writeInt(target);
}
}

View File

@ -31,6 +31,7 @@ package org.jf.dexlib.Code.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Util.Output;
import org.jf.dexlib.DexFile;
import java.util.Iterator;
@ -43,9 +44,7 @@ public class SparseSwitchDataPseudoInstruction extends Instruction {
return getTargetCount() * 8 + 4;
}
public SparseSwitchDataPseudoInstruction(int[] keys, int[] targets) {
super(Opcode.NOP, keys.length * 8 + 4);
public static void emit(Output out, int[] keys, int[] targets) {
if (keys.length != targets.length) {
throw new RuntimeException("The number of keys and offsets don't match");
}
@ -59,20 +58,14 @@ public class SparseSwitchDataPseudoInstruction extends Instruction {
"The maximum number of switch elements is 65535");
}
buffer[0] = 0x00;
buffer[1] = 0x02; //sparse-switch psuedo-opcode
buffer[2] = (byte) targets.length;
buffer[3] = (byte) (targets.length >> 8);
int position = 8;
out.writeByte(0x00);
out.writeByte(0x02);
out.writeShort(targets.length);
if (targets.length > 0) {
int key = keys[0];
buffer[4] = (byte) key;
buffer[5] = (byte) (key >> 8);
buffer[6] = (byte) (key >> 16);
buffer[7] = (byte) (key >> 24);
out.writeInt(key);
for (int i = 1; i < keys.length; i++) {
key = keys[i];
@ -80,18 +73,11 @@ public class SparseSwitchDataPseudoInstruction extends Instruction {
throw new RuntimeException("The targets in a sparse switch block must be sorted in ascending" +
"order, by key");
}
buffer[position++] = (byte) key;
buffer[position++] = (byte) (key >> 8);
buffer[position++] = (byte) (key >> 16);
buffer[position++] = (byte) (key >> 24);
out.writeInt(key);
}
for (int target : targets) {
buffer[position++] = (byte) target;
buffer[position++] = (byte) (target >> 8);
buffer[position++] = (byte) (target >> 16);
buffer[position++] = (byte) (target >> 24);
out.writeInt(target);
}
}
}

View File

@ -37,6 +37,7 @@ options {
package org.jf.smali;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.regex.*;
import java.lang.Float;
import java.lang.Double;
@ -50,8 +51,7 @@ import org.jf.dexlib.Code.Format.*;
@members {
public DexFile dexFile;
public ClassDefItem classDefItem;
public ClassDataItem classDataItem;
public TypeIdItem classType;
private byte parseRegister_nibble(String register, int totalMethodRegisters, int methodParameterRegisters)
throws SemanticException {
@ -151,28 +151,30 @@ smali_file
: ^(I_CLASS_DEF header methods fields annotations)
{
AnnotationDirectoryItem annotationDirectoryItem = null;
if ( $methods.methodAnnotationSets != null ||
$methods.parameterAnnotationSets != null ||
$fields.fieldAnnotationSets != null ||
ClassDefItem classDefItem = null;
ClassDataItem classDataItem = null;
if ( $methods.methodAnnotations != null ||
$methods.parameterAnnotations != null ||
$fields.fieldAnnotations != null ||
$annotations.annotationSetItem != null) {
annotationDirectoryItem = new AnnotationDirectoryItem(
annotationDirectoryItem = AnnotationDirectoryItem.getInternedAnnotationDirectoryItem(
dexFile,
$annotations.annotationSetItem,
$fields.fieldAnnotationSets,
$methods.methodAnnotationSets,
$methods.parameterAnnotationSets);
$fields.fieldAnnotations,
$methods.methodAnnotations,
$methods.parameterAnnotations);
}
classDefItem.setAnnotations(annotationDirectoryItem);
if ((classDataItem.getStaticFields().size() +
classDataItem.getInstanceFields().size() +
classDataItem.getDirectMethods().size() +
classDataItem.getVirtualMethods().size()) == 0) {
classDefItem.setClassDataItem(null);
}
if ($fields.staticFields.size() != 0 || $fields.instanceFields.size() != 0 ||
$methods.directMethods.size() != 0 || $methods.virtualMethods.size()!= 0) {
classDataItem = ClassDataItem.getInternedClassDataItem(dexFile, $fields.staticFields, $fields.instanceFields,
$methods.directMethods, $methods.virtualMethods);
}
classDefItem = ClassDefItem.getInternedClassDefItem(dexFile, $header.classType, $header.accessFlags,
$header.superType, $header.implementsList, $header.sourceSpec, annotationDirectoryItem,
classDataItem, $fields.staticFieldInitialValues);
};
catch [Exception ex] {
reportError(new SemanticException(input, ex));
@ -183,9 +185,12 @@ smali_file
header returns[TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementsList, StringIdItem sourceSpec]
: class_spec super_spec? implements_list source_spec
{
classDataItem = new ClassDataItem(dexFile, 0);
classDefItem = new ClassDefItem(dexFile, $class_spec.type, $class_spec.accessFlags,
$super_spec.type, $implements_list.implementsList, $source_spec.source, classDataItem);
classType = $class_spec.type;
$classType = classType;
$accessFlags = $class_spec.accessFlags;
$superType = $super_spec.type;
$implementsList = $implements_list.implementsList;
$sourceSpec = $source_spec.source;
};
@ -210,15 +215,20 @@ implements_spec returns[TypeIdItem type]
};
implements_list returns[TypeListItem implementsList]
@init { ArrayList<TypeIdItem> typeList; }
: {typeList = new ArrayList<TypeIdItem>();}
@init { List<TypeIdItem> typeList; }
: {typeList = new LinkedList<TypeIdItem>();}
(implements_spec {typeList.add($implements_spec.type);} )*
{if (typeList.size() > 0) $implementsList = new TypeListItem(dexFile, typeList);
else $implementsList = null;};
{
if (typeList.size() > 0) {
$implementsList = TypeListItem.getInternedTypeListItem(dexFile, typeList);
} else {
$implementsList = null;
}
};
source_spec returns[StringIdItem source]
: {$source = null;}
^(I_SOURCE string_literal {$source = new StringIdItem(dexFile, $string_literal.value);})
^(I_SOURCE string_literal {$source = StringIdItem.getInternedStringIdItem(dexFile, $string_literal.value);})
| ;
@ -236,51 +246,82 @@ access_list returns [int value]
}
)*);
fields returns[List<AnnotationDirectoryItem.FieldAnnotation> fieldAnnotationSets]
fields returns[List<ClassDataItem.EncodedField> staticFields, List<ClassDataItem.EncodedField> instanceFields,
List<ClassDefItem.StaticFieldInitializer> staticFieldInitialValues, List<AnnotationDirectoryItem.FieldAnnotation> fieldAnnotations]
@init
{
$staticFields = new LinkedList<ClassDataItem.EncodedField>();
$instanceFields = new LinkedList<ClassDataItem.EncodedField>();
$staticFieldInitialValues = new LinkedList<ClassDefItem.StaticFieldInitializer>();
}
: ^(I_FIELDS
(field
{
classDefItem.addField($field.encodedField, $field.encodedValue);
if ($field.encodedField.isStatic()) {
$staticFields.add($field.encodedField);
$staticFieldInitialValues.add(new ClassDefItem.StaticFieldInitializer(
$field.encodedValue, $field.encodedField));
} else {
$instanceFields.add($field.encodedField);
}
if ($field.fieldAnnotationSet != null) {
if ($fieldAnnotationSets == null) {
$fieldAnnotationSets = new ArrayList<AnnotationDirectoryItem.FieldAnnotation>();
if ($fieldAnnotations == null) {
$fieldAnnotations = new LinkedList<AnnotationDirectoryItem.FieldAnnotation>();
}
fieldAnnotationSets.add($field.fieldAnnotationSet);
AnnotationDirectoryItem.FieldAnnotation fieldAnnotation = new AnnotationDirectoryItem.FieldAnnotation(
$field.encodedField.field, $field.fieldAnnotationSet);
$fieldAnnotations.add(fieldAnnotation);
}
})*);
methods returns[List<AnnotationDirectoryItem.MethodAnnotation> methodAnnotationSets,
List<AnnotationDirectoryItem.ParameterAnnotation> parameterAnnotationSets]
methods returns[List<ClassDataItem.EncodedMethod> directMethods,
List<ClassDataItem.EncodedMethod> virtualMethods,
List<AnnotationDirectoryItem.MethodAnnotation> methodAnnotations,
List<AnnotationDirectoryItem.ParameterAnnotation> parameterAnnotations]
@init
{
$directMethods = new LinkedList<ClassDataItem.EncodedMethod>();
$virtualMethods = new LinkedList<ClassDataItem.EncodedMethod>();
}
: ^(I_METHODS
(method
{
classDataItem.addMethod($method.encodedMethod);
if ($method.encodedMethod.isDirect()) {
$directMethods.add($method.encodedMethod);
} else {
$virtualMethods.add($method.encodedMethod);
}
if ($method.methodAnnotationSet != null) {
if ($methodAnnotationSets == null) {
$methodAnnotationSets = new ArrayList<AnnotationDirectoryItem.MethodAnnotation>();
if ($methodAnnotations == null) {
$methodAnnotations = new LinkedList<AnnotationDirectoryItem.MethodAnnotation>();
}
$methodAnnotationSets.add($method.methodAnnotationSet);
AnnotationDirectoryItem.MethodAnnotation methodAnnotation =
new AnnotationDirectoryItem.MethodAnnotation($method.encodedMethod.method, $method.methodAnnotationSet);
$methodAnnotations.add(methodAnnotation);
}
if ($method.parameterAnnotationSets != null) {
if ($parameterAnnotationSets == null) {
$parameterAnnotationSets = new ArrayList<AnnotationDirectoryItem.ParameterAnnotation>();
if ($parameterAnnotations == null) {
$parameterAnnotations = new LinkedList<AnnotationDirectoryItem.ParameterAnnotation>();
}
$parameterAnnotationSets.add($method.parameterAnnotationSets);
AnnotationDirectoryItem.ParameterAnnotation parameterAnnotation =
new AnnotationDirectoryItem.ParameterAnnotation($method.encodedMethod.method,
$method.parameterAnnotationSets);
$parameterAnnotations.add(parameterAnnotation);
}
})*);
field returns[ClassDataItem.EncodedField encodedField, EncodedValue encodedValue, AnnotationDirectoryItem.FieldAnnotation fieldAnnotationSet]
field returns [ClassDataItem.EncodedField encodedField, EncodedValue encodedValue, AnnotationSetItem fieldAnnotationSet]
:^(I_FIELD MEMBER_NAME access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) field_initial_value annotations?)
{
TypeIdItem classType = classDefItem.getClassType();
StringIdItem memberName = new StringIdItem(dexFile, $MEMBER_NAME.text);
StringIdItem memberName = StringIdItem.getInternedStringIdItem(dexFile, $MEMBER_NAME.text);
TypeIdItem fieldType = $nonvoid_type_descriptor.type;
FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, memberName, fieldType);
$encodedField = new ClassDataItem.EncodedField(dexFile, fieldIdItem, $access_list.value);
FieldIdItem fieldIdItem = FieldIdItem.getInternedFieldIdItem(dexFile, classType, fieldType, memberName);
$encodedField = new ClassDataItem.EncodedField(fieldIdItem, $access_list.value);
if ($field_initial_value.encodedValue != null) {
if (($access_list.value & AccessFlags.STATIC.getValue()) == 0) {
if (!$encodedField.isStatic()) {
throw new SemanticException(input, "Initial field values can only be specified for static fields.");
}
@ -290,7 +331,7 @@ field returns[ClassDataItem.EncodedField encodedField, EncodedValue encodedValue
}
if ($annotations.annotationSetItem != null) {
$fieldAnnotationSet = new AnnotationDirectoryItem.FieldAnnotation(dexFile, fieldIdItem, $annotations.annotationSetItem);
$fieldAnnotationSet = $annotations.annotationSetItem;
}
};
@ -300,22 +341,22 @@ field_initial_value returns[EncodedValue encodedValue]
| ;
literal returns[EncodedValue encodedValue]
: integer_literal { $encodedValue = new EncodedValue(dexFile, new IntEncodedValueSubField($integer_literal.value)); }
| long_literal { $encodedValue = new EncodedValue(dexFile, new LongEncodedValueSubField($long_literal.value)); }
| short_literal { $encodedValue = new EncodedValue(dexFile, new ShortEncodedValueSubField($short_literal.value)); }
| byte_literal { $encodedValue = new EncodedValue(dexFile, new ByteEncodedValueSubField($byte_literal.value)); }
| float_literal { $encodedValue = new EncodedValue(dexFile, new FloatEncodedValueSubField($float_literal.value)); }
| double_literal { $encodedValue = new EncodedValue(dexFile, new DoubleEncodedValueSubField($double_literal.value)); }
| char_literal { $encodedValue = new EncodedValue(dexFile, new CharEncodedValueSubField($char_literal.value)); }
| string_literal { $encodedValue = new EncodedValue(dexFile, new EncodedIndexedItemReference(dexFile, new StringIdItem(dexFile, $string_literal.value))); }
| bool_literal { $encodedValue = new EncodedValue(dexFile, new BoolEncodedValueSubField($bool_literal.value)); }
| NULL_LITERAL { $encodedValue = new EncodedValue(dexFile, new NullEncodedValueSubField()); }
| type_descriptor { $encodedValue = new EncodedValue(dexFile, new EncodedIndexedItemReference(dexFile, $type_descriptor.type)); }
| array_literal { $encodedValue = new EncodedValue(dexFile, new ArrayEncodedValueSubField(dexFile, $array_literal.values)); }
| subannotation { $encodedValue = new EncodedValue(dexFile, $subannotation.value); }
| field_literal { $encodedValue = new EncodedValue(dexFile, $field_literal.value); }
| method_literal { $encodedValue = new EncodedValue(dexFile, $method_literal.value); }
| enum_literal { $encodedValue = new EncodedValue(dexFile, $enum_literal.value); };
: integer_literal { $encodedValue = new IntEncodedValue($integer_literal.value); }
| long_literal { $encodedValue = new LongEncodedValue($long_literal.value); }
| short_literal { $encodedValue = new ShortEncodedValue($short_literal.value); }
| byte_literal { $encodedValue = new ByteEncodedValue($byte_literal.value); }
| float_literal { $encodedValue = new FloatEncodedValue($float_literal.value); }
| double_literal { $encodedValue = new DoubleEncodedValue($double_literal.value); }
| char_literal { $encodedValue = new CharEncodedValue($char_literal.value); }
| string_literal { $encodedValue = new StringEncodedValue(StringIdItem.getInternedStringIdItem(dexFile, $string_literal.value)); }
| bool_literal { $encodedValue = $bool_literal.value?BooleanEncodedValue.TrueValue:BooleanEncodedValue.FalseValue; }
| NULL_LITERAL { $encodedValue = NullEncodedValue.NullValue; }
| type_descriptor { $encodedValue = new TypeEncodedValue($type_descriptor.type); }
| array_literal { $encodedValue = new ArrayEncodedValue($array_literal.values); }
| subannotation { $encodedValue = new AnnotationEncodedValue($subannotation.annotationType, $subannotation.elementNames, $subannotation.elementValues); }
| field_literal { $encodedValue = new FieldEncodedValue($field_literal.value); }
| method_literal { $encodedValue = new MethodEncodedValue($method_literal.value); }
| enum_literal { $encodedValue = new EnumEncodedValue($enum_literal.value); };
//everything but string
@ -407,8 +448,8 @@ sparse_switch_targets[int baseAddress, int targetCount] returns[int[\] targets]
);
method returns[ ClassDataItem.EncodedMethod encodedMethod,
AnnotationDirectoryItem.MethodAnnotation methodAnnotationSet,
AnnotationDirectoryItem.ParameterAnnotation parameterAnnotationSets]
AnnotationSetItem methodAnnotationSet,
AnnotationSetRefList parameterAnnotationSets]
scope
{
HashMap<String, Integer> labels;
@ -441,7 +482,10 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
methodIdItem = $method_name_and_prototype.methodIdItem;
accessFlags = $access_list.value;
isStatic = (accessFlags & AccessFlags.STATIC.getValue()) != 0;
methodParameterRegisters = methodIdItem.getParameterRegisterCount(isStatic);
methodParameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
if (!isStatic) {
methodParameterRegisters++;
}
}
registers_directive
{
@ -457,9 +501,7 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
annotations
)
{
ArrayList<InstructionField> instructions = $statements.instructions;
Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> temp = $method::tryList.encodeTries(dexFile);
Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> temp = $method::tryList.encodeTries();
List<CodeItem.TryItem> tries = temp.first;
List<CodeItem.EncodedCatchHandler> handlers = temp.second;
@ -467,9 +509,9 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
DebugInfoItem debugInfoItem = $method::debugInfo.encodeDebugInfo(dexFile);
CodeItem codeItem;
if (totalMethodRegisters == 0 &&
instructions.size() == 0 &&
$statements.encodedInstructions.length == 0 &&
$method::labels.size()== 0 &&
(tries == null || tries.size() == 0) &&
(handlers == null || handlers.size() == 0) &&
@ -484,30 +526,32 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
" registers, for the method parameters");
}
int methodParameterCount = methodIdItem.getParameterCount();
int methodParameterCount = methodIdItem.getPrototype().getParameterRegisterCount();
if ($method::debugInfo.getParameterNameCount() > methodParameterCount) {
throw new SemanticException(input, "Too many parameter names specified. This method only has " +
Integer.toString(methodParameterCount) +
" parameters.");
}
codeItem = new CodeItem(dexFile,
codeItem = CodeItem.getInternedCodeItem(dexFile,
totalMethodRegisters,
methodIdItem.getParameterRegisterCount(isStatic),
instructions,
methodParameterRegisters,
$statements.maxOutRegisters,
debugInfoItem,
$statements.encodedInstructions,
$statements.referencedItems,
tries,
handlers);
}
$encodedMethod = new ClassDataItem.EncodedMethod(dexFile, methodIdItem, accessFlags, codeItem);
$encodedMethod = new ClassDataItem.EncodedMethod(methodIdItem, accessFlags, codeItem);
if ($annotations.annotationSetItem != null) {
$methodAnnotationSet = new AnnotationDirectoryItem.MethodAnnotation(dexFile, methodIdItem, $annotations.annotationSetItem);
$methodAnnotationSet = $annotations.annotationSetItem;
}
if ($parameters.parameterAnnotations != null) {
$parameterAnnotationSets = new AnnotationDirectoryItem.ParameterAnnotation(dexFile, methodIdItem, $parameters.parameterAnnotations);
$parameterAnnotationSets = $parameters.parameterAnnotations;
}
};
@ -515,26 +559,26 @@ method_prototype returns[ProtoIdItem protoIdItem]
: ^(I_METHOD_PROTOTYPE ^(I_METHOD_RETURN_TYPE type_descriptor) field_type_list)
{
TypeIdItem returnType = $type_descriptor.type;
ArrayList<TypeIdItem> parameterTypes = $field_type_list.types;
List<TypeIdItem> parameterTypes = $field_type_list.types;
TypeListItem parameterTypeListItem = TypeListItem.getInternedTypeListItem(dexFile, parameterTypes);
$protoIdItem = new ProtoIdItem(dexFile, returnType, parameterTypes);
$protoIdItem = ProtoIdItem.getInternedProtoIdItem(dexFile, returnType, parameterTypeListItem);
};
method_name_and_prototype returns[MethodIdItem methodIdItem]
: MEMBER_NAME method_prototype
{
TypeIdItem classType = classDefItem.getClassType();
String methodNameString = $MEMBER_NAME.text;
StringIdItem methodName = new StringIdItem(dexFile, methodNameString);
StringIdItem methodName = StringIdItem.getInternedStringIdItem(dexFile, methodNameString);
ProtoIdItem protoIdItem = $method_prototype.protoIdItem;
$methodIdItem = new MethodIdItem(dexFile, classType, methodName, protoIdItem);
$methodIdItem = MethodIdItem.getInternedMethodIdItem(dexFile, classType, protoIdItem, methodName);
};
field_type_list returns[ArrayList<TypeIdItem> types]
field_type_list returns[List<TypeIdItem> types]
@init
{
$types = new ArrayList<TypeIdItem>();
$types = new LinkedList<TypeIdItem>();
}
: (
nonvoid_type_descriptor
@ -548,18 +592,18 @@ fully_qualified_method returns[MethodIdItem methodIdItem]
: reference_type_descriptor MEMBER_NAME method_prototype
{
TypeIdItem classType = $reference_type_descriptor.type;
StringIdItem methodName = new StringIdItem(dexFile, $MEMBER_NAME.text);
StringIdItem methodName = StringIdItem.getInternedStringIdItem(dexFile, $MEMBER_NAME.text);
ProtoIdItem prototype = $method_prototype.protoIdItem;
$methodIdItem = new MethodIdItem(dexFile, classType, methodName, prototype);
$methodIdItem = MethodIdItem.getInternedMethodIdItem(dexFile, classType, prototype, methodName);
};
fully_qualified_field returns[FieldIdItem fieldIdItem]
: reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor
{
TypeIdItem classType = $reference_type_descriptor.type;
StringIdItem fieldName = new StringIdItem(dexFile, $MEMBER_NAME.text);
StringIdItem fieldName = StringIdItem.getInternedStringIdItem(dexFile, $MEMBER_NAME.text);
TypeIdItem fieldType = $nonvoid_type_descriptor.type;
$fieldIdItem = new FieldIdItem(dexFile, classType, fieldName, fieldType);
$fieldIdItem = FieldIdItem.getInternedFieldIdItem(dexFile, classType, fieldType, fieldName);
};
registers_directive returns[int registers]
@ -651,7 +695,7 @@ parameters returns[AnnotationSetRefList parameterAnnotations]
{
if ($parameter.parameterAnnotationSet != null) {
while (annotationSetItems.size() < parameterCount) {
annotationSetItems.add(new AnnotationSetItem(dexFile, -1));
annotationSetItems.add(AnnotationSetItem.getInternedAnnotationSetItem(dexFile, null));
}
annotationSetItems.add($parameter.parameterAnnotationSet);
}
@ -662,9 +706,9 @@ parameters returns[AnnotationSetRefList parameterAnnotations]
{
if (annotationSetItems.size() > 0) {
while (annotationSetItems.size() < parameterCount) {
annotationSetItems.add(new AnnotationSetItem(dexFile, -1));
annotationSetItems.add(AnnotationSetItem.getInternedAnnotationSetItem(dexFile, null));
}
$parameterAnnotations = new AnnotationSetRefList(dexFile, annotationSetItems);
$parameterAnnotations = AnnotationSetRefList.getInternedAnnotationSetRefList(dexFile, annotationSetItems);
}
};
@ -737,18 +781,23 @@ source
$method::debugInfo.addSetFile($address.address, $string_literal.value);
};
statements[int totalMethodRegisters, int methodParameterRegisters] returns[ArrayList<InstructionField> instructions]
statements[int totalMethodRegisters, int methodParameterRegisters] returns[byte[\] encodedInstructions, List<Item> referencedItems, int maxOutRegisters]
@init
{
$instructions = new ArrayList<InstructionField>();
ByteArrayOutput out = new ByteArrayOutput();
$referencedItems = new LinkedList<Item>();
$maxOutRegisters = 0;
}
: ^(I_STATEMENTS (instruction[$totalMethodRegisters, $methodParameterRegisters]
: ^(I_STATEMENTS (instruction[$totalMethodRegisters, $methodParameterRegisters, out, $referencedItems]
{
if ($instruction.instruction != null) {
$instructions.add($instruction.instruction);
$method::currentAddress += $instruction.instruction.getSize($method::currentAddress * 2) / 2;
$method::currentAddress = out.getCursor() / 2;
if ($maxOutRegisters < $instruction.outRegisters) {
$maxOutRegisters = $instruction.outRegisters;
}
})*);
})*)
{
$encodedInstructions = out.toByteArray();
};
label_ref returns[int labelAddress]
: label
@ -787,8 +836,37 @@ offset_or_label returns[int offsetValue]
: offset {$offsetValue = $offset.offsetValue;}
| label_ref {$offsetValue = $label_ref.labelAddress-$method::currentAddress;};
instruction[int totalMethodRegisters, int methodParameterRegisters] returns[InstructionField instruction]
register_list[int totalMethodRegisters, int methodParameterRegisters] returns[byte[\] registers, byte registerCount]
@init
{
$registers = new byte[5];
$registerCount = 0;
}
: ^(I_REGISTER_LIST
(REGISTER
{
if ($registerCount == 5) {
throw new SemanticException(input, "A list of registers can only have a maximum of 5 registers. Use the <op>/range alternate opcode instead.");
}
$registers[$registerCount++] = parseRegister_nibble($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
})*);
register_range[int totalMethodRegisters, int methodParameterRegisters] returns[int startRegister, int endRegister]
: ^(I_REGISTER_RANGE startReg=REGISTER endReg=REGISTER?)
{
$startRegister = parseRegister_short($startReg.text, $totalMethodRegisters, $methodParameterRegisters);
if ($endReg == null) {
$endRegister = $startRegister;
} else {
$endRegister = parseRegister_short($endReg.text, $totalMethodRegisters, $methodParameterRegisters);
}
}
;
instruction[int totalMethodRegisters, int methodParameterRegisters, Output out, List<Item> referencedItems] returns[int outRegisters]
: //e.g. goto endloop:
{$outRegisters = 0;}
^(I_STATEMENT_FORMAT10t INSTRUCTION_FORMAT10t offset_or_label)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT10t.text);
@ -799,13 +877,13 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
throw new SemanticException(input, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-128, 127].");
}
$instruction = new InstructionField(dexFile, new Instruction10t(dexFile, opcode, (byte)addressOffset));
Instruction10t.emit(out, opcode, (byte)addressOffset);
}
| //e.g. return
^(I_STATEMENT_FORMAT10x INSTRUCTION_FORMAT10x)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT10x.text);
$instruction = new InstructionField(dexFile, new Instruction10x(dexFile, opcode));
Instruction10x.emit(out, opcode);
}
| //e.g. const/4 v0, 5
^(I_STATEMENT_FORMAT11n INSTRUCTION_FORMAT11n REGISTER short_integral_literal)
@ -816,7 +894,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
short litB = $short_integral_literal.value;
literalTools.checkNibble(litB);
$instruction = new InstructionField(dexFile, new Instruction11n(dexFile, opcode, regA, (byte)litB));
Instruction11n.emit(out, opcode, regA, (byte)litB);
}
| //e.g. move-result-object v1
^(I_STATEMENT_FORMAT11x INSTRUCTION_FORMAT11x REGISTER)
@ -824,7 +902,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT11x.text);
short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
$instruction = new InstructionField(dexFile, new Instruction11x(dexFile, opcode, regA));
Instruction11x.emit(out, opcode, regA);
}
| //e.g. move v1 v2
^(I_STATEMENT_FORMAT12x INSTRUCTION_FORMAT12x registerA=REGISTER registerB=REGISTER)
@ -833,7 +911,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
$instruction = new InstructionField(dexFile, new Instruction12x(dexFile, opcode, regA, regB));
Instruction12x.emit(out, opcode, regA, regB);
}
| //e.g. goto/16 endloop:
^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t offset_or_label)
@ -846,7 +924,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
throw new SemanticException(input, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767].");
}
$instruction = new InstructionField(dexFile, new Instruction20t(dexFile, opcode, (short)addressOffset));
Instruction20t.emit(out, opcode, (short)addressOffset);
}
| //e.g. sget_object v0 java/lang/System/out LJava/io/PrintStream;
^(I_STATEMENT_FORMAT21c_FIELD INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field)
@ -856,7 +934,8 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem;
$instruction = new InstructionField(dexFile, new Instruction21c(dexFile, opcode, regA, fieldIdItem));
Instruction21c.emit(out, opcode, regA, fieldIdItem);
$referencedItems.add(fieldIdItem);
}
| //e.g. const-string v1 "Hello World!"
^(I_STATEMENT_FORMAT21c_STRING INSTRUCTION_FORMAT21c_STRING REGISTER string_literal)
@ -864,9 +943,10 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21c_STRING.text);
short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
StringIdItem stringIdItem = new StringIdItem(dexFile, $string_literal.value);
StringIdItem stringIdItem = StringIdItem.getInternedStringIdItem(dexFile, $string_literal.value);
$instruction = new InstructionField(dexFile, new Instruction21c(dexFile, opcode, regA, stringIdItem));
Instruction21c.emit(out, opcode, regA, stringIdItem);
$referencedItems.add(stringIdItem);
}
| //e.g. const-class v2 org/jf/HelloWorld2/HelloWorld2
^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor)
@ -876,7 +956,8 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
TypeIdItem typeIdItem = $reference_type_descriptor.type;
$instruction = new InstructionField(dexFile, new Instruction21c(dexFile, opcode, regA, typeIdItem));
Instruction21c.emit(out, opcode, regA, typeIdItem);
$referencedItems.add(typeIdItem);
}
| //e.g. const/high16 v1, 1234
^(I_STATEMENT_FORMAT21h INSTRUCTION_FORMAT21h REGISTER short_integral_literal)
@ -886,7 +967,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
short litB = $short_integral_literal.value;
$instruction = new InstructionField(dexFile, new Instruction21h(dexFile, opcode, regA, litB));
Instruction21h.emit(out, opcode, regA, litB);
}
| //e.g. const/16 v1, 1234
^(I_STATEMENT_FORMAT21s INSTRUCTION_FORMAT21s REGISTER short_integral_literal)
@ -896,7 +977,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
short litB = $short_integral_literal.value;
$instruction = new InstructionField(dexFile, new Instruction21s(dexFile, opcode, regA, litB));
Instruction21s.emit(out, opcode, regA, litB);
}
| //e.g. if-eqz v0, endloop:
^(I_STATEMENT_FORMAT21t INSTRUCTION_FORMAT21t REGISTER offset_or_label)
@ -910,7 +991,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
throw new SemanticException(input, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767].");
}
$instruction = new InstructionField(dexFile, new Instruction21t(dexFile, opcode, regA, (short)addressOffset));
Instruction21t.emit(out, opcode, regA, (short)addressOffset);
}
| //e.g. add-int v0, v1, 123
^(I_STATEMENT_FORMAT22b INSTRUCTION_FORMAT22b registerA=REGISTER registerB=REGISTER short_integral_literal)
@ -922,7 +1003,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
short litC = $short_integral_literal.value;
literalTools.checkByte(litC);
$instruction = new InstructionField(dexFile, new Instruction22b(dexFile, opcode, regA, regB, (byte)litC));
Instruction22b.emit(out, opcode, regA, regB, (byte)litC);
}
| //e.g. iput-object v1 v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
^(I_STATEMENT_FORMAT22c_FIELD INSTRUCTION_FORMAT22c_FIELD registerA=REGISTER registerB=REGISTER fully_qualified_field)
@ -933,7 +1014,8 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem;
$instruction = new InstructionField(dexFile, new Instruction22c(dexFile, opcode, regA, regB, fieldIdItem));
Instruction22c.emit(out, opcode, regA, regB);
$referencedItems.add(fieldIdItem);
}
| //e.g. instance-of v0, v1, Ljava/lang/String;
^(I_STATEMENT_FORMAT22c_TYPE INSTRUCTION_FORMAT22c_TYPE registerA=REGISTER registerB=REGISTER nonvoid_type_descriptor)
@ -944,7 +1026,8 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
$instruction = new InstructionField(dexFile, new Instruction22c(dexFile, opcode, regA, regB, typeIdItem));
Instruction22c.emit(out, opcode, regA, regB);
$referencedItems.add(typeIdItem);
}
| //e.g. add-int/lit16 v0, v1, 12345
^(I_STATEMENT_FORMAT22s INSTRUCTION_FORMAT22s registerA=REGISTER registerB=REGISTER short_integral_literal)
@ -955,7 +1038,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
short litC = $short_integral_literal.value;
$instruction = new InstructionField(dexFile, new Instruction22s(dexFile, opcode, regA, regB, litC));
Instruction22s.emit(out, opcode, regA, regB, litC);
}
| //e.g. if-eq v0, v1, endloop:
^(I_STATEMENT_FORMAT22t INSTRUCTION_FORMAT22t registerA=REGISTER registerB=REGISTER offset_or_label)
@ -970,7 +1053,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
throw new SemanticException(input, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767].");
}
$instruction = new InstructionField(dexFile, new Instruction22t(dexFile, opcode, regA, regB, (short)addressOffset));
Instruction22t.emit(out, opcode, regA, regB, (short)addressOffset);
}
| //e.g. move/from16 v1, v1234
^(I_STATEMENT_FORMAT22x INSTRUCTION_FORMAT22x registerA=REGISTER registerB=REGISTER)
@ -979,7 +1062,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
short regA = parseRegister_byte($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
$instruction = new InstructionField(dexFile, new Instruction22x(dexFile, opcode, regA, regB));
Instruction22x.emit(out, opcode, regA, regB);
}
| //e.g. add-int v1, v2, v3
^(I_STATEMENT_FORMAT23x INSTRUCTION_FORMAT23x registerA=REGISTER registerB=REGISTER registerC=REGISTER)
@ -989,7 +1072,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
short regB = parseRegister_byte($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
short regC = parseRegister_byte($registerC.text, $totalMethodRegisters, $methodParameterRegisters);
$instruction = new InstructionField(dexFile, new Instruction23x(dexFile, opcode, regA, regB, regC));
Instruction23x.emit(out, opcode, regA, regB, regC);
}
| //e.g. goto/32 endloop:
^(I_STATEMENT_FORMAT30t INSTRUCTION_FORMAT30t offset_or_label)
@ -998,7 +1081,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
int addressOffset = $offset_or_label.offsetValue;
$instruction = new InstructionField(dexFile, new Instruction30t(dexFile, opcode, addressOffset));
Instruction30t.emit(out, opcode, addressOffset);
}
| //e.g. const-string/jumbo v1 "Hello World!"
^(I_STATEMENT_FORMAT31c INSTRUCTION_FORMAT31c REGISTER string_literal)
@ -1006,9 +1089,10 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT31c.text);
short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
StringIdItem stringIdItem = new StringIdItem(dexFile, $string_literal.value);
StringIdItem stringIdItem = StringIdItem.getInternedStringIdItem(dexFile, $string_literal.value);
$instruction = new InstructionField(dexFile, new Instruction31c(dexFile, opcode, regA, stringIdItem));
Instruction31c.emit(out, opcode, regA);
$referencedItems.add(stringIdItem);
}
| //e.g. const v0, 123456
^(I_STATEMENT_FORMAT31i INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal)
@ -1018,7 +1102,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
int litB = $fixed_32bit_literal.value;
$instruction = new InstructionField(dexFile, new Instruction31i(dexFile, opcode, regA, litB));
Instruction31i.emit(out, opcode, regA, litB);
}
| //e.g. fill-array-data v0, ArrayData:
^(I_STATEMENT_FORMAT31t INSTRUCTION_FORMAT31t REGISTER offset_or_label)
@ -1032,7 +1116,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
addressOffset++;
}
$instruction = new InstructionField(dexFile, new Instruction31t(dexFile, opcode, regA, addressOffset));
Instruction31t.emit(out, opcode, regA, addressOffset);
}
| //e.g. move/16 v5678, v1234
^(I_STATEMENT_FORMAT32x INSTRUCTION_FORMAT32x registerA=REGISTER registerB=REGISTER)
@ -1041,7 +1125,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
int regA = parseRegister_short($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
$instruction = new InstructionField(dexFile, new Instruction32x(dexFile, opcode, regA, regB));
Instruction32x.emit(out, opcode, regA, regB);
}
| //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
^(I_STATEMENT_FORMAT35c_METHOD INSTRUCTION_FORMAT35c_METHOD register_list[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method)
@ -1051,10 +1135,12 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
//this depends on the fact that register_list returns a byte[5]
byte[] registers = $register_list.registers;
byte registerCount = $register_list.registerCount;
$outRegisters = registerCount;
MethodIdItem methodIdItem = $fully_qualified_method.methodIdItem;
$instruction = new InstructionField(dexFile, new Instruction35c(dexFile, opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], methodIdItem));
Instruction35c.emit(out, opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], methodIdItem);
$referencedItems.add(methodIdItem);
}
| //e.g. filled-new-array {v0,v1}, I
^(I_STATEMENT_FORMAT35c_TYPE INSTRUCTION_FORMAT35c_TYPE register_list[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor)
@ -1064,10 +1150,12 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
//this depends on the fact that register_list returns a byte[5]
byte[] registers = $register_list.registers;
byte registerCount = $register_list.registerCount;
$outRegisters = registerCount;
TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
$instruction = new InstructionField(dexFile, new Instruction35c(dexFile, opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], typeIdItem));
Instruction35c.emit(out, opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], typeIdItem);
$referencedItems.add(typeIdItem);
}
| //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
^(I_STATEMENT_FORMAT3rc_METHOD INSTRUCTION_FORMAT3rc_METHOD register_range[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method)
@ -1084,10 +1172,12 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
throw new SemanticException(input, "A register range must have the lower register listed first");
}
$outRegisters = registerCount;
MethodIdItem methodIdItem = $fully_qualified_method.methodIdItem;
//not supported yet
$instruction = new InstructionField(dexFile, new Instruction3rc(dexFile, opcode, (short)registerCount, startRegister, methodIdItem));
Instruction3rc.emit(out, opcode, (short)registerCount, startRegister, methodIdItem);
$referencedItems.add(methodIdItem);
}
| //e.g. filled-new-array/range {v0..v6} I
^(I_STATEMENT_FORMAT3rc_TYPE INSTRUCTION_FORMAT3rc_TYPE register_range[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor)
@ -1104,10 +1194,12 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
throw new SemanticException(input, "A register range must have the lower register listed first");
}
$outRegisters = registerCount;
TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
//not supported yet
$instruction = new InstructionField(dexFile, new Instruction3rc(dexFile, opcode, (short)registerCount, startRegister, typeIdItem));
Instruction3rc.emit(out, opcode, (short)registerCount, startRegister, typeIdItem);
$referencedItems.add(typeIdItem);
}
| //e.g. const-wide v0, 5000000000L
^(I_STATEMENT_FORMAT51l INSTRUCTION_FORMAT51l REGISTER fixed_64bit_literal)
@ -1117,38 +1209,55 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
long litB = $fixed_64bit_literal.value;
$instruction = new InstructionField(dexFile, new Instruction51l(dexFile, opcode, regA, litB));
Instruction51l.emit(out, opcode, regA, litB);
}
| //e.g. .array-data 4 1000000 .end array-data
^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE short_integral_literal) array_elements)
{
out.alignTo(4);
int elementWidth = $short_integral_literal.value;
List<byte[]> byteValues = $array_elements.values;
$instruction = new InstructionField(dexFile, new ArrayDataPseudoInstruction(dexFile, elementWidth, byteValues));
int length = 0;
for (byte[] byteValue: byteValues) {
length+=byteValue.length;
}
byte[] encodedValues = new byte[length];
int index = 0;
for (byte[] byteValue: byteValues) {
System.arraycopy(byteValue, 0, encodedValues, index, byteValue.length);
index+=byteValue.length;
}
ArrayDataPseudoInstruction.emit(out, elementWidth, encodedValues);
}
|
^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal)
{
int currentAddress = $method::currentAddress;
Integer baseAddress = $method::packedSwitchDeclarations.get(currentAddress);
out.alignTo(4);
$method::currentAddress = out.getCursor() / 2;
Integer baseAddress = $method::packedSwitchDeclarations.get($method::currentAddress);
if (baseAddress == null) {
baseAddress = 0;
}
}
packed_switch_targets[baseAddress])
{
int startKey = $fixed_32bit_literal.value;
int[] targets = $packed_switch_targets.targets;
$instruction = new InstructionField(dexFile, new PackedSwitchDataPseudoInstruction(dexFile, startKey, targets));
PackedSwitchDataPseudoInstruction.emit(out, startKey, targets);
}
|
^(I_STATEMENT_SPARSE_SWITCH sparse_switch_target_count sparse_switch_keys[$sparse_switch_target_count.targetCount]
{
int currentAddress = $method::currentAddress;
Integer baseAddress = $method::sparseSwitchDeclarations.get(currentAddress);
out.alignTo(4);
$method::currentAddress = out.getCursor() / 2;
Integer baseAddress = $method::sparseSwitchDeclarations.get($method::currentAddress);
if (baseAddress == null) {
baseAddress = 0;
}
@ -1159,64 +1268,42 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
int[] keys = $sparse_switch_keys.keys;
int[] targets = $sparse_switch_targets.targets;
$instruction = new InstructionField(dexFile, new SparseSwitchDataPseudoInstruction(dexFile, keys, targets));
SparseSwitchDataPseudoInstruction.emit(out, keys, targets);
};
catch [Exception ex] {
reportError(new SemanticException(input, ex));
recover(input, null);
}
register_list[int totalMethodRegisters, int methodParameterRegisters] returns[byte[\] registers, byte registerCount]
@init
{
$registers = new byte[5];
$registerCount = 0;
}
: ^(I_REGISTER_LIST
(REGISTER
{
if ($registerCount == 5) {
throw new SemanticException(input, "A list of registers can only have a maximum of 5 registers. Use the <op>/range alternate opcode instead.");
}
$registers[$registerCount++] = parseRegister_nibble($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
})*);
register_range[int totalMethodRegisters, int methodParameterRegisters] returns[int startRegister, int endRegister]
: ^(I_REGISTER_RANGE startReg=REGISTER endReg=REGISTER?)
{
$startRegister = parseRegister_short($startReg.text, $totalMethodRegisters, $methodParameterRegisters);
if ($endReg == null) {
$endRegister = $startRegister;
} else {
$endRegister = parseRegister_short($endReg.text, $totalMethodRegisters, $methodParameterRegisters);
}
}
;
nonvoid_type_descriptor returns [TypeIdItem type]
: (PRIMITIVE_TYPE
| CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR)
{
$type = new TypeIdItem(dexFile, $start.getText());
$type = TypeIdItem.getInternedTypeIdItem(dexFile, $start.getText());
};
reference_type_descriptor returns [TypeIdItem type]
: (CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR)
{
$type = new TypeIdItem(dexFile, $start.getText());
$type = TypeIdItem.getInternedTypeIdItem(dexFile, $start.getText());
};
class_type_descriptor returns [TypeIdItem type]
: CLASS_DESCRIPTOR
{
$type = new TypeIdItem(dexFile, $CLASS_DESCRIPTOR.text);
$type = TypeIdItem.getInternedTypeIdItem(dexFile, $CLASS_DESCRIPTOR.text);
};
type_descriptor returns [TypeIdItem type]
: VOID_TYPE {$type = new TypeIdItem(dexFile, "V");}
: VOID_TYPE {$type = TypeIdItem.getInternedTypeIdItem(dexFile, "V");}
| nonvoid_type_descriptor {$type = $nonvoid_type_descriptor.type;}
;
@ -1277,9 +1364,13 @@ string_literal returns[String value]
bool_literal returns[boolean value]
: BOOL_LITERAL { $value = Boolean.parseBoolean($BOOL_LITERAL.text); };
array_literal returns[ArrayList<EncodedValue> values]
: {$values = new ArrayList<EncodedValue>();}
^(I_ENCODED_ARRAY (literal {$values.add($literal.encodedValue);})*);
array_literal returns[EncodedValue[\] values]
: {ArrayList<EncodedValue> valuesList = new ArrayList<EncodedValue>();}
^(I_ENCODED_ARRAY (literal {valuesList.add($literal.encodedValue);})*)
{
$values = new EncodedValue[valuesList.size()];
valuesList.toArray($values);
};
annotations returns[AnnotationSetItem annotationSetItem]
@ -1287,7 +1378,7 @@ annotations returns[AnnotationSetItem annotationSetItem]
^(I_ANNOTATIONS (annotation {annotationList.add($annotation.annotationItem);} )*)
{
if (annotationList.size() > 0) {
$annotationSetItem = new AnnotationSetItem(dexFile, annotationList);
$annotationSetItem = AnnotationSetItem.getInternedAnnotationSetItem(dexFile, annotationList);
}
};
@ -1295,39 +1386,51 @@ annotations returns[AnnotationSetItem annotationSetItem]
annotation returns[AnnotationItem annotationItem]
: ^(I_ANNOTATION ANNOTATION_VISIBILITY subannotation)
{
AnnotationVisibility visibility = AnnotationVisibility.fromName($ANNOTATION_VISIBILITY.text);
$annotationItem = new AnnotationItem(dexFile, visibility, $subannotation.value);
AnnotationVisibility visibility = AnnotationVisibility.valueOf($ANNOTATION_VISIBILITY.text.toUpperCase());
AnnotationEncodedSubValue encodedAnnotation = new AnnotationEncodedSubValue($subannotation.annotationType,
$subannotation.elementNames, $subannotation.elementValues);
$annotationItem = AnnotationItem.getInternedAnnotationItem(dexFile, visibility, encodedAnnotation);
};
annotation_element returns[AnnotationElement element]
annotation_element returns[StringIdItem elementName, EncodedValue elementValue]
: ^(I_ANNOTATION_ELEMENT MEMBER_NAME literal)
{
$element = new AnnotationElement(dexFile, new StringIdItem(dexFile, $MEMBER_NAME.text), $literal.encodedValue);
$elementName = StringIdItem.getInternedStringIdItem(dexFile, $MEMBER_NAME.text);
$elementValue = $literal.encodedValue;
};
subannotation returns[AnnotationEncodedValueSubField value]
: {ArrayList<AnnotationElement> elements = new ArrayList<AnnotationElement>();}
subannotation returns[TypeIdItem annotationType, StringIdItem[\] elementNames, EncodedValue[\] elementValues]
: {ArrayList<StringIdItem> elementNamesList = new ArrayList<StringIdItem>();
ArrayList<EncodedValue> elementValuesList = new ArrayList<EncodedValue>();}
^( I_SUBANNOTATION
class_type_descriptor
(annotation_element {elements.add($annotation_element.element);} )* )
(annotation_element
{
elementNamesList.add($annotation_element.elementName);
elementValuesList.add($annotation_element.elementValue);
} )* )
{
$value = new AnnotationEncodedValueSubField(dexFile, $class_type_descriptor.type, elements);
$annotationType = $class_type_descriptor.type;
$elementNames = new StringIdItem[elementNamesList.size()];
elementNamesList.toArray($elementNames);
$elementValues = new EncodedValue[elementValuesList.size()];
elementValuesList.toArray($elementValues);
};
field_literal returns[EncodedIndexedItemReference<FieldIdItem> value]
field_literal returns[FieldIdItem value]
: ^(I_ENCODED_FIELD fully_qualified_field)
{
$value = new EncodedIndexedItemReference<FieldIdItem>(dexFile, $fully_qualified_field.fieldIdItem);
$value = $fully_qualified_field.fieldIdItem;
};
method_literal returns[EncodedIndexedItemReference<MethodIdItem> value]
method_literal returns[MethodIdItem value]
: ^(I_ENCODED_METHOD fully_qualified_method)
{
$value = new EncodedIndexedItemReference<MethodIdItem>(dexFile, $fully_qualified_method.methodIdItem);
$value = $fully_qualified_method.methodIdItem;
};
enum_literal returns[EncodedIndexedItemReference<FieldIdItem> value]
enum_literal returns[FieldIdItem value]
: ^(I_ENCODED_ENUM fully_qualified_field)
{
$value = new EncodedIndexedItemReference<FieldIdItem>(dexFile, $fully_qualified_field.fieldIdItem, true);
$value = $fully_qualified_field.fieldIdItem;
};

View File

@ -227,8 +227,7 @@ public class main {
if (dexGen.getNumberOfSyntaxErrors() > 0) {
return false;
}
dexFile.ClassDefsSection.intern(dexGen.classDefItem);
return true;
}