Commit 988628a2 authored by Skylot's avatar Skylot

core: fix variable declaration used in several loops

parent c24cdf5c
...@@ -82,7 +82,6 @@ public class Jadx { ...@@ -82,7 +82,6 @@ public class Jadx {
passes.add(new CodeShrinker()); passes.add(new CodeShrinker());
passes.add(new SimplifyVisitor()); passes.add(new SimplifyVisitor());
passes.add(new ProcessVariables());
passes.add(new CheckRegions()); passes.add(new CheckRegions());
if (args.isCFGOutput()) { if (args.isCFGOutput()) {
...@@ -93,6 +92,7 @@ public class Jadx { ...@@ -93,6 +92,7 @@ public class Jadx {
passes.add(new ClassModifier()); passes.add(new ClassModifier());
passes.add(new PrepareForCodeGen()); passes.add(new PrepareForCodeGen());
passes.add(new LoopRegionVisitor()); passes.add(new LoopRegionVisitor());
passes.add(new ProcessVariables());
} }
passes.add(new CodeGen(args)); passes.add(new CodeGen(args));
return passes; return passes;
......
...@@ -15,6 +15,9 @@ import jadx.core.dex.nodes.InsnNode; ...@@ -15,6 +15,9 @@ import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.regions.SwitchRegion; import jadx.core.dex.regions.SwitchRegion;
import jadx.core.dex.regions.conditions.IfRegion; import jadx.core.dex.regions.conditions.IfRegion;
import jadx.core.dex.regions.loops.ForLoop;
import jadx.core.dex.regions.loops.LoopRegion;
import jadx.core.dex.regions.loops.LoopType;
import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.RegionUtils; import jadx.core.utils.RegionUtils;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
...@@ -112,25 +115,45 @@ public class ProcessVariables extends AbstractVisitor { ...@@ -112,25 +115,45 @@ public class ProcessVariables extends AbstractVisitor {
} }
} }
@Override private static class CollectUsageRegionVisitor extends TracedRegionVisitor {
public void visit(MethodNode mth) throws JadxException { private final List<RegisterArg> args;
if (mth.isNoCode()) { private final Map<Variable, Usage> usageMap;
return;
}
final Map<Variable, Usage> usageMap = new LinkedHashMap<Variable, Usage>(); public CollectUsageRegionVisitor(Map<Variable, Usage> usageMap) {
for (RegisterArg arg : mth.getArguments(true)) { this.usageMap = usageMap;
addToUsageMap(arg, usageMap); args = new ArrayList<RegisterArg>();
} }
// collect all variables usage
IRegionVisitor collect = new TracedRegionVisitor() {
@Override @Override
public void processBlockTraced(MethodNode mth, IBlock container, IRegion curRegion) { public void processBlockTraced(MethodNode mth, IBlock container, IRegion curRegion) {
regionProcess(mth, curRegion);
int len = container.getInstructions().size(); int len = container.getInstructions().size();
List<RegisterArg> args = new ArrayList<RegisterArg>();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
InsnNode insn = container.getInstructions().get(i); InsnNode insn = container.getInstructions().get(i);
if (insn.contains(AFlag.SKIP)) {
continue;
}
args.clear();
processInsn(insn, curRegion);
}
}
private void regionProcess(MethodNode mth, IRegion region) {
if (region instanceof LoopRegion) {
LoopRegion loopRegion = (LoopRegion) region;
LoopType loopType = loopRegion.getType();
if (loopType instanceof ForLoop) {
ForLoop forLoop = (ForLoop) loopType;
processInsn(forLoop.getInitInsn(), region);
processInsn(forLoop.getIncrInsn(), region);
}
}
}
void processInsn(InsnNode insn, IRegion curRegion) {
if (insn == null) {
return;
}
// result // result
RegisterArg result = insn.getResult(); RegisterArg result = insn.getResult();
if (result != null && result.isRegister()) { if (result != null && result.isRegister()) {
...@@ -150,7 +173,19 @@ public class ProcessVariables extends AbstractVisitor { ...@@ -150,7 +173,19 @@ public class ProcessVariables extends AbstractVisitor {
} }
} }
} }
};
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode()) {
return;
}
final Map<Variable, Usage> usageMap = new LinkedHashMap<Variable, Usage>();
for (RegisterArg arg : mth.getArguments(true)) {
addToUsageMap(arg, usageMap);
}
// collect all variables usage
IRegionVisitor collect = new CollectUsageRegionVisitor(usageMap);
DepthRegionTraversal.traverseAll(mth, collect); DepthRegionTraversal.traverseAll(mth, collect);
// reduce assigns map // reduce assigns map
...@@ -189,13 +224,13 @@ public class ProcessVariables extends AbstractVisitor { ...@@ -189,13 +224,13 @@ public class ProcessVariables extends AbstractVisitor {
for (IRegion assignRegion : u.getAssigns()) { for (IRegion assignRegion : u.getAssigns()) {
if (u.getArgRegion() == assignRegion if (u.getArgRegion() == assignRegion
&& canDeclareInRegion(u, assignRegion, regionsOrder)) { && canDeclareInRegion(u, assignRegion, regionsOrder)) {
u.getArg().getParentInsn().add(AFlag.DECLARE_VAR); if (declareAtAssign(u)) {
processVar(u.getArg());
it.remove(); it.remove();
break; break;
} }
} }
} }
}
if (usageMap.isEmpty()) { if (usageMap.isEmpty()) {
return; return;
} }
...@@ -239,7 +274,7 @@ public class ProcessVariables extends AbstractVisitor { ...@@ -239,7 +274,7 @@ public class ProcessVariables extends AbstractVisitor {
} }
} }
Usage addToUsageMap(RegisterArg arg, Map<Variable, Usage> usageMap) { private static Usage addToUsageMap(RegisterArg arg, Map<Variable, Usage> usageMap) {
Variable varId = new Variable(arg); Variable varId = new Variable(arg);
Usage usage = usageMap.get(varId); Usage usage = usageMap.get(varId);
if (usage == null) { if (usage == null) {
...@@ -260,6 +295,17 @@ public class ProcessVariables extends AbstractVisitor { ...@@ -260,6 +295,17 @@ public class ProcessVariables extends AbstractVisitor {
return usage; return usage;
} }
private static boolean declareAtAssign(Usage u) {
RegisterArg arg = u.getArg();
InsnNode parentInsn = arg.getParentInsn();
if (!arg.equals(parentInsn.getResult())) {
return false;
}
parentInsn.add(AFlag.DECLARE_VAR);
processVar(arg);
return true;
}
private static void declareVar(IContainer region, RegisterArg arg) { private static void declareVar(IContainer region, RegisterArg arg) {
DeclareVariablesAttr dv = region.get(AType.DECLARE_VARIABLES); DeclareVariablesAttr dv = region.get(AType.DECLARE_VARIABLES);
if (dv == null) { if (dv == null) {
...@@ -308,6 +354,14 @@ public class ProcessVariables extends AbstractVisitor { ...@@ -308,6 +354,14 @@ public class ProcessVariables extends AbstractVisitor {
LOG.debug("TODO: Not found order for region {} for {}", region, u); LOG.debug("TODO: Not found order for region {} for {}", region, u);
return false; return false;
} }
// workaround for declare variables used in several loops
if (region instanceof LoopRegion) {
for (IRegion r : u.getAssigns()) {
if (!RegionUtils.isRegionContainsRegion(region, r)) {
return false;
}
}
}
return isAllRegionsAfter(region, pos, u.getAssigns(), regionsOrder) return isAllRegionsAfter(region, pos, u.getAssigns(), regionsOrder)
&& isAllRegionsAfter(region, pos, u.getUseRegions(), regionsOrder); && isAllRegionsAfter(region, pos, u.getUseRegions(), regionsOrder);
} }
......
package jadx.tests.integration.names;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.ssa.LiveVarAnalysis;
import jadx.tests.api.IntegrationTest;
import java.util.BitSet;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;
public class TestNameAssign2 extends IntegrationTest {
public static class TestCls {
private static void test(MethodNode mth, int regNum, LiveVarAnalysis la) {
List<BlockNode> blocks = mth.getBasicBlocks();
int blocksCount = blocks.size();
BitSet hasPhi = new BitSet(blocksCount);
BitSet processed = new BitSet(blocksCount);
Deque<BlockNode> workList = new LinkedList<BlockNode>();
BitSet assignBlocks = la.getAssignBlocks(regNum);
for (int id = assignBlocks.nextSetBit(0); id >= 0; id = assignBlocks.nextSetBit(id + 1)) {
processed.set(id);
workList.add(blocks.get(id));
}
while (!workList.isEmpty()) {
BlockNode block = workList.pop();
BitSet domFrontier = block.getDomFrontier();
for (int id = domFrontier.nextSetBit(0); id >= 0; id = domFrontier.nextSetBit(id + 1)) {
if (!hasPhi.get(id) && la.isLive(id, regNum)) {
BlockNode df = blocks.get(id);
addPhi(df, regNum);
hasPhi.set(id);
if (!processed.get(id)) {
processed.set(id);
workList.add(df);
}
}
}
}
}
private static void addPhi(BlockNode df, int regNum) {
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
// TODO:
assertThat(code, containsOne("int id;"));
}
}
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