FindDuplicateSequences.java :  » Code-Analyzer » soot » soot » jbco » bafTransformations » Java Open Source

Java Open Source » Code Analyzer » soot 
soot » soot » jbco » bafTransformations » FindDuplicateSequences.java
/* Soot - a J*va Optimization Framework
 * Copyright (C) 1997-1999 Raja Vallee-Rai
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

package soot.jbco.bafTransformations;

import java.util.*;

import soot.*;
import soot.baf.*;
import soot.jbco.IJbcoTransform;
import soot.jimple.*;
import soot.util.*;
import soot.toolkits.graph.*;

/**
 * @author Michael Batchelder
 * 
 * Created on 12-May-2006
 */
public class FindDuplicateSequences extends BodyTransformer implements IJbcoTransform {

  int totalcounts[] = new int[512];
  
  public static String dependancies[] = new String[] {"bb.jbco_j2bl", "bb.jbco_rds", "bb.jbco_ful", "bb.lp" };

  public String[] getDependancies() {
    return dependancies;
  }
  
  public static String name = "bb.jbco_rds";
  
  public String getName() {
    return name;
  }
  
  public void outputSummary() {
    out.println("Duplicate Sequences:");
    for (int count = totalcounts.length - 1; count >= 0; count--)
      if (totalcounts[count] > 0)
          out.println("\t"+ count + " total: " + totalcounts[count]);
  }
  
