# HG changeset patch # User Michael Van De Vanter # Date 1389146982 28800 # Node ID fb846424299fce1f545f2a6efdbfdd175c2099d3 # Parent 58ca96949f2eb032b31c7a00950a35d2fe6a1dd6 Truffle/Ruby: extend Instrumentation framework with language-agnostic interfaces for access to AST printing utilities and a Ruby implementation diff -r 58ca96949f2e -r fb846424299f graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ASTPrinter.java --- /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. + *

+ * WARNING: 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); + +} diff -r 58ca96949f2e -r fb846424299f graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java --- 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. + *

+ * Disclaimer: 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(); + } diff -r 58ca96949f2e -r fb846424299f graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java --- /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 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; + } + +} diff -r 58ca96949f2e -r fb846424299f graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java --- 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)); }