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

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

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

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.apache.bcel.generic.CodeExceptionGen;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.candle.decompiler.intermediate.code.AbstractIntermediate;
import org.candle.decompiler.intermediate.code.BooleanBranchIntermediate;
import org.candle.decompiler.intermediate.code.CatchIntermediate;
import org.candle.decompiler.intermediate.code.FinallyIntermediate;
import org.candle.decompiler.intermediate.code.GoToIntermediate;
import org.candle.decompiler.intermediate.code.StatementIntermediate;
import org.candle.decompiler.intermediate.code.TryIntermediate;
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.traverse.BreadthFirstIterator;

public class RetractDuplicateFinally extends GraphIntermediateVisitor {

  private static final Log LOG = LogFactory.getLog(RetractDuplicateFinally.class);
 
  public RetractDuplicateFinally(IntermediateGraphContext igc) {
    super(igc);
  }
 
  @Override
  public void visitFinallyIntermediate(FinallyIntermediate line) {
    //TODO: Remove the highest finally statements first; won't fit this visitor
    //pattern.
   
   
    //get the bounds of the finally... associate the try.
   
    //finally is part of the try if the try + catch bounds has:
    //Try[0,13]
    //Catch[19,50]
    //Catch[56,65]
    //Finally | Handler[56, 65]| Handler[0, 42] |  | Range[66, 76]
   
    //in the case above, finally should match because lower bound == finally lower handler bound.
    //and upper bound of Catch matches upper bound of Finally Handler.
   
    //first, match the Try block that applies...
   
    //get lowest bound.
    InstructionHandle min = getLowestBound(line.getCodeExceptions());
    InstructionHandle max = getHighestBound(line.getCodeExceptions());
   
    LOG.debug("Finally Range: "+min.getPosition() + " -> "+max.getPosition());
   
    TryIntermediate matched = matchTryBlock(min, max);
    if(matched != null) {
      final Set<Integer> offsets = collectOffsets(line);
      //ok, now we need to eliminate finally blocks from this try and all of the catches.  thanks Java!
      List<CatchIntermediate> catchClauses = igc.getCatchClauses(matched);
      //for each catch clause...
      for(CatchIntermediate catchClause : catchClauses) {
        processCatch(catchClause, line, offsets);
      }
     
      processTry(matched, line, offsets);
    }
   
    //now, add the edge between end of FINALLY and the next statement.
    InstructionHandle finallyEnd = line.getBlockRange().getEnd();
    //get the next.. then search for next node in graph.
   
    AbstractIntermediate finallyLast = igc.findNextNode(finallyEnd);
    AbstractIntermediate afterFinally = igc.findNextNode(finallyEnd.getNext());
   
    igc.redirectPredecessors(finallyLast, afterFinally);
    igc.getGraph().removeVertex(finallyLast);
  }
 
  protected void processTry(TryIntermediate tryIntermediate, FinallyIntermediate finallyIntermediate, Set<Integer> offsets) {
    //ok, now let's handle the try...
    InstructionHandle end = tryIntermediate.getBlockRange().getEnd();
    //next should be GOTO.
    AbstractIntermediate tryEndNode = igc.findNextNode(end);
   
    AbstractIntermediate gotoIntermediate = null;
    //check to see if this is loop...
    if(tryEndNode instanceof StatementIntermediate) {
      LOG.debug("Position: "+tryEndNode.getInstruction().getPosition()+" Value: "+tryEndNode);
      gotoIntermediate = igc.getSingleSuccessor(tryEndNode);
    }
    else if(tryEndNode instanceof BooleanBranchIntermediate) {
      BooleanBranchIntermediate bbi = (BooleanBranchIntermediate)tryEndNode;
     
      //find higher target...
      AbstractIntermediate trueTarget = igc.getTrueTarget(bbi);
      AbstractIntermediate falseTarget = igc.getFalseTarget(bbi);
     
      int trueTargetPosition = trueTarget.getInstruction().getPosition();
      int falseTargetPosition = falseTarget.getInstruction().getPosition();
     
      gotoIntermediate = (trueTargetPosition > falseTargetPosition) ? trueTarget : falseTarget;
    }
   
    //validate it is a GOTO.
    if(!(gotoIntermediate instanceof GoToIntermediate)) {
      LOG.warn("Expected GOTO.  But this isn't: "+gotoIntermediate);
    }
    else {
      AbstractIntermediate tryFinallyFirst = igc.getSingleSuccessor(gotoIntermediate);
      eliminateNode(tryFinallyFirst, offsets);
     
      //now, eliminate the GOTO.
      igc.getGraph().removeVertex(gotoIntermediate);
      igc.getGraph().addEdge(tryIntermediate, finallyIntermediate);
    }
  }
 
