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() {