001: /*
002: * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: /*
027: * The contents of this file are subject to the Sun Public License
028: * Version 1.0 (the "License"); you may not use this file except in
029: * compliance with the License. A copy of the License is available at
030: * http://www.sun.com/, and in the file LICENSE.html in the
031: * doc directory.
032: *
033: * The Original Code is HAT. The Initial Developer of the
034: * Original Code is Bill Foote, with contributions from others
035: * at JavaSoft/Sun. Portions created by Bill Foote and others
036: * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved.
037: *
038: * In addition to the formal license, I ask that you don't
039: * change the history or donations files without permission.
040: *
041: */
042:
043: package com.sun.tools.hat.internal.model;
044:
045: import java.util.Vector;
046: import java.util.Enumeration;
047: import com.sun.tools.hat.internal.util.CompositeEnumeration;
048: import com.sun.tools.hat.internal.parser.ReadBuffer;
049:
050: /**
051: *
052: * @version @(#)JavaClass.java 1.19 07/05/09 17:45:57
053: * @author Bill Foote
054: */
055:
056: public class JavaClass extends JavaHeapObject {
057: // my id
058: private long id;
059: // my name
060: private String name;
061:
062: // These are JavaObjectRef before resolve
063: private JavaThing super class;
064: private JavaThing loader;
065: private JavaThing signers;
066: private JavaThing protectionDomain;
067:
068: // non-static fields
069: private JavaField[] fields;
070: // static fields
071: private JavaStatic[] statics;
072:
073: private static final JavaClass[] EMPTY_CLASS_ARRAY = new JavaClass[0];
074: // my subclasses
075: private JavaClass[] subclasses = EMPTY_CLASS_ARRAY;
076:
077: // my instances
078: private Vector<JavaHeapObject> instances = new Vector<JavaHeapObject>();
079:
080: // Who I belong to. Set on resolve.
081: private Snapshot mySnapshot;
082:
083: // Size of an instance, including VM overhead
084: private int instanceSize;
085: // Total number of fields including inherited ones
086: private int totalNumFields;
087:
088: public JavaClass(long id, String name, long super classId,
089: long loaderId, long signersId, long protDomainId,
090: JavaField[] fields, JavaStatic[] statics, int instanceSize) {
091: this .id = id;
092: this .name = name;
093: this .super class = new JavaObjectRef(super classId);
094: this .loader = new JavaObjectRef(loaderId);
095: this .signers = new JavaObjectRef(signersId);
096: this .protectionDomain = new JavaObjectRef(protDomainId);
097: this .fields = fields;
098: this .statics = statics;
099: this .instanceSize = instanceSize;
100: }
101:
102: public JavaClass(String name, long super classId, long loaderId,
103: long signersId, long protDomainId, JavaField[] fields,
104: JavaStatic[] statics, int instanceSize) {
105: this (-1L, name, super classId, loaderId, signersId,
106: protDomainId, fields, statics, instanceSize);
107: }
108:
109: public final JavaClass getClazz() {
110: return mySnapshot.getJavaLangClass();
111: }
112:
113: public final int getIdentifierSize() {
114: return mySnapshot.getIdentifierSize();
115: }
116:
117: public final int getMinimumObjectSize() {
118: return mySnapshot.getMinimumObjectSize();
119: }
120:
121: public void resolve(Snapshot snapshot) {
122: if (mySnapshot != null) {
123: return;
124: }
125: mySnapshot = snapshot;
126: resolveSuperclass(snapshot);
127: if (super class != null) {
128: ((JavaClass) super class).addSubclass(this );
129: }
130:
131: loader = loader.dereference(snapshot, null);
132: signers = signers.dereference(snapshot, null);
133: protectionDomain = protectionDomain.dereference(snapshot, null);
134:
135: for (int i = 0; i < statics.length; i++) {
136: statics[i].resolve(this , snapshot);
137: }
138: snapshot.getJavaLangClass().addInstance(this );
139: super .resolve(snapshot);
140: return;
141: }
142:
143: /**
144: * Resolve our superclass. This might be called well before
145: * all instances are available (like when reading deferred
146: * instances in a 1.2 dump file :-) Calling this is sufficient
147: * to be able to explore this class' fields.
148: */
149: public void resolveSuperclass(Snapshot snapshot) {
150: if (super class == null) {
151: // We must be java.lang.Object, so we have no superclass.
152: } else {
153: totalNumFields = fields.length;
154: super class = super class.dereference(snapshot, null);
155: if (super class == snapshot.getNullThing()) {
156: super class = null;
157: } else {
158: try {
159: JavaClass sc = (JavaClass) super class;
160: sc.resolveSuperclass(snapshot);
161: totalNumFields += sc.totalNumFields;
162: } catch (ClassCastException ex) {
163: System.out.println("Warning! Superclass of "
164: + name + " is " + super class);
165: super class = null;
166: }
167: }
168: }
169: }
170:
171: public boolean isString() {
172: return mySnapshot.getJavaLangString() == this ;
173: }
174:
175: public boolean isClassLoader() {
176: return mySnapshot.getJavaLangClassLoader().isAssignableFrom(
177: this );
178: }
179:
180: /**
181: * Get a numbered field from this class
182: */
183: public JavaField getField(int i) {
184: if (i < 0 || i >= fields.length) {
185: throw new Error("No field " + i + " for " + name);
186: }
187: return fields[i];
188: }
189:
190: /**
191: * Get the total number of fields that are part of an instance of
192: * this class. That is, include superclasses.
193: */
194: public int getNumFieldsForInstance() {
195: return totalNumFields;
196: }
197:
198: /**
199: * Get a numbered field from all the fields that are part of instance
200: * of this class. That is, include superclasses.
201: */
202: public JavaField getFieldForInstance(int i) {
203: if (super class != null) {
204: JavaClass sc = (JavaClass) super class;
205: if (i < sc.totalNumFields) {
206: return sc.getFieldForInstance(i);
207: }
208: i -= sc.totalNumFields;
209: }
210: return getField(i);
211: }
212:
213: /**
214: * Get the class responsible for field i, where i is a field number that
215: * could be passed into getFieldForInstance.
216: *
217: * @see JavaClass.getFieldForInstance()
218: */
219: public JavaClass getClassForField(int i) {
220: if (super class != null) {
221: JavaClass sc = (JavaClass) super class;
222: if (i < sc.totalNumFields) {
223: return sc.getClassForField(i);
224: }
225: }
226: return this ;
227: }
228:
229: public long getId() {
230: return id;
231: }
232:
233: public String getName() {
234: return name;
235: }
236:
237: public boolean isArray() {
238: return name.indexOf('[') != -1;
239: }
240:
241: public Enumeration getInstances(boolean includeSubclasses) {
242: if (includeSubclasses) {
243: Enumeration res = instances.elements();
244: for (int i = 0; i < subclasses.length; i++) {
245: res = new CompositeEnumeration(res, subclasses[i]
246: .getInstances(true));
247: }
248: return res;
249: } else {
250: return instances.elements();
251: }
252: }
253:
254: /**
255: * @return a count of the instances of this class
256: */
257: public int getInstancesCount(boolean includeSubclasses) {
258: int result = instances.size();
259: if (includeSubclasses) {
260: for (int i = 0; i < subclasses.length; i++) {
261: result += subclasses[i]
262: .getInstancesCount(includeSubclasses);
263: }
264: }
265: return result;
266: }
267:
268: public JavaClass[] getSubclasses() {
269: return subclasses;
270: }
271:
272: /**
273: * This can only safely be called after resolve()
274: */
275: public JavaClass getSuperclass() {
276: return (JavaClass) super class;
277: }
278:
279: /**
280: * This can only safely be called after resolve()
281: */
282: public JavaThing getLoader() {
283: return loader;
284: }
285:
286: /**
287: * This can only safely be called after resolve()
288: */
289: public boolean isBootstrap() {
290: return loader == mySnapshot.getNullThing();
291: }
292:
293: /**
294: * This can only safely be called after resolve()
295: */
296: public JavaThing getSigners() {
297: return signers;
298: }
299:
300: /**
301: * This can only safely be called after resolve()
302: */
303: public JavaThing getProtectionDomain() {
304: return protectionDomain;
305: }
306:
307: public JavaField[] getFields() {
308: return fields;
309: }
310:
311: /**
312: * Includes superclass fields
313: */
314: public JavaField[] getFieldsForInstance() {
315: Vector<JavaField> v = new Vector<JavaField>();
316: addFields(v);
317: JavaField[] result = new JavaField[v.size()];
318: for (int i = 0; i < v.size(); i++) {
319: result[i] = v.elementAt(i);
320: }
321: return result;
322: }
323:
324: public JavaStatic[] getStatics() {
325: return statics;
326: }
327:
328: // returns value of static field of given name
329: public JavaThing getStaticField(String name) {
330: for (int i = 0; i < statics.length; i++) {
331: JavaStatic s = statics[i];
332: if (s.getField().getName().equals(name)) {
333: return s.getValue();
334: }
335: }
336: return null;
337: }
338:
339: public String toString() {
340: return "class " + name;
341: }
342:
343: public int compareTo(JavaThing other) {
344: if (other instanceof JavaClass) {
345: return name.compareTo(((JavaClass) other).name);
346: }
347: return super .compareTo(other);
348: }
349:
350: /**
351: * @return true iff a variable of type this is assignable from an instance
352: * of other
353: */
354: public boolean isAssignableFrom(JavaClass other) {
355: if (this == other) {
356: return true;
357: } else if (other == null) {
358: return false;
359: } else {
360: return isAssignableFrom((JavaClass) other.super class);
361: // Trivial tail recursion: I have faith in javac.
362: }
363: }
364:
365: /**
366: * Describe the reference that this thing has to target. This will only
367: * be called if target is in the array returned by getChildrenForRootset.
368: */
369: public String describeReferenceTo(JavaThing target, Snapshot ss) {
370: for (int i = 0; i < statics.length; i++) {
371: JavaField f = statics[i].getField();
372: if (f.hasId()) {
373: JavaThing other = statics[i].getValue();
374: if (other == target) {
375: return "static field " + f.getName();
376: }
377: }
378: }
379: return super .describeReferenceTo(target, ss);
380: }
381:
382: /**
383: * @return the size of an instance of this class. Gives 0 for an array
384: * type.
385: */
386: public int getInstanceSize() {
387: return instanceSize + mySnapshot.getMinimumObjectSize();
388: }
389:
390: /**
391: * @return The size of all instances of this class. Correctly handles
392: * arrays.
393: */
394: public long getTotalInstanceSize() {
395: int count = instances.size();
396: if (count == 0 || !isArray()) {
397: return count * instanceSize;
398: }
399:
400: // array class and non-zero count, we have to
401: // get the size of each instance and sum it
402: long result = 0;
403: for (int i = 0; i < count; i++) {
404: JavaThing t = (JavaThing) instances.elementAt(i);
405: result += t.getSize();
406: }
407: return result;
408: }
409:
410: /**
411: * @return the size of this object
412: */
413: public int getSize() {
414: JavaClass cl = mySnapshot.getJavaLangClass();
415: if (cl == null) {
416: return 0;
417: } else {
418: return cl.getInstanceSize();
419: }
420: }
421:
422: public void visitReferencedObjects(JavaHeapObjectVisitor v) {
423: super .visitReferencedObjects(v);
424: JavaHeapObject sc = getSuperclass();
425: if (sc != null)
426: v.visit(getSuperclass());
427:
428: JavaThing other;
429: other = getLoader();
430: if (other instanceof JavaHeapObject) {
431: v.visit((JavaHeapObject) other);
432: }
433: other = getSigners();
434: if (other instanceof JavaHeapObject) {
435: v.visit((JavaHeapObject) other);
436: }
437: other = getProtectionDomain();
438: if (other instanceof JavaHeapObject) {
439: v.visit((JavaHeapObject) other);
440: }
441:
442: for (int i = 0; i < statics.length; i++) {
443: JavaField f = statics[i].getField();
444: if (!v.exclude(this , f) && f.hasId()) {
445: other = statics[i].getValue();
446: if (other instanceof JavaHeapObject) {
447: v.visit((JavaHeapObject) other);
448: }
449: }
450: }
451: }
452:
453: // package-privates below this point
454: final ReadBuffer getReadBuffer() {
455: return mySnapshot.getReadBuffer();
456: }
457:
458: final void setNew(JavaHeapObject obj, boolean flag) {
459: mySnapshot.setNew(obj, flag);
460: }
461:
462: final boolean isNew(JavaHeapObject obj) {
463: return mySnapshot.isNew(obj);
464: }
465:
466: final StackTrace getSiteTrace(JavaHeapObject obj) {
467: return mySnapshot.getSiteTrace(obj);
468: }
469:
470: final void addReferenceFromRoot(Root root, JavaHeapObject obj) {
471: mySnapshot.addReferenceFromRoot(root, obj);
472: }
473:
474: final Root getRoot(JavaHeapObject obj) {
475: return mySnapshot.getRoot(obj);
476: }
477:
478: final Snapshot getSnapshot() {
479: return mySnapshot;
480: }
481:
482: void addInstance(JavaHeapObject inst) {
483: instances.addElement(inst);
484: }
485:
486: // Internals only below this point
487: private void addFields(Vector<JavaField> v) {
488: if (super class != null) {
489: ((JavaClass) super class).addFields(v);
490: }
491: for (int i = 0; i < fields.length; i++) {
492: v.addElement(fields[i]);
493: }
494: }
495:
496: private void addSubclassInstances(Vector<JavaHeapObject> v) {
497: for (int i = 0; i < subclasses.length; i++) {
498: subclasses[i].addSubclassInstances(v);
499: }
500: for (int i = 0; i < instances.size(); i++) {
501: v.addElement(instances.elementAt(i));
502: }
503: }
504:
505: private void addSubclass(JavaClass sub) {
506: JavaClass newValue[] = new JavaClass[subclasses.length + 1];
507: System.arraycopy(subclasses, 0, newValue, 0, subclasses.length);
508: newValue[subclasses.length] = sub;
509: subclasses = newValue;
510: }
511: }
|