Mercurial > hg > graal-compiler
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 } |