core: fix BlockNode hashCode function
This commit is contained in:
@@ -10,7 +10,7 @@ import java.util.Set;
|
||||
|
||||
public class IgnoreEdgeAttr implements IAttribute {
|
||||
|
||||
private final Set<BlockNode> blocks = new HashSet<BlockNode>();
|
||||
private final Set<BlockNode> blocks = new HashSet<BlockNode>(3);
|
||||
|
||||
public Set<BlockNode> getBlocks() {
|
||||
return blocks;
|
||||
|
||||
@@ -179,7 +179,7 @@ public class BlockNode extends AttrNode implements IBlock {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id; // TODO id can change during reindex
|
||||
return startOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -187,23 +187,11 @@ public class BlockNode extends AttrNode implements IBlock {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (hashCode() != obj.hashCode()) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof BlockNode)) {
|
||||
return false;
|
||||
}
|
||||
BlockNode other = (BlockNode) obj;
|
||||
if (id != other.id) {
|
||||
return false;
|
||||
}
|
||||
if (startOffset != other.startOffset) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return id == other.id && startOffset == other.startOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -86,6 +86,17 @@ public class SimplifyVisitor extends AbstractVisitor {
|
||||
}
|
||||
break;
|
||||
|
||||
case MOVE:
|
||||
InsnArg firstArg = insn.getArg(0);
|
||||
if (firstArg.isLiteral()) {
|
||||
InsnNode constInsn = new InsnNode(InsnType.CONST, 1);
|
||||
constInsn.setResult(insn.getResult());
|
||||
constInsn.addArg(firstArg);
|
||||
constInsn.copyAttributesFrom(insn);
|
||||
return constInsn;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-13
@@ -359,7 +359,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
BlockNode sOut = out.getSecond();
|
||||
|
||||
// redirect out edges
|
||||
List<BlockNode> filtPreds = filterPredecessors(sOut);
|
||||
List<BlockNode> filtPreds = BlockUtils.filterPredecessors(sOut);
|
||||
if (filtPreds.size() > 1) {
|
||||
BlockNode pred = sOut.getPredecessors().get(0);
|
||||
BlockNode newPred = BlockSplitter.insertBlockBetween(mth, pred, sOut);
|
||||
@@ -446,18 +446,6 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
edgeAttr.getBlocks().add(toBlock);
|
||||
}
|
||||
|
||||
private static List<BlockNode> filterPredecessors(BlockNode block) {
|
||||
List<BlockNode> predecessors = block.getPredecessors();
|
||||
List<BlockNode> list = new ArrayList<BlockNode>(predecessors.size());
|
||||
for (BlockNode pred : predecessors) {
|
||||
IgnoreEdgeAttr edgeAttr = pred.get(AType.IGNORE_EDGE);
|
||||
if (edgeAttr == null || !edgeAttr.contains(block)) {
|
||||
list.add(pred);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static int countInstructions(ExceptionHandler excHandler) {
|
||||
int totalSize = 0;
|
||||
for (BlockNode excBlock : excHandler.getBlocks()) {
|
||||
|
||||
@@ -315,34 +315,40 @@ public class BlockProcessor extends AbstractVisitor {
|
||||
return false;
|
||||
}
|
||||
BlockNode exitBlock = mth.getExitBlocks().get(0);
|
||||
if (exitBlock.getPredecessors().size() > 1
|
||||
&& exitBlock.getInstructions().size() == 1
|
||||
&& !exitBlock.contains(AFlag.SYNTHETIC)) {
|
||||
InsnNode returnInsn = exitBlock.getInstructions().get(0);
|
||||
List<BlockNode> preds = new ArrayList<BlockNode>(exitBlock.getPredecessors());
|
||||
if (returnInsn.getArgsCount() != 0 && !isReturnArgAssignInPred(preds, returnInsn)) {
|
||||
return false;
|
||||
}
|
||||
boolean first = true;
|
||||
for (BlockNode pred : preds) {
|
||||
BlockNode newRetBlock = BlockSplitter.startNewBlock(mth, exitBlock.getStartOffset());
|
||||
newRetBlock.add(AFlag.SYNTHETIC);
|
||||
InsnNode newRetInsn;
|
||||
if (first) {
|
||||
newRetInsn = returnInsn;
|
||||
newRetBlock.add(AFlag.ORIG_RETURN);
|
||||
first = false;
|
||||
} else {
|
||||
newRetInsn = duplicateReturnInsn(returnInsn);
|
||||
}
|
||||
newRetBlock.getInstructions().add(newRetInsn);
|
||||
removeConnection(pred, exitBlock);
|
||||
connect(pred, newRetBlock);
|
||||
}
|
||||
cleanExitNodes(mth);
|
||||
return true;
|
||||
if (exitBlock.getInstructions().size() != 1
|
||||
|| exitBlock.contains(AFlag.SYNTHETIC)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
List<BlockNode> preds = exitBlock.getPredecessors();
|
||||
if (preds.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
preds = BlockUtils.filterPredecessors(exitBlock);
|
||||
if (preds.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
InsnNode returnInsn = exitBlock.getInstructions().get(0);
|
||||
if (returnInsn.getArgsCount() != 0 && !isReturnArgAssignInPred(preds, returnInsn)) {
|
||||
return false;
|
||||
}
|
||||
boolean first = true;
|
||||
for (BlockNode pred : preds) {
|
||||
BlockNode newRetBlock = BlockSplitter.startNewBlock(mth, exitBlock.getStartOffset());
|
||||
newRetBlock.add(AFlag.SYNTHETIC);
|
||||
InsnNode newRetInsn;
|
||||
if (first) {
|
||||
newRetInsn = returnInsn;
|
||||
newRetBlock.add(AFlag.ORIG_RETURN);
|
||||
first = false;
|
||||
} else {
|
||||
newRetInsn = duplicateReturnInsn(returnInsn);
|
||||
}
|
||||
newRetBlock.getInstructions().add(newRetInsn);
|
||||
removeConnection(pred, exitBlock);
|
||||
connect(pred, newRetBlock);
|
||||
}
|
||||
cleanExitNodes(mth);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isReturnArgAssignInPred(List<BlockNode> preds, InsnNode returnInsn) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package jadx.core.utils;
|
||||
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.IgnoreEdgeAttr;
|
||||
import jadx.core.dex.attributes.nodes.PhiListAttr;
|
||||
import jadx.core.dex.instructions.IfNode;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
@@ -79,6 +80,25 @@ public class BlockUtils {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return predecessors list without blocks contains 'IGNORE_EDGE' attribute.
|
||||
*
|
||||
* @return new list of filtered predecessors
|
||||
*/
|
||||
public static List<BlockNode> filterPredecessors(BlockNode block) {
|
||||
List<BlockNode> predecessors = block.getPredecessors();
|
||||
List<BlockNode> list = new ArrayList<BlockNode>(predecessors.size());
|
||||
for (BlockNode pred : predecessors) {
|
||||
IgnoreEdgeAttr edgeAttr = pred.get(AType.IGNORE_EDGE);
|
||||
if (edgeAttr == null) {
|
||||
list.add(pred);
|
||||
} else if (!edgeAttr.contains(block)) {
|
||||
list.add(pred);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static boolean isBackEdge(BlockNode from, BlockNode to) {
|
||||
if (to == null) {
|
||||
return false;
|
||||
|
||||
@@ -30,7 +30,6 @@ public class TestFinallyExtract extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
setOutputCFG();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package jadx.tests.integration.trycatch;
|
||||
|
||||
import jadx.core.clsp.NClass;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static jadx.tests.api.utils.JadxMatchers.containsOne;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestTryCatchFinally2 extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
private NClass[] classes;
|
||||
|
||||
public void test(OutputStream output) throws IOException {
|
||||
DataOutputStream out = new DataOutputStream(output);
|
||||
try {
|
||||
out.writeByte(1);
|
||||
out.writeInt(classes.length);
|
||||
for (NClass cls : classes) {
|
||||
writeString(out, cls.getName());
|
||||
}
|
||||
for (NClass cls : classes) {
|
||||
NClass[] parents = cls.getParents();
|
||||
out.writeByte(parents.length);
|
||||
for (NClass parent : parents) {
|
||||
out.writeInt(parent.getId());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeString(DataOutputStream out, String name) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("} finally {"));
|
||||
assertThat(code, containsOne("out.close();"));
|
||||
|
||||
assertThat(code, containsOne("for (NClass parent : parents) {"));
|
||||
|
||||
// TODO
|
||||
// assertThat(code, countString(2, "for (NClass cls : classes) {"));
|
||||
assertThat(code, containsOne("for (NClass cls : this.classes) {"));
|
||||
assertThat(code, containsOne("for (NClass cls2 : this.classes) {"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user