1 /*
   2  * Copyright (c) 1997, 2015, 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.Enumeration;
  36 import java.util.HashMap;
  37 import java.util.Map;
  38 import jdk.test.lib.hprof.util.Misc;
  39 
  40 
  41 /**
  42  *
  43  * @author      Bill Foote
  44  */
  45 
  46 /**
  47  * Represents an object that's allocated out of the Java heap.  It occupies
  48  * memory in the VM, and is the sort of thing that in a JDK 1.1 VM had
  49  * a handle.  It can be a
  50  * JavaClass, a JavaObjectArray, a JavaValueArray or a JavaObject.
  51  */
  52 
  53 public abstract class JavaHeapObject extends JavaThing {
  54 
  55     //
  56     // Who we refer to.  This is heavily optimized for space, because it's
  57     // well worth trading a bit of speed for less swapping.
  58     // referers and referersLen go through two phases:  Building and
  59     // resolved.  When building, referers might have duplicates, but can
  60     // be appended to.  When resolved, referers has no duplicates or
  61     // empty slots.
  62     //
  63     private JavaThing[] referers = null;
  64     private int referersLen = 0;        // -1 when resolved
  65 
  66     public abstract JavaClass getClazz();
  67     public abstract int getSize();
  68     public abstract long getId();
  69 
  70     /**
  71      * Do any initialization this thing needs after its data is read in.
  72      * Subclasses that override this should call super.resolve().
  73      */
  74     public void resolve(Snapshot snapshot) {
  75         StackTrace trace = snapshot.getSiteTrace(this);
  76         if (trace != null) {
  77             trace.resolve(snapshot);
  78         }
  79     }
  80 
  81     //
  82     //  Eliminate duplicates from referers, and size the array exactly.
  83     // This sets us up to answer queries.  See the comments around the
  84     // referers data member for details.
  85     //
  86     void setupReferers() {
  87         if (referersLen > 1) {
  88             // Copy referers to map, screening out duplicates
  89             Map<JavaThing, JavaThing> map = new HashMap<JavaThing, JavaThing>();
  90             for (int i = 0; i < referersLen; i++) {
  91                 if (map.get(referers[i]) == null) {
  92                     map.put(referers[i], referers[i]);
  93                 }
  94             }
  95 
  96             // Now copy into the array
  97             referers = new JavaThing[map.size()];
  98             map.keySet().toArray(referers);
  99         }
 100         referersLen = -1;
 101     }
 102 
 103 
 104     /**
 105      * @return the id of this thing as hex string
 106      */
 107     public String getIdString() {
 108         return Misc.toHex(getId());
 109     }
 110 
 111     public String toString() {
 112         return getClazz().getName() + "@" + getIdString();
 113     }
 114 
 115     /**
 116      * @return the StackTrace of the point of allocation of this object,
 117      *          or null if unknown
 118      */
 119     public StackTrace getAllocatedFrom() {
 120         return getClazz().getSiteTrace(this);
 121     }
 122 
 123     public boolean isNew() {
 124         return getClazz().isNew(this);
 125     }
 126 
 127     void setNew(boolean flag) {
 128         getClazz().setNew(this, flag);
 129     }
 130 
 131     /**
 132      * Tell the visitor about all of the objects we refer to
 133      */
 134     public void visitReferencedObjects(JavaHeapObjectVisitor v) {
 135         v.visit(getClazz());
 136     }
 137 
 138     void addReferenceFrom(JavaHeapObject other) {
 139         if (referersLen == 0) {
 140             referers = new JavaThing[1];        // It was null
 141         } else if (referersLen == referers.length) {
 142             JavaThing[] copy = new JavaThing[(3 * (referersLen + 1)) / 2];
 143             System.arraycopy(referers, 0, copy, 0, referersLen);
 144             referers = copy;
 145         }
 146         referers[referersLen++] = other;
 147         // We just append to referers here.  Measurements have shown that
 148         // around 10% to 30% are duplicates, so it's better to just append
 149         // blindly and screen out all the duplicates at once.
 150     }
 151 
 152     void addReferenceFromRoot(Root r) {
 153         getClazz().addReferenceFromRoot(r, this);
 154     }
 155 
 156     /**
 157      * If the rootset includes this object, return a Root describing one
 158      * of the reasons why.
 159      */
 160     public Root getRoot() {
 161         return getClazz().getRoot(this);
 162     }
 163 
 164     /**
 165      * Tell who refers to us.
 166      *
 167      * @return an Enumeration of JavaHeapObject instances
 168      */
 169     public Enumeration<JavaThing> getReferers() {
 170         if (referersLen != -1) {
 171             throw new RuntimeException("not resolved: " + getIdString());
 172         }
 173         return new Enumeration<JavaThing>() {
 174 
 175             private int num = 0;
 176 
 177             public boolean hasMoreElements() {
 178                 return referers != null && num < referers.length;
 179             }
 180 
 181             public JavaThing nextElement() {
 182                 return referers[num++];
 183             }
 184         };
 185     }
 186 
 187     /**
 188      * Given other, which the caller promises is in referers, determines if
 189      * the reference is only a weak reference.
 190      */
 191     public boolean refersOnlyWeaklyTo(Snapshot ss, JavaThing other) {
 192         return false;
 193     }
 194 
 195     /**
 196      * Describe the reference that this thing has to target.  This will only
 197      * be called if target is in the array returned by getChildrenForRootset.
 198      */
 199     public String describeReferenceTo(JavaThing target, Snapshot ss) {
 200         return "??";
 201     }
 202 
 203     public boolean isHeapAllocated() {
 204         return true;
 205     }
 206 
 207 }