Package dk.brics.xact.analysis.soot

Source Code of dk.brics.xact.analysis.soot.ArrayConstantAnalysis

package dk.brics.xact.analysis.soot;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import soot.ArrayType;
import soot.Local;
import soot.Unit;
import soot.ValueBox;
import soot.jimple.ArrayRef;
import soot.jimple.DefinitionStmt;
import soot.jimple.IntConstant;
import soot.jimple.NewArrayExpr;
import soot.jimple.Stmt;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.scalar.ForwardFlowAnalysis;

/**
* Determines for each program point the arrays whose exact contents are known in terms
* of other local variables.
* <p/>
* The analysis is specifically designed to handle the bytecode produced by inline array initializers
* (see example) and not much of anything else. Example of inline array initializer:
* <pre>
* XML[] array = new XML[] { xml1, xml2, xml3 }; // explicit
* XML y = XML.concat(xml1, xml2, xml3); // implicit
* </pre>
*/
public class ArrayConstantAnalysis extends ForwardFlowAnalysis<Unit,Map<Local,ArrayConstantInfo>> {

  // bottom is represented by not being in the keyset
  // top is represented by mapping to ArrayConstantInfo with contents=null
 
  public ArrayConstantAnalysis(DirectedGraph<Unit> graph) {
    super(graph);
    doAnalysis();
  }

  @Override
  protected void flowThrough(
      Map<Local, ArrayConstantInfo> src,
      Unit unit,
      Map<Local, ArrayConstantInfo> dest) {
    Stmt stmt = (Stmt)unit;
    final Set<Local> dead = new HashSet<Local>();
    srcloop:
    for (Local local : src.keySet()) {
      ArrayConstantInfo info = src.get(local);
      if (info.contents == null) {
          dead.add(local);
        continue;
      }
      ValueBox allowedBox = null; // the only place the statement is allowed to reference an array without breaking it
      boolean affected = false;
      if (stmt instanceof DefinitionStmt) {
        DefinitionStmt def = (DefinitionStmt)stmt;
        if (def.getLeftOp() instanceof ArrayRef) {
          ArrayRef array = (ArrayRef)def.getLeftOp();
          allowedBox = array.getBaseBox();
          if (array.getBase() == local) {
            // assignment into interesting array
            if (array.getIndex() instanceof IntConstant) {
              IntConstant index = (IntConstant)array.getIndex();
              if (index.value >= 0 && index.value < info.contents.length) {
                ArrayConstantInfo out = info.clone();
                out.contents[index.value] = def.getRightOpBox();
                dest.put(local, out);
              } else {
                // definitely ArrayIndexOutOfBoundsException
                // let's just map it to BOTTOM by not adding the array
                dest.clear();
                return;
              }
            } else {
              // unknown index, information is lost
              dead.add(local);
            }
            affected = true;
          }
        }
        else if (def.getLeftOp() instanceof Local) {
            for (int i=0; i<info.contents.length; i++) {
                if (info.contents[i] == def.getLeftOp()) {
                    dead.add(local);
                    continue srcloop;
                }
            }
        }
      }
      if (!affected) {
        dest.put(local, src.get(local));
      }
      for (ValueBox used : stmt.getUseBoxes()) {
        if (used.getValue() == local && used != allowedBox) {
          dead.add(local);
          break;
        }
      }
    }
    // consider new arrays that become live
    if (stmt instanceof DefinitionStmt) {
      DefinitionStmt def = (DefinitionStmt)stmt;
      if (def.getRightOp() instanceof NewArrayExpr) {
        Local left = (Local)def.getLeftOp(); // left side is local because right side is complex expression
        NewArrayExpr expr = (NewArrayExpr)def.getRightOp();
        if (expr.getSize() instanceof IntConstant) {
          int size = ((IntConstant)expr.getSize()).value;
          dest.put(left, new ArrayConstantInfo(new ValueBox[size]));
        } else {
          // unknown length
          dead.add(left);
        }
      }
      else if (def.getLeftOp().getType() instanceof ArrayType) {
        if (def.getLeftOp() instanceof Local) {
          Local left = (Local)def.getLeftOp();
          // array acquired by some other means (method call, multidimensional array, typecast, aliasing, etc.)
          dead.add(left);
        }
      }
    }
    // move dead arrays to TOP
    for (Local deadLocal : dead) {
      dest.put(deadLocal, ArrayConstantInfo.UNKNOWN);
    }
  }

  @Override
  protected void copy(
      Map<Local, ArrayConstantInfo> src,
      Map<Local, ArrayConstantInfo> dest) {
    dest.clear();
    for (Map.Entry<Local,ArrayConstantInfo> entry : src.entrySet()) {
      dest.put(entry.getKey(), entry.getValue().clone());
    }
  }

  @Override
  protected Map<Local, ArrayConstantInfo> entryInitialFlow() {
    return new LinkedHashMap<Local,ArrayConstantInfo>();
  }

  @Override
  protected void merge(
      Map<Local, ArrayConstantInfo> src1,
      Map<Local, ArrayConstantInfo> src2,
      Map<Local, ArrayConstantInfo> dest) {
    for (Map.Entry<Local,ArrayConstantInfo> entry : src1.entrySet()) {
      ArrayConstantInfo info2 = src2.get(entry.getKey());
      if (info2 == null) {
        dest.put(entry.getKey(), entry.getValue());
      } else {
        ArrayConstantInfo merged = entry.getValue().leastUpperBound(info2);
        dest.put(entry.getKey(), merged);
      }
    }
    for (Map.Entry<Local,ArrayConstantInfo> entry : src2.entrySet()) {
      ArrayConstantInfo info1 = src1.get(entry.getKey());
      if (info1 != null)
        continue;
      dest.put(entry.getKey(), entry.getValue());
    }
  }
 
  @Override
  protected Map<Local, ArrayConstantInfo> newInitialFlow() {
    return new LinkedHashMap<Local,ArrayConstantInfo>();
  }

}
TOP

Related Classes of dk.brics.xact.analysis.soot.ArrayConstantAnalysis

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.