|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
/* |
|
* The Original Code is HAT. The Initial Developer of the |
|
* Original Code is Bill Foote, with contributions from others |
|
* at JavaSoft/Sun. |
|
*/ |
|
|
|
package com.sun.tools.hat.internal.model; |
|
|
|
import java.util.Vector; |
|
import java.util.Enumeration; |
|
import com.sun.tools.hat.internal.util.CompositeEnumeration; |
|
import com.sun.tools.hat.internal.parser.ReadBuffer; |
|
|
|
/** |
|
* |
|
* @author Bill Foote |
|
*/ |
|
|
|
|
|
public class JavaClass extends JavaHeapObject { |
|
|
|
private long id; |
|
|
|
private String name; |
|
|
|
|
|
private JavaThing superclass; |
|
private JavaThing loader; |
|
private JavaThing signers; |
|
private JavaThing protectionDomain; |
|
|
|
|
|
private JavaField[] fields; |
|
|
|
private JavaStatic[] statics; |
|
|
|
private static final JavaClass[] EMPTY_CLASS_ARRAY = new JavaClass[0]; |
|
|
|
private JavaClass[] subclasses = EMPTY_CLASS_ARRAY; |
|
|
|
|
|
private Vector<JavaHeapObject> instances = new Vector<JavaHeapObject>(); |
|
|
|
|
|
private Snapshot mySnapshot; |
|
|
|
|
|
private int instanceSize; |
|
|
|
private int totalNumFields; |
|
|
|
|
|
public JavaClass(long id, String name, long superclassId, long loaderId, |
|
long signersId, long protDomainId, |
|
JavaField[] fields, JavaStatic[] statics, |
|
int instanceSize) { |
|
this.id = id; |
|
this.name = name; |
|
this.superclass = new JavaObjectRef(superclassId); |
|
this.loader = new JavaObjectRef(loaderId); |
|
this.signers = new JavaObjectRef(signersId); |
|
this.protectionDomain = new JavaObjectRef(protDomainId); |
|
this.fields = fields; |
|
this.statics = statics; |
|
this.instanceSize = instanceSize; |
|
} |
|
|
|
public JavaClass(String name, long superclassId, long loaderId, |
|
long signersId, long protDomainId, |
|
JavaField[] fields, JavaStatic[] statics, |
|
int instanceSize) { |
|
this(-1L, name, superclassId, loaderId, signersId, |
|
protDomainId, fields, statics, instanceSize); |
|
} |
|
|
|
public final JavaClass getClazz() { |
|
return mySnapshot.getJavaLangClass(); |
|
} |
|
|
|
public final int getIdentifierSize() { |
|
return mySnapshot.getIdentifierSize(); |
|
} |
|
|
|
public final int getMinimumObjectSize() { |
|
return mySnapshot.getMinimumObjectSize(); |
|
} |
|
|
|
public void resolve(Snapshot snapshot) { |
|
if (mySnapshot != null) { |
|
return; |
|
} |
|
mySnapshot = snapshot; |
|
resolveSuperclass(snapshot); |
|
if (superclass != null) { |
|
((JavaClass) superclass).addSubclass(this); |
|
} |
|
|
|
loader = loader.dereference(snapshot, null); |
|
signers = signers.dereference(snapshot, null); |
|
protectionDomain = protectionDomain.dereference(snapshot, null); |
|
|
|
for (int i = 0; i < statics.length; i++) { |
|
statics[i].resolve(this, snapshot); |
|
} |
|
snapshot.getJavaLangClass().addInstance(this); |
|
super.resolve(snapshot); |
|
return; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void resolveSuperclass(Snapshot snapshot) { |
|
if (superclass == null) { |
|
// We must be java.lang.Object, so we have no superclass. |
|
} else { |
|
totalNumFields = fields.length; |
|
superclass = superclass.dereference(snapshot, null); |
|
if (superclass == snapshot.getNullThing()) { |
|
superclass = null; |
|
} else { |
|
try { |
|
JavaClass sc = (JavaClass) superclass; |
|
sc.resolveSuperclass(snapshot); |
|
totalNumFields += sc.totalNumFields; |
|
} catch (ClassCastException ex) { |
|
System.out.println("Warning! Superclass of " + name + " is " + superclass); |
|
superclass = null; |
|
} |
|
} |
|
} |
|
} |
|
|
|
public boolean isString() { |
|
return mySnapshot.getJavaLangString() == this; |
|
} |
|
|
|
public boolean isClassLoader() { |
|
return mySnapshot.getJavaLangClassLoader().isAssignableFrom(this); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public JavaField getField(int i) { |
|
if (i < 0 || i >= fields.length) { |
|
throw new Error("No field " + i + " for " + name); |
|
} |
|
return fields[i]; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public int getNumFieldsForInstance() { |
|
return totalNumFields; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public JavaField getFieldForInstance(int i) { |
|
if (superclass != null) { |
|
JavaClass sc = (JavaClass) superclass; |
|
if (i < sc.totalNumFields) { |
|
return sc.getFieldForInstance(i); |
|
} |
|
i -= sc.totalNumFields; |
|
} |
|
return getField(i); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public JavaClass getClassForField(int i) { |
|
if (superclass != null) { |
|
JavaClass sc = (JavaClass) superclass; |
|
if (i < sc.totalNumFields) { |
|
return sc.getClassForField(i); |
|
} |
|
} |
|
return this; |
|
} |
|
|
|
public long getId() { |
|
return id; |
|
} |
|
|
|
public String getName() { |
|
return name; |
|
} |
|
|
|
public boolean isArray() { |
|
return name.indexOf('[') != -1; |
|
} |
|
|
|
public Enumeration getInstances(boolean includeSubclasses) { |
|
if (includeSubclasses) { |
|
Enumeration res = instances.elements(); |
|
for (int i = 0; i < subclasses.length; i++) { |
|
res = new CompositeEnumeration(res, |
|
subclasses[i].getInstances(true)); |
|
} |
|
return res; |
|
} else { |
|
return instances.elements(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public int getInstancesCount(boolean includeSubclasses) { |
|
int result = instances.size(); |
|
if (includeSubclasses) { |
|
for (int i = 0; i < subclasses.length; i++) { |
|
result += subclasses[i].getInstancesCount(includeSubclasses); |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
public JavaClass[] getSubclasses() { |
|
return subclasses; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public JavaClass getSuperclass() { |
|
return (JavaClass) superclass; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public JavaThing getLoader() { |
|
return loader; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public boolean isBootstrap() { |
|
return loader == mySnapshot.getNullThing(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public JavaThing getSigners() { |
|
return signers; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public JavaThing getProtectionDomain() { |
|
return protectionDomain; |
|
} |
|
|
|
public JavaField[] getFields() { |
|
return fields; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public JavaField[] getFieldsForInstance() { |
|
Vector<JavaField> v = new Vector<JavaField>(); |
|
addFields(v); |
|
JavaField[] result = new JavaField[v.size()]; |
|
for (int i = 0; i < v.size(); i++) { |
|
result[i] = v.elementAt(i); |
|
} |
|
return result; |
|
} |
|
|
|
|
|
public JavaStatic[] getStatics() { |
|
return statics; |
|
} |
|
|
|
|
|
public JavaThing getStaticField(String name) { |
|
for (int i = 0; i < statics.length; i++) { |
|
JavaStatic s = statics[i]; |
|
if (s.getField().getName().equals(name)) { |
|
return s.getValue(); |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
public String toString() { |
|
return "class " + name; |
|
} |
|
|
|
public int compareTo(JavaThing other) { |
|
if (other instanceof JavaClass) { |
|
return name.compareTo(((JavaClass) other).name); |
|
} |
|
return super.compareTo(other); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isAssignableFrom(JavaClass other) { |
|
if (this == other) { |
|
return true; |
|
} else if (other == null) { |
|
return false; |
|
} else { |
|
return isAssignableFrom((JavaClass) other.superclass); |
|
// Trivial tail recursion: I have faith in javac. |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public String describeReferenceTo(JavaThing target, Snapshot ss) { |
|
for (int i = 0; i < statics.length; i++) { |
|
JavaField f = statics[i].getField(); |
|
if (f.hasId()) { |
|
JavaThing other = statics[i].getValue(); |
|
if (other == target) { |
|
return "static field " + f.getName(); |
|
} |
|
} |
|
} |
|
return super.describeReferenceTo(target, ss); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public int getInstanceSize() { |
|
return instanceSize + mySnapshot.getMinimumObjectSize(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public long getTotalInstanceSize() { |
|
int count = instances.size(); |
|
if (count == 0 || !isArray()) { |
|
return count * instanceSize; |
|
} |
|
|
|
// array class and non-zero count, we have to |
|
|
|
long result = 0; |
|
for (int i = 0; i < count; i++) { |
|
JavaThing t = (JavaThing) instances.elementAt(i); |
|
result += t.getSize(); |
|
} |
|
return result; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public int getSize() { |
|
JavaClass cl = mySnapshot.getJavaLangClass(); |
|
if (cl == null) { |
|
return 0; |
|
} else { |
|
return cl.getInstanceSize(); |
|
} |
|
} |
|
|
|
public void visitReferencedObjects(JavaHeapObjectVisitor v) { |
|
super.visitReferencedObjects(v); |
|
JavaHeapObject sc = getSuperclass(); |
|
if (sc != null) v.visit(getSuperclass()); |
|
|
|
JavaThing other; |
|
other = getLoader(); |
|
if (other instanceof JavaHeapObject) { |
|
v.visit((JavaHeapObject)other); |
|
} |
|
other = getSigners(); |
|
if (other instanceof JavaHeapObject) { |
|
v.visit((JavaHeapObject)other); |
|
} |
|
other = getProtectionDomain(); |
|
if (other instanceof JavaHeapObject) { |
|
v.visit((JavaHeapObject)other); |
|
} |
|
|
|
for (int i = 0; i < statics.length; i++) { |
|
JavaField f = statics[i].getField(); |
|
if (!v.exclude(this, f) && f.hasId()) { |
|
other = statics[i].getValue(); |
|
if (other instanceof JavaHeapObject) { |
|
v.visit((JavaHeapObject) other); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
final ReadBuffer getReadBuffer() { |
|
return mySnapshot.getReadBuffer(); |
|
} |
|
|
|
final void setNew(JavaHeapObject obj, boolean flag) { |
|
mySnapshot.setNew(obj, flag); |
|
} |
|
|
|
final boolean isNew(JavaHeapObject obj) { |
|
return mySnapshot.isNew(obj); |
|
} |
|
|
|
final StackTrace getSiteTrace(JavaHeapObject obj) { |
|
return mySnapshot.getSiteTrace(obj); |
|
} |
|
|
|
final void addReferenceFromRoot(Root root, JavaHeapObject obj) { |
|
mySnapshot.addReferenceFromRoot(root, obj); |
|
} |
|
|
|
final Root getRoot(JavaHeapObject obj) { |
|
return mySnapshot.getRoot(obj); |
|
} |
|
|
|
final Snapshot getSnapshot() { |
|
return mySnapshot; |
|
} |
|
|
|
void addInstance(JavaHeapObject inst) { |
|
instances.addElement(inst); |
|
} |
|
|
|
|
|
private void addFields(Vector<JavaField> v) { |
|
if (superclass != null) { |
|
((JavaClass) superclass).addFields(v); |
|
} |
|
for (int i = 0; i < fields.length; i++) { |
|
v.addElement(fields[i]); |
|
} |
|
} |
|
|
|
private void addSubclassInstances(Vector<JavaHeapObject> v) { |
|
for (int i = 0; i < subclasses.length; i++) { |
|
subclasses[i].addSubclassInstances(v); |
|
} |
|
for (int i = 0; i < instances.size(); i++) { |
|
v.addElement(instances.elementAt(i)); |
|
} |
|
} |
|
|
|
private void addSubclass(JavaClass sub) { |
|
JavaClass newValue[] = new JavaClass[subclasses.length + 1]; |
|
System.arraycopy(subclasses, 0, newValue, 0, subclasses.length); |
|
newValue[subclasses.length] = sub; |
|
subclasses = newValue; |
|
} |
|
} |