diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java index f6fc95a1..55f1ddc7 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java @@ -33,7 +33,9 @@ package org.jf.dexlib2.analysis; import com.google.common.base.Objects; import com.google.common.collect.Maps; +import org.jf.dexlib2.Opcode; import org.jf.dexlib2.iface.instruction.*; +import org.jf.dexlib2.iface.instruction.formats.Instruction22c; import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.reference.Reference; import org.jf.util.ExceptionWithContext; @@ -43,9 +45,16 @@ import javax.annotation.Nullable; import java.util.*; public class AnalyzedInstruction implements Comparable { + /** + * The MethodAnalyzer containing this instruction + */ + @Nonnull + protected final MethodAnalyzer methodAnalyzer; + /** * The actual instruction */ + @Nullable protected Instruction instruction; /** @@ -85,7 +94,9 @@ public class AnalyzedInstruction implements Comparable { */ protected final Instruction originalInstruction; - public AnalyzedInstruction(Instruction instruction, int instructionIndex, int registerCount) { + public AnalyzedInstruction(MethodAnalyzer methodAnalyzer, Instruction instruction, int instructionIndex, + int registerCount) { + this.methodAnalyzer = methodAnalyzer; this.instruction = instruction; this.originalInstruction = instruction; this.instructionIndex = instructionIndex; @@ -353,6 +364,17 @@ public class AnalyzedInstruction implements Comparable { return false; } + if (instruction.getOpcode() == Opcode.IF_EQZ || instruction.getOpcode() == Opcode.IF_NEZ) { + AnalyzedInstruction previousInstruction = getPreviousInstruction(); + if (previousInstruction != null && + previousInstruction.instruction != null && + previousInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF && + registerNumber == ((Instruction22c)previousInstruction.instruction).getRegisterB() && + MethodAnalyzer.canNarrowAfterInstanceOf(previousInstruction, this, methodAnalyzer.getClassPath())) { + return true; + } + } + if (!setsRegister()) { return false; } @@ -367,6 +389,16 @@ public class AnalyzedInstruction implements Comparable { return false; } + @Nullable + private AnalyzedInstruction getPreviousInstruction() { + for (AnalyzedInstruction predecessor: predecessors) { + if (predecessor.getInstructionIndex() == getInstructionIndex() - 1) { + return predecessor; + } + } + return null; + } + public int getDestinationRegister() { if (!this.instruction.getOpcode().setsRegister()) { throw new ExceptionWithContext("Cannot call getDestinationRegister() for an instruction that doesn't " + diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java index 1715bce7..b7a15a01 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java @@ -112,7 +112,7 @@ public class MethodAnalyzer { //override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't //have to handle the case this special case of instruction being null, in the main class - startOfMethod = new AnalyzedInstruction(null, -1, methodImpl.getRegisterCount()) { + startOfMethod = new AnalyzedInstruction(this, null, -1, methodImpl.getRegisterCount()) { public boolean setsRegister() { return false; } @@ -141,6 +141,10 @@ public class MethodAnalyzer { analyze(); } + public ClassPath getClassPath() { + return classPath; + } + private void analyze() { Method method = this.method; MethodImplementation methodImpl = this.methodImpl; @@ -422,7 +426,8 @@ public class MethodAnalyzer { int currentCodeAddress = 0; for (int i=0; i 0) { + AnalyzedInstruction prevAnalyzedInstruction = analyzedInstructions.valueAt(instructionIndex - 1); + if (prevAnalyzedInstruction.instruction != null && + prevAnalyzedInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF) { + if (canNarrowAfterInstanceOf(prevAnalyzedInstruction, analyzedInstruction, classPath)) { + // Propagate the original type to the failing branch, and the new type to the successful branch + int narrowingRegister = ((Instruction22c)prevAnalyzedInstruction.instruction).getRegisterB(); + RegisterType originalType = analyzedInstruction.getPreInstructionRegisterType(narrowingRegister); + RegisterType newType = RegisterType.getRegisterType(classPath, + (TypeReference)((Instruction22c)prevAnalyzedInstruction.instruction).getReference()); + + AnalyzedInstruction fallthroughInstruction = analyzedInstructions.valueAt( + analyzedInstruction.getInstructionIndex() + 1); + + int nextAddress = getInstructionAddress(analyzedInstruction) + + ((Instruction21t)analyzedInstruction.instruction).getCodeOffset(); + AnalyzedInstruction branchInstruction = analyzedInstructions.get(nextAddress); + + if (analyzedInstruction.instruction.getOpcode() == Opcode.IF_EQZ) { + overridePredecessorRegisterTypeAndPropagateChanges(fallthroughInstruction, analyzedInstruction, + narrowingRegister, newType); + overridePredecessorRegisterTypeAndPropagateChanges(branchInstruction, analyzedInstruction, + narrowingRegister, originalType); + } else { + overridePredecessorRegisterTypeAndPropagateChanges(fallthroughInstruction, analyzedInstruction, + narrowingRegister, originalType); + overridePredecessorRegisterTypeAndPropagateChanges(branchInstruction, analyzedInstruction, + narrowingRegister, newType); + } + } + } + } + } + + private void analyzeInstanceOf(@Nonnull AnalyzedInstruction analyzedInstruction) { + setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BOOLEAN_TYPE); } private void analyzeArrayLength(@Nonnull AnalyzedInstruction analyzedInstruction) {