  protected void internalTransform(Body b, String phaseName, Map options) {
    
    int weight = soot.jbco.Main.getWeight(phaseName, b.getMethod().getSignature());
    if (weight == 0) return;
    
    if (output)
      out.println("Checking " + b.getMethod().getName()
          + " for duplicate sequences..");

    ArrayList<Unit> illegalUnits = new ArrayList<Unit>();
    ArrayList seenUnits = new ArrayList();
    ArrayList workList = new ArrayList();
    PatchingChain units = b.getUnits();
    BriefUnitGraph bug = new BriefUnitGraph(b);
    workList.addAll(bug.getHeads());
    while (workList.size()>0) {
      Unit u = (Unit)workList.remove(0);
      if (seenUnits.contains(u))
        continue;
      
      if (u instanceof NewInst) {
        RefType t = ((NewInst)u).getBaseType();
        ArrayList tmpWorkList = new ArrayList();
        tmpWorkList.add(u);
        while (tmpWorkList.size() > 0) {
          Unit v = (Unit)tmpWorkList.remove(0);
          
          // horrible approximatin about which init call belongs to which new
          if (v instanceof SpecialInvokeInst) {
            SpecialInvokeInst si = (SpecialInvokeInst)v;
            if (si.getMethodRef().getSignature().indexOf("void <init>") < 0
                || si.getMethodRef().declaringClass() != t.getSootClass())
              tmpWorkList.addAll(bug.getSuccsOf(v));
          } else {
            tmpWorkList.addAll(bug.getSuccsOf(v));
          }
          illegalUnits.add(v);
        }
      }
      
      seenUnits.add(u);
      workList.addAll(bug.getSuccsOf(u));
    }
    seenUnits = null;
    
    int controlLocalIndex = 0;
    int longestSeq = (units.size() / 2) - 1;
    if (longestSeq > 20) 
      longestSeq = 20;
    
    Local controlLocal = null;
    Chain bLocals = b.getLocals();
    int counts[] = new int[longestSeq + 1];
    //ArrayList protectedUnits = new ArrayList();
    HashMap bafToJLocals = soot.jbco.Main.methods2Baf2JLocals.get(b.getMethod());
    boolean changed = true;
    HashMap stackHeightsBefore = null;
    for (int count = longestSeq; count > 2; count--) 
    {
      Object uArry[] = units.toArray();
      if (uArry.length <= 0)
        return;

      //int count = uArry.length > 100 ? 4 : uArry.length > 50 ? 3 : 2;

      ArrayList<ArrayList<Unit>> candidates = new ArrayList<ArrayList<Unit>>();
      ArrayList<Object> unitIDs = new ArrayList<Object>();
      
      if (changed) {
        stackHeightsBefore = StackTypeHeightCalculator
          .calculateStackHeights(b,bafToJLocals);
        bug = StackTypeHeightCalculator.bug;
        changed = false;
      }
      
      LOOP:
      for (int i = 0; i < uArry.length; i++) {
        unitIDs.add(uArry[i]);

        if (i + count > uArry.length) 
          continue;
        
        ArrayList<Unit> seq = new ArrayList<Unit>();
        for (int j = 0; j < count; j++) {
          Unit u = (Unit)uArry[i + j];
          if (u instanceof IdentityInst || u instanceof ReturnInst || illegalUnits.contains(u))
            break;

          // don't allow units within the sequence that have more than one
          // predecessor that is not _within_ the sequence
          if (j > 0) {
            List preds = bug.getPredsOf(u);
            if (preds.size()>0) {
              int found = 0;
              Iterator pit = preds.iterator();
              while (pit.hasNext()) {
                Unit p = (Unit)pit.next();
                for (int jj = 0; jj < count; jj++) {
                  if (p == uArry[i+jj]) {
                    found++;
                    break;
                  }
                }
              }
              if (found<preds.size())
                continue LOOP;
            }
          }      

          seq.add(u);
        }
        if (seq.size() == count) {
          if (seq.get(seq.size() - 1).fallsThrough())
            candidates.add(seq);
        }
      }

      HashMap<ArrayList, ArrayList<ArrayList<Object>>> selected = new HashMap<ArrayList, ArrayList<ArrayList<Object>>>();
      for (int i = 0; i < candidates.size(); i++) {
        ArrayList seq = candidates.get(i);
        ArrayList<ArrayList<Object>> matches = new ArrayList<ArrayList<Object>>();
        for (int j = 0; j < (uArry.length - count); j++) {
          if (overlap(uArry, seq, j, count))
            continue;
          
          boolean found = false;
          for (int k = 0; k < count; k++) {
            Unit u = (Unit) seq.get(k);

            found = false;
            
            Unit v = (Unit)uArry[j + k];
            if (!equalUnits(u, v, b) || illegalUnits.contains(v))
              break;

            if (k > 0) {
              List preds = bug.getPredsOf(v);
              if (preds.size()>0) {
                int fcount = 0;
                Iterator pit = preds.iterator();
                while (pit.hasNext()) {
                  Unit p = (Unit)pit.next();
                  for (int jj = 0; jj < count; jj++) {
                    if (p == uArry[j+jj]) {
                      fcount++;
                      break;
                    }
                  }
                }
                if (fcount<preds.size())
                  break;
              }
            }  
            
            // No need to calc AFTER stack, since they are equal units            
            if (!stackHeightsBefore.get(u).equals(stackHeightsBefore.get(v)))
              break;

            found = true;
          }

          if (found) {
            ArrayList<Object> foundSeq = new ArrayList<Object>();
            for (int m = 0; m < count; m++)
              foundSeq.add(uArry[j + m]);
            matches.add(foundSeq);
          }
        }

        if (matches.size() > 0) {
          boolean done = false;
          for (int x = 0; x < seq.size(); x++)
            if (!unitIDs.contains(seq.get(x)))
              done = true;
            else
              unitIDs.remove(seq.get(x));

          if (!done) {
            matches = cullOverlaps(b, unitIDs, matches);
            if (matches.size()>0) 
              selected.put(seq, matches);
          }
        }
      }

      if (selected.size() <= 0)
        continue;

      Iterator<ArrayList> keys = selected.keySet().iterator();
      while (keys.hasNext()) {
        ArrayList key = keys.next();
        ArrayList avalues = selected.get(key);
        if (avalues.size() < 1 || soot.jbco.util.Rand.getInt(10) <= weight)
          continue;

        changed = true;
        
        controlLocal = Baf.v().newLocal(
            "controlLocalfordups" + controlLocalIndex, IntType.v());
        bLocals.add(controlLocal);
        bafToJLocals.put(controlLocal,Jimple.v().newLocal("controlLocalfordups" + controlLocalIndex++, IntType.v()));

        counts[key.size()] += avalues.size();

        ArrayList jumps = new ArrayList();

        Unit first = (Unit) key.get(0);
        //protectedUnits.addAll(key);

        Unit store = Baf.v().newStoreInst(IntType.v(), controlLocal);
        //protectedUnits.add(store);

        units.insertBefore(store, first);

        Unit pushUnit = Baf.v().newPushInst(IntConstant.v(0));
        //protectedUnits.add(pushUnit);

        units.insertBefore(pushUnit, store);

        int index = 1;
        Iterator values = avalues.iterator();
        while (values.hasNext()) {
          ArrayList next = (ArrayList) values.next();
          Unit jump = (Unit) units.getSuccOf(next.get(next.size() - 1));
          //protectedUnits.add(jump);

          Unit firstt = (Unit) next.get(0);
          Unit storet = (Unit) store.clone();
          //protectedUnits.add(storet);

          units.insertBefore(storet, firstt);

          pushUnit = Baf.v().newPushInst(IntConstant.v(index++));
          //protectedUnits.add(pushUnit);

          units.insertBefore(pushUnit, storet);

          Unit goUnit = Baf.v().newGotoInst(first);
          //protectedUnits.add(goUnit);

          units.insertAfter(goUnit, storet);
          jumps.add(jump);
        }

        Unit insertAfter = (Unit) key.get(key.size() - 1);
        //protectedUnits.add(insertAfter);

        Unit swUnit = Baf.v().newTableSwitchInst(
            (Unit) units.getSuccOf(insertAfter), 1, jumps.size(), jumps);
        //protectedUnits.add(swUnit);

        units.insertAfter(swUnit, insertAfter);

        Unit loadUnit = Baf.v().newLoadInst(IntType.v(), controlLocal);
        //protectedUnits.add(loadUnit);

        units.insertAfter(loadUnit, insertAfter);

        values = avalues.iterator();
        while (values.hasNext()) {
          ArrayList next = (ArrayList) values.next();
          units.removeAll(next);
          //protectedUnits.removeAll(next);
        }
      }
    } // end of for loop for duplicate seq of various length
    
    boolean dupsExist = false;
    if (output)
      System.out.println("Duplicate Sequences for " + b.getMethod().getName());

    for (int count = longestSeq; count >= 0; count--)
      if (counts[count] > 0) {
        if (output)
          out.println(count + " total: " + counts[count]);
        dupsExist = true;
        totalcounts[count] += counts[count];
      }

    if (!dupsExist) {
      if (output)
        out.println("\tnone");
    } else if (debug) {
        StackTypeHeightCalculator.calculateStackHeights(b);
    }
  }

