diff graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java @ 19645:10a1fc5e3209

Truffle/Instrumentation: new, experimental kind of Instrument
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Sat, 28 Feb 2015 15:52:13 -0800
parents b5467bb34b24
children 907128d02b31
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Sat Feb 28 12:50:25 2015 -0800
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Sat Feb 28 15:52:13 2015 -0800
@@ -24,13 +24,15 @@
  */
 package com.oracle.truffle.api.instrument;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.impl.*;
 import com.oracle.truffle.api.nodes.*;
 
 // TODO (mlvdv) migrate some of this to external documentation.
+// TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe),
+// then break out some of the nested classes into package privates.
 /**
  * A dynamically added/removed binding between a {@link Probe}, which provides notification of
  * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest
@@ -44,8 +46,8 @@
  * <li>Create an Instrument via factory method {@link Instrument#create(TruffleEventListener)}.</li>
  * <li>"Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event
  * notifications begin to arrive at the listener.</li>
- * <li>When no longer needed, "detach" the Instrument via {@link Instrument#dispose()}, at which
- * point event notifications to the listener cease, and the Instrument becomes unusable.</li>
+ * <li>When no longer needed, "detach" the Instrument via {@link TruffleEventInstrument#dispose()},
+ * at which point event notifications to the listener cease, and the Instrument becomes unusable.</li>
  * </ol>
  * <p>
  * <h4>Options for creating listeners:</h4>
@@ -123,8 +125,8 @@
  * error to attempt attaching a previously attached instrument.</li>
  * <li>Attaching an instrument modifies every existing clone of the AST to which it is being
  * attached, which can trigger deoptimization.</li>
- * <li>The method {@link Instrument#dispose()} makes an instrument inactive by removing it from the
- * Probe to which it was attached and rendering it permanently inert.</li>
+ * <li>The method {@link TruffleEventInstrument#dispose()} makes an instrument inactive by removing
+ * it from the Probe to which it was attached and rendering it permanently inert.</li>
  * <li>Disposal removes the implementation of an instrument from all ASTs to which it was attached,
  * which can trigger deoptimization.</li>
  * </ul>
@@ -142,7 +144,7 @@
  * @see Probe
  * @see TruffleEventListener
  */
-public final class Instrument {
+public abstract class Instrument {
 
     /**
      * Creates an instrument that will route execution events to a listener.
@@ -152,25 +154,23 @@
      * @return a new instrument, ready for attachment at a probe
      */
     public static Instrument create(TruffleEventListener listener, String instrumentInfo) {
-        return new Instrument(listener, instrumentInfo);
+        return new TruffleEventInstrument(listener, instrumentInfo);
     }
 
     /**
      * Creates an instrument that will route execution events to a listener.
      */
     public static Instrument create(TruffleEventListener listener) {
-        return new Instrument(listener, null);
+        return new TruffleEventInstrument(listener, null);
     }
 
+    // TODO (mlvdv) experimental
     /**
-     * Tool-supplied listener for events.
+     * For implementation testing.
      */
-    private final TruffleEventListener toolEventListener;
-
-    /**
-     * Optional documentation, mainly for debugging.
-     */
-    private final String instrumentInfo;
+    public static Instrument create(TruffleOptListener listener) {
+        return new TruffleOptInstrument(listener, null);
+    }
 
     /**
      * Has this instrument been disposed? stays true once set.
@@ -179,8 +179,12 @@
 
     private Probe probe = null;
 
-    private Instrument(TruffleEventListener listener, String instrumentInfo) {
-        this.toolEventListener = listener;
+    /**
+     * Optional documentation, mainly for debugging.
+     */
+    private final String instrumentInfo;
+
+    private Instrument(String instrumentInfo) {
         this.instrumentInfo = instrumentInfo;
     }
 
@@ -216,35 +220,176 @@
         return isDisposed;
     }
 
-    InstrumentNode addToChain(InstrumentNode nextNode) {
-        return new InstrumentNode(nextNode);
-    }
+    abstract InstrumentNode addToChain(InstrumentNode nextNode);
 
     /**
      * Removes this instrument from an instrument chain.
      */
-    InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
-        boolean found = false;
-        if (instrumentNode != null) {
-            if (instrumentNode.getInstrument() == this) {
-                // Found the match at the head of the chain
-                return instrumentNode.nextInstrument;
+    abstract InstrumentNode removeFromChain(InstrumentNode instrumentNode);
+
+    private static final class TruffleEventInstrument extends Instrument {
+
+        /**
+         * Tool-supplied listener for events.
+         */
+        private final TruffleEventListener toolEventListener;
+
+        private TruffleEventInstrument(TruffleEventListener listener, String instrumentInfo) {
+            super(instrumentInfo);
+            this.toolEventListener = listener;
+        }
+
+        @Override
+        InstrumentNode addToChain(InstrumentNode nextNode) {
+            return new TruffleEventInstrumentNode(nextNode);
+        }
+
+        @Override
+        InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
+            boolean found = false;
+            if (instrumentNode != null) {
+                if (instrumentNode.getInstrument() == this) {
+                    // Found the match at the head of the chain
+                    return instrumentNode.nextInstrument;
+                }
+                // Match not at the head of the chain; remove it.
+                found = instrumentNode.removeFromChain(TruffleEventInstrument.this);
+            }
+            if (!found) {
+                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+            }
+            return instrumentNode;
+        }
+
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class TruffleEventInstrumentNode extends InstrumentNode {
+
+            private TruffleEventInstrumentNode(InstrumentNode nextNode) {
+                super(nextNode);
+            }
+
+            public void enter(Node node, VirtualFrame vFrame) {
+                TruffleEventInstrument.this.toolEventListener.enter(node, vFrame);
+                if (nextInstrument != null) {
+                    nextInstrument.enter(node, vFrame);
+                }
+            }
+
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                TruffleEventInstrument.this.toolEventListener.returnVoid(node, vFrame);
+                if (nextInstrument != null) {
+                    nextInstrument.returnVoid(node, vFrame);
+                }
+            }
+
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                TruffleEventInstrument.this.toolEventListener.returnValue(node, vFrame, result);
+                if (nextInstrument != null) {
+                    nextInstrument.returnValue(node, vFrame, result);
+                }
+            }
+
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                TruffleEventInstrument.this.toolEventListener.returnExceptional(node, vFrame, exception);
+                if (nextInstrument != null) {
+                    nextInstrument.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : toolEventListener.getClass().getSimpleName();
             }
-            // Match not at the head of the chain; remove it.
-            found = instrumentNode.removeFromChain(Instrument.this);
+        }
+
+    }
+
+    public interface TruffleOptListener {
+        void notifyIsCompiled(boolean isCompiled);
+    }
+
+    private static final class TruffleOptInstrument extends Instrument {
+
+        private final TruffleOptListener toolOptListener;
+
+        private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) {
+            super(instrumentInfo);
+            this.toolOptListener = listener;
+        }
+
+        @Override
+        InstrumentNode addToChain(InstrumentNode nextNode) {
+            return new TruffleOptInstrumentNode(nextNode);
+        }
+
+        @Override
+        InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
+            boolean found = false;
+            if (instrumentNode != null) {
+                if (instrumentNode.getInstrument() == this) {
+                    // Found the match at the head of the chain
+                    return instrumentNode.nextInstrument;
+                }
+                // 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;
         }
