comparison agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2004-2007 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 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 = OopUtilities.classOopToKlass(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(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 ObjArray interfaces = ik.getLocalInterfaces();
197 final int len = (int) interfaces.getLength();
198 for (int i = 0; i < len; i++) {
199 Klass k = (Klass) interfaces.getObjAt(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
208 Oop signers = ik.getSigners();
209 writeEdge(instance, signers, "signed-by");
210
211 // write protection domain
212 Oop protectionDomain = ik.getProtectionDomain();
213 writeEdge(instance, protectionDomain, "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 StringBuffer 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 StringBuffer(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 }