From 83e6f4bb6043ea09e3416878cf846f7c4c301ddf Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Mon, 24 Aug 2009 05:42:49 +0000 Subject: [PATCH] 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 --- .../Format/ArrayDataPseudoInstruction.java | 24 +- .../jf/dexlib/Code/Format/Instruction10t.java | 9 +- .../jf/dexlib/Code/Format/Instruction10x.java | 7 +- .../jf/dexlib/Code/Format/Instruction11n.java | 9 +- .../jf/dexlib/Code/Format/Instruction11x.java | 9 +- .../jf/dexlib/Code/Format/Instruction12x.java | 9 +- .../jf/dexlib/Code/Format/Instruction20t.java | 10 +- .../jf/dexlib/Code/Format/Instruction21c.java | 18 +- .../jf/dexlib/Code/Format/Instruction21h.java | 12 +- .../jf/dexlib/Code/Format/Instruction21s.java | 12 +- .../jf/dexlib/Code/Format/Instruction21t.java | 12 +- .../jf/dexlib/Code/Format/Instruction22b.java | 13 +- .../jf/dexlib/Code/Format/Instruction22c.java | 11 +- .../jf/dexlib/Code/Format/Instruction22s.java | 12 +- .../jf/dexlib/Code/Format/Instruction22t.java | 12 +- .../jf/dexlib/Code/Format/Instruction22x.java | 12 +- .../jf/dexlib/Code/Format/Instruction23x.java | 13 +- .../jf/dexlib/Code/Format/Instruction30t.java | 12 +- .../jf/dexlib/Code/Format/Instruction31c.java | 11 +- .../jf/dexlib/Code/Format/Instruction31i.java | 14 +- .../jf/dexlib/Code/Format/Instruction31t.java | 14 +- .../jf/dexlib/Code/Format/Instruction32x.java | 14 +- .../jf/dexlib/Code/Format/Instruction35c.java | 25 +- .../jf/dexlib/Code/Format/Instruction3rc.java | 24 +- .../jf/dexlib/Code/Format/Instruction51l.java | 18 +- .../PackedSwitchDataPseudoInstruction.java | 30 +- .../SparseSwitchDataPseudoInstruction.java | 32 +- .../antlr3/org/jf/smali/smaliTreeWalker.g | 489 +++++++++++------- smali/src/main/java/org/jf/smali/main.java | 3 +- 29 files changed, 453 insertions(+), 437 deletions(-) diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/ArrayDataPseudoInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/ArrayDataPseudoInstruction.java index da70b040..b9d16ed2 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/ArrayDataPseudoInstruction.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/ArrayDataPseudoInstruction.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10t.java index 641d5ac9..f7fe81ae 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10t.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10x.java index 566072f1..e1953fcb 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10x.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11n.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11n.java index bacbc0d8..d2b80d99 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11n.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11n.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java index d9da5578..9d4a8f22 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java index 0ca772f7..a2682a4d 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java index c0cf09dd..efb3e0ca 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java index ad849dab..bb315a81 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java index 37003d55..e134c66d 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java index e702f017..a93241de 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java index b9673b56..8851bbbc 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java index 96432da6..f8d67c92 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java index 061ea96a..d4fc1f58 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java index 9630a500..f8b843ab 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java index 4b4c583e..2ce07dc2 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java index 48a2543a..8eaf33b2 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java index 234f9578..632072a9 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java index b555d097..5edbe21f 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java index 9e1c747a..f1fcb212 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java index a5473b17..9c3ec82e 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java index 182a77f3..87e5c40d 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java index 30833ee8..be5b6e7e 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35c.java index 234a713d..01cef0b4 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35c.java @@ -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"); } } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rc.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rc.java index 18ed8c05..af26c1f5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rc.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rc.java @@ -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"); } } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java index ebd6455a..3a725729 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java @@ -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) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/PackedSwitchDataPseudoInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/PackedSwitchDataPseudoInstruction.java index e5ce46b7..c255029d 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/PackedSwitchDataPseudoInstruction.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/PackedSwitchDataPseudoInstruction.java @@ -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); } } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/SparseSwitchDataPseudoInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/SparseSwitchDataPseudoInstruction.java index f10ee60b..0dd97824 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/SparseSwitchDataPseudoInstruction.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/SparseSwitchDataPseudoInstruction.java @@ -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); } } } diff --git a/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g b/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g index 3c375962..a3cce681 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g @@ -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 typeList; } - : {typeList = new ArrayList();} +@init { List typeList; } + : {typeList = new LinkedList();} (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 fieldAnnotationSets] + +fields returns[List staticFields, List instanceFields, + List staticFieldInitialValues, List fieldAnnotations] + @init + { + $staticFields = new LinkedList(); + $instanceFields = new LinkedList(); + $staticFieldInitialValues = new LinkedList(); + } : ^(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(); + if ($fieldAnnotations == null) { + $fieldAnnotations = new LinkedList(); } - fieldAnnotationSets.add($field.fieldAnnotationSet); + AnnotationDirectoryItem.FieldAnnotation fieldAnnotation = new AnnotationDirectoryItem.FieldAnnotation( + $field.encodedField.field, $field.fieldAnnotationSet); + $fieldAnnotations.add(fieldAnnotation); } })*); -methods returns[List methodAnnotationSets, - List parameterAnnotationSets] +methods returns[List directMethods, + List virtualMethods, + List methodAnnotations, + List parameterAnnotations] + @init + { + $directMethods = new LinkedList(); + $virtualMethods = new LinkedList(); + } : ^(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(); + if ($methodAnnotations == null) { + $methodAnnotations = new LinkedList(); } - $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(); + if ($parameterAnnotations == null) { + $parameterAnnotations = new LinkedList(); } - $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 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 instructions = $statements.instructions; - - Pair, List> temp = $method::tryList.encodeTries(dexFile); + Pair, List> temp = $method::tryList.encodeTries(); List tries = temp.first; List 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 parameterTypes = $field_type_list.types; + List 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 types] +field_type_list returns[List types] @init { - $types = new ArrayList(); + $types = new LinkedList(); } : ( 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 instructions] +statements[int totalMethodRegisters, int methodParameterRegisters] returns[byte[\] encodedInstructions, List referencedItems, int maxOutRegisters] @init { - $instructions = new ArrayList(); + ByteArrayOutput out = new ByteArrayOutput(); + $referencedItems = new LinkedList(); + $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 /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 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 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 /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 values] - : {$values = new ArrayList();} - ^(I_ENCODED_ARRAY (literal {$values.add($literal.encodedValue);})*); +array_literal returns[EncodedValue[\] values] + : {ArrayList valuesList = new ArrayList();} + ^(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 elements = new ArrayList();} +subannotation returns[TypeIdItem annotationType, StringIdItem[\] elementNames, EncodedValue[\] elementValues] + : {ArrayList elementNamesList = new ArrayList(); + ArrayList elementValuesList = new ArrayList();} ^( 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 value] +field_literal returns[FieldIdItem value] : ^(I_ENCODED_FIELD fully_qualified_field) { - $value = new EncodedIndexedItemReference(dexFile, $fully_qualified_field.fieldIdItem); + $value = $fully_qualified_field.fieldIdItem; }; -method_literal returns[EncodedIndexedItemReference value] +method_literal returns[MethodIdItem value] : ^(I_ENCODED_METHOD fully_qualified_method) { - $value = new EncodedIndexedItemReference(dexFile, $fully_qualified_method.methodIdItem); + $value = $fully_qualified_method.methodIdItem; }; -enum_literal returns[EncodedIndexedItemReference value] +enum_literal returns[FieldIdItem value] : ^(I_ENCODED_ENUM fully_qualified_field) { - $value = new EncodedIndexedItemReference(dexFile, $fully_qualified_field.fieldIdItem, true); + $value = $fully_qualified_field.fieldIdItem; }; diff --git a/smali/src/main/java/org/jf/smali/main.java b/smali/src/main/java/org/jf/smali/main.java index 96bcd4bc..4359c9c8 100644 --- a/smali/src/main/java/org/jf/smali/main.java +++ b/smali/src/main/java/org/jf/smali/main.java @@ -227,8 +227,7 @@ public class main { if (dexGen.getNumberOfSyntaxErrors() > 0) { return false; } - - dexFile.ClassDefsSection.intern(dexGen.classDefItem); + return true; }