diff options
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java')
-rw-r--r-- | plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java new file mode 100644 index 000000000000..d5c9e8f20aee --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java @@ -0,0 +1,206 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.decompiler.modules.decompiler; + +import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Set; + + +public class LoopExtractHelper { + + + public static boolean extractLoops(Statement root) { + + boolean res = (extractLoopsRec(root) != 0); + + if (res) { + SequenceHelper.condenseSequences(root); + } + + return res; + } + + + private static int extractLoopsRec(Statement stat) { + + boolean res = false; + + while (true) { + + boolean updated = false; + + for (Statement st : stat.getStats()) { + int extr = extractLoopsRec(st); + res |= (extr != 0); + + if (extr == 2) { + updated = true; + break; + } + } + + if (!updated) { + break; + } + } + + if (stat.type == Statement.TYPE_DO) { + if (extractLoop((DoStatement)stat)) { + return 2; + } + } + + return res ? 1 : 0; + } + + + private static boolean extractLoop(DoStatement stat) { + + if (stat.getLooptype() != DoStatement.LOOP_DO) { + return false; + } + + for (StatEdge edge : stat.getLabelEdges()) { + if (edge.getType() != StatEdge.TYPE_CONTINUE && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) { + return false; + } + } + + if (!extractLastIf(stat)) { + return extractFirstIf(stat); + } + else { + return true; + } + } + + private static boolean extractLastIf(DoStatement stat) { + + // search for an if condition at the end of the loop + Statement last = stat.getFirst(); + while (last.type == Statement.TYPE_SEQUENCE) { + last = last.getStats().getLast(); + } + + if (last.type == Statement.TYPE_IF) { + IfStatement lastif = (IfStatement)last; + if (lastif.iftype == IfStatement.IFTYPE_IF && lastif.getIfstat() != null) { + Statement ifstat = lastif.getIfstat(); + StatEdge elseedge = lastif.getAllSuccessorEdges().get(0); + + if (elseedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.closure == stat) { + + Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD); + set.remove(last); + + if (set.isEmpty()) { // no direct continues in a do{}while loop + if (isExternStatement(stat, ifstat, ifstat)) { + extractIfBlock(stat, lastif); + return true; + } + } + } + } + } + return false; + } + + private static boolean extractFirstIf(DoStatement stat) { + + // search for an if condition at the entrance of the loop + Statement first = stat.getFirst(); + while (first.type == Statement.TYPE_SEQUENCE) { + first = first.getFirst(); + } + + // found an if statement + if (first.type == Statement.TYPE_IF) { + IfStatement firstif = (IfStatement)first; + + if (firstif.getFirst().getExprents().isEmpty()) { + + if (firstif.iftype == IfStatement.IFTYPE_IF && firstif.getIfstat() != null) { + Statement ifstat = firstif.getIfstat(); + + if (isExternStatement(stat, ifstat, ifstat)) { + extractIfBlock(stat, firstif); + return true; + } + } + } + } + return false; + } + + + private static boolean isExternStatement(DoStatement loop, Statement block, Statement stat) { + + for (StatEdge edge : stat.getAllSuccessorEdges()) { + if (loop.containsStatement(edge.getDestination()) && + !block.containsStatement(edge.getDestination())) { + return false; + } + } + + for (Statement st : stat.getStats()) { + if (!isExternStatement(loop, block, st)) { + return false; + } + } + + return true; + } + + + private static void extractIfBlock(DoStatement loop, IfStatement ifstat) { + + Statement target = ifstat.getIfstat(); + StatEdge ifedge = ifstat.getIfEdge(); + + ifstat.setIfstat(null); + ifedge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, ifedge, StatEdge.TYPE_BREAK); + ifedge.closure = loop; + ifstat.getStats().removeWithKey(target.id); + + loop.addLabeledEdge(ifedge); + + SequenceStatement block = new SequenceStatement(Arrays.asList(loop, target)); + loop.getParent().replaceStatement(loop, block); + block.setAllParent(); + + loop.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, loop, target)); + + for (StatEdge edge : new ArrayList<StatEdge>(block.getLabelEdges())) { + if (edge.getType() == StatEdge.TYPE_CONTINUE || edge == ifedge) { + loop.addLabeledEdge(edge); + } + } + + for (StatEdge edge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) { + if (loop.containsStatementStrict(edge.getSource())) { + block.removePredecessor(edge); + edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, loop); + loop.addPredecessor(edge); + } + } + } +} |