public void fill() {
   DomM domM = (DomM) doms[0];
   DomV domV = (DomV) doms[1];
   DomH domH = (DomH) doms[2];
   int numA = domH.getLastA() + 1;
   for (int hIdx = 1; hIdx < numA; hIdx++) {
     Quad q = (Quad) domH.get(hIdx);
     jq_Method m = q.getMethod();
     int mIdx = domM.indexOf(m);
     assert (mIdx >= 0);
     Operator op = q.getOperator();
     RegisterOperand vo;
     if (op instanceof New) vo = New.getDest(q);
     else if (op instanceof NewArray) vo = NewArray.getDest(q);
     else if (op instanceof Invoke) vo = Invoke.getDest(q);
     else if (op instanceof MultiNewArray) vo = NewArray.getDest(q);
     else {
       Messages.fatal("Unknown quad in domain H: " + q);
       vo = null;
     }
     Register v = vo.getRegister();
     int vIdx = domV.indexOf(v);
     if (vIdx >= 0) add(mIdx, vIdx, hIdx);
   }
 }
  /**
   * Provides the set of all concrete classes that subclass/implement a given class/interface.
   *
   * @param s The name of a class or interface.
   * @return The set of all concrete classes that subclass/implement (directly or transitively) the
   *     class/interface named s, if it exists in the class hierarchy, and null otherwise.
   */
  public Set<String> getConcreteSubclasses(final String s) {
    if (clintToAllConcreteSubs == null) {
      if (clintToKind == null) build();
      missingClints = new HashSet<String>();
      Set<String> missingSuperclasses = new HashSet<String>();
      Set<String> missingSuperInterfs = new HashSet<String>();
      // Map from each concrete class in scope to set containing
      // itself and its (direct and transitive) superclasses and
      // its implemented interfaces (not necessarily in scope).
      Map<String, Set<String>> concreteClassToAllSups = new HashMap<String, Set<String>>();
      clintToAllConcreteSubs = new HashMap<String, Set<String>>();
      Set<String> emptyRdOnlySet = Collections.emptySet();
      for (String c : clintToKind.keySet()) {
        clintToAllConcreteSubs.put(c, emptyRdOnlySet);
        if (clintToKind.get(c) != TypeKind.CONCRETE_CLASS) continue;
        Set<String> clints = new ArraySet<String>(2);
        clints.add(c); // every concrete class is a concrete successor to itself
        boolean success1 = true;
        boolean success2 = true;
        String d = c;
        while (true) {
          success2 &= populateInterfaces(d, clints);
          String superClass = classToDeclaredSuperclass.get(d);
          if (superClass == null) {
            if (!d.equals("java.lang.Object")) {
              missingClints.add(d);
              success1 = false;
            }
            break;
          }
          boolean added = clints.add(superClass);
          assert (added);
          d = superClass;
        }
        if (success1 && success2) {
          concreteClassToAllSups.put(c, clints);
          continue;
        }
        if (!success1) missingSuperclasses.add(c);
        if (!success2) missingSuperInterfs.add(c);
      }
      if (!missingClints.isEmpty()) {
        Messages.log(MISSING_TYPES);
        for (String c : missingClints) Messages.log("\t" + c);
      }
      if (!missingSuperclasses.isEmpty()) {
        Messages.log(MISSING_SUPERCLASSES);
        for (String c : missingSuperclasses) Messages.log("\t" + c);
      }
      if (!missingSuperInterfs.isEmpty()) {
        Messages.log(MISSING_SUPERINTERFS);
        for (String c : missingSuperInterfs) Messages.log("\t" + c);
      }
      for (String c : concreteClassToAllSups.keySet()) {
        Set<String> sups = concreteClassToAllSups.get(c);
        for (String d : sups) {
          Set<String> subs = clintToAllConcreteSubs.get(d);
          if (subs == null || subs == emptyRdOnlySet) {
            subs = new ArraySet<String>(2);
            clintToAllConcreteSubs.put(d, subs);
          }
          subs.add(c);
        }
      }
      missingClints.clear();
    }

    return clintToAllConcreteSubs.get(s);
  }
  // builds maps clintToKind, classToDeclaredSuperclass, and clintToDeclaredInterfaces
  private void build() {
    System.out.println("Starting to build class hierarchy; this may take a while ...");
    Set<String> dynLoadedTypes = null;
    if (Config.CHkind.equals("dynamic")) {
      List<String> list = Program.g().getDynamicallyLoadedClasses();
      dynLoadedTypes = new HashSet<String>(list.size());
      dynLoadedTypes.addAll(list);
    }
    Classpath cp = new Classpath();
    cp.addToClasspath(System.getProperty("sun.boot.class.path"));
    cp.addExtClasspath();
    cp.addToClasspath(Config.userClassPathName);
    List<ClasspathElement> cpeList = cp.getClasspathElements();

    // logging info
    List<Pair<String, String>> duplicateTypes = new ArrayList<Pair<String, String>>();
    List<String> excludedTypes = new ArrayList<String>();
    List<String> typesNotDynLoaded = new ArrayList<String>();

    clintToKind = new HashMap<String, TypeKind>();
    classToDeclaredSuperclass = new HashMap<String, String>();
    clintToDeclaredInterfaces = new HashMap<String, Set<String>>();

    for (ClasspathElement cpe : cpeList) {
      for (String fileName : cpe.getEntries()) {
        if (!fileName.endsWith(".class")) continue;
        String baseName = fileName.substring(0, fileName.length() - 6);
        String typeName = baseName.replace('/', '.');

        // ignore types excluded from scope
        if (Config.isExcludedFromScope(typeName)) {
          excludedTypes.add(typeName);
          continue;
        }

        // ignore duplicate types in classpath
        if (clintToKind.containsKey(typeName)) {
          duplicateTypes.add(new Pair<String, String>(typeName, cpe.toString()));
          continue;
        }

        if (dynLoadedTypes != null && !dynLoadedTypes.contains(typeName)) {
          typesNotDynLoaded.add(typeName);
          continue;
        }
        InputStream is = cpe.getResourceAsStream(fileName);
        assert (is != null);
        DataInputStream in = new DataInputStream(is);
        if (Config.verbose >= 2) Messages.log("Processing class file %s from %s", fileName, cpe);
        processClassFile(in, typeName);
      }
    }

    if (Config.verbose >= 2) {
      if (!duplicateTypes.isEmpty()) {
        Messages.log(IGNORED_DUPLICATE_TYPES);
        for (Pair<String, String> p : duplicateTypes) Messages.log("\t%s, %s", p.val0, p.val1);
      }
      if (!excludedTypes.isEmpty()) {
        Messages.log(EXCLUDED_TYPES_IN_CHORD);
        for (String s : excludedTypes) Messages.log("\t" + s);
      }
      if (!typesNotDynLoaded.isEmpty()) {
        Messages.log(EXCLUDED_TYPES_NOT_DYN_LOADED);
        for (String s : typesNotDynLoaded) Messages.log("\t" + s);
      }
    }
    System.out.println("Finished building class hierarchy.");
  }