Package dk.brics.string.intermediate.operations

Source Code of dk.brics.string.intermediate.operations.AliasAnalysis

package dk.brics.string.intermediate.operations;

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

import dk.brics.string.intermediate.Application;
import dk.brics.string.intermediate.ArrayAddAll;
import dk.brics.string.intermediate.ArrayAssignment;
import dk.brics.string.intermediate.ArrayCorrupt;
import dk.brics.string.intermediate.ArrayFromArray;
import dk.brics.string.intermediate.ArrayNew;
import dk.brics.string.intermediate.ArrayWriteArray;
import dk.brics.string.intermediate.ArrayWriteElement;
import dk.brics.string.intermediate.AssertAliases;
import dk.brics.string.intermediate.AssertBinaryOp;
import dk.brics.string.intermediate.AssertUnaryOp;
import dk.brics.string.intermediate.BasicBinaryOp;
import dk.brics.string.intermediate.BasicUnaryOp;
import dk.brics.string.intermediate.Call;
import dk.brics.string.intermediate.Catch;
import dk.brics.string.intermediate.ExceptionalReturn;
import dk.brics.string.intermediate.Field;
import dk.brics.string.intermediate.FieldAssignment;
import dk.brics.string.intermediate.FieldReference;
import dk.brics.string.intermediate.Hotspot;
import dk.brics.string.intermediate.Method;
import dk.brics.string.intermediate.MethodHead;
import dk.brics.string.intermediate.Nop;
import dk.brics.string.intermediate.ObjectAssignment;
import dk.brics.string.intermediate.ObjectCorrupt;
import dk.brics.string.intermediate.PrimitiveAssignment;
import dk.brics.string.intermediate.PrimitiveFromArray;
import dk.brics.string.intermediate.PrimitiveInit;
import dk.brics.string.intermediate.Return;
import dk.brics.string.intermediate.Statement;
import dk.brics.string.intermediate.StatementVisitor;
import dk.brics.string.intermediate.StringAssignment;
import dk.brics.string.intermediate.StringBufferAppend;
import dk.brics.string.intermediate.StringBufferAppendChar;
import dk.brics.string.intermediate.StringBufferAssignment;
import dk.brics.string.intermediate.StringBufferBinaryOp;
import dk.brics.string.intermediate.StringBufferCorrupt;
import dk.brics.string.intermediate.StringBufferInit;
import dk.brics.string.intermediate.StringBufferPrepend;
import dk.brics.string.intermediate.StringBufferUnaryOp;
import dk.brics.string.intermediate.StringConcat;
import dk.brics.string.intermediate.StringFromArray;
import dk.brics.string.intermediate.StringFromStringBuffer;
import dk.brics.string.intermediate.StringInit;
import dk.brics.string.intermediate.Variable;

/**
* Alias analysis performed on a set of methods. This analysis also determines
* which variables might have been corrupted.
* <p/>
* This is a variable-pair-based may/must context-insensitive alias analysis.
* Only live variables are considered.
*/
public class AliasAnalysis implements FlowAnalysis, StatementVisitor {

  private LivenessAnalysis la;
  private FieldUsageAnalysis fieldUsage;
  private AliasAssertionAnalysis assertions;

  /**
   * Alias info for program point before each statement.
   */
  private Map<Statement, AliasInfo> flow_info;

  /**
   * Alias info for program point before current statement.
   */
  private AliasInfo before;

  /**
   * Alias info for program point after current statement.
   */
  private AliasInfo after;

  private boolean changed;

  private WorkList worklist;

  /**
   * Performs alias analysis.
   *
   * @param app the application to analyze
   * @param la  result from liveness analysis
   * @param fieldUsage result from field usage analysis
   */
  public AliasAnalysis(Application app, LivenessAnalysis la, FieldUsageAnalysis fieldUsage, AliasAssertionAnalysis assertions) {
    this.la = la;
    this.fieldUsage = fieldUsage;
    this.assertions = assertions;
    flow_info = new HashMap<Statement, AliasInfo>();
    worklist = new WorkList(this);
    for (Method m : app.getMethods()) {
      worklist.addAll(m);
    }
    worklist.iterate();
  }

