core: improve 'finally' extraction, refactor instructions
This commit is contained in:
@@ -52,7 +52,8 @@ public class ConvertToClsSet {
|
||||
LOG.info("done");
|
||||
}
|
||||
|
||||
private static void addFilesFromDirectory(File dir, List<InputFile> inputFiles) throws IOException, DecodeException {
|
||||
private static void addFilesFromDirectory(File dir,
|
||||
List<InputFile> inputFiles) throws IOException, DecodeException {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null) {
|
||||
return;
|
||||
|
||||
@@ -61,20 +61,15 @@ public class ArithNode extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ArithNode) || !super.equals(obj)) {
|
||||
if (!(obj instanceof ArithNode) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
ArithNode that = (ArithNode) obj;
|
||||
return op == that.op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + op.hashCode();
|
||||
ArithNode other = (ArithNode) obj;
|
||||
return op == other.op;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,20 +17,15 @@ public final class ConstClassNode extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ConstClassNode) || !super.equals(obj)) {
|
||||
if (!(obj instanceof ConstClassNode) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
ConstClassNode that = (ConstClassNode) obj;
|
||||
return clsType.equals(that.clsType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + clsType.hashCode();
|
||||
ConstClassNode other = (ConstClassNode) obj;
|
||||
return clsType.equals(other.clsType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,20 +16,15 @@ public final class ConstStringNode extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ConstStringNode) || !super.equals(obj)) {
|
||||
if (!(obj instanceof ConstStringNode) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
ConstStringNode that = (ConstStringNode) obj;
|
||||
return str.equals(that.str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + str.hashCode();
|
||||
ConstStringNode other = (ConstStringNode) obj;
|
||||
return str.equals(other.str);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -55,19 +55,14 @@ public final class FillArrayNode extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof FillArrayNode) || !super.equals(obj)) {
|
||||
if (!(obj instanceof FillArrayNode) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
FillArrayNode that = (FillArrayNode) obj;
|
||||
return elemType.equals(that.elemType) && data == that.data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + elemType.hashCode() + data.hashCode();
|
||||
FillArrayNode other = (FillArrayNode) obj;
|
||||
return elemType.equals(other.elemType) && data == other.data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,23 +20,6 @@ public class GotoNode extends InsnNode {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof GotoNode) || !super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
GotoNode gotoNode = (GotoNode) obj;
|
||||
return target == gotoNode.target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "-> " + InsnUtils.formatOffset(target);
|
||||
|
||||
@@ -4,6 +4,7 @@ import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.PrimitiveType;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
|
||||
import com.android.dx.io.instructions.DecodedInstruction;
|
||||
@@ -71,20 +72,15 @@ public class IfNode extends GotoNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof IfNode) || !super.equals(obj)) {
|
||||
if (!(obj instanceof IfNode) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
IfNode ifNode = (IfNode) obj;
|
||||
return op == ifNode.op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + op.hashCode();
|
||||
IfNode other = (IfNode) obj;
|
||||
return op == other.op;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,20 +17,15 @@ public class IndexInsnNode extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof IndexInsnNode) || !super.equals(obj)) {
|
||||
if (!(obj instanceof IndexInsnNode) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
IndexInsnNode that = (IndexInsnNode) obj;
|
||||
return index == null ? that.index == null : index.equals(that.index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + (index != null ? index.hashCode() : 0);
|
||||
IndexInsnNode other = (IndexInsnNode) obj;
|
||||
return index == null ? other.index == null : index.equals(other.index);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,7 +56,6 @@ public class InsnDecoder {
|
||||
InsnNode insn = decode(rawInsn, i);
|
||||
if (insn != null) {
|
||||
insn.setOffset(i);
|
||||
insn.setInsnHashCode(calcHashCode(rawInsn));
|
||||
}
|
||||
instructions[i] = insn;
|
||||
} else {
|
||||
@@ -67,21 +66,6 @@ public class InsnDecoder {
|
||||
return instructions;
|
||||
}
|
||||
|
||||
private int calcHashCode(DecodedInstruction insn) {
|
||||
int hash = insn.getOpcode();
|
||||
hash = hash * 31 + insn.getClass().getName().hashCode();
|
||||
hash = hash * 31 + insn.getFormat().ordinal();
|
||||
hash = hash * 31 + insn.getRegisterCount();
|
||||
hash = hash * 31 + insn.getIndex();
|
||||
hash = hash * 31 + insn.getTarget();
|
||||
hash = hash * 31 + insn.getA();
|
||||
hash = hash * 31 + insn.getB();
|
||||
hash = hash * 31 + insn.getC();
|
||||
hash = hash * 31 + insn.getD();
|
||||
hash = hash * 31 + insn.getE();
|
||||
return hash;
|
||||
}
|
||||
|
||||
private InsnNode decode(DecodedInstruction insn, int offset) throws DecodeException {
|
||||
switch (insn.getOpcode()) {
|
||||
case Opcodes.NOP:
|
||||
|
||||
@@ -45,23 +45,15 @@ public class InvokeNode extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof InvokeNode) || !super.equals(obj)) {
|
||||
if (!(obj instanceof InvokeNode) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
InvokeNode that = (InvokeNode) obj;
|
||||
return type == that.type && mth.equals(that.mth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + type.hashCode();
|
||||
result = 31 * result + mth.hashCode();
|
||||
return result;
|
||||
InvokeNode other = (InvokeNode) obj;
|
||||
return type == other.type && mth.equals(other.mth);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,26 +37,17 @@ public class SwitchNode extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof SwitchNode) || !super.equals(obj)) {
|
||||
if (!(obj instanceof SwitchNode) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
SwitchNode that = (SwitchNode) obj;
|
||||
return def == that.def
|
||||
&& Arrays.equals(keys, that.keys)
|
||||
&& Arrays.equals(targets, that.targets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + Arrays.hashCode(keys);
|
||||
result = 31 * result + Arrays.hashCode(targets);
|
||||
result = 31 * result + def;
|
||||
return result;
|
||||
SwitchNode other = (SwitchNode) obj;
|
||||
return def == other.def
|
||||
&& Arrays.equals(keys, other.keys)
|
||||
&& Arrays.equals(targets, other.targets);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -92,26 +92,16 @@ public class ConstructorInsn extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof ConstructorInsn) || !super.equals(o)) {
|
||||
if (!(obj instanceof ConstructorInsn) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
ConstructorInsn that = (ConstructorInsn) o;
|
||||
return callMth.equals(that.callMth)
|
||||
&& callType == that.callType
|
||||
&& instanceArg.equals(that.instanceArg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + callMth.hashCode();
|
||||
result = 31 * result + callType.hashCode();
|
||||
result = 31 * result + instanceArg.hashCode();
|
||||
return result;
|
||||
ConstructorInsn other = (ConstructorInsn) obj;
|
||||
return callMth.equals(other.callMth)
|
||||
&& callType == other.callType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -60,22 +60,17 @@ public final class TernaryInsn extends InsnNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean isSame(InsnNode obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof TernaryInsn) || !super.equals(obj)) {
|
||||
if (!(obj instanceof TernaryInsn) || !super.isSame(obj)) {
|
||||
return false;
|
||||
}
|
||||
TernaryInsn that = (TernaryInsn) obj;
|
||||
return condition.equals(that.condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + condition.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return InsnUtils.formatOffset(offset) + ": TERNARY"
|
||||
|
||||
@@ -22,7 +22,6 @@ public class InsnNode extends LineAttrNode {
|
||||
private RegisterArg result;
|
||||
private final List<InsnArg> arguments;
|
||||
protected int offset;
|
||||
protected int insnHashCode = super.hashCode();
|
||||
|
||||
public InsnNode(InsnType type, int argsCount) {
|
||||
this.insnType = type;
|
||||
@@ -197,39 +196,31 @@ public class InsnNode extends LineAttrNode {
|
||||
+ Utils.listToString(arguments);
|
||||
}
|
||||
|
||||
public void setInsnHashCode(int insnHashCode) {
|
||||
this.insnHashCode = insnHashCode;
|
||||
/**
|
||||
* Compare instruction only by identity.
|
||||
*/
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare instruction only by identity.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return insnHashCode;
|
||||
public final boolean equals(Object obj) {
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
/**
|
||||
* 'Soft' equals, don't compare arguments, only instruction specific parameters.
|
||||
*/
|
||||
public boolean isSame(InsnNode other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (hashCode() != obj.hashCode()) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof InsnNode)) {
|
||||
return false;
|
||||
}
|
||||
InsnNode other = (InsnNode) obj;
|
||||
if (insnType != other.insnType) {
|
||||
return false;
|
||||
}
|
||||
if (arguments.size() != other.arguments.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO !!! finish equals
|
||||
return true;
|
||||
return insnType == other.insnType
|
||||
&& arguments.size() == other.arguments.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public final class IfInfo {
|
||||
}
|
||||
|
||||
private IfInfo(IfCondition condition, BlockNode thenBlock, BlockNode elseBlock,
|
||||
Set<BlockNode> mergedBlocks, Set<BlockNode> skipBlocks) {
|
||||
Set<BlockNode> mergedBlocks, Set<BlockNode> skipBlocks) {
|
||||
this.condition = condition;
|
||||
this.thenBlock = thenBlock;
|
||||
this.elseBlock = elseBlock;
|
||||
|
||||
@@ -66,7 +66,8 @@ public class ReSugarCode extends AbstractVisitor {
|
||||
/**
|
||||
* Replace new array and sequence of array-put to new filled-array instruction.
|
||||
*/
|
||||
private static InsnNode processNewArray(MethodNode mth, List<InsnNode> instructions, int i, InstructionRemover remover) {
|
||||
private static InsnNode processNewArray(MethodNode mth, List<InsnNode> instructions, int i,
|
||||
InstructionRemover remover) {
|
||||
InsnNode insn = instructions.get(i);
|
||||
InsnArg arg = insn.getArg(0);
|
||||
if (!arg.isLiteral()) {
|
||||
|
||||
@@ -293,10 +293,11 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static boolean sameInsns(InsnNode remInsn, InsnNode fInsn, BlocksRemoveInfo removeInfo) {
|
||||
if (remInsn.getType() != fInsn.getType()
|
||||
|| remInsn.getArgsCount() != fInsn.getArgsCount()) {
|
||||
if (!remInsn.isSame(fInsn)) {
|
||||
return false;
|
||||
}
|
||||
// TODO: check instance arg in ConstructorInsn
|
||||
// TODO: compare literals
|
||||
for (int i = 0; i < remInsn.getArgsCount(); i++) {
|
||||
InsnArg remArg = remInsn.getArg(i);
|
||||
InsnArg fArg = fInsn.getArg(i);
|
||||
@@ -328,7 +329,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
return true;
|
||||
}
|
||||
if (remBlock.getPredecessors().size() != 1) {
|
||||
LOG.warn("Finally extract failed: remBlock pred: {}, {}", remBlock, remBlock.getPredecessors());
|
||||
LOG.warn("Finally extract failed: remBlock pred: {}, {}, method: {}", remBlock, remBlock.getPredecessors(), mth);
|
||||
return false;
|
||||
}
|
||||
BlockNode remBlockPred = remBlock.getPredecessors().get(0);
|
||||
|
||||
@@ -51,7 +51,7 @@ public class CheckRegions extends AbstractVisitor {
|
||||
// TODO
|
||||
// mth.add(AFlag.INCONSISTENT_CODE);
|
||||
LOG.debug(" Duplicated block: {} in {}", block, mth);
|
||||
printRegionsWithBlock(mth, block);
|
||||
// printRegionsWithBlock(mth, block);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -61,7 +61,8 @@ public class DepthRegionTraversal {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean traverseIterativeInternal(MethodNode mth, IRegionIterativeVisitor visitor, IContainer container) {
|
||||
private static boolean traverseIterativeInternal(MethodNode mth, IRegionIterativeVisitor visitor,
|
||||
IContainer container) {
|
||||
if (container instanceof IRegion) {
|
||||
IRegion region = (IRegion) container;
|
||||
if (visitor.visitRegion(mth, region)) {
|
||||
|
||||
@@ -124,7 +124,8 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
|
||||
return true;
|
||||
}
|
||||
|
||||
private static LoopType checkArrayForEach(MethodNode mth, InsnNode initInsn, InsnNode incrInsn, IfCondition condition) {
|
||||
private static LoopType checkArrayForEach(MethodNode mth, InsnNode initInsn, InsnNode incrInsn,
|
||||
IfCondition condition) {
|
||||
if (!(incrInsn instanceof ArithNode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class ClassFileManager extends ForwardingJavaFileManager<StandardJavaFile
|
||||
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForOutput(Location location, String className,
|
||||
Kind kind, FileObject sibling) throws IOException {
|
||||
Kind kind, FileObject sibling) throws IOException {
|
||||
JavaClassObject clsObject = new JavaClassObject(className, kind);
|
||||
classLoader.getClsMap().put(className, clsObject);
|
||||
return clsObject;
|
||||
|
||||
@@ -54,7 +54,8 @@ public class StaticCompiler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
|
||||
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind,
|
||||
FileObject sibling) throws IOException {
|
||||
if (kind == JavaFileObject.Kind.CLASS) {
|
||||
File file = new File(outDir, className.replace('.', '/') + ".class");
|
||||
files.add(file);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package jadx.tests.integration.trycatch;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.visitors.DepthTraversal;
|
||||
import jadx.core.dex.visitors.IDexTreeVisitor;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static jadx.tests.api.utils.JadxMatchers.containsOne;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestTryCatchFinally3 extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TestCls.class);
|
||||
|
||||
public static void process(ClassNode cls, List<IDexTreeVisitor> passes) {
|
||||
try {
|
||||
cls.load();
|
||||
for (IDexTreeVisitor visitor : passes) {
|
||||
DepthTraversal.visit(visitor, cls);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Class process exception: {}", cls, e);
|
||||
} finally {
|
||||
cls.unload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("for (IDexTreeVisitor visitor : passes) {"));
|
||||
|
||||
assertThat(code, containsOne("} catch (Exception e) {"));
|
||||
assertThat(code, containsOne("LOG.error(\"Class process exception: {}\", cls, e);"));
|
||||
|
||||
assertThat(code, containsOne("} finally {"));
|
||||
assertThat(code, containsOne("cls.unload();"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user