comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java @ 19652: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
comparison
equal deleted inserted replaced
19651:3ed1c541f420 19652:10a1fc5e3209
22 * or visit www.oracle.com if you need additional information or have any 22 * or visit www.oracle.com if you need additional information or have any
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.CompilerDirectives.TruffleBoundary; 28 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
28 import com.oracle.truffle.api.*;
29 import com.oracle.truffle.api.frame.*; 29 import com.oracle.truffle.api.frame.*;
30 import com.oracle.truffle.api.instrument.impl.*; 30 import com.oracle.truffle.api.instrument.impl.*;
31 import com.oracle.truffle.api.nodes.*; 31 import com.oracle.truffle.api.nodes.*;
32 32
33 // TODO (mlvdv) migrate some of this to external documentation. 33 // TODO (mlvdv) migrate some of this to external documentation.
34 // 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.
34 /** 36 /**
35 * A dynamically added/removed binding between a {@link Probe}, which provides notification of 37 * A dynamically added/removed binding between a {@link Probe}, which provides notification of
36 * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest 38 * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest
37 * Language (GL) Truffle AST, and a {@linkplain TruffleEventListener listener}, which consumes 39 * Language (GL) Truffle AST, and a {@linkplain TruffleEventListener listener}, which consumes
38 * notifications on behalf of an external tool. 40 * notifications on behalf of an external tool.
42 * <li>Create an implementation of {@link TruffleEventListener} that responds to events on behalf of 44 * <li>Create an implementation of {@link TruffleEventListener} that responds to events on behalf of
43 * a tool.</li> 45 * a tool.</li>
44 * <li>Create an Instrument via factory method {@link Instrument#create(TruffleEventListener)}.</li> 46 * <li>Create an Instrument via factory method {@link Instrument#create(TruffleEventListener)}.</li>
45 * <li>"Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event 47 * <li>"Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event
46 * notifications begin to arrive at the listener.</li> 48 * notifications begin to arrive at the listener.</li>
47 * <li>When no longer needed, "detach" the Instrument via {@link Instrument#dispose()}, at which 49 * <li>When no longer needed, "detach" the Instrument via {@link TruffleEventInstrument#dispose()},
48 * point event notifications to the listener cease, and the Instrument becomes unusable.</li> 50 * at which point event notifications to the listener cease, and the Instrument becomes unusable.</li>
49 * </ol> 51 * </ol>
50 * <p> 52 * <p>
51 * <h4>Options for creating listeners:</h4> 53 * <h4>Options for creating listeners:</h4>
52 * <p> 54 * <p>
53 * <ol> 55 * <ol>
121 * <li>An instrument becomes active only when <em>attached</em> to a Probe via 123 * <li>An instrument becomes active only when <em>attached</em> to a Probe via
122 * {@link Probe#attach(Instrument)}, and it may only be attached to a single Probe. It is a runtime 124 * {@link Probe#attach(Instrument)}, and it may only be attached to a single Probe. It is a runtime
123 * error to attempt attaching a previously attached instrument.</li> 125 * error to attempt attaching a previously attached instrument.</li>
124 * <li>Attaching an instrument modifies every existing clone of the AST to which it is being 126 * <li>Attaching an instrument modifies every existing clone of the AST to which it is being
125 * attached, which can trigger deoptimization.</li> 127 * attached, which can trigger deoptimization.</li>
126 * <li>The method {@link Instrument#dispose()} makes an instrument inactive by removing it from the 128 * <li>The method {@link TruffleEventInstrument#dispose()} makes an instrument inactive by removing
127 * Probe to which it was attached and rendering it permanently inert.</li> 129 * it from the Probe to which it was attached and rendering it permanently inert.</li>
128 * <li>Disposal removes the implementation of an instrument from all ASTs to which it was attached, 130 * <li>Disposal removes the implementation of an instrument from all ASTs to which it was attached,
129 * which can trigger deoptimization.</li> 131 * which can trigger deoptimization.</li>
130 * </ul> 132 * </ul>
131 * <p> 133 * <p>
132 * <h4>Sharing listeners:</h4> 134 * <h4>Sharing listeners:</h4>
140 * <strong>Disclaimer:</strong> experimental; under development. 142 * <strong>Disclaimer:</strong> experimental; under development.
141 * 143 *
142 * @see Probe 144 * @see Probe
143 * @see TruffleEventListener 145 * @see TruffleEventListener
144 */ 146 */
145 public final class Instrument { 147 public abstract class Instrument {
146 148
147 /** 149 /**
148 * Creates an instrument that will route execution events to a listener. 150 * Creates an instrument that will route execution events to a listener.
149 * 151 *
150 * @param listener a listener for event generated by the instrument 152 * @param listener a listener for event generated by the instrument
151 * @param instrumentInfo optional description of the instrument's role 153 * @param instrumentInfo optional description of the instrument's role
152 * @return a new instrument, ready for attachment at a probe 154 * @return a new instrument, ready for attachment at a probe
153 */ 155 */
154 public static Instrument create(TruffleEventListener listener, String instrumentInfo) { 156 public static Instrument create(TruffleEventListener listener, String instrumentInfo) {
155 return new Instrument(listener, instrumentInfo); 157 return new TruffleEventInstrument(listener, instrumentInfo);
156 } 158 }
157 159
158 /** 160 /**
159 * Creates an instrument that will route execution events to a listener. 161 * Creates an instrument that will route execution events to a listener.
160 */ 162 */
161 public static Instrument create(TruffleEventListener listener) { 163 public static Instrument create(TruffleEventListener listener) {
162 return new Instrument(listener, null); 164 return new TruffleEventInstrument(listener, null);
163 } 165 }
164 166
165 /** 167 // TODO (mlvdv) experimental
166 * Tool-supplied listener for events. 168 /**
167 */ 169 * For implementation testing.
168 private final TruffleEventListener toolEventListener; 170 */
171 public static Instrument create(TruffleOptListener listener) {
172 return new TruffleOptInstrument(listener, null);
173 }
174
175 /**
176 * Has this instrument been disposed? stays true once set.
177 */
178 private boolean isDisposed = false;
179
180 private Probe probe = null;
169 181
170 /** 182 /**
171 * Optional documentation, mainly for debugging. 183 * Optional documentation, mainly for debugging.
172 */ 184 */
173 private final String instrumentInfo; 185 private final String instrumentInfo;
174 186
175 /** 187 private Instrument(String instrumentInfo) {
176 * Has this instrument been disposed? stays true once set.
177 */
178 private boolean isDisposed = false;
179
180 private Probe probe = null;
181
182 private Instrument(TruffleEventListener listener, String instrumentInfo) {
183 this.toolEventListener = listener;
184 this.instrumentInfo = instrumentInfo; 188 this.instrumentInfo = instrumentInfo;
185 } 189 }
186 190
187 /** 191 /**
188 * Removes this instrument (and any clones) from the probe to which it attached and renders the 192 * Removes this instrument (and any clones) from the probe to which it attached and renders the
214 */ 218 */
215 boolean isDisposed() { 219 boolean isDisposed() {
216 return isDisposed; 220 return isDisposed;
217 } 221 }
218 222
219 InstrumentNode addToChain(InstrumentNode nextNode) { 223 abstract InstrumentNode addToChain(InstrumentNode nextNode);
220 return new InstrumentNode(nextNode);
221 }
222 224
223 /** 225 /**
224 * Removes this instrument from an instrument chain. 226 * Removes this instrument from an instrument chain.
225 */ 227 */
226 InstrumentNode removeFromChain(InstrumentNode instrumentNode) { 228 abstract InstrumentNode removeFromChain(InstrumentNode instrumentNode);
227 boolean found = false; 229
228 if (instrumentNode != null) { 230 private static final class TruffleEventInstrument extends Instrument {
229 if (instrumentNode.getInstrument() == this) { 231
230 // Found the match at the head of the chain 232 /**
231 return instrumentNode.nextInstrument; 233 * Tool-supplied listener for events.
232 } 234 */
233 // Match not at the head of the chain; remove it. 235 private final TruffleEventListener toolEventListener;
234 found = instrumentNode.removeFromChain(Instrument.this); 236
235 } 237 private TruffleEventInstrument(TruffleEventListener listener, String instrumentInfo) {
236 if (!found) { 238 super(instrumentInfo);
237 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); 239 this.toolEventListener = listener;
238 } 240 }
239 return instrumentNode; 241
242 @Override
243 InstrumentNode addToChain(InstrumentNode nextNode) {
244 return new TruffleEventInstrumentNode(nextNode);
245 }
246
247 @Override
248 InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
249 boolean found = false;
250 if (instrumentNode != null) {
251 if (instrumentNode.getInstrument() == this) {
252 // Found the match at the head of the chain
253 return instrumentNode.nextInstrument;
254 }
255 // Match not at the head of the chain; remove it.
256 found = instrumentNode.removeFromChain(TruffleEventInstrument.this);
257 }
258 if (!found) {
259 throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
260 }
261 return instrumentNode;
262 }
263
264 @NodeInfo(cost = NodeCost.NONE)
265 private final class TruffleEventInstrumentNode extends InstrumentNode {
266
267 private TruffleEventInstrumentNode(InstrumentNode nextNode) {
268 super(nextNode);
269 }
270
271 public void enter(Node node, VirtualFrame vFrame) {
272 TruffleEventInstrument.this.toolEventListener.enter(node, vFrame);
273 if (nextInstrument != null) {
274 nextInstrument.enter(node, vFrame);
275 }
276 }
277
278 public void returnVoid(Node node, VirtualFrame vFrame) {
279 TruffleEventInstrument.this.toolEventListener.returnVoid(node, vFrame);
280 if (nextInstrument != null) {
281 nextInstrument.returnVoid(node, vFrame);
282 }
283 }
284
285 public void returnValue(Node node, VirtualFrame vFrame, Object result) {
286 TruffleEventInstrument.this.toolEventListener.returnValue(node, vFrame, result);
287 if (nextInstrument != null) {
288 nextInstrument.returnValue(node, vFrame, result);
289 }
290 }
291
292 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
293 TruffleEventInstrument.this.toolEventListener.returnExceptional(node, vFrame, exception);
294 if (nextInstrument != null) {
295 nextInstrument.returnExceptional(node, vFrame, exception);
296 }
297 }
298
299 public String instrumentationInfo() {
300 final String info = getInstrumentInfo();
301 return info != null ? info : toolEventListener.getClass().getSimpleName();
302 }
303 }
304
305 }
306
307 public interface TruffleOptListener {
308 void notifyIsCompiled(boolean isCompiled);
309 }
310
311 private static final class TruffleOptInstrument extends Instrument {
312
313 private final TruffleOptListener toolOptListener;
314
315 private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) {
316 super(instrumentInfo);
317 this.toolOptListener = listener;
318 }
319
320 @Override
321 InstrumentNode addToChain(InstrumentNode nextNode) {
322 return new TruffleOptInstrumentNode(nextNode);
323 }
324
325 @Override
326 InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
327 boolean found = false;
328 if (instrumentNode != null) {
329 if (instrumentNode.getInstrument() == this) {
330 // Found the match at the head of the chain
331 return instrumentNode.nextInstrument;
332 }
333 // Match not at the head of the chain; remove it.
334 found = instrumentNode.removeFromChain(TruffleOptInstrument.this);
335 }
336 if (!found) {
337 throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
338 }
339 return instrumentNode;
340 }
341
342 @NodeInfo(cost = NodeCost.NONE)
343 private final class TruffleOptInstrumentNode extends InstrumentNode {
344
345 private boolean isCompiled;
346
347 private TruffleOptInstrumentNode(InstrumentNode nextNode) {
348 super(nextNode);
349 this.isCompiled = CompilerDirectives.inCompiledCode();
350 }
351
352 public void enter(Node node, VirtualFrame vFrame) {
353 if (this.isCompiled != CompilerDirectives.inCompiledCode()) {
354 this.isCompiled = CompilerDirectives.inCompiledCode();
355 TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled);
356 }
357 if (nextInstrument != null) {
358 nextInstrument.enter(node, vFrame);
359 }
360 }
361
362 public void returnVoid(Node node, VirtualFrame vFrame) {
363 if (nextInstrument != null) {
364 nextInstrument.returnVoid(node, vFrame);
365 }
366 }
367
368 public void returnValue(Node node, VirtualFrame vFrame, Object result) {
369 if (nextInstrument != null) {
370 nextInstrument.returnValue(node, vFrame, result);
371 }
372 }
373
374 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
375 if (nextInstrument != null) {
376 nextInstrument.returnExceptional(node, vFrame, exception);
377 }
378 }
379
380 public String instrumentationInfo() {
381 final String info = getInstrumentInfo();
382 return info != null ? info : toolOptListener.getClass().getSimpleName();
383 }
384 }
385
240 } 386 }
241 387
242 @NodeInfo(cost = NodeCost.NONE) 388 @NodeInfo(cost = NodeCost.NONE)
243 final class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode { 389 abstract class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode {
244 390 @Child protected InstrumentNode nextInstrument;
245 @Child private InstrumentNode nextInstrument; 391
246 392 protected InstrumentNode(InstrumentNode nextNode) {
247 private InstrumentNode(InstrumentNode nextNode) {
248 this.nextInstrument = nextNode; 393 this.nextInstrument = nextNode;
249 } 394 }
250 395
251 @Override 396 @Override
252 public boolean isInstrumentable() { 397 public boolean isInstrumentable() {
284 return true; 429 return true;
285 } 430 }
286 return nextInstrument.removeFromChain(instrument); 431 return nextInstrument.removeFromChain(instrument);
287 } 432 }
288 433
289 public void enter(Node node, VirtualFrame vFrame) { 434 protected String getInstrumentInfo() {
290 Instrument.this.toolEventListener.enter(node, vFrame); 435 return Instrument.this.instrumentInfo;
291 if (nextInstrument != null) { 436 }
292 nextInstrument.enter(node, vFrame); 437
293 }
294 }
295
296 public void returnVoid(Node node, VirtualFrame vFrame) {
297 Instrument.this.toolEventListener.returnVoid(node, vFrame);
298 if (nextInstrument != null) {
299 nextInstrument.returnVoid(node, vFrame);
300 }
301 }
302
303 public void returnValue(Node node, VirtualFrame vFrame, Object result) {
304 Instrument.this.toolEventListener.returnValue(node, vFrame, result);
305 if (nextInstrument != null) {
306 nextInstrument.returnValue(node, vFrame, result);
307 }
308 }
309
310 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
311 Instrument.this.toolEventListener.returnExceptional(node, vFrame, exception);
312 if (nextInstrument != null) {
313 nextInstrument.returnExceptional(node, vFrame, exception);
314 }
315 }
316
317 public String instrumentationInfo() {
318 if (Instrument.this.instrumentInfo != null) {
319 return Instrument.this.instrumentInfo;
320 }
321 return toolEventListener.getClass().getSimpleName();
322 }
323 } 438 }
324 439
325 } 440 }