changeset 13563:fb846424299f

Truffle/Ruby: extend Instrumentation framework with language-agnostic interfaces for access to AST printing utilities and a Ruby implementation
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Tue, 07 Jan 2014 18:09:42 -0800
parents 58ca96949f2e
children 35f637594acc
files graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ASTPrinter.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java
diffstat 4 files changed, 244 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ASTPrinter.java	Tue Jan 07 18:09:42 2014 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2014, 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;
+
+import java.io.*;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Language-agnostic access to AST-based debugging support.
+ * <p>
+ * <strong>WARNING:</strong> this interface is under development and will change substantially.
+ */
+public interface ASTPrinter {
+
+    /**
+     * Print a textual AST display, one line per node, with nesting.
+     * 
+     * @param p
+     * @param node the root node of the display.
+     * @param maxDepth the maximum number of levels to print below the root
+     * @param markNode a node to mark with a textual arrow prefix, if present.
+     */
+    void printTree(PrintWriter p, Node node, int maxDepth, Node markNode);
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Tue Jan 07 17:52:54 2014 -0800
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Tue Jan 07 18:09:42 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -26,6 +26,8 @@
 
 /**
  * Information about the runtime context of a Truffle program.
+ * <p>
+ * <strong>Disclaimer:</strong> this interface is under development and will change.
  */
 public interface ExecutionContext {
 
@@ -40,4 +42,9 @@
      */
     DebugManager getDebugManager();
 
+    /**
+     * Gets access to utilities for printing different aspects of a Truffle AST.
+     */
+    ASTPrinter getASTPrinter();
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java	Tue Jan 07 18:09:42 2014 -0800
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.debug;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
+import com.oracle.truffle.ruby.nodes.methods.*;
+
+/**
+ * Printers for Truffle-internal AST information.
+ */
+public final class RubyASTPrinter implements ASTPrinter {
+
+    public RubyASTPrinter() {
+    }
+
+    public void printTree(PrintWriter p, Node node, int maxDepth, Node markNode) {
+        printTree(p, node, maxDepth, markNode, 1);
+        p.println();
+        p.flush();
+    }
+
+    public String printTreeToString(Node node, int maxDepth, Node markNode) {
+        StringWriter out = new StringWriter();
+        printTree(new PrintWriter(out), node, maxDepth, markNode);
+        return out.toString();
+    }
+
+    public String printTreeToString(Node node, int maxDepth) {
+        return printTreeToString(node, maxDepth, null);
+    }
+
+    private static void printTree(PrintWriter p, Node node, int maxDepth, Node markNode, int level) {
+        if (node == null) {
+            p.print("null");
+            return;
+        }
+
+        p.print(nodeName(node));
+
+        String sep = "";
+        p.print("(");
+
+        final SourceSection src = node.getSourceSection();
+        if (src != null) {
+            if (!(src instanceof NullSourceSection)) {
+                p.print(src.getSource().getName() + ":" + src.getStartLine());
+            } else if (src instanceof CoreSourceSection) {
+                final CoreSourceSection coreSection = (CoreSourceSection) src;
+                p.print("core=\"" + (coreSection == null ? "?" : coreSection.toString()) + "\"");
+            }
+        }
+        if (node instanceof PhylumMarked) {
+            final PhylumMarked markedNode = (PhylumMarked) node;
+            String prefix = "";
+            for (NodePhylum phylum : markedNode.getPhylumMarks()) {
+                p.print(prefix);
+                prefix = ",";
+                p.print(phylum.toString());
+            }
+
+        }
+
+        ArrayList<NodeField> childFields = new ArrayList<>();
+
+        for (NodeField field : NodeClass.get(node.getClass()).getFields()) {
+            if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) {
+                childFields.add(field);
+            } else if (field.getKind() == NodeFieldKind.DATA) {
+                // p.print(sep);
+                // sep = ", ";
+                //
+                // final String fieldName = field.getName();
+                // switch (fieldName) {
+                //
+                // }
+                // p.print(fieldName);
+                // p.print(" = ");
+                // p.print(field.loadValue(node));
+            }
+        }
+        p.print(")");
+
+        if (level <= maxDepth) {
+
+            if (childFields.size() != 0) {
+                p.print(" {");
+                for (NodeField field : childFields) {
+
+                    Object value = field.loadValue(node);
+                    if (value == null) {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                        p.print(" = null ");
+                    } else if (field.getKind() == NodeFieldKind.CHILD) {
+                        final Node valueNode = (Node) value;
+                        printNewLine(p, level, valueNode == markNode);
+                        p.print(field.getName());
+                        p.print(" = ");
+                        printTree(p, valueNode, maxDepth, markNode, level + 1);
+                    } else if (field.getKind() == NodeFieldKind.CHILDREN) {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                        Node[] children = (Node[]) value;
+                        p.print(" = [");
+                        sep = "";
+                        for (Node child : children) {
+                            p.print(sep);
+                            sep = ", ";
+                            printTree(p, child, maxDepth, markNode, level + 1);
+                        }
+                        p.print("]");
+                    } else {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                    }
+                }
+                printNewLine(p, level - 1);
+                p.print("}");
+            }
+        }
+    }
+
+    private static void printNewLine(PrintWriter p, int level, boolean mark) {
+        p.println();
+        for (int i = 0; i < level; i++) {
+            if (mark && i == 0) {
+                p.print(" -->");
+            } else {
+                p.print("    ");
+            }
+        }
+    }
+
+    private static void printNewLine(PrintWriter p, int level) {
+        printNewLine(p, level, false);
+    }
+
+    private static String nodeName(Node node) {
+        String nodeVal = null;
+        if (node instanceof CallNode) {
+            final CallNode callNode = (CallNode) node;
+            nodeVal = callNode.getName();
+
+        } else if (node instanceof FixnumLiteralNode) {
+            final FixnumLiteralNode fixnum = (FixnumLiteralNode) node;
+            nodeVal = Integer.toString(fixnum.getValue());
+        } else if (node instanceof MethodDefinitionNode) {
+            final MethodDefinitionNode defNode = (MethodDefinitionNode) node;
+            nodeVal = defNode.getName();
+        }
+        String result = node.getClass().getSimpleName();
+        if (nodeVal != null) {
+            result = result + "[\"" + nodeVal + "\"]";
+        }
+        return result;
+    }
+
+}
--- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java	Tue Jan 07 17:52:54 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java	Tue Jan 07 18:09:42 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
  * code is released under a tri EPL/GPL/LGPL license. You can use it,
  * redistribute it and/or modify it under the terms of the:
  *
@@ -42,6 +42,7 @@
     private final AtExitManager atExitManager;
     private final RubyDebugManager debugManager;
     private final SourceManager sourceManager;
+    private final ASTPrinter astPrinter;
 
     private AtomicLong nextObjectID = new AtomicLong(0);
 
@@ -50,14 +51,19 @@
     private POSIX posix = POSIXFactory.getPOSIX();
 
     public RubyContext(RubyParser parser) {
-        this(new Configuration(new ConfigurationBuilder()), parser);
+        this(new Configuration(new ConfigurationBuilder()), parser, null);
     }
 
     public RubyContext(Configuration configuration, RubyParser parser) {
+        this(configuration, parser, null);
+    }
+
+    public RubyContext(Configuration configuration, RubyParser parser, ASTPrinter astPrinter) {
         assert configuration != null;
 
         this.configuration = configuration;
         this.parser = parser;
+        this.astPrinter = astPrinter;
 
         objectSpaceManager = new ObjectSpaceManager(this);
         traceManager = new TraceManager(this);
@@ -91,6 +97,10 @@
         return debugManager;
     }
 
+    public ASTPrinter getASTPrinter() {
+        return astPrinter;
+    }
+
     public void implementationMessage(String format, Object... arguments) {
         System.err.println("rubytruffle: " + String.format(format, arguments));
     }