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