# HG changeset patch # User Christian Humer # Date 1408453169 -7200 # Node ID 2270852ee1ef2205bb226faf2bc52eb0056ac8f4 # Parent fa5e6262059382c95ddfa4db75155681d18ae582# Parent 1051d6e4b61bc6ee701b55d6c4ee54c19056713a Merge. diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java --- 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) { diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java --- 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 diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Tue 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 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. * diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTNodeProber.java --- 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 instrumenting inserting a {@link Probe} at a Truffle AST - * node. + * Methods for inserting a {@link Probe} at a Truffle AST node. *

- * 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. *

* Disclaimer: experimental interface under development. Really! */ diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java --- 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. *

* WARNING: 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 */ diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ExecutionEvents.java --- 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}. *

* Disclaimer: experimental interface under development. */ diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java --- 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. - *

- * Disclaimer: experimental interface under development. In particular, the - * notify 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; } diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java --- 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 diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagged.java --- 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 (empty set if none). + * In which user-sensible categories has this node been tagged (empty set if none). */ Iterable getSyntaxTags(); diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java --- 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. - *

- * 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. *

* 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. *

- * 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. + *

+ * 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 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 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; diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java --- /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> 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 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. + *

+ * 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. + *

+ * 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 newProbeList = new ArrayList<>(2); + newProbeList.add(probe); + lineToProbesMap.put(line, newProbeList); + } else { + // Probe list exists, add to existing + final Collection 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 getProbesAtLine(LineLocation line) { + Collection probeList = lineToProbesMap.get(line); + + if (probeList == null) + probeList = new ArrayList<>(2); + + return probeList; + } +} diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java --- 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 srcToProbe = new HashMap<>(); - - // TODO (mlvdv) use weak references. - /** - * Map: Source line ==> probes associated with source sections starting on the line. - */ - private final Map> lineToProbes = new HashMap<>(); - private final List probeListeners = new ArrayList<>(); + private final List 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 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 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 findProbesTaggedAs(SyntaxTag tag) { final List 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 findProbesByLine(LineLocation lineLocation) { - final Collection 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); } diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java --- 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 diff -r fa5e62620593 -r 2270852ee1ef graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java --- 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 diff -r fa5e62620593 -r 2270852ee1ef mx/mx_graal.py --- 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)