Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java @ 19825:907128d02b31
Truffle/Instrumentation: For clients of Instrumentation, replace the TruffleEventListener interface with two: InstrumentListener, and ASTInstrumentListener. The former is simple, completely Truffle-safe (can't affect Truffle execution), and designed for simple tools. The latter is similar to the previous interface.
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Thu, 12 Mar 2015 18:03:05 -0700 |
parents | 10a1fc5e3209 |
children | 2e3cc2a27711 |
comparison
equal
deleted
inserted
replaced
19824:8b7a143aea6b | 19825:907128d02b31 |
---|---|
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; | 28 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; |
29 import com.oracle.truffle.api.frame.*; | 29 import com.oracle.truffle.api.frame.*; |
30 import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; | |
30 import com.oracle.truffle.api.instrument.impl.*; | 31 import com.oracle.truffle.api.instrument.impl.*; |
31 import com.oracle.truffle.api.nodes.*; | 32 import com.oracle.truffle.api.nodes.*; |
33 import com.oracle.truffle.api.source.*; | |
32 | 34 |
33 // TODO (mlvdv) migrate some of this to external documentation. | 35 // TODO (mlvdv) migrate some of this to external documentation. |
34 // TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe), | 36 // TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe), |
35 // then break out some of the nested classes into package privates. | 37 // then break out some of the nested classes into package privates. |
36 /** | 38 /** |
37 * A dynamically added/removed binding between a {@link Probe}, which provides notification of | 39 * A dynamically added/removed binding between a {@link Probe}, which provides notification of |
38 * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest | 40 * <em>execution events</em> taking place at a {@link Node} in a Guest Language (GL) Truffle AST, |
39 * Language (GL) Truffle AST, and a {@linkplain TruffleEventListener listener}, which consumes | 41 * and a <em>listener</em>, which consumes notifications on behalf of an external tool. There are at |
40 * notifications on behalf of an external tool. | 42 * present two kinds of listeners that be used: |
43 * <ol> | |
44 * <li>{@link InstrumentListener} is the simplest and is intended for tools that require no access | |
45 * to the <em>internal execution state</em> of the Truffle execution, only that execution has passed | |
46 * through a particular location in the program. Information about that location is made available | |
47 * via the {@link Probe} argument in notification methods, including the {@linkplain SourceSection | |
48 * source location} of the node and any {@linkplain SyntaxTag tags} that have been applied to the | |
49 * node.</li> | |
50 * <li>{@link ASTInstrumentListener} 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 * <p> | 54 * <p> |
42 * <h4>Summary: How to "instrument" an AST location:</h4> | 55 * <h4>Summary: How to "instrument" an AST location:</h4> |
56 * <p> | |
43 * <ol> | 57 * <ol> |
44 * <li>Create an implementation of {@link TruffleEventListener} that responds to events on behalf of | 58 * <li>Create an implementation of a <em>listener</em> interface.</li> |
45 * a tool.</li> | 59 * <li>Create an Instrument via factory methods |
46 * <li>Create an Instrument via factory method {@link Instrument#create(TruffleEventListener)}.</li> | 60 * {@link Instrument#create(InstrumentListener, String)} or |
61 * {@link Instrument#create(ASTInstrumentListener, String)}.</li> | |
47 * <li>"Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event | 62 * <li>"Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event |
48 * notifications begin to arrive at the listener.</li> | 63 * notifications begin to arrive at the listener.</li> |
49 * <li>When no longer needed, "detach" the Instrument via {@link TruffleEventInstrument#dispose()}, | 64 * <li>When no longer needed, "detach" the Instrument via {@link ASTInstrument#dispose()}, at which |
50 * at which point event notifications to the listener cease, and the Instrument becomes unusable.</li> | 65 * point event notifications to the listener cease, and the Instrument becomes unusable.</li> |
51 * </ol> | 66 * </ol> |
52 * <p> | 67 * <p> |
53 * <h4>Options for creating listeners:</h4> | 68 * <h4>Options for creating listeners:</h4> |
54 * <p> | 69 * <p> |
55 * <ol> | 70 * <ol> |
56 * <li>Implement the interface {@link TruffleEventListener}. The event handling methods account for | 71 * <li>Implement one of the <em>listener interfaces</em>: {@link InstrumentListener} or |
57 * both the entry into an AST node (about to call) and several possible kinds of exit from an AST | 72 * {@link ASTInstrumentListener} . Their event handling methods account for both the entry into an |
58 * node (just returned).</li> | 73 * AST node (about to call) and three possible kinds of <em>execution return</em> from an AST node.</li> |
59 * <li>Extend {@link DefaultEventListener}, which provides a no-op implementation of every | 74 * <li>Extend one of the <em>helper implementations</em>: {@link DefaultInstrumentListener} or |
60 * {@link TruffleEventListener} method; override the methods of interest.</li> | 75 * {@link DefaultASTInstrumentListener}. These provide no-op implementation of every listener |
61 * <li>Extend {@link SimpleEventListener}, where return values are ignored so only two methods (for | 76 * method, so only the methods of interest need to be overridden.</li> |
62 * "enter" and "return") will notify all events.</li> | 77 * <li>Extend one of the <em>helper implementations</em>: {@link SimpleInstrumentListener} or |
78 * {@link SimpleASTInstrumentListener}. These re-route all <em>execution returns</em> to a single | |
79 * method, ignoring return values, so only two methods (for "enter" and "return") will notify all | |
80 * events.</li> | |
63 * </ol> | 81 * </ol> |
64 * <p> | 82 * <p> |
65 * <h4>General guidelines for listener implementation:</h4> | 83 * <h4>General guidelines for {@link ASTInstrumentListener} implementation:</h4> |
66 * <p> | 84 * <p> |
67 * When an Instrument is attached to a Probe, the listener effectively becomes part of the executing | 85 * Unlike the listener interface {@link InstrumentListener}, which isolates implementations |
68 * GL program; performance can be affected by the listener's implementation. | 86 * completely from Truffle internals (and is thus <em>Truffle-safe</em>), implementations of |
87 * {@link ASTInstrumentListener} can interact directly with (and potentially affect) Truffle | |
88 * execution in general and Truffle optimization in particular. For example, it is possible to | |
89 * implement a debugger with this interface. | |
90 * </p> | |
91 * <p> | |
92 * As a consequence, implementations of {@link ASTInstrumentListener} effectively become part of the | |
93 * Truffle execution and must be coded according to general guidelines for Truffle implementations. | |
94 * For example: | |
69 * <ul> | 95 * <ul> |
70 * <li>Do not store {@link Frame} or {@link Node} references in fields.</li> | 96 * <li>Do not store {@link Frame} or {@link Node} references in fields.</li> |
71 * <li>Prefer {@code final} fields and (where performance is important) short methods.</li> | 97 * <li>Prefer {@code final} fields and (where performance is important) short methods.</li> |
72 * <li>If needed, pass along the {@link VirtualFrame} reference from an event notification as far as | 98 * <li>If needed, pass along the {@link VirtualFrame} reference from an event notification as far as |
73 * possible through code that is expected to be inlined, since this incurs no runtime overhead. When | 99 * possible through code that is expected to be inlined, since this incurs no runtime overhead. When |
76 * <li>If a listener calls back to its tool during event handling, and if performance is an issue, | 102 * <li>If a listener calls back to its tool during event handling, and if performance is an issue, |
77 * then this should be through a final "callback" field in the instrument, and the called methods | 103 * then this should be through a final "callback" field in the instrument, and the called methods |
78 * should be minimal.</li> | 104 * should be minimal.</li> |
79 * <li>On the other hand, implementations should prevent Truffle from inlining beyond a reasonable | 105 * <li>On the other hand, implementations should prevent Truffle from inlining beyond a reasonable |
80 * point with the method annotation {@link TruffleBoundary}.</li> | 106 * point with the method annotation {@link TruffleBoundary}.</li> |
81 * <li>The implicit "outer" pointer in a non-static inner class is a useful way to implement | 107 * <li>The implicit "outer" pointer in a non-static inner class is a useful (and |
82 * callbacks to owner tools.</li> | 108 * Truffle-optimizable) way to implement callbacks to owner tools.</li> |
83 * <li>Primitive-valued return events are boxed for notification, but Truffle will eliminate the | 109 * <li>Primitive-valued return events are boxed for event notification, but Truffle will eliminate |
84 * boxing if they are cast back to their primitive values quickly (in particular before crossing any | 110 * the boxing if they are cast back to their primitive values quickly (in particular before crossing |
85 * {@link TruffleBoundary} annotations). | 111 * any {@link TruffleBoundary} annotations). |
86 * </ul> | 112 * </ul> |
87 * <p> | 113 * <p> |
88 * <h4>Allowing for AST cloning:</h4> | 114 * <h4>Allowing for AST cloning:</h4> |
89 * <p> | 115 * <p> |
90 * Truffle routinely <em>clones</em> ASTs, which has consequences for listener implementation. | 116 * Truffle routinely <em>clones</em> ASTs, which has consequences for implementations of |
117 * {@link ASTInstrumentListener} (but not for implementations of {@link InstrumentListener}, from | |
118 * which cloning is hidden). | |
91 * <ul> | 119 * <ul> |
92 * <li>Even though a {@link Probe} is uniquely associated with a particular location in the | 120 * <li>Even though a {@link Probe} is uniquely associated with a particular location in the |
93 * executing Guest Language program, execution events at that location will in general be | 121 * executing Guest Language program, execution events at that location will in general be |
94 * implemented by different {@link Node} instances, i.e. <em>clones</em> of the originally probed | 122 * implemented by different {@link Node} instances, i.e. <em>clones</em> of the originally probed |
95 * node.</li> | 123 * node.</li> |
96 * <li>Because of <em>cloning</em> the {@link Node} supplied with notifications to a particular | 124 * <li>Because of <em>cloning</em> the {@link Node} supplied with notifications to a particular |
97 * listener will vary, but because they all represent the same GL program location the events should | 125 * listener will vary, but because they all represent the same GL program location the events should |
98 * be treated as equivalent for most purposes.</li> | 126 * be treated as equivalent for most purposes.</li> |
99 * </ul> | 127 * </ul> |
100 * <p> | 128 * <p> |
101 * <h4>Access to execution state:</h4> | 129 * <h4>Access to execution state via {@link ASTInstrumentListener}:</h4> |
102 * <p> | 130 * <p> |
103 * <ul> | 131 * <ul> |
104 * <li>Event notification arguments provide primary access to the GL program's execution states: | 132 * <li>Notification arguments provide primary access to the GL program's execution states: |
105 * <ul> | 133 * <ul> |
106 * <li>{@link Node}: the concrete node (in one of the AST's clones) from which the event originated. | 134 * <li>{@link Node}: the concrete node (in one of the AST's clones) from which the event originated. |
107 * </li> | 135 * </li> |
108 * <li>{@link VirtualFrame}: the current execution frame. | 136 * <li>{@link VirtualFrame}: the current execution frame. |
109 * </ul> | 137 * </ul> |
110 * <li>Some global information is available, for example the execution | 138 * <li>Truffle global information is available, for example the execution |
111 * {@linkplain TruffleRuntime#iterateFrames(FrameInstanceVisitor) stack}.</li> | 139 * {@linkplain TruffleRuntime#iterateFrames(FrameInstanceVisitor) stack}.</li> |
112 * <li>Additional information needed by a listener could be stored when created, preferably | 140 * <li>Additional API access to execution state may be added in the future.</li> |
113 * {@code final} of course. For example, a reference to the {@link Probe} to which the listener's | |
114 * Instrument has been attached would give access to its corresponding | |
115 * {@linkplain Probe#getProbedSourceSection() source location} or to the collection of | |
116 * {@linkplain SyntaxTag tags} currently applied to the Probe.</li> | |
117 * </ul> | 141 * </ul> |
118 * <p> | 142 * <p> |
119 * <h4>Activating and deactivating Instruments:</h4> | 143 * <h4>Activating and deactivating Instruments:</h4> |
120 * <p> | 144 * <p> |
121 * Instruments are <em>single-use</em>: | 145 * Instruments are <em>single-use</em>: |
123 * <li>An instrument becomes active only when <em>attached</em> to a Probe via | 147 * <li>An instrument becomes active only when <em>attached</em> to a Probe via |
124 * {@link Probe#attach(Instrument)}, and it may only be attached to a single Probe. It is a runtime | 148 * {@link Probe#attach(Instrument)}, and it may only be attached to a single Probe. It is a runtime |
125 * error to attempt attaching a previously attached instrument.</li> | 149 * error to attempt attaching a previously attached instrument.</li> |
126 * <li>Attaching an instrument modifies every existing clone of the AST to which it is being | 150 * <li>Attaching an instrument modifies every existing clone of the AST to which it is being |
127 * attached, which can trigger deoptimization.</li> | 151 * attached, which can trigger deoptimization.</li> |
128 * <li>The method {@link TruffleEventInstrument#dispose()} makes an instrument inactive by removing | 152 * <li>The method {@link Instrument#dispose()} makes an instrument inactive by removing it from the |
129 * it from the Probe to which it was attached and rendering it permanently inert.</li> | 153 * Probe to which it was attached and rendering it permanently inert.</li> |
130 * <li>Disposal removes the implementation of an instrument from all ASTs to which it was attached, | 154 * <li>Disposal removes the implementation of an instrument from all ASTs to which it was attached, |
131 * which can trigger deoptimization.</li> | 155 * which can trigger deoptimization.</li> |
132 * </ul> | 156 * </ul> |
133 * <p> | 157 * <p> |
134 * <h4>Sharing listeners:</h4> | 158 * <h4>Sharing listeners:</h4> |
140 * would be created with the same listener. | 164 * would be created with the same listener. |
141 * <p> | 165 * <p> |
142 * <strong>Disclaimer:</strong> experimental; under development. | 166 * <strong>Disclaimer:</strong> experimental; under development. |
143 * | 167 * |
144 * @see Probe | 168 * @see Probe |
145 * @see TruffleEventListener | 169 * @see TruffleEvents |
146 */ | 170 */ |
147 public abstract class Instrument { | 171 public abstract class Instrument { |
148 | 172 |
149 /** | 173 /** |
150 * Creates an instrument that will route execution events to a listener. | 174 * Creates an instrument that will route execution events to a listener. |
151 * | 175 * |
152 * @param listener a listener for event generated by the instrument | 176 * @param listener a minimal listener for event generated by the instrument. |
153 * @param instrumentInfo optional description of the instrument's role | 177 * @param instrumentInfo optional description of the instrument's role, useful for debugging. |
154 * @return a new instrument, ready for attachment at a probe | 178 * @return a new instrument, ready for attachment at a probe |
155 */ | 179 */ |
156 public static Instrument create(TruffleEventListener listener, String instrumentInfo) { | 180 public static Instrument create(InstrumentListener listener, String instrumentInfo) { |
157 return new TruffleEventInstrument(listener, instrumentInfo); | 181 return new BasicInstrument(listener, instrumentInfo); |
158 } | 182 } |
159 | 183 |
160 /** | 184 /** |
161 * Creates an instrument that will route execution events to a listener. | 185 * Creates an instrument that will route execution events to a listener, along with access to |
162 */ | 186 * internal execution state. |
163 public static Instrument create(TruffleEventListener listener) { | 187 * |
164 return new TruffleEventInstrument(listener, null); | 188 * @param astListener a listener for event generated by the instrument that provides access to |
189 * internal execution state | |
190 * @param instrumentInfo optional description of the instrument's role, useful for debugging. | |
191 * @return a new instrument, ready for attachment at a probe | |
192 */ | |
193 public static Instrument create(ASTInstrumentListener astListener, String instrumentInfo) { | |
194 return new ASTInstrument(astListener, instrumentInfo); | |
165 } | 195 } |
166 | 196 |
167 // TODO (mlvdv) experimental | 197 // TODO (mlvdv) experimental |
168 /** | 198 /** |
169 * For implementation testing. | 199 * For implementation testing. |
175 /** | 205 /** |
176 * Has this instrument been disposed? stays true once set. | 206 * Has this instrument been disposed? stays true once set. |
177 */ | 207 */ |
178 private boolean isDisposed = false; | 208 private boolean isDisposed = false; |
179 | 209 |
180 private Probe probe = null; | 210 protected Probe probe = null; |
181 | 211 |
182 /** | 212 /** |
183 * Optional documentation, mainly for debugging. | 213 * Optional documentation, mainly for debugging. |
184 */ | 214 */ |
185 private final String instrumentInfo; | 215 private final String instrumentInfo; |
218 */ | 248 */ |
219 boolean isDisposed() { | 249 boolean isDisposed() { |
220 return isDisposed; | 250 return isDisposed; |
221 } | 251 } |
222 | 252 |
223 abstract InstrumentNode addToChain(InstrumentNode nextNode); | 253 abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode); |
224 | 254 |
225 /** | 255 /** |
226 * Removes this instrument from an instrument chain. | 256 * An instrument that propagates events to an instance of {@link InstrumentListener}. |
227 */ | 257 */ |
228 abstract InstrumentNode removeFromChain(InstrumentNode instrumentNode); | 258 private static final class BasicInstrument extends Instrument { |
229 | |
230 private static final class TruffleEventInstrument extends Instrument { | |
231 | 259 |
232 /** | 260 /** |
233 * Tool-supplied listener for events. | 261 * Tool-supplied listener for events. |
234 */ | 262 */ |
235 private final TruffleEventListener toolEventListener; | 263 private final InstrumentListener instrumentListener; |
236 | 264 |
237 private TruffleEventInstrument(TruffleEventListener listener, String instrumentInfo) { | 265 private BasicInstrument(InstrumentListener basicListener, String instrumentInfo) { |
238 super(instrumentInfo); | 266 super(instrumentInfo); |
239 this.toolEventListener = listener; | 267 this.instrumentListener = basicListener; |
240 } | 268 } |
241 | 269 |
242 @Override | 270 @Override |
243 InstrumentNode addToChain(InstrumentNode nextNode) { | 271 AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { |
244 return new TruffleEventInstrumentNode(nextNode); | 272 return new BasicInstrumentNode(nextNode); |
245 } | 273 } |
246 | 274 |
247 @Override | 275 @Override |
248 InstrumentNode removeFromChain(InstrumentNode instrumentNode) { | 276 AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { |
249 boolean found = false; | 277 boolean found = false; |
250 if (instrumentNode != null) { | 278 if (instrumentNode != null) { |
251 if (instrumentNode.getInstrument() == this) { | 279 if (instrumentNode.getInstrument() == this) { |
252 // Found the match at the head of the chain | 280 // Found the match at the head of the chain |
253 return instrumentNode.nextInstrument; | 281 return instrumentNode.nextInstrument; |
254 } | 282 } |
255 // Match not at the head of the chain; remove it. | 283 // Match not at the head of the chain; remove it. |
256 found = instrumentNode.removeFromChain(TruffleEventInstrument.this); | 284 found = instrumentNode.removeFromChain(BasicInstrument.this); |
257 } | 285 } |
258 if (!found) { | 286 if (!found) { |
259 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); | 287 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); |
260 } | 288 } |
261 return instrumentNode; | 289 return instrumentNode; |
262 } | 290 } |
263 | 291 |
264 @NodeInfo(cost = NodeCost.NONE) | 292 @NodeInfo(cost = NodeCost.NONE) |
265 private final class TruffleEventInstrumentNode extends InstrumentNode { | 293 private final class BasicInstrumentNode extends AbstractInstrumentNode { |
266 | 294 |
267 private TruffleEventInstrumentNode(InstrumentNode nextNode) { | 295 private BasicInstrumentNode(AbstractInstrumentNode nextNode) { |
268 super(nextNode); | 296 super(nextNode); |
269 } | 297 } |
270 | 298 |
271 public void enter(Node node, VirtualFrame vFrame) { | 299 public void enter(Node node, VirtualFrame vFrame) { |
272 TruffleEventInstrument.this.toolEventListener.enter(node, vFrame); | 300 BasicInstrument.this.instrumentListener.enter(BasicInstrument.this.probe); |
273 if (nextInstrument != null) { | 301 if (nextInstrument != null) { |
274 nextInstrument.enter(node, vFrame); | 302 nextInstrument.enter(node, vFrame); |
275 } | 303 } |
276 } | 304 } |
277 | 305 |
278 public void returnVoid(Node node, VirtualFrame vFrame) { | 306 public void returnVoid(Node node, VirtualFrame vFrame) { |
279 TruffleEventInstrument.this.toolEventListener.returnVoid(node, vFrame); | 307 BasicInstrument.this.instrumentListener.returnVoid(BasicInstrument.this.probe); |
280 if (nextInstrument != null) { | 308 if (nextInstrument != null) { |
281 nextInstrument.returnVoid(node, vFrame); | 309 nextInstrument.returnVoid(node, vFrame); |
282 } | 310 } |
283 } | 311 } |
284 | 312 |
285 public void returnValue(Node node, VirtualFrame vFrame, Object result) { | 313 public void returnValue(Node node, VirtualFrame vFrame, Object result) { |
286 TruffleEventInstrument.this.toolEventListener.returnValue(node, vFrame, result); | 314 BasicInstrument.this.instrumentListener.returnValue(BasicInstrument.this.probe, result); |
287 if (nextInstrument != null) { | 315 if (nextInstrument != null) { |
288 nextInstrument.returnValue(node, vFrame, result); | 316 nextInstrument.returnValue(node, vFrame, result); |
289 } | 317 } |
290 } | 318 } |
291 | 319 |
292 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { | 320 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { |
293 TruffleEventInstrument.this.toolEventListener.returnExceptional(node, vFrame, exception); | 321 BasicInstrument.this.instrumentListener.returnExceptional(BasicInstrument.this.probe, exception); |
294 if (nextInstrument != null) { | 322 if (nextInstrument != null) { |
295 nextInstrument.returnExceptional(node, vFrame, exception); | 323 nextInstrument.returnExceptional(node, vFrame, exception); |
296 } | 324 } |
297 } | 325 } |
298 | 326 |
299 public String instrumentationInfo() { | 327 public String instrumentationInfo() { |
300 final String info = getInstrumentInfo(); | 328 final String info = getInstrumentInfo(); |
301 return info != null ? info : toolEventListener.getClass().getSimpleName(); | 329 return info != null ? info : instrumentListener.getClass().getSimpleName(); |
302 } | 330 } |
303 } | 331 } |
304 | 332 } |
305 } | 333 |
306 | 334 /** |
307 public interface TruffleOptListener { | 335 * Removes this instrument from an instrument chain. |
308 void notifyIsCompiled(boolean isCompiled); | 336 */ |
309 } | 337 abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode); |
310 | 338 |
311 private static final class TruffleOptInstrument extends Instrument { | 339 /** |
312 | 340 * An instrument that propagates events to an instance of {@link ASTInstrumentListener}. |
313 private final TruffleOptListener toolOptListener; | 341 */ |
314 | 342 private static final class ASTInstrument extends Instrument { |
315 private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) { | 343 |
344 /** | |
345 * Tool-supplied listener for AST events. | |
346 */ | |
347 private final ASTInstrumentListener astListener; | |
348 | |
349 private ASTInstrument(ASTInstrumentListener astListener, String instrumentInfo) { | |
316 super(instrumentInfo); | 350 super(instrumentInfo); |
317 this.toolOptListener = listener; | 351 this.astListener = astListener; |
318 } | 352 } |
319 | 353 |
320 @Override | 354 @Override |
321 InstrumentNode addToChain(InstrumentNode nextNode) { | 355 AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { |
322 return new TruffleOptInstrumentNode(nextNode); | 356 return new ASTInstrumentNode(nextNode); |
323 } | 357 } |
324 | 358 |
325 @Override | 359 @Override |
326 InstrumentNode removeFromChain(InstrumentNode instrumentNode) { | 360 AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { |
327 boolean found = false; | 361 boolean found = false; |
328 if (instrumentNode != null) { | 362 if (instrumentNode != null) { |
329 if (instrumentNode.getInstrument() == this) { | 363 if (instrumentNode.getInstrument() == this) { |
330 // Found the match at the head of the chain | 364 // Found the match at the head of the chain |
331 return instrumentNode.nextInstrument; | 365 return instrumentNode.nextInstrument; |
332 } | 366 } |
333 // Match not at the head of the chain; remove it. | 367 // Match not at the head of the chain; remove it. |
334 found = instrumentNode.removeFromChain(TruffleOptInstrument.this); | 368 found = instrumentNode.removeFromChain(ASTInstrument.this); |
335 } | 369 } |
336 if (!found) { | 370 if (!found) { |
337 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); | 371 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); |
338 } | 372 } |
339 return instrumentNode; | 373 return instrumentNode; |
340 } | 374 } |
341 | 375 |
342 @NodeInfo(cost = NodeCost.NONE) | 376 @NodeInfo(cost = NodeCost.NONE) |
343 private final class TruffleOptInstrumentNode extends InstrumentNode { | 377 private final class ASTInstrumentNode extends AbstractInstrumentNode { |
378 | |
379 private ASTInstrumentNode(AbstractInstrumentNode nextNode) { | |
380 super(nextNode); | |
381 } | |
382 | |
383 public void enter(Node node, VirtualFrame vFrame) { | |
384 ASTInstrument.this.astListener.enter(ASTInstrument.this.probe, node, vFrame); | |
385 if (nextInstrument != null) { | |
386 nextInstrument.enter(node, vFrame); | |
387 } | |
388 } | |
389 | |
390 public void returnVoid(Node node, VirtualFrame vFrame) { | |
391 ASTInstrument.this.astListener.returnVoid(ASTInstrument.this.probe, node, vFrame); | |
392 if (nextInstrument != null) { | |
393 nextInstrument.returnVoid(node, vFrame); | |
394 } | |
395 } | |
396 | |
397 public void returnValue(Node node, VirtualFrame vFrame, Object result) { | |
398 ASTInstrument.this.astListener.returnValue(ASTInstrument.this.probe, node, vFrame, result); | |
399 if (nextInstrument != null) { | |
400 nextInstrument.returnValue(node, vFrame, result); | |
401 } | |
402 } | |
403 | |
404 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { | |
405 ASTInstrument.this.astListener.returnExceptional(ASTInstrument.this.probe, node, vFrame, exception); | |
406 if (nextInstrument != null) { | |
407 nextInstrument.returnExceptional(node, vFrame, exception); | |
408 } | |
409 } | |
410 | |
411 public String instrumentationInfo() { | |
412 final String info = getInstrumentInfo(); | |
413 return info != null ? info : astListener.getClass().getSimpleName(); | |
414 } | |
415 } | |
416 | |
417 } | |
418 | |
419 public interface TruffleOptListener { | |
420 void notifyIsCompiled(boolean isCompiled); | |
421 } | |
422 | |
423 private static final class TruffleOptInstrument extends Instrument { | |
424 | |
425 private final TruffleOptListener toolOptListener; | |
426 | |
427 private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) { | |
428 super(instrumentInfo); | |
429 this.toolOptListener = listener; | |
430 } | |
431 | |
432 @Override | |
433 AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { | |
434 return new TruffleOptInstrumentNode(nextNode); | |
435 } | |
436 | |
437 @Override | |
438 AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { | |
439 boolean found = false; | |
440 if (instrumentNode != null) { | |
441 if (instrumentNode.getInstrument() == this) { | |
442 // Found the match at the head of the chain | |
443 return instrumentNode.nextInstrument; | |
444 } | |
445 // Match not at the head of the chain; remove it. | |
446 found = instrumentNode.removeFromChain(TruffleOptInstrument.this); | |
447 } | |
448 if (!found) { | |
449 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); | |
450 } | |
451 return instrumentNode; | |
452 } | |
453 | |
454 @NodeInfo(cost = NodeCost.NONE) | |
455 private final class TruffleOptInstrumentNode extends AbstractInstrumentNode { | |
344 | 456 |
345 private boolean isCompiled; | 457 private boolean isCompiled; |
346 | 458 |
347 private TruffleOptInstrumentNode(InstrumentNode nextNode) { | 459 private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) { |
348 super(nextNode); | 460 super(nextNode); |
349 this.isCompiled = CompilerDirectives.inCompiledCode(); | 461 this.isCompiled = CompilerDirectives.inCompiledCode(); |
350 } | 462 } |
351 | 463 |
352 public void enter(Node node, VirtualFrame vFrame) { | 464 public void enter(Node node, VirtualFrame vFrame) { |
384 } | 496 } |
385 | 497 |
386 } | 498 } |
387 | 499 |
388 @NodeInfo(cost = NodeCost.NONE) | 500 @NodeInfo(cost = NodeCost.NONE) |
389 abstract class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode { | 501 abstract class AbstractInstrumentNode extends Node implements TruffleEvents, InstrumentationNode { |
390 @Child protected InstrumentNode nextInstrument; | 502 |
391 | 503 @Child protected AbstractInstrumentNode nextInstrument; |
392 protected InstrumentNode(InstrumentNode nextNode) { | 504 |
505 protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) { | |
393 this.nextInstrument = nextNode; | 506 this.nextInstrument = nextNode; |
394 } | 507 } |
395 | 508 |
396 @Override | 509 @Override |
397 public boolean isInstrumentable() { | 510 public boolean isInstrumentable() { |