# HG changeset patch
# User Michael Van De Vanter
- * Client-oriented documentation for the use of Instruments is available online at https://
- * wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events
- *
- * @see Probe
- * @see EventHandlerNode
- */
-public abstract class Instrument {
-
- /**
- * Has this instrument been disposed? stays true once set.
- */
- private boolean isDisposed = false;
-
- protected Probe probe = null;
-
- /**
- * Optional documentation, mainly for debugging.
- */
- private final String instrumentInfo;
-
- /**
- *
- * The implementation of Instruments is complicated by the requirement that Truffle be able to
- * clone ASTs at any time. In particular, any instrumentation-supporting Nodes that have been
- * attached to an AST must be cloned along with the AST: AST clones are not permitted to share
- * Nodes.
- *
- * AST cloning is intended to be as transparent as possible to clients. This is
- * encouraged by providing the {@link SimpleInstrumentListener} for clients that need know
- * nothing more than the properties associated with a Probe: its {@link SourceSection} and any
- * associated instances of {@link SyntaxTag}.
- *
- * AST cloning is not transparent to clients that use the
- * {@link StandardInstrumentListener}, since those event methods identify the concrete Node
- * instance (and thus the AST instance) where the event takes place.
- *
- *
- *
* Tools share a common life cycle:
*
* Probing a node is idempotent:
@@ -422,8 +422,8 @@
/**
* Attaches a {@link SimpleInstrumentListener listener} to a {@link Probe}, creating a
- * binding called an {@link Instrument}. Until the Instrument is
- * {@linkplain Instrument#dispose() disposed}, it routes synchronous notification of
+ * binding called an {@link ProbeInstrument}. Until the Instrument is
+ * {@linkplain ProbeInstrument#dispose() disposed}, it routes synchronous notification of
* {@linkplain EventHandlerNode execution events} taking place at the Probe's AST location to
* the listener.
*
@@ -433,16 +433,16 @@
* @return a handle for access to the binding
*/
@SuppressWarnings("static-method")
- public Instrument attach(Probe probe, SimpleInstrumentListener listener, String instrumentInfo) {
- final Instrument instrument = new Instrument.SimpleInstrument(listener, instrumentInfo);
+ public ProbeInstrument attach(Probe probe, SimpleInstrumentListener listener, String instrumentInfo) {
+ final ProbeInstrument instrument = new ProbeInstrument.SimpleInstrument(listener, instrumentInfo);
probe.attach(instrument);
return instrument;
}
/**
* Attaches a {@link StandardInstrumentListener listener} to a {@link Probe}, creating
- * a binding called an {@link Instrument}. Until the Instrument is
- * {@linkplain Instrument#dispose() disposed}, it routes synchronous notification of
+ * a binding called an {@link ProbeInstrument}. Until the Instrument is
+ * {@linkplain ProbeInstrument#dispose() disposed}, it routes synchronous notification of
* {@linkplain EventHandlerNode execution events} taking place at the Probe's AST location to
* the listener.
*
@@ -452,16 +452,16 @@
* @return a handle for access to the binding
*/
@SuppressWarnings("static-method")
- public Instrument attach(Probe probe, StandardInstrumentListener listener, String instrumentInfo) {
- final Instrument instrument = new Instrument.StandardInstrument(listener, instrumentInfo);
+ public ProbeInstrument attach(Probe probe, StandardInstrumentListener listener, String instrumentInfo) {
+ final ProbeInstrument instrument = new ProbeInstrument.StandardInstrument(listener, instrumentInfo);
probe.attach(instrument);
return instrument;
}
/**
* Attaches a {@link AdvancedInstrumentResultListener listener} to a {@link Probe},
- * creating a binding called an {@link Instrument}. Until the Instrument is
- * {@linkplain Instrument#dispose() disposed}, it routes synchronous notification of
+ * creating a binding called an {@link ProbeInstrument}. Until the Instrument is
+ * {@linkplain ProbeInstrument#dispose() disposed}, it routes synchronous notification of
* {@linkplain EventHandlerNode execution events} taking place at the Probe's AST location to
* the listener.
*
@@ -480,8 +480,8 @@
* @return a handle for access to the binding
*/
@SuppressWarnings("static-method")
- public Instrument attach(Probe probe, AdvancedInstrumentResultListener listener, AdvancedInstrumentRootFactory rootFactory, Class> requiredResultType, String instrumentInfo) {
- final Instrument instrument = new Instrument.AdvancedInstrument(listener, rootFactory, requiredResultType, instrumentInfo);
+ public ProbeInstrument attach(Probe probe, AdvancedInstrumentResultListener listener, AdvancedInstrumentRootFactory rootFactory, Class> requiredResultType, String instrumentInfo) {
+ final ProbeInstrument instrument = new ProbeInstrument.AdvancedInstrument(listener, rootFactory, requiredResultType, instrumentInfo);
probe.attach(instrument);
return instrument;
}
diff -r 7ec5eef84ecf -r e7643754d982 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Fri Sep 25 14:58:35 2015 -0700
@@ -44,7 +44,7 @@
*
*
* @see Instrumenter
- * @see Instrument
+ * @see ProbeInstrument
* @see ASTProber
* @see ProbeListener
* @see SyntaxTag
@@ -115,7 +115,7 @@
*
*
+ * Client-oriented documentation for the use of Instruments is available online at https://
+ * wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events
+ *
+ * @see Probe
+ * @see EventHandlerNode
+ */
+public abstract class ProbeInstrument {
+
+ /**
+ * Has this instrument been disposed? stays true once set.
+ */
+ private boolean isDisposed = false;
+
+ protected Probe probe = null;
+
+ /**
+ * Optional documentation, mainly for debugging.
+ */
+ private final String instrumentInfo;
+
+ /**
+ *
+ * The implementation of Instruments is complicated by the requirement that Truffle be able to
+ * clone ASTs at any time. In particular, any instrumentation-supporting Nodes that have been
+ * attached to an AST must be cloned along with the AST: AST clones are not permitted to share
+ * Nodes.
+ *
+ * AST cloning is intended to be as transparent as possible to clients. This is
+ * encouraged by providing the {@link SimpleInstrumentListener} for clients that need know
+ * nothing more than the properties associated with a Probe: its {@link SourceSection} and any
+ * associated instances of {@link SyntaxTag}.
+ *
+ * AST cloning is not transparent to clients that use the
+ * {@link StandardInstrumentListener}, since those event methods identify the concrete Node
+ * instance (and thus the AST instance) where the event takes place.
+ *
+ *
+ *
- * A {@link ProbeNode} is the head of a chain of nodes acting on behalf of {@linkplain Instrument
+ * A {@link ProbeNode} is the head of a chain of nodes acting on behalf of {@linkplain ProbeInstrument
* instruments}. It is attached to an AST as a child of a guest-language-specific
* {@link WrapperNode} node.
*
- * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument instruments}
+ * When Truffle clones an AST, the chain, including all attached {@linkplain ProbeInstrument instruments}
* will be cloned along with the {@link WrapperNode} to which it is attached. An instance of
* {@link Probe} represents abstractly the instrumentation at a particular location in a Guest
* Language AST, tracks the clones of the chain, and keeps the instrumentation attached to the
@@ -135,7 +135,7 @@
* Adds an {@link AbstractInstrumentNode} to this chain.
*/
@TruffleBoundary
- void addInstrument(Instrument instrument) {
+ void addInstrument(ProbeInstrument instrument) {
assert instrument.getProbe() == probe;
// The existing chain of nodes may be empty
// Attach the modified chain.
@@ -148,7 +148,7 @@
* @throws RuntimeException if no matching instrument is found,
*/
@TruffleBoundary
- void removeInstrument(Instrument instrument) {
+ void removeInstrument(ProbeInstrument instrument) {
assert instrument.getProbe() == probe;
final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrumentNode);
if (modifiedChain == null) {
diff -r 7ec5eef84ecf -r e7643754d982 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java Fri Sep 25 14:58:35 2015 -0700
@@ -37,7 +37,7 @@
* execution state should use {@link StandardInstrumentListener}.
*
* Clients are free, of course, to record additional information in the listener implementation that
- * carries additional information about the context and reason for the particular {@link Instrument}
+ * carries additional information about the context and reason for the particular {@link ProbeInstrument}
* that is to be created from the listener.
*
* Notification is fully synchronous, so overrides have performance implications. Non-trivial
diff -r 7ec5eef84ecf -r e7643754d982 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java Fri Sep 25 14:58:35 2015 -0700
@@ -39,7 +39,7 @@
* {@link SimpleInstrumentListener}.
*
* Clients are free, of course, to record additional information in the listener implementation that
- * carries additional information about the context and reason for the particular {@link Instrument}
+ * carries additional information about the context and reason for the particular {@link ProbeInstrument}
* that is to be created from the listener.
*
* Notification is fully synchronous, so overrides have performance implications. Non-trivial
diff -r 7ec5eef84ecf -r e7643754d982 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/WrapperNode.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/WrapperNode.java Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/WrapperNode.java Fri Sep 25 14:58:35 2015 -0700
@@ -28,7 +28,7 @@
/**
* A {@link Node} instance that must be inserted into a Truffle AST in order to enable
- * {@linkplain Instrument instrumentation} at a particular Guest Language (GL) node.
+ * {@linkplain ProbeInstrument instrumentation} at a particular Guest Language (GL) node.
*
* The implementation must be GL-specific. A wrapper decorates a GL AST node (the wrapper's
* child) by acting as a transparent proxy with respect to the GL's execution
@@ -41,7 +41,7 @@
* at the wrapped AST node during program execution.
*
* When a GL AST is cloned, the {@link WrapperNode}, its {@link EventHandlerNode} and any
- * {@linkplain Instrument instrumentation} are also cloned; they are in effect part of the GL AST.
+ * {@linkplain ProbeInstrument instrumentation} are also cloned; they are in effect part of the GL AST.
* An instance of {@link Probe} represents abstractly the instrumentation at a particular location
* in a GL AST; it tracks all the copies of the Wrapper and attached instrumentation, and acts as a
* single point of access for tools.
@@ -60,11 +60,11 @@
*
*
- * @see Instrument
+ * @see ProbeInstrument
*/
public interface WrapperNode extends InstrumentationNode {
diff -r 7ec5eef84ecf -r e7643754d982 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java Fri Sep 25 14:58:35 2015 -0700
@@ -119,12 +119,12 @@
*
*
*
*
- *
- * Implementation Notes
- * Implementation Notes: the Life Cycle of an {@link Instrument} at a {@link Probe}
- *
- *
- */
- private Instrument(String instrumentInfo) {
- this.instrumentInfo = instrumentInfo;
- }
-
- /**
- * Gets the {@link Probe} to which this Instrument is currently attached: {@code null} if not
- * yet attached to a Probe or if this Instrument has been {@linkplain #dispose() disposed}.
- */
- public Probe getProbe() {
- return probe;
- }
-
- /**
- * Removes this Instrument from the Probe to which it attached and renders this Instrument
- * inert.
- *
- * @throws IllegalStateException if this instrument has already been disposed
- */
- public void dispose() throws IllegalStateException {
- if (isDisposed) {
- throw new IllegalStateException("Attempt to dispose an already disposed Instrumennt");
- }
- if (probe != null) {
- // It's attached
- probe.disposeInstrument(this);
- probe = null;
- }
- this.isDisposed = true;
- }
-
- /**
- * For internal implementation only.
- */
- void setAttachedTo(Probe probe) {
- this.probe = probe;
- }
-
- /**
- * Has this instrument been disposed and rendered unusable?
- */
- boolean isDisposed() {
- return isDisposed;
- }
-
- abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode);
-
- /**
- * Removes this instrument from an instrument chain.
- */
- abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode);
-
- /**
- * An instrument that propagates events to an instance of {@link SimpleInstrumentListener}.
- */
- static final class SimpleInstrument extends Instrument {
-
- /**
- * Tool-supplied listener for events.
- */
- private final SimpleInstrumentListener simpleListener;
-
- SimpleInstrument(SimpleInstrumentListener simpleListener, String instrumentInfo) {
- super(instrumentInfo);
- this.simpleListener = simpleListener;
- }
-
- @Override
- AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
- return new SimpleInstrumentNode(nextNode);
- }
-
- @Override
- AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
- boolean found = false;
- if (instrumentNode != null) {
- if (instrumentNode.getInstrument() == this) {
- // Found the match at the head of the chain
- return instrumentNode.nextInstrumentNode;
- }
- // Match not at the head of the chain; remove it.
- found = instrumentNode.removeFromChain(SimpleInstrument.this);
- }
- if (!found) {
- throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
- }
- return instrumentNode;
- }
-
- /**
- * Node that implements a {@link SimpleInstrument} in a particular AST.
- */
- @NodeInfo(cost = NodeCost.NONE)
- private final class SimpleInstrumentNode extends AbstractInstrumentNode {
-
- private SimpleInstrumentNode(AbstractInstrumentNode nextNode) {
- super(nextNode);
- }
-
- @Override
- public void enter(Node node, VirtualFrame vFrame) {
- SimpleInstrument.this.simpleListener.onEnter(SimpleInstrument.this.probe);
- if (nextInstrumentNode != null) {
- nextInstrumentNode.enter(node, vFrame);
- }
- }
-
- @Override
- public void returnVoid(Node node, VirtualFrame vFrame) {
- SimpleInstrument.this.simpleListener.onReturnVoid(SimpleInstrument.this.probe);
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnVoid(node, vFrame);
- }
- }
-
- @Override
- public void returnValue(Node node, VirtualFrame vFrame, Object result) {
- SimpleInstrument.this.simpleListener.onReturnValue(SimpleInstrument.this.probe, result);
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnValue(node, vFrame, result);
- }
- }
-
- @Override
- public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
- SimpleInstrument.this.simpleListener.onReturnExceptional(SimpleInstrument.this.probe, exception);
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnExceptional(node, vFrame, exception);
- }
- }
-
- @Override
- public String instrumentationInfo() {
- final String info = getInstrumentInfo();
- return info != null ? info : simpleListener.getClass().getSimpleName();
- }
- }
- }
-
- /**
- * An instrument that propagates events to an instance of {@link StandardInstrumentListener}.
- */
- static final class StandardInstrument extends Instrument {
-
- /**
- * Tool-supplied listener for AST events.
- */
- private final StandardInstrumentListener standardListener;
-
- StandardInstrument(StandardInstrumentListener standardListener, String instrumentInfo) {
- super(instrumentInfo);
- this.standardListener = standardListener;
- }
-
- @Override
- AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
- return new StandardInstrumentNode(nextNode);
- }
-
- @Override
- AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
- boolean found = false;
- if (instrumentNode != null) {
- if (instrumentNode.getInstrument() == this) {
- // Found the match at the head of the chain
- return instrumentNode.nextInstrumentNode;
- }
- // Match not at the head of the chain; remove it.
- found = instrumentNode.removeFromChain(StandardInstrument.this);
- }
- if (!found) {
- throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
- }
- return instrumentNode;
- }
-
- /**
- * Node that implements a {@link StandardInstrument} in a particular AST.
- */
- @NodeInfo(cost = NodeCost.NONE)
- private final class StandardInstrumentNode extends AbstractInstrumentNode {
-
- private StandardInstrumentNode(AbstractInstrumentNode nextNode) {
- super(nextNode);
- }
-
- @Override
- public void enter(Node node, VirtualFrame vFrame) {
- standardListener.onEnter(StandardInstrument.this.probe, node, vFrame);
- if (nextInstrumentNode != null) {
- nextInstrumentNode.enter(node, vFrame);
- }
- }
-
- @Override
- public void returnVoid(Node node, VirtualFrame vFrame) {
- standardListener.onReturnVoid(StandardInstrument.this.probe, node, vFrame);
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnVoid(node, vFrame);
- }
- }
-
- @Override
- public void returnValue(Node node, VirtualFrame vFrame, Object result) {
- standardListener.onReturnValue(StandardInstrument.this.probe, node, vFrame, result);
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnValue(node, vFrame, result);
- }
- }
-
- @Override
- public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
- standardListener.onReturnExceptional(StandardInstrument.this.probe, node, vFrame, exception);
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnExceptional(node, vFrame, exception);
- }
- }
-
- @Override
- public String instrumentationInfo() {
- final String info = getInstrumentInfo();
- return info != null ? info : standardListener.getClass().getSimpleName();
- }
- }
- }
-
- /**
- * An instrument that allows clients to provide an AST fragment to be executed directly from
- * within a Probe's instrumentation chain, and thus directly in the executing Truffle
- * AST with potential for full optimization.
- */
- static final class AdvancedInstrument extends Instrument {
-
- private final AdvancedInstrumentResultListener resultListener;
- private final AdvancedInstrumentRootFactory rootFactory;
- private final Class> requiredResultType;
-
- AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class> requiredResultType, String instrumentInfo) {
- super(instrumentInfo);
- this.resultListener = resultListener;
- this.rootFactory = rootFactory;
- this.requiredResultType = requiredResultType;
- }
-
- @Override
- AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
- return new AdvancedInstrumentNode(nextNode);
- }
-
- @Override
- AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
- boolean found = false;
- if (instrumentNode != null) {
- if (instrumentNode.getInstrument() == this) {
- // Found the match at the head of the chain
- return instrumentNode.nextInstrumentNode;
- }
- // Match not at the head of the chain; remove it.
- found = instrumentNode.removeFromChain(AdvancedInstrument.this);
- }
- if (!found) {
- throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
- }
- return instrumentNode;
- }
-
- /**
- * Node that implements a {@link AdvancedInstrument} in a particular AST.
- */
- @NodeInfo(cost = NodeCost.NONE)
- private final class AdvancedInstrumentNode extends AbstractInstrumentNode {
-
- @Child private AdvancedInstrumentRoot instrumentRoot;
-
- private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) {
- super(nextNode);
- }
-
- @Override
- public void enter(Node node, VirtualFrame vFrame) {
- if (instrumentRoot == null) {
- try {
- final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node);
- if (newInstrumentRoot != null) {
- instrumentRoot = newInstrumentRoot;
- adoptChildren();
- AdvancedInstrument.this.probe.invalidateProbeUnchanged();
- }
- } catch (RuntimeException ex) {
- if (resultListener != null) {
- resultListener.onFailure(node, vFrame, ex);
- }
- }
- }
- if (instrumentRoot != null) {
- try {
- final Object result = instrumentRoot.executeRoot(node, vFrame);
- if (resultListener != null) {
- checkResultType(result);
- resultListener.onExecution(node, vFrame, result);
- }
- } catch (RuntimeException ex) {
- if (resultListener != null) {
- resultListener.onFailure(node, vFrame, ex);
- }
- }
- }
- if (nextInstrumentNode != null) {
- nextInstrumentNode.enter(node, vFrame);
- }
- }
-
- private void checkResultType(Object result) {
- if (requiredResultType == null) {
- return;
- }
- if (result == null) {
- throw instrumentResultNull();
- }
- if (!(requiredResultType.isAssignableFrom(result.getClass()))) {
- throw instrumentResultWrongType(result);
- }
- }
-
- @TruffleBoundary
- private RuntimeException instrumentResultNull() {
- return new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required");
- }
-
- @TruffleBoundary
- private RuntimeException instrumentResultWrongType(Object result) {
- return new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName());
- }
-
- @Override
- public void returnVoid(Node node, VirtualFrame vFrame) {
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnVoid(node, vFrame);
- }
- }
-
- @Override
- public void returnValue(Node node, VirtualFrame vFrame, Object result) {
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnValue(node, vFrame, result);
- }
- }
-
- @Override
- public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnExceptional(node, vFrame, exception);
- }
- }
-
- @Override
- public String instrumentationInfo() {
- final String info = getInstrumentInfo();
- return info != null ? info : rootFactory.getClass().getSimpleName();
- }
- }
- }
-
- // TODO (mlvdv) experimental
- public interface TruffleOptListener {
- void notifyIsCompiled(boolean isCompiled);
- }
-
- @SuppressWarnings("unused")
- private static final class TruffleOptInstrument extends Instrument {
-
- private final TruffleOptListener toolOptListener;
-
- private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) {
- super(instrumentInfo);
- this.toolOptListener = listener;
- }
-
- @Override
- AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
- return new TruffleOptInstrumentNode(nextNode);
- }
-
- @Override
- AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
- boolean found = false;
- if (instrumentNode != null) {
- if (instrumentNode.getInstrument() == this) {
- // Found the match at the head of the chain
- return instrumentNode.nextInstrumentNode;
- }
- // Match not at the head of the chain; remove it.
- found = instrumentNode.removeFromChain(TruffleOptInstrument.this);
- }
- if (!found) {
- throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
- }
- return instrumentNode;
- }
-
- @NodeInfo(cost = NodeCost.NONE)
- private final class TruffleOptInstrumentNode extends AbstractInstrumentNode {
-
- private boolean isCompiled;
-
- private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) {
- super(nextNode);
- this.isCompiled = CompilerDirectives.inCompiledCode();
- }
-
- @Override
- public void enter(Node node, VirtualFrame vFrame) {
- if (this.isCompiled != CompilerDirectives.inCompiledCode()) {
- this.isCompiled = CompilerDirectives.inCompiledCode();
- TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled);
- }
- if (nextInstrumentNode != null) {
- nextInstrumentNode.enter(node, vFrame);
- }
- }
-
- @Override
- public void returnVoid(Node node, VirtualFrame vFrame) {
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnVoid(node, vFrame);
- }
- }
-
- @Override
- public void returnValue(Node node, VirtualFrame vFrame, Object result) {
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnValue(node, vFrame, result);
- }
- }
-
- @Override
- public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
- if (nextInstrumentNode != null) {
- nextInstrumentNode.returnExceptional(node, vFrame, exception);
- }
- }
-
- @Override
- public String instrumentationInfo() {
- final String info = getInstrumentInfo();
- return info != null ? info : toolOptListener.getClass().getSimpleName();
- }
- }
- }
-
- @NodeInfo(cost = NodeCost.NONE)
- abstract class AbstractInstrumentNode extends EventHandlerNode {
-
- @Child protected AbstractInstrumentNode nextInstrumentNode;
-
- protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) {
- this.nextInstrumentNode = nextNode;
- }
-
- @Override
- public Probe getProbe() {
- return probe;
- }
-
- /**
- * Gets the instrument that created this node.
- */
- private Instrument getInstrument() {
- return Instrument.this;
- }
-
- /**
- * Removes the node from this chain that was added by a particular instrument, assuming that
- * the head of the chain is not the one to be replaced. This is awkward, but is required
- * because {@link Node#replace(Node)} won't take a {@code null} argument. This doesn't work
- * for the tail of the list, which would be replacing itself with null. So the replacement
- * must be directed the parent of the node being removed.
- */
- private boolean removeFromChain(Instrument instrument) {
- assert getInstrument() != instrument;
- if (nextInstrumentNode == null) {
- return false;
- }
- if (nextInstrumentNode.getInstrument() == instrument) {
- // Next is the one to remove
- if (nextInstrumentNode.nextInstrumentNode == null) {
- // Next is at the tail; just forget
- nextInstrumentNode = null;
- } else {
- // Replace next with its successor
- nextInstrumentNode.replace(nextInstrumentNode.nextInstrumentNode);
- }
- return true;
- }
- return nextInstrumentNode.removeFromChain(instrument);
- }
-
- protected String getInstrumentInfo() {
- return Instrument.this.instrumentInfo;
- }
- }
-}
diff -r 7ec5eef84ecf -r e7643754d982 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java Fri Sep 25 14:58:35 2015 -0700
@@ -73,14 +73,14 @@
}
/**
- * {@linkplain Instrument Instrumentation}-based collectors of data during Guest Language
+ * {@linkplain ProbeInstrument Instrumentation}-based collectors of data during Guest Language
* program execution.
*
*
*
* Note:The relationship must be with an AST location, not a specific
@@ -57,7 +57,7 @@
*
+ *
+ * Implementation Notes
+ * Implementation Notes: the Life Cycle of an {@link ProbeInstrument} at a {@link Probe}
+ *
+ *
+ */
+ private ProbeInstrument(String instrumentInfo) {
+ this.instrumentInfo = instrumentInfo;
+ }
+
+ /**
+ * Gets the {@link Probe} to which this Instrument is currently attached: {@code null} if not
+ * yet attached to a Probe or if this Instrument has been {@linkplain #dispose() disposed}.
+ */
+ public Probe getProbe() {
+ return probe;
+ }
+
+ /**
+ * Removes this Instrument from the Probe to which it attached and renders this Instrument
+ * inert.
+ *
+ * @throws IllegalStateException if this instrument has already been disposed
+ */
+ public void dispose() throws IllegalStateException {
+ if (isDisposed) {
+ throw new IllegalStateException("Attempt to dispose an already disposed Instrumennt");
+ }
+ if (probe != null) {
+ // It's attached
+ probe.disposeInstrument(this);
+ probe = null;
+ }
+ this.isDisposed = true;
+ }
+
+ /**
+ * For internal implementation only.
+ */
+ void setAttachedTo(Probe probe) {
+ this.probe = probe;
+ }
+
+ /**
+ * Has this instrument been disposed and rendered unusable?
+ */
+ boolean isDisposed() {
+ return isDisposed;
+ }
+
+ abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode);
+
+ /**
+ * Removes this instrument from an instrument chain.
+ */
+ abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode);
+
+ /**
+ * An instrument that propagates events to an instance of {@link SimpleInstrumentListener}.
+ */
+ static final class SimpleInstrument extends ProbeInstrument {
+
+ /**
+ * Tool-supplied listener for events.
+ */
+ private final SimpleInstrumentListener simpleListener;
+
+ SimpleInstrument(SimpleInstrumentListener simpleListener, String instrumentInfo) {
+ super(instrumentInfo);
+ this.simpleListener = simpleListener;
+ }
+
+ @Override
+ AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+ return new SimpleInstrumentNode(nextNode);
+ }
+
+ @Override
+ AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
+ boolean found = false;
+ if (instrumentNode != null) {
+ if (instrumentNode.getInstrument() == this) {
+ // Found the match at the head of the chain
+ return instrumentNode.nextInstrumentNode;
+ }
+ // Match not at the head of the chain; remove it.
+ found = instrumentNode.removeFromChain(SimpleInstrument.this);
+ }
+ if (!found) {
+ throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+ }
+ return instrumentNode;
+ }
+
+ /**
+ * Node that implements a {@link SimpleInstrument} in a particular AST.
+ */
+ @NodeInfo(cost = NodeCost.NONE)
+ private final class SimpleInstrumentNode extends AbstractInstrumentNode {
+
+ private SimpleInstrumentNode(AbstractInstrumentNode nextNode) {
+ super(nextNode);
+ }
+
+ @Override
+ public void enter(Node node, VirtualFrame vFrame) {
+ SimpleInstrument.this.simpleListener.onEnter(SimpleInstrument.this.probe);
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.enter(node, vFrame);
+ }
+ }
+
+ @Override
+ public void returnVoid(Node node, VirtualFrame vFrame) {
+ SimpleInstrument.this.simpleListener.onReturnVoid(SimpleInstrument.this.probe);
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnVoid(node, vFrame);
+ }
+ }
+
+ @Override
+ public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+ SimpleInstrument.this.simpleListener.onReturnValue(SimpleInstrument.this.probe, result);
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnValue(node, vFrame, result);
+ }
+ }
+
+ @Override
+ public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+ SimpleInstrument.this.simpleListener.onReturnExceptional(SimpleInstrument.this.probe, exception);
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnExceptional(node, vFrame, exception);
+ }
+ }
+
+ @Override
+ public String instrumentationInfo() {
+ final String info = getInstrumentInfo();
+ return info != null ? info : simpleListener.getClass().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * An instrument that propagates events to an instance of {@link StandardInstrumentListener}.
+ */
+ static final class StandardInstrument extends ProbeInstrument {
+
+ /**
+ * Tool-supplied listener for AST events.
+ */
+ private final StandardInstrumentListener standardListener;
+
+ StandardInstrument(StandardInstrumentListener standardListener, String instrumentInfo) {
+ super(instrumentInfo);
+ this.standardListener = standardListener;
+ }
+
+ @Override
+ AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+ return new StandardInstrumentNode(nextNode);
+ }
+
+ @Override
+ AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
+ boolean found = false;
+ if (instrumentNode != null) {
+ if (instrumentNode.getInstrument() == this) {
+ // Found the match at the head of the chain
+ return instrumentNode.nextInstrumentNode;
+ }
+ // Match not at the head of the chain; remove it.
+ found = instrumentNode.removeFromChain(StandardInstrument.this);
+ }
+ if (!found) {
+ throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+ }
+ return instrumentNode;
+ }
+
+ /**
+ * Node that implements a {@link StandardInstrument} in a particular AST.
+ */
+ @NodeInfo(cost = NodeCost.NONE)
+ private final class StandardInstrumentNode extends AbstractInstrumentNode {
+
+ private StandardInstrumentNode(AbstractInstrumentNode nextNode) {
+ super(nextNode);
+ }
+
+ @Override
+ public void enter(Node node, VirtualFrame vFrame) {
+ standardListener.onEnter(StandardInstrument.this.probe, node, vFrame);
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.enter(node, vFrame);
+ }
+ }
+
+ @Override
+ public void returnVoid(Node node, VirtualFrame vFrame) {
+ standardListener.onReturnVoid(StandardInstrument.this.probe, node, vFrame);
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnVoid(node, vFrame);
+ }
+ }
+
+ @Override
+ public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+ standardListener.onReturnValue(StandardInstrument.this.probe, node, vFrame, result);
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnValue(node, vFrame, result);
+ }
+ }
+
+ @Override
+ public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+ standardListener.onReturnExceptional(StandardInstrument.this.probe, node, vFrame, exception);
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnExceptional(node, vFrame, exception);
+ }
+ }
+
+ @Override
+ public String instrumentationInfo() {
+ final String info = getInstrumentInfo();
+ return info != null ? info : standardListener.getClass().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * An instrument that allows clients to provide an AST fragment to be executed directly from
+ * within a Probe's instrumentation chain, and thus directly in the executing Truffle
+ * AST with potential for full optimization.
+ */
+ static final class AdvancedInstrument extends ProbeInstrument {
+
+ private final AdvancedInstrumentResultListener resultListener;
+ private final AdvancedInstrumentRootFactory rootFactory;
+ private final Class> requiredResultType;
+
+ AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class> requiredResultType, String instrumentInfo) {
+ super(instrumentInfo);
+ this.resultListener = resultListener;
+ this.rootFactory = rootFactory;
+ this.requiredResultType = requiredResultType;
+ }
+
+ @Override
+ AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+ return new AdvancedInstrumentNode(nextNode);
+ }
+
+ @Override
+ AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
+ boolean found = false;
+ if (instrumentNode != null) {
+ if (instrumentNode.getInstrument() == this) {
+ // Found the match at the head of the chain
+ return instrumentNode.nextInstrumentNode;
+ }
+ // Match not at the head of the chain; remove it.
+ found = instrumentNode.removeFromChain(AdvancedInstrument.this);
+ }
+ if (!found) {
+ throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+ }
+ return instrumentNode;
+ }
+
+ /**
+ * Node that implements a {@link AdvancedInstrument} in a particular AST.
+ */
+ @NodeInfo(cost = NodeCost.NONE)
+ private final class AdvancedInstrumentNode extends AbstractInstrumentNode {
+
+ @Child private AdvancedInstrumentRoot instrumentRoot;
+
+ private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) {
+ super(nextNode);
+ }
+
+ @Override
+ public void enter(Node node, VirtualFrame vFrame) {
+ if (instrumentRoot == null) {
+ try {
+ final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node);
+ if (newInstrumentRoot != null) {
+ instrumentRoot = newInstrumentRoot;
+ adoptChildren();
+ AdvancedInstrument.this.probe.invalidateProbeUnchanged();
+ }
+ } catch (RuntimeException ex) {
+ if (resultListener != null) {
+ resultListener.onFailure(node, vFrame, ex);
+ }
+ }
+ }
+ if (instrumentRoot != null) {
+ try {
+ final Object result = instrumentRoot.executeRoot(node, vFrame);
+ if (resultListener != null) {
+ checkResultType(result);
+ resultListener.onExecution(node, vFrame, result);
+ }
+ } catch (RuntimeException ex) {
+ if (resultListener != null) {
+ resultListener.onFailure(node, vFrame, ex);
+ }
+ }
+ }
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.enter(node, vFrame);
+ }
+ }
+
+ private void checkResultType(Object result) {
+ if (requiredResultType == null) {
+ return;
+ }
+ if (result == null) {
+ throw instrumentResultNull();
+ }
+ if (!(requiredResultType.isAssignableFrom(result.getClass()))) {
+ throw instrumentResultWrongType(result);
+ }
+ }
+
+ @TruffleBoundary
+ private RuntimeException instrumentResultNull() {
+ return new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required");
+ }
+
+ @TruffleBoundary
+ private RuntimeException instrumentResultWrongType(Object result) {
+ return new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName());
+ }
+
+ @Override
+ public void returnVoid(Node node, VirtualFrame vFrame) {
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnVoid(node, vFrame);
+ }
+ }
+
+ @Override
+ public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnValue(node, vFrame, result);
+ }
+ }
+
+ @Override
+ public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnExceptional(node, vFrame, exception);
+ }
+ }
+
+ @Override
+ public String instrumentationInfo() {
+ final String info = getInstrumentInfo();
+ return info != null ? info : rootFactory.getClass().getSimpleName();
+ }
+ }
+ }
+
+ // TODO (mlvdv) experimental
+ public interface TruffleOptListener {
+ void notifyIsCompiled(boolean isCompiled);
+ }
+
+ @SuppressWarnings("unused")
+ private static final class TruffleOptInstrument extends ProbeInstrument {
+
+ private final TruffleOptListener toolOptListener;
+
+ private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) {
+ super(instrumentInfo);
+ this.toolOptListener = listener;
+ }
+
+ @Override
+ AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+ return new TruffleOptInstrumentNode(nextNode);
+ }
+
+ @Override
+ AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
+ boolean found = false;
+ if (instrumentNode != null) {
+ if (instrumentNode.getInstrument() == this) {
+ // Found the match at the head of the chain
+ return instrumentNode.nextInstrumentNode;
+ }
+ // Match not at the head of the chain; remove it.
+ found = instrumentNode.removeFromChain(TruffleOptInstrument.this);
+ }
+ if (!found) {
+ throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+ }
+ return instrumentNode;
+ }
+
+ @NodeInfo(cost = NodeCost.NONE)
+ private final class TruffleOptInstrumentNode extends AbstractInstrumentNode {
+
+ private boolean isCompiled;
+
+ private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) {
+ super(nextNode);
+ this.isCompiled = CompilerDirectives.inCompiledCode();
+ }
+
+ @Override
+ public void enter(Node node, VirtualFrame vFrame) {
+ if (this.isCompiled != CompilerDirectives.inCompiledCode()) {
+ this.isCompiled = CompilerDirectives.inCompiledCode();
+ TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled);
+ }
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.enter(node, vFrame);
+ }
+ }
+
+ @Override
+ public void returnVoid(Node node, VirtualFrame vFrame) {
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnVoid(node, vFrame);
+ }
+ }
+
+ @Override
+ public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnValue(node, vFrame, result);
+ }
+ }
+
+ @Override
+ public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+ if (nextInstrumentNode != null) {
+ nextInstrumentNode.returnExceptional(node, vFrame, exception);
+ }
+ }
+
+ @Override
+ public String instrumentationInfo() {
+ final String info = getInstrumentInfo();
+ return info != null ? info : toolOptListener.getClass().getSimpleName();
+ }
+ }
+ }
+
+ @NodeInfo(cost = NodeCost.NONE)
+ abstract class AbstractInstrumentNode extends EventHandlerNode {
+
+ @Child protected AbstractInstrumentNode nextInstrumentNode;
+
+ protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) {
+ this.nextInstrumentNode = nextNode;
+ }
+
+ @Override
+ public Probe getProbe() {
+ return probe;
+ }
+
+ /**
+ * Gets the instrument that created this node.
+ */
+ private ProbeInstrument getInstrument() {
+ return ProbeInstrument.this;
+ }
+
+ /**
+ * Removes the node from this chain that was added by a particular instrument, assuming that
+ * the head of the chain is not the one to be replaced. This is awkward, but is required
+ * because {@link Node#replace(Node)} won't take a {@code null} argument. This doesn't work
+ * for the tail of the list, which would be replacing itself with null. So the replacement
+ * must be directed the parent of the node being removed.
+ */
+ private boolean removeFromChain(ProbeInstrument instrument) {
+ assert getInstrument() != instrument;
+ if (nextInstrumentNode == null) {
+ return false;
+ }
+ if (nextInstrumentNode.getInstrument() == instrument) {
+ // Next is the one to remove
+ if (nextInstrumentNode.nextInstrumentNode == null) {
+ // Next is at the tail; just forget
+ nextInstrumentNode = null;
+ } else {
+ // Replace next with its successor
+ nextInstrumentNode.replace(nextInstrumentNode.nextInstrumentNode);
+ }
+ return true;
+ }
+ return nextInstrumentNode.removeFromChain(instrument);
+ }
+
+ protected String getInstrumentInfo() {
+ return ProbeInstrument.this.instrumentInfo;
+ }
+ }
+}
diff -r 7ec5eef84ecf -r e7643754d982 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Fri Sep 25 14:58:35 2015 -0700
@@ -27,7 +27,7 @@
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.instrument.Instrument.AbstractInstrumentNode;
+import com.oracle.truffle.api.instrument.ProbeInstrument.AbstractInstrumentNode;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
@@ -36,11 +36,11 @@
* Implementation class & interface for enabling the attachment of {@linkplain Probe Probes} to
* Truffle ASTs.
*