/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.hit; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.util.Set; public class ArrayInstance extends Instance { private int mType; private int mNumEntries; private byte[] mData; public ArrayInstance(long id, StackTrace stack, int type, int numEntries, byte[] data) { mId = id; mStack = stack; mType = type; mNumEntries = numEntries; mData = data; } public final void resolveReferences(State state) { if (mType != Types.OBJECT) { return; } /* * mData holds a stream of object instance ids * Spin through them all and list ourselves as a reference holder. */ int idSize = Types.getTypeSize(mType); final int N = mNumEntries; ByteArrayInputStream bais = new ByteArrayInputStream(mData); DataInputStream dis = new DataInputStream(bais); for (int i = 0; i < N; i++) { long id; try { if (idSize == 4) { id = dis.readInt(); } else { id = dis.readLong(); } Instance instance = state.findReference(id); if (instance != null) { instance.addParent(this); } } catch (java.io.IOException e) { e.printStackTrace(); } } } @Override public final int getSize() { return mData.length; } @Override public final void visit(Set resultSet, Filter filter) { // If we're in the set then we and our children have been visited if (resultSet.contains(this)) { return; } if (null != filter) { if (filter.accept(this)) { resultSet.add(this); } } else { resultSet.add(this); } if (mType != Types.OBJECT) { return; } /* * mData holds a stream of object instance ids * Spin through them all and visit them */ int idSize = Types.getTypeSize(mType); final int N = mNumEntries; ByteArrayInputStream bais = new ByteArrayInputStream(mData); DataInputStream dis = new DataInputStream(bais); State state = mHeap.mState; for (int i = 0; i < N; i++) { long id; try { if (idSize == 4) { id = dis.readInt(); } else { id = dis.readLong(); } Instance instance = state.findReference(id); if (instance != null) { instance.visit(resultSet, filter); } } catch (java.io.IOException e) { e.printStackTrace(); } } } @Override public final String getTypeName() { return Types.getTypeName(mType) + "[" + mNumEntries + "]"; } public final String toString() { return String.format("%s@0x08x", getTypeName(), mId); } @Override public String describeReferenceTo(long referent) { // If this isn't an object array then we can't refer to an object if (mType != Types.OBJECT) { return super.describeReferenceTo(referent); } int idSize = Types.getTypeSize(mType); final int N = mNumEntries; int numRefs = 0; StringBuilder result = new StringBuilder("Elements ["); ByteArrayInputStream bais = new ByteArrayInputStream(mData); DataInputStream dis = new DataInputStream(bais); /* * Spin through all the objects and build up a string describing * all of the array elements that refer to the target object. */ for (int i = 0; i < N; i++) { long id; try { if (idSize == 4) { id = dis.readInt(); } else { id = dis.readLong(); } if (id == referent) { numRefs++; if (numRefs > 1) { result.append(", "); } result.append(i); } } catch (java.io.IOException e) { e.printStackTrace(); } } if (numRefs == 0) { return super.describeReferenceTo(referent); } result.append("]"); return result.toString(); } }