334 lines · 11.7 KB · Java
RawDownload
/* * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */  /* * 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.io.IOException;import com.sun.tools.hat.internal.parser.ReadBuffer; /** * Represents Java instance * * @author      Bill Foote */public class JavaObject extends JavaLazyReadObject {     private Object clazz;       // Number before resolve                                // JavaClass after resolve    /**     * Construct a new JavaObject.     *     * @param classID id of the class object     * @param offset The offset of field data     */    public JavaObject(long classID, long offset) {        super(offset);        this.clazz = makeId(classID);    }     public void resolve(Snapshot snapshot) {        if (clazz instanceof JavaClass) {            return;        }        if (clazz instanceof Number) {            long classID = getIdValue((Number)clazz);            clazz = snapshot.findThing(classID);            if (! (clazz instanceof JavaClass)) {                warn("Class " + Long.toHexString(classID) + " not found, " +                     "adding fake class!");                int length;                ReadBuffer buf = snapshot.getReadBuffer();                int idSize = snapshot.getIdentifierSize();                long lenOffset = getOffset() + 2*idSize + 4;                try {                    length = buf.getInt(lenOffset);                } catch (IOException exp) {                    throw new RuntimeException(exp);                }                clazz = snapshot.addFakeInstanceClass(classID, length);            }        } else {            throw new InternalError("should not reach here");        }         JavaClass cl = (JavaClass) clazz;        cl.resolve(snapshot);         // while resolving, parse fields in verbose mode.        // but, getFields calls parseFields in non-verbose mode        // to avoid printing warnings repeatedly.        parseFields(getValue(), true);         cl.addInstance(this);        super.resolve(snapshot);    }     /**     * Are we the same type as other?  We are iff our clazz is the     * same type as other's.     */    public boolean isSameTypeAs(JavaThing other) {        if (!(other instanceof JavaObject)) {            return false;        }        JavaObject oo = (JavaObject) other;        return getClazz().equals(oo.getClazz());    }     /**     * Return our JavaClass object.  This may only be called after resolve.     */    public JavaClass getClazz() {        return (JavaClass) clazz;    }     public JavaThing[] getFields() {        // pass false to verbose mode so that dereference        // warnings are not printed.        return parseFields(getValue(), false);    }     // returns the value of field of given name    public JavaThing getField(String name) {        JavaThing[] flds = getFields();        JavaField[] instFields = getClazz().getFieldsForInstance();        for (int i = 0; i < instFields.length; i++) {            if (instFields[i].getName().equals(name)) {                return flds[i];            }        }        return null;    }     public int compareTo(JavaThing other) {        if (other instanceof JavaObject) {            JavaObject oo = (JavaObject) other;            return getClazz().getName().compareTo(oo.getClazz().getName());        }        return super.compareTo(other);    }     public void visitReferencedObjects(JavaHeapObjectVisitor v) {        super.visitReferencedObjects(v);        JavaThing[] flds = getFields();        for (int i = 0; i < flds.length; i++) {            if (flds[i] != null) {                if (v.mightExclude()                    && v.exclude(getClazz().getClassForField(i),                                 getClazz().getFieldForInstance(i)))                {                    // skip it                } else if (flds[i] instanceof JavaHeapObject) {                    v.visit((JavaHeapObject) flds[i]);                }            }        }    }     public boolean refersOnlyWeaklyTo(Snapshot ss, JavaThing other) {        if (ss.getWeakReferenceClass() != null) {            final int referentFieldIndex = ss.getReferentFieldIndex();            if (ss.getWeakReferenceClass().isAssignableFrom(getClazz())) {                //                // REMIND:  This introduces a dependency on the JDK                //      implementation that is undesirable.                JavaThing[] flds = getFields();                for (int i = 0; i < flds.length; i++) {                    if (i != referentFieldIndex && flds[i] == other) {                        return false;                    }                }                return true;            }        }        return false;    }     /**     * Describe the reference that this thing has to target.  This will only     * be called if target is in the array returned by getChildrenForRootset.     */    public String describeReferenceTo(JavaThing target, Snapshot ss) {        JavaThing[] flds = getFields();        for (int i = 0; i < flds.length; i++) {            if (flds[i] == target) {                JavaField f = getClazz().getFieldForInstance(i);                return "field " + f.getName();            }        }        return super.describeReferenceTo(target, ss);    }     public String toString() {        if (getClazz().isString()) {            JavaThing value = getField("value");            if (value instanceof JavaValueArray) {                return ((JavaValueArray)value).valueString();            } else {                return "null";            }        } else {            return super.toString();        }    }     // Internals only below this point     /*     * Java instance record (HPROF_GC_INSTANCE_DUMP) looks as below:     *     *     object ID     *     stack trace serial number (int)     *     class ID     *     data length (int)     *     byte[length]     */    protected final int readValueLength() throws IOException {        JavaClass cl = getClazz();        int idSize = cl.getIdentifierSize();        long lengthOffset = getOffset() + 2*idSize + 4;        return cl.getReadBuffer().getInt(lengthOffset);    }     protected final byte[] readValue() throws IOException {        JavaClass cl = getClazz();        int idSize = cl.getIdentifierSize();        ReadBuffer buf = cl.getReadBuffer();        long offset = getOffset() + 2*idSize + 4;        int length = buf.getInt(offset);        if (length == 0) {            return Snapshot.EMPTY_BYTE_ARRAY;        } else {            byte[] res = new byte[length];            buf.get(offset + 4, res);            return res;        }    }     private JavaThing[] parseFields(byte[] data, boolean verbose) {        JavaClass cl = getClazz();        int target = cl.getNumFieldsForInstance();        JavaField[] fields = cl.getFields();        JavaThing[] fieldValues = new JavaThing[target];        Snapshot snapshot = cl.getSnapshot();        int idSize = snapshot.getIdentifierSize();        int fieldNo = 0;        // In the dump file, the fields are stored in this order:        // fields of most derived class (immediate class) are stored        // first and then the super class and so on. In this object,        // fields are stored in the reverse ("natural") order. i.e.,        // fields of most super class are stored first.         // target variable is used to compensate for the fact that        // the dump file starts field values from the leaf working        // upwards in the inheritance hierarchy, whereas JavaObject        // starts with the top of the inheritance hierarchy and works down.        target -= fields.length;        JavaClass currClass = cl;        int index = 0;        for (int i = 0; i < fieldValues.length; i++, fieldNo++) {            while (fieldNo >= fields.length) {                currClass = currClass.getSuperclass();                fields = currClass.getFields();                fieldNo = 0;                target -= fields.length;            }            JavaField f = fields[fieldNo];            char sig = f.getSignature().charAt(0);            switch (sig) {                case 'L':                case '[': {                    long id = objectIdAt(index, data);                    index += idSize;                    JavaObjectRef ref = new JavaObjectRef(id);                    fieldValues[target+fieldNo] = ref.dereference(snapshot, f, verbose);                    break;                }                case 'Z': {                    byte value = byteAt(index, data);                    index++;                    fieldValues[target+fieldNo] = new JavaBoolean(value != 0);                    break;                }                case 'B': {                    byte value = byteAt(index, data);                    index++;                    fieldValues[target+fieldNo] = new JavaByte(value);                    break;                }                case 'S': {                    short value = shortAt(index, data);                    index += 2;                    fieldValues[target+fieldNo] = new JavaShort(value);                    break;                }                case 'C': {                    char value = charAt(index, data);                    index += 2;                    fieldValues[target+fieldNo] = new JavaChar(value);                    break;                }                case 'I': {                    int value = intAt(index, data);                    index += 4;                    fieldValues[target+fieldNo] = new JavaInt(value);                    break;                }                case 'J': {                    long value = longAt(index, data);                    index += 8;                    fieldValues[target+fieldNo] = new JavaLong(value);                    break;                }                case 'F': {                    float value = floatAt(index, data);                    index += 4;                    fieldValues[target+fieldNo] = new JavaFloat(value);                    break;                }                case 'D': {                    double value = doubleAt(index, data);                    index += 8;                    fieldValues[target+fieldNo] = new JavaDouble(value);                    break;                }                default:                    throw new RuntimeException("invalid signature: " + sig);            }        }        return fieldValues;    }     private void warn(String msg) {        System.out.println("WARNING: " + msg);    }}