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