Package org.candle.decompiler.intermediate.graph.enhancer

Source Code of org.candle.decompiler.intermediate.graph.enhancer.ConditionToWhileLoop

package org.candle.decompiler.intermediate.graph.enhancer;

import java.util.List;
import java.util.TreeSet;

import org.apache.bcel.generic.BranchHandle;
import org.candle.decompiler.intermediate.code.AbstractIntermediate;
import org.candle.decompiler.intermediate.code.BooleanBranchIntermediate;
import org.candle.decompiler.intermediate.code.GoToIntermediate;
import org.candle.decompiler.intermediate.code.IntermediateComparator;
import org.candle.decompiler.intermediate.code.StatementIntermediate;
import org.candle.decompiler.intermediate.code.loop.WhileIntermediate;
import org.candle.decompiler.intermediate.expression.Continue;
import org.candle.decompiler.intermediate.graph.GraphIntermediateVisitor;
import org.candle.decompiler.intermediate.graph.context.IntermediateGraphContext;
import org.candle.decompiler.intermediate.graph.edge.IntermediateEdge;
import org.jgrapht.Graphs;
import org.jgrapht.alg.CycleDetector;

public class ConditionToWhileLoop extends GraphIntermediateVisitor {
 
  public ConditionToWhileLoop(IntermediateGraphContext igc) {
    super(igc, true);
  }

  @Override
  public void visitBooleanBranchIntermediate(BooleanBranchIntermediate line) {
    List<AbstractIntermediate> predecessors = Graphs.predecessorListOf(igc.getGraph(), line);
   
    CycleDetector<AbstractIntermediate, IntermediateEdge> cycleDetector = new CycleDetector<AbstractIntermediate, IntermediateEdge>(igc.getGraph());
    if(!cycleDetector.detectCyclesContainingVertex(line)) {
      return;
    }
   
    //first, determine if the condition has two incoming lines.
    if(predecessors.size() >= 2) {
      //check to see that 1 predecessor is a GOTO.
     
      TreeSet<GoToIntermediate> incomingGotoNonNested = new TreeSet<GoToIntermediate>(new IntermediateComparator());
      TreeSet<GoToIntermediate> incomingGotoNested = new TreeSet<GoToIntermediate>(new IntermediateComparator());
      GoToIntermediate nestedLine = null;
      AbstractIntermediate otherLine = null;
     
      //classify.
      for(AbstractIntermediate predecessor : predecessors) {
        //check to see if 1 is GOTO.
        if(predecessor instanceof GoToIntermediate) {
          if(isNested(line, predecessor)) {
            incomingGotoNested.add((GoToIntermediate)predecessor);
          }
          else {
            incomingGotoNonNested.add((GoToIntermediate)predecessor);
          }
          continue;
        }
        else {
          otherLine = predecessor;
        }
      }
     
      //if there are more than one GOTO statements that are not-nested, return.
      if(incomingGotoNonNested.size() > 1) {
        return;
      }
     
      nestedLine = getCandidateGoto(incomingGotoNonNested, incomingGotoNested);
     
      //stop if both conditions aren't met.
      if(nestedLine == null || otherLine == null) {
        return;
      }
     
      //check to validate that the GOTO instruction is less than the other incoming...
      if(comparator.before(otherLine, line)) {
        //take the lower condition...
        BranchHandle refHandle = null;
        if(comparator.before(nestedLine, line)) {
          refHandle = (BranchHandle)nestedLine.getInstruction();
        }
        else {
          refHandle = (BranchHandle)line.getInstruction();
        }
       
       
        WhileIntermediate whileIntermediate = new WhileIntermediate(refHandle, line);
       
        //add this to the graph.
        this.igc.getGraph().addVertex(whileIntermediate);
       
        //get the incoming from the goto...
        igc.redirectPredecessors(nestedLine, whileIntermediate);
        igc.redirectSuccessors(line, whileIntermediate);
               
        //now, create line from other to while.
        this.igc.getGraph().addEdge(otherLine, whileIntermediate);
       
        //now, remove the GOTO and Conditional Vertex from graph.
        igc.getGraph().removeVertex(nestedLine);
        igc.getGraph().removeVertex(line);
       
       
       
        //now, the other GOTO lines coming in should all be CONTINUE statements...
        for(GoToIntermediate gotoIntermediate : incomingGotoNested) {
          Continue continueExpression = new Continue(gotoIntermediate.getInstruction());
          StatementIntermediate continueIntermediate = new StatementIntermediate(gotoIntermediate.getInstruction(), continueExpression);

          //add the node...
          igc.getGraph().addVertex(continueIntermediate);
          igc.redirectPredecessors(gotoIntermediate, continueIntermediate);
          //remove vertex.
          igc.getGraph().removeVertex(gotoIntermediate);
         
          //now, add line to the loop.
          igc.getGraph().addEdge(continueIntermediate, whileIntermediate);
        }
       
        updateEdges(whileIntermediate);
      }
    }
  }
 
  protected GoToIntermediate getCandidateGoto(TreeSet<GoToIntermediate> incomingGotoNonNested, TreeSet<GoToIntermediate> incomingGotoNested) {
    return incomingGotoNonNested.pollLast();
  }
 
  protected void updateEdges(WhileIntermediate wi) {
    List<AbstractIntermediate> predecessors = igc.getPredecessors(wi);
    for(AbstractIntermediate predecessor : predecessors) {
      IntermediateEdge ie = igc.getGraph().getEdge(predecessor, wi);
      igc.validateBackEdge(ie);
    }
    List<AbstractIntermediate> successors = igc.getSuccessors(wi);
    for(AbstractIntermediate successor : successors) {
      IntermediateEdge ie = igc.getGraph().getEdge(wi, successor);
      igc.validateBackEdge(ie);
    }
  }

  protected boolean isNested(BooleanBranchIntermediate ci, AbstractIntermediate ai)
  {
    int max = igc.getFalseTarget(ci).getInstruction().getPosition();
    int min = igc.getTrueTarget(ci).getInstruction().getPosition();
   
    return (ai.getInstruction().getPosition() <= max && ai.getInstruction().getPosition() >= min);
   
   
  }
 
}
TOP

Related Classes of org.candle.decompiler.intermediate.graph.enhancer.ConditionToWhileLoop

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.