All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.jimple.toolkits.pointer.CastCheckEliminator Maven / Gradle / Ivy

package soot.jimple.toolkits.pointer;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 2003 - 2004 Ondrej Lhotak
 * %%
 * This program 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 program 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import soot.Local;
import soot.RefType;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.ValueBox;
import soot.jimple.AssignStmt;
import soot.jimple.CastExpr;
import soot.jimple.ConditionExpr;
import soot.jimple.EqExpr;
import soot.jimple.IfStmt;
import soot.jimple.InstanceOfExpr;
import soot.jimple.IntConstant;
import soot.jimple.NeExpr;
import soot.jimple.NewExpr;
import soot.jimple.NullConstant;
import soot.jimple.Stmt;
import soot.toolkits.graph.BriefUnitGraph;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.ForwardBranchedFlowAnalysis;

/** A flow analysis that detects redundant cast checks. */
public class CastCheckEliminator extends ForwardBranchedFlowAnalysis {
  Map unitToKill = new HashMap();
  Map unitToGenFallThrough = new HashMap();
  Map unitToGenBranch = new HashMap();
  LocalTypeSet emptySet;

  public CastCheckEliminator(BriefUnitGraph cfg) {
    super(cfg);
    makeInitialSet();
    doAnalysis();
    tagCasts();
  }

  /** Put the results of the analysis into tags in cast statements. */
  protected void tagCasts() {
    for (Iterator sIt = ((UnitGraph) graph).getBody().getUnits().iterator(); sIt.hasNext();) {
      final Stmt s = (Stmt) sIt.next();
      if (s instanceof AssignStmt) {
        AssignStmt as = (AssignStmt) s;
        Value rhs = as.getRightOp();
        if (rhs instanceof CastExpr) {
          CastExpr cast = (CastExpr) rhs;
          Type t = cast.getCastType();
          if (t instanceof RefType) {
            if (cast.getOp() instanceof Local) {
              Local l = (Local) cast.getOp();
              LocalTypeSet set = (LocalTypeSet) getFlowBefore(s);
              s.addTag(new CastCheckTag(set.get(set.indexOf(l, (RefType) t))));
            } else {
              NullConstant nc = (NullConstant) cast.getOp();
              s.addTag(new CastCheckTag(true));
            }
          }
        }
      }
    }
  }

  /**
   * Find all the locals of reference type and all the types used in casts to initialize the mapping from locals and types to
   * bits in the bit vector in LocalTypeSet.
   */
  protected void makeInitialSet() {
    // Find all locals of reference type
    Collection locals = ((UnitGraph) graph).getBody().getLocals();
    List refLocals = new ArrayList();
    for (Iterator lIt = locals.iterator(); lIt.hasNext();) {
      final Local l = (Local) lIt.next();
      if (l.getType() instanceof RefType) {
        refLocals.add(l);
      }
    }

    // Find types of all casts
    List types = new ArrayList();
    for (Iterator sIt = ((UnitGraph) graph).getBody().getUnits().iterator(); sIt.hasNext();) {
      final Stmt s = (Stmt) sIt.next();
      if (s instanceof AssignStmt) {
        AssignStmt as = (AssignStmt) s;
        Value rhs = as.getRightOp();
        if (rhs instanceof CastExpr) {
          Type t = ((CastExpr) rhs).getCastType();
          if (t instanceof RefType && !types.contains(t)) {
            types.add(t);
          }
        }
      }
    }

    emptySet = new LocalTypeSet(refLocals, types);
  }

  /** Returns a new, aggressive (local,type) set. */
  @Override
  protected LocalTypeSet newInitialFlow() {
    LocalTypeSet ret = (LocalTypeSet) emptySet.clone();
    ret.setAllBits();
    return ret;
  }

