Commit c18074f6 authored by Skylot's avatar Skylot

core: insert 'continue' instruction

parent 8a706193
......@@ -440,7 +440,7 @@ public class InsnGen {
makeTernary((TernaryInsn) insn, code, state);
break;
case ARGS:
case ONE_ARG:
addArg(code, insn.getArg(0));
break;
......
package jadx.core.dex.instructions;
public enum InsnType {
NOP, // replacement for removed instructions
CONST,
CONST_STR,
......@@ -48,16 +47,24 @@ public enum InsnType {
INVOKE,
// additional instructions
// *** Additional instructions ***
// replacement for removed instructions
NOP,
TERNARY,
CONSTRUCTOR,
BREAK,
CONTINUE,
STR_CONCAT, // strings concatenation
// strings concatenation
STR_CONCAT,
TERNARY,
ARGS, // just generate arguments
// just generate one argument
ONE_ARG,
PHI,
NEW_MULTIDIM_ARRAY // TODO: now multidimensional arrays created using Array.newInstance function
// TODO: now multidimensional arrays created using Array.newInstance function
NEW_MULTIDIM_ARRAY
}
......@@ -36,7 +36,7 @@ public class InsnNode extends LineAttrNode {
}
public static InsnNode wrapArg(InsnArg arg) {
InsnNode insn = new InsnNode(InsnType.ARGS, 1);
InsnNode insn = new InsnNode(InsnType.ONE_ARG, 1);
insn.addArg(arg);
return insn;
}
......
......@@ -34,6 +34,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -519,7 +520,7 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return debugInfoOffset;
}
public SSAVar makeNewSVar(int regNum, int[] versions, RegisterArg arg) {
public SSAVar makeNewSVar(int regNum, int[] versions, @NotNull RegisterArg arg) {
SSAVar var = new SSAVar(regNum, versions[regNum], arg);
versions[regNum]++;
if (sVars.isEmpty()) {
......
......@@ -427,9 +427,9 @@ public class BlockMakerVisitor extends AbstractVisitor {
return true;
}
}
// insert additional blocks if loop has several exits
if (loops.size() == 1) {
LoopInfo loop = loops.get(0);
// insert additional blocks for possible 'break' insertion
List<Edge> edges = loop.getExitEdges();
if (!edges.isEmpty()) {
boolean change = false;
......@@ -444,6 +444,21 @@ public class BlockMakerVisitor extends AbstractVisitor {
return true;
}
}
// insert additional blocks for possible 'continue' insertion
BlockNode loopEnd = loop.getEnd();
if (loopEnd.getPredecessors().size() > 1) {
boolean change = false;
List<BlockNode> nodes = new ArrayList<BlockNode>(loopEnd.getPredecessors());
for (BlockNode pred : nodes) {
if (!pred.contains(AFlag.SYNTHETIC)) {
insertBlockBetween(mth, pred, loopEnd);
change = true;
}
}
if (change) {
return true;
}
}
}
}
return splitReturn(mth);
......
......@@ -239,13 +239,19 @@ public class IfMakerHelper {
}
static void confirmMerge(IfInfo info) {
for (BlockNode block : info.getMergedBlocks()) {
block.add(AFlag.SKIP);
if (info.getMergedBlocks().size() > 1) {
for (BlockNode block : info.getMergedBlocks()) {
if (block != info.getIfBlock()) {
block.add(AFlag.SKIP);
}
}
}
for (BlockNode block : info.getSkipBlocks()) {
block.add(AFlag.SKIP);
if (!info.getSkipBlocks().isEmpty()) {
for (BlockNode block : info.getSkipBlocks()) {
block.add(AFlag.SKIP);
}
info.getSkipBlocks().clear();
}
info.getSkipBlocks().clear();
}
private static IfInfo getNextIf(IfInfo info, BlockNode block) {
......
......@@ -166,7 +166,9 @@ public class RegionMaker {
LoopRegion loopRegion = makeLoopRegion(curRegion, loop, exitBlocks);
if (loopRegion == null) {
return makeEndlessLoop(curRegion, stack, loop, loopStart);
BlockNode exit = makeEndlessLoop(curRegion, stack, loop, loopStart);
insertContinueInsns(loop);
return exit;
}
curRegion.getSubBlocks().add(loopRegion);
IRegion outerRegion = stack.peekRegion();
......@@ -233,6 +235,7 @@ public class RegionMaker {
loopRegion.setBody(body);
}
stack.pop();
insertContinueInsns(loop);
return out;
}
......@@ -359,9 +362,12 @@ public class RegionMaker {
if (source.contains(AType.CATCH_BLOCK)
&& source.getSuccessors().size() == 2) {
BlockNode other = BlockUtils.selectOther(loopExit, source.getSuccessors());
if (other != null && other.contains(AType.EXC_HANDLER)) {
insertBlock = source;
confirm = true;
if (other != null) {
other = BlockUtils.skipSyntheticSuccessor(other);
if (other.contains(AType.EXC_HANDLER)) {
insertBlock = source;
confirm = true;
}
}
}
}
......@@ -405,6 +411,45 @@ public class RegionMaker {
return true;
}
private static void insertContinueInsns(LoopInfo loop) {
BlockNode loopEnd = loop.getEnd();
List<BlockNode> predecessors = loopEnd.getPredecessors();
if (predecessors.size() <= 1) {
return;
}
for (BlockNode pred : predecessors) {
if (!pred.contains(AFlag.SYNTHETIC)
|| BlockUtils.checkLastInsnType(pred, InsnType.CONTINUE)) {
continue;
}
List<BlockNode> nodes = pred.getPredecessors();
if (nodes.isEmpty()) {
continue;
}
BlockNode codePred = nodes.get(0);
if (codePred.contains(AFlag.SKIP)) {
continue;
}
if (!isDominatedOnBlocks(codePred, predecessors)) {
for (BlockNode blockNode : predecessors) {
if (blockNode != pred && BlockUtils.isPathExists(codePred, blockNode)) {
InsnNode cont = new InsnNode(InsnType.CONTINUE, 0);
pred.getInstructions().add(cont);
}
}
}
}
}
private static boolean isDominatedOnBlocks(BlockNode dom, List<BlockNode> blocks) {
for (BlockNode node : blocks) {
if (!node.isDominator(dom)) {
return false;
}
}
return true;
}
private final Set<BlockNode> cacheSet = new HashSet<BlockNode>();
private BlockNode processMonitorEnter(IRegion curRegion, BlockNode block, InsnNode insn, RegionStack stack) {
......@@ -444,7 +489,7 @@ public class RegionMaker {
* Traverse from monitor-enter thru successors and collect blocks contains monitor-exit
*/
private static void traverseMonitorExits(SynchronizedRegion region, InsnArg arg, BlockNode block,
Set<BlockNode> exits, Set<BlockNode> visited) {
Set<BlockNode> exits, Set<BlockNode> visited) {
visited.add(block);
for (InsnNode insn : block.getInstructions()) {
if (insn.getType() == InsnType.MONITOR_EXIT
......
......@@ -439,4 +439,14 @@ public class BlockUtils {
}
return block == end;
}
/**
* Return successor of synthetic block or same block otherwise.
*/
public static BlockNode skipSyntheticSuccessor(BlockNode block) {
if (block.isSynthetic() && !block.getSuccessors().isEmpty()) {
return block.getSuccessors().get(0);
}
return block;
}
}
package jadx.tests.integration.loops;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import org.junit.Test;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;
public class TestContinueInLoop extends IntegrationTest {
public static class TestCls {
private int f;
private void test(int[] a, int b) {
for (int i = 0; i < a.length; i++) {
int v = a[i];
if (v < b) {
a[i]++;
} else if (v > b) {
a[i]--;
} else {
continue;
}
if (i < b) {
break;
}
}
this.f++;
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("for (int i = 0; i < a.length; i++) {"));
assertThat(code, containsOne("if (i < b) {"));
assertThat(code, containsOne("continue;"));
assertThat(code, containsOne("break;"));
assertThat(code, containsOne("this.f++;"));
}
}
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