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:
JesusFreke@JesusFreke.com 2010-03-03 03:26:17 +00:00
parent 7974e53f15
commit ef24b31c98
4 changed files with 51 additions and 57 deletions

View File

@ -68,17 +68,17 @@ public class MethodDefinition {
if (encodedMethod.codeItem != null) {
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex);
AnalyzedInstruction[] instructions = methodAnalyzer.makeInstructionArray();
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
packedSwitchMap = new SparseIntArray(1);
sparseSwitchMap = new SparseIntArray(1);
instructionMap = new SparseIntArray(instructions.length);
instructionMap = new SparseIntArray(instructions.size());
registerCount = encodedMethod.codeItem.getRegisterCount();
int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) {
AnalyzedInstruction instruction = instructions[i];
for (int i=0; i<instructions.size(); i++) {
AnalyzedInstruction instruction = instructions.get(i);
if (instruction.getInstruction().opcode == Opcode.PACKED_SWITCH) {
packedSwitchMap.append(
currentCodeAddress + ((OffsetInstruction)instruction.getInstruction()).getTargetAddressOffset(),
@ -248,9 +248,8 @@ public class MethodDefinition {
return methodItems;
}
AnalyzedInstruction[] instructions;
if (baksmali.registerInfo != 0 || baksmali.deodex) {
instructions = methodAnalyzer.analyze();
methodAnalyzer.analyze();
ValidationException validationException = methodAnalyzer.getValidationException();
if (validationException != null) {
@ -258,14 +257,13 @@ public class MethodDefinition {
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE));
}
} else {
instructions = methodAnalyzer.makeInstructionArray();
}
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
AnalyzedInstruction lastInstruction = null;
for (int i=instructions.length-1; i>=0; i--) {
AnalyzedInstruction instruction = instructions[i];
for (int i=instructions.size()-1; i>=0; i--) {
AnalyzedInstruction instruction = instructions.get(i);
if (!instruction.isDead()) {
lastInstruction = instruction;
@ -277,8 +275,8 @@ public class MethodDefinition {
BitSet printPostRegister = new BitSet(registerCount);
int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) {
AnalyzedInstruction instruction = instructions[i];
for (int i=0; i<instructions.size(); i++) {
AnalyzedInstruction instruction = instructions.get(i);
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, stg, instruction.getInstruction(),
@ -295,7 +293,7 @@ public class MethodDefinition {
encodedMethod.codeItem, currentCodeAddress, stg, instruction.getOriginalInstruction(), false)));
}
if (i != instructions.length - 1) {
if (i != instructions.size() - 1) {
methodItems.add(new BlankMethodItem(stg, currentCodeAddress));
}
@ -319,7 +317,7 @@ public class MethodDefinition {
addArgsRegs(printPreRegister, instruction);
}
if ((baksmali.registerInfo & main.MERGE) != 0) {
addMergeRegs(printPreRegister, instructions, i);
addMergeRegs(printPreRegister, instruction);
} else if ((baksmali.registerInfo & main.FULLMERGE) != 0 &&
(i == 0 || instruction.isBeginningInstruction())) {
addParamRegs(printPreRegister);
@ -334,7 +332,7 @@ public class MethodDefinition {
}
if ((baksmali.registerInfo & main.FULLMERGE) != 0) {
addFullMergeRegs(printPreRegister, methodItems, methodAnalyzer, i, currentCodeAddress);
addFullMergeRegs(printPreRegister, methodItems, methodAnalyzer, instruction, currentCodeAddress);
}
if (!printPreRegister.isEmpty()) {
@ -417,16 +415,7 @@ public class MethodDefinition {
}
private void addFullMergeRegs(BitSet printPreRegister, List<MethodItem> methodItems, MethodAnalyzer methodAnalyzer,
int instructionNum, 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];
AnalyzedInstruction instruction, int currentCodeAddress) {
if (instruction.getPredecessorCount() <= 1) {
return;
}
@ -482,33 +471,25 @@ public class MethodDefinition {
}
}
private void addMergeRegs(BitSet printPreRegister, AnalyzedInstruction instructions[], int instructionNum) {
//MethodAnalyzer cached the analyzedInstructions, so we're not actually re-analyzing, just getting the
//instructions that have already been analyzed
AnalyzedInstruction instruction = instructions[instructionNum];
if (instructionNum == 0) {
private void addMergeRegs(BitSet printPreRegister, AnalyzedInstruction instruction) {
if (instruction.isBeginningInstruction()) {
addParamRegs(printPreRegister);
} else {
if (instruction.isBeginningInstruction()) {
addParamRegs(printPreRegister);
}
}
if (instruction.getPredecessorCount() <= 1) {
//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
//post-instruction registers
return;
}
if (instruction.getPredecessorCount() <= 1) {
//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
//post-instruction registers
return;
}
for (int registerNum=0; registerNum<registerCount; registerNum++) {
RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum);
for (int registerNum=0; registerNum<registerCount; registerNum++) {
RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum);
for (AnalyzedInstruction predecessor: instruction.getPredecessors()) {
if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) {
printPreRegister.set(registerNum);
continue;
}
for (AnalyzedInstruction predecessor: instruction.getPredecessors()) {
if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) {
printPreRegister.set(registerNum);
continue;
}
}
}

View File

@ -170,6 +170,8 @@ public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
* @return a boolean value indicating whether this instruction is a beginning instruction
*/
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) {
return false;
}

View File

@ -110,12 +110,13 @@ public class MethodAnalyzer {
return analyzerState == VERIFIED;
}
public AnalyzedInstruction[] analyze() {
public void analyze() {
assert encodedMethod != null;
assert encodedMethod.codeItem != null;
if (analyzerState >= ANALYZED) {
return makeInstructionArray();
//the instructions have already been analyzed, so there is nothing to do
return;
}
CodeItem codeItem = encodedMethod.codeItem;
@ -273,7 +274,6 @@ public class MethodAnalyzer {
}
analyzerState = ANALYZED;
return makeInstructionArray();
}
private int getThisRegister() {
@ -309,12 +309,11 @@ public class MethodAnalyzer {
return startOfMethod;
}
public AnalyzedInstruction[] makeInstructionArray() {
AnalyzedInstruction[] instructionArray = new AnalyzedInstruction[instructions.size()];
for (int i=0; i<instructions.size(); i++) {
instructionArray[i] = instructions.valueAt(i);
}
return instructionArray;
/**
* @return a read-only list containing the instructions for tihs method.
*/
public List<AnalyzedInstruction> getInstructions() {
return instructions.getValues();
}
public ValidationException getValidationException() {

View File

@ -16,6 +16,10 @@
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,
* 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 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 Object[] mValues;
private int mSize;