  /** This is the flow function as described in the assignment write-up. */
  @Override
  protected void flowThrough(LocalTypeSet in, Unit unit, List outFallValues,
      List outBranchValues) {
    final LocalTypeSet out = (LocalTypeSet) in.clone();
    LocalTypeSet outBranch = out; // aliased to out unless unit is IfStmt
    final Stmt stmt = (Stmt) unit;

    // First kill all locals defined in this statement
    for (Iterator bIt = stmt.getDefBoxes().iterator(); bIt.hasNext();) {
      final ValueBox b = (ValueBox) bIt.next();
      Value v = b.getValue();
      if (v instanceof Local && v.getType() instanceof RefType) {
        out.killLocal((Local) v);
      }
    }

    // An AssignStmt may be a new, a simple copy, or a cast
    if (stmt instanceof AssignStmt) {
      AssignStmt astmt = (AssignStmt) stmt;
      Value rhs = astmt.getRightOp();
      Value lhs = astmt.getLeftOp();
      if (lhs instanceof Local && rhs.getType() instanceof RefType) {
        Local l = (Local) lhs;
        if (rhs instanceof NewExpr) {
          out.localMustBeSubtypeOf(l, (RefType) rhs.getType());
        } else if (rhs instanceof CastExpr) {
          CastExpr cast = (CastExpr) rhs;
          Type castType = cast.getCastType();
          if (castType instanceof RefType && cast.getOp() instanceof Local) {
            RefType refType = (RefType) castType;
            Local opLocal = (Local) cast.getOp();
            out.localCopy(l, opLocal);
            out.localMustBeSubtypeOf(l, refType);
            out.localMustBeSubtypeOf(opLocal, refType);
          }
        } else if (rhs instanceof Local) {
          out.localCopy(l, (Local) rhs);
        }
      }

      // Handle if statements
    } else if (stmt instanceof IfStmt) {
      IfStmt ifstmt = (IfStmt) stmt;

      // This do ... while(false) is here so I can break out of it rather
      // than having to have seven nested if statements. Silly people who
      // took goto's out of the language...  
      do {
        if (graph.getPredsOf(stmt).size() != 1) {
          break;
        }
        Object predecessor = graph.getPredsOf(stmt).get(0);
        if (!(predecessor instanceof AssignStmt)) {
          break;
        }
        AssignStmt pred = (AssignStmt) predecessor;
        if (!(pred.getRightOp() instanceof InstanceOfExpr)) {
          break;
        }
        InstanceOfExpr iofexpr = (InstanceOfExpr) pred.getRightOp();
        if (!(iofexpr.getCheckType() instanceof RefType)) {
          break;
        }
        if (!(iofexpr.getOp() instanceof Local)) {
          break;
        }
        ConditionExpr c = (ConditionExpr) ifstmt.getCondition();
        if (!c.getOp1().equals(pred.getLeftOp())) {
          break;
        }
        if (!(c.getOp2() instanceof IntConstant)) {
          break;
        }
        if (((IntConstant) c.getOp2()).value != 0) {
          break;
        }
        if (c instanceof NeExpr) {
          // The IfStmt is like this:
          // if x instanceof t goto somewhere_else
          // So x is of type t on the taken branch
          outBranch = (LocalTypeSet) out.clone();
          outBranch.localMustBeSubtypeOf((Local) iofexpr.getOp(), (RefType) iofexpr.getCheckType());
        } else if (c instanceof EqExpr) {
          // The IfStmt is like this:
          // if !(x instanceof t) goto somewhere_else
          // So x is of type t on the fallthrough branch
          outBranch = (LocalTypeSet) out.clone();
          out.localMustBeSubtypeOf((Local) iofexpr.getOp(), (RefType) iofexpr.getCheckType());
        }
      } while (false);
    }

    // Now copy the computed (local,type) set to all successors
    for (Iterator it = outFallValues.iterator(); it.hasNext();) {
      copy(out, it.next());
    }
    for (Iterator it = outBranchValues.iterator(); it.hasNext();) {
      copy(outBranch, it.next());
    }
  }

  @Override
  protected void copy(LocalTypeSet s, LocalTypeSet d) {
    d.and(s);
    d.or(s);
  }

  // The merge operator is set intersection.
  @Override
  protected void merge(LocalTypeSet in1, LocalTypeSet in2, LocalTypeSet o) {
    o.setAllBits();
    o.and(in1);
    o.and(in2);
  }

  /** Returns a new, aggressive (local,type) set. */
  @Override
  protected LocalTypeSet entryInitialFlow() {
    LocalTypeSet ret = (LocalTypeSet) emptySet.clone();
    return ret;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy