/**
   * If this is a putfield or putstatic instruction, check to see if the field is @NonNull, and
   * treat it as dereferences.
   *
   * @param location the Location of the instruction
   * @param vnaFrame the ValueNumberFrame at the Location of the instruction
   * @param fact the dataflow value to modify
   * @throws DataflowAnalysisException
   */
  private void checkNonNullPutField(
      Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact)
      throws DataflowAnalysisException {
    INullnessAnnotationDatabase database =
        AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase();

    FieldInstruction fieldIns = (FieldInstruction) location.getHandle().getInstruction();

    XField field = XFactory.createXField(fieldIns, methodGen.getConstantPool());
    char firstChar = field.getSignature().charAt(0);
    if (firstChar != 'L' && firstChar != '[') {
      return;
    }
    NullnessAnnotation resolvedAnnotation = database.getResolvedAnnotation(field, true);
    if (resolvedAnnotation == NullnessAnnotation.NONNULL) {
      IsNullValueFrame invFrame = invDataflow.getFactAtLocation(location);
      if (!invFrame.isValid()) {
        return;
      }
      IsNullValue value = invFrame.getTopValue();
      if (reportDereference(value)) {
        ValueNumber vn = vnaFrame.getTopValue();
        fact.addDeref(vn, location);
      }
    }
  }
 private void handleNullCheck(
     Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact)
     throws DataflowAnalysisException {
   if (reportPotentialDereference(location, invDataflow.getFactAtLocation(location))) {
     ValueNumber vn = vnaFrame.getTopValue();
     fact.addDeref(vn, location);
   }
 }
 /**
  * If this is a method call instruction, check to see if any of the parameters are @NonNull, and
  * treat them as dereferences.
  *
  * @param location the Location of the instruction
  * @param vnaFrame the ValueNumberFrame at the Location of the instruction
  * @param fact the dataflow value to modify
  * @throws DataflowAnalysisException
  */
 private void checkNonNullParams(
     Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact)
     throws DataflowAnalysisException {
   ConstantPoolGen constantPool = methodGen.getConstantPool();
   Set<ValueNumber> nonNullParams =
       checkNonNullParams(
           location, vnaFrame, constantPool, method, invDataflow.getFactAtLocation(location));
   for (ValueNumber vn : nonNullParams) {
     fact.addDeref(vn, location);
   }
 }
  /**
   * Check method call at given location to see if it unconditionally dereferences a parameter. Mark
   * any such arguments as derefs.
   *
   * @param location the Location of the method call
   * @param vnaFrame ValueNumberFrame at the Location
   * @param fact the dataflow value to modify
   * @throws DataflowAnalysisException
   */
  private void checkUnconditionalDerefDatabase(
      Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact)
      throws DataflowAnalysisException {
    ConstantPoolGen constantPool = methodGen.getConstantPool();

    for (ValueNumber vn :
        checkUnconditionalDerefDatabase(
            location,
            vnaFrame,
            constantPool,
            invDataflow.getFactAtLocation(location),
            typeDataflow)) {
      fact.addDeref(vn, location);
    }
  }
  /**
   * If this is a method call instruction, check to see if any of the parameters are @NonNull, and
   * treat them as dereferences.
   *
   * @param location the Location of the instruction
   * @param vnaFrame the ValueNumberFrame at the Location of the instruction
   * @param fact the dataflow value to modify
   * @throws DataflowAnalysisException
   */
  private void checkNonNullReturnValue(
      XMethod thisMethod,
      Location location,
      ValueNumberFrame vnaFrame,
      UnconditionalValueDerefSet fact)
      throws DataflowAnalysisException {
    INullnessAnnotationDatabase database =
        AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase();

    if (database.getResolvedAnnotation(thisMethod, true) != NullnessAnnotation.NONNULL) {
      return;
    }
    if (reportPotentialDereference(location, invDataflow.getFactAtLocation(location))) {
      ValueNumber vn = vnaFrame.getTopValue();
      fact.addDeref(vn, location);
    }
  }
 @Override
 public boolean isTop(UnconditionalValueDerefSet fact) {
   return fact.isTop();
 }
 @Override
 public void makeFactTop(UnconditionalValueDerefSet fact) {
   fact.setIsTop();
 }
 @Override
 public void initEntryFact(UnconditionalValueDerefSet result) throws DataflowAnalysisException {
   result.clear();
 }
 @Override
 public void copy(UnconditionalValueDerefSet source, UnconditionalValueDerefSet dest) {
   dest.makeSameAs(source);
 }
  /**
   * Check to see if the instruction has a null check associated with it, and if so, add a
   * dereference.
   *
   * @param location the Location of the instruction
   * @param vnaFrame ValueNumberFrame at the Location of the instruction
   * @param fact the dataflow value to modify
   * @throws DataflowAnalysisException
   */
  private void checkInstance(
      Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact)
      throws DataflowAnalysisException {
    // See if this instruction has a null check.
    // If it does, the fall through predecessor will be
    // identify itself as the null check.
    if (!location.isFirstInstructionInBasicBlock()) {
      return;
    }
    if (invDataflow == null) {
      return;
    }
    BasicBlock fallThroughPredecessor =
        cfg.getPredecessorWithEdgeType(location.getBasicBlock(), EdgeTypes.FALL_THROUGH_EDGE);
    if (fallThroughPredecessor == null || !fallThroughPredecessor.isNullCheck()) {
      return;
    }

    // Get the null-checked value
    ValueNumber vn =
        vnaFrame.getInstance(location.getHandle().getInstruction(), methodGen.getConstantPool());

    // Ignore dereferences of this
    if (!methodGen.isStatic()) {
      ValueNumber v = vnaFrame.getValue(0);
      if (v.equals(vn)) {
        return;
      }
    }
    if (vn.hasFlag(ValueNumber.CONSTANT_CLASS_OBJECT)) {
      return;
    }

    IsNullValueFrame startFact = null;

    startFact = invDataflow.getStartFact(fallThroughPredecessor);

    if (!startFact.isValid()) {
      return;
    }

    int slot =
        startFact.getInstanceSlot(
            location.getHandle().getInstruction(), methodGen.getConstantPool());
    if (!reportDereference(startFact, slot)) {
      return;
    }
    if (DEBUG) {
      System.out.println("FOUND GUARANTEED DEREFERENCE");
      System.out.println("Load: " + vnaFrame.getLoad(vn));
      System.out.println("Pred: " + fallThroughPredecessor);
      System.out.println("startFact: " + startFact);
      System.out.println("Location: " + location);
      System.out.println("Value number frame: " + vnaFrame);
      System.out.println("Dereferenced valueNumber: " + vn);
      System.out.println("invDataflow: " + startFact);
      System.out.println("IGNORE_DEREF_OF_NCP: " + IGNORE_DEREF_OF_NCP);
    }
    // Mark the value number as being dereferenced at this location
    fact.addDeref(vn, location);
  }
 @Override
 public int getLastUpdateTimestamp(UnconditionalValueDerefSet fact) {
   return fact.getLastUpdateTimestamp();
 }
  @Override
  public void transferInstruction(
      InstructionHandle handle, BasicBlock basicBlock, UnconditionalValueDerefSet fact)
      throws DataflowAnalysisException {

    Instruction instruction = handle.getInstruction();
    if (fact.isTop()) {
      return;
    }
    Location location = new Location(handle, basicBlock);

    // If this is a call to an assertion method,
    // change the dataflow value to be TOP.
    // We don't want to report future derefs that would
    // be guaranteed only if the assertion methods
    // returns normally.
    // TODO: at some point, evaluate whether we should revisit this
    if (isAssertion(handle) // || handle.getInstruction() instanceof ATHROW
    ) {
      if (DEBUG) {
        System.out.println("MAKING BOTTOM0 AT: " + location);
      }
      fact.clear();
      return;
    }

    // Get value number frame
    ValueNumberFrame vnaFrame = vnaDataflow.getFactAtLocation(location);
    if (!vnaFrame.isValid()) {
      if (DEBUG) {
        System.out.println("MAKING TOP1 AT: " + location);
      }
      // Probably dead code.
      // Assume this location can't be reached.
      makeFactTop(fact);
      return;
    }
    if (isNullCheck(handle, methodGen.getConstantPool())) {
      handleNullCheck(location, vnaFrame, fact);
    }

    // Check for calls to a method that unconditionally dereferences
    // a parameter. Mark any such arguments as derefs.
    if (CHECK_CALLS && instruction instanceof InvokeInstruction) {
      checkUnconditionalDerefDatabase(location, vnaFrame, fact);
    }

    // If this is a method call instruction,
    // check to see if any of the parameters are @NonNull,
    // and treat them as dereferences.
    if (CHECK_ANNOTATIONS && instruction instanceof InvokeInstruction) {
      checkNonNullParams(location, vnaFrame, fact);
    }

    if (CHECK_ANNOTATIONS && instruction instanceof ARETURN) {
      XMethod thisMethod = XFactory.createXMethod(methodGen);
      checkNonNullReturnValue(thisMethod, location, vnaFrame, fact);
    }

    if (CHECK_ANNOTATIONS
        && (instruction instanceof PUTFIELD || instruction instanceof PUTSTATIC)) {
      checkNonNullPutField(location, vnaFrame, fact);
    }

    // Check to see if an instance value is dereferenced here
    checkInstance(location, vnaFrame, fact);

    /*
    if (false) {
        fact.cleanDerefSet(location, vnaFrame);
    }*/

    if (DEBUG && fact.isTop()) {
      System.out.println("MAKING TOP2 At: " + location);
    }
  }
 @Override
 public boolean isFactValid(UnconditionalValueDerefSet fact) {
   return !fact.isTop() && !fact.isBottom();
 }
 @Override
 public void setLastUpdateTimestamp(UnconditionalValueDerefSet fact, int lastUpdate) {
   fact.setLastUpdateTimestamp(lastUpdate);
 }
  public void meetInto(
      UnconditionalValueDerefSet fact,
      Edge edge,
      UnconditionalValueDerefSet result,
      boolean onlyEdge) {
    if (isExceptionEdge(edge) && !onlyEdge) {
      if (DEBUG) {
        System.out.println("Skipping exception edge");
      }
      return;
    }

    ValueNumber knownNonnullOnBranch = null;
    // Edge transfer function
    if (isFactValid(fact)) {
      fact = propagateDerefSetsToMergeInputValues(fact, edge);
      if (invDataflow != null) {
        knownNonnullOnBranch = findValueKnownNonnullOnBranch(fact, edge);
        if (knownNonnullOnBranch != null) {
          fact = duplicateFact(fact);
          fact.clearDerefSet(knownNonnullOnBranch);
        }
      }
    }
    boolean isBackEdge = edge.isBackwardInBytecode();
    Set<Integer> loopExitBranches = ClassContext.getLoopExitBranches(method, methodGen);
    assert loopExitBranches != null;
    boolean sourceIsTopOfLoop = edge.sourceIsTopOfLoop(loopExitBranches);
    if (sourceIsTopOfLoop && edge.getType() == EdgeTypes.FALL_THROUGH_EDGE) {
      isBackEdge = true;
    }
    /*
    if (false && (edge.getType() == EdgeTypes.IFCMP_EDGE || sourceIsTopOfLoop)) {
        System.out.println("Meet into " + edge);
        System.out.println("  foo2: " + sourceIsTopOfLoop);
        System.out.println("  getType: " + edge.getType());
        System.out.println("  Backedge according to bytecode: " + isBackEdge);
        System.out.println("  Fact hashCode: " + System.identityHashCode(result));
        System.out.println("  Initial fact: " + result);
        System.out.println("  Edge fact: " + fact);
    }
     */
    if (result.isTop() || fact.isBottom()) {
      // Make result identical to other fact
      copy(fact, result);
      if (ASSUME_NONZERO_TRIP_LOOPS && isBackEdge && !fact.isTop()) {
        result.resultsFromBackEdge = true;
      }
    } else if (ASSUME_NONZERO_TRIP_LOOPS && isBackEdge && !fact.isTop()) {
      result.unionWith(fact, vnaDataflow.getAnalysis().getFactory());
      result.resultsFromBackEdge = true;
      if (DEBUG) {
        System.out.println(
            "\n Forcing union of " + System.identityHashCode(result) + " due to backedge info");
        System.out.println("  result: " + result);
      }

    } else if (result.isBottom() || fact.isTop()) {
      // No change in result fact
    } else {
      // Dataflow merge
      // (intersection of unconditional deref values)
      if (ASSUME_NONZERO_TRIP_LOOPS && result.resultsFromBackEdge) {
        result.backEdgeUpdateCount++;
        if (result.backEdgeUpdateCount < 10) {
          if (DEBUG) {
            System.out.println(
                "\n Union update of " + System.identityHashCode(result) + " due to backedge info");
          }
          result.unionWith(fact, vnaDataflow.getAnalysis().getFactory());
          return;
        }
      }
      result.mergeWith(fact, knownNonnullOnBranch, vnaDataflow.getAnalysis().getFactory());
      if (DEBUG) {
        System.out.println("  updated: " + System.identityHashCode(result));
        System.out.println("  result: " + result);
      }
    }
    if (DEBUG && isBackEdge && edge.getType() == EdgeTypes.IFCMP_EDGE) {
      System.out.println("  result: " + result);
    }
  }
  /**
   * Find out if any VNs in the source block contribute to unconditionally dereferenced VNs in the
   * target block. If so, the VN in the source block is also unconditionally dereferenced, and we
   * must propagate the target VN's dereferences.
   *
   * @param fact a dataflow value
   * @param edge edge to check for merge input values
   * @return possibly-modified dataflow value
   */
  private UnconditionalValueDerefSet propagateDerefSetsToMergeInputValues(
      UnconditionalValueDerefSet fact, Edge edge) {

    ValueNumberFrame blockValueNumberFrame = vnaDataflow.getResultFact(edge.getSource());
    ValueNumberFrame targetValueNumberFrame = vnaDataflow.getStartFact(edge.getTarget());

    UnconditionalValueDerefSet originalFact = fact;
    fact = duplicateFact(fact);

    if (blockValueNumberFrame.isValid() && targetValueNumberFrame.isValid()) {
      int slots = 0;
      if (targetValueNumberFrame.getNumSlots() == blockValueNumberFrame.getNumSlots()) {
        slots = targetValueNumberFrame.getNumSlots();
      } else if (targetValueNumberFrame.getNumLocals() == blockValueNumberFrame.getNumLocals()) {
        slots = targetValueNumberFrame.getNumLocals();
      }

      if (slots > 0) {
        if (DEBUG) {
          System.out.println("** Valid VNA frames for " + edge);
          System.out.println("** Block : " + blockValueNumberFrame);
          System.out.println("** Target: " + targetValueNumberFrame);
        }

        for (int i = 0; i < slots; i++) {
          ValueNumber blockVN = blockValueNumberFrame.getValue(i);
          ValueNumber targetVN = targetValueNumberFrame.getValue(i);
          if (blockVN.equals(targetVN)) {
            continue;
          }
          fact.clearDerefSet(blockVN);
          if (originalFact.isUnconditionallyDereferenced(targetVN)) {
            fact.setDerefSet(blockVN, originalFact.getUnconditionalDerefLocationSet(targetVN));
          }
        } // for all slots

        for (ValueNumber blockVN : blockValueNumberFrame.valueNumbersForLoads()) {
          AvailableLoad load = blockValueNumberFrame.getLoad(blockVN);
          if (load == null) {
            continue;
          }
          ValueNumber[] targetVNs = targetValueNumberFrame.getAvailableLoad(load);
          if (targetVNs != null) {
            for (ValueNumber targetVN : targetVNs) {
              if (targetVN.hasFlag(ValueNumber.PHI_NODE)
                  && fact.isUnconditionallyDereferenced(targetVN)
                  && !fact.isUnconditionallyDereferenced(blockVN)) {
                // Block VN is also dereferenced
                // unconditionally.
                AvailableLoad targetLoad = targetValueNumberFrame.getLoad(targetVN);
                if (!load.equals(targetLoad)) {
                  continue;
                }
                if (DEBUG) {
                  System.out.println(
                      "** Copy vn derefs for " + load + " from " + targetVN + " --> " + blockVN);
                  System.out.println(
                      "** block phi for "
                          + System.identityHashCode(blockValueNumberFrame)
                          + " is "
                          + blockValueNumberFrame.phiNodeForLoads);
                  System.out.println(
                      "** target phi for "
                          + System.identityHashCode(targetValueNumberFrame)
                          + " is "
                          + targetValueNumberFrame.phiNodeForLoads);
                }
                fact.setDerefSet(blockVN, fact.getUnconditionalDerefLocationSet(targetVN));
              }
            }
          }
        }
      }
    }
    if (DEBUG) {
      System.out.println("Target VNF: " + targetValueNumberFrame);
      System.out.println("Block VNF: " + blockValueNumberFrame);
      System.out.println("fact: " + fact);
    }
    fact.cleanDerefSet(null, blockValueNumberFrame);
    return fact;
  }
 @Override
 public boolean same(UnconditionalValueDerefSet fact1, UnconditionalValueDerefSet fact2) {
   return fact1.resultsFromBackEdge || fact1.isSameAs(fact2);
 }