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 }