Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java
41161 views
1
/*
2
* Copyright (c) 2004, 2021, 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 java.util.*;
29
import sun.jvm.hotspot.oops.*;
30
import sun.jvm.hotspot.runtime.*;
31
32
/**
33
* <p>This class writes Java heap in Graph eXchange Language (GXL)
34
* format. GXL is an open standard for serializing arbitrary graphs in
35
* XML syntax.</p>
36
*
37
* <p>A GXL document contains one or more graphs. A graph contains
38
* nodes and edges. Both nodes and edges can have attributes. graphs,
39
* nodes, edges and attributes are represented by XML elements graph,
40
* node, edge and attr respectively. Attributes can be typed. GXL
41
* supports locator, bool, int, float, bool, string, enum as well as
42
* set, seq, bag, tup types. Nodes must have a XML attribute 'id' that
43
* is unique id of the node in the GXL document. Edges must have
44
* 'from' and 'to' XML attributes that are ids of from and to nodes.</p>
45
*
46
* <p>Java heap to GXL document mapping:</p>
47
* <ul>
48
* <li>Java object - GXL node.
49
* <li>Java primitive field - GXL attribute (type mapping below).
50
* <li>Java reference field - GXL edge from referee to referent node.
51
* <li>Java primitive array - GXL node with seq type attribute.
52
* <li>Java char array - GXL node with one attribute of string type.
53
* <li>Java object array - GXL node and 'length' edges.
54
* </ul>
55
*
56
* <p>Java primitive to GXL type mapping:</p>
57
* <ul>
58
* <li>Java byte, int, short, long - GXL int attribute
59
* <li>Java float, double - GXL float attribute
60
* <li>Java boolean - GXL bool atttribute
61
* <li>Java char - GXL string attribute
62
* </ul>
63
*
64
* Exact Java primitive type code is written in 'kind' attribute of
65
* 'attr' element. Type code is specified in JVM spec. second edition
66
* section 4.3.2 (Field Descriptor).
67
*
68
* @see <a href="http://www.gupro.de/GXL/">GXL</a>
69
* @see <a href="http://www.gupro.de/GXL/dtd/dtd.html">GXL DTD</a>
70
*/
71
72
public class HeapGXLWriter extends AbstractHeapGraphWriter {
73
public void write(String fileName) throws IOException {
74
out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
75
super.write();
76
if (out.checkError()) {
77
throw new IOException();
78
}
79
out.flush();
80
}
81
82
protected void writeHeapHeader() throws IOException {
83
// XML processing instruction
84
out.print("<?xml version='1.0' encoding='");
85
out.print(ENCODING);
86
out.println("'?>");
87
88
out.println("<gxl>");
89
out.println("<graph id='JavaHeap'>");
90
91
// document properties
92
writeAttribute("creation-date", "string", new Date().toString());
93
94
// write VM info
95
writeVMInfo();
96
97
// emit a node for null
98
out.print("<node id='");
99
out.print(getID(null));
100
out.println("'/>");
101
}
102
103
protected void writeObjectHeader(Oop oop) throws IOException {
104
refFields = new ArrayList<>();
105
isArray = oop.isArray();
106
107
// generate an edge for instanceof relation
108
// between object node and it's class node.
109
writeEdge(oop, oop.getKlass().getJavaMirror(), "instanceof");
110
111
out.print("<node id='");
112
out.print(getID(oop));
113
out.println("'>");
114
}
115
116
protected void writeObjectFooter(Oop oop) throws IOException {
117
out.println("</node>");
118
119
// write the reference fields as edges
120
for (Iterator itr = refFields.iterator(); itr.hasNext();) {
121
OopField field = (OopField) itr.next();
122
Oop ref = field.getValue(oop);
123
124
String name = field.getID().getName();
125
if (isArray) {
126
// for arrays elements we use element<index> pattern
127
name = "element" + name;
128
} else {
129
name = identifierToXMLName(name);
130
}
131
writeEdge(oop, ref, name);
132
}
133
refFields = null;
134
}
135
136
protected void writeObjectArray(ObjArray array) throws IOException {
137
writeObjectHeader(array);
138
writeArrayLength(array);
139
writeObjectFields(array);
140
writeObjectFooter(array);
141
}
142
143
protected void writePrimitiveArray(TypeArray array)
144
throws IOException {
145
writeObjectHeader(array);
146
// write array length
147
writeArrayLength(array);
148
// write array elements
149
out.println("\t<attr name='elements'>");
150
TypeArrayKlass klass = (TypeArrayKlass) array.getKlass();
151
if (klass.getElementType() == TypeArrayKlass.T_CHAR) {
152
// char[] special treatment -- write it as string
153
out.print("\t<string>");
154
out.print(escapeXMLChars(OopUtilities.charArrayToString(array)));
155
out.println("</string>");
156
} else {
157
out.println("\t<seq>");
158
writeObjectFields(array);
159
out.println("\t</seq>");
160
}
161
out.println("\t</attr>");
162
writeObjectFooter(array);
163
}
164
165
protected void writeClass(Instance instance) throws IOException {
166
writeObjectHeader(instance);
167
Klass reflectedType = java_lang_Class.asKlass(instance);
168
boolean isInstanceKlass = (reflectedType instanceof InstanceKlass);
169
// reflectedType is null for primitive types (int.class etc).
170
if (reflectedType != null) {
171
Symbol name = reflectedType.getName();
172
if (name != null) {
173
// write class name as an attribute
174
writeAttribute("class-name", "string", name.asString());
175
}
176
if (isInstanceKlass) {
177
// write object-size as an attribute
178
long sizeInBytes = reflectedType.getLayoutHelper();
179
writeAttribute("object-size", "int",
180
Long.toString(sizeInBytes));
181
// write static fields of this class.
182
writeObjectFields((InstanceKlass)reflectedType);
183
}
184
}
185
out.println("</node>");
186
187
// write edges for super class and direct interfaces
188
if (reflectedType != null) {
189
Klass superType = reflectedType.getSuper();
190
Oop superMirror = (superType == null)?
191
null : superType.getJavaMirror();
192
writeEdge(instance, superMirror, "extends");
193
if (isInstanceKlass) {
194
// write edges for directly implemented interfaces
195
InstanceKlass ik = (InstanceKlass) reflectedType;
196
KlassArray interfaces = ik.getLocalInterfaces();
197
final int len = interfaces.length();
198
for (int i = 0; i < len; i++) {
199
Klass k = interfaces.getAt(i);
200
writeEdge(instance, k.getJavaMirror(), "implements");
201
}
202
203
// write loader
204
Oop loader = ik.getClassLoader();
205
writeEdge(instance, loader, "loaded-by");
206
207
// write signers NYI
208
// Oop signers = ik.getJavaMirror().getSigners();
209
writeEdge(instance, null, "signed-by");
210
211
// write protection domain NYI
212
// Oop protectionDomain = ik.getJavaMirror().getProtectionDomain();
213
writeEdge(instance, null, "protection-domain");
214
215
// write edges for static reference fields from this class
216
for (Iterator itr = refFields.iterator(); itr.hasNext();) {
217
OopField field = (OopField) itr.next();
218
Oop ref = field.getValue(reflectedType);
219
String name = field.getID().getName();
220
writeEdge(instance, ref, identifierToXMLName(name));
221
}
222
}
223
}
224
refFields = null;
225
}
226
227
protected void writeReferenceField(Oop oop, OopField field)
228
throws IOException {
229
refFields.add(field);
230
}
231
232
protected void writeByteField(Oop oop, ByteField field)
233
throws IOException {
234
writeField(field, "int", "B", Byte.toString(field.getValue(oop)));
235
}
236
237
protected void writeCharField(Oop oop, CharField field)
238
throws IOException {
239
writeField(field, "string", "C",
240
escapeXMLChars(Character.toString(field.getValue(oop))));
241
}
242
243
protected void writeBooleanField(Oop oop, BooleanField field)
244
throws IOException {
245
writeField(field, "bool", "Z", Boolean.toString(field.getValue(oop)));
246
}
247
248
protected void writeShortField(Oop oop, ShortField field)
249
throws IOException {
250
writeField(field, "int", "S", Short.toString(field.getValue(oop)));
251
}
252
253
protected void writeIntField(Oop oop, IntField field)
254
throws IOException {
255
writeField(field, "int", "I", Integer.toString(field.getValue(oop)));
256
}
257
258
protected void writeLongField(Oop oop, LongField field)
259
throws IOException {
260
writeField(field, "int", "J", Long.toString(field.getValue(oop)));
261
}
262
263
protected void writeFloatField(Oop oop, FloatField field)
264
throws IOException {
265
writeField(field, "float", "F", Float.toString(field.getValue(oop)));
266
}
267
268
protected void writeDoubleField(Oop oop, DoubleField field)
269
throws IOException {
270
writeField(field, "float", "D", Double.toString(field.getValue(oop)));
271
}
272
273
protected void writeHeapFooter() throws IOException {
274
out.println("</graph>");
275
out.println("</gxl>");
276
}
277
278
//-- Internals only below this point
279
280
// Java identifier to XML NMTOKEN type string
281
private static String identifierToXMLName(String name) {
282
// for now, just replace '$' with '_'
283
return name.replace('$', '_');
284
}
285
286
// escapes XML meta-characters and illegal characters
287
private static String escapeXMLChars(String s) {
288
// FIXME: is there a better way or API?
289
StringBuilder result = null;
290
for(int i = 0, max = s.length(), delta = 0; i < max; i++) {
291
char c = s.charAt(i);
292
String replacement = null;
293
if (c == '&') {
294
replacement = "&amp;";
295
} else if (c == '<') {
296
replacement = "&lt;";
297
} else if (c == '>') {
298
replacement = "&gt;";
299
} else if (c == '"') {
300
replacement = "&quot;";
301
} else if (c == '\'') {
302
replacement = "&apos;";
303
} else if (c < '\u0020' || (c > '\ud7ff' && c < '\ue000') ||
304
c == '\ufffe' || c == '\uffff') {
305
// These are illegal in XML -- put these in a CDATA section.
306
// Refer to section 2.2 Characters in XML specification at
307
// http://www.w3.org/TR/2004/REC-xml-20040204/
308
replacement = "<![CDATA[&#x" +
309
Integer.toHexString((int)c) + ";]]>";
310
}
311
312
if (replacement != null) {
313
if (result == null) {
314
result = new StringBuilder(s);
315
}
316
result.replace(i + delta, i + delta + 1, replacement);
317
delta += (replacement.length() - 1);
318
}
319
}
320
if (result == null) {
321
return s;
322
}
323
return result.toString();
324
}
325
326
private static String getID(Oop oop) {
327
// address as unique id for node -- prefixed by "ID_".
328
if (oop == null) {
329
return "ID_NULL";
330
} else {
331
return "ID_" + oop.getHandle().toString();
332
}
333
}
334
335
private void writeArrayLength(Array array) throws IOException {
336
writeAttribute("length", "int",
337
Integer.toString((int) array.getLength()));
338
}
339
340
private void writeAttribute(String name, String type, String value) {
341
out.print("\t<attr name='");
342
out.print(name);
343
out.print("'><");
344
out.print(type);
345
out.print('>');
346
out.print(value);
347
out.print("</");
348
out.print(type);
349
out.println("></attr>");
350
}
351
352
private void writeEdge(Oop from, Oop to, String name) throws IOException {
353
out.print("<edge from='");
354
out.print(getID(from));
355
out.print("' to='");
356
out.print(getID(to));
357
out.println("'>");
358
writeAttribute("name", "string", name);
359
out.println("</edge>");
360
}
361
362
private void writeField(Field field, String type, String kind,
363
String value) throws IOException {
364
// 'type' is GXL type of the attribute
365
// 'kind' is Java type code ("B", "C", "Z", "S", "I", "J", "F", "D")
366
if (isArray) {
367
out.print('\t');
368
} else {
369
out.print("\t<attr name='");
370
String name = field.getID().getName();
371
out.print(identifierToXMLName(name));
372
out.print("' kind='");
373
out.print(kind);
374
out.print("'>");
375
}
376
out.print('<');
377
out.print(type);
378
out.print('>');
379
out.print(value);
380
out.print("</");
381
out.print(type);
382
out.print('>');
383
if (isArray) {
384
out.println();
385
} else {
386
out.println("</attr>");
387
}
388
}
389
390
private void writeVMInfo() throws IOException {
391
VM vm = VM.getVM();
392
writeAttribute("vm-version", "string", vm.getVMRelease());
393
writeAttribute("vm-type", "string",
394
(vm.isClientCompiler())? "client" :
395
((vm.isServerCompiler())? "server" : "core"));
396
writeAttribute("os", "string", vm.getOS());
397
writeAttribute("cpu", "string", vm.getCPU());
398
writeAttribute("pointer-size", "string",
399
Integer.toString((int)vm.getOopSize() * 8));
400
}
401
402
// XML encoding that we'll use
403
private static final String ENCODING = "UTF-8";
404
405
// reference fields of currently visited object
406
private List<OopField> refFields;
407
// are we writing an array now?
408
private boolean isArray;
409
private PrintWriter out;
410
}
411
412