# HG changeset patch # User Michael Van De Vanter # Date 1400544876 25200 # Node ID 8c34e2cc4add5e203601764f1a226066540202cb # Parent dcaf3993ad175bc2e6b4440886099ddd9fe3c333 Truffle/Instrumentation: significant reorganization of the instrumentation framework's implementation and connection to the runtime ExecutionContext, with some new features, including a Tag-based "trap" mechanisms. diff -r dcaf3993ad17 -r 8c34e2cc4add 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 May 13 18:31:18 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Mon May 19 17:14:36 2014 -0700 @@ -27,31 +27,131 @@ import java.util.*; import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.instrument.impl.*; import com.oracle.truffle.api.source.*; /** * Access to information and basic services in the runtime context for a Truffle-implemented guest * language. *

- * Disclaimer: this interface is under development and will change. + * Disclaimer: this class is under development and will change. */ -public interface ExecutionContext { +public abstract class ExecutionContext { + + private final ProbeManager probeManager = new ProbeManager(); + private final SourceManager sourceManager = new SourceManager(); + private final List sourceListeners = new ArrayList<>(); + private Visualizer visualizer = new DefaultVisualizer(); + + protected ExecutionContext() { + } + + public void initialize() { + setSourceCallback(new SourceCallback() { + + public void startLoading(Source source) { + for (SourceListener listener : sourceListeners) { + listener.loadStarting(source); + } + } + + public void endLoading(Source source) { + for (SourceListener listener : sourceListeners) { + listener.loadEnding(source); + } + } + }); + } + + /** + * Gets access to source management services. + */ + public final SourceManager getSourceManager() { + return sourceManager; + } + + /** + * Registers a tool interested in being notified about the loading of {@link Source}s. + */ + public final void addSourceListener(SourceListener listener) { + assert listener != null; + sourceListeners.add(listener); + } + + /** + * Registers a tool interested in being notified about the insertion of a newly created + * {@link Probe} into a Truffle AST. + */ + public final void addProbeListener(ProbeListener listener) { + probeManager.addProbeListener(listener); + } + + /** + * Return the (possibly newly created) {@link Probe} uniquely associated with a particular + * source code location. 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); + } + + /** + * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty + * collection if no probes found. + */ + public final Collection findProbesTaggedAs(PhylumTag tag) { + return probeManager.findProbesTaggedAs(tag); + } + + /** + * Returns all existing probes with first character on a specified line; empty collection if no + * probes found. + */ + public final Collection findProbesByLine(SourceLineLocation 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. + * + * @throws IllegalStateException if a trap is already set + */ + public final void setPhylumTrap(PhylumTrap trap) throws IllegalStateException { + // TODO (mlvdv) consider allowing multiple traps (without inhibiting Truffle inlining) + probeManager.setPhylumTrap(trap); + } + + /** + * Clears a trap that will halt execution; only one trap may be set at a time. + * + * @throws IllegalStateException if no trap is set. + */ + public final void clearPhylumTrap() { + probeManager.clearPhylumTrap(); + } + + /** + * Access to information visualization services for the specific language. + */ + public final Visualizer getVisualizer() { + return visualizer; + } + + /** + * Assign guest language-specific visualization support for tools. This must be assigned outside + * the implementation context to avoid build circularities. + */ + public final void setVisualizer(Visualizer visualizer) { + this.visualizer = visualizer; + } /** * Gets the name of the language, possibly with version number. in short enough form that it * might be used for an interactive prompt. */ - String getLanguageShortName(); - - /** - * Gets access to source management services. - */ - SourceManager getSourceManager(); - - /** - * Registers a tool interested in being notified of events related to the loading of sources. - */ - void addSourceListener(SourceListener listener); + public abstract String getLanguageShortName(); /** * Add instrumentation to subsequently constructed Truffle ASTs for the guest language; every @@ -60,51 +160,19 @@ * @throws IllegalStateException if AST instrumentation not enabled * @throws IllegalArgumentException if prober not usable for the guest language implementation. */ - void addNodeProber(ASTNodeProber nodeProber) throws IllegalStateException, IllegalArgumentException; - - /** - * Registers a tool interested in being notified about the insertion of a newly created - * {@link Probe} into a Truffle AST. - */ - void addProbeListener(ProbeListener listener); - - /** - * Return the (possibly newly created) {@link Probe} uniquely associated with a particular - * source code location. A newly created probe carries no tags. - * - * @return a probe uniquely associated with an extent of guest language source code. - */ - Probe getProbe(SourceSection sourceSection); - - /** - * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty - * collection if no probes found. - */ - Collection findProbesTaggedAs(PhylumTag tag); + public abstract void addNodeProber(ASTNodeProber nodeProber) throws IllegalStateException, IllegalArgumentException; /** - * Returns all existing probes with first character on a specified line; empty collection if no - * probes found. + * Assigns a guest language-specific manager for using {@link ASTNodeProber}s added by tools to + * instrument ASTs with {@link Probe}s at specified nodes. This must be assigned outside the + * implementation context to avoid build circularities. It must also be set before any + * instrumentation probe implementations are assigned. */ - Collection findProbesByLine(SourceLineLocation lineLocation); + public abstract void setASTProber(ASTProber astProber); /** - * 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. - * - * @throws IllegalStateException if a trap is already set + * Establishes source event reporting */ - void setTrap(PhylumTrap trap) throws IllegalStateException; + protected abstract void setSourceCallback(SourceCallback sourceCallback); - /** - * Clears a trap that will halt execution; only one trap may be set at a time. - * - * @throws IllegalStateException if no trap is set. - */ - void clearTrap() throws IllegalStateException; - - /** - * Access to information visualization services for the specific language. - */ - Visualizer getVisualizer(); } diff -r dcaf3993ad17 -r 8c34e2cc4add graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java Tue May 13 18:31:18 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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.impl; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.instrument.impl.*; -import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeCallback; -import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeImpl; -import com.oracle.truffle.api.source.*; - -public abstract class AbstractExecutionContext implements ExecutionContext { - - // 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 SourceManager sourceManager = new SourceManager(); - private final List sourceListeners = new ArrayList<>(); - private final List probeListeners = new ArrayList<>(); - - private final SourceCallback sourceCallback = new SourceCallback() { - - public void startLoading(Source source) { - for (SourceListener listener : sourceListeners) { - listener.loadStarting(source); - } - } - - public void endLoading(Source source) { - for (SourceListener listener : sourceListeners) { - listener.loadEnding(source); - } - } - }; - - private final ProbeCallback probeCallback = new ProbeCallback() { - /** - * Receives (from the {@link Probe} implementation) and distributes notification that a - * {@link Probe} has acquired a new {@linkplain PhylumTag tag}. - */ - public void newTagAdded(ProbeImpl probe, PhylumTag tag) { - for (ProbeListener listener : probeListeners) { - listener.probeTaggedAs(probe, tag); - } - if (trap != null && tag == trap.getTag()) { - probe.setTrap(trap); - } - } - }; - - private Visualizer visualizer = new DefaultVisualizer(); - - /** - * When non-null, "enter" events with matching tags will trigger a callback. - */ - private PhylumTrap trap = null; - - protected AbstractExecutionContext() { - } - - public void initialize() { - setSourceCallback(sourceCallback); - } - - public final SourceManager getSourceManager() { - return sourceManager; - } - - public void addSourceListener(SourceListener listener) { - assert listener != null; - sourceListeners.add(listener); - } - - public void addProbeListener(ProbeListener listener) { - assert listener != null; - probeListeners.add(listener); - } - - public Probe getProbe(SourceSection sourceSection) { - assert sourceSection != null; - - ProbeImpl probe = srcToProbe.get(sourceSection); - - if (probe != null) { - return probe; - } - probe = InstrumentationNode.createProbe(sourceSection, probeCallback); - - // 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 SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine()); - - Collection probes = lineToProbes.get(lineLocation); - if (probes == null) { - probes = new ArrayList<>(2); - lineToProbes.put(lineLocation, probes); - } - probes.add(probe); - - for (ProbeListener listener : probeListeners) { - listener.newProbeInserted(sourceSection, probe); - } - - return probe; - } - - /** - * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty - * collection if no probes found. - */ - public Collection findProbesTaggedAs(PhylumTag tag) { - final List probes = new ArrayList<>(); - for (Probe probe : srcToProbe.values()) { - if (tag == null || probe.isTaggedAs(tag)) { - probes.add(probe); - } - } - return probes; - } - - public Collection findProbesByLine(SourceLineLocation lineLocation) { - final Collection probes = lineToProbes.get(lineLocation); - if (probes == null) { - return Collections.emptyList(); - } - return new ArrayList<>(probes); - } - - // TODO (mlvdv) consider allowing multiple traps (without inhibiting Truffle inlining) - public void setTrap(PhylumTrap trap) { - assert trap != null; - if (this.trap != null) { - throw new IllegalStateException("trap already set"); - } - this.trap = trap; - - for (ProbeImpl probe : srcToProbe.values()) { - if (probe.isTaggedAs(trap.getTag())) { - probe.setTrap(trap); - } - } - } - - public void clearTrap() { - if (this.trap == null) { - throw new IllegalStateException("no trap set"); - } - for (ProbeImpl probe : srcToProbe.values()) { - if (probe.isTaggedAs(trap.getTag())) { - probe.setTrap(null); - } - } - trap = null; - } - - public Visualizer getVisualizer() { - return visualizer; - } - - /** - * Assign guest language-specific visualization support for tools. This must be assigned outside - * the implementation context to avoid build circularities. - */ - public void setVisualizer(Visualizer visualizer) { - this.visualizer = visualizer; - } - - /** - * Assigns a guest language-specific manager for using {@link ASTNodeProber}s added by tools to - * instrument ASTs with {@link Probe}s at specified nodes. This must be assigned outside the - * implementation context to avoid build circularities. It must also be set before any - * instrumentation probe implementations are assigned. - */ - public abstract void setASTProber(ASTProber astProber); - - /** - * Establishes source event reporting - */ - protected abstract void setSourceCallback(SourceCallback sourceCallback); - -} diff -r dcaf3993ad17 -r 8c34e2cc4add graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Tue May 13 18:31:18 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Mon May 19 17:14:36 2014 -0700 @@ -31,29 +31,29 @@ import com.oracle.truffle.api.nodes.*; /** - * A receiver of Truffle AST {@link ExecutionEvents}, propagated from a {@link Probe} to which the - * instrument is attached, for the benefit of associated tools. + * A receiver of Truffle AST runtime {@link ExecutionEvents}, propagated from the {@link Probe} to + * which the instrument is attached, for the benefit of associated tools. *

- * Guidelines for implementing Instruments, with particular attention to avoiding undesired runtime + * Guidelines for implementing {@link Instrument}s, with particular attention to minimize runtime * performance overhead: *

    - *
  1. Extend {@link Instrument} and override only the event handling methods for which some action - * is needed.
  2. + *
  3. Extend this abstract class and override only the {@linkplain ExecutionEvents event handling + * methods} for which intervention is needed.
  4. *
  5. Instruments are Truffle {@link Node}s and should be coded as much as possible in the desired * Truffle style, documented more thoroughly elsewhere.
  6. *
  7. Maintain as little state as possible.
  8. - *
  9. If state is necessary, make it {@code final} if possible.
  10. - *
  11. If non-final state is necessary, annotate it as {@link CompilationFinal} and call - * {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.
  12. + *
  13. If state is necessary, make object fields {@code final} if at all possible.
  14. + *
  15. If non-final object-valued state is necessary, annotate it as {@link CompilationFinal} and + * call {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.
  16. *
  17. Never store a {@link Frame} value in a field.
  18. *
  19. Minimize computation in standard execution paths.
  20. - *
  21. Callbacks to tools should be made via callbacks provided at construction and stored in - * {@code final} fields.
  22. - *
  23. Tool callback methods should usually be annotated as {@link SlowPath} to prevent them from - * being inlined into fast execution paths.
  24. - *
  25. If computation is needed, and if performance is important, then the computation is best - * expressed as a guest language AST and evaluated using standard Truffle mechanisms so that - * standard Truffle optimizations can be applied.
  26. + *
  27. If runtime calls must be made back to a tool, construct the instrument with a callback stored + * in a {@code final} field.
  28. + *
  29. Tool methods called by the instrument should be annotated as {@link SlowPath} to prevent them + * from being inlined into fast execution paths.
  30. + *
  31. If computation in the execution path is needed, and if performance is important, then the + * computation is best expressed as a guest language AST and evaluated using standard Truffle + * mechanisms so that standard Truffle optimizations can be applied.
  32. *
*

* Guidelines for attachment to a {@link Probe}: @@ -65,6 +65,18 @@ * every copy, and so the Instrument will receive events corresponding to the intended syntactic * unit of code, independent of which AST copy is being executed. * + *

+ * Guidelines for handling {@link ExecutionEvents}: + *

    + *
  1. Separate event methods are defined for each kind of possible return: object-valued, + * primitive-valued, void-valued, and exceptional.
  2. + *
  3. Override "leave*" primitive methods if the language implementation returns primitives and the + * instrument should avoid boxing them.
  4. + *
  5. On the other hand, if boxing all primitives for instrumentation is desired, it is only + * necessary to override the object-valued return methods, since the default implementation of each + * primitive-valued return method is to box the value and forward it to the object-valued return + * method.
  6. + *
* *

* Disclaimer: experimental; under development. @@ -72,7 +84,7 @@ * @see Probe * @see ASTNodeProber */ -public class Instrument extends InstrumentationNode { +public abstract class Instrument extends InstrumentationNode { protected Instrument() { } diff -r dcaf3993ad17 -r 8c34e2cc4add 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 May 13 18:31:18 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Mon May 19 17:14:36 2014 -0700 @@ -25,8 +25,6 @@ package com.oracle.truffle.api.instrument; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; /** * A collector of {@link ExecutionEvents} at a specific site (node) in a Truffle AST (generated by a @@ -54,7 +52,7 @@ * @see Instrument * @see Wrapper */ -public interface Probe extends PhylumTagged { +public interface Probe extends ExecutionEvents, PhylumTagged { /** * The source location with which this probe is (presumably uniquely) associated. @@ -77,66 +75,4 @@ */ void removeInstrument(Instrument oldInstrument); - // TODO (mlvdv) migrate the remaining methods to another interface. - - /** - * @see ExecutionEvents#enter(Node, VirtualFrame) - */ - void notifyEnter(Node astNode, VirtualFrame frame); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame) - */ - void notifyLeave(Node astNode, VirtualFrame frame); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, boolean) - */ - void notifyLeave(Node astNode, VirtualFrame frame, boolean result); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, byte) - */ - void notifyLeave(Node astNode, VirtualFrame frame, byte result); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, short) - */ - void notifyLeave(Node astNode, VirtualFrame frame, short result); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, int) - */ - void notifyLeave(Node astNode, VirtualFrame frame, int result); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, long) - */ - void notifyLeave(Node astNode, VirtualFrame frame, long result); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, char) - */ - void notifyLeave(Node astNode, VirtualFrame frame, char result); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, float) - */ - void notifyLeave(Node astNode, VirtualFrame frame, float result); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, double) - */ - void notifyLeave(Node astNode, VirtualFrame frame, double result); - - /** - * @see ExecutionEvents#leave(Node, VirtualFrame, Object) - */ - void notifyLeave(Node astNode, VirtualFrame frame, Object result); - - /** - * @see ExecutionEvents#leaveExceptional(Node, VirtualFrame, Exception) - */ - void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e); - } diff -r dcaf3993ad17 -r 8c34e2cc4add graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceCallback.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceCallback.java Mon May 19 17:14:36 2014 -0700 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.instrument; + +import com.oracle.truffle.api.*; + +/** + * Instrumentation callback for guest language source-related events. + */ +public interface SourceCallback { + + public void startLoading(Source source); + + public void endLoading(Source source); +} diff -r dcaf3993ad17 -r 8c34e2cc4add graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java Tue May 13 18:31:18 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java Mon May 19 17:14:36 2014 -0700 @@ -77,13 +77,14 @@ } if (node instanceof PhylumTagged) { final PhylumTagged taggedNode = (PhylumTagged) node; + p.print("["); String prefix = ""; for (PhylumTag tag : taggedNode.getPhylumTags()) { p.print(prefix); prefix = ","; p.print(tag.toString()); } - + p.print("]"); } ArrayList childFields = new ArrayList<>(); diff -r dcaf3993ad17 -r 8c34e2cc4add 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 May 13 18:31:18 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java Mon May 19 17:14:36 2014 -0700 @@ -39,7 +39,7 @@ */ public abstract class InstrumentationNode extends Node implements ExecutionEvents { - public interface ProbeCallback { + interface ProbeCallback { void newTagAdded(ProbeImpl probe, PhylumTag tag); } @@ -49,7 +49,7 @@ * * @return a new probe */ - public static ProbeImpl createProbe(SourceSection sourceSection, ProbeCallback probeCallback) { + static ProbeImpl createProbe(SourceSection sourceSection, ProbeCallback probeCallback) { return new ProbeImpl(sourceSection, probeCallback); } @@ -64,7 +64,7 @@ /** * @return the instance of {@link Probe} to which this instrument is attached. */ - public Probe getProbe() { + protected Probe getProbe() { final InstrumentationNode parent = (InstrumentationNode) getParent(); return parent == null ? null : parent.getProbe(); } @@ -199,7 +199,7 @@ * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful * for instrumentation about its AST location(s). */ - public static final class ProbeImpl extends InstrumentationNode implements Probe { + static final class ProbeImpl extends InstrumentationNode implements Probe { private final ProbeCallback probeCallback; @@ -259,7 +259,7 @@ } @Override - public Probe getProbe() { + protected Probe getProbe() { return this; } @@ -271,14 +271,14 @@ } @SlowPath - public void setTrap(PhylumTrap trap) { + void setTrap(PhylumTrap trap) { assert trap == null || isTaggedAs(trap.getTag()); probeUnchanged.invalidate(); this.trap = trap; probeUnchanged = Truffle.getRuntime().createAssumption(); } - public void notifyEnter(Node astNode, VirtualFrame frame) { + public void enter(Node astNode, VirtualFrame frame) { if (trap != null || next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -292,7 +292,7 @@ } } - public void notifyLeave(Node astNode, VirtualFrame frame) { + public void leave(Node astNode, VirtualFrame frame) { if (next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -301,16 +301,7 @@ } } - public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, byte result) { + public void leave(Node astNode, VirtualFrame frame, boolean result) { if (next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -319,16 +310,7 @@ } } - public void notifyLeave(Node astNode, VirtualFrame frame, short result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, int result) { + public void leave(Node astNode, VirtualFrame frame, byte result) { if (next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -337,7 +319,7 @@ } } - public void notifyLeave(Node astNode, VirtualFrame frame, long result) { + public void leave(Node astNode, VirtualFrame frame, short result) { if (next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -346,16 +328,7 @@ } } - public void notifyLeave(Node astNode, VirtualFrame frame, char result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, float result) { + public void leave(Node astNode, VirtualFrame frame, int result) { if (next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -364,7 +337,16 @@ } } - public void notifyLeave(Node astNode, VirtualFrame frame, double result) { + public void leave(Node astNode, VirtualFrame frame, long result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void leave(Node astNode, VirtualFrame frame, char result) { if (next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -373,7 +355,7 @@ } } - public void notifyLeave(Node astNode, VirtualFrame frame, Object result) { + public void leave(Node astNode, VirtualFrame frame, float result) { if (next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -382,7 +364,25 @@ } } - public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + public void leave(Node astNode, VirtualFrame frame, double result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void leave(Node astNode, VirtualFrame frame, Object result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { if (next != null) { if (!probeUnchanged.isValid()) { CompilerDirectives.transferToInterpreter(); @@ -391,50 +391,6 @@ } } - public void enter(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame, boolean result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, byte result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, short result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, int result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, long result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, char result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, float result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, double result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, Object result) { - } - - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - } - } } diff -r dcaf3993ad17 -r 8c34e2cc4add graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java Mon May 19 17:14:36 2014 -0700 @@ -0,0 +1,159 @@ +/* + * 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.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeCallback; +import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeImpl; +import com.oracle.truffle.api.source.*; + +/** + * Factory and services for AST {@link Probe}s + */ +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 ProbeCallback probeCallback; + + /** + * When non-null, "enter" events with matching tags will trigger a callback. + */ + private PhylumTrap phylumTrap = null; + + public ProbeManager() { + this.probeCallback = new ProbeCallback() { + /** + * Receives (from the {@link Probe} implementation) and distributes notification that a + * {@link Probe} has acquired a new {@linkplain PhylumTag tag}. + */ + public void newTagAdded(ProbeImpl probe, PhylumTag tag) { + for (ProbeListener listener : probeListeners) { + listener.probeTaggedAs(probe, tag); + } + if (phylumTrap != null && tag == phylumTrap.getTag()) { + probe.setTrap(phylumTrap); + } + } + }; + } + + public void addProbeListener(ProbeListener listener) { + assert listener != null; + probeListeners.add(listener); + } + + public Probe getProbe(SourceSection sourceSection) { + assert sourceSection != null; + + ProbeImpl probe = srcToProbe.get(sourceSection); + + if (probe != null) { + return probe; + } + probe = InstrumentationNode.createProbe(sourceSection, probeCallback); + + // 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 SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine()); + + Collection probes = lineToProbes.get(lineLocation); + if (probes == null) { + probes = new ArrayList<>(2); + lineToProbes.put(lineLocation, probes); + } + probes.add(probe); + + for (ProbeListener listener : probeListeners) { + listener.newProbeInserted(sourceSection, probe); + } + + return probe; + } + + public Collection findProbesTaggedAs(PhylumTag tag) { + final List probes = new ArrayList<>(); + for (Probe probe : srcToProbe.values()) { + if (tag == null || probe.isTaggedAs(tag)) { + probes.add(probe); + } + } + return probes; + } + + public Collection findProbesByLine(SourceLineLocation lineLocation) { + final Collection probes = lineToProbes.get(lineLocation); + if (probes == null) { + return Collections.emptyList(); + } + return new ArrayList<>(probes); + } + + public void setPhylumTrap(PhylumTrap trap) { + assert trap != null; + if (this.phylumTrap != null) { + throw new IllegalStateException("trap already set"); + } + this.phylumTrap = trap; + + PhylumTag tag = trap.getTag(); + for (ProbeImpl probe : srcToProbe.values()) { + if (probe.isTaggedAs(tag)) { + probe.setTrap(trap); + } + } + } + + public void clearPhylumTrap() { + if (this.phylumTrap == null) { + throw new IllegalStateException("no trap set"); + } + for (ProbeImpl probe : srcToProbe.values()) { + if (probe.isTaggedAs(phylumTrap.getTag())) { + probe.setTrap(null); + } + } + phylumTrap = null; + } + +} diff -r dcaf3993ad17 -r 8c34e2cc4add graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SourceCallback.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SourceCallback.java Tue May 13 18:31:18 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 com.oracle.truffle.api.*; - -/** - * Instrumentation callback for guest language source-related events. - */ -public interface SourceCallback { - - public void startLoading(Source source); - - public void endLoading(Source source); -}