changeset 16856:7833417c8172

Changes to Instrumentation
author David Piorkowski <david.piorkowski@oracle.com>
date Mon, 18 Aug 2014 14:36:12 -0700
parents 226552569e34
children 7bfbad29d331
files graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.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/ProbeManager.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/SLStatementWrapper.java
diffstat 9 files changed, 367 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java	Mon Aug 18 21:02:51 2014 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java	Mon Aug 18 14:36:12 2014 -0700
@@ -188,7 +188,7 @@
 
         public TestWrapper(RootNode child, ExecutionContext context) {
             this.child = insert(child);
-            this.probe = context.getProbe(child.getSourceSection());
+            this.probe = context.createProbe(child.getSourceSection());
         }
 
         public boolean isTaggedAs(SyntaxTag tag) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Mon Aug 18 21:02:51 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Mon Aug 18 14:36:12 2014 -0700
@@ -45,6 +45,9 @@
     protected ExecutionContext() {
     }
 
+    /**
+     * Sets up the {@link SourceCallback} for this execution context.
+     */
     public void initialize() {
         setSourceCallback(new SourceCallback() {
 
@@ -99,23 +102,13 @@
     }
 
     /**
-     * Return the (possibly newly created) {@link Probe} uniquely associated with a particular
-     * source code location. A newly created probe carries no tags.
+     * Return a newly created {@link Probe} uniquely associated with a particular source section. A
+     * newly created probe carries no tags.
      *
      * @return a probe uniquely associated with an extent of guest language source code.
      */
-    public final Probe getProbe(SourceSection sourceSection) {
-        return probeManager.getProbe(sourceSection);
-    }
-
-    /**
-     * Has a {@link Probe} been created that is uniquely associated with a particular source code
-     * location.
-     *
-     * @return a probe uniquely associated with an extent of guest language source code.
-     */
-    public final boolean hasProbe(SourceSection sourceSection) {
-        return probeManager.hasProbe(sourceSection);
+    public final Probe createProbe(SourceSection source) {
+        return probeManager.createProbe(source);
     }
 
     /**
@@ -127,14 +120,6 @@
     }
 
     /**
-     * Returns all existing probes with first character on a specified line; empty collection if no
-     * probes found.
-     */
-    public final Collection<Probe> findProbesByLine(LineLocation lineLocation) {
-        return probeManager.findProbesByLine(lineLocation);
-    }
-
-    /**
      * Sets a trap that will make a callback at any AST location where a existing probe holds a
      * specified tag; only one trap may be set at a time.
      *
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Mon Aug 18 21:02:51 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Mon Aug 18 14:36:12 2014 -0700
@@ -55,7 +55,10 @@
 public interface Probe extends ExecutionEvents, SyntaxTagged {
 
     /**
-     * The source location with which this probe is (presumably uniquely) associated.
+     * Get the {@link SourceSection} associated with this probe. This is no longer uniquely
+     * associated.
+     *
+     * @return The source associated with this probe.
      */
     SourceSection getSourceLocation();
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java	Mon Aug 18 21:02:51 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java	Mon Aug 18 14:36:12 2014 -0700
@@ -39,7 +39,7 @@
      * Notifies that a newly created (untagged) {@link Probe} has been inserted into a Truffle AST.
      * There will be no notification when an existing {@link Probe} is shared by an AST copy.
      */
-    void newProbeInserted(SourceSection location, Probe probe);
+    void newProbeInserted(SourceSection source, Probe probe);
 
     /**
      * Notifies that a (fully constructed) {@link Probe} has been tagged. A subsequent marking with
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Mon Aug 18 21:02:51 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Mon Aug 18 14:36:12 2014 -0700
@@ -35,6 +35,8 @@
 
 /**
  * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments.
+ * Instruments are represented as a chain using the next field. Each instrument chain is connected
+ * to a single probe.
  * <p>
  * Coordinates propagation of Truffle AST {@link ExecutionEvents}.
  */
@@ -44,18 +46,12 @@
         void newTagAdded(ProbeImpl probe, SyntaxTag tag);
     }
 
-    /**
-     * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection}
-     * extent of guest language source code.
-     *
-     * @return a new probe
-     */
-    static ProbeImpl createProbe(SourceSection sourceSection, ProbeCallback probeCallback) {
-        return new ProbeImpl(sourceSection, probeCallback);
+    static ProbeImpl createProbe(SourceSection source, ProbeCallback probeCallback) {
+        return new ProbeImpl(source, probeCallback);
     }
 
     /**
-     * Next in chain.
+     * Next instrumentation node in chain.
      */
     @Child protected InstrumentationNode next;
 
@@ -71,7 +67,7 @@
     }
 
     /**
-     * Add a probe to the end of this probe chain.
+     * Add an instrument to the end of this instrument chain.
      */
     private void internalAddInstrument(Instrument newInstrument) {
         if (next == null) {
@@ -81,6 +77,12 @@
         }
     }
 
+    /**
+     * Remove an instrument from this instrument chain. If no matching instrument is found, a
+     * {@link RuntimeException} is thrown.
+     *
+     * @param oldInstrument The {@link Instrument} to remove.
+     */
     private void internalRemoveInstrument(Instrument oldInstrument) {
         if (next == null) {
             throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument);
@@ -109,6 +111,14 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to has just been entered. This will
+     * continue to call {@link #internalEnter(Node, VirtualFrame)} to inform all instruments in the
+     * chain.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of entry
+     */
     protected void internalEnter(Node astNode, VirtualFrame frame) {
         enter(astNode, frame);
         if (next != null) {
@@ -116,6 +126,14 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalEnter(Node, VirtualFrame)} to inform all instruments in the
+     * chain. In this case, there is no return value.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame) {
         leave(astNode, frame);
         if (next != null) {
@@ -123,6 +141,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to has just been left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, boolean)} to inform all
+     * instruments in the chain. In this case, a boolean value was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The boolean result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, boolean result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -130,6 +157,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, byte)} to inform all instruments
+     * in the chain. In this case, a byte value was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The byte result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, byte result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -137,6 +173,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, short)} to inform all instruments
+     * in the chain. In this case, a short value was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The short result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, short result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -144,6 +189,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, int)} to inform all instruments in
+     * the chain. In this case, a int value was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The int result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, int result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -151,6 +205,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, long)} to inform all instruments
+     * in the chain. In this case, a long value was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The long result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, long result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -158,6 +221,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, char)} to inform all instruments
+     * in the chain. In this case, a char value was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The char result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, char result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -165,6 +237,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, float)} to inform all instruments
+     * in the chain. In this case, a float value was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The float result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, float result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -172,6 +253,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, double)} to inform all instruments
+     * in the chain. In this case, a double value was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The double result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, double result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -179,6 +269,15 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeave(Node, VirtualFrame, Object)} to inform all instruments
+     * in the chain. In this case, an Object was returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param result The Object result
+     */
     protected void internalLeave(Node astNode, VirtualFrame frame, Object result) {
         leave(astNode, frame, result);
         if (next != null) {
@@ -186,6 +285,16 @@
         }
     }
 
