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
17package com.android.hit;
18
19import java.io.ByteArrayInputStream;
20import java.io.DataInputStream;
21import java.util.ArrayList;
22import java.util.HashSet;
23import java.util.Set;
24
25public class ClassObj extends Instance implements Comparable<ClassObj> {
26    String mClassName;
27    long mSuperclassId;
28
29    String[] mFieldNames;
30    int[] mFieldTypes;
31
32    String[] mStaticFieldNames;
33    int[] mStaticFieldTypes;
34    byte[] mStaticFieldValues;
35
36    ArrayList<Instance> mInstances = new ArrayList<Instance>();
37    Set<ClassObj> mSubclasses = new HashSet<ClassObj>();
38
39    int mSize;
40
41    public ClassObj(long id, StackTrace stack, String className) {
42        mId = id;
43        mStack = stack;
44        mClassName = className;
45    }
46
47    @Override
48    public final void resolveReferences(State state) {
49        ByteArrayInputStream bais =
50            new ByteArrayInputStream(mStaticFieldValues);
51        DataInputStream dis = new DataInputStream(bais);
52        int[] types = mStaticFieldTypes;
53        final int N = types.length;
54
55        /*
56         * Spin through the list of static fields, find all object references,
57         * and list ourselves as a reference holder.  Also add them to
58         * the list of root objects.
59         */
60        try {
61            for (int i = 0; i < N; i++) {
62                int type = types[i];
63                int size = Types.getTypeSize(type);
64
65                if (type == Types.OBJECT) {
66                    long id;
67
68                    if (size == 4) {
69                        id = dis.readInt();
70                    } else {
71                        id = dis.readLong();
72                    }
73
74                    RootObj root = new RootObj(RootType.JAVA_STATIC, id);
75
76                    if (id == 0) {
77                        root.mComment = String.format(
78                            "Static field %s:%s null",
79                                mClassName,
80                                mStaticFieldNames[i]);
81                    } else {
82                        Instance instance = state.findReference(id);
83
84                        instance.addParent(this);
85
86                        root.mComment = String.format(
87                            "Static field %s:%s %s [%s] 0x%08x",
88                                mClassName,
89                                mStaticFieldNames[i],
90                                instance.getTypeName(),
91                                instance.mHeap.mName,
92                                id);
93                    }
94
95                    mHeap.addRoot(root);
96                } else {
97                    dis.skipBytes(size);
98                }
99            }
100        } catch (Exception e) {
101            e.printStackTrace();
102            System.exit(1);
103        }
104
105        //  Lastly, add ourself as a subclass of our superclass
106        if (mSuperclassId != 0) {
107            ClassObj superclass = state.findClass(mSuperclassId);
108
109            superclass.addSubclass(this);
110        }
111    }
112
113    public final void addSubclass(ClassObj subclass) {
114        mSubclasses.add(subclass);
115    }
116
117    public final void dumpSubclasses() {
118        for (ClassObj subclass: mSubclasses) {
119            System.out.println("     " + subclass.mClassName);
120        }
121    }
122
123    public final String toString() {
124        return mClassName.replace('/', '.');
125    }
126
127    public final void addInstance(Instance instance) {
128        mInstances.add(instance);
129    }
130
131    public final void setSuperclassId(long id) {
132        mSuperclassId = id;
133    }
134
135    public final void setFieldNames(String[] names) {
136        mFieldNames = names;
137    }
138
139    public final void setFieldTypes(int[] types) {
140        mFieldTypes = types;
141    }
142
143    public final void setStaticFieldNames(String[] names) {
144        mStaticFieldNames = names;
145    }
146
147    public final void setStaticFieldTypes(int[] types) {
148        mStaticFieldTypes = types;
149    }
150
151    public final void setStaticFieldValues(byte[] values) {
152        mStaticFieldValues = values;
153    }
154
155    public final void dump() {
156        System.out.println("+----------  ClassObj dump for: " + mClassName);
157
158        System.out.println("+-----  Static fields");
159
160        for (int i = 0; i < mStaticFieldNames.length; i++) {
161            System.out.println(mStaticFieldNames[i] + ": "
162                + mStaticFieldTypes[i]);
163        }
164
165        System.out.println("+-----  Instance fields");
166
167        for (int i = 0; i < mFieldNames.length; i++) {
168            System.out.println(mFieldNames[i] + ": " + mFieldTypes[i]);
169        }
170    }
171
172    @Override
173    public final String getTypeName() {
174        return "class " + mClassName;
175    }
176
177    @Override
178    public final void visit(Set<Instance> resultSet, Filter filter) {
179        if (resultSet.contains(this)) {
180            return;
181        }
182
183        if (filter != null) {
184            if (filter.accept(this)) {
185                resultSet.add(this);
186            }
187        } else {
188            resultSet.add(this);
189        }
190
191        ByteArrayInputStream bais =
192            new ByteArrayInputStream(mStaticFieldValues);
193        DataInputStream dis = new DataInputStream(bais);
194        int[] types = mStaticFieldTypes;
195        final int N = types.length;
196        State state = mHeap.mState;
197
198        /*
199         * Spin through the list of static fields, find all object references,
200         * and visit them.
201         */
202        try {
203            for (int i = 0; i < N; i++) {
204                int type = types[i];
205                int size = Types.getTypeSize(type);
206
207                if (type == Types.OBJECT) {
208                    long id;
209
210                    if (size == 4) {
211                        id = dis.readInt();
212                    } else {
213                        id = dis.readLong();
214                    }
215
216                    Instance instance = state.findReference(id);
217
218                    if (instance != null) {
219                        instance.visit(resultSet, filter);
220                    }
221                } else {
222                    dis.skipBytes(size);
223                }
224            }
225        } catch (Exception e) {
226            e.printStackTrace();
227        }
228    }
229
230    public final int compareTo(ClassObj o) {
231        return mClassName.compareTo(o.mClassName);
232    }
233
234    public final boolean equals(Object o) {
235        if (! (o instanceof ClassObj)) {
236            return false;
237        }
238
239        return 0 == compareTo((ClassObj) o);
240    }
241}
242