changeset 16861:2270852ee1ef

Merge.
author Christian Humer <christian.humer@gmail.com>
date Tue, 19 Aug 2014 14:59:29 +0200
parents fa5e62620593 (current diff) 1051d6e4b61b (diff)
children bf499b4d86e9
files
diffstat 15 files changed, 403 insertions(+), 126 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java	Tue Aug 19 14:59:29 2014 +0200
@@ -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/CallTarget.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java	Tue Aug 19 14:59:29 2014 +0200
@@ -30,7 +30,7 @@
 public interface CallTarget {
 
     /**
-     * Calls this target as a root method..
+     * Calls this target as a root method.
      *
      * @param arguments passed arguments as an object array
      * @return the return result of the call
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Tue Aug 19 14:59:29 2014 +0200
@@ -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, untagged, {@link Probe} associated with a particular source section,
+     * with no requirement that the association be unique.
      *
-     * @return a probe uniquely associated with an extent of guest language source code.
+     * @return a probe 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/ASTNodeProber.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTNodeProber.java	Tue Aug 19 14:59:29 2014 +0200
@@ -27,11 +27,10 @@
 import com.oracle.truffle.api.nodes.*;
 
 /**
- * Implementation of a policy for <em>instrumenting</em> inserting a {@link Probe} at a Truffle AST
- * node.
+ * Methods for inserting a {@link Probe} at a Truffle AST node.
  * <p>
- * Note that this interface is guest language agnostic, but current extensions are
- * language-specific. This will be revisited.
+ * This interface is guest language agnostic, but current extensions are language-specific. This
+ * will be revisited.
  * <p>
  * <strong>Disclaimer:</strong> experimental interface under development. Really!
  */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java	Tue Aug 19 14:59:29 2014 +0200
@@ -29,7 +29,8 @@
 import com.oracle.truffle.api.nodes.*;
 
 /**
- * Language-agnostic access to AST-based debugging support.
+ * Access to AST-based debugging support, which is could be language implementation specific in the
+ * details chosen to be presented.
  * <p>
  * <strong>WARNING:</strong> this interface is under development and will change substantially.
  */
@@ -37,7 +38,7 @@
 
     /**
      * Prints a textual AST display, one line per node, with nesting.
-     * 
+     *
      * @param p
      * @param node the root node of the display.
      * @param maxDepth the maximum number of levels to print below the root
@@ -47,7 +48,7 @@
 
     /**
      * Creates a textual AST display, one line per node, with nesting.
-     * 
+     *
      * @param node the root node of the display.
      * @param maxDepth the maximum number of levels to print below the root
      * @param markNode a node to mark with a textual arrow prefix, if present.
@@ -56,7 +57,7 @@
 
     /**
      * Creates a textual AST display, one line per node, with nesting.
-     * 
+     *
      * @param node the root node of the display.
      * @param maxDepth the maximum number of levels to print below the root
      */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ExecutionEvents.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ExecutionEvents.java	Tue Aug 19 14:59:29 2014 +0200
@@ -28,8 +28,9 @@
 import com.oracle.truffle.api.nodes.*;
 
 /**
- * Normal events during program execution at Truffle AST nodes that are reported via a {@link Probe}
- * associated with the node, and made available to the probe's attached {@link Instrument}s.
+ * Normal events at each Truffle AST {@link Node} that occur during guest language execution, and
+ * which the {@link Probe} associated with that node, if any, reports to every {@link Instrument}
+ * attached to the {@link Probe}.
  * <p>
  * <strong>Disclaimer:</strong> experimental interface under development.
  */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Tue Aug 19 14:59:29 2014 +0200
@@ -45,9 +45,6 @@
  * attached instruments seldom changes. The assumption is invalidated when instruments are added or
  * removed, but some instruments may change their internal state in such a way that the assumption
  * should also be invalidated.
- * <p>
- * <strong>Disclaimer:</strong> experimental interface under development. In particular, the
- * <em>notify</em> methods must be migrated to another interface.
  *
  * @see Instrument
  * @see Wrapper
@@ -55,24 +52,34 @@
 public interface Probe extends ExecutionEvents, SyntaxTagged {
 
     /**
-     * The source location with which this probe is (presumably uniquely) associated.
+     * Get the {@link SourceSection} in some Truffle AST associated with this probe.
+     *
+     * @return The source associated with this probe.
      */
     SourceSection getSourceLocation();
 
     /**
-     * Mark this probe as being associated with an AST node in some category useful for debugging
-     * and other tools.
+     * Mark this probe as belonging to some tool-related category that can be used to guide tool
+     * behavior at an associated AST node. For example, a debugger might add the tag
+     * {@link StandardSyntaxTag#STATEMENT} as a way of configuring where execution should stop when
+     * stepping.
      */
     void tagAs(SyntaxTag tag);
 
     /**
-     * Adds an instrument to this probe.
+     * Adds an {@link Instrument} to this probe's collection. No check is made to see if the same
+     * instrument has already been added.
+     *
+     * @param newInstrument The instrument to add to this probe.
      */
     void addInstrument(Instrument newInstrument);
 
     /**
-     * Removes an instrument from this probe.
+     * Removes the given instrument from the probe's collection.
+     *
+     * @param oldInstrument The instrument to remove from this probe.
+     * @throws RuntimeException if no matching instrument has been attached.
      */
-    void removeInstrument(Instrument oldInstrument);
+    void removeInstrument(Instrument oldInstrument) throws RuntimeException;
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java	Tue Aug 19 14:59:29 2014 +0200
@@ -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/SyntaxTagged.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagged.java	Tue Aug 19 14:59:29 2014 +0200
@@ -36,12 +36,13 @@
 public interface SyntaxTagged {
 
     /**
-     * Is this node tagged as belonging to a particular category of language constructs?
+     * Is this node tagged as belonging to a particular human-sensible category of language
+     * constructs?
      */
     boolean isTaggedAs(SyntaxTag tag);
 
     /**
-     * In which categories has this node been tagged (<em>empty set</em> if none).
+     * In which user-sensible categories has this node been tagged (<em>empty set</em> if none).
      */
     Iterable<SyntaxTag> getSyntaxTags();
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Tue Aug 19 14:59:29 2014 +0200
@@ -34,9 +34,9 @@
 import com.oracle.truffle.api.source.*;
 
 /**
- * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments.
- * <p>
- * Coordinates propagation of Truffle AST {@link ExecutionEvents}.
+ * Abstract implementation of Truffle {@link Node}s used as AST {@link Probe}s and
+ * {@link Instrument}s. A {@link Probe} manages its attached {@link Instrument}s by appending them
+ * to a chain through which {@link ExecutionEvents} are propagated.
  */
 public abstract class InstrumentationNode extends Node implements ExecutionEvents {
 
@@ -44,18 +44,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 +65,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 +75,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 +109,14 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution is just about to enter an AST node with which this
+     * instrumentation node is associated. 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 +124,15 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +140,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +174,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +191,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +208,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +225,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +242,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +259,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +276,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 +293,16 @@
         }
     }
 
+    /**
+     * Informs the instrument that execution has just returned from an AST node with which this
+     * instrumentation node is associated. 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 thrown.
+     *
+     * @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) {
@@ -195,41 +312,66 @@
 
     /**
      * Holder of a chain of {@linkplain InstrumentationNode instruments}: manages the
-     * {@link Assumption} that none of the instruments have changed since last checked.
+     * {@link Assumption} that no {@link Instrument}s have been added or removed and that none of
+     * the attached instruments have changed state in a way that would require deopt.
      * <p>
      * 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>
-     * May be categorized by one or more {@linkplain SyntaxTag tags}, signifying information useful
-     * for instrumentation about its AST location(s).
+     * Each probe is associated with a {@link SourceSection}, not necessarily uniquely, although
+     * such a policy could be enforced for some uses.
+     * <p>
+     * Each {@link Probe} be categorized by one or more {@linkplain SyntaxTag tags}, signifying
+     * information useful for instrumentation about its AST location(s).
      */
     static final class ProbeImpl extends InstrumentationNode implements Probe {
 
         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 region of source code associated with this probe. Note that this is distinct from
+         * {@link Node#getSourceSection()}, which is {@code null} for all instances of
+         * {@link InstrumentationNode} since they have no corresponding source of their own.
+         */
+        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 +381,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 +414,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 +427,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	Tue Aug 19 14:59:29 2014 +0200
@@ -0,0 +1,114 @@
+/*
+ * 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.*;
+
+/**
+ * A mapping from {@link LineLocation} (a line number in a specific piece of {@link Source} code) to
+ * a collection of {@link Probe}s whose associated {@link SourceSection} starts on that line.
+ */
+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() {
+    }
+
+    public void newProbeInserted(SourceSection source, Probe probe) {
+        final LineLocation line = source.getLineLocation();
+        this.addProbeToLine(line, probe);
+    }
+
+    public void probeTaggedAs(Probe probe, SyntaxTag tag) {
+        // This map ignores tags
+    }
+
+    /**
+     * 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 starting 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	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java	Tue Aug 19 14:59:29 2014 +0200
@@ -36,20 +36,17 @@
  */
 public final class ProbeManager {
 
-    // TODO (mlvdv) use weak references.
-    /**
-     * Map: SourceSection ==> probe associated with that source section in an AST.
-     */
-    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<>();
 
+    private final List<ProbeImpl> allProbes = new ArrayList<>();
+
+    /**
+     * Called when a {@link #tagTrap} is activated in a Probe.
+     */
+    /**
+     * The callback to be triggered by the {@link #tagTrap}.
+     *
+     */
     private final ProbeCallback probeCallback;
 
     /**
@@ -74,11 +71,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 +95,35 @@
         }
     }
 
-    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 new {@link Probe} associated with a {@link SourceSection} of code corresponding to
+     * a Trufle AST node.
+     *
+     * @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);
+        allProbes.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 the subset of all {@link Probe}s holding a particular {@link SyntaxTag}, or the whole
+     * collection if the specified tag is {@code null}.
+     *
+     * @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 : allProbes) {
             if (tag == null || probe.isTaggedAs(tag)) {
                 probes.add(probe);
             }
@@ -134,15 +131,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);
-    }
-
-    public void setTagTrap(SyntaxTagTrap tagTrap) {
+    /**
+     * Calls {@link ProbeImpl#setTrap(SyntaxTagTrap)} for all probes with the given
+     * {@link SyntaxTag} . There can only be one tag trap set at a time.
+     *
+     * @param tagTrap The {@link SyntaxTagTrap} to set.
+     * @throws IllegalStateException if a trap is currently set.
+     */
+    public void setTagTrap(SyntaxTagTrap tagTrap) throws IllegalStateException {
         assert tagTrap != null;
         if (this.tagTrap != null) {
             throw new IllegalStateException("trap already set");
@@ -150,18 +146,23 @@
         this.tagTrap = tagTrap;
 
         SyntaxTag tag = tagTrap.getTag();
-        for (ProbeImpl probe : srcToProbe.values()) {
+        for (ProbeImpl probe : allProbes) {
             if (probe.isTaggedAs(tag)) {
                 probe.setTrap(tagTrap);
             }
         }
     }
 
+    /**
+     * Clears the current {@link SyntaxTagTrap}.
+     *
+     * @throws IllegalStateException if no trap is currently set.
+     */
     public void clearTagTrap() {
         if (this.tagTrap == null) {
             throw new IllegalStateException("no trap set");
         }
-        for (ProbeImpl probe : srcToProbe.values()) {
+        for (ProbeImpl probe : allProbes) {
             if (probe.isTaggedAs(tagTrap.getTag())) {
                 probe.setTrap(null);
             }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Tue Aug 19 14:59:29 2014 +0200
@@ -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	Tue Aug 19 14:56:19 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Tue Aug 19 14:59:29 2014 +0200
@@ -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
--- a/mx/mx_graal.py	Tue Aug 19 14:56:19 2014 +0200
+++ b/mx/mx_graal.py	Tue Aug 19 14:59:29 2014 +0200
@@ -556,7 +556,7 @@
         if not os.path.islink(dstLib) or not os.path.realpath(dstLib) == src:
             if exists(dstLib):
                 os.remove(dstLib)
-                os.symlink(src, dstLib)
+            os.symlink(src, dstLib)
     else:
         # do a copy and then a move to get atomic updating (on Unix)
         fd, tmp = tempfile.mkstemp(suffix='', prefix=name, dir=dst)