Mercurial > hg > graal-jvmci-8
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,410 @@ +/* + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package sun.jvm.hotspot.utilities; + +import java.io.*; +import java.util.*; +import sun.jvm.hotspot.oops.*; +import sun.jvm.hotspot.runtime.*; + +/** + * <p>This class writes Java heap in Graph eXchange Language (GXL) + * format. GXL is an open standard for serializing arbitrary graphs in + * XML syntax.</p> + * + * <p>A GXL document contains one or more graphs. A graph contains + * nodes and edges. Both nodes and edges can have attributes. graphs, + * nodes, edges and attributes are represented by XML elements graph, + * node, edge and attr respectively. Attributes can be typed. GXL + * supports locator, bool, int, float, bool, string, enum as well as + * set, seq, bag, tup types. Nodes must have a XML attribute 'id' that + * is unique id of the node in the GXL document. Edges must have + * 'from' and 'to' XML attributes that are ids of from and to nodes.</p> + * + * <p>Java heap to GXL document mapping:</p> + * <ul> + * <li>Java object - GXL node. + * <li>Java primitive field - GXL attribute (type mapping below). + * <li>Java reference field - GXL edge from referee to referent node. + * <li>Java primitive array - GXL node with seq type attribute. + * <li>Java char array - GXL node with one attribute of string type. + * <li>Java object array - GXL node and 'length' edges. + * </ul> + * + * <p>Java primitive to GXL type mapping:</p> + * <ul> + * <li>Java byte, int, short, long - GXL int attribute + * <li>Java float, double - GXL float attribute + * <li>Java boolean - GXL bool atttribute + * <li>Java char - GXL string attribute + * </ul> + * + * Exact Java primitive type code is written in 'kind' attribute of + * 'attr' element. Type code is specified in JVM spec. second edition + * section 4.3.2 (Field Descriptor). + * + * @see <a href="http://www.gupro.de/GXL/">GXL</a> + * @see <a href="http://www.gupro.de/GXL/dtd/dtd.html">GXL DTD</a> + */ + +public class HeapGXLWriter extends AbstractHeapGraphWriter { + public void write(String fileName) throws IOException { + out = new PrintWriter(new BufferedWriter(new FileWriter(fileName))); + super.write(); + if (out.checkError()) { + throw new IOException(); + } + out.flush(); + } + + protected void writeHeapHeader() throws IOException { + // XML processing instruction + out.print("<?xml version='1.0' encoding='"); + out.print(ENCODING); + out.println("'?>"); + + out.println("<gxl>"); + out.println("<graph id='JavaHeap'>"); + + // document properties + writeAttribute("creation-date", "string", new Date().toString()); + + // write VM info + writeVMInfo(); + + // emit a node for null + out.print("<node id='"); + out.print(getID(null)); + out.println("'/>"); + } + + protected void writeObjectHeader(Oop oop) throws IOException { + refFields = new ArrayList(); + isArray = oop.isArray(); + + // generate an edge for instanceof relation + // between object node and it's class node. + writeEdge(oop, oop.getKlass().getJavaMirror(), "instanceof"); + + out.print("<node id='"); + out.print(getID(oop)); + out.println("'>"); + } + + protected void writeObjectFooter(Oop oop) throws IOException { + out.println("</node>"); + + // write the reference fields as edges + for (Iterator itr = refFields.iterator(); itr.hasNext();) { + OopField field = (OopField) itr.next(); + Oop ref = field.getValue(oop); + + String name = field.getID().getName(); + if (isArray) { + // for arrays elements we use element<index> pattern + name = "element" + name; + } else { + name = identifierToXMLName(name); + } + writeEdge(oop, ref, name); + } + refFields = null; + } + + protected void writeObjectArray(ObjArray array) throws IOException { + writeObjectHeader(array); + writeArrayLength(array); + writeObjectFields(array); + writeObjectFooter(array); + } + + protected void writePrimitiveArray(TypeArray array) + throws IOException { + writeObjectHeader(array); + // write array length + writeArrayLength(array); + // write array elements + out.println("\t<attr name='elements'>"); + TypeArrayKlass klass = (TypeArrayKlass) array.getKlass(); + if (klass.getElementType() == TypeArrayKlass.T_CHAR) { + // char[] special treatment -- write it as string + out.print("\t<string>"); + out.print(escapeXMLChars(OopUtilities.charArrayToString(array))); + out.println("</string>"); + } else { + out.println("\t<seq>"); + writeObjectFields(array); + out.println("\t</seq>"); + } + out.println("\t</attr>"); + writeObjectFooter(array); + } + + protected void writeClass(Instance instance) throws IOException { + writeObjectHeader(instance); + Klass reflectedType = OopUtilities.classOopToKlass(instance); + boolean isInstanceKlass = (reflectedType instanceof InstanceKlass); + // reflectedType is null for primitive types (int.class etc). + if (reflectedType != null) { + Symbol name = reflectedType.getName(); + if (name != null) { + // write class name as an attribute + writeAttribute("class-name", "string", name.asString()); + } + if (isInstanceKlass) { + // write object-size as an attribute + long sizeInBytes = reflectedType.getLayoutHelper(); + writeAttribute("object-size", "int", + Long.toString(sizeInBytes)); + // write static fields of this class. + writeObjectFields(reflectedType); + } + } + out.println("</node>"); + + // write edges for super class and direct interfaces + if (reflectedType != null) { + Klass superType = reflectedType.getSuper(); + Oop superMirror = (superType == null)? + null : superType.getJavaMirror(); + writeEdge(instance, superMirror, "extends"); + if (isInstanceKlass) { + // write edges for directly implemented interfaces + InstanceKlass ik = (InstanceKlass) reflectedType; + ObjArray interfaces = ik.getLocalInterfaces(); + final int len = (int) interfaces.getLength(); + for (int i = 0; i < len; i++) { + Klass k = (Klass) interfaces.getObjAt(i); + writeEdge(instance, k.getJavaMirror(), "implements"); + } + + // write loader + Oop loader = ik.getClassLoader(); + writeEdge(instance, loader, "loaded-by"); + + // write signers + Oop signers = ik.getSigners(); + writeEdge(instance, signers, "signed-by"); + + // write protection domain + Oop protectionDomain = ik.getProtectionDomain(); + writeEdge(instance, protectionDomain, "protection-domain"); + + // write edges for static reference fields from this class + for (Iterator itr = refFields.iterator(); itr.hasNext();) { + OopField field = (OopField) itr.next(); + Oop ref = field.getValue(reflectedType); + String name = field.getID().getName(); + writeEdge(instance, ref, identifierToXMLName(name)); + } + } + } + refFields = null; + } + + protected void writeReferenceField(Oop oop, OopField field) + throws IOException { + refFields.add(field); + } + + protected void writeByteField(Oop oop, ByteField field) + throws IOException { + writeField(field, "int", "B", Byte.toString(field.getValue(oop))); + } + + protected void writeCharField(Oop oop, CharField field) + throws IOException { + writeField(field, "string", "C", + escapeXMLChars(Character.toString(field.getValue(oop)))); + } + + protected void writeBooleanField(Oop oop, BooleanField field) + throws IOException { + writeField(field, "bool", "Z", Boolean.toString(field.getValue(oop))); + } + + protected void writeShortField(Oop oop, ShortField field) + throws IOException { + writeField(field, "int", "S", Short.toString(field.getValue(oop))); + } + + protected void writeIntField(Oop oop, IntField field) + throws IOException { + writeField(field, "int", "I", Integer.toString(field.getValue(oop))); + } + + protected void writeLongField(Oop oop, LongField field) + throws IOException { + writeField(field, "int", "J", Long.toString(field.getValue(oop))); + } + + protected void writeFloatField(Oop oop, FloatField field) + throws IOException { + writeField(field, "float", "F", Float.toString(field.getValue(oop))); + } + + protected void writeDoubleField(Oop oop, DoubleField field) + throws IOException { + writeField(field, "float", "D", Double.toString(field.getValue(oop))); + } + + protected void writeHeapFooter() throws IOException { + out.println("</graph>"); + out.println("</gxl>"); + } + + //-- Internals only below this point + + // Java identifier to XML NMTOKEN type string + private static String identifierToXMLName(String name) { + // for now, just replace '$' with '_' + return name.replace('$', '_'); + } + + // escapes XML meta-characters and illegal characters + private static String escapeXMLChars(String s) { + // FIXME: is there a better way or API? + StringBuffer result = null; + for(int i = 0, max = s.length(), delta = 0; i < max; i++) { + char c = s.charAt(i); + String replacement = null; + if (c == '&') { + replacement = "&"; + } else if (c == '<') { + replacement = "<"; + } else if (c == '>') { + replacement = ">"; + } else if (c == '"') { + replacement = """; + } else if (c == '\'') { + replacement = "'"; + } else if (c < '\u0020' || (c > '\ud7ff' && c < '\ue000') || + c == '\ufffe' || c == '\uffff') { + // These are illegal in XML -- put these in a CDATA section. + // Refer to section 2.2 Characters in XML specification at + // http://www.w3.org/TR/2004/REC-xml-20040204/ + replacement = "<![CDATA[&#x" + + Integer.toHexString((int)c) + ";]]>"; + } + + if (replacement != null) { + if (result == null) { + result = new StringBuffer(s); + } + result.replace(i + delta, i + delta + 1, replacement); + delta += (replacement.length() - 1); + } + } + if (result == null) { + return s; + } + return result.toString(); + } + + private static String getID(Oop oop) { + // address as unique id for node -- prefixed by "ID_". + if (oop == null) { + return "ID_NULL"; + } else { + return "ID_" + oop.getHandle().toString(); + } + } + + private void writeArrayLength(Array array) throws IOException { + writeAttribute("length", "int", + Integer.toString((int) array.getLength())); + } + + private void writeAttribute(String name, String type, String value) { + out.print("\t<attr name='"); + out.print(name); + out.print("'><"); + out.print(type); + out.print('>'); + out.print(value); + out.print("</"); + out.print(type); + out.println("></attr>"); + } + + private void writeEdge(Oop from, Oop to, String name) throws IOException { + out.print("<edge from='"); + out.print(getID(from)); + out.print("' to='"); + out.print(getID(to)); + out.println("'>"); + writeAttribute("name", "string", name); + out.println("</edge>"); + } + + private void writeField(Field field, String type, String kind, + String value) throws IOException { + // 'type' is GXL type of the attribute + // 'kind' is Java type code ("B", "C", "Z", "S", "I", "J", "F", "D") + if (isArray) { + out.print('\t'); + } else { + out.print("\t<attr name='"); + String name = field.getID().getName(); + out.print(identifierToXMLName(name)); + out.print("' kind='"); + out.print(kind); + out.print("'>"); + } + out.print('<'); + out.print(type); + out.print('>'); + out.print(value); + out.print("</"); + out.print(type); + out.print('>'); + if (isArray) { + out.println(); + } else { + out.println("</attr>"); + } + } + + private void writeVMInfo() throws IOException { + VM vm = VM.getVM(); + writeAttribute("vm-version", "string", vm.getVMRelease()); + writeAttribute("vm-type", "string", + (vm.isClientCompiler())? "client" : + ((vm.isServerCompiler())? "server" : "core")); + writeAttribute("os", "string", vm.getOS()); + writeAttribute("cpu", "string", vm.getCPU()); + writeAttribute("pointer-size", "string", + Integer.toString((int)vm.getOopSize() * 8)); + } + + // XML encoding that we'll use + private static final String ENCODING = "UTF-8"; + + // reference fields of currently visited object + private List/*<OopField>*/ refFields; + // are we writing an array now? + private boolean isArray; + private PrintWriter out; +}