提交 7b6825d8 编写于 作者: S Skylot

core: move same instructions from predecessors for loops

上级 a27cb9c3
......@@ -96,4 +96,8 @@ public abstract class AttrNode implements IAttributeNode {
public String getAttributesString() {
return storage.toString();
}
public boolean isAttrStorageEmpty() {
return storage.isEmpty();
}
}
......@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import com.android.dx.io.instructions.DecodedInstruction;
import com.rits.cloning.Cloner;
......@@ -251,12 +252,14 @@ public class InsnNode extends LineAttrNode {
if (this == other) {
return true;
}
if (insnType != other.insnType
|| arguments.size() != other.arguments.size()) {
if (insnType != other.insnType) {
return false;
}
// check wrapped instructions
int size = arguments.size();
if (size != other.arguments.size()) {
return false;
}
// check wrapped instructions
for (int i = 0; i < size; i++) {
InsnArg arg = arguments.get(i);
InsnArg otherArg = other.arguments.get(i);
......@@ -273,6 +276,16 @@ public class InsnNode extends LineAttrNode {
}
return true;
}
/**
* 'Hard' equals, compare all arguments
*/
public boolean isDeepEquals(InsnNode other) {
if (this == other) {
return true;
}
return isSame(other)
&& Objects.equals(arguments, other.arguments);
}
protected <T extends InsnNode> T copyCommonParams(T copy) {
copy.setResult(result);
......
......@@ -45,6 +45,10 @@ public class BlockProcessor extends AbstractVisitor {
private static void processBlocksTree(MethodNode mth) {
computeDominators(mth);
if (independentBlockTreeMod(mth)) {
clearBlocksState(mth);
computeDominators(mth);
}
markReturnBlocks(mth);
int i = 0;
......@@ -64,6 +68,109 @@ public class BlockProcessor extends AbstractVisitor {
processNestedLoops(mth);
}
private static boolean removeEmptyBlock(MethodNode mth, BlockNode block) {
if (block.getInstructions().isEmpty()
&& !block.isSynthetic()
&& block.isAttrStorageEmpty()
&& block.getSuccessors().size() <= 1) {
LOG.debug("Removing empty block: {}", block);
if (block.getSuccessors().size() == 1) {
BlockNode successor = block.getSuccessors().get(0);
block.getPredecessors().forEach(pred -> {
pred.getSuccessors().remove(block);
BlockSplitter.connect(pred, successor);
BlockSplitter.replaceTarget(pred, block, successor);
pred.updateCleanSuccessors();
});
BlockSplitter.removeConnection(block, successor);
} else {
block.getPredecessors().forEach(pred -> {
pred.getSuccessors().remove(block);
pred.updateCleanSuccessors();
});
}
block.add(AFlag.REMOVE);
block.getSuccessors().clear();
block.getPredecessors().clear();
return true;
}
return false;
}
private static boolean deduplicateBlockInsns(BlockNode block) {
if (block.contains(AFlag.LOOP_START) || block.contains(AFlag.LOOP_END)) {
// search for same instruction at end of all predecessors blocks
List<BlockNode> predecessors = block.getPredecessors();
int predsCount = predecessors.size();
if (predsCount > 1) {
InsnNode lastInsn = BlockUtils.getLastInsn(block);
if (lastInsn != null && lastInsn.getType() == InsnType.IF) {
return false;
}
int sameInsnCount = getSameLastInsnCount(predecessors);
if (sameInsnCount > 0) {
List<InsnNode> insns = getLastInsns(predecessors.get(0), sameInsnCount);
insertAtStart(block, insns);
predecessors.forEach(pred -> getLastInsns(pred, sameInsnCount).clear());
LOG.debug("Move duplicate insns, count: {} to block {}", sameInsnCount, block);
return true;
}
}
}
return false;
}
private static List<InsnNode> getLastInsns(BlockNode blockNode, int sameInsnCount) {
List<InsnNode> instructions = blockNode.getInstructions();
int size = instructions.size();
return instructions.subList(size - sameInsnCount, size);
}
private static void insertAtStart(BlockNode block, List<InsnNode> insns) {
List<InsnNode> blockInsns = block.getInstructions();
List<InsnNode> newInsnList = new ArrayList<>(insns.size() + blockInsns.size());
newInsnList.addAll(insns);
newInsnList.addAll(blockInsns);
blockInsns.clear();
blockInsns.addAll(newInsnList);
}
private static int getSameLastInsnCount(List<BlockNode> predecessors) {
int sameInsnCount = 0;
while (true) {
InsnNode insn = null;
for (BlockNode pred : predecessors) {
InsnNode curInsn = getInsnsFromEnd(pred, sameInsnCount);
if (curInsn == null) {
return sameInsnCount;
}
if (insn == null) {
insn = curInsn;
} else {
if (!isSame(insn, curInsn)) {
return sameInsnCount;
}
}
}
sameInsnCount++;
}
}
private static boolean isSame(InsnNode insn, InsnNode curInsn) {
return /*insn.getType() == InsnType.MOVE &&*/ insn.isDeepEquals(curInsn) && insn.canReorder();
}
private static InsnNode getInsnsFromEnd(BlockNode block, int number) {
List<InsnNode> instructions = block.getInstructions();
int insnCount = instructions.size();
if (insnCount <= number) {
return null;
}
return instructions.get(insnCount - number - 1);
}
private static void computeDominators(MethodNode mth) {
List<BlockNode> basicBlocks = mth.getBasicBlocks();
int nBlocks = basicBlocks.size();
......@@ -104,9 +211,7 @@ public class BlockProcessor extends AbstractVisitor {
markLoops(mth);
// clear self dominance
for (BlockNode block : basicBlocks) {
block.getDoms().clear(block.getId());
}
basicBlocks.forEach(block -> block.getDoms().clear(block.getId()));
// calculate immediate dominators
for (BlockNode block : basicBlocks) {
......@@ -148,9 +253,7 @@ public class BlockProcessor extends AbstractVisitor {
if (block.getDomFrontier() != null) {
return;
}
for (BlockNode c : block.getDominatesOn()) {
computeBlockDF(mth, c);
}
block.getDominatesOn().forEach(c -> computeBlockDF(mth, c));
List<BlockNode> blocks = mth.getBasicBlocks();
BitSet domFrontier = null;
for (BlockNode s : block.getSuccessors()) {
......@@ -180,39 +283,37 @@ public class BlockProcessor extends AbstractVisitor {
private static void markReturnBlocks(MethodNode mth) {
mth.getExitBlocks().clear();
for (BlockNode block : mth.getBasicBlocks()) {
mth.getBasicBlocks().forEach(block -> {
if (BlockUtils.checkLastInsnType(block, InsnType.RETURN)) {
block.add(AFlag.RETURN);
mth.getExitBlocks().add(block);
}
}
});
}
private static void markLoops(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
for (BlockNode succ : block.getSuccessors()) {
// Every successor that dominates its predecessor is a header of a loop,
// block -> succ is a back edge.
if (block.getDoms().get(succ.getId())) {
succ.add(AFlag.LOOP_START);
mth.getBasicBlocks().forEach(block -> {
// Every successor that dominates its predecessor is a header of a loop,
// block -> succ is a back edge.
block.getSuccessors().forEach(successor -> {
if (block.getDoms().get(successor.getId())) {
successor.add(AFlag.LOOP_START);
block.add(AFlag.LOOP_END);
LoopInfo loop = new LoopInfo(succ, block);
succ.addAttr(AType.LOOP, loop);
LoopInfo loop = new LoopInfo(successor, block);
successor.addAttr(AType.LOOP, loop);
block.addAttr(AType.LOOP, loop);
}
}
}
});
});
}
private static void registerLoops(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
mth.getBasicBlocks().forEach(block -> {
if (block.contains(AFlag.LOOP_START)) {
for (LoopInfo loop : block.getAll(AType.LOOP)) {
mth.registerLoop(loop);
}
block.getAll(AType.LOOP).forEach(mth::registerLoop);
}
}
});
}
private static void processNestedLoops(MethodNode mth) {
......@@ -242,10 +343,14 @@ public class BlockProcessor extends AbstractVisitor {
}
private static boolean modifyBlocksTree(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
List<BlockNode> basicBlocks = mth.getBasicBlocks();
for (BlockNode block : basicBlocks) {
if (block.getPredecessors().isEmpty() && block != mth.getEnterBlock()) {
throw new JadxRuntimeException("Unreachable block: " + block);
}
}
for (BlockNode block : basicBlocks) {
if (checkLoops(mth, block)) {
return true;
}
......@@ -253,6 +358,25 @@ public class BlockProcessor extends AbstractVisitor {
return splitReturn(mth);
}
private static boolean independentBlockTreeMod(MethodNode mth) {
List<BlockNode> basicBlocks = mth.getBasicBlocks();
boolean changed = false;
for (BlockNode basicBlock : basicBlocks) {
if (deduplicateBlockInsns(basicBlock)) {
changed = true;
}
}
for (BlockNode basicBlock : basicBlocks) {
if (removeEmptyBlock(mth, basicBlock)) {
changed = true;
}
}
if (BlockSplitter.removeEmptyDetachedBlocks(mth)) {
changed = true;
}
return changed;
}
private static boolean checkLoops(MethodNode mth, BlockNode block) {
// check loops
List<LoopInfo> loops = block.getAll(AType.LOOP);
......@@ -303,9 +427,7 @@ public class BlockProcessor extends AbstractVisitor {
change = true;
}
}
if (change) {
return true;
}
return change;
}
}
return false;
......
......@@ -253,8 +253,8 @@ public class BlockSplitter extends AbstractVisitor {
}
}
static void removeEmptyDetachedBlocks(MethodNode mth) {
mth.getBasicBlocks().removeIf(block ->
static boolean removeEmptyDetachedBlocks(MethodNode mth) {
return mth.getBasicBlocks().removeIf(block ->
block.getInstructions().isEmpty()
&& block.getPredecessors().isEmpty()
&& block.getSuccessors().isEmpty()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册