Home | History | Annotate | Download | only in hit
      1 /*
      2  * Copyright (C) 2008 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.hit;
     18 
     19 import java.io.ByteArrayInputStream;
     20 import java.io.DataInputStream;
     21 import java.io.IOException;
     22 import java.util.Set;
     23 
     24 public class ClassInstance extends Instance {
     25     private byte[] mFieldValues;
     26 
     27     public ClassInstance(long id, StackTrace stack, long classId) {
     28         mId = id;
     29         mStack = stack;
     30         mClassId = classId;
     31     }
     32 
     33     public final void loadFieldData(DataInputStream in, int numBytes)
     34             throws IOException {
     35         mFieldValues = new byte[numBytes];
     36         in.readFully(mFieldValues);
     37     }
     38 
     39     @Override
     40     public void resolveReferences(State state) {
     41         ClassObj isa = mHeap.mState.findClass(mClassId);
     42 
     43         resolve(state, isa, isa.mStaticFieldTypes, isa.mStaticFieldValues);
     44         resolve(state, isa, isa.mFieldTypes, mFieldValues);
     45     }
     46 
     47     private void resolve(State state, ClassObj isa, int[] types,
     48             byte[] values) {
     49         ByteArrayInputStream bais = new ByteArrayInputStream(values);
     50         DataInputStream dis = new DataInputStream(bais);
     51         final int N = types.length;
     52 
     53         /*
     54          * Spin through the list of fields, find all object references,
     55          * and list ourselves as a reference holder.
     56          */
     57         try {
     58             for (int i = 0; i < N; i++) {
     59                 int type = types[i];
     60                 int size = Types.getTypeSize(type);
     61 
     62                     if (type == Types.OBJECT) {
     63                         long id;
     64 
     65                         if (size == 4) {
     66                             id = dis.readInt();
     67                         } else {
     68                             id = dis.readLong();
     69                         }
     70 
     71                         Instance instance = state.findReference(id);
     72 
     73                         if (instance != null) {
     74                             instance.addParent(this);
     75                         }
     76                     } else {
     77                         dis.skipBytes(size);
     78                     }
     79             }
     80         } catch (Exception e) {
     81             e.printStackTrace();
     82         }
     83     }
     84 
     85     @Override
     86     public final int getSize() {
     87         ClassObj isa = mHeap.mState.findClass(mClassId);
     88 
     89         return isa.getSize();
     90     }
     91 
     92     @Override
     93     public final void visit(Set<Instance> resultSet, Filter filter) {
     94         if (resultSet.contains(this)) {
     95             return;
     96         }
     97 
     98         if (filter != null) {
     99             if (filter.accept(this)) {
    100                 resultSet.add(this);
    101             }
    102         } else {
    103             resultSet.add(this);
    104         }
    105 
    106         State state = mHeap.mState;
    107         ClassObj isa = state.findClass(mClassId);
    108         int[] types = isa.mFieldTypes;
    109         ByteArrayInputStream bais = new ByteArrayInputStream(mFieldValues);
    110         DataInputStream dis = new DataInputStream(bais);
    111         final int N = types.length;
    112 
    113         /*
    114          * Spin through the list of fields, find all object references,
    115          * and list ourselves as a reference holder.
    116          */
    117         try {
    118             for (int i = 0; i < N; i++) {
    119                 int type = types[i];
    120                 int size = Types.getTypeSize(type);
    121 
    122                 if (type == Types.OBJECT) {
    123                     long id;
    124 
    125                     if (size == 4) {
    126                         id = dis.readInt();
    127                     } else {
    128                         id = dis.readLong();
    129                     }
    130 
    131                     Instance instance = state.findReference(id);
    132 
    133                     if (instance != null) {
    134                         instance.visit(resultSet, filter);
    135                     }
    136                 } else {
    137                     dis.skipBytes(size);
    138                 }
    139             }
    140         } catch (Exception e) {
    141             e.printStackTrace();
    142         }
    143     }
    144 
    145     @Override
    146     public final String getTypeName() {
    147         ClassObj theClass = mHeap.mState.findClass(mClassId);
    148 
    149         return theClass.mClassName;
    150     }
    151 
    152     public final String toString() {
    153         return String.format("%s@0x%08x", getTypeName(), mId);
    154     }
    155 
    156     @Override
    157     public String describeReferenceTo(long referent) {
    158         ClassObj isa = mHeap.mState.findClass(mClassId);
    159         int[] types = isa.mFieldTypes;
    160         String[] fieldNames = isa.mFieldNames;
    161         ByteArrayInputStream bais = new ByteArrayInputStream(mFieldValues);
    162         DataInputStream dis = new DataInputStream(bais);
    163         final int N = types.length;
    164         StringBuilder result = new StringBuilder("Referenced in field(s):");
    165         int numReferences = 0;
    166 
    167         /*
    168          * Spin through the list of fields, add info about the field
    169          * references to the output text.
    170          */
    171         try {
    172             for (int i = 0; i < N; i++) {
    173                 int type = types[i];
    174                 int size = Types.getTypeSize(type);
    175 
    176                 if (type == Types.OBJECT) {
    177                     long id;
    178 
    179                     if (size == 4) {
    180                         id = dis.readInt();
    181                     } else {
    182                         id = dis.readLong();
    183                     }
    184 
    185                     if (id == referent) {
    186                         numReferences++;
    187                         result.append("\n    ");
    188                         result.append(fieldNames[i]);
    189                     }
    190                 } else {
    191                     dis.skipBytes(size);
    192                 }
    193             }
    194         } catch (Exception e) {
    195             e.printStackTrace();
    196         }
    197 
    198         /*
    199          *  TODO:  perform a similar loop over the static fields of isa
    200          */
    201 
    202         if (numReferences == 0) {
    203             return super.describeReferenceTo(referent);
    204         }
    205 
    206         return result.toString();
    207     }
    208 }
    209