  private boolean equalUnits(Object o1, Object o2, Body b) {
    if (o1.getClass() != o2.getClass())
      return false;

    // this is actually handled by the predecessor checks
    
    // if units are targets of different jumps then not equal
    //if (!((Unit)o1).getBoxesPointingToThis().equals(
    //    ((Unit)o2).getBoxesPointingToThis()))
    //  return false;
      
    List<Trap> l1 = getTrapsForUnit(o1,b);
    List<Trap> l2 = getTrapsForUnit(o2,b);
    if (l1.size() != l2.size()) 
      return false;
    else {
      for (int i = 0; i < l1.size(); i++)
        if (l1.get(i) != l2.get(i)) return false;
    }
    
    if (o1 instanceof NoArgInst)
      return true;

    /*
    if (o1 instanceof IncInst) {
      IncInst ii = (IncInst)o1;
      if (ii.getLocal() != ((IncInst)o2).getLocal() || ii.getConstant() != ((IncInst)o2).getConstant())
        return false;
      return true;
    }*/
    
    if (o1 instanceof TargetArgInst) {
      //return false;
      //Maybe shouldn't allow duplicate target units?
      if (o1 instanceof OpTypeArgInst) 
          return ((TargetArgInst)o1).getTarget() == ((TargetArgInst)o2).getTarget() 
          && ((OpTypeArgInst)o1).getOpType() == ((OpTypeArgInst)o2).getOpType(); 
      else return
        ((TargetArgInst)o1).getTarget() == ((TargetArgInst)o2).getTarget();
    }

    if (o1 instanceof OpTypeArgInst)
      return ((OpTypeArgInst) o1).getOpType() == ((OpTypeArgInst) o2)
          .getOpType();

    if (o1 instanceof MethodArgInst)
      return ((MethodArgInst) o1).getMethod() == ((MethodArgInst) o2)
          .getMethod();

    if (o1 instanceof FieldArgInst)
      return ((FieldArgInst) o1).getField() == ((FieldArgInst) o2).getField();

    if (o1 instanceof PrimitiveCastInst) {
      return ((PrimitiveCastInst) o1).getFromType() == ((PrimitiveCastInst) o2)
          .getFromType()
          && ((PrimitiveCastInst) o1).getToType() == ((PrimitiveCastInst) o2)
              .getToType();
    }

    if (o1 instanceof DupInst)
      return compareDups(o1, o2);

    if (o1 instanceof LoadInst)
      return ((LoadInst) o1).getLocal() == ((LoadInst) o2).getLocal();
    
    if (o1 instanceof StoreInst)
      return ((StoreInst) o1).getLocal() == ((StoreInst) o2).getLocal();

    if (o1 instanceof PushInst)
      return equalConstants(((PushInst) o1).getConstant(), ((PushInst) o2)
          .getConstant());

    if (o1 instanceof IncInst)
      if (equalConstants(((IncInst) o1).getConstant(), ((IncInst) o2)
          .getConstant()))
        return (((IncInst) o1).getLocal() == ((IncInst) o2).getLocal());

    if (o1 instanceof InstanceCastInst)
      return equalTypes(((InstanceCastInst) o1).getCastType(),
          ((InstanceCastInst) o2).getCastType());

    if (o1 instanceof InstanceOfInst)
      return equalTypes(((InstanceOfInst) o1).getCheckType(),
          ((InstanceOfInst) o2).getCheckType());

    if (o1 instanceof NewArrayInst)
      return equalTypes(((NewArrayInst) o1).getBaseType(), ((NewArrayInst) o2)
          .getBaseType());

    if (o1 instanceof NewInst)
      return equalTypes(((NewInst) o1).getBaseType(), ((NewInst) o2)
          .getBaseType());

    if (o1 instanceof NewMultiArrayInst)
      return equalTypes(((NewMultiArrayInst) o1).getBaseType(),
          ((NewMultiArrayInst) o2).getBaseType())
          && ((NewMultiArrayInst) o1).getDimensionCount() == ((NewMultiArrayInst) o2)
              .getDimensionCount();

    if (o1 instanceof PopInst)
      return ((PopInst) o1).getWordCount() == ((PopInst) o2).getWordCount();

    if (o1 instanceof SwapInst) {
      return ((SwapInst) o1).getFromType() == ((SwapInst) o2).getFromType()
          && ((SwapInst) o1).getToType() == ((SwapInst) o2).getToType();
    }

    return false;
  }
  
