Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java @ 7267:a4b84ba6dc2e
Introduction of the Truffle API for efficient implementation of dynamic languages on top of the Graal VM. New projects com.oracle.truffle.api for the API definition and com.oracle.truffle.api.test for API tests and documentation.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Tue, 18 Dec 2012 15:33:55 +0100 |
parents | |
children | 5e3d1a68664e |
comparison
equal
deleted
inserted
replaced
7259:494d99e07614 | 7267:a4b84ba6dc2e |
---|---|
1 /* | |
2 * Copyright (c) 2012, 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 package com.oracle.truffle.api.nodes; | |
24 | |
25 import java.io.*; | |
26 import java.lang.annotation.*; | |
27 import java.lang.reflect.*; | |
28 import java.net.*; | |
29 import java.util.*; | |
30 | |
31 import javax.xml.parsers.*; | |
32 import javax.xml.transform.*; | |
33 import javax.xml.transform.dom.*; | |
34 import javax.xml.transform.stream.*; | |
35 | |
36 import org.w3c.dom.*; | |
37 | |
38 /** | |
39 * Utility class for creating output for the ideal graph visualizer. | |
40 */ | |
41 public class GraphPrintVisitor { | |
42 | |
43 public static final String GraphVisualizerAddress = "127.0.0.1"; | |
44 public static final int GraphVisualizerPort = 4444; | |
45 | |
46 private Document dom; | |
47 private Map<Object, Element> nodeMap; | |
48 private List<Element> edgeList; | |
49 private Map<Object, Element> prevNodeMap; | |
50 private int id; | |
51 private Element graphDocument; | |
52 private Element groupElement; | |
53 private Element graphElement; | |
54 private Element nodesElement; | |
55 private Element edgesElement; | |
56 | |
57 public GraphPrintVisitor() { | |
58 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | |
59 try { | |
60 DocumentBuilder db = dbf.newDocumentBuilder(); | |
61 | |
62 dom = db.newDocument(); | |
63 } catch (ParserConfigurationException ex) { | |
64 System.out.println("Error while trying to instantiate DocumentBuilder " + ex); | |
65 } | |
66 | |
67 graphDocument = dom.createElement("graphDocument"); | |
68 dom.appendChild(graphDocument); | |
69 } | |
70 | |
71 public GraphPrintVisitor beginGroup(String groupName) { | |
72 groupElement = dom.createElement("group"); | |
73 graphDocument.appendChild(groupElement); | |
74 Element properties = dom.createElement("properties"); | |
75 groupElement.appendChild(properties); | |
76 | |
77 if (!groupName.isEmpty()) { | |
78 // set group name | |
79 Element propName = dom.createElement("p"); | |
80 propName.setAttribute("name", "name"); | |
81 propName.setTextContent(groupName); | |
82 properties.appendChild(propName); | |
83 } | |
84 | |
85 // forget old nodes | |
86 nodeMap = prevNodeMap = null; | |
87 edgeList = null; | |
88 | |
89 return this; | |
90 } | |
91 | |
92 public GraphPrintVisitor beginGraph(String graphName) { | |
93 if (null == groupElement) { | |
94 beginGroup(""); | |
95 } else if (null != prevNodeMap) { | |
96 // TODO: difference (create removeNode,removeEdge elements) | |
97 } | |
98 | |
99 graphElement = dom.createElement("graph"); | |
100 groupElement.appendChild(graphElement); | |
101 Element properties = dom.createElement("properties"); | |
102 graphElement.appendChild(properties); | |
103 nodesElement = dom.createElement("nodes"); | |
104 graphElement.appendChild(nodesElement); | |
105 edgesElement = dom.createElement("edges"); | |
106 graphElement.appendChild(edgesElement); | |
107 | |
108 // set graph name | |
109 Element propName = dom.createElement("p"); | |
110 propName.setAttribute("name", "name"); | |
111 propName.setTextContent(graphName); | |
112 properties.appendChild(propName); | |
113 | |
114 // save old nodes | |
115 prevNodeMap = nodeMap; | |
116 nodeMap = new HashMap<>(); | |
117 edgeList = new ArrayList<>(); | |
118 | |
119 return this; | |
120 } | |
121 | |
122 @Override | |
123 public String toString() { | |
124 if (null != dom) { | |
125 try { | |
126 Transformer tr = TransformerFactory.newInstance().newTransformer(); | |
127 tr.setOutputProperty(OutputKeys.INDENT, "yes"); | |
128 tr.setOutputProperty(OutputKeys.METHOD, "xml"); | |
129 tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); | |
130 | |
131 StringWriter strWriter = new StringWriter(); | |
132 tr.transform(new DOMSource(dom), new StreamResult(strWriter)); | |
133 return strWriter.toString(); | |
134 } catch (TransformerException e) { | |
135 e.printStackTrace(); | |
136 } | |
137 } | |
138 return ""; | |
139 } | |
140 | |
141 public void printToFile(File f) { | |
142 try { | |
143 Transformer tr = TransformerFactory.newInstance().newTransformer(); | |
144 tr.setOutputProperty(OutputKeys.INDENT, "yes"); | |
145 tr.setOutputProperty(OutputKeys.METHOD, "xml"); | |
146 tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); | |
147 | |
148 tr.transform(new DOMSource(dom), new StreamResult(new FileOutputStream(f))); | |
149 } catch (TransformerException | FileNotFoundException e) { | |
150 e.printStackTrace(); | |
151 } | |
152 } | |
153 | |
154 public void printToSysout() { | |
155 try { | |
156 Transformer tr = TransformerFactory.newInstance().newTransformer(); | |
157 tr.setOutputProperty(OutputKeys.INDENT, "yes"); | |
158 tr.setOutputProperty(OutputKeys.METHOD, "xml"); | |
159 tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); | |
160 | |
161 tr.transform(new DOMSource(dom), new StreamResult(System.out)); | |
162 } catch (TransformerException e) { | |
163 e.printStackTrace(); | |
164 } | |
165 } | |
166 | |
167 public void printToNetwork() { | |
168 try { | |
169 Transformer tr = TransformerFactory.newInstance().newTransformer(); | |
170 tr.setOutputProperty(OutputKeys.METHOD, "xml"); | |
171 | |
172 Socket socket = new Socket(GraphVisualizerAddress, GraphVisualizerPort); | |
173 BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputStream(), 0x4000); | |
174 tr.transform(new DOMSource(dom), new StreamResult(stream)); | |
175 } catch (TransformerException | IOException e) { | |
176 e.printStackTrace(); | |
177 } | |
178 } | |
179 | |
180 private String nextId() { | |
181 return String.valueOf(id++); | |
182 } | |
183 | |
184 private String oldOrNextId(Object node) { | |
185 if (null != prevNodeMap && prevNodeMap.containsKey(node)) { | |
186 Element nodeElem = prevNodeMap.get(node); | |
187 return nodeElem.getAttribute("id"); | |
188 } else { | |
189 return nextId(); | |
190 } | |
191 } | |
192 | |
193 protected Element getElementByObject(Object op) { | |
194 return nodeMap.get(op); | |
195 } | |
196 | |
197 protected void createElementForNode(Object node) { | |
198 boolean exists = nodeMap.containsKey(node); | |
199 if (!exists || NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) != null) { | |
200 Element nodeElem = dom.createElement("node"); | |
201 nodeElem.setAttribute("id", !exists ? oldOrNextId(node) : nextId()); | |
202 nodeMap.put(node, nodeElem); | |
203 Element properties = dom.createElement("properties"); | |
204 nodeElem.appendChild(properties); | |
205 nodesElement.appendChild(nodeElem); | |
206 | |
207 setNodeProperty(node, "name", node.getClass().getSimpleName().replaceFirst("Node$", "")); | |
208 NodeInfo nodeInfo = node.getClass().getAnnotation(NodeInfo.class); | |
209 if (nodeInfo != null && !nodeInfo.shortName().isEmpty()) { | |
210 setNodeProperty(node, "shortName", nodeInfo.shortName()); | |
211 } | |
212 setNodeProperty(node, "nodeType", (Node.class.isAssignableFrom(node.getClass()) ? Node.class.getSimpleName() : "other")); | |
213 setNodeProperty(node, "nodeClass", node.getClass().getSimpleName()); | |
214 copyDebugProperties(node); // TODO: may overwrite property "name"? (currently allowed) | |
215 readNodeProperties(node); | |
216 } | |
217 } | |
218 | |
219 private Element getPropertyElement(Object node, String propertyName) { | |
220 Element nodeElem = getElementByObject(node); | |
221 Element propertiesElem = (Element) nodeElem.getElementsByTagName("properties").item(0); | |
222 if (propertiesElem == null) { | |
223 return null; | |
224 } | |
225 | |
226 NodeList propList = propertiesElem.getElementsByTagName("p"); | |
227 for (int i = 0; i < propList.getLength(); i++) { | |
228 Element p = (Element) propList.item(i); | |
229 if (propertyName.equals(p.getAttribute("name"))) { | |
230 return p; | |
231 } | |
232 } | |
233 return null; | |
234 } | |
235 | |
236 protected void setNodeProperty(Object node, String propertyName, Object value) { | |
237 Element nodeElem = getElementByObject(node); | |
238 Element propElem = getPropertyElement(node, propertyName); // if property exists, replace its value | |
239 if (null == propElem) { // if property doesn't exist, create one | |
240 propElem = dom.createElement("p"); | |
241 propElem.setAttribute("name", propertyName); | |
242 nodeElem.getElementsByTagName("properties").item(0).appendChild(propElem); | |
243 } | |
244 propElem.setTextContent(String.valueOf(value)); | |
245 } | |
246 | |
247 private void copyDebugProperties(Object node) { | |
248 if (node instanceof Node) { | |
249 Map<String, Object> debugProperties = ((Node) node).getDebugProperties(); | |
250 for (Map.Entry<String, Object> property : debugProperties.entrySet()) { | |
251 setNodeProperty(node, property.getKey(), property.getValue()); | |
252 } | |
253 } | |
254 } | |
255 | |
256 private void readNodeProperties(Object node) { | |
257 Field[] fields = NodeUtil.getAllFields(node.getClass()); | |
258 for (Field field : fields) { | |
259 if (Modifier.isStatic(field.getModifiers())) { | |
260 continue; | |
261 } | |
262 if (Node.class.isAssignableFrom(field.getType()) || (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType()))) { | |
263 continue; | |
264 } | |
265 String key = field.getName(); | |
266 if (field.getAnnotation(HiddenField.class) == null && getPropertyElement(node, key) == null) { | |
267 try { | |
268 field.setAccessible(true); | |
269 Object value = field.get(node); | |
270 setNodeProperty(node, key, value); | |
271 } catch (IllegalArgumentException | IllegalAccessException e) { | |
272 assert false : e; | |
273 } | |
274 } | |
275 } | |
276 } | |
277 | |
278 protected void connectNodes(Object a, Object b) { | |
279 if (nodeMap.get(a) == null || nodeMap.get(b) == null) { | |
280 return; | |
281 } | |
282 | |
283 String fromId = nodeMap.get(a).getAttribute("id"); | |
284 String toId = nodeMap.get(b).getAttribute("id"); | |
285 | |
286 // count existing to-edges | |
287 int count = 0; | |
288 for (Element e : edgeList) { | |
289 if (e.getAttribute("to").equals(toId)) { | |
290 ++count; | |
291 } | |
292 } | |
293 | |
294 Element edgeElem = dom.createElement("edge"); | |
295 edgeElem.setAttribute("from", fromId); | |
296 edgeElem.setAttribute("to", toId); | |
297 edgeElem.setAttribute("index", String.valueOf(count)); | |
298 edgesElement.appendChild(edgeElem); | |
299 edgeList.add(edgeElem); | |
300 } | |
301 | |
302 public GraphPrintVisitor visit(Object node) { | |
303 if (null == graphElement) { | |
304 beginGraph("truffle tree"); | |
305 } | |
306 | |
307 // if node is visited once again, skip | |
308 if (getElementByObject(node) == null || NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) != null) { | |
309 visitAny(node); | |
310 } | |
311 | |
312 return this; | |
313 } | |
314 | |
315 private void visitAny(Object node) { | |
316 // respect node's custom handler | |
317 if (NodeUtil.findAnnotation(node.getClass(), NullGraphPrintHandler.class) != null) { | |
318 return; | |
319 } | |
320 if (NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class) != null) { | |
321 Class<? extends GraphPrintHandler> gpHandlerClass = NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class).handler(); | |
322 try { | |
323 GraphPrintHandler gpHandler = gpHandlerClass.newInstance(); | |
324 gpHandler.visit(node, new GraphPrintAdapter()); | |
325 } catch (InstantiationException e) { | |
326 assert false; | |
327 } catch (IllegalAccessException e) { | |
328 assert false; | |
329 } | |
330 return; | |
331 } | |
332 | |
333 // default handler | |
334 createElementForNode(node); | |
335 | |
336 List<Object> children = NodeUtil.findNodeChildren(node); | |
337 for (Object child : children) { | |
338 if (child == null) { | |
339 continue; | |
340 } else if (child instanceof Node) { | |
341 visit(child); | |
342 } else { | |
343 continue; | |
344 } | |
345 connectNodes(node, child); | |
346 } | |
347 } | |
348 | |
349 public class GraphPrintAdapter { | |
350 public void createElementForNode(Object node) { | |
351 GraphPrintVisitor.this.createElementForNode(node); | |
352 } | |
353 public void visit(Object node) { | |
354 GraphPrintVisitor.this.visit(node); | |
355 } | |
356 public void connectNodes(Object node, Object child) { | |
357 GraphPrintVisitor.this.connectNodes(node, child); | |
358 } | |
359 public void setNodeProperty(Object node, String propertyName, Object value) { | |
360 GraphPrintVisitor.this.setNodeProperty(node, propertyName, value); | |
361 } | |
362 } | |
363 | |
364 public interface GraphPrintHandler { | |
365 void visit(Object node, GraphPrintAdapter gPrinter); | |
366 } | |
367 | |
368 @Retention(RetentionPolicy.RUNTIME) | |
369 @Target(ElementType.TYPE) | |
370 public @interface CustomGraphPrintHandler { | |
371 Class<? extends GraphPrintHandler> handler(); | |
372 } | |
373 @Retention(RetentionPolicy.RUNTIME) | |
374 @Target(ElementType.TYPE) | |
375 public @interface NullGraphPrintHandler { | |
376 } | |
377 @Retention(RetentionPolicy.RUNTIME) | |
378 @Target(ElementType.TYPE) | |
379 public @interface GraphDuplicate { | |
380 } | |
381 @Retention(RetentionPolicy.RUNTIME) | |
382 @Target(ElementType.FIELD) | |
383 public @interface HiddenField { | |
384 } | |
385 } |