提交 6c61ce52 编写于 作者: S Skylot

fix: handle cases with SSA variable used in several PHI's (#667)

上级 1830c273
...@@ -12,7 +12,6 @@ import jadx.core.dex.instructions.args.InsnArg; ...@@ -12,7 +12,6 @@ import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.InsnNode;
import jadx.core.utils.InsnRemover;
import jadx.core.utils.Utils; import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
...@@ -76,7 +75,7 @@ public final class PhiInsn extends InsnNode { ...@@ -76,7 +75,7 @@ public final class PhiInsn extends InsnNode {
protected RegisterArg removeArg(int index) { protected RegisterArg removeArg(int index) {
RegisterArg reg = (RegisterArg) super.removeArg(index); RegisterArg reg = (RegisterArg) super.removeArg(index);
blockBinds.remove(index); blockBinds.remove(index);
InsnRemover.fixUsedInPhiFlag(reg); reg.getSVar().updateUsedInPhiList();
return reg; return reg;
} }
...@@ -98,7 +97,7 @@ public final class PhiInsn extends InsnNode { ...@@ -98,7 +97,7 @@ public final class PhiInsn extends InsnNode {
RegisterArg reg = (RegisterArg) to; RegisterArg reg = (RegisterArg) to;
bindArg(reg, pred); bindArg(reg, pred);
reg.getSVar().setUsedInPhi(this); reg.getSVar().addUsedInPhi(this);
return true; return true;
} }
......
...@@ -12,7 +12,9 @@ import org.jetbrains.annotations.Nullable; ...@@ -12,7 +12,9 @@ import org.jetbrains.annotations.Nullable;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.AttrNode; import jadx.core.dex.attributes.AttrNode;
import jadx.core.dex.attributes.nodes.RegDebugInfoAttr; import jadx.core.dex.attributes.nodes.RegDebugInfoAttr;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.PhiInsn; import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.typeinference.TypeInfo; import jadx.core.dex.visitors.typeinference.TypeInfo;
import jadx.core.utils.StringUtils; import jadx.core.utils.StringUtils;
...@@ -24,8 +26,7 @@ public class SSAVar extends AttrNode { ...@@ -24,8 +26,7 @@ public class SSAVar extends AttrNode {
private RegisterArg assign; private RegisterArg assign;
private final List<RegisterArg> useList = new ArrayList<>(2); private final List<RegisterArg> useList = new ArrayList<>(2);
@Nullable private List<PhiInsn> usedInPhi = null;
private PhiInsn usedInPhi;
private TypeInfo typeInfo = new TypeInfo(); private TypeInfo typeInfo = new TypeInfo();
...@@ -85,24 +86,60 @@ public class SSAVar extends AttrNode { ...@@ -85,24 +86,60 @@ public class SSAVar extends AttrNode {
useList.removeIf(registerArg -> registerArg == arg); useList.removeIf(registerArg -> registerArg == arg);
} }
public void setUsedInPhi(@Nullable PhiInsn usedInPhi) { public void addUsedInPhi(PhiInsn phiInsn) {
this.usedInPhi = usedInPhi; if (usedInPhi == null) {
usedInPhi = new ArrayList<>(1);
}
usedInPhi.add(phiInsn);
}
public void removeUsedInPhi(PhiInsn phiInsn) {
if (usedInPhi != null) {
usedInPhi.removeIf(insn -> insn == phiInsn);
if (usedInPhi.isEmpty()) {
usedInPhi = null;
}
}
}
public void updateUsedInPhiList() {
this.usedInPhi = null;
for (RegisterArg reg : useList) {
InsnNode parentInsn = reg.getParentInsn();
if (parentInsn != null && parentInsn.getType() == InsnType.PHI) {
addUsedInPhi((PhiInsn) parentInsn);
}
}
} }
@Nullable @Nullable
public PhiInsn getUsedInPhi() { public PhiInsn getOnlyOneUseInPhi() {
if (usedInPhi != null && usedInPhi.size() == 1) {
return usedInPhi.get(0);
}
return null;
}
public List<PhiInsn> getUsedInPhi() {
if (usedInPhi == null) {
return Collections.emptyList();
}
return usedInPhi; return usedInPhi;
} }
public boolean isUsedInPhi() { public boolean isUsedInPhi() {
return usedInPhi != null; return usedInPhi != null && !usedInPhi.isEmpty();
} }
public int getVariableUseCount() { public int getVariableUseCount() {
int count = useList.size();
if (usedInPhi == null) { if (usedInPhi == null) {
return useList.size(); return count;
}
for (PhiInsn phiInsn : usedInPhi) {
count += phiInsn.getResult().getSVar().getUseCount();
} }
return useList.size() + usedInPhi.getResult().getSVar().getUseCount(); return count;
} }
public void setName(String name) { public void setName(String name) {
......
...@@ -58,11 +58,11 @@ public class InitCodeVariables extends AbstractVisitor { ...@@ -58,11 +58,11 @@ public class InitCodeVariables extends AbstractVisitor {
} }
private static void setCodeVar(SSAVar ssaVar, CodeVar codeVar) { private static void setCodeVar(SSAVar ssaVar, CodeVar codeVar) {
PhiInsn usedInPhi = ssaVar.getUsedInPhi(); List<PhiInsn> usedInPhiList = ssaVar.getUsedInPhi();
if (usedInPhi != null) { if (!usedInPhiList.isEmpty()) {
Set<SSAVar> vars = new LinkedHashSet<>(); Set<SSAVar> vars = new LinkedHashSet<>();
vars.add(ssaVar); vars.add(ssaVar);
collectConnectedVars(usedInPhi, vars); collectConnectedVars(usedInPhiList, vars);
setCodeVarType(codeVar, vars); setCodeVarType(codeVar, vars);
vars.forEach(var -> { vars.forEach(var -> {
if (var.isCodeVarSet()) { if (var.isCodeVarSet()) {
...@@ -92,19 +92,18 @@ public class InitCodeVariables extends AbstractVisitor { ...@@ -92,19 +92,18 @@ public class InitCodeVariables extends AbstractVisitor {
} }
} }
private static void collectConnectedVars(PhiInsn phiInsn, Set<SSAVar> vars) { private static void collectConnectedVars(List<PhiInsn> phiInsnList, Set<SSAVar> vars) {
if (phiInsn == null) { for (PhiInsn phiInsn : phiInsnList) {
return; SSAVar resultVar = phiInsn.getResult().getSVar();
} if (vars.add(resultVar)) {
SSAVar resultVar = phiInsn.getResult().getSVar(); collectConnectedVars(resultVar.getUsedInPhi(), vars);
if (vars.add(resultVar)) {
collectConnectedVars(resultVar.getUsedInPhi(), vars);
}
phiInsn.getArguments().forEach(arg -> {
SSAVar sVar = ((RegisterArg) arg).getSVar();
if (vars.add(sVar)) {
collectConnectedVars(sVar.getUsedInPhi(), vars);
} }
}); phiInsn.getArguments().forEach(arg -> {
SSAVar sVar = ((RegisterArg) arg).getSVar();
if (vars.add(sVar)) {
collectConnectedVars(sVar.getUsedInPhi(), vars);
}
});
}
} }
} }
...@@ -203,8 +203,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor { ...@@ -203,8 +203,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor {
private static void fixNamesForPhiInsns(MethodNode mth) { private static void fixNamesForPhiInsns(MethodNode mth) {
mth.getSVars().forEach(ssaVar -> { mth.getSVars().forEach(ssaVar -> {
PhiInsn phiInsn = ssaVar.getUsedInPhi(); for (PhiInsn phiInsn : ssaVar.getUsedInPhi()) {
if (phiInsn != null) {
Set<String> names = new HashSet<>(1 + phiInsn.getArgsCount()); Set<String> names = new HashSet<>(1 + phiInsn.getArgsCount());
addArgName(phiInsn.getResult(), names); addArgName(phiInsn.getResult(), names);
phiInsn.getArguments().forEach(arg -> addArgName(arg, names)); phiInsn.getArguments().forEach(arg -> addArgName(arg, names));
......
...@@ -89,9 +89,12 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor ...@@ -89,9 +89,12 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
|| !incrArg.getSVar().isUsedInPhi()) { || !incrArg.getSVar().isUsedInPhi()) {
return false; return false;
} }
PhiInsn phiInsn = incrArg.getSVar().getUsedInPhi(); List<PhiInsn> phiInsnList = incrArg.getSVar().getUsedInPhi();
if (phiInsn == null if (phiInsnList.size() != 1) {
|| phiInsn.getArgsCount() != 2 return false;
}
PhiInsn phiInsn = phiInsnList.get(0);
if (phiInsn.getArgsCount() != 2
|| !phiInsn.containsArg(incrArg) || !phiInsn.containsArg(incrArg)
|| incrArg.getSVar().getUseCount() != 1) { || incrArg.getSVar().getUseCount() != 1) {
return false; return false;
......
...@@ -62,8 +62,8 @@ public class TernaryMod { ...@@ -62,8 +62,8 @@ public class TernaryMod {
RegisterArg thenResArg = thenInsn.getResult(); RegisterArg thenResArg = thenInsn.getResult();
RegisterArg elseResArg = elseInsn.getResult(); RegisterArg elseResArg = elseInsn.getResult();
if (thenResArg != null && elseResArg != null) { if (thenResArg != null && elseResArg != null) {
PhiInsn thenPhi = thenResArg.getSVar().getUsedInPhi(); PhiInsn thenPhi = thenResArg.getSVar().getOnlyOneUseInPhi();
PhiInsn elsePhi = elseResArg.getSVar().getUsedInPhi(); PhiInsn elsePhi = elseResArg.getSVar().getOnlyOneUseInPhi();
if (thenPhi == null || thenPhi != elsePhi) { if (thenPhi == null || thenPhi != elsePhi) {
return false; return false;
} }
...@@ -165,8 +165,8 @@ public class TernaryMod { ...@@ -165,8 +165,8 @@ public class TernaryMod {
if (t.getResult() == null || e.getResult() == null) { if (t.getResult() == null || e.getResult() == null) {
return false; return false;
} }
PhiInsn tPhi = t.getResult().getSVar().getUsedInPhi(); PhiInsn tPhi = t.getResult().getSVar().getOnlyOneUseInPhi();
PhiInsn ePhi = e.getResult().getSVar().getUsedInPhi(); PhiInsn ePhi = e.getResult().getSVar().getOnlyOneUseInPhi();
if (ePhi == null || tPhi != ePhi) { if (ePhi == null || tPhi != ePhi) {
return false; return false;
} }
......
...@@ -187,7 +187,7 @@ public class SSATransform extends AbstractVisitor { ...@@ -187,7 +187,7 @@ public class SSATransform extends AbstractVisitor {
} }
RegisterArg arg = phiInsn.bindArg(state.getBlock()); RegisterArg arg = phiInsn.bindArg(state.getBlock());
var.use(arg); var.use(arg);
var.setUsedInPhi(phiInsn); var.addUsedInPhi(phiInsn);
} }
/** /**
...@@ -323,7 +323,7 @@ public class SSATransform extends AbstractVisitor { ...@@ -323,7 +323,7 @@ public class SSATransform extends AbstractVisitor {
} }
SSAVar sVar = ((RegisterArg) arg).getSVar(); SSAVar sVar = ((RegisterArg) arg).getSVar();
if (sVar != null) { if (sVar != null) {
sVar.setUsedInPhi(null); sVar.removeUsedInPhi(phiInsn);
} }
} }
InsnRemover.remove(mth, block, phiInsn); InsnRemover.remove(mth, block, phiInsn);
...@@ -347,13 +347,13 @@ public class SSATransform extends AbstractVisitor { ...@@ -347,13 +347,13 @@ public class SSATransform extends AbstractVisitor {
SSAVar argVar = arg.getSVar(); SSAVar argVar = arg.getSVar();
if (argVar != null) { if (argVar != null) {
argVar.removeUse(arg); argVar.removeUse(arg);
argVar.setUsedInPhi(null); argVar.removeUsedInPhi(phi);
} }
// try inline // try inline
if (inlinePhiInsn(mth, block, phi)) { if (inlinePhiInsn(mth, block, phi)) {
insns.remove(phiIndex); insns.remove(phiIndex);
} else { } else {
assign.setUsedInPhi(null); assign.removeUsedInPhi(phi);
InsnNode m = new InsnNode(InsnType.MOVE, 1); InsnNode m = new InsnNode(InsnType.MOVE, 1);
m.add(AFlag.SYNTHETIC); m.add(AFlag.SYNTHETIC);
......
...@@ -196,8 +196,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor { ...@@ -196,8 +196,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
} }
private void mergePhiBounds(SSAVar ssaVar) { private void mergePhiBounds(SSAVar ssaVar) {
PhiInsn usedInPhi = ssaVar.getUsedInPhi(); for (PhiInsn usedInPhi : ssaVar.getUsedInPhi()) {
if (usedInPhi != null) {
Set<ITypeBound> bounds = ssaVar.getTypeInfo().getBounds(); Set<ITypeBound> bounds = ssaVar.getTypeInfo().getBounds();
bounds.addAll(usedInPhi.getResult().getSVar().getTypeInfo().getBounds()); bounds.addAll(usedInPhi.getResult().getSVar().getTypeInfo().getBounds());
for (InsnArg arg : usedInPhi.getArguments()) { for (InsnArg arg : usedInPhi.getArguments()) {
...@@ -307,8 +306,8 @@ public final class TypeInferenceVisitor extends AbstractVisitor { ...@@ -307,8 +306,8 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
if (var.getTypeInfo().getType().isTypeKnown()) { if (var.getTypeInfo().getType().isTypeKnown()) {
return false; return false;
} }
PhiInsn phiInsn = var.getUsedInPhi(); List<PhiInsn> usedInPhiList = var.getUsedInPhi();
if (phiInsn == null) { if (usedInPhiList.isEmpty()) {
return false; return false;
} }
if (var.getUseCount() == 1) { if (var.getUseCount() == 1) {
...@@ -317,7 +316,15 @@ public final class TypeInferenceVisitor extends AbstractVisitor { ...@@ -317,7 +316,15 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
return false; return false;
} }
} }
for (PhiInsn phiInsn : usedInPhiList) {
if (!insertMoveForPhi(mth, phiInsn, var)) {
return false;
}
}
return true;
}
private boolean insertMoveForPhi(MethodNode mth, PhiInsn phiInsn, SSAVar var) {
int argsCount = phiInsn.getArgsCount(); int argsCount = phiInsn.getArgsCount();
for (int argIndex = 0; argIndex < argsCount; argIndex++) { for (int argIndex = 0; argIndex < argsCount; argIndex++) {
RegisterArg reg = phiInsn.getArg(argIndex); RegisterArg reg = phiInsn.getArg(argIndex);
......
...@@ -193,8 +193,7 @@ public class DebugUtils { ...@@ -193,8 +193,7 @@ public class DebugUtils {
} }
} }
for (SSAVar ssaVar : mth.getSVars()) { for (SSAVar ssaVar : mth.getSVars()) {
PhiInsn usedInPhi = ssaVar.getUsedInPhi(); for (PhiInsn usedInPhi : ssaVar.getUsedInPhi()) {
if (usedInPhi != null) {
boolean found = false; boolean found = false;
for (RegisterArg useArg : ssaVar.getUseList()) { for (RegisterArg useArg : ssaVar.getUseList()) {
InsnNode parentInsn = useArg.getParentInsn(); InsnNode parentInsn = useArg.getParentInsn();
......
...@@ -6,7 +6,6 @@ import java.util.List; ...@@ -6,7 +6,6 @@ import java.util.List;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.InsnWrapArg; import jadx.core.dex.instructions.args.InsnWrapArg;
import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.RegisterArg;
...@@ -65,7 +64,7 @@ public class InsnRemover { ...@@ -65,7 +64,7 @@ public class InsnRemover {
if (insn.getType() == InsnType.PHI) { if (insn.getType() == InsnType.PHI) {
for (InsnArg arg : insn.getArguments()) { for (InsnArg arg : insn.getArguments()) {
if (arg instanceof RegisterArg) { if (arg instanceof RegisterArg) {
fixUsedInPhiFlag((RegisterArg) arg); ((RegisterArg) arg).getSVar().updateUsedInPhiList();
} }
} }
} }
...@@ -73,19 +72,6 @@ public class InsnRemover { ...@@ -73,19 +72,6 @@ public class InsnRemover {
insn.add(AFlag.REMOVE); insn.add(AFlag.REMOVE);
} }
public static void fixUsedInPhiFlag(RegisterArg useReg) {
PhiInsn usedIn = null;
for (RegisterArg reg : useReg.getSVar().getUseList()) {
InsnNode parentInsn = reg.getParentInsn();
if (parentInsn != null
&& parentInsn.getType() == InsnType.PHI
&& parentInsn.containsArg(useReg)) {
usedIn = (PhiInsn) parentInsn;
}
}
useReg.getSVar().setUsedInPhi(usedIn);
}
public static void unbindResult(MethodNode mth, InsnNode insn) { public static void unbindResult(MethodNode mth, InsnNode insn) {
RegisterArg r = insn.getResult(); RegisterArg r = insn.getResult();
if (r != null && r.getSVar() != null && mth != null) { if (r != null && r.getSVar() != null && mth != null) {
......
package jadx.tests.integration.variables;
import java.util.List;
import org.junit.jupiter.api.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
public class TestVariablesDefinitions2 extends IntegrationTest {
public static class TestCls {
public static int test(List<String> list) {
int i = 0;
if (list != null) {
for (String str : list) {
if (str.isEmpty()) {
i++;
}
}
}
return i;
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("int i = 0;"));
assertThat(code, containsOne("i++;"));
assertThat(code, containsOne("return i;"));
assertThat(code, not(containsString("i2;")));
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册