use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.
the class LoopRegionVisitor method checkArrayForEach.
private static LoopType checkArrayForEach(MethodNode mth, InsnNode initInsn, InsnNode incrInsn, IfCondition condition) {
if (!(incrInsn instanceof ArithNode)) {
return null;
}
ArithNode arithNode = (ArithNode) incrInsn;
if (arithNode.getOp() != ArithOp.ADD) {
return null;
}
InsnArg lit = incrInsn.getArg(1);
if (!lit.isLiteral() || ((LiteralArg) lit).getLiteral() != 1) {
return null;
}
if (initInsn.getType() != InsnType.CONST || !initInsn.getArg(0).isLiteral() || ((LiteralArg) initInsn.getArg(0)).getLiteral() != 0) {
return null;
}
InsnArg condArg = incrInsn.getArg(0);
if (!condArg.isRegister()) {
return null;
}
SSAVar sVar = ((RegisterArg) condArg).getSVar();
List<RegisterArg> args = sVar.getUseList();
if (args.size() != 3 || args.get(2) != condArg) {
return null;
}
condArg = args.get(0);
RegisterArg arrIndex = args.get(1);
InsnNode arrGetInsn = arrIndex.getParentInsn();
if (arrGetInsn == null || arrGetInsn.getType() != InsnType.AGET) {
return null;
}
if (!condition.isCompare()) {
return null;
}
Compare compare = condition.getCompare();
if (compare.getOp() != IfOp.LT || compare.getA() != condArg) {
return null;
}
InsnNode len;
InsnArg bCondArg = compare.getB();
if (bCondArg.isInsnWrap()) {
len = ((InsnWrapArg) bCondArg).getWrapInsn();
} else if (bCondArg.isRegister()) {
len = ((RegisterArg) bCondArg).getAssignInsn();
} else {
return null;
}
if (len == null || len.getType() != InsnType.ARRAY_LENGTH) {
return null;
}
InsnArg arrayArg = len.getArg(0);
if (!arrayArg.equals(arrGetInsn.getArg(0))) {
return null;
}
RegisterArg iterVar = arrGetInsn.getResult();
if (iterVar == null) {
return null;
}
// array for each loop confirmed
len.add(AFlag.SKIP);
arrGetInsn.add(AFlag.SKIP);
InstructionRemover.unbindInsn(mth, len);
// inline array variable
CodeShrinker.shrinkMethod(mth);
if (arrGetInsn.contains(AFlag.WRAPPED)) {
InsnArg wrapArg = BlockUtils.searchWrappedInsnParent(mth, arrGetInsn);
if (wrapArg != null && wrapArg.getParentInsn() != null) {
wrapArg.getParentInsn().replaceArg(wrapArg, iterVar);
} else {
LOG.debug(" checkArrayForEach: Wrapped insn not found: {}, mth: {}", arrGetInsn, mth);
}
}
return new ForEachLoop(iterVar, len.getArg(0));
}
use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.
the class RegionGen method makeLoop.
public void makeLoop(LoopRegion region, ICodeWriter code) throws CodegenException {
code.startLineWithNum(region.getSourceLine());
LoopLabelAttr labelAttr = region.getInfo().getStart().get(AType.LOOP_LABEL);
if (labelAttr != null) {
code.add(mgen.getNameGen().getLoopLabel(labelAttr)).add(": ");
}
IfCondition condition = region.getCondition();
if (condition == null) {
// infinite loop
code.add("while (true) {");
makeRegionIndent(code, region.getBody());
code.startLine('}');
return;
}
InsnNode condInsn = condition.getFirstInsn();
InsnCodeOffset.attach(code, condInsn);
ConditionGen conditionGen = new ConditionGen(this);
LoopType type = region.getType();
if (type != null) {
if (type instanceof ForLoop) {
ForLoop forLoop = (ForLoop) type;
code.add("for (");
makeInsn(forLoop.getInitInsn(), code, Flags.INLINE);
code.add("; ");
conditionGen.add(code, condition);
code.add("; ");
makeInsn(forLoop.getIncrInsn(), code, Flags.INLINE);
code.add(") {");
CodeGenUtils.addCodeComments(code, mth, condInsn);
makeRegionIndent(code, region.getBody());
code.startLine('}');
return;
}
if (type instanceof ForEachLoop) {
ForEachLoop forEachLoop = (ForEachLoop) type;
code.add("for (");
declareVar(code, forEachLoop.getVarArg());
code.add(" : ");
addArg(code, forEachLoop.getIterableArg(), false);
code.add(") {");
CodeGenUtils.addCodeComments(code, mth, condInsn);
makeRegionIndent(code, region.getBody());
code.startLine('}');
return;
}
throw new JadxRuntimeException("Unknown loop type: " + type.getClass());
}
if (region.isConditionAtEnd()) {
code.add("do {");
CodeGenUtils.addCodeComments(code, mth, condInsn);
makeRegionIndent(code, region.getBody());
code.startLineWithNum(region.getSourceLine());
code.add("} while (");
conditionGen.add(code, condition);
code.add(");");
} else {
code.add("while (");
conditionGen.add(code, condition);
code.add(") {");
CodeGenUtils.addCodeComments(code, mth, condInsn);
makeRegionIndent(code, region.getBody());
code.startLine('}');
}
}
use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.
the class LoopRegionVisitor method checkIterableForEach.
private static boolean checkIterableForEach(MethodNode mth, LoopRegion loopRegion, IfCondition condition) {
List<RegisterArg> condArgs = condition.getRegisterArgs();
if (condArgs.size() != 1) {
return false;
}
RegisterArg iteratorArg = condArgs.get(0);
SSAVar sVar = iteratorArg.getSVar();
if (sVar == null || sVar.isUsedInPhi()) {
return false;
}
List<RegisterArg> itUseList = sVar.getUseList();
InsnNode assignInsn = iteratorArg.getAssignInsn();
if (itUseList.size() != 2) {
return false;
}
if (!checkInvoke(assignInsn, null, "iterator()Ljava/util/Iterator;")) {
return false;
}
InsnArg iterableArg = assignInsn.getArg(0);
InsnNode hasNextCall = itUseList.get(0).getParentInsn();
InsnNode nextCall = itUseList.get(1).getParentInsn();
if (!checkInvoke(hasNextCall, "java.util.Iterator", "hasNext()Z") || !checkInvoke(nextCall, "java.util.Iterator", "next()Ljava/lang/Object;")) {
return false;
}
List<InsnNode> toSkip = new LinkedList<>();
RegisterArg iterVar;
if (nextCall.contains(AFlag.WRAPPED)) {
InsnArg wrapArg = BlockUtils.searchWrappedInsnParent(mth, nextCall);
if (wrapArg != null && wrapArg.getParentInsn() != null) {
InsnNode parentInsn = wrapArg.getParentInsn();
BlockNode block = BlockUtils.getBlockByInsn(mth, parentInsn);
if (block == null) {
return false;
}
if (!RegionUtils.isRegionContainsBlock(loopRegion, block)) {
return false;
}
if (parentInsn.getType() == InsnType.CHECK_CAST) {
iterVar = parentInsn.getResult();
if (iterVar == null || !fixIterableType(mth, iterableArg, iterVar)) {
return false;
}
InsnArg castArg = BlockUtils.searchWrappedInsnParent(mth, parentInsn);
if (castArg != null && castArg.getParentInsn() != null) {
castArg.getParentInsn().replaceArg(castArg, iterVar);
} else {
// cast not inlined
toSkip.add(parentInsn);
}
} else {
iterVar = nextCall.getResult();
if (iterVar == null) {
return false;
}
// restore variable from inlined insn
iterVar.remove(AFlag.REMOVE);
nextCall.add(AFlag.DONT_GENERATE);
if (!fixIterableType(mth, iterableArg, iterVar)) {
return false;
}
parentInsn.replaceArg(wrapArg, iterVar);
}
} else {
LOG.warn(" checkIterableForEach: Wrapped insn not found: {}, mth: {}", nextCall, mth);
return false;
}
} else {
iterVar = nextCall.getResult();
if (iterVar == null) {
return false;
}
if (!usedOnlyInLoop(mth, loopRegion, iterVar)) {
return false;
}
if (!assignOnlyInLoop(mth, loopRegion, iterVar)) {
return false;
}
toSkip.add(nextCall);
}
assignInsn.add(AFlag.DONT_GENERATE);
assignInsn.getResult().add(AFlag.DONT_GENERATE);
for (InsnNode insnNode : toSkip) {
insnNode.add(AFlag.DONT_GENERATE);
}
for (RegisterArg itArg : itUseList) {
itArg.add(AFlag.DONT_GENERATE);
}
ForEachLoop forEachLoop = new ForEachLoop(iterVar, iterableArg);
forEachLoop.injectFakeInsns(loopRegion);
loopRegion.setType(forEachLoop);
return true;
}
use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.
the class RegionGen method makeLoop.
private CodeWriter makeLoop(LoopRegion region, CodeWriter code) throws CodegenException {
BlockNode header = region.getHeader();
if (header != null) {
List<InsnNode> headerInsns = header.getInstructions();
if (headerInsns.size() > 1) {
ErrorsCounter.methodError(mth, "Found not inlined instructions from loop header");
int last = headerInsns.size() - 1;
for (int i = 0; i < last; i++) {
InsnNode insn = headerInsns.get(i);
makeInsn(insn, code);
}
}
}
LoopLabelAttr labelAttr = region.getInfo().getStart().get(AType.LOOP_LABEL);
if (labelAttr != null) {
code.startLine(mgen.getNameGen().getLoopLabel(labelAttr)).add(':');
}
IfCondition condition = region.getCondition();
if (condition == null) {
// infinite loop
code.startLine("while (true) {");
makeRegionIndent(code, region.getBody());
code.startLine('}');
return code;
}
ConditionGen conditionGen = new ConditionGen(this);
LoopType type = region.getType();
if (type != null) {
if (type instanceof ForLoop) {
ForLoop forLoop = (ForLoop) type;
code.startLine("for (");
makeInsn(forLoop.getInitInsn(), code, Flags.INLINE);
code.add("; ");
conditionGen.add(code, condition);
code.add("; ");
makeInsn(forLoop.getIncrInsn(), code, Flags.INLINE);
code.add(") {");
makeRegionIndent(code, region.getBody());
code.startLine('}');
return code;
}
if (type instanceof ForEachLoop) {
ForEachLoop forEachLoop = (ForEachLoop) type;
code.startLine("for (");
declareVar(code, forEachLoop.getVarArg());
code.add(" : ");
addArg(code, forEachLoop.getIterableArg(), false);
code.add(") {");
makeRegionIndent(code, region.getBody());
code.startLine('}');
return code;
}
throw new JadxRuntimeException("Unknown loop type: " + type.getClass());
}
if (region.isConditionAtEnd()) {
code.startLine("do {");
makeRegionIndent(code, region.getBody());
code.startLine("} while (");
conditionGen.add(code, condition);
code.add(");");
} else {
code.startLine("while (");
conditionGen.add(code, condition);
code.add(") {");
makeRegionIndent(code, region.getBody());
code.startLine('}');
}
return code;
}
use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.
the class LoopRegionVisitor method checkArrayForEach.
private static LoopType checkArrayForEach(MethodNode mth, LoopRegion loopRegion, InsnNode initInsn, InsnNode incrInsn, IfCondition condition) {
if (!(incrInsn instanceof ArithNode)) {
return null;
}
ArithNode arithNode = (ArithNode) incrInsn;
if (arithNode.getOp() != ArithOp.ADD) {
return null;
}
InsnArg lit = incrInsn.getArg(1);
if (!lit.isLiteral() || ((LiteralArg) lit).getLiteral() != 1) {
return null;
}
if (initInsn.getType() != InsnType.CONST || !initInsn.getArg(0).isLiteral() || ((LiteralArg) initInsn.getArg(0)).getLiteral() != 0) {
return null;
}
InsnArg condArg = incrInsn.getArg(0);
if (!condArg.isRegister()) {
return null;
}
SSAVar sVar = ((RegisterArg) condArg).getSVar();
List<RegisterArg> args = sVar.getUseList();
if (args.size() != 3) {
return null;
}
condArg = InsnUtils.getRegFromInsn(args, InsnType.IF);
if (condArg == null) {
return null;
}
RegisterArg arrIndex = InsnUtils.getRegFromInsn(args, InsnType.AGET);
if (arrIndex == null) {
return null;
}
InsnNode arrGetInsn = arrIndex.getParentInsn();
if (arrGetInsn == null || arrGetInsn.containsWrappedInsn()) {
return null;
}
if (!condition.isCompare()) {
return null;
}
Compare compare = condition.getCompare();
if (compare.getOp() != IfOp.LT || compare.getA() != condArg) {
return null;
}
InsnNode len;
InsnArg bCondArg = compare.getB();
if (bCondArg.isInsnWrap()) {
len = ((InsnWrapArg) bCondArg).getWrapInsn();
} else if (bCondArg.isRegister()) {
len = ((RegisterArg) bCondArg).getAssignInsn();
} else {
return null;
}
if (len == null || len.getType() != InsnType.ARRAY_LENGTH) {
return null;
}
InsnArg arrayArg = len.getArg(0);
if (!arrayArg.equals(arrGetInsn.getArg(0))) {
return null;
}
RegisterArg iterVar = arrGetInsn.getResult();
if (iterVar == null) {
return null;
}
if (!usedOnlyInLoop(mth, loopRegion, iterVar)) {
return null;
}
// array for each loop confirmed
incrInsn.getResult().add(AFlag.DONT_GENERATE);
condArg.add(AFlag.DONT_GENERATE);
bCondArg.add(AFlag.DONT_GENERATE);
arrGetInsn.add(AFlag.DONT_GENERATE);
compare.getInsn().add(AFlag.DONT_GENERATE);
if (arrGetInsn.contains(AFlag.WRAPPED)) {
InsnArg wrapArg = BlockUtils.searchWrappedInsnParent(mth, arrGetInsn);
if (wrapArg != null && wrapArg.getParentInsn() != null) {
InsnNode parentInsn = wrapArg.getParentInsn();
parentInsn.replaceArg(wrapArg, iterVar.duplicate());
parentInsn.rebindArgs();
} else {
LOG.debug(" checkArrayForEach: Wrapped insn not found: {}, mth: {}", arrGetInsn, mth);
}
}
ForEachLoop forEachLoop = new ForEachLoop(iterVar, len.getArg(0));
forEachLoop.injectFakeInsns(loopRegion);
if (InsnUtils.dontGenerateIfNotUsed(len)) {
InsnRemover.remove(mth, len);
}
CodeShrinkVisitor.shrinkMethod(mth);
return forEachLoop;
}
Aggregations