1/*
2 * Copyright (c) 2004, 2017, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot.utilities;
26
27import java.io.*;
28import sun.jvm.hotspot.debugger.*;
29import sun.jvm.hotspot.memory.*;
30import sun.jvm.hotspot.oops.*;
31import 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
42public 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                            writeHeapRecordPrologue();
63                            if (oop instanceof TypeArray) {
64                                writePrimitiveArray((TypeArray)oop);
65                            } else if (oop instanceof ObjArray) {
66                                Klass klass = oop.getKlass();
67                                ObjArrayKlass oak = (ObjArrayKlass) klass;
68                                Klass bottomType = oak.getBottomKlass();
69                                if (bottomType instanceof InstanceKlass ||
70                                    bottomType instanceof TypeArrayKlass) {
71                                    writeObjectArray((ObjArray)oop);
72                                } else {
73                                    writeInternalObject(oop);
74                                }
75                            } else if (oop instanceof Instance) {
76                                Instance instance = (Instance) oop;
77                                Klass klass = instance.getKlass();
78                                Symbol name = klass.getName();
79                                if (name.equals(javaLangString)) {
80                                    writeString(instance);
81                                } else if (name.equals(javaLangClass)) {
82                                    writeClass(instance);
83                                } else if (name.equals(javaLangThread)) {
84                                    writeThread(instance);
85                                } else {
86                                    klass = klass.getSuper();
87                                    while (klass != null) {
88                                        name = klass.getName();
89                                        if (name.equals(javaLangThread)) {
90                                            writeThread(instance);
91                                            return false;
92                                        }
93                                        klass = klass.getSuper();
94                                    }
95                                    writeInstance(instance);
96                                }
97                            } else {
98                                // not-a-Java-visible oop
99                                writeInternalObject(oop);
100                            }
101                            writeHeapRecordEpilogue();
102                        } catch (IOException exp) {
103                            throw new RuntimeException(exp);
104                        }
105                        return false;
106                    }
107
108                    public void epilogue() {
109                        try {
110                            writeHeapFooter();
111                        } catch (IOException exp) {
112                            throw new RuntimeException(exp);
113                        }
114                    }
115                });
116
117                writeHeapRecordPrologue();
118
119                // write JavaThreads
120                writeJavaThreads();
121
122                // write JNI global handles
123                writeGlobalJNIHandles();
124
125        } catch (RuntimeException re) {
126            handleRuntimeException(re);
127        }
128    }
129
130    protected void writeJavaThreads() throws IOException {
131        Threads threads = VM.getVM().getThreads();
132        JavaThread jt = threads.first();
133        int index = 1;
134        while (jt != null) {
135            if (jt.getThreadObj() != null) {
136                // Note that the thread serial number range is 1-to-N
137                writeJavaThread(jt, index);
138                index++;
139            }
140            jt = jt.next();
141        }
142    }
143
144    protected void writeJavaThread(JavaThread jt, int index)
145                            throws IOException {
146    }
147
148    protected void writeGlobalJNIHandles() throws IOException {
149        JNIHandles handles = VM.getVM().getJNIHandles();
150        JNIHandleBlock blk = handles.globalHandles();
151        if (blk != null) {
152            try {
153                blk.oopsDo(new AddressVisitor() {
154                          public void visitAddress(Address handleAddr) {
155                              try {
156                                  if (handleAddr != null) {
157                                      writeGlobalJNIHandle(handleAddr);
158                                  }
159                              } catch (IOException exp) {
160                                  throw new RuntimeException(exp);
161                              }
162                          }
163                              public void visitCompOopAddress(Address handleAddr) {
164                             throw new RuntimeException("Should not reach here. JNIHandles are not compressed");
165                          }
166                       });
167            } catch (RuntimeException re) {
168                handleRuntimeException(re);
169            }
170        }
171    }
172
173    protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
174    }
175
176    protected void writeHeapHeader() throws IOException {
177    }
178
179    // write non-Java-visible (hotspot internal) object
180    protected void writeInternalObject(Oop oop) throws IOException {
181    }
182
183    // write Java primitive array
184    protected void writePrimitiveArray(TypeArray array) throws IOException {
185        writeObject(array);
186    }
187
188    // write Java object array
189    protected void writeObjectArray(ObjArray array) throws IOException {
190        writeObject(array);
191    }
192
193    protected void writeInstance(Instance instance) throws IOException {
194        writeObject(instance);
195    }
196
197    protected void writeString(Instance instance) throws IOException {
198        writeInstance(instance);
199    }
200
201    protected void writeClass(Instance instance) throws IOException {
202        writeInstance(instance);
203    }
204
205    protected void writeThread(Instance instance) throws IOException {
206        writeInstance(instance);
207    }
208
209    protected void writeObject(Oop oop) throws IOException {
210        writeObjectHeader(oop);
211        writeObjectFields(oop);
212        writeObjectFooter(oop);
213    }
214
215    protected void writeObjectHeader(Oop oop) throws IOException {
216    }
217
218    // write instance fields of given object
219    protected void writeObjectFields(final Oop oop) throws IOException {
220        try {
221            oop.iterate(new DefaultOopVisitor() {
222                    public void doOop(OopField field, boolean isVMField) {
223                        try {
224                                writeReferenceField(oop, field);
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    // write instance fields of given object
300    protected void writeObjectFields(final InstanceKlass oop) throws IOException {
301        try {
302            oop.iterateStaticFields(new DefaultOopVisitor() {
303                    public void doOop(OopField field, boolean isVMField) {
304                        try {
305                            writeReferenceField(null, field);
306                        } catch (IOException exp) {
307                            throw new RuntimeException(exp);
308                        }
309    }
310
311                    public void doByte(ByteField field, boolean isVMField) {
312                        try {
313                            writeByteField(null, field);
314                        } catch (IOException exp) {
315                            throw new RuntimeException(exp);
316                        }
317                    }
318
319                    public void doChar(CharField field, boolean isVMField) {
320                        try {
321                            writeCharField(null, field);
322                        } catch (IOException exp) {
323                            throw new RuntimeException(exp);
324                        }
325                    }
326
327                    public void doBoolean(BooleanField field, boolean vField) {
328                        try {
329                            writeBooleanField(null, field);
330                        } catch (IOException exp) {
331                            throw new RuntimeException(exp);
332                        }
333                    }
334
335                    public void doShort(ShortField field, boolean isVMField) {
336                        try {
337                            writeShortField(null, field);
338                        } catch (IOException exp) {
339                            throw new RuntimeException(exp);
340                        }
341                    }
342
343                    public void doInt(IntField field, boolean isVMField) {
344                        try {
345                            writeIntField(null, field);
346                        } catch (IOException exp) {
347                            throw new RuntimeException(exp);
348                        }
349                    }
350
351                    public void doLong(LongField field, boolean isVMField) {
352                        try {
353                            writeLongField(null, field);
354                        } catch (IOException exp) {
355                            throw new RuntimeException(exp);
356                        }
357                    }
358
359                    public void doFloat(FloatField field, boolean isVMField) {
360                        try {
361                            writeFloatField(null, field);
362                        } catch (IOException exp) {
363                            throw new RuntimeException(exp);
364                        }
365                    }
366
367                    public void doDouble(DoubleField field, boolean vField) {
368                        try {
369                            writeDoubleField(null, field);
370                        } catch (IOException exp) {
371                            throw new RuntimeException(exp);
372                        }
373                    }
374                });
375        } catch (RuntimeException re) {
376            handleRuntimeException(re);
377        }
378    }
379
380    // object field writers
381    protected void writeReferenceField(Oop oop, OopField field)
382        throws IOException {
383    }
384
385    protected void writeByteField(Oop oop, ByteField field)
386        throws IOException {
387    }
388
389    protected void writeCharField(Oop oop, CharField field)
390        throws IOException {
391    }
392
393    protected void writeBooleanField(Oop oop, BooleanField field)
394        throws IOException {
395    }
396
397    protected void writeShortField(Oop oop, ShortField field)
398        throws IOException {
399    }
400
401    protected void writeIntField(Oop oop, IntField field)
402        throws IOException {
403    }
404
405    protected void writeLongField(Oop oop, LongField field)
406        throws IOException {
407    }
408
409    protected void writeFloatField(Oop oop, FloatField field)
410        throws IOException {
411    }
412
413    protected void writeDoubleField(Oop oop, DoubleField field)
414        throws IOException {
415    }
416
417    protected void writeObjectFooter(Oop oop) throws IOException {
418    }
419
420    protected void writeHeapFooter() throws IOException {
421    }
422
423    protected void writeHeapRecordPrologue() throws IOException {
424    }
425
426    protected void writeHeapRecordEpilogue() throws IOException {
427    }
428
429    // HeapVisitor, OopVisitor methods can't throw any non-runtime
430    // exception. But, derived class write methods (which are called
431    // from visitor callbacks) may throw IOException. Hence, we throw
432    // RuntimeException with origianal IOException as cause from the
433    // visitor methods. This method gets back the original IOException
434    // (if any) and re-throws the same.
435    protected void handleRuntimeException(RuntimeException re)
436        throws IOException {
437        Throwable cause = re.getCause();
438        if (cause != null && cause instanceof IOException) {
439            throw (IOException) cause;
440        } else {
441            // some other RuntimeException, just re-throw
442            throw re;
443        }
444    }
445
446    // whether a given oop is Java visible or hotspot internal?
447    protected boolean isJavaVisible(Oop oop) {
448        if (oop instanceof Instance || oop instanceof TypeArray) {
449            return true;
450        } else if (oop instanceof ObjArray) {
451            ObjArrayKlass oak = (ObjArrayKlass) oop.getKlass();
452            Klass bottomKlass = oak.getBottomKlass();
453            return bottomKlass instanceof InstanceKlass ||
454                   bottomKlass instanceof TypeArrayKlass;
455        } else {
456            return false;
457        }
458    }
459
460    protected Symbol javaLangClass;
461    protected Symbol javaLangString;
462    protected Symbol javaLangThread;
463}
464