Projects STRLCPY jadx Commits 8a464e82
🤬
  • core: fix condition processing errors

  • Loading...
  • Skylot committed 1 decade ago
    8a464e82
    1 parent 066b5a89
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/Jadx.java
    skipped 14 lines
    15 15  import jadx.core.dex.visitors.PrepareForCodeGen;
    16 16  import jadx.core.dex.visitors.SimplifyVisitor;
    17 17  import jadx.core.dex.visitors.regions.CheckRegions;
     18 +import jadx.core.dex.visitors.regions.IfRegionVisitor;
    18 19  import jadx.core.dex.visitors.regions.ProcessVariables;
    19 20  import jadx.core.dex.visitors.regions.RegionMakerVisitor;
    20  -import jadx.core.dex.visitors.regions.TernaryVisitor;
    21 21  import jadx.core.dex.visitors.typeresolver.FinishTypeResolver;
    22 22  import jadx.core.dex.visitors.typeresolver.TypeResolver;
    23 23  import jadx.core.utils.Utils;
    skipped 46 lines
    70 70   
    71 71   passes.add(new CodeShrinker());
    72 72   passes.add(new RegionMakerVisitor());
    73  - passes.add(new TernaryVisitor());
     73 + passes.add(new IfRegionVisitor());
    74 74   
    75 75   passes.add(new CodeShrinker());
    76 76   passes.add(new SimplifyVisitor());
    skipped 32 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/instructions/mods/TernaryInsn.java
    skipped 1 lines
    2 2   
    3 3  import jadx.core.dex.instructions.InsnType;
    4 4  import jadx.core.dex.instructions.args.InsnArg;
     5 +import jadx.core.dex.instructions.args.LiteralArg;
    5 6  import jadx.core.dex.instructions.args.RegisterArg;
    6 7  import jadx.core.dex.nodes.InsnNode;
    7 8  import jadx.core.dex.regions.IfCondition;
    skipped 6 lines
    14 15   
    15 16   public TernaryInsn(IfCondition condition, RegisterArg result, InsnArg th, InsnArg els) {
    16 17   super(InsnType.TERNARY, 2);
    17  - this.condition = condition;
    18 18   setResult(result);
    19  - addArg(th);
    20  - addArg(els);
     19 + 
     20 + if (th.equals(LiteralArg.FALSE) && els.equals(LiteralArg.TRUE)) {
     21 + // inverted
     22 + this.condition = IfCondition.invert(condition);
     23 + addArg(els);
     24 + addArg(th);
     25 + } else {
     26 + this.condition = condition;
     27 + addArg(th);
     28 + addArg(els);
     29 + }
    21 30   }
    22 31   
    23 32   public IfCondition getCondition() {
    skipped 11 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java
    skipped 21 lines
    22 22   private List<BlockNode> successors = new ArrayList<BlockNode>(1);
    23 23   private List<BlockNode> cleanSuccessors;
    24 24   
    25  - private BitSet doms; // all dominators
    26  - private BlockNode idom; // immediate dominator
     25 + // all dominators
     26 + private BitSet doms;
     27 + // dominance frontier
     28 + private BitSet domFrontier;
     29 + // immediate dominator
     30 + private BlockNode idom;
     31 + // blocks on which dominates this block
    27 32   private final List<BlockNode> dominatesOn = new ArrayList<BlockNode>(1);
    28 33   
    29 34   private BlockRegState startState;
    skipped 86 lines
    116 121   
    117 122   public void setDoms(BitSet doms) {
    118 123   this.doms = doms;
     124 + }
     125 + 
     126 + public BitSet getDomFrontier() {
     127 + return domFrontier;
     128 + }
     129 + 
     130 + public void setDomFrontier(BitSet domFrontier) {
     131 + this.domFrontier = domFrontier;
    119 132   }
    120 133   
    121 134   /**
    skipped 73 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/nodes/IRegion.java
    skipped 7 lines
    8 8   
    9 9   List<IContainer> getSubBlocks();
    10 10   
     11 + boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock);
    11 12  }
    12 13   
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/regions/AbstractRegion.java
    1 1  package jadx.core.dex.regions;
    2 2   
    3 3  import jadx.core.dex.attributes.AttrNode;
     4 +import jadx.core.dex.nodes.IContainer;
    4 5  import jadx.core.dex.nodes.IRegion;
    5 6   
    6 7  public abstract class AbstractRegion extends AttrNode implements IRegion {
    skipped 11 lines
    18 19   
    19 20   public void setParent(IRegion parent) {
    20 21   this.parent = parent;
     22 + }
     23 + 
     24 + @Override
     25 + public boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock) {
     26 + // TODO: implement for others regions
     27 + return false;
    21 28   }
    22 29  }
    23 30   
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/regions/Region.java
    skipped 20 lines
    21 21   return blocks;
    22 22   }
    23 23   
     24 + public void add(IContainer region) {
     25 + if (region instanceof AbstractRegion) {
     26 + ((AbstractRegion) region).setParent(this);
     27 + }
     28 + blocks.add(region);
     29 + }
     30 + 
     31 + @Override
     32 + public boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock) {
     33 + int i = blocks.indexOf(oldBlock);
     34 + if (i != -1) {
     35 + blocks.set(i, newBlock);
     36 + return true;
     37 + }
     38 + return false;
     39 + }
     40 + 
    24 41   @Override
    25 42   public String toString() {
    26 43   StringBuilder sb = new StringBuilder();
    skipped 8 lines
    35 52   }
    36 53   return sb.toString();
    37 54   }
    38  - 
    39 55  }
    40 56   
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/BlockMakerVisitor.java
    skipped 18 lines
    19 19  import jadx.core.dex.trycatch.ExceptionHandler;
    20 20  import jadx.core.dex.trycatch.SplitterBlockAttr;
    21 21  import jadx.core.utils.BlockUtils;
     22 +import jadx.core.utils.EmptyBitSet;
    22 23  import jadx.core.utils.exceptions.JadxRuntimeException;
    23 24   
    24 25  import java.util.ArrayList;
    skipped 15 lines
    40 41   InsnType.SWITCH,
    41 42   InsnType.MONITOR_ENTER,
    42 43   InsnType.MONITOR_EXIT);
     44 + 
     45 + private static final BitSet EMPTY_BITSET = new EmptyBitSet();
    43 46   
    44 47   private static int nextBlockId;
    45 48   
    skipped 252 lines
    298 301   }
    299 302   }
    300 303   }
     304 + 
     305 + computeDominanceFrontier(mth);
     306 + }
     307 + 
     308 + private static void computeDominanceFrontier(MethodNode mth) {
     309 + for (BlockNode exit : mth.getExitBlocks()) {
     310 + exit.setDomFrontier(EMPTY_BITSET);
     311 + }
     312 + for (BlockNode block : mth.getBasicBlocks()) {
     313 + computeBlockDF(block);
     314 + }
     315 + }
     316 + 
     317 + private static void computeBlockDF(BlockNode block) {
     318 + if (block.getDomFrontier() != null) {
     319 + return;
     320 + }
     321 + BitSet domFrontier = null;
     322 + BitSet doms = block.getDoms();
     323 + int id = block.getId();
     324 + 
     325 + for (BlockNode s : block.getSuccessors()) {
     326 + if (s.getIDom() != block) {
     327 + if (domFrontier == null) {
     328 + domFrontier = new BitSet();
     329 + }
     330 + domFrontier.set(s.getId());
     331 + }
     332 + }
     333 + for (BlockNode node : block.getDominatesOn()) {
     334 + if (node.getIDom() == block) {
     335 + BitSet frontier = node.getDomFrontier();
     336 + if (frontier == null) {
     337 + computeBlockDF(node);
     338 + frontier = node.getDomFrontier();
     339 + }
     340 + for (int w = frontier.nextSetBit(0); w >= 0; w = frontier.nextSetBit(w + 1)) {
     341 + if (id == w || !doms.get(w)) {
     342 + if (domFrontier == null) {
     343 + domFrontier = new BitSet();
     344 + }
     345 + domFrontier.set(w);
     346 + }
     347 + }
     348 + }
     349 + }
     350 + if (domFrontier == null || domFrontier.cardinality() == 0) {
     351 + domFrontier = EMPTY_BITSET;
     352 + }
     353 + block.setDomFrontier(domFrontier);
    301 354   }
    302 355   
    303 356   private static void markReturnBlocks(MethodNode mth) {
    skipped 214 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java
    skipped 10 lines
    11 11  import jadx.core.dex.nodes.InsnNode;
    12 12  import jadx.core.dex.nodes.MethodNode;
    13 13  import jadx.core.dex.trycatch.ExceptionHandler;
     14 +import jadx.core.utils.BlockUtils;
    14 15  import jadx.core.utils.InsnUtils;
    15 16  import jadx.core.utils.RegionUtils;
    16 17  import jadx.core.utils.Utils;
    skipped 6 lines
    23 24  public class DotGraphVisitor extends AbstractVisitor {
    24 25   
    25 26   private static final String NL = "\\l";
     27 + private static final boolean PRINT_DOMINATORS = false;
    26 28   
    27 29   private final File dir;
    28 30   private final boolean useRegions;
    skipped 132 lines
    161 163   falsePath = ((IfNode) list.get(0)).getElseBlock();
    162 164   }
    163 165   for (BlockNode next : block.getSuccessors()) {
    164  - conn.startLine(makeName(block)).add(" -> ").add(makeName(next));
    165  - if (next == falsePath) {
    166  - conn.add("[style=dotted]");
     166 + String style = next == falsePath ? "[style=dashed]" : "";
     167 + addEdge(block, next, style);
     168 + }
     169 + 
     170 + if (PRINT_DOMINATORS) {
     171 + for (BlockNode dom : BlockUtils.bitSetToBlocks(mth, block.getDoms())) {
     172 + String style = "[color=green]";
     173 + if (dom == block.getIDom()) {
     174 + style = "[style=dashed, color=green]";
     175 + }
     176 + addEdge(block, dom, style);
     177 + }
     178 + 
     179 + for (BlockNode dom : BlockUtils.bitSetToBlocks(mth, block.getDomFrontier())) {
     180 + addEdge(block, dom, "[color=blue]");
    167 181   }
    168  - conn.add(';');
    169 182   }
     183 + }
     184 + 
     185 + private void addEdge(BlockNode from, BlockNode to, String style) {
     186 + conn.startLine(makeName(from)).add(" -> ").add(makeName(to));
     187 + conn.add(style);
     188 + conn.add(';');
    170 189   }
    171 190   
    172 191   private String attributesString(IAttributeNode block) {
    skipped 50 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlineVisitor.java
    skipped 21 lines
    22 22   && accessFlags.isStatic()
    23 23   && mth.getBasicBlocks().size() == 2) {
    24 24   BlockNode block = mth.getBasicBlocks().get(1);
    25  - if (block.getAttributes().contains(AttributeFlag.RETURN)) {
     25 + if (block.getInstructions().isEmpty()
     26 + || block.getAttributes().contains(AttributeFlag.RETURN)) {
    26 27   inlineMth(mth);
    27 28   }
    28 29   }
    skipped 26 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java
    skipped 37 lines
    38 38   }
    39 39   }
    40 40   };
    41  - DepthRegionTraverser.traverseAll(mth, collectBlocks);
     41 + DepthRegionTraversal.traverseAll(mth, collectBlocks);
    42 42   
    43 43   if (mth.getBasicBlocks().size() != blocksInRegions.size()) {
    44 44   for (BlockNode block : mth.getBasicBlocks()) {
    skipped 20 lines
    65 65   }
    66 66   }
    67 67   };
    68  - DepthRegionTraverser.traverseAll(mth, checkLoops);
     68 + DepthRegionTraversal.traverseAll(mth, checkLoops);
    69 69   }
    70 70  }
    71 71   
  • ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/CleanRegions.java
    skipped 43 lines
    44 44   }
    45 45   }
    46 46   };
    47  - DepthRegionTraverser.traverseAll(mth, removeEmptyBlocks);
     47 + DepthRegionTraversal.traverseAll(mth, removeEmptyBlocks);
    48 48   }
    49 49  }
    50 50   
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/DepthRegionTraversal.java
     1 +package jadx.core.dex.visitors.regions;
     2 + 
     3 +import jadx.core.dex.nodes.IBlock;
     4 +import jadx.core.dex.nodes.IContainer;
     5 +import jadx.core.dex.nodes.IRegion;
     6 +import jadx.core.dex.nodes.MethodNode;
     7 +import jadx.core.dex.trycatch.ExceptionHandler;
     8 + 
     9 +public class DepthRegionTraversal {
     10 + 
     11 + private DepthRegionTraversal() {
     12 + }
     13 + 
     14 + public static void traverse(MethodNode mth, IRegionVisitor visitor) {
     15 + traverseInternal(mth, visitor, mth.getRegion());
     16 + }
     17 + 
     18 + public static void traverseAll(MethodNode mth, IRegionVisitor visitor) {
     19 + traverse(mth, visitor);
     20 + for (ExceptionHandler h : mth.getExceptionHandlers()) {
     21 + traverseInternal(mth, visitor, h.getHandlerRegion());
     22 + }
     23 + }
     24 + 
     25 + public static void traverseAllIterative(MethodNode mth, IRegionIterativeVisitor visitor) {
     26 + boolean repeat;
     27 + do {
     28 + repeat = traverseAllIterativeIntern(mth, visitor);
     29 + } while (repeat);
     30 + }
     31 + 
     32 + private static void traverseInternal(MethodNode mth, IRegionVisitor visitor, IContainer container) {
     33 + if (container instanceof IBlock) {
     34 + visitor.processBlock(mth, (IBlock) container);
     35 + } else if (container instanceof IRegion) {
     36 + IRegion region = (IRegion) container;
     37 + visitor.enterRegion(mth, region);
     38 + for (IContainer subCont : region.getSubBlocks()) {
     39 + traverseInternal(mth, visitor, subCont);
     40 + }
     41 + visitor.leaveRegion(mth, region);
     42 + }
     43 + }
     44 + 
     45 + private static boolean traverseAllIterativeIntern(MethodNode mth, IRegionIterativeVisitor visitor) {
     46 + if (traverseIterativeInternal(mth, visitor, mth.getRegion())) {
     47 + return true;
     48 + }
     49 + for (ExceptionHandler h : mth.getExceptionHandlers()) {
     50 + if (traverseIterativeInternal(mth, visitor, h.getHandlerRegion())) {
     51 + return true;
     52 + }
     53 + }
     54 + return false;
     55 + }
     56 + 
     57 + public static boolean traverseIterativeInternal(MethodNode mth, IRegionIterativeVisitor visitor, IContainer container) {
     58 + if (container instanceof IRegion) {
     59 + IRegion region = (IRegion) container;
     60 + if (visitor.visitRegion(mth, region)) {
     61 + return true;
     62 + }
     63 + for (IContainer subCont : region.getSubBlocks()) {
     64 + if (traverseIterativeInternal(mth, visitor, subCont)) {
     65 + return true;
     66 + }
     67 + }
     68 + }
     69 + return false;
     70 + }
     71 +}
     72 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/DepthRegionTraverser.java
    1  -package jadx.core.dex.visitors.regions;
    2  - 
    3  -import jadx.core.dex.nodes.IBlock;
    4  -import jadx.core.dex.nodes.IContainer;
    5  -import jadx.core.dex.nodes.IRegion;
    6  -import jadx.core.dex.nodes.MethodNode;
    7  -import jadx.core.dex.trycatch.ExceptionHandler;
    8  - 
    9  -public class DepthRegionTraverser {
    10  - 
    11  - public static void traverse(MethodNode mth, IRegionVisitor visitor, IContainer container) {
    12  - if (container instanceof IBlock) {
    13  - visitor.processBlock(mth, (IBlock) container);
    14  - } else if (container instanceof IRegion) {
    15  - IRegion region = (IRegion) container;
    16  - visitor.enterRegion(mth, region);
    17  - for (IContainer subCont : region.getSubBlocks()) {
    18  - traverse(mth, visitor, subCont);
    19  - }
    20  - visitor.leaveRegion(mth, region);
    21  - }
    22  - }
    23  - 
    24  - public static void traverseAll(MethodNode mth, IRegionVisitor visitor) {
    25  - traverse(mth, visitor, mth.getRegion());
    26  - 
    27  - for (ExceptionHandler h : mth.getExceptionHandlers()) {
    28  - traverse(mth, visitor, h.getHandlerRegion());
    29  - }
    30  - }
    31  -}
    32  - 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/IRegionIterativeVisitor.java
     1 +package jadx.core.dex.visitors.regions;
     2 + 
     3 +import jadx.core.dex.nodes.IRegion;
     4 +import jadx.core.dex.nodes.MethodNode;
     5 + 
     6 +public interface IRegionIterativeVisitor {
     7 + 
     8 + /**
     9 + * If return 'true' traversal will be restarted.
     10 + */
     11 + boolean visitRegion(MethodNode mth, IRegion region);
     12 + 
     13 +}
     14 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java
     1 +package jadx.core.dex.visitors.regions;
     2 + 
     3 +import jadx.core.dex.attributes.AttributeFlag;
     4 +import jadx.core.dex.instructions.args.ArgType;
     5 +import jadx.core.dex.nodes.IBlock;
     6 +import jadx.core.dex.nodes.IContainer;
     7 +import jadx.core.dex.nodes.IRegion;
     8 +import jadx.core.dex.nodes.MethodNode;
     9 +import jadx.core.dex.regions.IfCondition;
     10 +import jadx.core.dex.regions.IfRegion;
     11 +import jadx.core.dex.regions.Region;
     12 +import jadx.core.dex.visitors.AbstractVisitor;
     13 +import jadx.core.utils.RegionUtils;
     14 + 
     15 +import java.util.List;
     16 + 
     17 +public class IfRegionVisitor extends AbstractVisitor implements IRegionVisitor, IRegionIterativeVisitor {
     18 + 
     19 + @Override
     20 + public void visit(MethodNode mth) {
     21 + DepthRegionTraversal.traverseAll(mth, this);
     22 + DepthRegionTraversal.traverseAllIterative(mth, this);
     23 + }
     24 + 
     25 + @Override
     26 + public void enterRegion(MethodNode mth, IRegion region) {
     27 + if (region instanceof IfRegion) {
     28 + processIfRegion(mth, (IfRegion) region);
     29 + }
     30 + }
     31 + 
     32 + @Override
     33 + public boolean visitRegion(MethodNode mth, IRegion region) {
     34 + if (region instanceof IfRegion) {
     35 + return removeRedundantElseBlock((IfRegion) region);
     36 + }
     37 + return false;
     38 + }
     39 + 
     40 + @Override
     41 + public void processBlock(MethodNode mth, IBlock container) {
     42 + }
     43 + 
     44 + @Override
     45 + public void leaveRegion(MethodNode mth, IRegion region) {
     46 + }
     47 + 
     48 + private static void processIfRegion(MethodNode mth, IfRegion ifRegion) {
     49 + simplifyIfCondition(ifRegion);
     50 + moveReturnToThenBlock(mth, ifRegion);
     51 + markElseIfChains(ifRegion);
     52 + 
     53 + TernaryMod.makeTernaryInsn(mth, ifRegion);
     54 + }
     55 + 
     56 + private static void simplifyIfCondition(IfRegion ifRegion) {
     57 + if (ifRegion.simplifyCondition()) {
     58 + IfCondition condition = ifRegion.getCondition();
     59 + if (condition.getMode() == IfCondition.Mode.NOT) {
     60 + tryInvertIfRegion(ifRegion);
     61 + }
     62 + }
     63 + }
     64 + 
     65 + private static void moveReturnToThenBlock(MethodNode mth, IfRegion ifRegion) {
     66 + if (!mth.getReturnType().equals(ArgType.VOID)
     67 + && hasSimpleReturnBlock(ifRegion.getElseRegion())
     68 + && !hasSimpleReturnBlock(ifRegion.getThenRegion())) {
     69 + tryInvertIfRegion(ifRegion);
     70 + }
     71 + }
     72 + 
     73 + private static boolean removeRedundantElseBlock(IfRegion ifRegion) {
     74 + if (ifRegion.getElseRegion() != null && hasSimpleReturnBlock(ifRegion.getThenRegion())) {
     75 + IRegion parent = ifRegion.getParent();
     76 + Region newRegion = new Region(parent);
     77 + if (parent.replaceSubBlock(ifRegion, newRegion)) {
     78 + newRegion.add(ifRegion);
     79 + newRegion.add(ifRegion.getElseRegion());
     80 + ifRegion.setElseRegion(null);
     81 + return true;
     82 + }
     83 + }
     84 + return false;
     85 + }
     86 + 
     87 + /**
     88 + * Mark if-else-if chains
     89 + */
     90 + private static void markElseIfChains(IfRegion ifRegion) {
     91 + IContainer elsRegion = ifRegion.getElseRegion();
     92 + if (elsRegion != null) {
     93 + if (elsRegion instanceof IfRegion) {
     94 + elsRegion.getAttributes().add(AttributeFlag.ELSE_IF_CHAIN);
     95 + } else if (elsRegion instanceof Region) {
     96 + List<IContainer> subBlocks = ((Region) elsRegion).getSubBlocks();
     97 + if (subBlocks.size() == 1 && subBlocks.get(0) instanceof IfRegion) {
     98 + subBlocks.get(0).getAttributes().add(AttributeFlag.ELSE_IF_CHAIN);
     99 + }
     100 + }
     101 + }
     102 + }
     103 + 
     104 + private static void tryInvertIfRegion(IfRegion ifRegion) {
     105 + IContainer elseRegion = ifRegion.getElseRegion();
     106 + if (elseRegion != null && RegionUtils.notEmpty(elseRegion)) {
     107 + ifRegion.invert();
     108 + }
     109 + }
     110 + 
     111 + private static boolean hasSimpleReturnBlock(IContainer region) {
     112 + if (region == null) {
     113 + return false;
     114 + }
     115 + if (region.getAttributes().contains(AttributeFlag.RETURN)) {
     116 + return true;
     117 + }
     118 + if (region instanceof IRegion) {
     119 + List<IContainer> subBlocks = ((IRegion) region).getSubBlocks();
     120 + if (subBlocks.size() == 1
     121 + && subBlocks.get(0).getAttributes().contains(AttributeFlag.RETURN)) {
     122 + return true;
     123 + }
     124 + }
     125 + return false;
     126 + }
     127 +}
     128 + 
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessReturnInsns.java
    skipped 31 lines
    32 32   && blockNotInLoop(mth, block)
    33 33   && noTrailInstructions(block)) {
    34 34   insns.remove(insns.size() - 1);
     35 + block.getAttributes().remove(AttributeFlag.RETURN);
    35 36   }
    36 37   }
    37 38   }
    skipped 44 lines
  • ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java
    skipped 103 lines
    104 104   }
    105 105   }
    106 106   };
    107  - DepthRegionTraverser.traverseAll(mth, collect);
     107 + DepthRegionTraversal.traverseAll(mth, collect);
    108 108   
    109 109   // reduce assigns map
    110 110   List<RegisterArg> mthArgs = mth.getArguments(true);
    skipped 84 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java
    skipped 411 lines
    412 412   BlockNode thenBlock = null;
    413 413   BlockNode elseBlock = null;
    414 414   
    415  - for (BlockNode d : block.getDominatesOn()) {
    416  - if (d != bThen && d != bElse) {
    417  - out = d;
    418  - break;
    419  - }
    420  - }
    421  - 
    422 415   IfRegion ifRegion = new IfRegion(currentRegion, block);
    423 416   currentRegion.getSubBlocks().add(ifRegion);
    424 417   
    425 418   IfInfo mergedIf = mergeNestedIfNodes(block, bThen, bElse, null);
    426 419   if (mergedIf != null) {
    427  - block = mergedIf.getIfnode();
    428 420   ifRegion.setCondition(mergedIf.getCondition());
    429 421   thenBlock = mergedIf.getThenBlock();
    430 422   elseBlock = mergedIf.getElseBlock();
    431  - bThen = thenBlock;
    432  - bElse = elseBlock;
    433  - }
    434  - 
    435  - if (thenBlock == null) {
     423 + out = BlockUtils.getPathCrossBlockFor(mth, thenBlock, elseBlock);
     424 + } else {
     425 + for (BlockNode d : block.getDominatesOn()) {
     426 + if (d != bThen && d != bElse) {
     427 + out = d;
     428 + break;
     429 + }
     430 + }
    436 431   // invert condition (compiler often do it)
    437 432   ifnode.invertCondition();
    438 433   BlockNode tmp = bThen;
    skipped 320 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMakerVisitor.java
    1 1  package jadx.core.dex.visitors.regions;
    2 2   
    3  -import jadx.core.dex.attributes.AttributeFlag;
    4 3  import jadx.core.dex.instructions.args.ArgType;
    5 4  import jadx.core.dex.nodes.IContainer;
    6 5  import jadx.core.dex.nodes.IRegion;
    7 6  import jadx.core.dex.nodes.InsnNode;
    8 7  import jadx.core.dex.nodes.MethodNode;
    9  -import jadx.core.dex.regions.IfRegion;
    10 8  import jadx.core.dex.regions.LoopRegion;
    11 9  import jadx.core.dex.regions.Region;
    12 10  import jadx.core.dex.regions.SynchronizedRegion;
    skipped 36 lines
    49 47   
    50 48   private static void postProcessRegions(MethodNode mth) {
    51 49   // make try-catch regions
    52  - DepthRegionTraverser.traverse(mth, new ProcessTryCatchRegions(mth), mth.getRegion());
     50 + DepthRegionTraversal.traverse(mth, new ProcessTryCatchRegions(mth));
    53 51   
    54 52   // merge conditions in loops
    55 53   if (mth.getLoopsCount() != 0) {
    56  - DepthRegionTraverser.traverseAll(mth, new AbstractRegionVisitor() {
     54 + DepthRegionTraversal.traverseAll(mth, new AbstractRegionVisitor() {
    57 55   @Override
    58 56   public void enterRegion(MethodNode mth, IRegion region) {
    59 57   if (region instanceof LoopRegion) {
    skipped 6 lines
    66 64   
    67 65   CleanRegions.process(mth);
    68 66   
    69  - DepthRegionTraverser.traverseAll(mth, new AbstractRegionVisitor() {
    70  - @Override
    71  - public void leaveRegion(MethodNode mth, IRegion region) {
    72  - if (region instanceof IfRegion) {
    73  - processIfRegion((IfRegion) region);
    74  - 
    75  - }
    76  - }
    77  - });
    78  - 
    79 67   // remove useless returns in void methods
    80 68   if (mth.getReturnType().equals(ArgType.VOID)) {
    81  - DepthRegionTraverser.traverseAll(mth, new ProcessReturnInsns());
     69 + DepthRegionTraversal.traverseAll(mth, new ProcessReturnInsns());
    82 70   }
    83 71   
    84 72   if (mth.getAccessFlags().isSynchronized()) {
    85 73   removeSynchronized(mth);
    86  - }
    87  - 
    88  - }
    89  - 
    90  - private static void processIfRegion(IfRegion ifRegion) {
    91  - if (ifRegion.simplifyCondition()) {
    92  -// IfCondition condition = ifRegion.getCondition();
    93  -// if (condition.getMode() == IfCondition.Mode.NOT) {
    94  -// ifRegion.invert();
    95  -// }
    96  - }
    97  - 
    98  - // mark if-else-if chains
    99  - IContainer elsRegion = ifRegion.getElseRegion();
    100  - if (elsRegion instanceof IfRegion) {
    101  - elsRegion.getAttributes().add(AttributeFlag.ELSE_IF_CHAIN);
    102  - } else if (elsRegion instanceof Region) {
    103  - List<IContainer> subBlocks = ((Region) elsRegion).getSubBlocks();
    104  - if (subBlocks.size() == 1 && subBlocks.get(0) instanceof IfRegion) {
    105  - subBlocks.get(0).getAttributes().add(AttributeFlag.ELSE_IF_CHAIN);
    106  - }
    107 74   }
    108 75   }
    109 76   
    skipped 25 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryVisitor.java jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java
    skipped 3 lines
    4 4  import jadx.core.dex.instructions.InsnType;
    5 5  import jadx.core.dex.instructions.args.ArgType;
    6 6  import jadx.core.dex.instructions.args.InsnArg;
    7  -import jadx.core.dex.instructions.args.LiteralArg;
    8 7  import jadx.core.dex.instructions.mods.TernaryInsn;
    9 8  import jadx.core.dex.nodes.BlockNode;
    10  -import jadx.core.dex.nodes.ClassNode;
    11 9  import jadx.core.dex.nodes.IContainer;
    12  -import jadx.core.dex.nodes.IRegion;
    13 10  import jadx.core.dex.nodes.InsnNode;
    14 11  import jadx.core.dex.nodes.MethodNode;
    15  -import jadx.core.dex.regions.IfCondition;
    16 12  import jadx.core.dex.regions.IfRegion;
    17 13  import jadx.core.dex.regions.Region;
    18 14  import jadx.core.dex.regions.TernaryRegion;
    19 15  import jadx.core.dex.visitors.CodeShrinker;
    20  -import jadx.core.dex.visitors.IDexTreeVisitor;
    21 16  import jadx.core.utils.InsnList;
    22  -import jadx.core.utils.exceptions.JadxException;
    23 17   
    24 18  import java.util.List;
    25 19   
    26  -public class TernaryVisitor extends AbstractRegionVisitor implements IDexTreeVisitor {
    27  - 
    28  - private static final LiteralArg FALSE_ARG = InsnArg.lit(0, ArgType.BOOLEAN);
    29  - private static final LiteralArg TRUE_ARG = InsnArg.lit(1, ArgType.BOOLEAN);
    30  - 
    31  - @Override
    32  - public boolean visit(ClassNode cls) throws JadxException {
    33  - return true;
    34  - }
     20 +public class TernaryMod {
    35 21   
    36  - @Override
    37  - public void visit(MethodNode mth) {
    38  - DepthRegionTraverser.traverseAll(mth, this);
     22 + private TernaryMod() {
    39 23   }
    40 24   
    41  - @Override
    42  - public void enterRegion(MethodNode mth, IRegion region) {
    43  - if (!(region instanceof IfRegion)) {
     25 + static void makeTernaryInsn(MethodNode mth, IfRegion ifRegion) {
     26 + if (ifRegion.getAttributes().contains(AttributeFlag.ELSE_IF_CHAIN)) {
    44 27   return;
    45 28   }
    46  - if (region.getAttributes().contains(AttributeFlag.ELSE_IF_CHAIN)) {
    47  - return;
    48  - }
    49  - IfRegion ifRegion = (IfRegion) region;
    50 29   IContainer thenRegion = ifRegion.getThenRegion();
    51 30   IContainer elseRegion = ifRegion.getElseRegion();
    52 31   if (thenRegion == null || elseRegion == null) {
    skipped 36 lines
    89 68   
    90 69   if (!mth.getReturnType().equals(ArgType.VOID)
    91 70   && t.getType() == InsnType.RETURN && e.getType() == InsnType.RETURN) {
    92  - boolean inverted = false;
    93  - InsnArg thenArg = t.getArg(0);
    94  - InsnArg elseArg = e.getArg(0);
    95  - if (thenArg.equals(FALSE_ARG) && elseArg.equals(TRUE_ARG)) {
    96  - inverted = true;
    97  - }
    98 71   InsnList.remove(tb, t);
    99 72   InsnList.remove(eb, e);
    100 73   tb.getAttributes().remove(AttributeFlag.RETURN);
    101 74   eb.getAttributes().remove(AttributeFlag.RETURN);
    102 75   
    103  - IfCondition condition = ifRegion.getCondition();
    104  - if (inverted) {
    105  - condition = IfCondition.invert(condition);
    106  - InsnArg tmp = thenArg;
    107  - thenArg = elseArg;
    108  - elseArg = tmp;
    109  - }
    110  - TernaryInsn ternInsn = new TernaryInsn(condition, null, thenArg, elseArg);
     76 + TernaryInsn ternInsn = new TernaryInsn(ifRegion.getCondition(), null, t.getArg(0), e.getArg(0));
    111 77   InsnNode retInsn = new InsnNode(InsnType.RETURN, 1);
    112 78   retInsn.addArg(InsnArg.wrapArg(ternInsn));
    113 79   
    skipped 27 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/utils/BlockUtils.java
    skipped 168 lines
    169 169   }
    170 170   }
    171 171   
    172  - private static boolean traverseSuccessorsUntil(BlockNode from, BlockNode until, Set<BlockNode> checked) {
     172 + private static boolean traverseSuccessorsUntil(BlockNode from, BlockNode until, BitSet visited) {
    173 173   for (BlockNode s : from.getCleanSuccessors()) {
    174 174   if (s == until) {
    175 175   return true;
    176 176   }
    177  - if (!checked.contains(s)) {
    178  - checked.add(s);
     177 + int id = s.getId();
     178 + if (!visited.get(id)) {
     179 + visited.set(id);
    179 180   if (until.isDominator(s)) {
    180 181   return true;
    181 182   }
    182  - if (traverseSuccessorsUntil(s, until, checked)) {
     183 + if (traverseSuccessorsUntil(s, until, visited)) {
    183 184   return true;
    184 185   }
    185 186   }
    skipped 8 lines
    194 195   if (end.isDominator(start)) {
    195 196   return true;
    196 197   }
    197  - return traverseSuccessorsUntil(start, end, new HashSet<BlockNode>());
     198 + return traverseSuccessorsUntil(start, end, new BitSet());
    198 199   }
    199 200   
    200 201   public static boolean isOnlyOnePathExists(BlockNode start, BlockNode end) {
    skipped 24 lines
    225 226   if (out != null) {
    226 227   return out;
    227 228   }
     229 + }
     230 + }
     231 + return null;
     232 + }
     233 + 
     234 + public static BlockNode getPathCrossBlockFor(MethodNode mth, BlockNode b1, BlockNode b2) {
     235 + if (b1 == null || b2 == null) {
     236 + return null;
     237 + }
     238 + BitSet b = new BitSet();
     239 + b.or(b1.getDomFrontier());
     240 + b.or(b2.getDomFrontier());
     241 + b.clear(b1.getId());
     242 + b.clear(b2.getId());
     243 + if (b.cardinality() == 1) {
     244 + BlockNode end = mth.getBasicBlocks().get(b.nextSetBit(0));
     245 + if (isPathExists(b1, end) && isPathExists(b2, end)) {
     246 + return end;
    228 247   }
    229 248   }
    230 249   return null;
    skipped 21 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/utils/EmptyBitSet.java
     1 +package jadx.core.utils;
     2 + 
     3 +import java.util.BitSet;
     4 + 
     5 +public class EmptyBitSet extends BitSet {
     6 + 
     7 + public EmptyBitSet() {
     8 + super(0);
     9 + }
     10 + 
     11 + @Override
     12 + public int cardinality() {
     13 + return 0;
     14 + }
     15 + 
     16 + @Override
     17 + public boolean isEmpty() {
     18 + return true;
     19 + }
     20 + 
     21 + @Override
     22 + public int nextSetBit(int fromIndex) {
     23 + return -1;
     24 + }
     25 + 
     26 + @Override
     27 + public int length() {
     28 + return 0;
     29 + }
     30 + 
     31 + @Override
     32 + public int size() {
     33 + return 0;
     34 + }
     35 + 
     36 + @Override
     37 + public void set(int bitIndex) {
     38 + throw new UnsupportedOperationException();
     39 + }
     40 + 
     41 + @Override
     42 + public void set(int bitIndex, boolean value) {
     43 + throw new UnsupportedOperationException();
     44 + }
     45 + 
     46 + @Override
     47 + public void set(int fromIndex, int toIndex) {
     48 + throw new UnsupportedOperationException();
     49 + }
     50 + 
     51 + @Override
     52 + public void set(int fromIndex, int toIndex, boolean value) {
     53 + throw new UnsupportedOperationException();
     54 + }
     55 + 
     56 + @Override
     57 + public boolean get(int bitIndex) {
     58 + return false;
     59 + }
     60 + 
     61 + @Override
     62 + public BitSet get(int fromIndex, int toIndex) {
     63 + throw new UnsupportedOperationException();
     64 + }
     65 + 
     66 + @Override
     67 + public void and(BitSet set) {
     68 + throw new UnsupportedOperationException();
     69 + }
     70 + 
     71 + @Override
     72 + public void or(BitSet set) {
     73 + throw new UnsupportedOperationException();
     74 + }
     75 + 
     76 + @Override
     77 + public void xor(BitSet set) {
     78 + throw new UnsupportedOperationException();
     79 + }
     80 + 
     81 + @Override
     82 + public void andNot(BitSet set) {
     83 + throw new UnsupportedOperationException();
     84 + }
     85 +}
     86 + 
  • ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/internal/conditions/TestConditions.java
    skipped 11 lines
    12 12  public class TestConditions extends InternalJadxTest {
    13 13   
    14 14   public static class TestCls {
    15  - private boolean f1(boolean a, boolean b, boolean c) {
     15 + private boolean test(boolean a, boolean b, boolean c) {
    16 16   return (a && b) || c;
    17 17   }
    18 18   }
    skipped 5 lines
    24 24   System.out.println(code);
    25 25   
    26 26   assertThat(code, not(containsString("(!a || !b) && !c")));
    27  - assertThat(code, containsString("(a && b) || c"));
    28  -// assertThat(code, containsString("return (a && b) || c;"));
     27 + assertThat(code, containsString("return (a && b) || c;"));
    29 28   }
    30 29  }
    31 30   
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/internal/conditions/TestConditions3.java
     1 +package jadx.tests.internal.conditions;
     2 + 
     3 +import jadx.api.InternalJadxTest;
     4 +import jadx.core.dex.nodes.ClassNode;
     5 + 
     6 +import java.util.List;
     7 +import java.util.regex.Pattern;
     8 + 
     9 +import org.junit.Test;
     10 + 
     11 +import static org.hamcrest.CoreMatchers.containsString;
     12 +import static org.hamcrest.CoreMatchers.not;
     13 +import static org.junit.Assert.assertThat;
     14 + 
     15 +public class TestConditions3 extends InternalJadxTest {
     16 + 
     17 + public static class TestCls {
     18 + private static final Pattern PATTERN = Pattern.compile("[a-f0-9]{20}");
     19 + 
     20 + public static Object test(final A a) {
     21 + List<String> list = a.getList();
     22 + if (list == null) {
     23 + return null;
     24 + }
     25 + if (list.size() != 1) {
     26 + return null;
     27 + }
     28 + String s = list.get(0);
     29 + if (isEmpty(s)) {
     30 + return null;
     31 + }
     32 + if (isDigitsOnly(s)) {
     33 + return new A().set(s);
     34 + }
     35 + if (PATTERN.matcher(s).matches()) {
     36 + return new A().set(s);
     37 + }
     38 + return null;
     39 + }
     40 + 
     41 + private static boolean isDigitsOnly(String s) {
     42 + return false;
     43 + }
     44 + 
     45 + private static boolean isEmpty(String s) {
     46 + return false;
     47 + }
     48 + 
     49 + private static class A {
     50 + public Object set(String s) {
     51 + return null;
     52 + }
     53 + 
     54 + public List<String> getList() {
     55 + return null;
     56 + }
     57 + }
     58 + }
     59 + 
     60 + @Test
     61 + public void test() {
     62 + ClassNode cls = getClassNode(TestCls.class);
     63 + String code = cls.getCode().toString();
     64 + System.out.println(code);
     65 + 
     66 + assertThat(code, containsString("return null;"));
     67 + assertThat(code, not(containsString("else")));
     68 + 
     69 + // TODO: fix constant inline
     70 +// assertThat(code, not(containsString("AnonymousClass_1")));
     71 + }
     72 +}
     73 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/internal/conditions/TestConditions4.java
     1 +package jadx.tests.internal.conditions;
     2 + 
     3 +import jadx.api.InternalJadxTest;
     4 +import jadx.core.dex.nodes.ClassNode;
     5 + 
     6 +import org.junit.Test;
     7 + 
     8 +import static org.hamcrest.CoreMatchers.containsString;
     9 +import static org.hamcrest.CoreMatchers.not;
     10 +import static org.junit.Assert.assertThat;
     11 + 
     12 +public class TestConditions4 extends InternalJadxTest {
     13 + 
     14 + public static class TestCls {
     15 + public int test(int num) {
     16 + boolean inRange = (num >= 59 && num <= 66);
     17 + return inRange ? num + 1 : num;
     18 + }
     19 + }
     20 + 
     21 + @Test
     22 + public void test() {
     23 + ClassNode cls = getClassNode(TestCls.class);
     24 + String code = cls.getCode().toString();
     25 + System.out.println(code);
     26 + 
     27 + assertThat(code, containsString("num >= 59 && num <= 66"));
     28 + assertThat(code, containsString("return inRange ? num + 1 : num;"));
     29 + assertThat(code, not(containsString("else")));
     30 + }
     31 +}
     32 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/internal/conditions/TestConditions5.java
     1 +package jadx.tests.internal.conditions;
     2 + 
     3 +import jadx.api.InternalJadxTest;
     4 +import jadx.core.dex.nodes.ClassNode;
     5 + 
     6 +import org.junit.Test;
     7 + 
     8 +import static org.hamcrest.CoreMatchers.containsString;
     9 +import static org.hamcrest.CoreMatchers.not;
     10 +import static org.junit.Assert.assertThat;
     11 + 
     12 +public class TestConditions5 extends InternalJadxTest {
     13 + 
     14 + public static class TestCls {
     15 + public static void assertEquals(Object a1, Object a2) {
     16 + if (a1 == null) {
     17 + if (a2 != null)
     18 + throw new AssertionError(a1 + " != " + a2);
     19 + } else if (!a1.equals(a2)) {
     20 + throw new AssertionError(a1 + " != " + a2);
     21 + }
     22 + }
     23 + }
     24 + 
     25 + @Test
     26 + public void test() {
     27 + ClassNode cls = getClassNode(TestCls.class);
     28 + String code = cls.getCode().toString();
     29 + System.out.println(code);
     30 + 
     31 + assertThat(code, containsString("if (a1 == null) {"));
     32 + assertThat(code, containsString("if (a2 != null) {"));
     33 + assertThat(code, containsString("throw new AssertionError(a1 + \" != \" + a2);"));
     34 + assertThat(code, not(containsString("if (a1.equals(a2)) {")));
     35 + assertThat(code, containsString("} else if (!a1.equals(a2)) {"));
     36 + }
     37 +}
     38 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/internal/inner/TestInnerClass3.java
     1 +package jadx.tests.internal.inner;
     2 + 
     3 +import jadx.api.InternalJadxTest;
     4 +import jadx.core.dex.nodes.ClassNode;
     5 + 
     6 +import org.junit.Test;
     7 + 
     8 +import static org.hamcrest.CoreMatchers.containsString;
     9 +import static org.hamcrest.CoreMatchers.not;
     10 +import static org.junit.Assert.assertThat;
     11 + 
     12 +public class TestInnerClass3 extends InternalJadxTest {
     13 + 
     14 + public static class TestCls {
     15 + private String c;
     16 + 
     17 + private void setC(String c) {
     18 + this.c = c;
     19 + }
     20 + 
     21 + public class C {
     22 + public String c() {
     23 + setC("c");
     24 + return c;
     25 + }
     26 + }
     27 + }
     28 + 
     29 + @Test
     30 + public void test() {
     31 + ClassNode cls = getClassNode(TestCls.class);
     32 + String code = cls.getCode().toString();
     33 + System.out.println(code);
     34 + 
     35 + assertThat(code, not(containsString("synthetic")));
     36 + assertThat(code, not(containsString("access$")));
     37 + assertThat(code, not(containsString("x0")));
     38 + assertThat(code, containsString("setC(\"c\");"));
     39 + }
     40 +}
     41 + 
  • ■ ■ ■ ■ ■ ■
    jadx-samples/src/main/java/jadx/samples/TestConditions.java
    1 1  package jadx.samples;
    2 2   
    3  -/**
    4  - * Failed tests for current jadx version
    5  - */
    6 3  public class TestConditions extends AbstractTest {
    7 4   
    8 5   public int test1(int num) {
    skipped 97 lines
Please wait...
Page is in error, reload to recover