Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java @ 20900:ca13a009e38b
Truffle/Instrumentation: Javadoc on Instrument now includes more thorough notes describing the implementation; client-oriented notes have been rewritten into a documentation page: https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Sun, 12 Apr 2015 22:37:16 -0700 |
parents | 129a09815063 |
children | f166d264af9f |
comparison
equal
deleted
inserted
replaced
20899:c7f1ab98d950 | 20900:ca13a009e38b |
---|---|
23 * questions. | 23 * questions. |
24 */ | 24 */ |
25 package com.oracle.truffle.api.instrument; | 25 package com.oracle.truffle.api.instrument; |
26 | 26 |
27 import com.oracle.truffle.api.*; | 27 import com.oracle.truffle.api.*; |
28 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; | |
29 import com.oracle.truffle.api.frame.*; | 28 import com.oracle.truffle.api.frame.*; |
30 import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; | 29 import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; |
31 import com.oracle.truffle.api.instrument.impl.*; | |
32 import com.oracle.truffle.api.nodes.*; | 30 import com.oracle.truffle.api.nodes.*; |
33 import com.oracle.truffle.api.source.*; | 31 import com.oracle.truffle.api.source.*; |
34 | 32 |
35 // TODO (mlvdv) migrate some of this to external documentation. | |
36 // TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe), | 33 // TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe), |
37 // then break out some of the nested classes into package privates. | 34 // then break out some of the nested classes into package privates. |
38 /** | 35 /** |
39 * A dynamically added/removed binding between a {@link Probe}, which provides notification of | 36 * A <em>binding</em> between: |
40 * <em>execution events</em> taking place at a {@link Node} in a Guest Language (GL) Truffle AST, | |
41 * and a <em>listener</em>, which consumes notifications on behalf of an external tool. There are at | |
42 * present two kinds of listeners that be used: | |
43 * <ol> | 37 * <ol> |
44 * <li>{@link SimpleInstrumentListener} is the simplest and is intended for tools that require no | 38 * <li>A {@link Probe}: a source of <em>execution events</em> taking place at a program location in |
45 * access to the <em>internal execution state</em> of the Truffle execution, only that execution has | 39 * an executing Truffle AST, and</li> |
46 * passed through a particular location in the program. Information about that location is made | 40 * <li>A <em>listener</em>: a consumer of execution events on behalf of an external client. |
47 * available via the {@link Probe} argument in notification methods, including the | |
48 * {@linkplain SourceSection source location} of the node and any {@linkplain SyntaxTag tags} that | |
49 * have been applied to the node.</li> | |
50 * <li>{@link StandardInstrumentListener} reports the same events and {@link Probe} argument, but | |
51 * additionally provides access to the execution state via the explicit {@link Node} and | |
52 * {@link Frame} at the current execution site.</li> | |
53 * </ol> | 41 * </ol> |
54 * <p> | 42 * <p> |
55 * <h4>Summary: How to "instrument" an AST location:</h4> | 43 * Client-oriented documentation for the use of Instruments is available online at <a |
44 * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events">Listening for | |
45 * Execution Events</a> | |
56 * <p> | 46 * <p> |
57 * <ol> | 47 * The implementation of Instruments is complicated by the requirement that Truffle be able to clone |
58 * <li>Create an implementation of a <em>listener</em> interface.</li> | 48 * ASTs at any time. In particular, any instrumentation-supporting Nodes that have been attached to |
59 * <li>Create an Instrument via factory methods | 49 * an AST must be cloned along with the AST: AST clones are not permitted to share Nodes. |
60 * {@link Instrument#create(SimpleInstrumentListener, String)} or | |
61 * {@link Instrument#create(StandardInstrumentListener, String)}.</li> | |
62 * <li>"Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event | |
63 * notifications begin to arrive at the listener.</li> | |
64 * <li>When no longer needed, "detach" the Instrument via {@link StandardInstrument#dispose()}, at | |
65 * which point event notifications to the listener cease, and the Instrument becomes unusable.</li> | |
66 * </ol> | |
67 * <p> | 50 * <p> |
68 * <h4>Options for creating listeners:</h4> | 51 * AST cloning is intended to be as <em>transparent</em> as possible to clients. This is encouraged |
52 * by providing the {@link SimpleInstrumentListener} for clients that need know nothing more than | |
53 * the properties associated with a Probe: it's {@link SourceSection} and any associated instances | |
54 * of {@link SyntaxTag}. | |
69 * <p> | 55 * <p> |
70 * <ol> | 56 * AST cloning is <em>not transparent</em> to clients that use the |
71 * <li>Implement one of the <em>listener interfaces</em>: {@link SimpleInstrumentListener} or | 57 * {@link StandardInstrumentListener}, since those event methods identify the concrete Node instance |
72 * {@link StandardInstrumentListener} . Their event handling methods account for both the entry into | 58 * (and thus the AST instance) where the event takes place. |
73 * an AST node (about to call) and three possible kinds of <em>execution return</em> from an AST | |
74 * node.</li> | |
75 * <li>Extend one of the <em>helper implementations</em>: {@link DefaultSimpleInstrumentListener} or | |
76 * {@link DefaultStandardInstrumentListener}. These provide no-op implementation of every listener | |
77 * method, so only the methods of interest need to be overridden.</li> | |
78 * </ol> | |
79 * <p> | 59 * <p> |
80 * <h4>General guidelines for {@link StandardInstrumentListener} implementation:</h4> | 60 * <h4>Implementation Notes: the Life Cycle of an {@link Instrument} at a {@link Probe}</h4> |
81 * <p> | |
82 * Unlike the listener interface {@link SimpleInstrumentListener}, which isolates implementations | |
83 * from Truffle internals (and is thus <em>Truffle-safe</em>), implementations of | |
84 * {@link StandardInstrumentListener} can interact directly with (and potentially affect) Truffle | |
85 * execution in general and Truffle optimization in particular. For example, it is possible to | |
86 * implement a debugger with this interface. | |
87 * </p> | |
88 * <p> | |
89 * As a consequence, implementations of {@link StandardInstrumentListener} effectively become part | |
90 * of the Truffle execution and must be coded according to general guidelines for Truffle | |
91 * implementations. For example: | |
92 * <ul> | |
93 * <li>Do not store {@link Frame} or {@link Node} references in fields.</li> | |
94 * <li>Prefer {@code final} fields and (where performance is important) short methods.</li> | |
95 * <li>If needed, pass along the {@link VirtualFrame} reference from an event notification as far as | |
96 * possible through code that is expected to be inlined, since this incurs no runtime overhead. When | |
97 * access to frame data is needed, substitute a more expensive {@linkplain Frame#materialize() | |
98 * materialized} representation of the frame.</li> | |
99 * <li>If a listener calls back to its tool during event handling, and if performance is an issue, | |
100 * then this should be through a final "callback" field in the instrument, and the called methods | |
101 * should be minimal.</li> | |
102 * <li>On the other hand, implementations should prevent Truffle from inlining beyond a reasonable | |
103 * point with the method annotation {@link TruffleBoundary}.</li> | |
104 * <li>The implicit "outer" pointer in a non-static inner class is a useful (and | |
105 * Truffle-optimizable) way to implement callbacks to owner tools.</li> | |
106 * <li>Primitive-valued return events are boxed for event notification, but Truffle will eliminate | |
107 * the boxing if they are cast back to their primitive values quickly (in particular before crossing | |
108 * any {@link TruffleBoundary} annotations). | |
109 * </ul> | |
110 * <p> | |
111 * <h4>Allowing for AST cloning:</h4> | |
112 * <p> | |
113 * Truffle routinely <em>clones</em> ASTs, which has consequences for implementations of | |
114 * {@link StandardInstrumentListener} (but not for implementations of | |
115 * {@link SimpleInstrumentListener}, from which cloning is hidden). | |
116 * <ul> | |
117 * <li>Even though a {@link Probe} is uniquely associated with a particular location in the | |
118 * executing Guest Language program, execution events at that location will in general be | |
119 * implemented by different {@link Node} instances, i.e. <em>clones</em> of the originally probed | |
120 * node.</li> | |
121 * <li>Because of <em>cloning</em> the {@link Node} supplied with notifications to a particular | |
122 * listener will vary, but because they all represent the same GL program location the events should | |
123 * be treated as equivalent for most purposes.</li> | |
124 * </ul> | |
125 * <p> | |
126 * <h4>Access to execution state via {@link StandardInstrumentListener}:</h4> | |
127 * <p> | 61 * <p> |
128 * <ul> | 62 * <ul> |
129 * <li>Notification arguments provide primary access to the GL program's execution states: | 63 * <li>A new Instrument is created in permanent association with a client-provided |
130 * <ul> | 64 * <em>listener.</em></li> |
131 * <li>{@link Node}: the concrete node (in one of the AST's clones) from which the event originated. | 65 * <li>Multiple Instruments may share a single listener.</li> |
66 * <li>An Instrument does nothing until it is {@linkplain Probe#attach(Instrument) attached} to a | |
67 * Probe, at which time the Instrument begins routing execution events from the Probe's AST location | |
68 * to the Instrument's listener.</li> | |
69 * <li>Neither Instruments nor Probes are {@link Node}s.</li> | |
70 * <li>A Probe has a single source-based location in an AST, but manages a separate | |
71 * <em>instrumentation chain</em> of Nodes at the equivalent location in each clone of the AST.</li> | |
72 * <li>When a probed AST is cloned, the instrumentation chain associated with each Probe is cloned | |
73 * along with the rest of the AST.</li> | |
74 * <li>When a new Instrument (for example an instance of {@link SimpleInstrument} is attached to a | |
75 * Probe, the Instrument inserts a new instance of its private Node type, | |
76 * {@link SimpleInstrument.SimpleInstrumentNode}, into <em>each of the instrument chains</em> | |
77 * managed by the Probe, i.e. one node instance per existing clone of the AST.</li> | |
78 * <li>If an Instrument is attached to a Probe in an AST that subsequently gets cloned, then the | |
79 * Instrument's private Node type will be cloned along with the rest of the the AST.</li> | |
80 * <li>Each Instrument's private Node type is a dynamic inner class whose only state is in the | |
81 * shared (outer) Instrument instance; that state includes a reference to the Instrument's listener. | |
132 * </li> | 82 * </li> |
133 * <li>{@link VirtualFrame}: the current execution frame. | 83 * <li>When an Instrument that has been attached to a Probe is {@linkplain #dispose() disposed}, the |
84 * Instrument searches every instrument chain associated with the Probe and removes the instance of | |
85 * its private Node type.</li> | |
86 * <li>Attaching and disposing an Instrument at a Probe <em>deoptimizes</em> any compilations of the | |
87 * AST.</li> | |
134 * </ul> | 88 * </ul> |
135 * <li>Truffle global information is available, for example the execution | |
136 * {@linkplain TruffleRuntime#iterateFrames(FrameInstanceVisitor) stack}.</li> | |
137 * <li>Additional API access to execution state may be added in the future.</li> | |
138 * </ul> | |
139 * <p> | |
140 * <h4>Activating and deactivating Instruments:</h4> | |
141 * <p> | |
142 * Instruments are <em>single-use</em>: | |
143 * <ul> | |
144 * <li>An instrument becomes active only when <em>attached</em> to a Probe via | |
145 * {@link Probe#attach(Instrument)}, and it may only be attached to a single Probe. It is a runtime | |
146 * error to attempt attaching a previously attached instrument.</li> | |
147 * <li>Attaching an instrument modifies every existing clone of the AST to which it is being | |
148 * attached, which can trigger deoptimization.</li> | |
149 * <li>The method {@link Instrument#dispose()} makes an instrument inactive by removing it from the | |
150 * Probe to which it was attached and rendering it permanently inert.</li> | |
151 * <li>Disposal removes the implementation of an instrument from all ASTs to which it was attached, | |
152 * which can trigger deoptimization.</li> | |
153 * </ul> | |
154 * <p> | |
155 * <h4>Sharing listeners:</h4> | |
156 * <p> | |
157 * Although an Instrument may only be attached to a single Probe, a listener can be shared among | |
158 * multiple Instruments. This can be useful for observing events that might happen at different | |
159 * locations in a single AST, for example all assignments to a particular variable. In this case a | |
160 * new Instrument would be created and attached at each assignment node, but all the Instruments | |
161 * would be created with the same listener. | |
162 * <p> | |
163 * <strong>Disclaimer:</strong> experimental; under development. | |
164 * | 89 * |
165 * @see Probe | 90 * @see Probe |
166 * @see TruffleEvents | 91 * @see TruffleEvents |
167 */ | 92 */ |
168 public abstract class Instrument { | 93 public abstract class Instrument { |
227 private Instrument(String instrumentInfo) { | 152 private Instrument(String instrumentInfo) { |
228 this.instrumentInfo = instrumentInfo; | 153 this.instrumentInfo = instrumentInfo; |
229 } | 154 } |
230 | 155 |
231 /** | 156 /** |
232 * Removes this instrument (and any clones) from the probe to which it attached and renders the | 157 * Removes this instrument from the probe to which it attached and renders the instrument inert. |
233 * instrument inert. | |
234 * | 158 * |
235 * @throws IllegalStateException if this instrument has already been disposed | 159 * @throws IllegalStateException if this instrument has already been disposed |
236 */ | 160 */ |
237 public void dispose() throws IllegalStateException { | 161 public void dispose() throws IllegalStateException { |
238 if (isDisposed) { | 162 if (isDisposed) { |
423 return info != null ? info : standardListener.getClass().getSimpleName(); | 347 return info != null ? info : standardListener.getClass().getSimpleName(); |
424 } | 348 } |
425 } | 349 } |
426 } | 350 } |
427 | 351 |
352 // TODO (mlvdv) EXPERIMENTAL- UNDER DEVELOPMENT | |
428 /** | 353 /** |
429 * An instrument that propagates events to an instance of {@link StandardInstrumentListener}. | 354 * An instrument that propagates events to an instance of {@link StandardInstrumentListener}. |
430 */ | 355 */ |
431 private static final class ToolNodeInstrument extends Instrument { | 356 private static final class ToolNodeInstrument extends Instrument { |
432 | 357 |