changeset 16880:7661cc464239

Truffle/Instrumentation: Added Instrumentable interface and LineLocationToSourceSections map SL: Updated implementation to use new Instrumentable interface
author David Piorkowski <david.piorkowski@oracle.com>
date Thu, 21 Aug 2014 13:28:22 -0700
parents 7af9301efe6b
children f0e3b50c29c8
files graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumentable.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToSourceSectionCollectionMap.java graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLCheckVariableEqualityInstrument.java graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestNodeProber.java graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.output graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.sl graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_varCompare.output graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_varCompare.sl 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/SLExpressionNode.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/SLASTProber.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/SLInstrumenter.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 24 files changed, 432 insertions(+), 581 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/instrument/Instrumentable.java	Thu Aug 21 13:28:22 2014 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 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.instrument;
+
+import com.oracle.truffle.api.*;
+
+public interface Instrumentable {
+
+    /**
+     * Optionally applies <em>instrumentation</em> at a Truffle AST node, depending on guest
+     * language characteristics and use-case policy. Ideally, the parent node of the guest language
+     * implements this interface.
+     * <ul>
+     * <li>if no instrumentation is to be applied, returns the AST node unmodified;</li>
+     * <li>if an AST node is to be instrumented, then creates a new Wrapper that <em>decorates</em>
+     * the AST node. Additionally, this creates a probe on the wrapper that is to be used for
+     * attaching instruments. This {@link Probe} is notified of all {@link ExecutionEvents} at the
+     * wrapped AST node.</li>
+     * </ul>
+     *
+     * @param context The {@link ExecutionContext} of the guest language used to create probes on
+     *            the wrapper.
+     * @return The probe that was created.
+     */
+    public Probe probe(ExecutionContext context);
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java	Thu Aug 21 13:28:22 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 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
@@ -43,8 +43,8 @@
     }
 
     public void newProbeInserted(SourceSection source, Probe probe) {
-        final LineLocation line = source.getLineLocation();
-        this.addProbeToLine(line, probe);
+        if (source != null && !(source instanceof NullSourceSection))
+            this.addProbeToLine(source.getLineLocation(), probe);
     }
 
     public void probeTaggedAs(Probe probe, SyntaxTag tag) {
@@ -81,7 +81,7 @@
      * @param line The {@link LineLocation} to attach the probe to.
      * @param probe The {@link Probe} to attach for that line location.
      */
-    private void addProbeToLine(LineLocation line, Probe probe) {
+    protected void addProbeToLine(LineLocation line, Probe probe) {
 
         if (!lineToProbesMap.containsKey(line)) {
             // Key does not exist, add new probe list
@@ -98,17 +98,36 @@
 
     /**
      * Returns a collection of {@link Probe}s at the given {@link LineLocation}. If there are no
-     * probes at that line, an empty list is returned.
+     * probes at that line, a new empty list of size 1 is returned.
      *
      * @param line The line to check.
      * @return A iterable collection of probes at the given line.
      */
-    private Collection<Probe> getProbesAtLine(LineLocation line) {
+    public Collection<Probe> getProbesAtLine(LineLocation line) {
         Collection<Probe> probeList = lineToProbesMap.get(line);
 
         if (probeList == null)
-            probeList = new ArrayList<>(2);
+            probeList = new ArrayList<>(1);
 
         return probeList;
     }
+
+    /**
+     * Convenience method to get probes according to a int line number. Returns a collection of
+     * {@link Probe}s at the given line number. If there are no probes at that line, a new empty
+     * list is returned.
+     *
+     * @param lineNumber The line number to check.
+     * @return A iterable collection of probes at the given line.
+     */
+    public Collection<Probe> getProbesAtLineNumber(int lineNumber) {
+        ArrayList<Probe> probes = new ArrayList<>();
+
+        for (LineLocation line : lineToProbesMap.keySet()) {
+            if (line.getLineNumber() == lineNumber)
+                probes.addAll(lineToProbesMap.get(line));
+        }
+
+        return probes;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToSourceSectionCollectionMap.java	Thu Aug 21 13:28:22 2014 -0700
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 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.instrument.impl;
+
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * A mapping from {@link LineLocation} (a line number in a specific piece of {@link Source} code) to
+ * a collection of {@link SourceSection}s that exist on that line. This class assumes that all nodes
+ * are instrumented as it uses the {@link ProbeListener} interface to determine the source sections
+ * that exist in the file.
+ */
+public class LineLocationToSourceSectionCollectionMap implements ProbeListener {
+
+    /**
+     * Map: Source line ==> source sections that exist on the line.
+     */
+    private final Map<LineLocation, Collection<SourceSection>> lineToSourceSectionsMap = new HashMap<>();
+
+    public LineLocationToSourceSectionCollectionMap() {
+
+    }
+
+    public void newProbeInserted(SourceSection sourceSection, Probe probe) {
+        if (sourceSection != null && !(sourceSection instanceof NullSourceSection)) {
+            this.addSourceSectionToLine(sourceSection.getLineLocation(), sourceSection);
+        }
+    }
+
+    public void probeTaggedAs(Probe probe, SyntaxTag tag) {
+        // This map ignores tags, but this subclasses can override this method to operate on tags.
+    }
+
+    /**
+     * Adds a source section to the given line.
+     * <p>
+     * If the line already exists in the internal {@link #lineToSourceSectionsMap}, this source
+     * section will be added to the existing collection. If no line already exists in the internal
+     * map, then a new key is added along with a new collection containing the source section.
+     * <p>
+     * This class does not check if a source section has already been added to a line.
+     *
+     * @param line The {@link LineLocation} to attach the source section to.
+     * @param sourceSection The {@link SourceSection} to attach for that line location.
+     */
+    protected void addSourceSectionToLine(LineLocation line, SourceSection sourceSection) {
+        if (!lineToSourceSectionsMap.containsKey(line)) {
+            // Key does not exist, add new source section list
+            final ArrayList<SourceSection> newSourceSectionList = new ArrayList<>(2);
+            newSourceSectionList.add(sourceSection);
+            lineToSourceSectionsMap.put(line, newSourceSectionList);
+        } else {
+            // Source section list exists, add to existing
+            final Collection<SourceSection> existingSourceSectionList = lineToSourceSectionsMap.get(line);
+            existingSourceSectionList.add(sourceSection);
+        }
+    }
+
+    /**
+     * Returns a collection of {@link SourceSection}s at the given {@link LineLocation}. If there
+     * are no source sections at that line, a new empty list of size 1 is returned.
+     *
+     * @param line The line to check.
+     * @return A iterable collection of source sections at the given line.
+     */
+    public Collection<SourceSection> getSourceSectionsAtLine(LineLocation line) {
+        Collection<SourceSection> sourceSectionList = lineToSourceSectionsMap.get(line);
+
+        if (sourceSectionList == null)
+            sourceSectionList = new ArrayList<>(1);
+
+        return sourceSectionList;
+    }
+
+    /**
+     * Convenience method to get source sections according to a int line number. Returns a
+     * collection of {@link SourceSection}s at the given line number. If there are no source
+     * sections at that line, a new empty list is returned.
+     *
+     * @param lineNumber The line number to check.
+     * @return A iterable collection of source sections at the given line.
+     */
+    public Collection<SourceSection> getSourceSectionsAtLineNumber(int lineNumber) {
+        ArrayList<SourceSection> sourceSections = new ArrayList<>();
+
+        for (LineLocation line : lineToSourceSectionsMap.keySet()) {
+            if (line.getLineNumber() == lineNumber)
+                sourceSections.addAll(lineToSourceSectionsMap.get(line));
+        }
+
+        return sourceSections;
+    }
+}
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLCheckVariableEqualityInstrument.java	Tue Aug 19 19:25:44 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 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.test.instrument;
-
-import java.io.*;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.sl.nodes.controlflow.*;
-import com.oracle.truffle.sl.runtime.*;
-
-/**
- * This sample instrument provides an example of a naive way to check if two numbers in SL are
- * equivalent using their variable names. This instrument is designed to be attached to an
- * {@link SLReturnNode}, but provides no guards ensuring this.
- */
-public class SLCheckVariableEqualityInstrument extends Instrument {
-
-    private final String varName1;
-    private final String varName2;
-    private final PrintStream output;
-
-    /**
-     * Constructor
-     *
-     * @param varName1 The name of the first variable to compare
-     * @param varName2 The name of the second variable to compare
-     * @param output The {@link PrintStream} from the context used to print results. See
-     *            {@link SLContext#getOutput()} for more info.
-     */
-    public SLCheckVariableEqualityInstrument(String varName1, String varName2, PrintStream output) {
-        this.varName1 = varName1;
-        this.varName2 = varName2;
-        this.output = output;
-    }
-
-    /**
-     * In the instrumentation test, this instrument is attached to a return statement. Since returns
-     * are handled via exceptions in Simple, we need to override the leaveExceptional method. This
-     * method does very limited error checking and simply prints "true" if the passed-in variables
-     * match or "false" if they do not.
-     */
-    @Override
-    public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-        FrameSlot f1 = frame.getFrameDescriptor().findFrameSlot(varName1);
-        FrameSlot f2 = frame.getFrameDescriptor().findFrameSlot(varName2);
-
-        if (f1 == null || f2 == null)
-            output.println("false");
-        else {
-            try {
-                output.println(frame.getLong(f1) == frame.getLong(f2));
-            } catch (FrameSlotTypeException e1) {
-                e1.printStackTrace();
-            }
-        }
-
-    }
-}
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestNodeProber.java	Tue Aug 19 19:25:44 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 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.test.instrument;
-
-import static com.oracle.truffle.api.instrument.StandardSyntaxTag.*;
-
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.sl.nodes.*;
-import com.oracle.truffle.sl.nodes.controlflow.*;
-import com.oracle.truffle.sl.nodes.instrument.*;
-import com.oracle.truffle.sl.nodes.local.*;
-import com.oracle.truffle.sl.runtime.*;
-
-/**
- * This sample AST Node Prober for simple is used to instrument the nodes that we are interested in
- * testing. This prober wraps return nodes and assignment nodes. For the purposes of this example,
- * this is appropriate, but ideally there would be only one node prober responsible for
- * instrumenting all the nodes of interest instead of a selective one like this one.
- *
- */
-public final class SLInstrumentTestNodeProber implements SLNodeProber {
-    private final SLContext slContext;
-
-    public SLInstrumentTestNodeProber(SLContext slContext) {
-        this.slContext = slContext;
-    }
-
-    /**
-     * Not implemented, only returns the astNode that was passed in.
-     */
-    public Node probeAs(Node astNode, SyntaxTag tag, Object... args) {
-        // TODO dp: Currently does nothing in the general case
-        return astNode;
-    }
-
-    /**
-     * If the passed in node is a {@link SLStatementWrapper}, then this simply tags it as a
-     * statement. If the passed in node is a {@link SLReturnNode}, then it is instrumented and
-     * tagged as a statement for testing. Only SLReturnNodes are wrapped.
-     */
-    public SLStatementNode probeAsStatement(SLStatementNode node) {
-        assert node != null;
-
-        SLStatementWrapper wrapper = null;
-        if (node instanceof SLStatementWrapper) {
-            wrapper = (SLStatementWrapper) node;
-            wrapper.tagAs(STATEMENT);
-            return wrapper;
-        } else if (node instanceof SLReturnNode) {
-            wrapper = new SLStatementWrapper(slContext, node);
-            wrapper.tagAs(STATEMENT);
-            return wrapper;
-        }
-        return node;
-    }
-
-    /**
-     * Not implemented. Returns the passed in node.
-     */
-    public SLExpressionNode probeAsCall(SLExpressionNode node, String callName) {
-        return node;
-    }
-
-    /**
-     * If the passed in node is a {@link SLExpressionWrapper}, then this simply tags it as an
-     * assignment. If the passed in node is a {@link SLWriteLocalVariableNode}, then it is
-     * instrumented and tagged as a assignment for testing. Only SLWriteLocalVariableNode are
-     * wrapped.
-     */
-    public SLExpressionNode probeAsLocalAssignment(SLExpressionNode node, String localName) {
-        assert node != null;
-
-        SLExpressionWrapper wrapper = null;
-        if (node instanceof SLExpressionWrapper) {
-            wrapper = (SLExpressionWrapper) node;
-            wrapper.tagAs(ASSIGNMENT);
-            return wrapper;
-        } else if (node instanceof SLWriteLocalVariableNode) {
-            wrapper = new SLExpressionWrapper(slContext, node);
-            wrapper.tagAs(ASSIGNMENT);
-            return wrapper;
-        }
-        return node;
-    }
-
-}
\ No newline at end of file
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu Aug 21 13:28:22 2014 -0700
@@ -37,12 +37,11 @@
 import org.junit.runners.model.*;
 
 import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.parser.*;
 import com.oracle.truffle.sl.runtime.*;
-import com.oracle.truffle.sl.test.*;
 import com.oracle.truffle.sl.test.instrument.SLInstrumentTestRunner.InstrumentTestCase;
 
 /**
@@ -58,8 +57,7 @@
     private static final String SOURCE_SUFFIX = ".sl";
     private static final String INPUT_SUFFIX = ".input";
     private static final String OUTPUT_SUFFIX = ".output";
-    private static final String VISITOR_ASSIGNMENT_COUNT_SUFFIX = "_assnCount";
-    private static final String VISITOR_VARIABLE_COMPARE_SUFFIX = "_varCompare";
+    private static final String ASSIGNMENT_VALUE_SUFFIX = "_assnCount";
 
     private static final String LF = System.getProperty("line.separator");
     private static SLContext slContext;
@@ -128,7 +126,8 @@
     protected static List<InstrumentTestCase> createTests(final Class<?> c) throws IOException, InitializationError {
         SLInstrumentTestSuite suite = c.getAnnotation(SLInstrumentTestSuite.class);
         if (suite == null) {
-            throw new InitializationError(String.format("@%s annotation required on class '%s' to run with '%s'.", SLTestSuite.class.getSimpleName(), c.getName(), SLTestRunner.class.getSimpleName()));
+            throw new InitializationError(String.format("@%s annotation required on class '%s' to run with '%s'.", SLInstrumentTestSuite.class.getSimpleName(), c.getName(),
+                            SLInstrumentTestRunner.class.getSimpleName()));
         }
 
         String[] paths = suite.value();
@@ -200,57 +199,29 @@
         PrintStream printer = new PrintStream(out);
         try {
             // We use the name of the file to determine what visitor to attach to it.
-            if (testCase.baseName.endsWith(VISITOR_ASSIGNMENT_COUNT_SUFFIX) || testCase.baseName.endsWith(VISITOR_VARIABLE_COMPARE_SUFFIX)) {
-                NodeVisitor nodeVisitor = null;
+            if (testCase.baseName.endsWith(ASSIGNMENT_VALUE_SUFFIX)) {
+                // Set up the execution context for Simple and register our two listeners
                 slContext = new SLContext(new BufferedReader(new StringReader(testCase.testInput)), printer);
-                final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName);
-                SLASTProber prober = new SLASTProber();
-
-                // Note that the visitor looks for an attachment point via line number
-                if (testCase.baseName.endsWith(VISITOR_ASSIGNMENT_COUNT_SUFFIX)) {
-                    nodeVisitor = new NodeVisitor() {
-
-                        public boolean visit(Node node) {
-                            if (node instanceof SLExpressionWrapper) {
-                                SLExpressionWrapper wrapper = (SLExpressionWrapper) node;
-                                int lineNum = wrapper.getSourceSection().getLineLocation().getLineNumber();
 
-                                if (lineNum == 4) {
-                                    wrapper.getProbe().addInstrument(new SLPrintAssigmentValueInstrument(slContext.getOutput()));
-                                }
-                            }
-                            return true;
-                        }
-                    };
-
-                    // Note that the visitor looks for an attachment point via line number
-                } else if (testCase.baseName.endsWith(VISITOR_VARIABLE_COMPARE_SUFFIX)) {
-                    nodeVisitor = new NodeVisitor() {
-
-                        public boolean visit(Node node) {
-                            if (node instanceof SLStatementWrapper) {
-                                SLStatementWrapper wrapper = (SLStatementWrapper) node;
-                                int lineNum = wrapper.getSourceSection().getLineLocation().getLineNumber();
-
-                                if (lineNum == 6) {
-                                    wrapper.getProbe().addInstrument(new SLCheckVariableEqualityInstrument("i", "count", slContext.getOutput()));
-                                }
-                            }
-                            return true;
-                        }
-                    };
-                }
-
-                prober.addNodeProber(new SLInstrumentTestNodeProber(slContext));
-                Parser.parseSL(slContext, source, prober);
+                final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName);
+                Parser.parseSL(slContext, source);
                 List<SLFunction> functionList = slContext.getFunctionRegistry().getFunctions();
 
                 // Since only functions can be global in SL, this guarantees that we instrument
                 // everything of interest. Parsing must occur before accepting the visitors since
-                // parsing is what creates our instrumentation points.
+                // the visitor which creates our instrumentation points expects a complete AST.
+
                 for (SLFunction function : functionList) {
                     RootCallTarget rootCallTarget = function.getCallTarget();
-                    rootCallTarget.getRootNode().accept(nodeVisitor);
+                    rootCallTarget.getRootNode().accept(new SLInstrumenter(slContext));
+                }
+
+                // We iterate over all tags the SLInsturmenter tagged as assignments and attach our
+                // test instrument to those.
+                for (Probe probe : slContext.findProbesTaggedAs(StandardSyntaxTag.ASSIGNMENT)) {
+                    if (probe.isTaggedAs(StandardSyntaxTag.ASSIGNMENT)) {
+                        probe.addInstrument(new SLPrintAssigmentValueInstrument(printer));
+                    }
                 }
 
                 SLFunction main = slContext.getFunctionRegistry().lookup("main");
@@ -272,7 +243,7 @@
     public static void runInMain(Class<?> testClass, String[] args) throws InitializationError, NoTestsRemainException {
         JUnitCore core = new JUnitCore();
         core.addListener(new TextListener(System.out));
-        SLTestRunner suite = new SLTestRunner(testClass);
+        SLInstrumentTestRunner suite = new SLInstrumentTestRunner(testClass);
         if (args.length > 0) {
             suite.filter(new NameFilter(args[0]));
         }
--- a/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.output	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.output	Thu Aug 21 13:28:22 2014 -0700
@@ -1,3 +1,5 @@
+100
+0
 1
 2
 3
--- a/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.sl	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.sl	Thu Aug 21 13:28:22 2014 -0700
@@ -8,5 +8,4 @@
 
 function main() {
   count = loop(100);
-  println(count);
 }
--- a/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_varCompare.output	Tue Aug 19 19:25:44 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-true
-100
--- a/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_varCompare.sl	Tue Aug 19 19:25:44 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-function loop(count) {  
-  i = 0;  
-  while (i < count) {  
-    i = i + 1;  
-  }  
-  return i;  
-}
-
-function main() {
-  count = loop(100);
-  println(count);
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Thu Aug 21 13:28:22 2014 -0700
@@ -152,7 +152,7 @@
         if (sourceCallback != null) {
             sourceCallback.startLoading(source);
         }
-        Parser.parseSL(context, source, null);
+        Parser.parseSL(context, source);
         if (sourceCallback != null) {
             sourceCallback.endLoading(source);
         }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Thu Aug 21 13:28:22 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, null);
+        Parser.parseSL(context, source);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Thu Aug 21 13:28:22 2014 -0700
@@ -29,8 +29,6 @@
 
 public final class SLContextFactory {
 
-    private static SLASTProber astProber;
-
     private SLContextFactory() {
 
     }
@@ -39,12 +37,6 @@
         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/SLExpressionNode.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Thu Aug 21 13:28:22 2014 -0700
@@ -24,10 +24,13 @@
 
 import java.math.*;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 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.nodes.instrument.*;
 import com.oracle.truffle.sl.runtime.*;
 
 /**
@@ -87,4 +90,20 @@
     public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException {
         return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame));
     }
+
+    @Override
+    public Probe probe(ExecutionContext context) {
+        Node parent = getParent();
+
+        if (parent == null)
+            throw new IllegalStateException("Cannot probe a node without a parent");
+
+        if (parent instanceof SLExpressionWrapper)
+            return ((SLExpressionWrapper) parent).getProbe();
+
+        SLExpressionWrapper wrapper = new SLExpressionWrapper((SLContext) context, this);
+        this.replace(wrapper);
+        wrapper.insertChild();
+        return wrapper.getProbe();
+    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Thu Aug 21 13:28:22 2014 -0700
@@ -22,9 +22,13 @@
  */
 package com.oracle.truffle.sl.nodes;
 
+import com.oracle.truffle.api.*;
 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.nodes.instrument.*;
+import com.oracle.truffle.sl.runtime.*;
 
 /**
  * The base class of all Truffle nodes for SL. All nodes (even expressions) can be used as
@@ -32,7 +36,7 @@
  * local variables.
  */
 @NodeInfo(language = "Simple Language", description = "The abstract base node for all statements")
-public abstract class SLStatementNode extends Node {
+public abstract class SLStatementNode extends Node implements Instrumentable {
 
     public SLStatementNode(SourceSection src) {
         super(src);
@@ -46,4 +50,20 @@
     public SLStatementNode getNonWrapperNode() {
         return this;
     }
+
+    @Override
+    public Probe probe(ExecutionContext context) {
+        Node parent = getParent();
+
+        if (parent == null)
+            throw new IllegalStateException("Cannot probe a node without a parent");
+
+        if (parent instanceof SLStatementWrapper)
+            return ((SLStatementWrapper) parent).getProbe();
+
+        SLStatementWrapper wrapper = new SLStatementWrapper((SLContext) context, this);
+        this.replace(wrapper);
+        wrapper.insertChild();
+        return wrapper.getProbe();
+    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTProber.java	Tue Aug 19 19:25:44 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * 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;
-    }
-
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Thu Aug 21 13:28:22 2014 -0700
@@ -46,11 +46,19 @@
 
     private final Probe probe;
 
+    /**
+     * Constructor.
+     *
+     * @param context The current Simple execution context
+     * @param child The {@link SLExpressionNode} that this wrapper is wrapping
+     */
     public SLExpressionWrapper(SLContext context, SLExpressionNode child) {
         super(child.getSourceSection());
         assert !(child instanceof SLExpressionWrapper);
-        this.child = insert(child);
         this.probe = context.createProbe(child.getSourceSection());
+        this.child = child;
+        // The child should only be inserted after a replace, so we defer inserting the child to the
+        // creator of the wrapper.
     }
 
     @Override
@@ -145,4 +153,11 @@
     public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException {
         return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame));
     }
+
+    /**
+     * Sets the parent pointer of this wrapper's child.
+     */
+    public void insertChild() {
+        insert(this.child);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLInstrumenter.java	Thu Aug 21 13:28:22 2014 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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 static com.oracle.truffle.api.instrument.StandardSyntaxTag.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.controlflow.*;
+import com.oracle.truffle.sl.nodes.local.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * This is a general purpose visitor which traverses a completely parsed Simple AST and instruments
+ * all the nodes within it. This visitor is designed to visit the tree immediately after it has been
+ * parsed.
+ *
+ */
+public class SLInstrumenter implements NodeVisitor {
+
+    private final SLContext context;
+
+    public SLInstrumenter(SLContext context) {
+        this.context = context;
+    }
+
+    /**
+     * Instruments and tags all relevant {@link SLStatementNode}s and {@link SLExpressionNode}s.
+     * Currently, only SLStatementNodes that are not SLExpressionNodes are tagged as statements.
+     */
+    public boolean visit(Node node) {
+        // We have to distinguish between SLExpressionNode and SLStatementNode since some of the
+        // generated factories have methods that require SLExpressionNodes as parameters. Since
+        // SLExpressionNodes are a subclass of SLStatementNode, we check if something is an
+        // SLExpressionNode first.
+        if (node instanceof SLExpressionNode && node.getParent() != null) {
+            SLExpressionNode expressionNode = (SLExpressionNode) node;
+            Probe probe = expressionNode.probe(context);
+            // probe.tagAs(STATEMENT);
+
+            if (node instanceof SLWriteLocalVariableNode)
+                probe.tagAs(ASSIGNMENT);
+
+        } else if (node instanceof SLStatementNode && node.getParent() != null) {
+
+            SLStatementNode statementNode = (SLStatementNode) node;
+            Probe probe = statementNode.probe(context);
+            probe.tagAs(STATEMENT);
+
+            if (node instanceof SLWhileNode)
+                probe.tagAs(START_LOOP);
+        }
+
+        return true;
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLNodeProber.java	Tue Aug 19 19:25:44 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * 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);
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Thu Aug 21 13:28:22 2014 -0700
@@ -48,8 +48,10 @@
     public SLStatementWrapper(SLContext context, SLStatementNode child) {
         super(child.getSourceSection());
         assert !(child instanceof SLStatementWrapper);
-        this.child = insert(child);
         this.probe = context.createProbe(child.getSourceSection());
+        this.child = child;
+        // The child should only be inserted after a replace, so we defer inserting the child to the
+        // creator of the wrapper.
     }
 
     @Override
@@ -94,6 +96,12 @@
             probe.leaveExceptional(child, frame, e);
             throw (e);
         }
+    }
 
+    /**
+     * Sets the parent pointer of this wrapper's child.
+     */
+    public void insertChild() {
+        insert(this.child);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Thu Aug 21 13:28:22 2014 -0700
@@ -33,7 +33,6 @@
 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,9 +51,9 @@
     public final Errors errors;
     private final SLNodeFactory factory;
     -->declarations
-    public Parser(SLContext context, Source source, SLNodeProber astProber) {
+    public Parser(SLContext context, Source source) {
         this.scanner = new Scanner(source.getInputStream());
-        this.factory = new SLNodeFactory(context, source, astProber);
+        this.factory = new SLNodeFactory(context, source);
         errors = new Errors();
     }
 
@@ -135,8 +134,8 @@
 -->initialization
     };
 
-    public static void parseSL(SLContext context, Source source, SLNodeProber astProber) {
-        Parser parser = new Parser(context, source, astProber);
+    public static void parseSL(SLContext context, Source source) {
+        Parser parser = new Parser(context, source);
         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	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Thu Aug 21 13:28:22 2014 -0700
@@ -30,7 +30,6 @@
 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
@@ -53,10 +52,10 @@
     public final Scanner scanner;
     public final Errors errors;
     private final SLNodeFactory factory;
-    
-    public Parser(SLContext context, Source source, SLNodeProber astProber) {
+
+    public Parser(SLContext context, Source source) {
         this.scanner = new Scanner(source.getInputStream());
-        this.factory = new SLNodeFactory(context, source, astProber);
+        this.factory = new SLNodeFactory(context, source);
         errors = new Errors();
     }
 
@@ -134,43 +133,43 @@
 	void Function() {
 		Expect(4);
 		Expect(1);
-		Token identifierToken = t; 
+		Token identifierToken = t;
 		Expect(5);
-		int bodyStartPos = t.charPos; 
-		factory.startFunction(identifierToken, bodyStartPos); 
+		int bodyStartPos = t.charPos;
+		factory.startFunction(identifierToken, bodyStartPos);
 		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 start = t.charPos; 
+		int start = t.charPos;
 		while (StartOf(1)) {
 			SLStatementNode s = Statement(inLoop);
-			body.add(s); 
+			body.add(s);
 		}
 		Expect(9);
-		int length = (t.charPos + t.val.length()) - start; 
-		result = factory.finishBlock(body, start, length); 
+		int length = (t.charPos + t.val.length()) - start;
+		result = factory.finishBlock(body, start, length);
 		return result;
 	}
 
 	SLStatementNode  Statement(boolean inLoop) {
 		SLStatementNode  result;
-		result = null; 
+		result = null;
 		switch (la.kind) {
 		case 13: {
 			result = WhileStatement();
@@ -178,13 +177,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;
 		}
@@ -209,29 +208,29 @@
 	SLStatementNode  WhileStatement() {
 		SLStatementNode  result;
 		Expect(13);
-		Token whileToken = t; 
+		Token whileToken = t;
 		Expect(5);
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode body = Block(true);
-		result = factory.createWhile(whileToken, condition, body); 
+		result = factory.createWhile(whileToken, condition, body);
 		return result;
 	}
 
 	SLStatementNode  IfStatement(boolean inLoop) {
 		SLStatementNode  result;
 		Expect(14);
-		Token ifToken = t; 
+		Token ifToken = t;
 		Expect(5);
 		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;
 	}
 
@@ -239,11 +238,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;
 	}
@@ -253,9 +252,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;
 	}
@@ -265,9 +264,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;
 	}
@@ -302,9 +301,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;
 	}
@@ -318,9 +317,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;
 	}
@@ -334,56 +333,56 @@
 			} 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();
-			int start = t.charPos; 
+			int start = t.charPos;
 			result = Expression();
-			SLExpressionNode expr = result; 
+			SLExpressionNode expr = result;
 			Expect(7);
-			int length = (t.charPos + t.val.length()) - start; 
-			result = factory.createParenExpression(expr, start, length); 
+			int length = (t.charPos + t.val.length()) - start;
+			result = factory.createParenExpression(expr, start, length);
 		} else SynErr(33);
 		return result;
 	}
@@ -408,8 +407,8 @@
 
     };
 
-    public static void parseSL(SLContext context, Source source, SLNodeProber astProber) {
-        Parser parser = new Parser(context, source, astProber);
+    public static void parseSL(SLContext context, Source source) {
+        Parser parser = new Parser(context, source);
         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	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Thu Aug 21 13:28:22 2014 -0700
@@ -32,7 +32,6 @@
 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.*;
 
@@ -75,12 +74,9 @@
     /* State while parsing a block. */
     private LexicalScope lexicalScope;
 
-    private final SLNodeProber prober;
-
-    public SLNodeFactory(SLContext context, Source source, SLNodeProber prober) {
+    public SLNodeFactory(SLContext context, Source source) {
         this.context = context;
         this.source = source;
-        this.prober = prober;
     }
 
     public void startFunction(Token nameToken, int bodyStartPos) {
@@ -156,114 +152,69 @@
     }
 
     /**
-     * Returns a {@link SLBreakNode} for the given token. This node will be instrumented, tagged as
-     * a statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was
-     * initialized in this class. ({@link #prober} != null)
+     * Returns an {@link SLBreakNode} for the given token.
      *
-     * @param breakToken The token containing the break node's info
-     * @return either:
-     *         <ul>
-     *         <li>An un-instrumented SLBreakNode if there is no prober</li>
-     *         <li>An {@link SLStatementWrapper} instrumenting this node.</li>
-     *         </ul>
+     * @param breakToken The token containing the break node's info.
+     * @return A SLBreakNode for the given token.
      */
     public SLStatementNode createBreak(Token breakToken) {
         final SLBreakNode breakNode = new SLBreakNode(srcFromToken(breakToken));
-        if (prober != null) {
-            return prober.probeAsStatement(breakNode);
-        }
         return breakNode;
     }
 
     /**
-     * Returns a {@link SLContinueNode} for the given token. This node will be instrumented, tagged
-     * as a statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was
-     * initialized in this class. ({@link #prober} != null)
+     * Returns an {@link SLContinueNode} for the given token.
      *
-     * @param continueToken The token containing the continue node's info
-     * @return either:
-     *         <ul>
-     *         <li>An un-instrumented SLContinueNode if there is no prober</li>
-     *         <li>An {@link SLStatementWrapper} instrumenting this node.</li>
-     *         </ul>
+     * @param continueToken The token containing the continue node's info.
+     * @return A SLContinueNode built using the given token.
      */
     public SLStatementNode createContinue(Token continueToken) {
         final SLContinueNode continueNode = new SLContinueNode(srcFromToken(continueToken));
-        if (prober != null) {
-            return prober.probeAsStatement(continueNode);
-        }
         return continueNode;
     }
 
     /**
-     * Returns a {@link SLWhileNode} for the given token. This node will be instrumented, tagged as
-     * a statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was
-     * initialized in this class. ({@link #prober} != null)
+     * Returns an {@link SLWhileNode} for the given parameters.
      *
      * @param whileToken The token containing the while node's info
      * @param conditionNode The conditional node for this while loop
      * @param bodyNode The body of the while loop
-     * @return either:
-     *         <ul>
-     *         <li>An un-instrumented SLWhileNode if there is no prober</li>
-     *         <li>An {@link SLStatementWrapper} instrumenting this node.</li>
-     *         </ul>
+     * @return A SLWhileNode built using the given parameters.
      */
     public SLStatementNode createWhile(Token whileToken, SLExpressionNode conditionNode, SLStatementNode bodyNode) {
         final int start = whileToken.charPos;
         final int end = bodyNode.getSourceSection().getCharEndIndex();
         final SLWhileNode whileNode = new SLWhileNode(source.createSection(whileToken.val, start, end - start), conditionNode, bodyNode);
-        if (prober != null) {
-            return prober.probeAsStatement(whileNode);
-        }
         return whileNode;
     }
 
     /**
-     * Returns a {@link SLIfNode} for the given token. This node will be instrumented, tagged as a
-     * statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was
-     * initialized in this class. ({@link #prober} != null)
+     * Returns an {@link SLIfNode} for the given parameters.
      *
      * @param ifToken The token containing the if node's info
      * @param conditionNode The condition node of this if statement
      * @param thenPartNode The then part of the if
      * @param elsePartNode The else part of the if
-     * @return either:
-     *         <ul>
-     *         <li>An un-instrumented SLIfNode if there is no prober</li>
-     *         <li>An {@link SLStatementWrapper} instrumenting this node.</li>
-     *         </ul>
+     * @return An SLIfNode for the given parameters.
      */
     public SLStatementNode createIf(Token ifToken, SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) {
         final int start = ifToken.charPos;
         final int end = elsePartNode == null ? thenPartNode.getSourceSection().getCharEndIndex() : elsePartNode.getSourceSection().getCharEndIndex();
         final SLIfNode ifNode = new SLIfNode(source.createSection(ifToken.val, start, end - start), conditionNode, thenPartNode, elsePartNode);
-        if (prober != null) {
-            return prober.probeAsStatement(ifNode);
-        }
         return ifNode;
     }
 
     /**
-     * Returns a {@link SLReturnNode} for the given token. This node will be instrumented, tagged as
-     * a statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was
-     * initialized in this class. ({@link #prober} != null)
+     * Returns an {@link SLReturnNode} for the given parameters.
      *
      * @param t The token containing the return node's info
      * @param valueNode The value of the return
-     * @return either:
-     *         <ul>
-     *         <li>An un-instrumented SLReturnNode if there is no prober</li>
-     *         <li>An {@link SLStatementWrapper} instrumenting this node.</li>
-     *         </ul>
+     * @return An SLReturnNode for the given parameters.
      */
     public SLStatementNode createReturn(Token t, SLExpressionNode valueNode) {
         final int start = t.charPos;
         final int length = valueNode == null ? t.val.length() : valueNode.getSourceSection().getCharEndIndex() - start;
         final SLReturnNode returnNode = new SLReturnNode(source.createSection(t.val, start, length), valueNode);
-        if (prober != null) {
-            return prober.probeAsStatement(returnNode);
-        }
         return returnNode;
     }
 
@@ -274,7 +225,7 @@
      * @param opToken The operator of the binary expression
      * @param leftNode The left node of the expression
      * @param rightNode The right node of the expression
-     * @return A subclass of SLExpressionNode for the operation given by opToken.
+     * @return A subclass of SLExpressionNode using the given parameters based on the given opToken.
      */
     public SLExpressionNode createBinary(Token opToken, SLExpressionNode leftNode, SLExpressionNode rightNode) {
         int start = leftNode.getSourceSection().getCharIndex();
@@ -311,54 +262,33 @@
     }
 
     /**
-     * Returns a {@link SLInvokeNode} for the given token. This node will be instrumented, tagged as
-     * a call and wrapped in an {@link SLExpressionWrapper} if an {@link SLASTProber} was
-     * initialized in this class. ({@link #prober} != null)
+     * Returns an {@link SLInvokeNode} for the given parameters.
      *
      * @param nameToken The name of the function being called
      * @param parameterNodes The parameters of the function call
      * @param finalToken A token used to determine the end of the sourceSelection for this call
-     * @return either:
-     *         <ul>
-     *         <li>An un-instrumented SLInvokeNode if there is no prober</li>
-     *         <li>An {@link SLExpressionWrapper} instrumenting this node.</li>
-     *         </ul>
+     * @return An SLInvokeNode for the given parameters.
      */
     public SLExpressionNode createCall(Token nameToken, List<SLExpressionNode> parameterNodes, Token finalToken) {
         final int startPos = nameToken.charPos;
         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()]));
     }
 
     /**
-     * Returns a {@link SLWriteLocalVariableNode} for the given token. This node will be
-     * instrumented, tagged as an assignment and wrapped in an {@link SLExpressionWrapper} if an
-     * {@link SLASTProber} was initialized in this class. ({@link #prober} != null)
+     * Returns an {@link SLWriteLocalVariableNode} for the given parameters.
      *
      * @param nameToken The name of the variable being assigned
      * @param valueNode The value to be assigned
-     * @return either:
-     *         <ul>
-     *         <li>An un-instrumented SLWriteLocalVariableNode if there is no prober</li>
-     *         <li>An {@link SLExpressionWrapper} instrumenting this node.</li>
-     *         </ul>
+     * @return An SLExpressionNode for the given parameters.
      */
     public SLExpressionNode createAssignment(Token nameToken, SLExpressionNode valueNode) {
         FrameSlot frameSlot = frameDescriptor.findOrAddFrameSlot(nameToken.val);
         lexicalScope.locals.put(nameToken.val, frameSlot);
         final int start = nameToken.charPos;
         final int length = valueNode.getSourceSection().getCharEndIndex() - start;
-        if (prober != null) {
-            SLWriteLocalVariableNode writeNode = SLWriteLocalVariableNodeFactory.create(source.createSection("=", start, length), valueNode, frameSlot);
-            final SLExpressionNode wrappedNode = prober.probeAsLocalAssignment(writeNode, nameToken.val);
-            return wrappedNode;
-        }
         return SLWriteLocalVariableNodeFactory.create(source.createSection("=", start, length), valueNode, frameSlot);
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Tue Aug 19 19:25:44 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu Aug 21 13:28:22 2014 -0700
@@ -33,7 +33,6 @@
 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.*;
 
@@ -52,7 +51,6 @@
     private final PrintStream output;
     private final SLFunctionRegistry functionRegistry;
     private SourceCallback sourceCallback = null;
-    private SLASTProber astProber;
 
     public SLContext(BufferedReader input, PrintStream output) {
         this.input = input;
@@ -154,7 +152,7 @@
             sourceCallback.startLoading(source);
         }
 
-        Parser.parseSL(this, source, astProber);
+        Parser.parseSL(this, source);
 
         if (sourceCallback != null) {
             sourceCallback.endLoading(source);
@@ -166,13 +164,4 @@
         }
         main.getCallTarget().call();
     }
-
-    /**
-     * Sets the {@link SLASTProber} for the executeMain method.
-     *
-     * @param astProber The prober to use for adding instrumentation for this context.
-     */
-    public void setASTNodeProber(SLASTProber astProber) {
-        this.astProber = astProber;
-    }
 }