  protected void processCatch(CatchIntermediate catchIntermediate, FinallyIntermediate finallyIntermediate, Set<Integer> offsets) {
    for(CodeExceptionGen ceg : finallyIntermediate.getCodeExceptions()) {
      int position = ceg.getEndPC().getPosition();
      if(catchIntermediate.getBlockRange().containsNumber(position))  {
        LOG.debug("Relevant: "+position);
       
        //we found the relevant position, now we need to find the next...
        AbstractIntermediate lastNode = igc.findNextNode(ceg.getEndPC());
       
        AbstractIntermediate finallyStart = igc.getSingleSuccessor(lastNode);
        LOG.debug("Finally start: "+finallyStart);
       
        //start eliminating nodes from this point.
        eliminateNode(finallyStart, offsets);
      }
    }
   
   
  }
 
  protected Set<Integer> collectOffsets(AbstractIntermediate line) {
    //this is the finally template.
    AbstractIntermediate first = igc.getSingleSuccessor(line);
    //now, store the instruction position.
    int position = first.getInstruction().getPosition();
   
    BreadthFirstIterator<AbstractIntermediate, IntermediateEdge> bfi = new BreadthFirstIterator<AbstractIntermediate, IntermediateEdge>(igc.getGraph(), first);
   
    Set<Integer> offsets = new TreeSet<Integer>();
    while(bfi.hasNext()) {
      AbstractIntermediate next = bfi.next();
      int nextPosition = next.getInstruction().getPosition();
     
      int offset = nextPosition - position;
      LOG.debug("Offset: "+offset);
      offsets.add(offset);
    }
   
    return offsets;
  }
 
  protected void eliminateNode(AbstractIntermediate first, Set<Integer> offsets) {
    InstructionHandle ih = first.getInstruction();
    int position = first.getInstruction().getPosition();
 
    for(Integer offset : offsets) {
      int target = position + offset;
     
      ih = igc.getInstructionHandle(target);
      if(ih == null) {
        LOG.warn("Not found expected InstructionHandle: "+(position+offset));
        continue;
      }
     
      //loop through...
      AbstractIntermediate ai = igc.findNextNode(ih);
      if(ai.getInstruction().getPosition() == target) {
        igc.getGraph().removeVertex(ai);
      }
      else {
        LOG.warn("Did not find vertex: "+target);
      }
    }
  }
 
 
 
  protected TryIntermediate matchTryBlock(InstructionHandle min, InstructionHandle max) {
    LinkedList<TryIntermediate> matches = new LinkedList<TryIntermediate>();
    //find the try block...
    for(AbstractIntermediate ai : igc.getGraph().vertexSet()) {
      if(ai instanceof TryIntermediate) {
        TryIntermediate tryIntermediate = ((TryIntermediate) ai);
        LOG.debug("Finally: "+tryIntermediate+ " , "+tryIntermediate.getInstruction().getPosition()+" , "+tryIntermediate.getBlockRange().getStart());
        if(tryIntermediate.getBlockRange().getStart().getPosition() == min.getPosition()) {
         
          //only add where max > try's max range...
          if(tryIntermediate.getBlockRange().getEnd().getPosition() < max.getPosition()) {
            matches.add(tryIntermediate);
          }
        }
      }
    }
   
    //return the smaller range...
    if(matches.size() > 0) {
      Collections.sort(matches, new Comparator<TryIntermediate>() {
        @Override
        public int compare(TryIntermediate t1, TryIntermediate t2) {
          if(t1.getBlockRange().getEnd().getPosition() > t2.getBlockRange().getEnd().getPosition()) {
            return -1;
          }
          return 0;
        }
      });
      LOG.debug("Match: "+matches.peekFirst()+" Range: "+matches.peekFirst().getBlockRange());
      return matches.getFirst();
    }
   
    return null;
  }

  protected InstructionHandle getHighestBound(Collection<CodeExceptionGen> cegs) {
    InstructionHandle highest = null;
    for(CodeExceptionGen ceg : cegs) {
      if(highest != null) {
        if(ceg.getEndPC().getPosition() > highest.getPosition()) {
          highest = ceg.getEndPC();
        }
      }
      else {
        highest = ceg.getEndPC();
      }
    }
   
    return highest;
  }
 
  protected InstructionHandle getLowestBound(Collection<CodeExceptionGen> cegs) {
    InstructionHandle lowest = null;
    for(CodeExceptionGen ceg : cegs) {
      if(lowest != null) {
        if(ceg.getStartPC().getPosition() < lowest.getPosition()) {
          lowest = ceg.getStartPC();
        }
      }
      else {
        lowest = ceg.getStartPC();
      }
    }
   
    return lowest;
  }
}
TOP

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

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.