-        if (!found) {
-            throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class TruffleOptInstrumentNode extends InstrumentNode {
+
+            private boolean isCompiled;
+
+            private TruffleOptInstrumentNode(InstrumentNode nextNode) {
+                super(nextNode);
+                this.isCompiled = CompilerDirectives.inCompiledCode();
+            }
+
+            public void enter(Node node, VirtualFrame vFrame) {
+                if (this.isCompiled != CompilerDirectives.inCompiledCode()) {
+                    this.isCompiled = CompilerDirectives.inCompiledCode();
+                    TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled);
+                }
+                if (nextInstrument != null) {
+                    nextInstrument.enter(node, vFrame);
+                }
+            }
+
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                if (nextInstrument != null) {
+                    nextInstrument.returnVoid(node, vFrame);
+                }
+            }
+
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                if (nextInstrument != null) {
+                    nextInstrument.returnValue(node, vFrame, result);
+                }
+            }
+
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                if (nextInstrument != null) {
+                    nextInstrument.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : toolOptListener.getClass().getSimpleName();
+            }
         }
-        return instrumentNode;
+
     }
 
     @NodeInfo(cost = NodeCost.NONE)
-    final class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode {
+    abstract class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode {
+        @Child protected InstrumentNode nextInstrument;
 
-        @Child private InstrumentNode nextInstrument;
-
-        private InstrumentNode(InstrumentNode nextNode) {
+        protected InstrumentNode(InstrumentNode nextNode) {
             this.nextInstrument = nextNode;
         }
 
@@ -286,40 +431,10 @@
             return nextInstrument.removeFromChain(instrument);
         }
 
-        public void enter(Node node, VirtualFrame vFrame) {
-            Instrument.this.toolEventListener.enter(node, vFrame);
-            if (nextInstrument != null) {
-                nextInstrument.enter(node, vFrame);
-            }
-        }
-
-        public void returnVoid(Node node, VirtualFrame vFrame) {
-            Instrument.this.toolEventListener.returnVoid(node, vFrame);
-            if (nextInstrument != null) {
-                nextInstrument.returnVoid(node, vFrame);
-            }
+        protected String getInstrumentInfo() {
+            return Instrument.this.instrumentInfo;
         }
 
-        public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-            Instrument.this.toolEventListener.returnValue(node, vFrame, result);
-            if (nextInstrument != null) {
-                nextInstrument.returnValue(node, vFrame, result);
-            }
-        }
-
-        public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-            Instrument.this.toolEventListener.returnExceptional(node, vFrame, exception);
-            if (nextInstrument != null) {
-                nextInstrument.returnExceptional(node, vFrame, exception);
-            }
-        }
-
-        public String instrumentationInfo() {
-            if (Instrument.this.instrumentInfo != null) {
-                return Instrument.this.instrumentInfo;
-            }
-            return toolEventListener.getClass().getSimpleName();
-        }
     }
 
 }