Commit d55969bc authored by Skylot's avatar Skylot

core: fix some 'try/catch/finally' cases

parent 99768940
...@@ -264,8 +264,10 @@ public class ClassGen { ...@@ -264,8 +264,10 @@ public class ClassGen {
try { try {
addMethod(code, mth); addMethod(code, mth);
} catch (Exception e) { } catch (Exception e) {
String msg = ErrorsCounter.methodError(mth, "Method generation error", e); code.newLine().add("/*");
code.startLine("/* " + msg + CodeWriter.NL + Utils.getStackTrace(e) + " */"); code.newLine().add(ErrorsCounter.methodError(mth, "Method generation error", e));
code.newLine().add(Utils.getStackTrace(e));
code.newLine().add("*/");
} }
} }
} }
......
...@@ -510,7 +510,18 @@ public class InsnGen { ...@@ -510,7 +510,18 @@ public class InsnGen {
case NEW_INSTANCE: case NEW_INSTANCE:
// only fallback - make new instance in constructor invoke // only fallback - make new instance in constructor invoke
fallbackOnlyInsn(insn); fallbackOnlyInsn(insn);
code.add("new " + insn.getResult().getType()); code.add("new ").add(insn.getResult().getType().toString());
break;
case PHI:
case MERGE:
fallbackOnlyInsn(insn);
code.add(insn.getType().toString()).add("(");
for (InsnArg insnArg : insn.getArguments()) {
addArg(code, insnArg);
code.add(' ');
}
code.add(")");
break; break;
default: default:
......
...@@ -167,7 +167,7 @@ public class MethodGen { ...@@ -167,7 +167,7 @@ public class MethodGen {
if (cause != null) { if (cause != null) {
code.newLine(); code.newLine();
code.add("/*"); code.add("/*");
code.startLine("Error: ").add(Utils.getStackTrace(cause)); code.newLine().add("Error: ").add(Utils.getStackTrace(cause));
code.add("*/"); code.add("*/");
} }
} }
......
...@@ -65,6 +65,9 @@ public enum InsnType { ...@@ -65,6 +65,9 @@ public enum InsnType {
ONE_ARG, ONE_ARG,
PHI, PHI,
// merge all arguments in one
MERGE,
// TODO: now multidimensional arrays created using Array.newInstance function // TODO: now multidimensional arrays created using Array.newInstance function
NEW_MULTIDIM_ARRAY NEW_MULTIDIM_ARRAY
} }
...@@ -77,8 +77,14 @@ public class RegisterArg extends InsnArg implements Named { ...@@ -77,8 +77,14 @@ public class RegisterArg extends InsnArg implements Named {
} }
public RegisterArg duplicate() { public RegisterArg duplicate() {
RegisterArg dup = new RegisterArg(getRegNum(), getType()); return duplicate(getRegNum(), sVar);
}
public RegisterArg duplicate(int regNum, SSAVar sVar) {
RegisterArg dup = new RegisterArg(regNum, getType());
if (sVar != null) {
dup.setSVar(sVar); dup.setSVar(sVar);
}
dup.copyAttributesFrom(this); dup.copyAttributesFrom(this);
return dup; return dup;
} }
......
...@@ -554,9 +554,8 @@ public class MethodNode extends LineAttrNode implements ILoadable { ...@@ -554,9 +554,8 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return debugInfoOffset; return debugInfoOffset;
} }
public SSAVar makeNewSVar(int regNum, int[] versions, @NotNull RegisterArg arg) { public SSAVar makeNewSVar(int regNum, int version, @NotNull RegisterArg assignArg) {
SSAVar var = new SSAVar(regNum, versions[regNum], arg); SSAVar var = new SSAVar(regNum, version, assignArg);
versions[regNum]++;
if (sVars.isEmpty()) { if (sVars.isEmpty()) {
sVars = new ArrayList<SSAVar>(); sVars = new ArrayList<SSAVar>();
} }
...@@ -564,6 +563,17 @@ public class MethodNode extends LineAttrNode implements ILoadable { ...@@ -564,6 +563,17 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return var; return var;
} }
public int getNextSVarVersion(int regNum) {
int v = -1;
for (SSAVar sVar : sVars) {
if (sVar.getRegNum() == regNum) {
v = Math.max(v, sVar.getVersion());
}
}
v++;
return v;
}
public void removeSVar(SSAVar var) { public void removeSVar(SSAVar var) {
sVars.remove(var); sVars.remove(var);
} }
......
...@@ -103,7 +103,9 @@ public class ConstInlineVisitor extends AbstractVisitor { ...@@ -103,7 +103,9 @@ public class ConstInlineVisitor extends AbstractVisitor {
int replaceCount = 0; int replaceCount = 0;
for (RegisterArg arg : use) { for (RegisterArg arg : use) {
InsnNode useInsn = arg.getParentInsn(); InsnNode useInsn = arg.getParentInsn();
if (useInsn == null || useInsn.getType() == InsnType.PHI) { if (useInsn == null
|| useInsn.getType() == InsnType.PHI
|| useInsn.getType() == InsnType.MERGE) {
continue; continue;
} }
LiteralArg litArg; LiteralArg litArg;
......
...@@ -162,7 +162,7 @@ public class BlockFinallyExtract extends AbstractVisitor { ...@@ -162,7 +162,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
return false; return false;
} }
/* 'finally' extract confirmed, run remove steps */ // 'finally' extract confirmed, run remove steps
LiveVarAnalysis laBefore = null; LiveVarAnalysis laBefore = null;
boolean runReMap = isReMapNeeded(removes); boolean runReMap = isReMapNeeded(removes);
...@@ -191,7 +191,7 @@ public class BlockFinallyExtract extends AbstractVisitor { ...@@ -191,7 +191,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
RegisterArg resArg = me.getResult(); RegisterArg resArg = me.getResult();
BlockNode succ = handlerBlock.getCleanSuccessors().get(0); BlockNode succ = handlerBlock.getCleanSuccessors().get(0);
if (laAfter.isLive(succ.getId(), resArg.getRegNum())) { if (laAfter.isLive(succ, resArg.getRegNum())) {
// kill variable // kill variable
InsnNode kill = new InsnNode(InsnType.NOP, 0); InsnNode kill = new InsnNode(InsnType.NOP, 0);
kill.setResult(resArg); kill.setResult(resArg);
...@@ -224,34 +224,59 @@ public class BlockFinallyExtract extends AbstractVisitor { ...@@ -224,34 +224,59 @@ public class BlockFinallyExtract extends AbstractVisitor {
BitSet processed = new BitSet(mth.getRegsCount()); BitSet processed = new BitSet(mth.getRegsCount());
for (BlocksRemoveInfo removeInfo : removes) { for (BlocksRemoveInfo removeInfo : removes) {
processed.clear(); processed.clear();
BlockNode insertBlock = removeInfo.getStart().getSecond(); BlocksPair start = removeInfo.getStart();
BlockNode insertBlockBefore = start.getFirst();
BlockNode insertBlock = start.getSecond();
if (removeInfo.getRegMap().isEmpty() || insertBlock == null) { if (removeInfo.getRegMap().isEmpty() || insertBlock == null) {
continue; continue;
} }
for (Map.Entry<RegisterArg, RegisterArg> entry : removeInfo.getRegMap().entrySet()) { for (Map.Entry<RegisterArg, RegisterArg> entry : removeInfo.getRegMap().entrySet()) {
RegisterArg from = entry.getKey(); RegisterArg fromReg = entry.getKey();
int regNum = from.getRegNum(); RegisterArg toReg = entry.getValue();
if (!processed.get(regNum)) { int fromRegNum = fromReg.getRegNum();
if (laBefore.isLive(insertBlock.getId(), regNum)) { int toRegNum = toReg.getRegNum();
if (!processed.get(fromRegNum)) {
boolean liveFromBefore = laBefore.isLive(insertBlockBefore, fromRegNum);
boolean liveFromAfter = laAfter.isLive(insertBlock, fromRegNum);
// boolean liveToBefore = laBefore.isLive(insertBlock, toRegNum);
boolean liveToAfter = laAfter.isLive(insertBlock, toRegNum);
if (liveToAfter && liveFromBefore) {
// merge 'to' and 'from' registers
InsnNode merge = new InsnNode(InsnType.MERGE, 2);
merge.setResult(toReg.duplicate());
merge.addArg(toReg.duplicate());
merge.addArg(fromReg.duplicate());
injectInsn(mth, insertBlock, merge);
} else if (liveFromBefore) {
// remap variable // remap variable
RegisterArg to = entry.getValue();
InsnNode move = new InsnNode(InsnType.MOVE, 1); InsnNode move = new InsnNode(InsnType.MOVE, 1);
move.setResult(to); move.setResult(toReg.duplicate());
move.addArg(from); move.addArg(fromReg.duplicate());
insertBlock.getInstructions().add(move); injectInsn(mth, insertBlock, move);
} else if (laAfter.isLive(insertBlock.getId(), regNum)) { } else if (liveFromAfter) {
// kill variable // kill variable
InsnNode kill = new InsnNode(InsnType.NOP, 0); InsnNode kill = new InsnNode(InsnType.NOP, 0);
kill.setResult(from); kill.setResult(fromReg.duplicate());
kill.add(AFlag.REMOVE); kill.add(AFlag.REMOVE);
insertBlock.getInstructions().add(0, kill); injectInsn(mth, insertBlock, kill);
} }
processed.set(regNum); processed.set(fromRegNum);
} }
} }
} }
} }
private static void injectInsn(MethodNode mth, BlockNode insertBlock, InsnNode insn) {
insn.add(AFlag.SYNTHETIC);
if (insertBlock.getInstructions().isEmpty()) {
insertBlock.getInstructions().add(insn);
} else {
BlockNode succBlock = splitBlock(mth, insertBlock, 0);
BlockNode predBlock = succBlock.getPredecessors().get(0);
predBlock.getInstructions().add(insn);
}
}
private static boolean isReMapNeeded(List<BlocksRemoveInfo> removes) { private static boolean isReMapNeeded(List<BlocksRemoveInfo> removes) {
for (BlocksRemoveInfo removeInfo : removes) { for (BlocksRemoveInfo removeInfo : removes) {
if (!removeInfo.getRegMap().isEmpty()) { if (!removeInfo.getRegMap().isEmpty()) {
...@@ -270,12 +295,42 @@ public class BlockFinallyExtract extends AbstractVisitor { ...@@ -270,12 +295,42 @@ public class BlockFinallyExtract extends AbstractVisitor {
if (removeInfo == null) { if (removeInfo == null) {
return null; return null;
} }
if (removeInfo.getOuts().size() != 1) { Set<BlocksPair> outs = removeInfo.getOuts();
LOG.debug("Unexpected finally block outs count: {}", removeInfo.getOuts()); if (outs.size() == 1) {
return null; return removeInfo;
} }
// check if several 'return' blocks maps to one out
if (mergeReturns(mth, outs)) {
return removeInfo; return removeInfo;
} }
LOG.debug("Unexpected finally block outs count: {}", outs);
return null;
}
private static boolean mergeReturns(MethodNode mth, Set<BlocksPair> outs) {
Set<BlockNode> rightOuts = new HashSet<BlockNode>();
boolean allReturns = true;
for (BlocksPair outPair : outs) {
BlockNode first = outPair.getFirst();
if (!first.isReturnBlock()) {
allReturns = false;
}
rightOuts.add(outPair.getSecond());
}
if (!allReturns || rightOuts.size() != 1) {
return false;
}
Iterator<BlocksPair> it = outs.iterator();
while (it.hasNext()) {
BlocksPair out = it.next();
BlockNode returnBlock = out.getFirst();
if (!returnBlock.contains(AFlag.ORIG_RETURN)) {
markForRemove(mth, returnBlock);
it.remove();
}
}
return true;
}
private static BlocksRemoveInfo checkFromFirstBlock(BlockNode remBlock, BlockNode startBlock, BitSet bs) { private static BlocksRemoveInfo checkFromFirstBlock(BlockNode remBlock, BlockNode startBlock, BitSet bs) {
BlocksRemoveInfo removeInfo = isStartBlock(remBlock, startBlock); BlocksRemoveInfo removeInfo = isStartBlock(remBlock, startBlock);
...@@ -453,7 +508,7 @@ public class BlockFinallyExtract extends AbstractVisitor { ...@@ -453,7 +508,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
// change start block in removeInfo // change start block in removeInfo
removeInfo.getProcessed().remove(removeInfo.getStart()); removeInfo.getProcessed().remove(removeInfo.getStart());
BlocksPair newStart = new BlocksPair(remBlock, startBlock); BlocksPair newStart = new BlocksPair(remBlock, startBlock);
removeInfo.setStart(newStart); // removeInfo.setStart(newStart);
removeInfo.getProcessed().add(newStart); removeInfo.getProcessed().add(newStart);
} }
// split end block // split end block
...@@ -529,6 +584,11 @@ public class BlockFinallyExtract extends AbstractVisitor { ...@@ -529,6 +584,11 @@ public class BlockFinallyExtract extends AbstractVisitor {
return true; return true;
} }
/**
* Split one block into connected 2 blocks with same connections.
*
* @return new successor block
*/
private static BlockNode splitBlock(MethodNode mth, BlockNode block, int splitIndex) { private static BlockNode splitBlock(MethodNode mth, BlockNode block, int splitIndex) {
BlockNode newBlock = BlockSplitter.startNewBlock(mth, -1); BlockNode newBlock = BlockSplitter.startNewBlock(mth, -1);
...@@ -654,6 +714,53 @@ public class BlockFinallyExtract extends AbstractVisitor { ...@@ -654,6 +714,53 @@ public class BlockFinallyExtract extends AbstractVisitor {
markForRemove(mth, mb); markForRemove(mth, mb);
edgeAttr.getBlocks().remove(mb); edgeAttr.getBlocks().remove(mb);
} }
mergeSyntheticPredecessors(mth, origReturnBlock);
}
private static void mergeSyntheticPredecessors(MethodNode mth, BlockNode block) {
List<BlockNode> preds = new ArrayList<BlockNode>(block.getPredecessors());
Iterator<BlockNode> it = preds.iterator();
while (it.hasNext()) {
BlockNode predBlock = it.next();
if (!predBlock.isSynthetic()) {
it.remove();
}
}
if (preds.size() < 2) {
return;
}
BlockNode commonBlock = null;
for (BlockNode predBlock : preds) {
List<BlockNode> successors = predBlock.getSuccessors();
if (successors.size() != 2) {
return;
}
BlockNode cmnBlk = BlockUtils.selectOtherSafe(block, successors);
if (commonBlock == null) {
commonBlock = cmnBlk;
} else if (cmnBlk != commonBlock) {
return;
}
if (!predBlock.contains(AType.IGNORE_EDGE)) {
return;
}
}
if (commonBlock == null) {
return;
}
// merge confirmed
BlockNode mergeBlock = null;
for (BlockNode predBlock : preds) {
if (mergeBlock == null) {
mergeBlock = predBlock;
continue;
}
for (BlockNode remPred : predBlock.getPredecessors()) {
connect(remPred, mergeBlock);
}
markForRemove(mth, predBlock);
}
} }
private static BlockNode getFinallyOutBlock(List<BlockNode> exitBlocks) { private static BlockNode getFinallyOutBlock(List<BlockNode> exitBlocks) {
......
...@@ -24,7 +24,7 @@ import org.slf4j.Logger; ...@@ -24,7 +24,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static jadx.core.dex.visitors.regions.RegionMaker.isEqualPaths; import static jadx.core.dex.visitors.regions.RegionMaker.isEqualPaths;
import static jadx.core.dex.visitors.regions.RegionMaker.isReturnBlocks; import static jadx.core.dex.visitors.regions.RegionMaker.isEqualReturnBlocks;
import static jadx.core.utils.BlockUtils.getNextBlock; import static jadx.core.utils.BlockUtils.getNextBlock;
import static jadx.core.utils.BlockUtils.isPathExists; import static jadx.core.utils.BlockUtils.isPathExists;
...@@ -277,7 +277,7 @@ public class IfMakerHelper { ...@@ -277,7 +277,7 @@ public class IfMakerHelper {
} }
private static boolean isSameBlocks(BlockNode first, BlockNode second) { private static boolean isSameBlocks(BlockNode first, BlockNode second) {
return first == second || isReturnBlocks(first, second); return first == second || isEqualReturnBlocks(first, second);
} }
static void confirmMerge(IfInfo info) { static void confirmMerge(IfInfo info) {
......
...@@ -256,17 +256,17 @@ public class ProcessVariables extends AbstractVisitor { ...@@ -256,17 +256,17 @@ public class ProcessVariables extends AbstractVisitor {
continue; continue;
} }
IRegion parent = region; IRegion parent = region;
boolean declare = false; boolean declared = false;
while (parent != null) { while (parent != null) {
if (canDeclareInRegion(u, region, regionsOrder)) { if (canDeclareInRegion(u, region, regionsOrder)) {
declareVar(region, u.getArg()); declareVar(region, u.getArg());
declare = true; declared = true;
break; break;
} }
region = parent; region = parent;
parent = region.getParent(); parent = region.getParent();
} }
if (!declare) { if (!declared) {
declareVar(mth.getRegion(), u.getArg()); declareVar(mth.getRegion(), u.getArg());
} }
} }
......
...@@ -12,6 +12,8 @@ import jadx.core.dex.instructions.SwitchNode; ...@@ -12,6 +12,8 @@ import jadx.core.dex.instructions.SwitchNode;
import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.Edge; import jadx.core.dex.nodes.Edge;
import jadx.core.dex.nodes.IBlock;
import jadx.core.dex.nodes.IContainer;
import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
...@@ -899,7 +901,7 @@ public class RegionMaker { ...@@ -899,7 +901,7 @@ public class RegionMaker {
} }
} }
public void processTryCatchBlocks(MethodNode mth) { public IRegion processTryCatchBlocks(MethodNode mth) {
Set<TryCatchBlock> tcs = new HashSet<TryCatchBlock>(); Set<TryCatchBlock> tcs = new HashSet<TryCatchBlock>();
for (ExceptionHandler handler : mth.getExceptionHandlers()) { for (ExceptionHandler handler : mth.getExceptionHandlers()) {
tcs.add(handler.getTryBlock()); tcs.add(handler.getTryBlock());
...@@ -935,6 +937,40 @@ public class RegionMaker { ...@@ -935,6 +937,40 @@ public class RegionMaker {
processExcHandler(handler, exits); processExcHandler(handler, exits);
} }
} }
return processHandlersOutBlocks(mth, tcs);
}
/**
* Search handlers successor blocks not included in any region.
*/
protected IRegion processHandlersOutBlocks(MethodNode mth, Set<TryCatchBlock> tcs) {
Set<IBlock> allRegionBlocks = new HashSet<IBlock>();
RegionUtils.getAllRegionBlocks(mth.getRegion(), allRegionBlocks);
Set<IBlock> succBlocks = new HashSet<IBlock>();
for (TryCatchBlock tc : tcs) {
for (ExceptionHandler handler : tc.getHandlers()) {
IContainer region = handler.getHandlerRegion();
if (region != null) {
IBlock lastBlock = RegionUtils.getLastBlock(region);
if (lastBlock instanceof BlockNode) {
succBlocks.addAll(((BlockNode) lastBlock).getSuccessors());
}
RegionUtils.getAllRegionBlocks(region, allRegionBlocks);
}
}
}
succBlocks.removeAll(allRegionBlocks);
if (succBlocks.isEmpty()) {
return null;
}
Region excOutRegion = new Region(mth.getRegion());
for (IBlock block : succBlocks) {
if (block instanceof BlockNode) {
excOutRegion.add(makeRegion((BlockNode) block, new RegionStack(mth)));
}
}
return excOutRegion;
} }
private void processExcHandler(ExceptionHandler handler, Set<BlockNode> exits) { private void processExcHandler(ExceptionHandler handler, Set<BlockNode> exits) {
...@@ -980,7 +1016,7 @@ public class RegionMaker { ...@@ -980,7 +1016,7 @@ public class RegionMaker {
if (b1 == null || b2 == null) { if (b1 == null || b2 == null) {
return false; return false;
} }
return isReturnBlocks(b1, b2) || isSyntheticPath(b1, b2); return isEqualReturnBlocks(b1, b2) || isSyntheticPath(b1, b2);
} }
private static boolean isSyntheticPath(BlockNode b1, BlockNode b2) { private static boolean isSyntheticPath(BlockNode b1, BlockNode b2) {
...@@ -989,7 +1025,7 @@ public class RegionMaker { ...@@ -989,7 +1025,7 @@ public class RegionMaker {
return (n1 != b1 || n2 != b2) && isEqualPaths(n1, n2); return (n1 != b1 || n2 != b2) && isEqualPaths(n1, n2);
} }
public static boolean isReturnBlocks(BlockNode b1, BlockNode b2) { public static boolean isEqualReturnBlocks(BlockNode b1, BlockNode b2) {
if (!b1.isReturnBlock() || !b2.isReturnBlock()) { if (!b1.isReturnBlock() || !b2.isReturnBlock()) {
return false; return false;
} }
......
...@@ -49,7 +49,10 @@ public class RegionMakerVisitor extends AbstractVisitor { ...@@ -49,7 +49,10 @@ public class RegionMakerVisitor extends AbstractVisitor {
mth.setRegion(rm.makeRegion(mth.getEnterBlock(), state)); mth.setRegion(rm.makeRegion(mth.getEnterBlock(), state));
if (!mth.isNoExceptionHandlers()) { if (!mth.isNoExceptionHandlers()) {
rm.processTryCatchBlocks(mth); IRegion expOutBlock = rm.processTryCatchBlocks(mth);
if (expOutBlock != null) {
mth.getRegion().add(expOutBlock);
}
} }
postProcessRegions(mth); postProcessRegions(mth);
......
...@@ -2,12 +2,17 @@ package jadx.core.dex.visitors.ssa; ...@@ -2,12 +2,17 @@ package jadx.core.dex.visitors.ssa;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.PhiListAttr; import jadx.core.dex.attributes.nodes.PhiListAttr;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.PhiInsn; import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar;
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.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.BlockUtils;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.exceptions.JadxRuntimeException;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
...@@ -23,6 +28,7 @@ public class EliminatePhiNodes extends AbstractVisitor { ...@@ -23,6 +28,7 @@ public class EliminatePhiNodes extends AbstractVisitor {
if (mth.isNoCode()) { if (mth.isNoCode()) {
return; return;
} }
replaceMergeInstructions(mth);
removePhiInstructions(mth); removePhiInstructions(mth);
} }
...@@ -50,4 +56,75 @@ public class EliminatePhiNodes extends AbstractVisitor { ...@@ -50,4 +56,75 @@ public class EliminatePhiNodes extends AbstractVisitor {
} }
LOG.warn("Phi node not removed: {}, mth: {}", phiInsn, mth); LOG.warn("Phi node not removed: {}, mth: {}", phiInsn, mth);
} }
private void replaceMergeInstructions(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
List<InsnNode> insns = block.getInstructions();
if (insns.isEmpty()) {
continue;
}
InsnNode insn = insns.get(0);
if (insn.getType() == InsnType.MERGE) {
replaceMerge(mth, block, insn);
}
}
}
/**
* Replace 'MERGE' with 'PHI' insn.
*/
private void replaceMerge(MethodNode mth, BlockNode block, InsnNode insn) {
if (insn.getArgsCount() != 2) {
throw new JadxRuntimeException("Unexpected count of arguments in merge insn: " + insn);
}
RegisterArg oldArg = (RegisterArg) insn.getArg(1);
RegisterArg newArg = (RegisterArg) insn.getArg(0);
int newRegNum = newArg.getRegNum();
if (oldArg.getRegNum() == newRegNum) {
throw new JadxRuntimeException("Unexpected register number in merge insn: " + insn);
}
SSAVar oldSVar = oldArg.getSVar();
RegisterArg assignArg = oldSVar.getAssign();
InsnNode assignParentInsn = assignArg.getParentInsn();
BlockNode assignBlock = BlockUtils.getBlockByInsn(mth, assignParentInsn);
if (assignBlock == null) {
throw new JadxRuntimeException("Unknown assign block for " + assignParentInsn);
}
BlockNode assignPred = null;
for (BlockNode pred : block.getPredecessors()) {
if (BlockUtils.isPathExists(assignBlock, pred)) {
assignPred = pred;
break;
}
}
if (assignPred == null) {
throw new JadxRuntimeException("Assign predecessor not found for " + assignBlock + " from " + block);
}
// all checks passed
RegisterArg newAssignArg = oldArg.duplicate(newRegNum, null);
SSAVar newSVar = mth.makeNewSVar(newRegNum, mth.getNextSVarVersion(newRegNum), newAssignArg);
newSVar.setName(oldSVar.getName());
newSVar.setType(assignArg.getType());
if (assignParentInsn != null) {
assignParentInsn.setResult(newAssignArg);
}
for (RegisterArg useArg : oldSVar.getUseList()) {
RegisterArg newUseArg = useArg.duplicate(newRegNum, newSVar);
InsnNode parentInsn = useArg.getParentInsn();
if (parentInsn != null) {
newSVar.use(newUseArg);
parentInsn.replaceArg(useArg, newUseArg);
}
}
block.getInstructions().remove(0);
PhiInsn phiInsn = SSATransform.addPhi(mth, block, newRegNum);
phiInsn.setResult(insn.getResult());
phiInsn.bindArg(newAssignArg.duplicate(), assignPred);
phiInsn.bindArg(newArg.duplicate(),
BlockUtils.selectOtherSafe(assignPred, block.getPredecessors()));
}
} }
...@@ -10,7 +10,12 @@ import jadx.core.utils.exceptions.JadxRuntimeException; ...@@ -10,7 +10,12 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
import java.util.BitSet; import java.util.BitSet;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LiveVarAnalysis { public class LiveVarAnalysis {
private static final Logger LOG = LoggerFactory.getLogger(LiveVarAnalysis.class);
private final MethodNode mth; private final MethodNode mth;
private BitSet[] uses; private BitSet[] uses;
...@@ -37,9 +42,17 @@ public class LiveVarAnalysis { ...@@ -37,9 +42,17 @@ public class LiveVarAnalysis {
} }
public boolean isLive(int blockId, int regNum) { public boolean isLive(int blockId, int regNum) {
if (blockId >= liveIn.length) {
LOG.warn("LiveVarAnalysis: out of bounds block: {}, max: {}", blockId, liveIn.length);
return false;
}
return liveIn[blockId].get(regNum); return liveIn[blockId].get(regNum);
} }
public boolean isLive(BlockNode block, int regNum) {
return isLive(block.getId(), regNum);
}
private void fillBasicBlockInfo() { private void fillBasicBlockInfo() {
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : mth.getBasicBlocks()) {
int blockId = block.getId(); int blockId = block.getId();
......
...@@ -93,7 +93,7 @@ public class SSATransform extends AbstractVisitor { ...@@ -93,7 +93,7 @@ public class SSATransform extends AbstractVisitor {
} }
} }
private static void addPhi(MethodNode mth, BlockNode block, int regNum) { public static PhiInsn addPhi(MethodNode mth, BlockNode block, int regNum) {
PhiListAttr phiList = block.get(AType.PHI_LIST); PhiListAttr phiList = block.get(AType.PHI_LIST);
if (phiList == null) { if (phiList == null) {
phiList = new PhiListAttr(); phiList = new PhiListAttr();
...@@ -112,6 +112,7 @@ public class SSATransform extends AbstractVisitor { ...@@ -112,6 +112,7 @@ public class SSATransform extends AbstractVisitor {
phiList.getList().add(phiInsn); phiList.getList().add(phiInsn);
phiInsn.setOffset(block.getStartOffset()); phiInsn.setOffset(block.getStartOffset());
block.getInstructions().add(0, phiInsn); block.getInstructions().add(0, phiInsn);
return phiInsn;
} }
private static void renameVariables(MethodNode mth) { private static void renameVariables(MethodNode mth) {
...@@ -124,13 +125,18 @@ public class SSATransform extends AbstractVisitor { ...@@ -124,13 +125,18 @@ public class SSATransform extends AbstractVisitor {
// init method arguments // init method arguments
for (RegisterArg arg : mth.getArguments(true)) { for (RegisterArg arg : mth.getArguments(true)) {
int regNum = arg.getRegNum(); int regNum = arg.getRegNum();
vars[regNum] = mth.makeNewSVar(regNum, versions, arg); vars[regNum] = newSSAVar(mth, versions, arg, regNum);
} }
BlockNode enterBlock = mth.getEnterBlock(); BlockNode enterBlock = mth.getEnterBlock();
initPhiInEnterBlock(vars, enterBlock); initPhiInEnterBlock(vars, enterBlock);
renameVar(mth, vars, versions, enterBlock); renameVar(mth, vars, versions, enterBlock);
} }
private static SSAVar newSSAVar(MethodNode mth, int[] versions, RegisterArg arg, int regNum) {
int version = versions[regNum]++;
return mth.makeNewSVar(regNum, version, arg);
}
private static void initPhiInEnterBlock(SSAVar[] vars, BlockNode enterBlock) { private static void initPhiInEnterBlock(SSAVar[] vars, BlockNode enterBlock) {
PhiListAttr phiList = enterBlock.get(AType.PHI_LIST); PhiListAttr phiList = enterBlock.get(AType.PHI_LIST);
if (phiList != null) { if (phiList != null) {
...@@ -168,7 +174,7 @@ public class SSATransform extends AbstractVisitor { ...@@ -168,7 +174,7 @@ public class SSATransform extends AbstractVisitor {
RegisterArg result = insn.getResult(); RegisterArg result = insn.getResult();
if (result != null) { if (result != null) {
int regNum = result.getRegNum(); int regNum = result.getRegNum();
vars[regNum] = mth.makeNewSVar(regNum, vers, result); vars[regNum] = newSSAVar(mth, vers, result, regNum);
} }
} }
for (BlockNode s : block.getSuccessors()) { for (BlockNode s : block.getSuccessors()) {
......
...@@ -3,7 +3,6 @@ package jadx.core.dex.visitors.typeinference; ...@@ -3,7 +3,6 @@ package jadx.core.dex.visitors.typeinference;
import jadx.core.dex.info.MethodInfo; import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.IndexInsnNode;
import jadx.core.dex.instructions.InvokeNode; import jadx.core.dex.instructions.InvokeNode;
import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.LiteralArg; import jadx.core.dex.instructions.args.LiteralArg;
...@@ -101,11 +100,11 @@ public class PostTypeInference { ...@@ -101,11 +100,11 @@ public class PostTypeInference {
return true; return true;
} }
case PHI: { case PHI:
PhiInsn phi = (PhiInsn) insn; case MERGE: {
ArgType type = phi.getResult().getType(); ArgType type = insn.getResult().getType();
if (!type.isTypeKnown()) { if (!type.isTypeKnown()) {
for (InsnArg arg : phi.getArguments()) { for (InsnArg arg : insn.getArguments()) {
if (arg.getType().isTypeKnown()) { if (arg.getType().isTypeKnown()) {
type = arg.getType(); type = arg.getType();
break; break;
...@@ -113,11 +112,11 @@ public class PostTypeInference { ...@@ -113,11 +112,11 @@ public class PostTypeInference {
} }
} }
boolean changed = false; boolean changed = false;
if (updateType(phi.getResult(), type)) { if (updateType(insn.getResult(), type)) {
changed = true; changed = true;
} }
for (int i = 0; i < phi.getArgsCount(); i++) { for (int i = 0; i < insn.getArgsCount(); i++) {
RegisterArg arg = phi.getArg(i); RegisterArg arg = (RegisterArg) insn.getArg(i);
if (updateType(arg, type)) { if (updateType(arg, type)) {
changed = true; changed = true;
} }
......
...@@ -36,7 +36,11 @@ public class DebugUtils { ...@@ -36,7 +36,11 @@ public class DebugUtils {
private static final Logger LOG = LoggerFactory.getLogger(DebugUtils.class); private static final Logger LOG = LoggerFactory.getLogger(DebugUtils.class);
public static void dump(MethodNode mth) { public static void dump(MethodNode mth) {
File out = new File("test-graph-tmp"); dump(mth, "");
}
public static void dump(MethodNode mth, String desc) {
File out = new File("test-graph" + desc + "-tmp");
DotGraphVisitor.dump(out).visit(mth); DotGraphVisitor.dump(out).visit(mth);
DotGraphVisitor.dumpRaw(out).visit(mth); DotGraphVisitor.dumpRaw(out).visit(mth);
DotGraphVisitor.dumpRegions(out).visit(mth); DotGraphVisitor.dumpRegions(out).visit(mth);
......
...@@ -72,6 +72,22 @@ public class RegionUtils { ...@@ -72,6 +72,22 @@ public class RegionUtils {
} }
} }
public static IBlock getLastBlock(IContainer container) {
if (container instanceof IBlock) {
return (IBlock) container;
} else if (container instanceof IBranchRegion) {
return null;
} else if (container instanceof IRegion) {
List<IContainer> blocks = ((IRegion) container).getSubBlocks();
if (blocks.isEmpty()) {
return null;
}
return getLastBlock(blocks.get(blocks.size() - 1));
} else {
throw new JadxRuntimeException(unknownContainerType(container));
}
}
/** /**
* Return true if last block in region has no successors * Return true if last block in region has no successors
*/ */
......
package jadx.tests.integration.trycatch;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Test;
import static jadx.tests.api.utils.JadxMatchers.containsLines;
import static org.junit.Assert.assertThat;
public class TestTryCatchFinally6 extends IntegrationTest {
public static class TestCls {
public static void test() throws IOException {
InputStream is = null;
try {
is = new FileInputStream("1.txt");
} finally {
if (is != null) {
is.close();
}
}
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsLines(2,
"InputStream is = null;",
"try {",
indent(1) + "is = new FileInputStream(\"1.txt\");",
"} finally {",
indent(1) + "if (is != null) {",
indent(2) + "is.close();",
indent(1) + "}",
"}"
));
}
}
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