jdk/src/jdk.dev/share/classes/com/sun/tools/hat/internal/model/JavaObject.java
changeset 30779 92bb39a2a876
parent 30778 43087a23d825
parent 30736 ff3fc75f3214
child 30780 b83f001a855d
child 30886 d2a0ec86d6ef
equal deleted inserted replaced
30778:43087a23d825 30779:92bb39a2a876
     1 /*
       
     2  * Copyright (c) 1997, 2008, 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 
       
    33 package com.sun.tools.hat.internal.model;
       
    34 
       
    35 import java.io.IOException;
       
    36 import com.sun.tools.hat.internal.parser.ReadBuffer;
       
    37 
       
    38 /**
       
    39  * Represents Java instance
       
    40  *
       
    41  * @author      Bill Foote
       
    42  */
       
    43 public class JavaObject extends JavaLazyReadObject {
       
    44 
       
    45     private Object clazz;       // Number before resolve
       
    46                                 // JavaClass after resolve
       
    47     /**
       
    48      * Construct a new JavaObject.
       
    49      *
       
    50      * @param classID id of the class object
       
    51      * @param offset The offset of field data
       
    52      */
       
    53     public JavaObject(long classID, long offset) {
       
    54         super(offset);
       
    55         this.clazz = makeId(classID);
       
    56     }
       
    57 
       
    58     public void resolve(Snapshot snapshot) {
       
    59         if (clazz instanceof JavaClass) {
       
    60             return;
       
    61         }
       
    62         if (clazz instanceof Number) {
       
    63             long classID = getIdValue((Number)clazz);
       
    64             clazz = snapshot.findThing(classID);
       
    65             if (! (clazz instanceof JavaClass)) {
       
    66                 warn("Class " + Long.toHexString(classID) + " not found, " +
       
    67                      "adding fake class!");
       
    68                 int length;
       
    69                 ReadBuffer buf = snapshot.getReadBuffer();
       
    70                 int idSize = snapshot.getIdentifierSize();
       
    71                 long lenOffset = getOffset() + 2*idSize + 4;
       
    72                 try {
       
    73                     length = buf.getInt(lenOffset);
       
    74                 } catch (IOException exp) {
       
    75                     throw new RuntimeException(exp);
       
    76                 }
       
    77                 clazz = snapshot.addFakeInstanceClass(classID, length);
       
    78             }
       
    79         } else {
       
    80             throw new InternalError("should not reach here");
       
    81         }
       
    82 
       
    83         JavaClass cl = (JavaClass) clazz;
       
    84         cl.resolve(snapshot);
       
    85 
       
    86         // while resolving, parse fields in verbose mode.
       
    87         // but, getFields calls parseFields in non-verbose mode
       
    88         // to avoid printing warnings repeatedly.
       
    89         parseFields(getValue(), true);
       
    90 
       
    91         cl.addInstance(this);
       
    92         super.resolve(snapshot);
       
    93     }
       
    94 
       
    95     /**
       
    96      * Are we the same type as other?  We are iff our clazz is the
       
    97      * same type as other's.
       
    98      */
       
    99     public boolean isSameTypeAs(JavaThing other) {
       
   100         if (!(other instanceof JavaObject)) {
       
   101             return false;
       
   102         }
       
   103         JavaObject oo = (JavaObject) other;
       
   104         return getClazz().equals(oo.getClazz());
       
   105     }
       
   106 
       
   107     /**
       
   108      * Return our JavaClass object.  This may only be called after resolve.
       
   109      */
       
   110     public JavaClass getClazz() {
       
   111         return (JavaClass) clazz;
       
   112     }
       
   113 
       
   114     public JavaThing[] getFields() {
       
   115         // pass false to verbose mode so that dereference
       
   116         // warnings are not printed.
       
   117         return parseFields(getValue(), false);
       
   118     }
       
   119 
       
   120     // returns the value of field of given name
       
   121     public JavaThing getField(String name) {
       
   122         JavaThing[] flds = getFields();
       
   123         JavaField[] instFields = getClazz().getFieldsForInstance();
       
   124         for (int i = 0; i < instFields.length; i++) {
       
   125             if (instFields[i].getName().equals(name)) {
       
   126                 return flds[i];
       
   127             }
       
   128         }
       
   129         return null;
       
   130     }
       
   131 
       
   132     public int compareTo(JavaThing other) {
       
   133         if (other instanceof JavaObject) {
       
   134             JavaObject oo = (JavaObject) other;
       
   135             return getClazz().getName().compareTo(oo.getClazz().getName());
       
   136         }
       
   137         return super.compareTo(other);
       
   138     }
       
   139 
       
   140     public void visitReferencedObjects(JavaHeapObjectVisitor v) {
       
   141         super.visitReferencedObjects(v);
       
   142         JavaThing[] flds = getFields();
       
   143         for (int i = 0; i < flds.length; i++) {
       
   144             if (flds[i] != null) {
       
   145                 if (v.mightExclude()
       
   146                     && v.exclude(getClazz().getClassForField(i),
       
   147                                  getClazz().getFieldForInstance(i)))
       
   148                 {
       
   149                     // skip it
       
   150                 } else if (flds[i] instanceof JavaHeapObject) {
       
   151                     v.visit((JavaHeapObject) flds[i]);
       
   152                 }
       
   153             }
       
   154         }
       
   155     }
       
   156 
       
   157     public boolean refersOnlyWeaklyTo(Snapshot ss, JavaThing other) {
       
   158         if (ss.getWeakReferenceClass() != null) {
       
   159             final int referentFieldIndex = ss.getReferentFieldIndex();
       
   160             if (ss.getWeakReferenceClass().isAssignableFrom(getClazz())) {
       
   161                 //
       
   162                 // REMIND:  This introduces a dependency on the JDK
       
   163                 //      implementation that is undesirable.
       
   164                 JavaThing[] flds = getFields();
       
   165                 for (int i = 0; i < flds.length; i++) {
       
   166                     if (i != referentFieldIndex && flds[i] == other) {
       
   167                         return false;
       
   168                     }
       
   169                 }
       
   170                 return true;
       
   171             }
       
   172         }
       
   173         return false;
       
   174     }
       
   175 
       
   176     /**
       
   177      * Describe the reference that this thing has to target.  This will only
       
   178      * be called if target is in the array returned by getChildrenForRootset.
       
   179      */
       
   180     public String describeReferenceTo(JavaThing target, Snapshot ss) {
       
   181         JavaThing[] flds = getFields();
       
   182         for (int i = 0; i < flds.length; i++) {
       
   183             if (flds[i] == target) {
       
   184                 JavaField f = getClazz().getFieldForInstance(i);
       
   185                 return "field " + f.getName();
       
   186             }
       
   187         }
       
   188         return super.describeReferenceTo(target, ss);
       
   189     }
       
   190 
       
   191     public String toString() {
       
   192         if (getClazz().isString()) {
       
   193             JavaThing value = getField("value");
       
   194             if (value instanceof JavaValueArray) {
       
   195                 return ((JavaValueArray)value).valueString();
       
   196             } else {
       
   197                 return "null";
       
   198             }
       
   199         } else {
       
   200             return super.toString();
       
   201         }
       
   202     }
       
   203 
       
   204     // Internals only below this point
       
   205 
       
   206     /*
       
   207      * Java instance record (HPROF_GC_INSTANCE_DUMP) looks as below:
       
   208      *
       
   209      *     object ID
       
   210      *     stack trace serial number (int)
       
   211      *     class ID
       
   212      *     data length (int)
       
   213      *     byte[length]
       
   214      */
       
   215     protected final int readValueLength() throws IOException {
       
   216         JavaClass cl = getClazz();
       
   217         int idSize = cl.getIdentifierSize();
       
   218         long lengthOffset = getOffset() + 2*idSize + 4;
       
   219         return cl.getReadBuffer().getInt(lengthOffset);
       
   220     }
       
   221 
       
   222     protected final byte[] readValue() throws IOException {
       
   223         JavaClass cl = getClazz();
       
   224         int idSize = cl.getIdentifierSize();
       
   225         ReadBuffer buf = cl.getReadBuffer();
       
   226         long offset = getOffset() + 2*idSize + 4;
       
   227         int length = buf.getInt(offset);
       
   228         if (length == 0) {
       
   229             return Snapshot.EMPTY_BYTE_ARRAY;
       
   230         } else {
       
   231             byte[] res = new byte[length];
       
   232             buf.get(offset + 4, res);
       
   233             return res;
       
   234         }
       
   235     }
       
   236 
       
   237     private JavaThing[] parseFields(byte[] data, boolean verbose) {
       
   238         JavaClass cl = getClazz();
       
   239         int target = cl.getNumFieldsForInstance();
       
   240         JavaField[] fields = cl.getFields();
       
   241         JavaThing[] fieldValues = new JavaThing[target];
       
   242         Snapshot snapshot = cl.getSnapshot();
       
   243         int idSize = snapshot.getIdentifierSize();
       
   244         int fieldNo = 0;
       
   245         // In the dump file, the fields are stored in this order:
       
   246         // fields of most derived class (immediate class) are stored
       
   247         // first and then the super class and so on. In this object,
       
   248         // fields are stored in the reverse ("natural") order. i.e.,
       
   249         // fields of most super class are stored first.
       
   250 
       
   251         // target variable is used to compensate for the fact that
       
   252         // the dump file starts field values from the leaf working
       
   253         // upwards in the inheritance hierarchy, whereas JavaObject
       
   254         // starts with the top of the inheritance hierarchy and works down.
       
   255         target -= fields.length;
       
   256         JavaClass currClass = cl;
       
   257         int index = 0;
       
   258         for (int i = 0; i < fieldValues.length; i++, fieldNo++) {
       
   259             while (fieldNo >= fields.length) {
       
   260                 currClass = currClass.getSuperclass();
       
   261                 fields = currClass.getFields();
       
   262                 fieldNo = 0;
       
   263                 target -= fields.length;
       
   264             }
       
   265             JavaField f = fields[fieldNo];
       
   266             char sig = f.getSignature().charAt(0);
       
   267             switch (sig) {
       
   268                 case 'L':
       
   269                 case '[': {
       
   270                     long id = objectIdAt(index, data);
       
   271                     index += idSize;
       
   272                     JavaObjectRef ref = new JavaObjectRef(id);
       
   273                     fieldValues[target+fieldNo] = ref.dereference(snapshot, f, verbose);
       
   274                     break;
       
   275                 }
       
   276                 case 'Z': {
       
   277                     byte value = byteAt(index, data);
       
   278                     index++;
       
   279                     fieldValues[target+fieldNo] = new JavaBoolean(value != 0);
       
   280                     break;
       
   281                 }
       
   282                 case 'B': {
       
   283                     byte value = byteAt(index, data);
       
   284                     index++;
       
   285                     fieldValues[target+fieldNo] = new JavaByte(value);
       
   286                     break;
       
   287                 }
       
   288                 case 'S': {
       
   289                     short value = shortAt(index, data);
       
   290                     index += 2;
       
   291                     fieldValues[target+fieldNo] = new JavaShort(value);
       
   292                     break;
       
   293                 }
       
   294                 case 'C': {
       
   295                     char value = charAt(index, data);
       
   296                     index += 2;
       
   297                     fieldValues[target+fieldNo] = new JavaChar(value);
       
   298                     break;
       
   299                 }
       
   300                 case 'I': {
       
   301                     int value = intAt(index, data);
       
   302                     index += 4;
       
   303                     fieldValues[target+fieldNo] = new JavaInt(value);
       
   304                     break;
       
   305                 }
       
   306                 case 'J': {
       
   307                     long value = longAt(index, data);
       
   308                     index += 8;
       
   309                     fieldValues[target+fieldNo] = new JavaLong(value);
       
   310                     break;
       
   311                 }
       
   312                 case 'F': {
       
   313                     float value = floatAt(index, data);
       
   314                     index += 4;
       
   315                     fieldValues[target+fieldNo] = new JavaFloat(value);
       
   316                     break;
       
   317                 }
       
   318                 case 'D': {
       
   319                     double value = doubleAt(index, data);
       
   320                     index += 8;
       
   321                     fieldValues[target+fieldNo] = new JavaDouble(value);
       
   322                     break;
       
   323                 }
       
   324                 default:
       
   325                     throw new RuntimeException("invalid signature: " + sig);
       
   326             }
       
   327         }
       
   328         return fieldValues;
       
   329     }
       
   330 
       
   331     private void warn(String msg) {
       
   332         System.out.println("WARNING: " + msg);
       
   333     }
       
   334 }