/* * Fernflower - The Analytical Java Decompiler * http://www.reversed-java.com * * (C) 2008 - 2010, Stiver * * This software is NEITHER public domain NOR free software * as per GNU License. See license.txt for more details. * * This software is distributed WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. */ package org.jetbrains.java.decompiler.modules.decompiler; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.collectors.CounterContainer; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; public class SequenceHelper { public static void condenseSequences(Statement root) { condenseSequencesRec(root); } private static void condenseSequencesRec(Statement stat) { if(stat.type == Statement.TYPE_SEQUENCE) { List lst = new ArrayList(); lst.addAll(stat.getStats()); boolean unfolded = false; // unfold blocks for(int i=0;i(st.getLabelEdges())) { if(edge.getSource() != last) { last.addLabeledEdge(edge); } } lst.remove(i); lst.addAll(i, st.getStats()); i--; unfolded = true; } } } if(unfolded) { SequenceStatement sequence = new SequenceStatement(lst); sequence.setAllParent(); stat.getParent().replaceStatement(stat, sequence); stat = sequence; } } // sequence consisting of one statement -> disband if(stat.type == Statement.TYPE_SEQUENCE) { removeEmptyStatements((SequenceStatement)stat); if(stat.getStats().size() == 1) { Statement st = stat.getFirst(); boolean ok = st.getAllSuccessorEdges().isEmpty(); if(!ok) { StatEdge edge = st.getAllSuccessorEdges().get(0); ok = stat.getAllSuccessorEdges().isEmpty(); if(!ok) { StatEdge statedge = stat.getAllSuccessorEdges().get(0); ok = (edge.getDestination() == statedge.getDestination()); if(ok) { st.removeSuccessor(edge); } } } if(ok) { stat.getParent().replaceStatement(stat, st); stat = st; } } } // replace flat statements with synthetic basic blocks outer: for(;;) { for(Statement st: stat.getStats()) { if((st.getStats().isEmpty() || st.getExprents() != null) && st.type != Statement.TYPE_BASICBLOCK) { destroyAndFlattenStatement(st); continue outer; } } break; } // recursion for(int i=0;i lstSuccs = last.getAllSuccessorEdges(); if(!lstSuccs.isEmpty()) { if(lstSuccs.get(0).getDestination() != next) { return false; } } for(StatEdge edge : next.getPredecessorEdges(StatEdge.TYPE_BREAK)) { if(last != edge.getSource() && !last.containsStatementStrict(edge.getSource())) { return false; } } return true; } private static void removeEmptyStatements(SequenceStatement sequence) { if(sequence.getStats().size() <= 1) { return; } mergeFlatStatements(sequence); for(;;) { boolean found = false; for(Statement st: sequence.getStats()) { if(st.getExprents() != null && st.getExprents().isEmpty()) { if(st.getAllSuccessorEdges().isEmpty()) { List lstBreaks = st.getPredecessorEdges(StatEdge.TYPE_BREAK); if(lstBreaks.isEmpty()) { for(StatEdge edge: st.getAllPredecessorEdges()) { edge.getSource().removeSuccessor(edge); } found = true; } } else { StatEdge sucedge = st.getAllSuccessorEdges().get(0); if(sucedge.getType() != StatEdge.TYPE_FINALLYEXIT) { st.removeSuccessor(sucedge); for(StatEdge edge: st.getAllPredecessorEdges()) { if(sucedge.getType()!=StatEdge.TYPE_REGULAR) { edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, sucedge.getType()); } st.removePredecessor(edge); edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, sucedge.getDestination()); sucedge.getDestination().addPredecessor(edge); if(sucedge.closure != null) { sucedge.closure.addLabeledEdge(edge); } } found = true; } } if(found) { sequence.getStats().removeWithKey(st.id); break; } } } if(!found) { break; } } sequence.setFirst(sequence.getStats().get(0)); } private static void mergeFlatStatements(SequenceStatement sequence) { for(;;) { Statement next = null; Statement current = null; boolean found = false; for(int i=sequence.getStats().size()-1;i>=0;i--) { next = current; current = sequence.getStats().get(i); if(next != null && current.getExprents()!=null && !current.getExprents().isEmpty()) { if(next.getExprents()!=null) { next.getExprents().addAll(0, current.getExprents()); current.getExprents().clear(); found = true; } else { Statement first = getFirstExprentlist(next); if(first != null) { first.getExprents().addAll(0, current.getExprents()); current.getExprents().clear(); found = true; } } } } if(!found) { break; } } } private static Statement getFirstExprentlist(Statement stat) { if(stat.getExprents() != null) { return stat; } switch(stat.type) { case Statement.TYPE_IF: case Statement.TYPE_SEQUENCE: case Statement.TYPE_SWITCH: case Statement.TYPE_SYNCRONIZED: return getFirstExprentlist(stat.getFirst()); } return null; } public static void destroyAndFlattenStatement(Statement stat) { destroyStatementContent(stat, false); BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock( DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER))); if(stat.getExprents() == null) { bstat.setExprents(new ArrayList()); } else { bstat.setExprents(DecHelper.copyExprentList(stat.getExprents())); } stat.getParent().replaceStatement(stat, bstat); } public static void destroyStatementContent(Statement stat, boolean self) { for(Statement st: stat.getStats()) { destroyStatementContent(st, true); } stat.getStats().clear(); if(self) { for(StatEdge edge : stat.getAllSuccessorEdges()) { stat.removeSuccessor(edge); } } } }