Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.oracle.truffle.api.nodes.GraphPrintVisitor Maven / Gradle / Ivy
Go to download
Truffle is a multi-language framework for executing dynamic languages
that achieves high performance when combined with Graal.
/*
* Copyright (c) 2012, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.api.nodes;
import java.io.*;
import java.lang.annotation.*;
import java.net.*;
import java.util.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
import com.oracle.truffle.api.nodes.NodeFieldAccessor.NodeFieldKind;
/**
* Utility class for creating output for the ideal graph visualizer.
*/
public class GraphPrintVisitor {
public static final String GraphVisualizerAddress = "127.0.0.1";
public static final int GraphVisualizerPort = 4444;
private Document dom;
private Map nodeMap;
private List edgeList;
private Map prevNodeMap;
private int id;
private Element graphDocument;
private Element groupElement;
private Element graphElement;
private Element nodesElement;
private Element edgesElement;
public GraphPrintVisitor() {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.newDocument();
} catch (ParserConfigurationException ex) {
throw new RuntimeException(ex);
}
graphDocument = dom.createElement("graphDocument");
dom.appendChild(graphDocument);
}
public GraphPrintVisitor beginGroup(String groupName) {
groupElement = dom.createElement("group");
graphDocument.appendChild(groupElement);
Element properties = dom.createElement("properties");
groupElement.appendChild(properties);
if (!groupName.isEmpty()) {
// set group name
Element propName = dom.createElement("p");
propName.setAttribute("name", "name");
propName.setTextContent(groupName);
properties.appendChild(propName);
}
// forget old nodes
nodeMap = prevNodeMap = null;
edgeList = null;
return this;
}
public GraphPrintVisitor beginGraph(String graphName) {
if (null == groupElement) {
beginGroup("");
} else if (null != prevNodeMap) {
// TODO: difference (create removeNode,removeEdge elements)
}
graphElement = dom.createElement("graph");
groupElement.appendChild(graphElement);
Element properties = dom.createElement("properties");
graphElement.appendChild(properties);
nodesElement = dom.createElement("nodes");
graphElement.appendChild(nodesElement);
edgesElement = dom.createElement("edges");
graphElement.appendChild(edgesElement);
// set graph name
Element propName = dom.createElement("p");
propName.setAttribute("name", "name");
propName.setTextContent(graphName);
properties.appendChild(propName);
// save old nodes
prevNodeMap = nodeMap;
nodeMap = new IdentityHashMap<>();
edgeList = new ArrayList<>();
return this;
}
@Override
public String toString() {
if (null != dom) {
try {
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.setOutputProperty(OutputKeys.INDENT, "yes");
tr.setOutputProperty(OutputKeys.METHOD, "xml");
tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
StringWriter strWriter = new StringWriter();
tr.transform(new DOMSource(dom), new StreamResult(strWriter));
return strWriter.toString();
} catch (TransformerException e) {
e.printStackTrace();
}
}
return "";
}
public void printToFile(File f) {
try {
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.setOutputProperty(OutputKeys.INDENT, "yes");
tr.setOutputProperty(OutputKeys.METHOD, "xml");
tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
tr.transform(new DOMSource(dom), new StreamResult(new FileOutputStream(f)));
} catch (TransformerException | FileNotFoundException e) {
e.printStackTrace();
}
}
public void printToSysout() {
try {
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.setOutputProperty(OutputKeys.INDENT, "yes");
tr.setOutputProperty(OutputKeys.METHOD, "xml");
tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
tr.transform(new DOMSource(dom), new StreamResult(System.out));
} catch (TransformerException e) {
e.printStackTrace();
}
}
public void printToNetwork(boolean ignoreErrors) {
try {
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.setOutputProperty(OutputKeys.METHOD, "xml");
Socket socket = new Socket(GraphVisualizerAddress, GraphVisualizerPort);
BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputStream(), 0x4000);
tr.transform(new DOMSource(dom), new StreamResult(stream));
} catch (TransformerException | IOException e) {
if (!ignoreErrors) {
e.printStackTrace();
}
}
}
private String nextId() {
return String.valueOf(id++);
}
private String oldOrNextId(Object node) {
if (null != prevNodeMap && prevNodeMap.containsKey(node)) {
Element nodeElem = prevNodeMap.get(node);
return nodeElem.getAttribute("id");
} else {
return nextId();
}
}
protected Element getElementByObject(Object op) {
return nodeMap.get(op);
}
protected void createElementForNode(Object node) {
boolean exists = nodeMap.containsKey(node);
if (!exists || NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) != null) {
Element nodeElem = dom.createElement("node");
nodeElem.setAttribute("id", !exists ? oldOrNextId(node) : nextId());
nodeMap.put(node, nodeElem);
Element properties = dom.createElement("properties");
nodeElem.appendChild(properties);
nodesElement.appendChild(nodeElem);
setNodeProperty(node, "name", node.getClass().getSimpleName().replaceFirst("Node$", ""));
NodeInfo nodeInfo = node.getClass().getAnnotation(NodeInfo.class);
if (nodeInfo != null) {
setNodeProperty(node, "cost", nodeInfo.cost());
if (!nodeInfo.shortName().isEmpty()) {
setNodeProperty(node, "shortName", nodeInfo.shortName());
}
}
setNodeProperty(node, "class", node.getClass().getSimpleName());
if (node instanceof Node) {
readNodeProperties((Node) node);
copyDebugProperties((Node) node);
}
}
}
private Element getPropertyElement(Object node, String propertyName) {
Element nodeElem = getElementByObject(node);
Element propertiesElem = (Element) nodeElem.getElementsByTagName("properties").item(0);
if (propertiesElem == null) {
return null;
}
NodeList propList = propertiesElem.getElementsByTagName("p");
for (int i = 0; i < propList.getLength(); i++) {
Element p = (Element) propList.item(i);
if (propertyName.equals(p.getAttribute("name"))) {
return p;
}
}
return null;
}
protected void setNodeProperty(Object node, String propertyName, Object value) {
Element nodeElem = getElementByObject(node);
Element propElem = getPropertyElement(node, propertyName); // if property exists, replace
// its value
if (null == propElem) { // if property doesn't exist, create one
propElem = dom.createElement("p");
propElem.setAttribute("name", propertyName);
nodeElem.getElementsByTagName("properties").item(0).appendChild(propElem);
}
propElem.setTextContent(String.valueOf(value));
}
private void copyDebugProperties(Node node) {
Map debugProperties = node.getDebugProperties();
for (Map.Entry property : debugProperties.entrySet()) {
setNodeProperty(node, property.getKey(), property.getValue());
}
}
private void readNodeProperties(Node node) {
NodeFieldAccessor[] fields = node.getNodeClass().getFields();
for (NodeFieldAccessor field : fields) {
if (field.getKind() == NodeFieldKind.DATA) {
String key = field.getName();
if (getPropertyElement(node, key) == null) {
Object value = field.loadValue(node);
setNodeProperty(node, key, value);
}
}
}
}
protected void connectNodes(Object a, Object b, String label) {
if (nodeMap.get(a) == null || nodeMap.get(b) == null) {
return;
}
String fromId = nodeMap.get(a).getAttribute("id");
String toId = nodeMap.get(b).getAttribute("id");
// count existing to-edges
int count = 0;
for (Element e : edgeList) {
if (e.getAttribute("to").equals(toId)) {
++count;
}
}
Element edgeElem = dom.createElement("edge");
edgeElem.setAttribute("from", fromId);
edgeElem.setAttribute("to", toId);
edgeElem.setAttribute("index", String.valueOf(count));
if (label != null) {
edgeElem.setAttribute("label", label);
}
edgesElement.appendChild(edgeElem);
edgeList.add(edgeElem);
}
public GraphPrintVisitor visit(Object node) {
if (null == graphElement) {
beginGraph("truffle tree");
}
// if node is visited once again, skip
if (getElementByObject(node) != null && NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) == null) {
return this;
}
// respect node's custom handler
if (NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class) != null) {
Class extends GraphPrintHandler> customHandlerClass = NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class).handler();
try {
GraphPrintHandler customHandler = customHandlerClass.newInstance();
customHandler.visit(node, new GraphPrintAdapter());
} catch (InstantiationException | IllegalAccessException e) {
assert false : e;
}
} else if (NodeUtil.findAnnotation(node.getClass(), NullGraphPrintHandler.class) != null) {
// ignore
} else {
// default handler
createElementForNode(node);
if (node instanceof Node) {
for (Map.Entry child : findNamedNodeChildren((Node) node).entrySet()) {
visit(child.getValue());
connectNodes(node, child.getValue(), child.getKey());
}
}
}
return this;
}
private static LinkedHashMap findNamedNodeChildren(Node node) {
LinkedHashMap nodes = new LinkedHashMap<>();
NodeClass nodeClass = node.getNodeClass();
for (NodeFieldAccessor field : nodeClass.getFields()) {
NodeFieldKind kind = field.getKind();
if (kind == NodeFieldKind.CHILD || kind == NodeFieldKind.CHILDREN) {
Object value = field.loadValue(node);
if (value != null) {
if (kind == NodeFieldKind.CHILD) {
nodes.put(field.getName(), (Node) value);
} else if (kind == NodeFieldKind.CHILDREN) {
Object[] children = (Object[]) value;
for (int i = 0; i < children.length; i++) {
if (children[i] != null) {
nodes.put(field.getName() + "[" + i + "]", (Node) children[i]);
}
}
}
}
}
}
return nodes;
}
public class GraphPrintAdapter {
public void createElementForNode(Object node) {
GraphPrintVisitor.this.createElementForNode(node);
}
public void visit(Object node) {
GraphPrintVisitor.this.visit(node);
}
public void connectNodes(Object node, Object child) {
GraphPrintVisitor.this.connectNodes(node, child, null);
}
public void setNodeProperty(Object node, String propertyName, Object value) {
GraphPrintVisitor.this.setNodeProperty(node, propertyName, value);
}
}
public interface GraphPrintHandler {
void visit(Object node, GraphPrintAdapter gPrinter);
}
public interface ChildSupplier {
/** Supplies an additional child if available. */
Object startNode(Object callNode);
void endNode(Object callNode);
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomGraphPrintHandler {
Class extends GraphPrintHandler> handler();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface NullGraphPrintHandler {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface GraphDuplicate {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface HiddenField {
}
}