1/*
2 * Copyright (c) 2008, 2015, 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 */
24package com.sun.hotspot.igv.data.serialization;
25
26import com.sun.hotspot.igv.data.*;
27import java.io.IOException;
28import java.io.InputStream;
29import java.io.Writer;
30import java.util.HashSet;
31import java.util.Set;
32
33/**
34 *
35 * @author Thomas Wuerthinger
36 */
37public class Printer {
38
39    private InputStream in;
40
41    public Printer() {
42        this(null);
43    }
44
45    public Printer(InputStream inputStream) {
46        this.in = inputStream;
47    }
48
49    public void export(Writer writer, GraphDocument document) {
50
51        XMLWriter xmlWriter = new XMLWriter(writer);
52
53        try {
54            export(xmlWriter, document);
55        } catch (IOException ex) {
56        }
57    }
58
59    private void export(XMLWriter xmlWriter, GraphDocument document) throws IOException {
60        xmlWriter.startTag(Parser.ROOT_ELEMENT);
61        xmlWriter.writeProperties(document.getProperties());
62        for (FolderElement e : document.getElements()) {
63            if (e instanceof Group) {
64                export(xmlWriter, (Group) e);
65            } else if (e instanceof InputGraph) {
66                export(xmlWriter, (InputGraph)e, null, false);
67            }
68        }
69
70        xmlWriter.endTag();
71        xmlWriter.flush();
72    }
73
74    private void export(XMLWriter writer, Group g) throws IOException {
75        Properties attributes = new Properties();
76        attributes.setProperty("difference", Boolean.toString(true));
77        writer.startTag(Parser.GROUP_ELEMENT, attributes);
78        writer.writeProperties(g.getProperties());
79
80        boolean shouldExport = true;
81        if (in != null) {
82            char c = (char) in.read();
83            if (c != 'y') {
84                shouldExport = false;
85            }
86        }
87
88        if (shouldExport) {
89            if (g.getMethod() != null) {
90                export(writer, g.getMethod());
91            }
92
93            InputGraph previous = null;
94            for (FolderElement e : g.getElements()) {
95                if (e instanceof InputGraph) {
96                    InputGraph graph = (InputGraph) e;
97                    export(writer, graph, previous, true);
98                    previous = graph;
99                } else if (e instanceof Group) {
100                    export(writer, (Group) e);
101                }
102            }
103        }
104
105        writer.endTag();
106    }
107
108    public void export(XMLWriter writer, InputGraph graph, InputGraph previous, boolean difference) throws IOException {
109
110        writer.startTag(Parser.GRAPH_ELEMENT);
111        writer.writeProperties(graph.getProperties());
112        writer.startTag(Parser.NODES_ELEMENT);
113
114        Set<InputNode> removed = new HashSet<>();
115        Set<InputNode> equal = new HashSet<>();
116
117        if (previous != null) {
118            for (InputNode n : previous.getNodes()) {
119                int id = n.getId();
120                InputNode n2 = graph.getNode(id);
121                if (n2 == null) {
122                    removed.add(n);
123                } else if (n.equals(n2)) {
124                    equal.add(n);
125                }
126            }
127        }
128
129        if (difference) {
130            for (InputNode n : removed) {
131                writer.simpleTag(Parser.REMOVE_NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, Integer.toString(n.getId())));
132            }
133        }
134
135        for (InputNode n : graph.getNodes()) {
136            if (!difference || !equal.contains(n)) {
137                writer.startTag(Parser.NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, Integer.toString(n.getId())));
138                writer.writeProperties(n.getProperties());
139                writer.endTag();
140            }
141        }
142
143        writer.endTag();
144
145        writer.startTag(Parser.EDGES_ELEMENT);
146        Set<InputEdge> removedEdges = new HashSet<>();
147        Set<InputEdge> equalEdges = new HashSet<>();
148
149        if (previous != null) {
150            for (InputEdge e : previous.getEdges()) {
151                if (graph.getEdges().contains(e)) {
152                    equalEdges.add(e);
153                } else {
154                    removedEdges.add(e);
155                }
156            }
157        }
158
159        if (difference) {
160            for (InputEdge e : removedEdges) {
161                writer.simpleTag(Parser.REMOVE_EDGE_ELEMENT, createProperties(e));
162            }
163        }
164
165        for (InputEdge e : graph.getEdges()) {
166            if (!difference || !equalEdges.contains(e)) {
167                if (!equalEdges.contains(e)) {
168                    writer.simpleTag(Parser.EDGE_ELEMENT, createProperties(e));
169                }
170            }
171        }
172
173        writer.endTag();
174
175        writer.startTag(Parser.CONTROL_FLOW_ELEMENT);
176        for (InputBlock b : graph.getBlocks()) {
177            writer.startTag(Parser.BLOCK_ELEMENT, new Properties(Parser.BLOCK_NAME_PROPERTY, b.getName()));
178
179            if (b.getSuccessors().size() > 0) {
180                writer.startTag(Parser.SUCCESSORS_ELEMENT);
181                for (InputBlock s : b.getSuccessors()) {
182                    writer.simpleTag(Parser.SUCCESSOR_ELEMENT, new Properties(Parser.BLOCK_NAME_PROPERTY, s.getName()));
183                }
184                writer.endTag();
185            }
186
187            if (b.getNodes().size() > 0) {
188            writer.startTag(Parser.NODES_ELEMENT);
189                for (InputNode n : b.getNodes()) {
190                    writer.simpleTag(Parser.NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, n.getId() + ""));
191                }
192                writer.endTag();
193            }
194
195            writer.endTag();
196        }
197
198        writer.endTag();
199        writer.endTag();
200    }
201
202    private void export(XMLWriter w, InputMethod method) throws IOException {
203
204        w.startTag(Parser.METHOD_ELEMENT, new Properties(Parser.METHOD_BCI_PROPERTY, method.getBci() + "", Parser.METHOD_NAME_PROPERTY, method.getName(), Parser.METHOD_SHORT_NAME_PROPERTY, method.getShortName()));
205
206        w.writeProperties(method.getProperties());
207
208        if (method.getInlined().size() > 0) {
209            w.startTag(Parser.INLINE_ELEMENT);
210            for (InputMethod m : method.getInlined()) {
211                export(w, m);
212            }
213            w.endTag();
214        }
215
216        w.startTag(Parser.BYTECODES_ELEMENT);
217
218        StringBuilder b = new StringBuilder();
219        b.append("<![CDATA[\n");
220        for (InputBytecode code : method.getBytecodes()) {
221            b.append(code.getBci());
222            b.append(" ");
223            b.append(code.getName());
224            b.append("\n");
225        }
226
227        b.append("]]>");
228        w.write(b.toString());
229        w.endTag();
230        w.endTag();
231    }
232
233    private Properties createProperties(InputEdge edge) {
234        Properties p = new Properties();
235        if (edge.getToIndex() != 0) {
236            p.setProperty(Parser.TO_INDEX_PROPERTY, Integer.toString(edge.getToIndex()));
237        }
238        if (edge.getFromIndex() != 0) {
239            p.setProperty(Parser.FROM_INDEX_PROPERTY, Integer.toString(edge.getFromIndex()));
240        }
241        p.setProperty(Parser.TO_PROPERTY, Integer.toString(edge.getTo()));
242        p.setProperty(Parser.FROM_PROPERTY, Integer.toString(edge.getFrom()));
243        p.setProperty(Parser.TYPE_PROPERTY, edge.getType());
244        return p;
245    }
246}
247