  public void transfer(Statement s) {
    before = getInfoBefore(s);
    for (Statement ss : s.getSuccs()) {
      after = getInfoBefore(ss);
      changed = false;
      s.visitBy(this);
      if (changed) {
        worklist.add(ss);
      }
    }

    // visit interprocedural successors
    if (s instanceof Return) {
      Return returnStm = (Return)s;
      Method method = s.getMethod();
      for (Call call : method.getCallSites()) {
        for (Statement afterCall : call.getSuccs()) {
          after = getInfoBefore(afterCall);
          changed = false;
          transferReturn(returnStm, call, afterCall);
          if (changed) {
            worklist.add(afterCall);
          }
        }
      }
    }
    if (s instanceof Call) {
      Call call = (Call)s;
      after = getInfoBefore(call.target.getEntry());
      changed = false;
      transferCall(call, call.target.getEntry());
      if (changed) {
        worklist.add(call.target.getEntry());
      }
    }
  }

  /**
   * Transfers alias information from a {@link Return} statement to the statements
   * following a corresponding {@link Call} statement. Information being transferred:
   * <ul>
   * <li>If parameter <i>i</i> is corrupt, then caller's actual argument <i>i</i> is corrupted.
   * <li>If the returned value might be an alias for parameter <i>i</i>, then caller's actual argument <i>i</i> becomes a possible alias
   *     for the caller's result variable.
   * <li>If the returned value is corrupt, then caller's result variable is corrupted.
   * </ul>
   * @param returnStm the return statement.
   * @param call a call to the method containing the return statement.
   * @param to the statement receiving the alias information. This is a successor of <tt>call</tt>, and corresponds to the {@link #after} field.
   */
  private void transferReturn(Return returnStm, Call call, Statement to) {
    Method method = returnStm.getMethod();
    MethodHead head = method.getEntry();
    AliasInfo beforeCall = getInfoBefore(call);
    AliasStatus status;
    // add aliasing between arguments and return value
    // and corruption of parameters to corruption of arguments
    for (int i=0; i<head.params.length; i++) {
      status = before.getAliasStatus(returnStm.retvar, head.params[i]);
      changed |= after.mergeStatus(beforeCall, call.retvar, call.args[i], status);

      if (before.isCorrupt(head.params[i])) {
        changed |= after.mergeCorrupt(beforeCall, call.args[i]);
      }
    }

    // add aliasing between fields pairs, and between fields and return value
    for (Field field1 : fieldUsage.getUsedFields(method)) {
      for (Field field2 : fieldUsage.getUsedFields(method)) {
        if (field1 == field2)
          continue;

        status = before.getAliasStatus(field1.getVariable(), field2.getVariable());
        changed |= after.mergeStatus(beforeCall, field1.getVariable(), field2.getVariable(), status);
        changed |= after.mergeStatus(beforeCall, field2.getVariable(), field1.getVariable(), status);
      }
      // if a field was assigned to one of the parameters, tell the caller that his arguments are now
      // aliases for the field
      for (int i=0; i<head.params.length; i++) {
        status = before.getAliasStatus(field1.getVariable(), head.params[i]);
        changed |= after.mergeStatus(beforeCall, call.args[i], field1.getVariable(), status);
        // no need to merge for field1 as left-hand side. A local that was aliased with field1
        // can still not become aliased with an argument, just because field1 changed value.
      }

      // set aliasing with field and return value
      status = before.getAliasStatus(returnStm.retvar, field1.getVariable());
      changed |= after.mergeStatus(beforeCall, call.retvar, field1.getVariable(), status);

      // if the field was corrupted, transfer this to the caller
      if (before.isCorrupt(field1.getVariable())) {
        changed |= after.mergeCorrupt(beforeCall, field1.getVariable());
      }
    }

    // if the return value might be corrupt
    if (before.isCorrupt(returnStm.retvar)) {
      changed |= after.setCorrupt(call.retvar);
    }
  }

