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.Vector;
  36 import java.util.Enumeration;
  37 import jdk.test.lib.hprof.util.CompositeEnumeration;
  38 import jdk.test.lib.hprof.parser.ReadBuffer;
  39 
  40 /**
  41  *
  42  * @author      Bill Foote
  43  */
  44 
  45 
  46 public class JavaClass extends JavaHeapObject {
  47     // my id
  48     private long id;
  49     // my name
  50     private String name;
  51 
  52     // These are JavaObjectRef before resolve
  53     private JavaThing superclass;
  54     private JavaThing loader;
  55     private JavaThing signers;
  56     private JavaThing protectionDomain;
  57 
  58     // non-static fields
  59     private JavaField[] fields;
  60     // static fields
  61     private JavaStatic[] statics;
  62 
  63     private static final JavaClass[] EMPTY_CLASS_ARRAY = new JavaClass[0];
  64     // my subclasses
  65     private JavaClass[] subclasses = EMPTY_CLASS_ARRAY;
  66 
  67     // my instances
  68     private Vector<JavaHeapObject> instances = new Vector<JavaHeapObject>();
  69 
  70     // Who I belong to.  Set on resolve.
  71     private Snapshot mySnapshot;
  72 
  73     // Size of an instance, including VM overhead
  74     private int instanceSize;
  75     // Total number of fields including inherited ones
  76     private int totalNumFields;
  77 
  78 
  79     public JavaClass(long id, String name, long superclassId, long loaderId,
  80                      long signersId, long protDomainId,
  81                      JavaField[] fields, JavaStatic[] statics,
  82                      int instanceSize) {
  83         this.id = id;
  84         this.name = name;
  85         this.superclass = new JavaObjectRef(superclassId);
  86         this.loader = new JavaObjectRef(loaderId);
  87         this.signers = new JavaObjectRef(signersId);
  88         this.protectionDomain = new JavaObjectRef(protDomainId);
  89         this.fields = fields;
  90         this.statics = statics;
  91         this.instanceSize = instanceSize;
  92     }
  93 
  94     public JavaClass(String name, long superclassId, long loaderId,
  95                      long signersId, long protDomainId,
  96                      JavaField[] fields, JavaStatic[] statics,
  97                      int instanceSize) {
  98         this(-1L, name, superclassId, loaderId, signersId,
  99              protDomainId, fields, statics, instanceSize);
 100     }
 101 
 102     public final JavaClass getClazz() {
 103         return mySnapshot.getJavaLangClass();
 104     }
 105 
 106     public final int getIdentifierSize() {
 107         return mySnapshot.getIdentifierSize();
 108     }
 109 
 110     public final int getMinimumObjectSize() {
 111         return mySnapshot.getMinimumObjectSize();
 112     }
 113 
 114     public void resolve(Snapshot snapshot) {
 115         if (mySnapshot != null) {
 116             return;
 117         }
 118         mySnapshot = snapshot;
 119         resolveSuperclass(snapshot);
 120         if (superclass != null) {
 121             ((JavaClass) superclass).addSubclass(this);
 122         }
 123 
 124         loader  = loader.dereference(snapshot, null);
 125         signers  = signers.dereference(snapshot, null);
 126         protectionDomain  = protectionDomain.dereference(snapshot, null);
 127 
 128         for (int i = 0; i < statics.length; i++) {
 129             statics[i].resolve(this, snapshot);
 130         }
 131         snapshot.getJavaLangClass().addInstance(this);
 132         super.resolve(snapshot);
 133         return;
 134     }
 135 
 136     /**
 137      * Resolve our superclass.  This might be called well before
 138      * all instances are available (like when reading deferred
 139      * instances in a 1.2 dump file :-)  Calling this is sufficient
 140      * to be able to explore this class' fields.
 141      */
 142     public void resolveSuperclass(Snapshot snapshot) {
 143         if (superclass == null) {
 144             // We must be java.lang.Object, so we have no superclass.
 145         } else {
 146             totalNumFields = fields.length;
 147             superclass = superclass.dereference(snapshot, null);
 148             if (superclass == snapshot.getNullThing()) {
 149                 superclass = null;
 150             } else {
 151                 try {
 152                     JavaClass sc = (JavaClass) superclass;
 153                     sc.resolveSuperclass(snapshot);
 154                     totalNumFields += sc.totalNumFields;
 155                 } catch (ClassCastException ex) {
 156                     System.out.println("Warning!  Superclass of " + name + " is " + superclass);
 157                     superclass = null;
 158                 }
 159             }
 160         }
 161     }
 162 
 163     public boolean isString() {
 164         return mySnapshot.getJavaLangString() == this;
 165     }
 166 
 167     public boolean isClassLoader() {
 168         return mySnapshot.getJavaLangClassLoader().isAssignableFrom(this);
 169     }
 170 
 171     /**
 172      * Get a numbered field from this class
 173      */
 174     public JavaField getField(int i) {
 175         if (i < 0 || i >= fields.length) {
 176             throw new Error("No field " + i + " for " + name);
 177         }
 178         return fields[i];
 179     }
 180 
 181     /**
 182      * Get the total number of fields that are part of an instance of
 183      * this class.  That is, include superclasses.
 184      */
 185     public int getNumFieldsForInstance() {
 186         return totalNumFields;
 187     }
 188 
 189     /**
 190      * Get a numbered field from all the fields that are part of instance
 191      * of this class.  That is, include superclasses.
 192      */
 193     public JavaField getFieldForInstance(int i) {
 194         if (superclass != null) {
 195             JavaClass sc = (JavaClass) superclass;
 196             if (i < sc.totalNumFields) {
 197                 return sc.getFieldForInstance(i);
 198             }
 199             i -= sc.totalNumFields;
 200         }
 201         return getField(i);
 202     }
 203 
 204     /**
 205      * Get the class responsible for field i, where i is a field number that
 206      * could be passed into getFieldForInstance.
 207      *
 208      * @see JavaClass.getFieldForInstance()
 209      */
 210     public JavaClass getClassForField(int i) {
 211         if (superclass != null) {
 212             JavaClass sc = (JavaClass) superclass;
 213             if (i < sc.totalNumFields) {
 214                 return sc.getClassForField(i);
 215             }
 216         }
 217         return this;
 218     }
 219 
 220     public long getId() {
 221         return id;
 222     }
 223 
 224     public String getName() {
 225         return name;
 226     }
 227 
 228     public boolean isArray() {
 229         return name.indexOf('[') != -1;
 230     }
 231 
 232     public Enumeration<JavaHeapObject> getInstances(boolean includeSubclasses) {
 233         if (includeSubclasses) {
 234             Enumeration<JavaHeapObject> res = instances.elements();
 235             for (int i = 0; i < subclasses.length; i++) {
 236                 res = new CompositeEnumeration(res,
 237                               subclasses[i].getInstances(true));
 238             }
 239             return res;
 240         } else {
 241             return instances.elements();
 242         }
 243     }
 244 
 245     /**
 246      * @return a count of the instances of this class
 247      */
 248     public int getInstancesCount(boolean includeSubclasses) {
 249         int result = instances.size();
 250         if (includeSubclasses) {
 251             for (int i = 0; i < subclasses.length; i++) {
 252                 result += subclasses[i].getInstancesCount(includeSubclasses);
 253             }
 254         }
 255         return result;
 256     }
 257 
 258     public JavaClass[] getSubclasses() {
 259         return subclasses;
 260     }
 261 
 262     /**
 263      * This can only safely be called after resolve()
 264      */
 265     public JavaClass getSuperclass() {
 266         return (JavaClass) superclass;
 267     }
 268 
 269     /**
 270      * This can only safely be called after resolve()
 271      */
 272     public JavaThing getLoader() {
 273         return loader;
 274     }
 275 
 276     /**
 277      * This can only safely be called after resolve()
 278      */
 279     public boolean isBootstrap() {
 280         return loader == mySnapshot.getNullThing();
 281     }
 282 
 283     /**
 284      * This can only safely be called after resolve()
 285      */
 286     public JavaThing getSigners() {
 287         return signers;
 288     }
 289 
 290     /**
 291      * This can only safely be called after resolve()
 292      */
 293     public JavaThing getProtectionDomain() {
 294         return protectionDomain;
 295     }
 296 
 297     public JavaField[] getFields() {
 298         return fields;
 299     }
 300 
 301     /**
 302      * Includes superclass fields
 303      */
 304     public JavaField[] getFieldsForInstance() {
 305         Vector<JavaField> v = new Vector<JavaField>();
 306         addFields(v);
 307         JavaField[] result = new JavaField[v.size()];
 308         for (int i = 0; i < v.size(); i++) {
 309             result[i] =  v.elementAt(i);
 310         }
 311         return result;
 312     }
 313 
 314 
 315     public JavaStatic[] getStatics() {
 316         return statics;
 317     }
 318 
 319     // returns value of static field of given name
 320     public JavaThing getStaticField(String name) {
 321         for (int i = 0; i < statics.length; i++) {
 322             JavaStatic s = statics[i];
 323             if (s.getField().getName().equals(name)) {
 324                 return s.getValue();
 325             }
 326         }
 327         return null;
 328     }
 329 
 330     public String toString() {
 331         return "class " + name;
 332     }
 333 
 334     public int compareTo(JavaThing other) {
 335         if (other instanceof JavaClass) {
 336             return name.compareTo(((JavaClass) other).name);
 337         }
 338         return super.compareTo(other);
 339     }
 340 
 341 
 342     /**
 343      * @return true iff a variable of type this is assignable from an instance
 344      *          of other
 345      */
 346     public boolean isAssignableFrom(JavaClass other) {
 347         if (this == other) {
 348             return true;
 349         } else if (other == null) {
 350             return false;
 351         } else {
 352             return isAssignableFrom((JavaClass) other.superclass);
 353             // Trivial tail recursion:  I have faith in javac.
 354         }
 355     }
 356 
 357     /**
 358      * Describe the reference that this thing has to target.  This will only
 359      * be called if target is in the array returned by getChildrenForRootset.
 360      */
 361      public String describeReferenceTo(JavaThing target, Snapshot ss) {
 362         for (int i = 0; i < statics.length; i++) {
 363             JavaField f = statics[i].getField();
 364             if (f.hasId()) {
 365                 JavaThing other = statics[i].getValue();
 366                 if (other == target) {
 367                     return "static field " + f.getName();
 368                 }
 369             }
 370         }
 371         return super.describeReferenceTo(target, ss);
 372     }
 373 
 374     /**
 375      * @return the size of an instance of this class.  Gives 0 for an array
 376      *          type.
 377      */
 378     public int getInstanceSize() {
 379         return instanceSize + mySnapshot.getMinimumObjectSize();
 380     }
 381 
 382 
 383     /**
 384      * @return The size of all instances of this class.  Correctly handles
 385      *          arrays.
 386      */
 387     public long getTotalInstanceSize() {
 388         int count = instances.size();
 389         if (count == 0 || !isArray()) {
 390             return count * instanceSize;
 391         }
 392 
 393         // array class and non-zero count, we have to
 394         // get the size of each instance and sum it
 395         long result = 0;
 396         for (int i = 0; i < count; i++) {
 397             JavaThing t = (JavaThing) instances.elementAt(i);
 398             result += t.getSize();
 399         }
 400         return result;
 401     }
 402 
 403     /**
 404      * @return the size of this object
 405      */
 406     public int getSize() {
 407         JavaClass cl = mySnapshot.getJavaLangClass();
 408         if (cl == null) {
 409             return 0;
 410         } else {
 411             return cl.getInstanceSize();
 412         }
 413     }
 414 
 415     public void visitReferencedObjects(JavaHeapObjectVisitor v) {
 416         super.visitReferencedObjects(v);
 417         JavaHeapObject sc = getSuperclass();
 418         if (sc != null) v.visit(getSuperclass());
 419 
 420         JavaThing other;
 421         other = getLoader();
 422         if (other instanceof JavaHeapObject) {
 423             v.visit((JavaHeapObject)other);
 424         }
 425         other = getSigners();
 426         if (other instanceof JavaHeapObject) {
 427             v.visit((JavaHeapObject)other);
 428         }
 429         other = getProtectionDomain();
 430         if (other instanceof JavaHeapObject) {
 431             v.visit((JavaHeapObject)other);
 432         }
 433 
 434         for (int i = 0; i < statics.length; i++) {
 435             JavaField f = statics[i].getField();
 436             if (!v.exclude(this, f) && f.hasId()) {
 437                 other = statics[i].getValue();
 438                 if (other instanceof JavaHeapObject) {
 439                     v.visit((JavaHeapObject) other);
 440                 }
 441             }
 442         }
 443     }
 444 
 445     // package-privates below this point
 446     final ReadBuffer getReadBuffer() {
 447         return mySnapshot.getReadBuffer();
 448     }
 449 
 450     final void setNew(JavaHeapObject obj, boolean flag) {
 451         mySnapshot.setNew(obj, flag);
 452     }
 453 
 454     final boolean isNew(JavaHeapObject obj) {
 455         return mySnapshot.isNew(obj);
 456     }
 457 
 458     final StackTrace getSiteTrace(JavaHeapObject obj) {
 459         return mySnapshot.getSiteTrace(obj);
 460     }
 461 
 462     final void addReferenceFromRoot(Root root, JavaHeapObject obj) {
 463         mySnapshot.addReferenceFromRoot(root, obj);
 464     }
 465 
 466     final Root getRoot(JavaHeapObject obj) {
 467         return mySnapshot.getRoot(obj);
 468     }
 469 
 470     final Snapshot getSnapshot() {
 471         return mySnapshot;
 472     }
 473 
 474     void addInstance(JavaHeapObject inst) {
 475         instances.addElement(inst);
 476     }
 477 
 478     // Internals only below this point
 479     private void addFields(Vector<JavaField> v) {
 480         if (superclass != null) {
 481             ((JavaClass) superclass).addFields(v);
 482         }
 483         for (int i = 0; i < fields.length; i++) {
 484             v.addElement(fields[i]);
 485         }
 486     }
 487 
 488     private void addSubclassInstances(Vector<JavaHeapObject> v) {
 489         for (int i = 0; i < subclasses.length; i++) {
 490             subclasses[i].addSubclassInstances(v);
 491         }
 492         for (int i = 0; i < instances.size(); i++) {
 493             v.addElement(instances.elementAt(i));
 494         }
 495     }
 496 
 497     private void addSubclass(JavaClass sub) {
 498         JavaClass newValue[] = new JavaClass[subclasses.length + 1];
 499         System.arraycopy(subclasses, 0, newValue, 0, subclasses.length);
 500         newValue[subclasses.length] = sub;
 501         subclasses = newValue;
 502     }
 503 }