mirror of
https://github.com/revanced/smali.git
synced 2025-05-05 00:54:25 +02:00
Refactor the MethodAnalyzer API so that the instructions are returned as a read-only list
git-svn-id: https://smali.googlecode.com/svn/trunk@662 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
7974e53f15
commit
ef24b31c98
@ -68,17 +68,17 @@ public class MethodDefinition {
|
|||||||
|
|
||||||
if (encodedMethod.codeItem != null) {
|
if (encodedMethod.codeItem != null) {
|
||||||
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex);
|
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex);
|
||||||
AnalyzedInstruction[] instructions = methodAnalyzer.makeInstructionArray();
|
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
|
||||||
|
|
||||||
packedSwitchMap = new SparseIntArray(1);
|
packedSwitchMap = new SparseIntArray(1);
|
||||||
sparseSwitchMap = new SparseIntArray(1);
|
sparseSwitchMap = new SparseIntArray(1);
|
||||||
instructionMap = new SparseIntArray(instructions.length);
|
instructionMap = new SparseIntArray(instructions.size());
|
||||||
|
|
||||||
registerCount = encodedMethod.codeItem.getRegisterCount();
|
registerCount = encodedMethod.codeItem.getRegisterCount();
|
||||||
|
|
||||||
int currentCodeAddress = 0;
|
int currentCodeAddress = 0;
|
||||||
for (int i=0; i<instructions.length; i++) {
|
for (int i=0; i<instructions.size(); i++) {
|
||||||
AnalyzedInstruction instruction = instructions[i];
|
AnalyzedInstruction instruction = instructions.get(i);
|
||||||
if (instruction.getInstruction().opcode == Opcode.PACKED_SWITCH) {
|
if (instruction.getInstruction().opcode == Opcode.PACKED_SWITCH) {
|
||||||
packedSwitchMap.append(
|
packedSwitchMap.append(
|
||||||
currentCodeAddress + ((OffsetInstruction)instruction.getInstruction()).getTargetAddressOffset(),
|
currentCodeAddress + ((OffsetInstruction)instruction.getInstruction()).getTargetAddressOffset(),
|
||||||
@ -248,9 +248,8 @@ public class MethodDefinition {
|
|||||||
return methodItems;
|
return methodItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalyzedInstruction[] instructions;
|
|
||||||
if (baksmali.registerInfo != 0 || baksmali.deodex) {
|
if (baksmali.registerInfo != 0 || baksmali.deodex) {
|
||||||
instructions = methodAnalyzer.analyze();
|
methodAnalyzer.analyze();
|
||||||
|
|
||||||
ValidationException validationException = methodAnalyzer.getValidationException();
|
ValidationException validationException = methodAnalyzer.getValidationException();
|
||||||
if (validationException != null) {
|
if (validationException != null) {
|
||||||
@ -258,14 +257,13 @@ public class MethodDefinition {
|
|||||||
String.format("ValidationException: %s" ,validationException.getMessage()),
|
String.format("ValidationException: %s" ,validationException.getMessage()),
|
||||||
validationException.getCodeAddress(), Integer.MIN_VALUE));
|
validationException.getCodeAddress(), Integer.MIN_VALUE));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
instructions = methodAnalyzer.makeInstructionArray();
|
|
||||||
}
|
}
|
||||||
|
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
|
||||||
|
|
||||||
AnalyzedInstruction lastInstruction = null;
|
AnalyzedInstruction lastInstruction = null;
|
||||||
|
|
||||||
for (int i=instructions.length-1; i>=0; i--) {
|
for (int i=instructions.size()-1; i>=0; i--) {
|
||||||
AnalyzedInstruction instruction = instructions[i];
|
AnalyzedInstruction instruction = instructions.get(i);
|
||||||
|
|
||||||
if (!instruction.isDead()) {
|
if (!instruction.isDead()) {
|
||||||
lastInstruction = instruction;
|
lastInstruction = instruction;
|
||||||
@ -277,8 +275,8 @@ public class MethodDefinition {
|
|||||||
BitSet printPostRegister = new BitSet(registerCount);
|
BitSet printPostRegister = new BitSet(registerCount);
|
||||||
|
|
||||||
int currentCodeAddress = 0;
|
int currentCodeAddress = 0;
|
||||||
for (int i=0; i<instructions.length; i++) {
|
for (int i=0; i<instructions.size(); i++) {
|
||||||
AnalyzedInstruction instruction = instructions[i];
|
AnalyzedInstruction instruction = instructions.get(i);
|
||||||
|
|
||||||
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
|
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
|
||||||
encodedMethod.codeItem, currentCodeAddress, stg, instruction.getInstruction(),
|
encodedMethod.codeItem, currentCodeAddress, stg, instruction.getInstruction(),
|
||||||
@ -295,7 +293,7 @@ public class MethodDefinition {
|
|||||||
encodedMethod.codeItem, currentCodeAddress, stg, instruction.getOriginalInstruction(), false)));
|
encodedMethod.codeItem, currentCodeAddress, stg, instruction.getOriginalInstruction(), false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != instructions.length - 1) {
|
if (i != instructions.size() - 1) {
|
||||||
methodItems.add(new BlankMethodItem(stg, currentCodeAddress));
|
methodItems.add(new BlankMethodItem(stg, currentCodeAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +317,7 @@ public class MethodDefinition {
|
|||||||
addArgsRegs(printPreRegister, instruction);
|
addArgsRegs(printPreRegister, instruction);
|
||||||
}
|
}
|
||||||
if ((baksmali.registerInfo & main.MERGE) != 0) {
|
if ((baksmali.registerInfo & main.MERGE) != 0) {
|
||||||
addMergeRegs(printPreRegister, instructions, i);
|
addMergeRegs(printPreRegister, instruction);
|
||||||
} else if ((baksmali.registerInfo & main.FULLMERGE) != 0 &&
|
} else if ((baksmali.registerInfo & main.FULLMERGE) != 0 &&
|
||||||
(i == 0 || instruction.isBeginningInstruction())) {
|
(i == 0 || instruction.isBeginningInstruction())) {
|
||||||
addParamRegs(printPreRegister);
|
addParamRegs(printPreRegister);
|
||||||
@ -334,7 +332,7 @@ public class MethodDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((baksmali.registerInfo & main.FULLMERGE) != 0) {
|
if ((baksmali.registerInfo & main.FULLMERGE) != 0) {
|
||||||
addFullMergeRegs(printPreRegister, methodItems, methodAnalyzer, i, currentCodeAddress);
|
addFullMergeRegs(printPreRegister, methodItems, methodAnalyzer, instruction, currentCodeAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!printPreRegister.isEmpty()) {
|
if (!printPreRegister.isEmpty()) {
|
||||||
@ -417,16 +415,7 @@ public class MethodDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addFullMergeRegs(BitSet printPreRegister, List<MethodItem> methodItems, MethodAnalyzer methodAnalyzer,
|
private void addFullMergeRegs(BitSet printPreRegister, List<MethodItem> methodItems, MethodAnalyzer methodAnalyzer,
|
||||||
int instructionNum, int currentCodeAddress) {
|
AnalyzedInstruction instruction, int currentCodeAddress) {
|
||||||
if (instructionNum == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//MethodAnalyzer cached the analyzedInstructions, so we're not actually re-analyzing, just getting the
|
|
||||||
//instructions that have already been analyzed
|
|
||||||
AnalyzedInstruction[] instructions = methodAnalyzer.analyze();
|
|
||||||
AnalyzedInstruction instruction = instructions[instructionNum];
|
|
||||||
|
|
||||||
if (instruction.getPredecessorCount() <= 1) {
|
if (instruction.getPredecessorCount() <= 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -482,33 +471,25 @@ public class MethodDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMergeRegs(BitSet printPreRegister, AnalyzedInstruction instructions[], int instructionNum) {
|
private void addMergeRegs(BitSet printPreRegister, AnalyzedInstruction instruction) {
|
||||||
//MethodAnalyzer cached the analyzedInstructions, so we're not actually re-analyzing, just getting the
|
if (instruction.isBeginningInstruction()) {
|
||||||
//instructions that have already been analyzed
|
|
||||||
AnalyzedInstruction instruction = instructions[instructionNum];
|
|
||||||
|
|
||||||
if (instructionNum == 0) {
|
|
||||||
addParamRegs(printPreRegister);
|
addParamRegs(printPreRegister);
|
||||||
} else {
|
}
|
||||||
if (instruction.isBeginningInstruction()) {
|
|
||||||
addParamRegs(printPreRegister);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instruction.getPredecessorCount() <= 1) {
|
if (instruction.getPredecessorCount() <= 1) {
|
||||||
//in the common case of an instruction that only has a single predecessor which is the previous
|
//in the common case of an instruction that only has a single predecessor which is the previous
|
||||||
//instruction, the pre-instruction registers will always match the previous instruction's
|
//instruction, the pre-instruction registers will always match the previous instruction's
|
||||||
//post-instruction registers
|
//post-instruction registers
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int registerNum=0; registerNum<registerCount; registerNum++) {
|
for (int registerNum=0; registerNum<registerCount; registerNum++) {
|
||||||
RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum);
|
RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum);
|
||||||
|
|
||||||
for (AnalyzedInstruction predecessor: instruction.getPredecessors()) {
|
for (AnalyzedInstruction predecessor: instruction.getPredecessors()) {
|
||||||
if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) {
|
if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) {
|
||||||
printPreRegister.set(registerNum);
|
printPreRegister.set(registerNum);
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,8 @@ public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
|
|||||||
* @return a boolean value indicating whether this instruction is a beginning instruction
|
* @return a boolean value indicating whether this instruction is a beginning instruction
|
||||||
*/
|
*/
|
||||||
public boolean isBeginningInstruction() {
|
public boolean isBeginningInstruction() {
|
||||||
|
//if this instruction has no predecessors, it is either the fake "StartOfMethod" instruction or it is an
|
||||||
|
//unreachable instruction.
|
||||||
if (predecessors.size() == 0) {
|
if (predecessors.size() == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -110,12 +110,13 @@ public class MethodAnalyzer {
|
|||||||
return analyzerState == VERIFIED;
|
return analyzerState == VERIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnalyzedInstruction[] analyze() {
|
public void analyze() {
|
||||||
assert encodedMethod != null;
|
assert encodedMethod != null;
|
||||||
assert encodedMethod.codeItem != null;
|
assert encodedMethod.codeItem != null;
|
||||||
|
|
||||||
if (analyzerState >= ANALYZED) {
|
if (analyzerState >= ANALYZED) {
|
||||||
return makeInstructionArray();
|
//the instructions have already been analyzed, so there is nothing to do
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeItem codeItem = encodedMethod.codeItem;
|
CodeItem codeItem = encodedMethod.codeItem;
|
||||||
@ -273,7 +274,6 @@ public class MethodAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
analyzerState = ANALYZED;
|
analyzerState = ANALYZED;
|
||||||
return makeInstructionArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getThisRegister() {
|
private int getThisRegister() {
|
||||||
@ -309,12 +309,11 @@ public class MethodAnalyzer {
|
|||||||
return startOfMethod;
|
return startOfMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnalyzedInstruction[] makeInstructionArray() {
|
/**
|
||||||
AnalyzedInstruction[] instructionArray = new AnalyzedInstruction[instructions.size()];
|
* @return a read-only list containing the instructions for tihs method.
|
||||||
for (int i=0; i<instructions.size(); i++) {
|
*/
|
||||||
instructionArray[i] = instructions.valueAt(i);
|
public List<AnalyzedInstruction> getInstructions() {
|
||||||
}
|
return instructions.getValues();
|
||||||
return instructionArray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValidationException getValidationException() {
|
public ValidationException getValidationException() {
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package org.jf.dexlib.Util;
|
package org.jf.dexlib.Util;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SparseArrays map integers to Objects. Unlike a normal array of Objects,
|
* SparseArrays map integers to Objects. Unlike a normal array of Objects,
|
||||||
* there can be gaps in the indices. It is intended to be more efficient
|
* there can be gaps in the indices. It is intended to be more efficient
|
||||||
@ -340,6 +344,14 @@ public class SparseArray<E> {
|
|||||||
return ~high;
|
return ~high;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a read-only list of the values in this SparseArray which are in ascending order, based on their
|
||||||
|
* associated key
|
||||||
|
*/
|
||||||
|
public List<E> getValues() {
|
||||||
|
return Collections.unmodifiableList(Arrays.asList((E[])mValues));
|
||||||
|
}
|
||||||
|
|
||||||
private int[] mKeys;
|
private int[] mKeys;
|
||||||
private Object[] mValues;
|
private Object[] mValues;
|
||||||
private int mSize;
|
private int mSize;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user