Mercurial > hg > truffle
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 = "&"; | |
295 } else if (c == '<') { | |
296 replacement = "<"; | |
297 } else if (c == '>') { | |
298 replacement = ">"; | |
299 } else if (c == '"') { | |
300 replacement = """; | |
301 } else if (c == '\'') { | |
302 replacement = "'"; | |
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 } |