diff options
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java')
-rw-r--r-- | plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java new file mode 100644 index 000000000000..adeda024151b --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java @@ -0,0 +1,220 @@ +/* + * 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.*; + +import java.util.ArrayList; +import java.util.List; + + +public class InlineSingleBlockHelper { + + + public static boolean inlineSingleBlocks(RootStatement root) { + + boolean res = inlineSingleBlocksRec(root); + + if (res) { + SequenceHelper.condenseSequences(root); + } + + return res; + } + + private static boolean inlineSingleBlocksRec(Statement stat) { + + boolean res = false; + + for (Statement st : stat.getStats()) { + res |= inlineSingleBlocksRec(st); + } + + if (stat.type == Statement.TYPE_SEQUENCE) { + + SequenceStatement seq = (SequenceStatement)stat; + for (int i = 1; i < seq.getStats().size(); i++) { + if (isInlineable(seq, i)) { + inlineBlock(seq, i); + return true; + } + } + } + + return res; + } + + private static void inlineBlock(SequenceStatement seq, int index) { + + Statement first = seq.getStats().get(index); + Statement pre = seq.getStats().get(index - 1); + pre.removeSuccessor(pre.getAllSuccessorEdges().get(0)); // single regular edge + + StatEdge edge = first.getPredecessorEdges(StatEdge.TYPE_BREAK).get(0); + Statement source = edge.getSource(); + Statement parent = source.getParent(); + source.removeSuccessor(edge); + + List<Statement> lst = new ArrayList<Statement>(); + for (int i = seq.getStats().size() - 1; i >= index; i--) { + lst.add(0, seq.getStats().remove(i)); + } + + if (parent.type == Statement.TYPE_IF && ((IfStatement)parent).iftype == IfStatement.IFTYPE_IF && + source == parent.getFirst()) { + IfStatement ifparent = (IfStatement)parent; + SequenceStatement block = new SequenceStatement(lst); + block.setAllParent(); + + StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, source, block); + source.addSuccessor(newedge); + ifparent.setIfEdge(newedge); + ifparent.setIfstat(block); + + ifparent.getStats().addWithKey(block, block.id); + block.setParent(ifparent); + } + else { + lst.add(0, source); + + SequenceStatement block = new SequenceStatement(lst); + block.setAllParent(); + + parent.replaceStatement(source, block); + + // LabelHelper.lowContinueLabels not applicable because of forward continue edges + // LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>()); + // do it by hand + for (StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) { + + block.removePredecessor(prededge); + prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, source); + source.addPredecessor(prededge); + + source.addLabeledEdge(prededge); + } + + + if (parent.type == Statement.TYPE_SWITCH) { + ((SwitchStatement)parent).sortEdgesAndNodes(); + } + + source.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, source, first)); + } + } + + private static boolean isInlineable(SequenceStatement seq, int index) { + + Statement first = seq.getStats().get(index); + Statement pre = seq.getStats().get(index - 1); + + if (pre.hasBasicSuccEdge()) { + return false; + } + + + List<StatEdge> lst = first.getPredecessorEdges(StatEdge.TYPE_BREAK); + + if (lst.size() == 1) { + StatEdge edge = lst.get(0); + + if (sameCatchRanges(edge)) { + if (edge.explicit) { + return true; + } + else { + for (int i = index; i < seq.getStats().size(); i++) { + if (!noExitLabels(seq.getStats().get(i), seq)) { + return false; + } + } + return true; + } + } + // FIXME: count labels properly + } + + return false; + } + + private static boolean sameCatchRanges(StatEdge edge) { + + Statement from = edge.getSource(); + Statement to = edge.getDestination(); + + while (true) { + + Statement parent = from.getParent(); + if (parent.containsStatementStrict(to)) { + break; + } + + if (parent.type == Statement.TYPE_TRYCATCH || + parent.type == Statement.TYPE_CATCHALL) { + if (parent.getFirst() == from) { + return false; + } + } + else if (parent.type == Statement.TYPE_SYNCRONIZED) { + if (parent.getStats().get(1) == from) { + return false; + } + } + + from = parent; + } + + return true; + } + + private static boolean noExitLabels(Statement block, Statement sequence) { + + for (StatEdge edge : block.getAllSuccessorEdges()) { + if (edge.getType() != StatEdge.TYPE_REGULAR && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) { + if (!sequence.containsStatementStrict(edge.getDestination())) { + return false; + } + } + } + + for (Statement st : block.getStats()) { + if (!noExitLabels(st, sequence)) { + return false; + } + } + + return true; + } + + public static boolean isBreakEdgeLabeled(Statement source, Statement closure) { + + if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) { + + Statement parent = source.getParent(); + + if (parent == closure) { + return false; + } + else { + return parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH || + isBreakEdgeLabeled(parent, closure); + } + } + else { + return true; + } + } +} |