  /**
   * Transfers alias information from a {@link Call} statement to the {@link MethodHead} of
   * the called method. Information being transferred:
   * <ul>
   * <li>If actual argument <i>i</i> might be an alias for actual argument <i>j</i>, then
   *     parameter <i>i</i> becomes a possible alias for parameter <i>j</i>.
   * <li>If actual argument <i>i</i> is corrupt, then parameter <i>i</i> is corrupted.
   * </ul>
   * @param callStm the call statement.
   * @param head method head of the call's target method.
   */
  private void transferCall(Call callStm, MethodHead head) {
    // add aliasing between arguments to aliasing between parameters
    // and corruption of arguments to corruption of parameters
    for  (int i=0; i<head.params.length; i++) {
      for (int j=i+1; j<head.params.length; j++) {
        AliasStatus status = before.getAliasStatus(callStm.args[i], callStm.args[j]);
        changed |= after.mergeStatus(after, head.params[i], head.params[j], status);
        changed |= after.mergeStatus(after, head.params[j], head.params[i], status);
      }
      if (before.isCorrupt(callStm.args[i])) {
        changed |= after.setCorrupt(head.params[i]);
      }
    }
    // add aliasing status between fields pairs and between fields and arguments
    for (Field field1 : fieldUsage.getUsedFields(callStm.target)) {
      for (Field field2 : fieldUsage.getUsedFields(callStm.target)) {
        if (field1 == field2)
          continue;

        AliasStatus status = before.getAliasStatus(field1.getVariable(), field2.getVariable());
        changed |= after.mergeStatus(after, field1.getVariable(), field2.getVariable(), status);
        changed |= after.mergeStatus(after, field2.getVariable(), field1.getVariable(), status);
      }

      for (int i=0; i<head.params.length; i++) {
        AliasStatus status = before.getAliasStatus(field1.getVariable(), callStm.args[i]);
        changed |= after.mergeStatus(after, field1.getVariable(), head.params[i], status);
        changed |= after.mergeStatus(after, head.params[i], field1.getVariable(), status);
      }

      if (before.isCorrupt(field1.getVariable())) {
        changed |= after.setCorrupt(field1.getVariable());
      }
    }
  }

  /**
   * Returns the alias information as inferred just before the given statement.
   */
  public AliasInfo getInfoBefore(Statement s) {
    if (!flow_info.containsKey(s)) {
      Set<Variable> live = new HashSet<Variable>(la.getLiveBefore(s));
      /* for (Field field : app.getFields()) {
                live.add(field.getVariable());
            }*/
      for (Field field : fieldUsage.getUsedFields(s.getMethod())) {
        live.add(field.getVariable());
      }
      flow_info.put(s, new AliasInfo(live));
    }
    return flow_info.get(s);
  }

  public void visitPrimitiveAssignment(PrimitiveAssignment s) {
    transferIdentity();
  }
  public void visitPrimitiveInit(PrimitiveInit s) {
    transferIdentity();
  }
  public void visitStringBufferAppendChar(StringBufferAppendChar s) {
    transferIdentity();
  }
  public void visitBasicUnaryOp(BasicUnaryOp s) {
    transferIdentity();
  }
  public void visitBasicBinaryOp(BasicBinaryOp s) {
    transferIdentity();
  }
  public void visitAssertBinaryOp(AssertBinaryOp s) {
    transferIdentity();
  }
  public void visitAssertUnaryOp(AssertUnaryOp s) {
    transferIdentity();
  }
  public void visitAssertAliases(AssertAliases s) {
    if (assertions.isValid(s)) {
      if (s.alias) {
        changed |= after.mergeAssertAliases(before, s.a, s.b);
      } else {
        changed |= after.mergeAssertNotAliases(before, s.a, s.b);
      }
    } else {
      // invalid assertion. just pretend it wasn't here
      transferIdentity();
    }
  }
 
  public void visitArrayAssignment(ArrayAssignment s) {
    transferFilter(s.to);
    transferAssign(s.to, s.from);
  }

  public void visitArrayCorrupt(ArrayCorrupt s) {
    transferIdentity();
    transferCorrupt(s.to);
  }

  public void visitArrayAddAll(ArrayAddAll s) {
    transferIdentity();
  }

