0
|
1 /*
|
|
2 * Copyright 2004-2005 Sun Microsystems, Inc. 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.
|
|
8 *
|
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 * version 2 for more details (a copy is included in the LICENSE file that
|
|
13 * accompanied this code).
|
|
14 *
|
|
15 * You should have received a copy of the GNU General Public License version
|
|
16 * 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 *
|
|
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any questions.
|
|
22 *
|
|
23 */
|
|
24
|
|
25 package sun.jvm.hotspot.utilities;
|
|
26
|
|
27 import java.io.*;
|
|
28 import sun.jvm.hotspot.debugger.*;
|
|
29 import sun.jvm.hotspot.memory.*;
|
|
30 import sun.jvm.hotspot.oops.*;
|
|
31 import sun.jvm.hotspot.runtime.*;
|
|
32
|
|
33 /**
|
|
34 * This is abstract base class for heap graph writers. This class does
|
|
35 * not assume any file format for the heap graph. It hides heap
|
|
36 * iteration, object (fields) iteration mechanism from derived
|
|
37 * classes. This class does not even accept OutputStream etc. so that
|
|
38 * derived class can construct specific writer/filter from input
|
|
39 * stream.
|
|
40 */
|
|
41
|
|
42 public abstract class AbstractHeapGraphWriter implements HeapGraphWriter {
|
|
43 // the function iterates heap and calls Oop type specific writers
|
|
44 protected void write() throws IOException {
|
|
45 SymbolTable symTbl = VM.getVM().getSymbolTable();
|
|
46 javaLangClass = symTbl.probe("java/lang/Class");
|
|
47 javaLangString = symTbl.probe("java/lang/String");
|
|
48 javaLangThread = symTbl.probe("java/lang/Thread");
|
|
49 ObjectHeap heap = VM.getVM().getObjectHeap();
|
|
50 try {
|
|
51 heap.iterate(new DefaultHeapVisitor() {
|
|
52 public void prologue(long usedSize) {
|
|
53 try {
|
|
54 writeHeapHeader();
|
|
55 } catch (IOException exp) {
|
|
56 throw new RuntimeException(exp);
|
|
57 }
|
|
58 }
|
|
59
|
|
60 public boolean doObj(Oop oop) {
|
|
61 try {
|
|
62 if (oop instanceof TypeArray) {
|
|
63 writePrimitiveArray((TypeArray)oop);
|
|
64 } else if (oop instanceof ObjArray) {
|
|
65 Klass klass = oop.getKlass();
|
|
66 ObjArrayKlass oak = (ObjArrayKlass) klass;
|
|
67 Klass bottomType = oak.getBottomKlass();
|
|
68 if (bottomType instanceof InstanceKlass ||
|
|
69 bottomType instanceof TypeArrayKlass) {
|
|
70 writeObjectArray((ObjArray)oop);
|
|
71 } else {
|
|
72 writeInternalObject(oop);
|
|
73 }
|
|
74 } else if (oop instanceof Instance) {
|
|
75 Instance instance = (Instance) oop;
|
|
76 Klass klass = instance.getKlass();
|
|
77 Symbol name = klass.getName();
|
|
78 if (name.equals(javaLangString)) {
|
|
79 writeString(instance);
|
|
80 } else if (name.equals(javaLangClass)) {
|
|
81 writeClass(instance);
|
|
82 } else if (name.equals(javaLangThread)) {
|
|
83 writeThread(instance);
|
|
84 } else {
|
|
85 klass = klass.getSuper();
|
|
86 while (klass != null) {
|
|
87 name = klass.getName();
|
|
88 if (name.equals(javaLangThread)) {
|
|
89 writeThread(instance);
|
|
90 return false;
|
|
91 }
|
|
92 klass = klass.getSuper();
|
|
93 }
|
|
94 writeInstance(instance);
|
|
95 }
|
|
96 } else {
|
|
97 // not-a-Java-visible oop
|
|
98 writeInternalObject(oop);
|
|
99 }
|
|
100 } catch (IOException exp) {
|
|
101 throw new RuntimeException(exp);
|
|
102 }
|
|
103 return false;
|
|
104 }
|
|
105
|
|
106 public void epilogue() {
|
|
107 try {
|
|
108 writeHeapFooter();
|
|
109 } catch (IOException exp) {
|
|
110 throw new RuntimeException(exp);
|
|
111 }
|
|
112 }
|
|
113 });
|
|
114
|
|
115 // write JavaThreads
|
|
116 writeJavaThreads();
|
|
117
|
|
118 // write JNI global handles
|
|
119 writeGlobalJNIHandles();
|
|
120
|
|
121 } catch (RuntimeException re) {
|
|
122 handleRuntimeException(re);
|
|
123 }
|
|
124 }
|
|
125
|
|
126 protected void writeJavaThreads() throws IOException {
|
|
127 Threads threads = VM.getVM().getThreads();
|
|
128 JavaThread jt = threads.first();
|
|
129 int index = 1;
|
|
130 while (jt != null) {
|
|
131 if (jt.getThreadObj() != null) {
|
|
132 // Note that the thread serial number range is 1-to-N
|
|
133 writeJavaThread(jt, index);
|
|
134 index++;
|
|
135 }
|
|
136 jt = jt.next();
|
|
137 }
|
|
138 }
|
|
139
|
|
140 protected void writeJavaThread(JavaThread jt, int index)
|
|
141 throws IOException {
|
|
142 }
|
|
143
|
|
144 protected void writeGlobalJNIHandles() throws IOException {
|
|
145 JNIHandles handles = VM.getVM().getJNIHandles();
|
|
146 JNIHandleBlock blk = handles.globalHandles();
|
|
147 if (blk != null) {
|
|
148 try {
|
|
149 blk.oopsDo(new AddressVisitor() {
|
|
150 public void visitAddress(Address handleAddr) {
|
|
151 try {
|
|
152 if (handleAddr != null) {
|
|
153 writeGlobalJNIHandle(handleAddr);
|
|
154 }
|
|
155 } catch (IOException exp) {
|
|
156 throw new RuntimeException(exp);
|
|
157 }
|
|
158 }
|
|
159 });
|
|
160 } catch (RuntimeException re) {
|
|
161 handleRuntimeException(re);
|
|
162 }
|
|
163 }
|
|
164 }
|
|
165
|
|
166 protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
|
|
167 }
|
|
168
|
|
169 protected void writeHeapHeader() throws IOException {
|
|
170 }
|
|
171
|
|
172 // write non-Java-visible (hotspot internal) object
|
|
173 protected void writeInternalObject(Oop oop) throws IOException {
|
|
174 }
|
|
175
|
|
176 // write Java primitive array
|
|
177 protected void writePrimitiveArray(TypeArray array) throws IOException {
|
|
178 writeObject(array);
|
|
179 }
|
|
180
|
|
181 // write Java object array
|
|
182 protected void writeObjectArray(ObjArray array) throws IOException {
|
|
183 writeObject(array);
|
|
184 }
|
|
185
|
|
186 protected void writeInstance(Instance instance) throws IOException {
|
|
187 writeObject(instance);
|
|
188 }
|
|
189
|
|
190 protected void writeString(Instance instance) throws IOException {
|
|
191 writeInstance(instance);
|
|
192 }
|
|
193
|
|
194 protected void writeClass(Instance instance) throws IOException {
|
|
195 writeInstance(instance);
|
|
196 }
|
|
197
|
|
198 protected void writeThread(Instance instance) throws IOException {
|
|
199 writeInstance(instance);
|
|
200 }
|
|
201
|
|
202 protected void writeObject(Oop oop) throws IOException {
|
|
203 writeObjectHeader(oop);
|
|
204 writeObjectFields(oop);
|
|
205 writeObjectFooter(oop);
|
|
206 }
|
|
207
|
|
208 protected void writeObjectHeader(Oop oop) throws IOException {
|
|
209 }
|
|
210
|
|
211 // write instance fields of given object
|
|
212 protected void writeObjectFields(final Oop oop) throws IOException {
|
|
213 try {
|
|
214 oop.iterate(new DefaultOopVisitor() {
|
|
215 public void doOop(OopField field, boolean isVMField) {
|
|
216 try {
|
|
217 Oop ref = field.getValue(oop);
|
|
218 if (ref instanceof TypeArray ||
|
|
219 ref instanceof ObjArray ||
|
|
220 ref instanceof Instance) {
|
|
221 writeReferenceField(oop, field);
|
|
222 } else {
|
|
223 writeInternalReferenceField(oop, field);
|
|
224 }
|
|
225 } catch (IOException exp) {
|
|
226 throw new RuntimeException(exp);
|
|
227 }
|
|
228 }
|
|
229
|
|
230 public void doByte(ByteField field, boolean isVMField) {
|
|
231 try {
|
|
232 writeByteField(oop, field);
|
|
233 } catch (IOException exp) {
|
|
234 throw new RuntimeException(exp);
|
|
235 }
|
|
236 }
|
|
237
|
|
238 public void doChar(CharField field, boolean isVMField) {
|
|
239 try {
|
|
240 writeCharField(oop, field);
|
|
241 } catch (IOException exp) {
|
|
242 throw new RuntimeException(exp);
|
|
243 }
|
|
244 }
|
|
245
|
|
246 public void doBoolean(BooleanField field, boolean vField) {
|
|
247 try {
|
|
248 writeBooleanField(oop, field);
|
|
249 } catch (IOException exp) {
|
|
250 throw new RuntimeException(exp);
|
|
251 }
|
|
252 }
|
|
253
|
|
254 public void doShort(ShortField field, boolean isVMField) {
|
|
255 try {
|
|
256 writeShortField(oop, field);
|
|
257 } catch (IOException exp) {
|
|
258 throw new RuntimeException(exp);
|
|
259 }
|
|
260 }
|
|
261
|
|
262 public void doInt(IntField field, boolean isVMField) {
|
|
263 try {
|
|
264 writeIntField(oop, field);
|
|
265 } catch (IOException exp) {
|
|
266 throw new RuntimeException(exp);
|
|
267 }
|
|
268 }
|
|
269
|
|
270 public void doLong(LongField field, boolean isVMField) {
|
|
271 try {
|
|
272 writeLongField(oop, field);
|
|
273 } catch (IOException exp) {
|
|
274 throw new RuntimeException(exp);
|
|
275 }
|
|
276 }
|
|
277
|
|
278 public void doFloat(FloatField field, boolean isVMField) {
|
|
279 try {
|
|
280 writeFloatField(oop, field);
|
|
281 } catch (IOException exp) {
|
|
282 throw new RuntimeException(exp);
|
|
283 }
|
|
284 }
|
|
285
|
|
286 public void doDouble(DoubleField field, boolean vField) {
|
|
287 try {
|
|
288 writeDoubleField(oop, field);
|
|
289 } catch (IOException exp) {
|
|
290 throw new RuntimeException(exp);
|
|
291 }
|
|
292 }
|
|
293 }, false);
|
|
294 } catch (RuntimeException re) {
|
|
295 handleRuntimeException(re);
|
|
296 }
|
|
297 }
|
|
298
|
|
299 // object field writers
|
|
300 protected void writeInternalReferenceField(Oop oop, OopField field)
|
|
301 throws IOException {
|
|
302 }
|
|
303
|
|
304 protected void writeReferenceField(Oop oop, OopField field)
|
|
305 throws IOException {
|
|
306 }
|
|
307
|
|
308 protected void writeByteField(Oop oop, ByteField field)
|
|
309 throws IOException {
|
|
310 }
|
|
311
|
|
312 protected void writeCharField(Oop oop, CharField field)
|
|
313 throws IOException {
|
|
314 }
|
|
315
|
|
316 protected void writeBooleanField(Oop oop, BooleanField field)
|
|
317 throws IOException {
|
|
318 }
|
|
319
|
|
320 protected void writeShortField(Oop oop, ShortField field)
|
|
321 throws IOException {
|
|
322 }
|
|
323
|
|
324 protected void writeIntField(Oop oop, IntField field)
|
|
325 throws IOException {
|
|
326 }
|
|
327
|
|
328 protected void writeLongField(Oop oop, LongField field)
|
|
329 throws IOException {
|
|
330 }
|
|
331
|
|
332 protected void writeFloatField(Oop oop, FloatField field)
|
|
333 throws IOException {
|
|
334 }
|
|
335
|
|
336 protected void writeDoubleField(Oop oop, DoubleField field)
|
|
337 throws IOException {
|
|
338 }
|
|
339
|
|
340 protected void writeObjectFooter(Oop oop) throws IOException {
|
|
341 }
|
|
342
|
|
343 protected void writeHeapFooter() throws IOException {
|
|
344 }
|
|
345
|
|
346 // HeapVisitor, OopVisitor methods can't throw any non-runtime
|
|
347 // exception. But, derived class write methods (which are called
|
|
348 // from visitor callbacks) may throw IOException. Hence, we throw
|
|
349 // RuntimeException with origianal IOException as cause from the
|
|
350 // visitor methods. This method gets back the original IOException
|
|
351 // (if any) and re-throws the same.
|
|
352 protected void handleRuntimeException(RuntimeException re)
|
|
353 throws IOException {
|
|
354 Throwable cause = re.getCause();
|
|
355 if (cause != null && cause instanceof IOException) {
|
|
356 throw (IOException) cause;
|
|
357 } else {
|
|
358 // some other RuntimeException, just re-throw
|
|
359 throw re;
|
|
360 }
|
|
361 }
|
|
362
|
|
363 // whether a given oop is Java visible or hotspot internal?
|
|
364 protected boolean isJavaVisible(Oop oop) {
|
|
365 if (oop instanceof Instance || oop instanceof TypeArray) {
|
|
366 return true;
|
|
367 } else if (oop instanceof ObjArray) {
|
|
368 ObjArrayKlass oak = (ObjArrayKlass) oop.getKlass();
|
|
369 Klass bottomKlass = oak.getBottomKlass();
|
|
370 return bottomKlass instanceof InstanceKlass ||
|
|
371 bottomKlass instanceof TypeArrayKlass;
|
|
372 } else {
|
|
373 return false;
|
|
374 }
|
|
375 }
|
|
376
|
|
377 protected Symbol javaLangClass;
|
|
378 protected Symbol javaLangString;
|
|
379 protected Symbol javaLangThread;
|
|
380 }
|