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