  public void visitArrayFromArray(ArrayFromArray s) {
    transferFilter(s.to);
    transferAssign(s.to, s.from);
  }

  public void visitArrayNew(ArrayNew s) {
    transferFilter(s.to);
    transferNew(s.to);
  }

  public void visitArrayWriteArray(ArrayWriteArray s) {
    transferIdentity();
    transferAssign(s.to, s.from);
  }

  public void visitArrayWriteElement(ArrayWriteElement s) {
    transferIdentity();
    transferAssign(s.to, s.from);
  }

  public void visitCall(Call s) {
    transferFilter(s.retvar);
    // this only handles flow from call to its successors in the method
    // see transferCall for the interprocedural flow
  }

  public void visitMethodHead(MethodHead s) {
    transferIdentity();

    // parameter aliases are definitely aliases of the formal parameters
    Variable[] pa = s.getMethod().getParamAlias();
    for (int i = 0; i < s.params.length; i++) {
      if (pa[i] != null) {
        changed |= after.mergeStatus(after, pa[i], s.params[i], AliasStatus.DEFINITELY);
      }
    }
  }

  public void visitNop(Nop s) {
    transferIdentity();
  }

  public void visitReturn(Return s) {
    // see transferReturn for the interprocedural flow
  }

  public void visitStringAssignment(StringAssignment s) {
    transferIdentity();
  }

  public void visitStringBufferAppend(StringBufferAppend s) {
    transferIdentity();
  }

  public void visitStringBufferAssignment(StringBufferAssignment s) {
    transferFilter(s.to);
    transferAssign(s.to, s.from);
  }

  public void visitStringBufferBinaryOp(StringBufferBinaryOp s) {
    transferIdentity();
  }

  public void visitStringBufferCorrupt(StringBufferCorrupt s) {
    transferIdentity();
    transferCorrupt(s.to);
  }

  public void visitStringBufferInit(StringBufferInit s) {
    transferFilter(s.to);
    transferNew(s.to);
  }

  public void visitStringBufferPrepend(StringBufferPrepend s) {
    transferIdentity();
  }

  public void visitStringBufferUnaryOp(StringBufferUnaryOp s) {
    transferIdentity();
  }

  public void visitStringConcat(StringConcat s) {
    transferIdentity();
  }

  public void visitStringFromArray(StringFromArray s) {
    transferIdentity();
  }
  public void visitPrimitiveFromArray(PrimitiveFromArray s) {
    transferIdentity();
  }

  public void visitStringFromStringBuffer(StringFromStringBuffer s) {
    transferIdentity();
  }

  public void visitStringInit(StringInit s) {
    transferIdentity();
  }

  public void visitObjectAssignment(ObjectAssignment s) {
    transferFilter(s.to);
    transferAssign(s.to, s.from);
  }

  public void visitObjectCorrupt(ObjectCorrupt s) {
    transferIdentity();
    transferCorrupt(s.to);
  }

  public void visitHotspot(Hotspot s) {
    transferIdentity();
  }

  public void visitFieldAssignment(FieldAssignment s) {
    transferIdentity(); // we use identity instead of filter to perform weak update
    transferAssign(s.getTo(), s.getFrom());
  }

  public void visitFieldReference(FieldReference s) {
    transferFilter(s.getTo());
    transferAssign(s.getTo(), s.getFrom());
  }

  public void visitCatch(Catch s) {
    transferIdentity();
    // exceptional flow cannot change aliasing
  }
  public void visitExceptionalReturn(ExceptionalReturn s) {
    // interprocedural flow handled elsewhere
  }

  private void transferIdentity() {
    changed |= after.mergeIdentity(before);
  }

  private void transferFilter(Variable a) {
    changed |= after.mergeFilter(before, a);
  }

  private void transferAssign(Variable a, Variable b) {
    changed |= after.mergeAssign(before, a, b);
  }

  private void transferCorrupt(Variable a) {
    changed |= after.mergeCorrupt(before, a);
  }

  private void transferNew(Variable a) {
    changed |= after.mergeNew(a);
  }

}
TOP

Related Classes of dk.brics.string.intermediate.operations.AliasAnalysis

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.