changeset 16595:618d92152d3c

SL: Added support for instrumentation.
author David Piorkowski <david.piorkowski@oracle.com>
date Thu, 24 Jul 2014 16:14:44 -0700
parents 8084d44c78d3
children 9e2317b1092b
files graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTPrinter.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTProber.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLDefaultVisualizer.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLNodeProber.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java
diffstat 14 files changed, 814 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Thu Jul 24 12:22:54 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Thu Jul 24 16:14:44 2014 -0700
@@ -152,7 +152,7 @@
         if (sourceCallback != null) {
             sourceCallback.startLoading(source);
         }
-        Parser.parseSL(context, source);
+        Parser.parseSL(context, source, null);
         if (sourceCallback != null) {
             sourceCallback.endLoading(source);
         }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Thu Jul 24 12:22:54 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Thu Jul 24 16:14:44 2014 -0700
@@ -50,6 +50,6 @@
     private static void doDefineFunction(SLContext context, String code) {
         Source source = Source.fromText(code, "[defineFunction]");
         /* The same parsing code as for parsing the initial source. */
-        Parser.parseSL(context, source);
+        Parser.parseSL(context, source, null);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Thu Jul 24 16:14:44 2014 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.sl.factory;
+
+import java.io.*;
+
+import com.oracle.truffle.sl.nodes.instrument.*;
+import com.oracle.truffle.sl.runtime.*;
+
+public final class SLContextFactory {
+
+    private static SLASTProber astProber;
+
+    private SLContextFactory() {
+
+    }
+
+    public static SLContext create() {
+        final SLContext slContext = new SLContext(new BufferedReader(new InputStreamReader(System.in)), System.out);
+        slContext.initialize();
+        slContext.setVisualizer(new SLDefaultVisualizer());
+        astProber = new SLASTProber();
+        slContext.setASTNodeProber(astProber);
+        return slContext;
+    }
+
+    public static void addNodeProber(SLNodeProber nodeProber) {
+        astProber.addNodeProber(nodeProber);
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Thu Jul 24 12:22:54 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Thu Jul 24 16:14:44 2014 -0700
@@ -42,4 +42,8 @@
      * Execute this node as as statement, where no return value is necessary.
      */
     public abstract void executeVoid(VirtualFrame frame);
+
+    public SLStatementNode getNonWrapperNode() {
+        return this;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTPrinter.java	Thu Jul 24 16:14:44 2014 -0700
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.sl.nodes.instrument;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+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.source.*;
+
+/**
+ * SLASTPrinter is used to print for SL's internal Truffle AST. This is used by
+ * {@link SLDefaultVisualizer} to provide a means of displaying the internal Truffle AST
+ */
+public final class SLASTPrinter implements ASTPrinter {
+    public SLASTPrinter() {
+    }
+
+    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 NullSourceSection) {
+                final NullSourceSection nullSection = (NullSourceSection) src;
+                p.print(nullSection.getShortDescription());
+            }
+        }
+        if (node instanceof SyntaxTagged) {
+            final SyntaxTagged taggedNode = (SyntaxTagged) node;
+            p.print("[");
+            String prefix = "";
+            for (SyntaxTag tag : taggedNode.getSyntaxTags()) {
+                p.print(prefix);
+                prefix = ",";
+                p.print(tag.toString());
+            }
+            p.print("]");
+        }
+
+        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) {
+        return node.getClass().getSimpleName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTProber.java	Thu Jul 24 16:14:44 2014 -0700
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.sl.nodes.instrument;
+
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+
+/**
+ * SLASTProber contains the collection of {@link SLNodeProber}s and methods to attach the probers to
+ * nodes.
+ */
+public final class SLASTProber implements ASTProber, SLNodeProber {
+
+    private ArrayList<SLNodeProber> nodeProbers = new ArrayList<>();
+
+    public SLASTProber() {
+    }
+
+    /**
+     * Adds a {@link SLNodeProber} to this SLASTProber. Probes must be of type {@link SLNodeProber}
+     * and must not already have been added.
+     *
+     * @param nodeProber the {@link SLNodeProber} to add.
+     */
+    public void addNodeProber(ASTNodeProber nodeProber) {
+        if (nodeProber instanceof SLNodeProber) {
+            assert !nodeProbers.contains(nodeProber);
+            nodeProbers.add((SLNodeProber) nodeProber);
+        } else {
+            throw new IllegalArgumentException("invalid prober for SL implementation");
+        }
+    }
+
+    /**
+     * Unimplemented, does nothing.
+     */
+    public Node probeAs(Node astNode, SyntaxTag tag, Object... args) {
+        return astNode;
+    }
+
+    /**
+     * Attaches the current probers to the given {@link SLStatementNode} as a statement.
+     *
+     * @param node The {@link SLStatementNode} to attach the stored set of probers to.
+     */
+    @Override
+    public SLStatementNode probeAsStatement(SLStatementNode node) {
+        SLStatementNode result = node;
+        for (SLNodeProber nodeProber : nodeProbers) {
+            result = nodeProber.probeAsStatement(result);
+        }
+        return result;
+    }
+
+    /**
+     * Attaches the current probers to the given {@link SLExpressionNode} as a call. This will wrap
+     * the passed in node in an {@link SLExpressionWrapper}, tag it as a call and attach an
+     * instrument to it.
+     *
+     * @param node The {@link SLExpressionNode} to attach the stored set of probers to.
+     * @param callName The name of the call ???
+     *
+     */
+    @Override
+    public SLExpressionNode probeAsCall(SLExpressionNode node, String callName) {
+        SLExpressionNode result = node;
+        for (SLNodeProber nodeProber : nodeProbers) {
+            result = nodeProber.probeAsCall(node, callName);
+        }
+        return result;
+    }
+
+    /**
+     * Attaches the current probers to the given {@link SLExpressionNode} as an assignment. This
+     * will wrap the passed in node in an {@link SLExpressionWrapper}, tag it as an assignment and
+     * attach an instrument to it.
+     *
+     * @param node The {@link SLExpressionNode} to attached the stored set of probers to.
+     * @param localName The name of the assignment ???
+     *
+     */
+    @Override
+    public SLExpressionNode probeAsLocalAssignment(SLExpressionNode node, String localName) {
+        SLExpressionNode result = node;
+        for (SLNodeProber nodeProber : nodeProbers) {
+            result = nodeProber.probeAsLocalAssignment(result, localName);
+        }
+        return result;
+    }
+
+    public ASTNodeProber getCombinedNodeProber() {
+        return nodeProbers.isEmpty() ? null : this;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLDefaultVisualizer.java	Thu Jul 24 16:14:44 2014 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.sl.nodes.instrument;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * SLDefaultVisualizer provides methods to get the names of SL's internal Truffle AST nodes.
+ *
+ */
+public class SLDefaultVisualizer extends DefaultVisualizer {
+
+    private final SLASTPrinter astPrinter;
+
+    public SLDefaultVisualizer() {
+        this.astPrinter = new SLASTPrinter();
+    }
+
+    @Override
+    public ASTPrinter getASTPrinter() {
+        return astPrinter;
+    }
+
+    @Override
+    public String displayMethodName(Node node) {
+
+        if (node == null) {
+            return null;
+        }
+        RootNode root = node.getRootNode();
+        if (root instanceof SLRootNode) {
+            SLRootNode slRootNode = (SLRootNode) root;
+            return slRootNode.toString();
+
+        }
+        return "unknown";
+    }
+
+    @Override
+    public String displayCallTargetName(CallTarget callTarget) {
+        if (callTarget instanceof RootCallTarget) {
+            final RootCallTarget rootCallTarget = (RootCallTarget) callTarget;
+            SLRootNode slRootNode = (SLRootNode) rootCallTarget.getRootNode();
+            return slRootNode.toString();
+        }
+        return callTarget.toString();
+    }
+
+    @Override
+    public String displayValue(ExecutionContext context, Object value) {
+        if (value == SLNull.SINGLETON) {
+            return "null";
+        }
+        return value.toString();
+    }
+
+    @Override
+    public String displayIdentifier(FrameSlot slot) {
+
+        final Object id = slot.getIdentifier();
+        return id.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Thu Jul 24 16:14:44 2014 -0700
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.sl.nodes.instrument;
+
+import java.math.*;
+
+import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * SLExpressionWrapper is a Truffle AST node that gets inserted as the parent to the node that it is
+ * wrapping. Any debugging instruments are attached to this wrapper through {@link Probe}s (which
+ * themselves contain the instruments. It is through this mechanism that tools can interact directly
+ * with the AST. <br/>
+ * {@link SLExpressionWrapper} specifically wraps {@link SLExpressionNode}s and overrides the
+ * various execute functions in {@link SLExpressionNode} to operate on the child of the wrapper
+ * instead of the wrapper itself.
+ *
+ */
+public final class SLExpressionWrapper extends SLExpressionNode implements Wrapper {
+    @Child private SLExpressionNode child;
+
+    private final Probe probe;
+
+    public SLExpressionWrapper(SLContext context, SLExpressionNode child) {
+        super(child.getSourceSection());
+        assert !(child instanceof SLExpressionWrapper);
+        this.child = insert(child);
+        this.probe = context.getProbe(child.getSourceSection());
+    }
+
+    @Override
+    public SLExpressionNode getNonWrapperNode() {
+        return child;
+    }
+
+    @Override
+    public Node getChild() {
+        return child;
+    }
+
+    @Override
+    public Probe getProbe() {
+        return probe;
+    }
+
+    @Override
+    @SlowPath
+    public boolean isTaggedAs(SyntaxTag tag) {
+        return probe.isTaggedAs(tag);
+    }
+
+    @Override
+    @SlowPath
+    public Iterable<SyntaxTag> getSyntaxTags() {
+        return probe.getSyntaxTags();
+    }
+
+    @SlowPath
+    public void tagAs(SyntaxTag tag) {
+        probe.tagAs(tag);
+    }
+
+    @Override
+    public Object executeGeneric(VirtualFrame frame) {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        probe.enter(child, frame);
+        Object result;
+
+        try {
+            result = child.executeGeneric(frame);
+            probe.leave(child, frame, result);
+        } catch (Exception e) {
+            probe.leaveExceptional(child, frame, e);
+            throw (e);
+        }
+        return result;
+    }
+
+    @Override
+    public long executeLong(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        return SLTypesGen.SLTYPES.expectLong(executeGeneric(frame));
+    }
+
+    @Override
+    public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        return SLTypesGen.SLTYPES.expectBigInteger(executeGeneric(frame));
+    }
+
+    @Override
+    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        return SLTypesGen.SLTYPES.expectBoolean(executeGeneric(frame));
+    }
+
+    @Override
+    public String executeString(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        return SLTypesGen.SLTYPES.expectString(executeGeneric(frame));
+    }
+
+    @Override
+    public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        probe.enter(child, frame);
+        SLFunction result;
+
+        try {
+            result = child.executeFunction(frame);
+            probe.leave(child, frame, result);
+        } catch (Exception e) {
+            probe.leaveExceptional(child, frame, e);
+            throw (e);
+        }
+        return result;
+    }
+
+    @Override
+    public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException {
+        return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLNodeProber.java	Thu Jul 24 16:14:44 2014 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.sl.nodes.instrument;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.sl.nodes.*;
+
+public interface SLNodeProber extends ASTNodeProber {
+
+    SLStatementNode probeAsStatement(SLStatementNode result);
+
+    SLExpressionNode probeAsCall(SLExpressionNode node, String callName);
+
+    SLExpressionNode probeAsLocalAssignment(SLExpressionNode node, String localName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Thu Jul 24 16:14:44 2014 -0700
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.sl.nodes.instrument;
+
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * SLStatmentWrapper is a Truffle AST node that gets inserted as the parent to the node that it is
+ * wrapping. Any debugging instruments are attached to this wrapper through {@link Probe}s (which
+ * themselves contain the instruments). It is through this mechanism that tools can interact
+ * directly with the AST. <br/>
+ * SLStatmentWrapper specifically wraps {@link SLStatementWrapper}s and overrides the executeVoid
+ * function of {@link SLStatementNode} to operate on the child of the wrapper instead of the wrapper
+ * itself.
+ *
+ */
+public final class SLStatementWrapper extends SLStatementNode implements Wrapper {
+
+    @Child private SLStatementNode child;
+
+    private final Probe probe;
+
+    public SLStatementWrapper(SLContext context, SLStatementNode child) {
+        super(child.getSourceSection());
+        assert !(child instanceof SLStatementWrapper);
+        this.child = insert(child);
+        this.probe = context.getProbe(child.getSourceSection());
+    }
+
+    @Override
+    public SLStatementNode getNonWrapperNode() {
+        return child;
+    }
+
+    public Node getChild() {
+        return child;
+    }
+
+    public Probe getProbe() {
+        return probe;
+    }
+
+    @SlowPath
+    public boolean isTaggedAs(SyntaxTag tag) {
+        return probe.isTaggedAs(tag);
+    }
+
+    @SlowPath
+    public Iterable<SyntaxTag> getSyntaxTags() {
+        return probe.getSyntaxTags();
+    }
+
+    @SlowPath
+    public void tagAs(SyntaxTag tag) {
+        probe.tagAs(tag);
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        probe.enter(child, frame);
+
+        try {
+            child.executeVoid(frame);
+            probe.leave(child, frame);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probe.leaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Thu Jul 24 12:22:54 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Thu Jul 24 16:14:44 2014 -0700
@@ -33,6 +33,7 @@
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.runtime.*;
 
 // Checkstyle: stop
@@ -51,9 +52,9 @@
     public final Errors errors;
     private final SLNodeFactory factory;
     -->declarations
-    public Parser(SLContext context, Source source) {
+    public Parser(SLContext context, Source source, SLNodeProber astProber) {
         this.scanner = new Scanner(source.getInputStream());
-        this.factory = new SLNodeFactory(context, source);
+        this.factory = new SLNodeFactory(context, source, astProber);
         errors = new Errors();
     }
 
@@ -134,8 +135,8 @@
 -->initialization
     };
 
-    public static void parseSL(SLContext context, Source source) {
-        Parser parser = new Parser(context, source);
+    public static void parseSL(SLContext context, Source source, SLNodeProber astProber) {
+        Parser parser = new Parser(context, source, astProber);
         parser.Parse();
         if (parser.errors.errors.size() > 0) {
             StringBuilder msg = new StringBuilder("Error(s) parsing script:\n");
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Thu Jul 24 12:22:54 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Thu Jul 24 16:14:44 2014 -0700
@@ -30,6 +30,7 @@
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.runtime.*;
 
 // Checkstyle: stop
@@ -52,10 +53,10 @@
     public final Scanner scanner;
     public final Errors errors;
     private final SLNodeFactory factory;
-    
-    public Parser(SLContext context, Source source) {
+
+    public Parser(SLContext context, Source source, SLNodeProber astProber) {
         this.scanner = new Scanner(source.getInputStream());
-        this.factory = new SLNodeFactory(context, source);
+        this.factory = new SLNodeFactory(context, source, astProber);
         errors = new Errors();
     }
 
@@ -133,41 +134,41 @@
 	void Function() {
 		Expect(4);
 		Expect(1);
-		factory.startFunction(t); 
+		factory.startFunction(t);
 		Expect(5);
 		if (la.kind == 1) {
 			Get();
-			factory.addFormalParameter(t); 
+			factory.addFormalParameter(t);
 			while (la.kind == 6) {
 				Get();
 				Expect(1);
-				factory.addFormalParameter(t); 
+				factory.addFormalParameter(t);
 			}
 		}
 		Expect(7);
 		SLStatementNode body = Block(false);
-		factory.finishFunction(body); 
+		factory.finishFunction(body);
 	}
 
 	SLStatementNode  Block(boolean inLoop) {
 		SLStatementNode  result;
 		factory.startBlock();
-		List<SLStatementNode> body = new ArrayList<>(); 
+		List<SLStatementNode> body = new ArrayList<>();
 		Expect(8);
-		int lBracePos = t.charPos; 
+		int lBracePos = t.charPos;
 		while (StartOf(1)) {
 			SLStatementNode s = Statement(inLoop);
-			body.add(s); 
+			body.add(s);
 		}
 		Expect(9);
-		int length = (t.charPos + t.val.length()) - lBracePos; 
-		result = factory.finishBlock(body, lBracePos, length); 
+		int length = (t.charPos + t.val.length()) - lBracePos;
+		result = factory.finishBlock(body, lBracePos, length);
 		return result;
 	}
 
 	SLStatementNode  Statement(boolean inLoop) {
 		SLStatementNode  result;
-		result = null; 
+		result = null;
 		switch (la.kind) {
 		case 13: {
 			result = WhileStatement();
@@ -175,13 +176,13 @@
 		}
 		case 10: {
 			Get();
-			if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); } 
+			if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); }
 			Expect(11);
 			break;
 		}
 		case 12: {
 			Get();
-			if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); } 
+			if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); }
 			Expect(11);
 			break;
 		}
@@ -207,11 +208,11 @@
 		SLStatementNode  result;
 		Expect(13);
 		Expect(5);
-		Token whileToken = t; 
+		Token whileToken = t;
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode body = Block(true);
-		result = factory.createWhile(whileToken, condition, body); 
+		result = factory.createWhile(whileToken, condition, body);
 		return result;
 	}
 
@@ -219,16 +220,16 @@
 		SLStatementNode  result;
 		Expect(14);
 		Expect(5);
-		Token ifToken = t; 
+		Token ifToken = t;
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode thenPart = Block(inLoop);
-		SLStatementNode elsePart = null; 
+		SLStatementNode elsePart = null;
 		if (la.kind == 15) {
 			Get();
 			elsePart = Block(inLoop);
 		}
-		result = factory.createIf(ifToken, condition, thenPart, elsePart); 
+		result = factory.createIf(ifToken, condition, thenPart, elsePart);
 		return result;
 	}
 
@@ -236,11 +237,11 @@
 		SLStatementNode  result;
 		Expect(16);
 		Token returnToken = t;
-		SLExpressionNode value = null; 
+		SLExpressionNode value = null;
 		if (StartOf(2)) {
 			value = Expression();
 		}
-		result = factory.createReturn(returnToken, value); 
+		result = factory.createReturn(returnToken, value);
 		Expect(11);
 		return result;
 	}
@@ -250,9 +251,9 @@
 		result = LogicTerm();
 		while (la.kind == 17) {
 			Get();
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = LogicTerm();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -262,9 +263,9 @@
 		result = LogicFactor();
 		while (la.kind == 18) {
 			Get();
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = LogicFactor();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -299,9 +300,9 @@
 				break;
 			}
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Arithmetic();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -315,9 +316,9 @@
 			} else {
 				Get();
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Term();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -331,48 +332,48 @@
 			} else {
 				Get();
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Factor();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
 
 	SLExpressionNode  Factor() {
 		SLExpressionNode  result;
-		result = null; 
+		result = null;
 		if (la.kind == 1) {
 			Get();
-			Token nameToken = t; 
+			Token nameToken = t;
 			if (la.kind == 5) {
 				Get();
 				List<SLExpressionNode> parameters = new ArrayList<>();
-				SLExpressionNode parameter; 
+				SLExpressionNode parameter;
 				if (StartOf(2)) {
 					parameter = Expression();
-					parameters.add(parameter); 
+					parameters.add(parameter);
 					while (la.kind == 6) {
 						Get();
 						parameter = Expression();
-						parameters.add(parameter); 
+						parameters.add(parameter);
 					}
 				}
 				Expect(7);
-				Token finalToken = t; 
-				result = factory.createCall(nameToken, parameters, finalToken); 
+				Token finalToken = t;
+				result = factory.createCall(nameToken, parameters, finalToken);
 			} else if (la.kind == 29) {
 				Get();
 				SLExpressionNode value = Expression();
-				result = factory.createAssignment(nameToken, value); 
+				result = factory.createAssignment(nameToken, value);
 			} else if (StartOf(4)) {
-				result = factory.createRead(nameToken); 
+				result = factory.createRead(nameToken);
 			} else SynErr(32);
 		} else if (la.kind == 2) {
 			Get();
-			result = factory.createStringLiteral(t); 
+			result = factory.createStringLiteral(t);
 		} else if (la.kind == 3) {
 			Get();
-			result = factory.createNumericLiteral(t); 
+			result = factory.createNumericLiteral(t);
 		} else if (la.kind == 5) {
 			Get();
 			result = Expression();
@@ -401,8 +402,8 @@
 
     };
 
-    public static void parseSL(SLContext context, Source source) {
-        Parser parser = new Parser(context, source);
+    public static void parseSL(SLContext context, Source source, SLNodeProber astProber) {
+        Parser parser = new Parser(context, source, astProber);
         parser.Parse();
         if (parser.errors.errors.size() > 0) {
             StringBuilder msg = new StringBuilder("Error(s) parsing script:\n");
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Thu Jul 24 12:22:54 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Thu Jul 24 16:14:44 2014 -0700
@@ -32,6 +32,7 @@
 import com.oracle.truffle.sl.nodes.call.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
 import com.oracle.truffle.sl.nodes.expression.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.nodes.local.*;
 import com.oracle.truffle.sl.runtime.*;
 
@@ -72,9 +73,12 @@
     /* State while parsing a block. */
     private LexicalScope lexicalScope;
 
-    public SLNodeFactory(SLContext context, Source source) {
+    private final SLNodeProber prober;
+
+    public SLNodeFactory(SLContext context, Source source, SLNodeProber prober) {
         this.context = context;
         this.source = source;
+        this.prober = prober;
     }
 
     public void startFunction(Token nameToken) {
@@ -179,6 +183,14 @@
     public SLStatementNode createIf(Token t, SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) {
         final int start = t.charPos;
         final int end = elsePartNode == null ? thenPartNode.getSourceSection().getCharEndIndex() : elsePartNode.getSourceSection().getCharEndIndex();
+
+        // if (prober != null) {
+        // SLStatementNode wrappedThenNode = prober.probeAsStatement(thenPartNode);
+        // // SLStatementNode wrappedElseNode = prober.probeAsStatement(elsePartNode);
+        // return new SLIfNode(source.createSection(t.val, start, end - start), conditionNode,
+        // wrappedThenNode, elsePartNode);
+        // }
+
         return new SLIfNode(source.createSection(t.val, start, end - start), conditionNode, thenPartNode, elsePartNode);
     }
 
@@ -227,6 +239,10 @@
         final int endPos = finalToken.charPos + finalToken.val.length();
         final SourceSection src = source.createSection(nameToken.val, startPos, endPos - startPos);
         SLExpressionNode functionNode = createRead(nameToken);
+        if (prober != null) {
+            SLExpressionNode wrappedNode = prober.probeAsCall(functionNode, nameToken.val);
+            return SLInvokeNode.create(src, wrappedNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()]));
+        }
         return SLInvokeNode.create(src, functionNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()]));
     }
 
@@ -235,6 +251,10 @@
         lexicalScope.locals.put(nameToken.val, frameSlot);
         final int start = nameToken.charPos;
         final int length = valueNode.getSourceSection().getCharEndIndex() - start;
+        if (prober != null) {
+            final SLExpressionNode wrappedNode = prober.probeAsLocalAssignment(valueNode, nameToken.val);
+            return SLWriteLocalVariableNodeFactory.create(source.createSection("=", start, length), wrappedNode, frameSlot);
+        }
         return SLWriteLocalVariableNodeFactory.create(source.createSection("=", start, length), valueNode, frameSlot);
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu Jul 24 12:22:54 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu Jul 24 16:14:44 2014 -0700
@@ -29,8 +29,11 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.nodes.local.*;
 import com.oracle.truffle.sl.parser.*;
 
@@ -49,6 +52,7 @@
     private final PrintStream output;
     private final SLFunctionRegistry functionRegistry;
     private SourceCallback sourceCallback = null;
+    private SLASTProber astProber;
 
     public SLContext(BufferedReader input, PrintStream output) {
         this.input = input;
@@ -133,4 +137,28 @@
         /* Register the builtin function in our function registry. */
         getFunctionRegistry().register(name, rootNode);
     }
+
+    public void executeMain(Source source) {
+
+        if (sourceCallback != null) {
+            sourceCallback.startLoading(source);
+        }
+
+        Parser.parseSL(this, source, astProber);
+
+        if (sourceCallback != null) {
+            sourceCallback.endLoading(source);
+        }
+
+        SLFunction main = getFunctionRegistry().lookup("main");
+        if (main.getCallTarget() == null) {
+            throw new SLException("No function main() defined in SL source file.");
+        }
+        main.getCallTarget().call();
+    }
+
+    public void setASTNodeProber(SLASTProber astProber) {
+        // TODO Auto-generated method stub
+        this.astProber = astProber;
+    }
 }