1 /*
   2  * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 /*
  28  * The Original Code is HAT. The Initial Developer of the
  29  * Original Code is Bill Foote, with contributions from others
  30  * at JavaSoft/Sun.
  31  */
  32 
  33 package jdk.test.lib.hprof.model;
  34 
  35 import java.util.Vector;
  36 import java.util.Hashtable;
  37 import java.util.Enumeration;
  38 
  39 import jdk.test.lib.hprof.util.ArraySorter;
  40 import jdk.test.lib.hprof.util.Comparer;
  41 
  42 /**
  43  * @author      A. Sundararajan
  44  */
  45 
  46 public class ReachableObjects {
  47     public ReachableObjects(JavaHeapObject root,
  48                             final ReachableExcludes excludes) {
  49         this.root = root;
  50 
  51         final Hashtable<JavaHeapObject, JavaHeapObject> bag = new Hashtable<JavaHeapObject, JavaHeapObject>();
  52         final Hashtable<String, String> fieldsExcluded = new Hashtable<String, String>();  //Bag<String>
  53         final Hashtable<String, String> fieldsUsed = new Hashtable<String, String>();   // Bag<String>
  54         JavaHeapObjectVisitor visitor = new AbstractJavaHeapObjectVisitor() {
  55             public void visit(JavaHeapObject t) {
  56                 // Size is zero for things like integer fields
  57                 if (t != null && t.getSize() > 0 && bag.get(t) == null) {
  58                     bag.put(t, t);
  59                     t.visitReferencedObjects(this);
  60                 }
  61             }
  62 
  63             public boolean mightExclude() {
  64                 return excludes != null;
  65             }
  66 
  67             public boolean exclude(JavaClass clazz, JavaField f) {
  68                 if (excludes == null) {
  69                     return false;
  70                 }
  71                 String nm = clazz.getName() + "." + f.getName();
  72                 if (excludes.isExcluded(nm)) {
  73                     fieldsExcluded.put(nm, nm);
  74                     return true;
  75                 } else {
  76                     fieldsUsed.put(nm, nm);
  77                     return false;
  78                 }
  79             }
  80         };
  81         // Put the closure of root and all objects reachable from root into
  82         // bag (depth first), but don't include root:
  83         visitor.visit(root);
  84         bag.remove(root);
  85 
  86         // Now grab the elements into a vector, and sort it in decreasing size
  87         JavaThing[] things = new JavaThing[bag.size()];
  88         int i = 0;
  89         for (Enumeration<JavaHeapObject> e = bag.elements(); e.hasMoreElements(); ) {
  90             things[i++] = (JavaThing) e.nextElement();
  91         }
  92         ArraySorter.sort(things, new Comparer() {
  93             public int compare(Object lhs, Object rhs) {
  94                 JavaThing left = (JavaThing) lhs;
  95                 JavaThing right = (JavaThing) rhs;
  96                 long diff = right.getSize() - left.getSize();
  97                 if (diff != 0) {
  98                     return Long.signum(diff);
  99                 }
 100                 return left.compareTo(right);
 101             }
 102         });
 103         this.reachables = things;
 104 
 105         this.totalSize = root.getSize();
 106         for (i = 0; i < things.length; i++) {
 107             this.totalSize += things[i].getSize();
 108         }
 109 
 110         excludedFields = getElements(fieldsExcluded);
 111         usedFields = getElements(fieldsUsed);
 112     }
 113 
 114     public JavaHeapObject getRoot() {
 115         return root;
 116     }
 117 
 118     public JavaThing[] getReachables() {
 119         return reachables;
 120     }
 121 
 122     public long getTotalSize() {
 123         return totalSize;
 124     }
 125 
 126     public String[] getExcludedFields() {
 127         return excludedFields;
 128     }
 129 
 130     public String[] getUsedFields() {
 131         return usedFields;
 132     }
 133 
 134     private String[] getElements(Hashtable<?, ?> ht) {
 135         Object[] keys = ht.keySet().toArray();
 136         int len = keys.length;
 137         String[] res = new String[len];
 138         System.arraycopy(keys, 0, res, 0, len);
 139         ArraySorter.sortArrayOfStrings(res);
 140         return res;
 141     }
 142 
 143     private JavaHeapObject root;
 144     private JavaThing[] reachables;
 145     private String[]  excludedFields;
 146     private String[]  usedFields;
 147     private long totalSize;
 148 }