JavaClass.java revision 2224:2a8815d86b93
1/*
2 * Copyright (c) 1997, 2016, 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
33package jdk.test.lib.hprof.model;
34
35import java.util.Vector;
36import java.util.Enumeration;
37import jdk.test.lib.hprof.util.CompositeEnumeration;
38import jdk.test.lib.hprof.parser.ReadBuffer;
39
40/**
41 *
42 * @author      Bill Foote
43 */
44
45
46public 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}
504