JavaClass.java revision 2779:56d1e05e0def
1/*
2 * Copyright (c) 1997, 2017, 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    @Override
407    public long getSize() {
408        JavaClass cl = mySnapshot.getJavaLangClass();
409        if (cl == null) {
410            return 0;
411        } else {
412            return cl.getInstanceSize();
413        }
414    }
415
416    public void visitReferencedObjects(JavaHeapObjectVisitor v) {
417        super.visitReferencedObjects(v);
418        JavaHeapObject sc = getSuperclass();
419        if (sc != null) v.visit(getSuperclass());
420
421        JavaThing other;
422        other = getLoader();
423        if (other instanceof JavaHeapObject) {
424            v.visit((JavaHeapObject)other);
425        }
426        other = getSigners();
427        if (other instanceof JavaHeapObject) {
428            v.visit((JavaHeapObject)other);
429        }
430        other = getProtectionDomain();
431        if (other instanceof JavaHeapObject) {
432            v.visit((JavaHeapObject)other);
433        }
434
435        for (int i = 0; i < statics.length; i++) {
436            JavaField f = statics[i].getField();
437            if (!v.exclude(this, f) && f.hasId()) {
438                other = statics[i].getValue();
439                if (other instanceof JavaHeapObject) {
440                    v.visit((JavaHeapObject) other);
441                }
442            }
443        }
444    }
445
446    // package-privates below this point
447    final ReadBuffer getReadBuffer() {
448        return mySnapshot.getReadBuffer();
449    }
450
451    final void setNew(JavaHeapObject obj, boolean flag) {
452        mySnapshot.setNew(obj, flag);
453    }
454
455    final boolean isNew(JavaHeapObject obj) {
456        return mySnapshot.isNew(obj);
457    }
458
459    final StackTrace getSiteTrace(JavaHeapObject obj) {
460        return mySnapshot.getSiteTrace(obj);
461    }
462
463    final void addReferenceFromRoot(Root root, JavaHeapObject obj) {
464        mySnapshot.addReferenceFromRoot(root, obj);
465    }
466
467    final Root getRoot(JavaHeapObject obj) {
468        return mySnapshot.getRoot(obj);
469    }
470
471    final Snapshot getSnapshot() {
472        return mySnapshot;
473    }
474
475    void addInstance(JavaHeapObject inst) {
476        instances.addElement(inst);
477    }
478
479    // Internals only below this point
480    private void addFields(Vector<JavaField> v) {
481        if (superclass != null) {
482            ((JavaClass) superclass).addFields(v);
483        }
484        for (int i = 0; i < fields.length; i++) {
485            v.addElement(fields[i]);
486        }
487    }
488
489    private void addSubclassInstances(Vector<JavaHeapObject> v) {
490        for (int i = 0; i < subclasses.length; i++) {
491            subclasses[i].addSubclassInstances(v);
492        }
493        for (int i = 0; i < instances.size(); i++) {
494            v.addElement(instances.elementAt(i));
495        }
496    }
497
498    private void addSubclass(JavaClass sub) {
499        JavaClass newValue[] = new JavaClass[subclasses.length + 1];
500        System.arraycopy(subclasses, 0, newValue, 0, subclasses.length);
501        newValue[subclasses.length] = sub;
502        subclasses = newValue;
503    }
504}
505