  private List<Trap> getTrapsForUnit(Object o, Body b) {
    ArrayList<Trap> list = new ArrayList<Trap>();
    Chain traps = b.getTraps();
    if (traps.size() != 0) {
      PatchingChain units = b.getUnits();
      Iterator it = traps.iterator();
      while (it.hasNext()) {
        Trap t = (Trap)it.next();
        Iterator tit = units.iterator(t.getBeginUnit(),t.getEndUnit());
        while (tit.hasNext()) {
          if (tit.next() == o) {
            list.add(t);
            break;
          }
        }
      }
    }
    return list;
  }

  private boolean overlap(Object units[], List list, int idx, int count) {
    if (idx < 0 || list == null || list.size() == 0)
      return false;
    
    Object first = list.get(0);
    Object last = list.get(list.size()-1);
    for (int i = idx; i < idx + count; i++)
      if (i < units.length && (first == units[i] || last == units[i]))
        return true;

    return false;
  }

  private boolean equalConstants(Constant c1, Constant c2) {
    Type t = c1.getType();
    if (t != c2.getType())
      return false;

    if (t instanceof IntType)
      return ((IntConstant) c1).value == ((IntConstant) c2).value;

    if (t instanceof FloatType)
      return ((FloatConstant) c1).value == ((FloatConstant) c2).value;

    if (t instanceof LongType)
      return ((LongConstant) c1).value == ((LongConstant) c2).value;

    if (t instanceof DoubleType)
      return ((DoubleConstant) c1).value == ((DoubleConstant) c2).value;

    if (c1 instanceof StringConstant && c2 instanceof StringConstant)
      return ((StringConstant) c1).value == ((StringConstant) c2).value;

    return c1 instanceof NullConstant && c2 instanceof NullConstant;
  }

  private boolean compareDups(Object o1, Object o2) {
    DupInst d1 = (DupInst) o1;
    DupInst d2 = (DupInst) o2;

    List<Type> l1 = d1.getOpTypes();
    List<Type> l2 = d2.getOpTypes();
    for (int k = 0; k < 2; k++) {
      if (k == 1) {
        l1 = d1.getUnderTypes();
        l2 = d2.getUnderTypes();
      }
      if (l1.size() != l2.size())
        return false;

      for (int i = 0; i < l1.size(); i++)
        if (l1.get(i) != l2.get(i))
          return false;
    }

    return true;
  }

  private boolean equalTypes(Type t1, Type t2) {
    if (t1 instanceof RefType) {
      if (t2 instanceof RefType) {
        // TODO: more discerning comparison here?
        RefType rt1 = (RefType) t1;

        return rt1.compareTo(t2) == 0;
      }
      return false;
    }

    if (t1 instanceof PrimType && t2 instanceof PrimType)
      return t1.getClass() == t2.getClass();

    return false;
  }

  private static ArrayList<ArrayList<Object>> cullOverlaps(Body b, ArrayList<Object> ids, ArrayList<ArrayList<Object>> matches) {
    ArrayList<ArrayList<Object>> newMatches = new ArrayList<ArrayList<Object>>();
    for (int i = 0; i < matches.size(); i++) {
      ArrayList<Object> match = matches.get(i);
      Iterator<Object> it = match.iterator();
      boolean clean = true;
      while (it.hasNext()) {
        if (!ids.contains(it.next())) {
          clean = false;
          break;
        }
      }
      if (clean) {
        List targs = b.getUnitBoxes(true);
        for (int j = 0; j < targs.size() && clean; j++) {
          Unit u = ((UnitBox) targs.get(j)).getUnit();
          it = match.iterator();
          while (it.hasNext()) {
            if (u == it.next()) {
              clean = false;
              break;
            }
          }
        }
      }

      if (clean) {
        it = match.iterator();
        while (it.hasNext())
          ids.remove(it.next());
        newMatches.add(match);
      }
    }
    return newMatches;
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.