+    /**
+     * Inform the instrument that the AST node this is attached to is about to be left. This will
+     * continue to call {@link #internalLeaveExceptional(Node, VirtualFrame, Exception)} to inform
+     * all instruments in the chain. In this case, a exception (sometimes containing a value) was
+     * returned.
+     *
+     * @param astNode The {@link Node} that was entered
+     * @param frame The {@link VirtualFrame} at the time of exit
+     * @param e The exception
+     */
     protected void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
         leaveExceptional(astNode, frame, null);
         if (next != null) {
@@ -200,6 +309,11 @@
      * An instance is intended to be shared by every clone of the AST node with which it is
      * originally attached, so it holds no parent pointer.
      * <p>
+     * Each probe is associated with a {@link SourceSection} which was originally intended to be a
+     * unique id for the probe, but this is no longer true. Instead, it is the responsibility of the
+     * tool using to probes to track which probes they are interested in. One approach is to use the
+     * callback functionality in {@link ProbeManager}.
+     * <p>
      * May be categorized by one or more {@linkplain SyntaxTag tags}, signifying information useful
      * for instrumentation about its AST location(s).
      */
@@ -207,29 +321,48 @@
 
         private final ProbeCallback probeCallback;
 
-        /**
-         * Source information about the AST node (and its clones) to which this probe is attached.
-         */
-        private final SourceSection probedSourceSection;
-
         // TODO (mlvdv) assumption model broken
         @CompilerDirectives.CompilationFinal private Assumption probeUnchanged;
 
         @CompilerDirectives.CompilationFinal private SyntaxTagTrap trap = null;
 
+        /**
+         * The collection of tags for this instrumentation node
+         */
         private final ArrayList<SyntaxTag> tags = new ArrayList<>();
 
-        private ProbeImpl(SourceSection sourceSection, ProbeCallback probeCallback) {
+        /**
+         * The wrapper that this probe belongs to.
+         */
+        private final SourceSection source;
+
+        /**
+         * Constructor.
+         *
+         * @param source The {@link SourceSection} associated with this probe.
+         * @param probeCallback The {@link ProbeCallback} to inform when tags have been added to
+         *            this probe.
+         */
+        private ProbeImpl(SourceSection source, ProbeCallback probeCallback) {
             this.probeCallback = probeCallback;
-            this.probedSourceSection = sourceSection;
+            this.source = source;
             this.probeUnchanged = Truffle.getRuntime().createAssumption();
             this.next = null;
         }
 
+        /**
+         * Returns the {@link SourceSection} associated with this probe.
+         */
         public SourceSection getSourceLocation() {
-            return probedSourceSection;
+            return source;
         }
 
+        /**
+         * Tags this probe with the given {@link SyntaxTag}. If the tag already exists, the tag is
+         * not added.
+         *
+         * @param tag The tag to add to this probe.
+         */
         @SlowPath
         public void tagAs(SyntaxTag tag) {
             assert tag != null;
@@ -239,15 +372,32 @@
             }
         }
 
+        /**
+         * Checks if this probe has been tagged with the given tag.
+         *
+         * @param tag The {@link SyntaxTag} to check for.
+         * @return True if this probe has the given tag, false otherwise.
+         */
         public boolean isTaggedAs(SyntaxTag tag) {
             assert tag != null;
             return tags.contains(tag);
         }
 
+        /**
+         * Returns an iterable collection of all syntax tags on this probe.
+         *
+         * @return A collection of {@link SyntaxTag}s.
+         */
         public Iterable<SyntaxTag> getSyntaxTags() {
             return tags;
         }
 
+        /**
+         * Adds the given {@link Instrument} to this probe's chain of instruments. This method does
+         * not check to see if the same instrument has already been added.
+         *
+         * @param instrument The instrument to add to this probe.
+         */
         @SlowPath
         public void addInstrument(Instrument instrument) {
             probeUnchanged.invalidate();
@@ -255,6 +405,12 @@
             probeUnchanged = Truffle.getRuntime().createAssumption();
         }
 
+        /**
+         * Removes the given instrument from the chain of instruments. If no matching instrument is
+         * found, a {@link RuntimeException} is thrown.
+         *
+         * @param instrument The instrument to remove from this probe.
+         */
         @SlowPath
         public void removeInstrument(Instrument instrument) {
             probeUnchanged.invalidate();
@@ -262,6 +418,9 @@
             probeUnchanged = Truffle.getRuntime().createAssumption();
         }
 
+        /**
+         * Returns this probe.
+         */
         @Override
         protected Probe getProbe() {
             return this;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java	Mon Aug 18 14:36:12 2014 -0700
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument.impl;
+
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * This class maintains a mapping from {@link LineLocation} to a collection of {@link Probe}s to be
+ * used by debugging tools.
+ *
+ */
+public class LineLocationToProbeCollectionMap implements ProbeListener {
+    /**
+     * Map: Source line ==> probes associated with source sections starting on the line.
+     */
+    private final Map<LineLocation, Collection<Probe>> lineToProbesMap = new HashMap<>();
+
+    public LineLocationToProbeCollectionMap() {
+    }
+
+    /**
+     * Adds the current wrapper's child's line location and probe to this map.
+     */
+    public void newProbeInserted(SourceSection source, Probe probe) {
+        final LineLocation line = source.getLineLocation();
+        this.addProbeToLine(line, probe);
+    }
+
+    /**
+     * Does nothing.
+     */
+    public void probeTaggedAs(Probe probe, SyntaxTag tag) {
+
+    }
+
+    /**
+     * Returns the {@link Probe}, if any, associated with source that starts on a specified line; if
+     * there are more than one, return the one with the first character location.
+     */
+    public Probe findLineProbe(LineLocation lineLocation) {
+        Probe probe = null;
+        final Collection<Probe> probes = getProbesAtLine(lineLocation);
+        for (Probe probeOnLine : probes) {
+            if (probe == null) {
+                probe = probeOnLine;
+            } else if (probeOnLine.getSourceLocation().getCharIndex() < probe.getSourceLocation().getCharIndex()) {
+                probe = probeOnLine;
+            }
+        }
+        return probe;
+    }
+
+    /**
+     * Adds a probe to the given line.
+     * <p>
+     * If the line already exists in the internal {@link #lineToProbesMap}, this probe 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 probe.
+     * <p>
+     * This class requires that each added line/probe pair hasn't been previously added. However,
+     * attaching the same probe to a new line location is allowed.
+     *
+     * @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) {
+
+        if (!lineToProbesMap.containsKey(line)) {
+            // Key does not exist, add new probe list
+            final ArrayList<Probe> newProbeList = new ArrayList<>(2);
+            newProbeList.add(probe);
+            lineToProbesMap.put(line, newProbeList);
+        } else {
+            // Probe list exists, add to existing
+            final Collection<Probe> existingProbeList = lineToProbesMap.get(line);
+            assert !existingProbeList.contains(probe);
+            existingProbeList.add(probe);
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * @param line The line to check.
+     * @return A iterable collection of probes at the given line.
+     */
+    private Collection<Probe> getProbesAtLine(LineLocation line) {
+        Collection<Probe> probeList = lineToProbesMap.get(line);
+
+        if (probeList == null)
+            probeList = new ArrayList<>(2);
+
+        return probeList;
+    }
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java	Mon Aug 18 21:02:51 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java	Mon Aug 18 14:36:12 2014 -0700
@@ -36,20 +36,20 @@
  */
 public final class ProbeManager {
 
-    // TODO (mlvdv) use weak references.
     /**
-     * Map: SourceSection ==> probe associated with that source section in an AST.
+     * The collection of {@link ProbeListener}s to call.
      */
-    private final Map<SourceSection, ProbeImpl> srcToProbe = new HashMap<>();
-
-    // TODO (mlvdv) use weak references.
-    /**
-     * Map: Source line ==> probes associated with source sections starting on the line.
-     */
-    private final Map<LineLocation, Collection<Probe>> lineToProbes = new HashMap<>();
-
     private final List<ProbeListener> probeListeners = new ArrayList<>();
 
+    /**
+     * The collection of all probes added.
+     */
+    private final List<ProbeImpl> probeList = new ArrayList<>();
+
+    /**
+     * The callback to be triggered by the {@link #tagTrap}.
+     *
+     */
     private final ProbeCallback probeCallback;
 
     /**
@@ -74,11 +74,21 @@
         };
     }
 
+    /**
+     * Add a {@link ProbeListener} to receive events.
+     *
+     * @param listener The listener to be added.
+     */
     public void addProbeListener(ProbeListener listener) {
         assert listener != null;
         probeListeners.add(listener);
     }
 
+    /**
+     * Remove a {@link ProbeListener}. If no matching probe listener is found, nothing happens.
+     *
+     * @param removeListener
+     */
     public void removeProbeListener(ProbeListener removeListener) {
         final List<ProbeListener> listeners = new ArrayList<>(probeListeners);
         for (ProbeListener listener : listeners) {
@@ -88,45 +98,36 @@
         }
     }
 
-    public Probe getProbe(SourceSection sourceSection) {
-        assert sourceSection != null;
-
-        ProbeImpl probe = srcToProbe.get(sourceSection);
-
-        if (probe != null) {
-            return probe;
-        }
-        probe = InstrumentationNode.createProbe(sourceSection, probeCallback);
+    /**
+     * Creates a {@link Probe} for the given {@link SourceSection} and informs all
+     * {@link ProbeListener}s stored in this manager of its creation.
+     *
+     * @param source The source section to associate with this probe.
+     * @return The probe that was created.
+     */
+    public Probe createProbe(SourceSection source) {
+        assert source != null;
 
-        // Register new probe by unique SourceSection
-        srcToProbe.put(sourceSection, probe);
-
-        // Register new probe by source line, there may be more than one
-        // Create line location for map key
-        final LineLocation lineLocation = sourceSection.getLineLocation();
-
-        Collection<Probe> probes = lineToProbes.get(lineLocation);
-        if (probes == null) {
-            probes = new ArrayList<>(2);
-            lineToProbes.put(lineLocation, probes);
-        }
-        probes.add(probe);
+        ProbeImpl probe = InstrumentationNode.createProbe(source, probeCallback);
+        probeList.add(probe);
 
         for (ProbeListener listener : probeListeners) {
-            listener.newProbeInserted(sourceSection, probe);
+            listener.newProbeInserted(source, probe);
         }
 
         return probe;
     }
 
-    public boolean hasProbe(SourceSection sourceSection) {
-        assert sourceSection != null;
-        return srcToProbe.get(sourceSection) != null;
-    }
-
+    /**
+     * Returns a collection of {@link Probe}s created by this manager that have the given
+     * {@link SyntaxTag}.
+     *
+     * @param tag The tag to search for.
+     * @return An iterable collection of probes containing the given tag.
+     */
     public Collection<Probe> findProbesTaggedAs(SyntaxTag tag) {
         final List<Probe> probes = new ArrayList<>();
-        for (Probe probe : srcToProbe.values()) {
+        for (Probe probe : probeList) {
             if (tag == null || probe.isTaggedAs(tag)) {
                 probes.add(probe);
             }
@@ -134,14 +135,14 @@
         return probes;
     }
 
-    public Collection<Probe> findProbesByLine(LineLocation lineLocation) {
-        final Collection<Probe> probes = lineToProbes.get(lineLocation);
-        if (probes == null) {
-            return Collections.emptyList();
-        }
-        return new ArrayList<>(probes);
-    }
-
+    /**
+     * Calls {@link ProbeImpl#setTrap(SyntaxTagTrap)} for all probes with the given
+     * {@link SyntaxTag} . There can only be one tag trap set at a time. An
+     * {@link IllegalStateException} is thrown if this is called and a tag trap has already been
+     * set.
+     *
+     * @param tagTrap The {@link SyntaxTagTrap} to set.
+     */
     public void setTagTrap(SyntaxTagTrap tagTrap) {
         assert tagTrap != null;
         if (this.tagTrap != null) {
@@ -150,18 +151,22 @@
         this.tagTrap = tagTrap;
 
         SyntaxTag tag = tagTrap.getTag();
-        for (ProbeImpl probe : srcToProbe.values()) {
+        for (ProbeImpl probe : probeList) {
             if (probe.isTaggedAs(tag)) {
                 probe.setTrap(tagTrap);
             }
         }
     }
 
+    /**
+     * Clears the current {@link SyntaxTagTrap}. If no trap has been set, an
+     * {@link IllegalStateException} is thrown.
+     */
     public void clearTagTrap() {
         if (this.tagTrap == null) {
             throw new IllegalStateException("no trap set");
         }
-        for (ProbeImpl probe : srcToProbe.values()) {
+        for (ProbeImpl probe : probeList) {
             if (probe.isTaggedAs(tagTrap.getTag())) {
                 probe.setTrap(null);
             }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Mon Aug 18 21:02:51 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Mon Aug 18 14:36:12 2014 -0700
@@ -50,7 +50,7 @@
         super(child.getSourceSection());
         assert !(child instanceof SLExpressionWrapper);
         this.child = insert(child);
-        this.probe = context.getProbe(child.getSourceSection());
+        this.probe = context.createProbe(child.getSourceSection());
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Mon Aug 18 21:02:51 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Mon Aug 18 14:36:12 2014 -0700
@@ -49,7 +49,7 @@
         super(child.getSourceSection());
         assert !(child instanceof SLStatementWrapper);
         this.child = insert(child);
-        this.probe = context.getProbe(child.getSourceSection());
+        this.probe = context.createProbe(child.getSourceSection());
     }
 
     @Override