Commit 2383c401 authored by Skylot's avatar Skylot

fix: correct arg replace in PHI instruction (#462)

parent 305cf537
package jadx.core.dex.instructions; package jadx.core.dex.instructions;
import java.util.LinkedHashMap; import java.util.ArrayList;
import java.util.Map; import java.util.List;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.ArgType;
...@@ -17,11 +18,12 @@ import jadx.core.utils.exceptions.JadxRuntimeException; ...@@ -17,11 +18,12 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
public final class PhiInsn extends InsnNode { public final class PhiInsn extends InsnNode {
private final Map<RegisterArg, BlockNode> blockBinds; // map arguments to blocks (in same order as in arguments list)
private final List<BlockNode> blockBinds;
public PhiInsn(int regNum, int predecessors) { public PhiInsn(int regNum, int predecessors) {
super(InsnType.PHI, predecessors); super(InsnType.PHI, predecessors);
this.blockBinds = new LinkedHashMap<>(predecessors); this.blockBinds = new ArrayList<>(predecessors);
setResult(InsnArg.reg(regNum, ArgType.UNKNOWN)); setResult(InsnArg.reg(regNum, ArgType.UNKNOWN));
add(AFlag.DONT_INLINE); add(AFlag.DONT_INLINE);
add(AFlag.DONT_GENERATE); add(AFlag.DONT_GENERATE);
...@@ -34,19 +36,24 @@ public final class PhiInsn extends InsnNode { ...@@ -34,19 +36,24 @@ public final class PhiInsn extends InsnNode {
} }
public void bindArg(RegisterArg arg, BlockNode pred) { public void bindArg(RegisterArg arg, BlockNode pred) {
if (blockBinds.containsValue(pred)) { if (blockBinds.contains(pred)) {
throw new JadxRuntimeException("Duplicate predecessors in PHI insn: " + pred + ", " + this); throw new JadxRuntimeException("Duplicate predecessors in PHI insn: " + pred + ", " + this);
} }
addArg(arg); super.addArg(arg);
blockBinds.put(arg, pred); blockBinds.add(pred);
} }
@Nullable
public BlockNode getBlockByArg(RegisterArg arg) { public BlockNode getBlockByArg(RegisterArg arg) {
return blockBinds.get(arg); int index = getArgIndex(arg);
if (index == -1) {
return null;
}
return blockBinds.get(index);
} }
public Map<RegisterArg, BlockNode> getBlockBinds() { public BlockNode getBlockByArgIndex(int argIndex) {
return blockBinds; return blockBinds.get(argIndex);
} }
@Override @Override
...@@ -57,17 +64,20 @@ public final class PhiInsn extends InsnNode { ...@@ -57,17 +64,20 @@ public final class PhiInsn extends InsnNode {
@Override @Override
public boolean removeArg(InsnArg arg) { public boolean removeArg(InsnArg arg) {
if (!(arg instanceof RegisterArg)) { int index = getArgIndex(arg);
if (index == -1) {
return false; return false;
} }
RegisterArg reg = (RegisterArg) arg; removeArg(index);
if (super.removeArg(reg)) { return true;
blockBinds.remove(reg); }
reg.getSVar().removeUse(reg);
InsnRemover.fixUsedInPhiFlag(reg); @Override
return true; protected RegisterArg removeArg(int index) {
} RegisterArg reg = (RegisterArg) super.removeArg(index);
return false; blockBinds.remove(index);
InsnRemover.fixUsedInPhiFlag(reg);
return reg;
} }
@Override @Override
...@@ -75,21 +85,31 @@ public final class PhiInsn extends InsnNode { ...@@ -75,21 +85,31 @@ public final class PhiInsn extends InsnNode {
if (!(from instanceof RegisterArg) || !(to instanceof RegisterArg)) { if (!(from instanceof RegisterArg) || !(to instanceof RegisterArg)) {
return false; return false;
} }
BlockNode pred = getBlockByArg((RegisterArg) from);
int argIndex = getArgIndex(from);
if (argIndex == -1) {
return false;
}
BlockNode pred = getBlockByArgIndex(argIndex);
if (pred == null) { if (pred == null) {
throw new JadxRuntimeException("Unknown predecessor block by arg " + from + " in PHI: " + this); throw new JadxRuntimeException("Unknown predecessor block by arg " + from + " in PHI: " + this);
} }
if (removeArg(from)) { removeArg(argIndex);
RegisterArg reg = (RegisterArg) to;
bindArg(reg, pred); RegisterArg reg = (RegisterArg) to;
reg.getSVar().setUsedInPhi(this); bindArg(reg, pred);
} reg.getSVar().setUsedInPhi(this);
return true; return true;
} }
@Override @Override
public void addArg(InsnArg arg) {
throw new JadxRuntimeException("Direct addArg is forbidden for PHI insn, bindArg must be used");
}
@Override
public void setArg(int n, InsnArg arg) { public void setArg(int n, InsnArg arg) {
throw new JadxRuntimeException("Unsupported operation for PHI node"); throw new JadxRuntimeException("Direct setArg is forbidden for PHI insn, bindArg must be used");
} }
@Override @Override
......
...@@ -139,15 +139,29 @@ public class InsnNode extends LineAttrNode { ...@@ -139,15 +139,29 @@ public class InsnNode extends LineAttrNode {
} }
protected boolean removeArg(InsnArg arg) { protected boolean removeArg(InsnArg arg) {
int index = getArgIndex(arg);
if (index == -1) {
return false;
}
removeArg(index);
return true;
}
protected InsnArg removeArg(int index) {
InsnArg arg = arguments.get(index);
arguments.remove(index);
InsnRemover.unbindArgUsage(null, arg);
return arg;
}
protected int getArgIndex(InsnArg arg) {
int count = getArgsCount(); int count = getArgsCount();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (arg == arguments.get(i)) { if (arg == arguments.get(i)) {
arguments.remove(i); return i;
InsnRemover.unbindArgUsage(null, arg);
return true;
} }
} }
return false; return -1;
} }
protected void addReg(DecodedInstruction insn, int i, ArgType type) { protected void addReg(DecodedInstruction insn, int i, ArgType type) {
......
...@@ -3,7 +3,6 @@ package jadx.core.dex.visitors.typeinference; ...@@ -3,7 +3,6 @@ package jadx.core.dex.visitors.typeinference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
...@@ -318,10 +317,12 @@ public final class TypeInferenceVisitor extends AbstractVisitor { ...@@ -318,10 +317,12 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
return false; return false;
} }
} }
for (Map.Entry<RegisterArg, BlockNode> entry : phiInsn.getBlockBinds().entrySet()) {
RegisterArg reg = entry.getKey(); int argsCount = phiInsn.getArgsCount();
for (int argIndex = 0; argIndex < argsCount; argIndex++) {
RegisterArg reg = phiInsn.getArg(argIndex);
if (reg.getSVar() == var) { if (reg.getSVar() == var) {
BlockNode blockNode = entry.getValue(); BlockNode blockNode = phiInsn.getBlockByArgIndex(argIndex);
InsnNode lastInsn = BlockUtils.getLastInsn(blockNode); InsnNode lastInsn = BlockUtils.getLastInsn(blockNode);
if (lastInsn != null && BlockSplitter.makeSeparate(lastInsn.getType())) { if (lastInsn != null && BlockSplitter.makeSeparate(lastInsn.getType())) {
if (Consts.DEBUG) { if (Consts.DEBUG) {
......
...@@ -162,9 +162,6 @@ public class DebugUtils { ...@@ -162,9 +162,6 @@ public class DebugUtils {
if (insn.getType() == InsnType.PHI) { if (insn.getType() == InsnType.PHI) {
PhiInsn phi = (PhiInsn) insn; PhiInsn phi = (PhiInsn) insn;
phis.add(phi); phis.add(phi);
if (phi.getArgsCount() != phi.getBlockBinds().size()) {
throw new JadxRuntimeException("Incorrect args and binds in PHI");
}
if (phi.getArgsCount() == 0) { if (phi.getArgsCount() == 0) {
throw new JadxRuntimeException("No args and binds in PHI"); throw new JadxRuntimeException("No args and binds in PHI");
} }
......
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