1 /*
2  * Copyright (c) 2004, 2018, 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 
25 package sun.jvm.hotspot.utilities;
26 
27 import java.io.*;
28 import sun.jvm.hotspot.debugger.*;
29 import sun.jvm.hotspot.gc.shared.OopStorage;
30 import sun.jvm.hotspot.memory.*;
31 import sun.jvm.hotspot.oops.*;
32 import sun.jvm.hotspot.runtime.*;
33 
34 /**
35  * This is abstract base class for heap graph writers. This class does
36  * not assume any file format for the heap graph. It hides heap
37  * iteration, object (fields) iteration mechanism from derived
38  * classes. This class does not even accept OutputStream etc. so that
39  * derived class can construct specific writer/filter from input
40  * stream.
41  */
42 
43 public abstract class AbstractHeapGraphWriter implements HeapGraphWriter {
44     // the function iterates heap and calls Oop type specific writers
write()45     protected void write() throws IOException {
46         javaLangClass = "java/lang/Class";
47         javaLangString = "java/lang/String";
48         javaLangThread = "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 
writeJavaThreads()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 
writeJavaThread(JavaThread jt, int index)144     protected void writeJavaThread(JavaThread jt, int index)
145                             throws IOException {
146     }
147 
writeGlobalJNIHandles()148     protected void writeGlobalJNIHandles() throws IOException {
149         JNIHandles handles = VM.getVM().getJNIHandles();
150         OopStorage 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 
writeGlobalJNIHandle(Address handleAddr)173     protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
174     }
175 
writeHeapHeader()176     protected void writeHeapHeader() throws IOException {
177     }
178 
179     // write non-Java-visible (hotspot internal) object
writeInternalObject(Oop oop)180     protected void writeInternalObject(Oop oop) throws IOException {
181     }
182 
183     // write Java primitive array
writePrimitiveArray(TypeArray array)184     protected void writePrimitiveArray(TypeArray array) throws IOException {
185         writeObject(array);
186     }
187 
188     // write Java object array
writeObjectArray(ObjArray array)189     protected void writeObjectArray(ObjArray array) throws IOException {
190         writeObject(array);
191     }
192 
writeInstance(Instance instance)193     protected void writeInstance(Instance instance) throws IOException {
194         writeObject(instance);
195     }
196 
writeString(Instance instance)197     protected void writeString(Instance instance) throws IOException {
198         writeInstance(instance);
199     }
200 
writeClass(Instance instance)201     protected void writeClass(Instance instance) throws IOException {
202         writeInstance(instance);
203     }
204 
writeThread(Instance instance)205     protected void writeThread(Instance instance) throws IOException {
206         writeInstance(instance);
207     }
208 
writeObject(Oop oop)209     protected void writeObject(Oop oop) throws IOException {
210         writeObjectHeader(oop);
211         writeObjectFields(oop);
212         writeObjectFooter(oop);
213     }
214 
writeObjectHeader(Oop oop)215     protected void writeObjectHeader(Oop oop) throws IOException {
216     }
217 
218     // write instance fields of given object
writeObjectFields(final Oop oop)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
writeObjectFields(final InstanceKlass oop)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
writeReferenceField(Oop oop, OopField field)381     protected void writeReferenceField(Oop oop, OopField field)
382         throws IOException {
383     }
384 
writeByteField(Oop oop, ByteField field)385     protected void writeByteField(Oop oop, ByteField field)
386         throws IOException {
387     }
388 
writeCharField(Oop oop, CharField field)389     protected void writeCharField(Oop oop, CharField field)
390         throws IOException {
391     }
392 
writeBooleanField(Oop oop, BooleanField field)393     protected void writeBooleanField(Oop oop, BooleanField field)
394         throws IOException {
395     }
396 
writeShortField(Oop oop, ShortField field)397     protected void writeShortField(Oop oop, ShortField field)
398         throws IOException {
399     }
400 
writeIntField(Oop oop, IntField field)401     protected void writeIntField(Oop oop, IntField field)
402         throws IOException {
403     }
404 
writeLongField(Oop oop, LongField field)405     protected void writeLongField(Oop oop, LongField field)
406         throws IOException {
407     }
408 
writeFloatField(Oop oop, FloatField field)409     protected void writeFloatField(Oop oop, FloatField field)
410         throws IOException {
411     }
412 
writeDoubleField(Oop oop, DoubleField field)413     protected void writeDoubleField(Oop oop, DoubleField field)
414         throws IOException {
415     }
416 
writeObjectFooter(Oop oop)417     protected void writeObjectFooter(Oop oop) throws IOException {
418     }
419 
writeHeapFooter()420     protected void writeHeapFooter() throws IOException {
421     }
422 
writeHeapRecordPrologue()423     protected void writeHeapRecordPrologue() throws IOException {
424     }
425 
writeHeapRecordEpilogue()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.
handleRuntimeException(RuntimeException re)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?
isJavaVisible(Oop oop)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 String javaLangClass;
461     protected String javaLangString;
462     protected String javaLangThread;
463 }
464