Commit 9cea0163 authored by Skylot's avatar Skylot

core: fix BlockNode hashCode function

parent 577176dd
......@@ -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;
}
......
......@@ -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);
if (exitBlock.getInstructions().size() != 1
|| exitBlock.contains(AFlag.SYNTHETIC)) {
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);
}
cleanExitNodes(mth);
return true;
newRetBlock.getInstructions().add(newRetInsn);
removeConnection(pred, exitBlock);
connect(pred, newRetBlock);
}
return false;
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();
......
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) {"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment