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

qilin.core.builder.callgraph.Edge Maven / Gradle / Ivy

package qilin.core.builder.callgraph;

import qilin.core.context.Context;
import qilin.core.pag.ContextMethod;
import qilin.util.Invalidable;
import sootup.core.jimple.common.expr.AbstractInvokeExpr;
import sootup.core.jimple.common.expr.JInterfaceInvokeExpr;
import sootup.core.jimple.common.expr.JSpecialInvokeExpr;
import sootup.core.jimple.common.expr.JStaticInvokeExpr;
import sootup.core.jimple.common.expr.JVirtualInvokeExpr;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.SootMethod;

/**
 * Represents a single edge in a call graph.
 *
 * @author Ondrej Lhotak
 */
public final class Edge implements Invalidable {

  /**
   * The method in which the call occurs; may be null for calls not occurring in a specific method
   * (eg. implicit calls by the VM)
   */
  private ContextMethod src;

  /** The target method of the call edge. */
  private ContextMethod tgt;

  /**
   * The unit at which the call occurs; may be null for calls not occurring at a specific statement
   * (eg. calls in native code)
   */
  private Stmt srcUnit;

  /**
   * The kind of edge. Note: kind should not be tested by other classes; instead, accessors such as
   * isExplicit() should be added.
   */
  private final Kind kind;

  private boolean invalid = false;

  public Edge(ContextMethod src, Stmt srcUnit, ContextMethod tgt, Kind kind) {
    this.src = src;
    this.srcUnit = srcUnit;
    this.tgt = tgt;
    this.kind = kind;
  }

  public Edge(ContextMethod src, Stmt srcUnit, ContextMethod tgt) {
    this.kind = ieToKind(srcUnit.getInvokeExpr());
    this.src = src;
    this.srcUnit = srcUnit;
    this.tgt = tgt;
  }

  public SootMethod src() {
    return (src == null) ? null : src.method();
  }

  public Context srcCtxt() {
    return (src == null) ? null : src.context();
  }

  public ContextMethod getSrc() {
    return src;
  }

  public Stmt srcUnit() {
    return srcUnit;
  }

  public Stmt srcStmt() {
    return srcUnit;
  }

  public SootMethod tgt() {
    return (tgt == null) ? null : tgt.method();
  }

  public Context tgtCtxt() {
    return (tgt == null) ? null : tgt.context();
  }

  public ContextMethod getTgt() {
    return tgt;
  }

  public Kind kind() {
    return kind;
  }

  public static Kind ieToKind(AbstractInvokeExpr ie) {
    if (ie instanceof JVirtualInvokeExpr) {
      return Kind.VIRTUAL;
    } else if (ie instanceof JSpecialInvokeExpr) {
      return Kind.SPECIAL;
    } else if (ie instanceof JInterfaceInvokeExpr) {
      return Kind.INTERFACE;
    } else if (ie instanceof JStaticInvokeExpr) {
      return Kind.STATIC;
    } else {
      throw new RuntimeException();
    }
  }

  /** Returns true if the call is due to an explicit invoke statement. */
  public boolean isExplicit() {
    return Kind.isExplicit(this.kind);
  }

  /** Returns true if the call is due to an explicit instance invoke statement. */
  public boolean isInstance() {
    return Kind.isInstance(this.kind);
  }

  public boolean isVirtual() {
    return Kind.isVirtual(this.kind);
  }

  public boolean isSpecial() {
    return Kind.isSpecial(this.kind);
  }

  /** Returns true if the call is to static initializer. */
  public boolean isClinit() {
    return Kind.isClinit(this.kind);
  }

  /** Returns true if the call is due to an explicit static invoke statement. */
  public boolean isStatic() {
    return Kind.isStatic(this.kind);
  }

  public boolean isThreadRunCall() {
    return Kind.isThread(this.kind);
  }

  public boolean passesParameters() {
    return Kind.passesParameters(this.kind);
  }

  @Override
  public boolean isInvalid() {
    return invalid;
  }

  @Override
  public void invalidate() {
    // Since the edge remains in the QueueReaders for a while, the GC could not claim old units.
    src = null;
    srcUnit = null;
    tgt = null;
    invalid = true;
  }

  @Override
  public int hashCode() {
    if (invalid) {
      return 0;
    }
    int ret = (tgt.hashCode() + 20) + (kind == null ? 0 : kind.getNumber());
    if (src != null) {
      ret = ret * 32 + src.hashCode();
    }
    if (srcUnit != null) {
      ret = ret * 32 + srcUnit.hashCode();
    }
    return ret;
  }

  @Override
  public boolean equals(Object other) {
    if (!(other instanceof Edge)) {
      return false;
    }
    Edge o = (Edge) other;
    return (o.src == this.src) && (o.srcUnit == srcUnit) && (o.tgt == tgt) && (o.kind == kind);
  }

  @Override
  public String toString() {
    return this.kind + " edge: " + srcUnit + " in " + src + " ==> " + tgt;
  }

  private Edge nextByUnit = this;
  private Edge prevByUnit = this;
  private Edge nextBySrc = this;
  private Edge prevBySrc = this;
  private Edge nextByTgt = this;
  private Edge prevByTgt = this;

  void insertAfterByUnit(Edge other) {
    nextByUnit = other.nextByUnit;
    nextByUnit.prevByUnit = this;
    other.nextByUnit = this;
    prevByUnit = other;
  }

  void insertAfterBySrc(Edge other) {
    nextBySrc = other.nextBySrc;
    nextBySrc.prevBySrc = this;
    other.nextBySrc = this;
    prevBySrc = other;
  }

  void insertAfterByTgt(Edge other) {
    nextByTgt = other.nextByTgt;
    nextByTgt.prevByTgt = this;
    other.nextByTgt = this;
    prevByTgt = other;
  }

  void insertBeforeByUnit(Edge other) {
    prevByUnit = other.prevByUnit;
    prevByUnit.nextByUnit = this;
    other.prevByUnit = this;
    nextByUnit = other;
  }

  void insertBeforeBySrc(Edge other) {
    prevBySrc = other.prevBySrc;
    prevBySrc.nextBySrc = this;
    other.prevBySrc = this;
    nextBySrc = other;
  }

  void insertBeforeByTgt(Edge other) {
    prevByTgt = other.prevByTgt;
    prevByTgt.nextByTgt = this;
    other.prevByTgt = this;
    nextByTgt = other;
  }

  void remove() {
    invalid = true;
    nextByUnit.prevByUnit = prevByUnit;
    prevByUnit.nextByUnit = nextByUnit;
    nextBySrc.prevBySrc = prevBySrc;
    prevBySrc.nextBySrc = nextBySrc;
    nextByTgt.prevByTgt = prevByTgt;
    prevByTgt.nextByTgt = nextByTgt;
  }

  Edge nextByUnit() {
    return nextByUnit;
  }

  Edge nextBySrc() {
    return nextBySrc;
  }

  Edge nextByTgt() {
    return nextByTgt;
  }

  Edge prevByUnit() {
    return prevByUnit;
  }

  Edge prevBySrc() {
    return prevBySrc;
  }

  Edge prevByTgt() {
    return prevByTgt;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy