private BlockDataFlowState generateDFState(CFGBlock block) {
    int totalGlobals = this.uniqueGlobals.get(block.getMethodName()).size();

    // Get the original inBitSet for this block
    BitSet origIn;
    if (this.cfgBlocksState.containsKey(block)) {
      origIn = this.cfgBlocksState.get(block).getIn();
    } else {
      origIn = new BitSet(totalGlobals);
      origIn.set(0, totalGlobals);
    }

    // Calculate the in BitSet by taking intersection of predecessors
    BlockDataFlowState bFlow = new BlockDataFlowState(totalGlobals);

    // If there exist at least one successor, set Out to all True
    if (block.getSuccessors().size() > 0) {
      bFlow.getOut().set(0, totalGlobals);
    }

    BitSet out = bFlow.getOut();
    for (CFGBlock pred : block.getSuccessors()) {
      if (this.cfgBlocksState.containsKey(pred)) {
        out.and(this.cfgBlocksState.get(pred).getIn());
      }
    }

    calculateGenKillSets(block, bFlow);

    // Calculate Out
    BitSet in = bFlow.getIn(); // IN = (OUT - KILL) U GEN
    in.or(out);
    in.xor(bFlow.getKill());
    in.or(bFlow.getGen());

    if (!in.equals(origIn)) {
      // Add successors to cfgBlocks list
      for (CFGBlock pred : block.getPredecessors()) {
        if (!cfgBlocksToProcess.contains(pred)) {
          cfgBlocksToProcess.add(pred);
        }
      }
    }

    // Remove this block, since it has been processed
    cfgBlocksToProcess.remove(block);

    return bFlow;
  }
 private void calculateGenKillSets(CFGBlock block, BlockDataFlowState bFlow) {
   for (int i = block.getStatements().size() - 1; i >= 0; i--) {
     LIRStatement stmt = block.getStatements().get(i);
     if (stmt.getClass().equals(QuadrupletStmt.class)) {
       QuadrupletStmt qStmt = (QuadrupletStmt) stmt;
       if (!qStmt.getDestination().getClass().equals(RegisterName.class)) {
         updateKillGenSet(block.getMethodName(), qStmt, bFlow);
       }
     } else if (stmt.getClass().equals(StoreStmt.class)) {
       updateKillGenSet(block.getMethodName(), (StoreStmt) stmt, bFlow);
     } else if (stmt.getClass().equals(CallStmt.class)) {
       updateKillGenSet(block.getMethodName(), (CallStmt) stmt, bFlow);
     }
   }
 }
  private void setExitBlock(String methodName) {
    for (CFGBlock block : this.mMap.get(methodName).getCfgBlocks()) {
      if (block.getSuccessors().size() == 0) {
        //				return block;
        CFGBlock exit = block;
        BlockDataFlowState entryBlockFlow =
            new BlockDataFlowState(
                this.uniqueGlobals.get(methodName).size()); // IN = GEN for entry block
        calculateGenKillSets(exit, entryBlockFlow);
        entryBlockFlow.setIn(entryBlockFlow.getGen());
        cfgBlocksToProcess.remove(exit);

        this.cfgBlocksState.put(exit, entryBlockFlow);
      }
    }
  }
  private void initialize(String methodName) {
    this.cfgBlocksToProcess.clear();
    HashSet<Name> temp = new HashSet<Name>();

    for (CFGBlock block : this.mMap.get(methodName).getCfgBlocks()) {
      List<LIRStatement> blockStmts = block.getStatements();
      for (int i = 0; i < blockStmts.size(); i++) {
        LIRStatement stmt = blockStmts.get(i);
        if (stmt.getClass().equals(QuadrupletStmt.class)) {
          QuadrupletStmt qStmt = (QuadrupletStmt) stmt;

          if (qStmt.getDestination().isGlobal()) temp.add(qStmt.getDestination());
        } else if (stmt.getClass().equals(StoreStmt.class)) {
          StoreStmt sStmt = (StoreStmt) stmt;
          temp.add(sStmt.getVariable());
        }
      }

      this.cfgBlocksToProcess.add(block);
    }

    this.uniqueGlobals.put(methodName, new ArrayList<Name>());
    this.uniqueGlobals.get(methodName).addAll(temp);
  }
  private void optimize(CFGBlock block) {
    BlockDataFlowState bFlow = assignmentDefGenerator.getBlockAssignReachingDefs().get(block);
    QuadrupletStmt qStmt;
    PopStmt popStmt;
    PushStmt pushStmt;
    CmpStmt cStmt;
    Name newArg1, newArg2, dest;

    for (LIRStatement stmt : block.getStatements()) {
      // Reset kill set
      bFlow.getKill().clear();
      if (stmt.getClass().equals(CallStmt.class)) {
        CallStmt callStmt = (CallStmt) stmt;
        if (callStmt.getMethodLabel().equals(ProgramFlattener.exceptionHandlerLabel)) continue;

        // Update BlockDataFlowState kill set
        assignmentDefGenerator.invalidateFunctionCall(bFlow);
        // Update BlockDataFlowState in set by using updated kill set
        bFlow.getIn().xor(bFlow.getKill());

      } else if (stmt.getClass().equals(QuadrupletStmt.class)) {
        qStmt = (QuadrupletStmt) stmt;
        newArg1 = copyPropagateOnArg(qStmt.getArg1(), bFlow);
        if (newArg1 != null) {
          qStmt.setArg1(newArg1);
        }
        newArg2 = copyPropagateOnArg(qStmt.getArg2(), bFlow);
        if (newArg2 != null) {
          qStmt.setArg2(newArg2);
        }
        dest = qStmt.getDestination();
        if (dest != null) {
          // Check if dest is ArrayName and try to optimize index
          if (dest.getClass().equals(ArrayName.class)) {
            Name arrIndex = ((ArrayName) dest).getIndex();
            Name propagatedName = copyPropagateOnArg(arrIndex, bFlow);
            if (propagatedName != null) ((ArrayName) dest).setIndex(propagatedName);
          }
        }

        // Update BlockDataFlowState kill set
        assignmentDefGenerator.updateKillGenSet(dest, bFlow);
        // Update BlockDataFlowState in set by using updated kill set
        bFlow.getIn().xor(bFlow.getKill());

        // Optimize PopStmt
      } else if (stmt.getClass().equals(PopStmt.class)) {
        popStmt = (PopStmt) stmt;
        newArg1 = copyPropagateOnArg(popStmt.getName(), bFlow);
        if (newArg1 != null) {
          popStmt.setName(newArg1);
        }

        // Optimize PushStmt
      } else if (stmt.getClass().equals(PushStmt.class)) {
        pushStmt = (PushStmt) stmt;
        newArg1 = copyPropagateOnArg(pushStmt.getName(), bFlow);
        if (newArg1 != null) {
          pushStmt.setName(newArg1);
        }

        // Optimize CmpStmt
      } else if (stmt.getClass().equals(CmpStmt.class)) {
        cStmt = (CmpStmt) stmt;
        newArg1 = copyPropagateOnArg(cStmt.getArg1(), bFlow);
        if (newArg1 != null) {
          cStmt.setArg1(newArg1);
        }
        newArg2 = copyPropagateOnArg(cStmt.getArg2(), bFlow);
        if (newArg2 != null) {
          cStmt.setArg2(newArg2);
        }
      }
    }
  }