Mercurial > hg > truffle
comparison truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java @ 21951:9c8c0937da41
Moving all sources into truffle subdirectory
author | Jaroslav Tulach <jaroslav.tulach@oracle.com> |
---|---|
date | Wed, 17 Jun 2015 10:58:08 +0200 |
parents | graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java@36285949c1d5 |
children | ff6f34159b8a |
comparison
equal
deleted
inserted
replaced
21950:2a5011c7e641 | 21951:9c8c0937da41 |
---|---|
1 /* | |
2 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. Oracle designates this | |
8 * particular file as subject to the "Classpath" exception as provided | |
9 * by Oracle in the LICENSE file that accompanied this code. | |
10 * | |
11 * This code is distributed in the hope that it will be useful, but WITHOUT | |
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 * version 2 for more details (a copy is included in the LICENSE file that | |
15 * accompanied this code). | |
16 * | |
17 * You should have received a copy of the GNU General Public License version | |
18 * 2 along with this work; if not, write to the Free Software Foundation, | |
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
20 * | |
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
22 * or visit www.oracle.com if you need additional information or have any | |
23 * questions. | |
24 */ | |
25 package com.oracle.truffle.api.instrument; | |
26 | |
27 import com.oracle.truffle.api.*; | |
28 import com.oracle.truffle.api.frame.*; | |
29 import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; | |
30 import com.oracle.truffle.api.nodes.*; | |
31 import com.oracle.truffle.api.source.*; | |
32 | |
33 // TODO (mlvdv) these statics should not be global. Move them to some kind of context. | |
34 // TODO (mlvdv) migrate factory (together with Probe)? break out nested classes? | |
35 | |
36 /** | |
37 * A <em>binding</em> between: | |
38 * <ol> | |
39 * <li>A {@link Probe}: a source of <em>execution events</em> taking place at a program location in | |
40 * an executing Truffle AST, and</li> | |
41 * <li>A <em>listener</em>: a consumer of execution events on behalf of an external client. | |
42 * </ol> | |
43 * <p> | |
44 * Client-oriented documentation for the use of Instruments is available online at <a | |
45 * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events" | |
46 * >https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events</a> | |
47 * <p> | |
48 * The implementation of Instruments is complicated by the requirement that Truffle be able to clone | |
49 * ASTs at any time. In particular, any instrumentation-supporting Nodes that have been attached to | |
50 * an AST must be cloned along with the AST: AST clones are not permitted to share Nodes. | |
51 * <p> | |
52 * AST cloning is intended to be as <em>transparent</em> as possible to clients. This is encouraged | |
53 * by providing the {@link SimpleInstrumentListener} for clients that need know nothing more than | |
54 * the properties associated with a Probe: it's {@link SourceSection} and any associated instances | |
55 * of {@link SyntaxTag}. | |
56 * <p> | |
57 * AST cloning is <em>not transparent</em> to clients that use the | |
58 * {@link StandardInstrumentListener}, since those event methods identify the concrete Node instance | |
59 * (and thus the AST instance) where the event takes place. | |
60 * <p> | |
61 * <h4>Implementation Notes: the Life Cycle of an {@link Instrument} at a {@link Probe}</h4> | |
62 * <p> | |
63 * <ul> | |
64 * <li>A new Instrument is created in permanent association with a client-provided | |
65 * <em>listener.</em></li> | |
66 * | |
67 * <li>Multiple Instruments may share a single listener.</li> | |
68 * | |
69 * <li>An Instrument does nothing until it is {@linkplain Probe#attach(Instrument) attached} to a | |
70 * Probe, at which time the Instrument begins routing execution events from the Probe's AST location | |
71 * to the Instrument's listener.</li> | |
72 * | |
73 * <li>Neither Instruments nor Probes are {@link Node}s.</li> | |
74 * | |
75 * <li>A Probe has a single source-based location in an AST, but manages a separate | |
76 * <em>instrumentation chain</em> of Nodes at the equivalent location in each clone of the AST.</li> | |
77 * <li>When a probed AST is cloned, the instrumentation chain associated with each Probe is cloned | |
78 * along with the rest of the AST.</li> | |
79 * | |
80 * <li>When a new Instrument (for example an instance of {@link SimpleInstrument} is attached to a | |
81 * Probe, the Instrument inserts a new instance of its private Node type, | |
82 * {@link SimpleInstrument.SimpleInstrumentNode}, into <em>each of the instrument chains</em> | |
83 * managed by the Probe, i.e. one node instance per existing clone of the AST.</li> | |
84 * | |
85 * <li>If an Instrument is attached to a Probe in an AST that subsequently gets cloned, then the | |
86 * Instrument's private Node type will be cloned along with the rest of the the AST.</li> | |
87 * <li>Each Instrument's private Node type is a dynamic inner class whose only state is in the | |
88 * shared (outer) Instrument instance; that state includes a reference to the Instrument's listener. | |
89 * </li> | |
90 * | |
91 * <li>When an Instrument that has been attached to a Probe is {@linkplain #dispose() disposed}, the | |
92 * Instrument searches every instrument chain associated with the Probe and removes the instance of | |
93 * its private Node type.</li> | |
94 * | |
95 * <li>Attaching and disposing an Instrument at a Probe <em>deoptimizes</em> any compilations of the | |
96 * AST.</li> | |
97 * | |
98 * </ul> | |
99 * | |
100 * @see Probe | |
101 * @see TruffleEvents | |
102 */ | |
103 public abstract class Instrument { | |
104 | |
105 /** | |
106 * Creates a <em>Simple Instrument</em>: this Instrument routes execution events to a | |
107 * client-provided listener. | |
108 * | |
109 * @param listener a listener for execution events | |
110 * @param instrumentInfo optional description of the instrument's role, intended for debugging. | |
111 * @return a new instrument, ready for attachment at a probe | |
112 */ | |
113 public static Instrument create(SimpleInstrumentListener listener, String instrumentInfo) { | |
114 return new SimpleInstrument(listener, instrumentInfo); | |
115 } | |
116 | |
117 /** | |
118 * Creates a <em>Standard Instrument</em>: this Instrument routes execution events, together | |
119 * with access to Truffle execution state, to a client-provided listener. | |
120 * | |
121 * @param standardListener a listener for execution events and execution state | |
122 * @param instrumentInfo optional description of the instrument's role, intended for debugging. | |
123 * @return a new instrument, ready for attachment at a probe | |
124 */ | |
125 public static Instrument create(StandardInstrumentListener standardListener, String instrumentInfo) { | |
126 return new StandardInstrument(standardListener, instrumentInfo); | |
127 } | |
128 | |
129 /** | |
130 * Creates an <em>Advanced Instrument</em>: this Instrument executes efficiently, subject to | |
131 * full Truffle optimization, a client-provided AST fragment every time the Probed node is | |
132 * entered. | |
133 * <p> | |
134 * Any {@link RuntimeException} thrown by execution of the fragment is caught by the framework | |
135 * and reported to the listener; there is no other notification. | |
136 * | |
137 * @param resultListener optional client callback for results/failure notification | |
138 * @param rootFactory provider of AST fragments on behalf of the client | |
139 * @param requiredResultType optional requirement, any non-assignable result is reported to the | |
140 * the listener, if any, as a failure | |
141 * @param instrumentInfo optional description of the instrument's role, intended for debugging. | |
142 * @return a new instrument, ready for attachment at a probe | |
143 */ | |
144 public static Instrument create(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) { | |
145 return new AdvancedInstrument(resultListener, rootFactory, requiredResultType, instrumentInfo); | |
146 } | |
147 | |
148 // TODO (mlvdv) experimental | |
149 /** | |
150 * For implementation testing. | |
151 */ | |
152 public static Instrument create(TruffleOptListener listener) { | |
153 return new TruffleOptInstrument(listener, null); | |
154 } | |
155 | |
156 /** | |
157 * Has this instrument been disposed? stays true once set. | |
158 */ | |
159 private boolean isDisposed = false; | |
160 | |
161 protected Probe probe = null; | |
162 | |
163 /** | |
164 * Optional documentation, mainly for debugging. | |
165 */ | |
166 private final String instrumentInfo; | |
167 | |
168 private Instrument(String instrumentInfo) { | |
169 this.instrumentInfo = instrumentInfo; | |
170 } | |
171 | |
172 /** | |
173 * Gets the {@link Probe} to which this Instrument is currently attached: {@code null} if not | |
174 * yet attached to a Probe or if this Instrument has been {@linkplain #dispose() disposed}. | |
175 */ | |
176 public Probe getProbe() { | |
177 return probe; | |
178 } | |
179 | |
180 /** | |
181 * Removes this Instrument from the Probe to which it attached and renders this Instrument | |
182 * inert. | |
183 * | |
184 * @throws IllegalStateException if this instrument has already been disposed | |
185 */ | |
186 public void dispose() throws IllegalStateException { | |
187 if (isDisposed) { | |
188 throw new IllegalStateException("Attempt to dispose an already disposed Instrumennt"); | |
189 } | |
190 if (probe != null) { | |
191 // It's attached | |
192 probe.disposeInstrument(this); | |
193 probe = null; | |
194 } | |
195 this.isDisposed = true; | |
196 } | |
197 | |
198 /** | |
199 * For internal implementation only. | |
200 */ | |
201 void setAttachedTo(Probe probe) { | |
202 this.probe = probe; | |
203 } | |
204 | |
205 /** | |
206 * Has this instrument been disposed and rendered unusable? | |
207 */ | |
208 boolean isDisposed() { | |
209 return isDisposed; | |
210 } | |
211 | |
212 abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode); | |
213 | |
214 /** | |
215 * Removes this instrument from an instrument chain. | |
216 */ | |
217 abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode); | |
218 | |
219 /** | |
220 * An instrument that propagates events to an instance of {@link SimpleInstrumentListener}. | |
221 */ | |
222 private static final class SimpleInstrument extends Instrument { | |
223 | |
224 /** | |
225 * Tool-supplied listener for events. | |
226 */ | |
227 private final SimpleInstrumentListener simpleListener; | |
228 | |
229 private SimpleInstrument(SimpleInstrumentListener simpleListener, String instrumentInfo) { | |
230 super(instrumentInfo); | |
231 this.simpleListener = simpleListener; | |
232 } | |
233 | |
234 @Override | |
235 AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { | |
236 return new SimpleInstrumentNode(nextNode); | |
237 } | |
238 | |
239 @Override | |
240 AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { | |
241 boolean found = false; | |
242 if (instrumentNode != null) { | |
243 if (instrumentNode.getInstrument() == this) { | |
244 // Found the match at the head of the chain | |
245 return instrumentNode.nextInstrumentNode; | |
246 } | |
247 // Match not at the head of the chain; remove it. | |
248 found = instrumentNode.removeFromChain(SimpleInstrument.this); | |
249 } | |
250 if (!found) { | |
251 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); | |
252 } | |
253 return instrumentNode; | |
254 } | |
255 | |
256 /** | |
257 * Node that implements a {@link SimpleInstrument} in a particular AST. | |
258 */ | |
259 @NodeInfo(cost = NodeCost.NONE) | |
260 private final class SimpleInstrumentNode extends AbstractInstrumentNode { | |
261 | |
262 private SimpleInstrumentNode(AbstractInstrumentNode nextNode) { | |
263 super(nextNode); | |
264 } | |
265 | |
266 public void enter(Node node, VirtualFrame vFrame) { | |
267 SimpleInstrument.this.simpleListener.enter(SimpleInstrument.this.probe); | |
268 if (nextInstrumentNode != null) { | |
269 nextInstrumentNode.enter(node, vFrame); | |
270 } | |
271 } | |
272 | |
273 public void returnVoid(Node node, VirtualFrame vFrame) { | |
274 SimpleInstrument.this.simpleListener.returnVoid(SimpleInstrument.this.probe); | |
275 if (nextInstrumentNode != null) { | |
276 nextInstrumentNode.returnVoid(node, vFrame); | |
277 } | |
278 } | |
279 | |
280 public void returnValue(Node node, VirtualFrame vFrame, Object result) { | |
281 SimpleInstrument.this.simpleListener.returnValue(SimpleInstrument.this.probe, result); | |
282 if (nextInstrumentNode != null) { | |
283 nextInstrumentNode.returnValue(node, vFrame, result); | |
284 } | |
285 } | |
286 | |
287 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { | |
288 SimpleInstrument.this.simpleListener.returnExceptional(SimpleInstrument.this.probe, exception); | |
289 if (nextInstrumentNode != null) { | |
290 nextInstrumentNode.returnExceptional(node, vFrame, exception); | |
291 } | |
292 } | |
293 | |
294 public String instrumentationInfo() { | |
295 final String info = getInstrumentInfo(); | |
296 return info != null ? info : simpleListener.getClass().getSimpleName(); | |
297 } | |
298 } | |
299 } | |
300 | |
301 /** | |
302 * An instrument that propagates events to an instance of {@link StandardInstrumentListener}. | |
303 */ | |
304 private static final class StandardInstrument extends Instrument { | |
305 | |
306 /** | |
307 * Tool-supplied listener for AST events. | |
308 */ | |
309 private final StandardInstrumentListener standardListener; | |
310 | |
311 private StandardInstrument(StandardInstrumentListener standardListener, String instrumentInfo) { | |
312 super(instrumentInfo); | |
313 this.standardListener = standardListener; | |
314 } | |
315 | |
316 @Override | |
317 AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { | |
318 return new StandardInstrumentNode(nextNode); | |
319 } | |
320 | |
321 @Override | |
322 AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { | |
323 boolean found = false; | |
324 if (instrumentNode != null) { | |
325 if (instrumentNode.getInstrument() == this) { | |
326 // Found the match at the head of the chain | |
327 return instrumentNode.nextInstrumentNode; | |
328 } | |
329 // Match not at the head of the chain; remove it. | |
330 found = instrumentNode.removeFromChain(StandardInstrument.this); | |
331 } | |
332 if (!found) { | |
333 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); | |
334 } | |
335 return instrumentNode; | |
336 } | |
337 | |
338 /** | |
339 * Node that implements a {@link StandardInstrument} in a particular AST. | |
340 */ | |
341 @NodeInfo(cost = NodeCost.NONE) | |
342 private final class StandardInstrumentNode extends AbstractInstrumentNode { | |
343 | |
344 private StandardInstrumentNode(AbstractInstrumentNode nextNode) { | |
345 super(nextNode); | |
346 } | |
347 | |
348 public void enter(Node node, VirtualFrame vFrame) { | |
349 standardListener.enter(StandardInstrument.this.probe, node, vFrame); | |
350 if (nextInstrumentNode != null) { | |
351 nextInstrumentNode.enter(node, vFrame); | |
352 } | |
353 } | |
354 | |
355 public void returnVoid(Node node, VirtualFrame vFrame) { | |
356 standardListener.returnVoid(StandardInstrument.this.probe, node, vFrame); | |
357 if (nextInstrumentNode != null) { | |
358 nextInstrumentNode.returnVoid(node, vFrame); | |
359 } | |
360 } | |
361 | |
362 public void returnValue(Node node, VirtualFrame vFrame, Object result) { | |
363 standardListener.returnValue(StandardInstrument.this.probe, node, vFrame, result); | |
364 if (nextInstrumentNode != null) { | |
365 nextInstrumentNode.returnValue(node, vFrame, result); | |
366 } | |
367 } | |
368 | |
369 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { | |
370 standardListener.returnExceptional(StandardInstrument.this.probe, node, vFrame, exception); | |
371 if (nextInstrumentNode != null) { | |
372 nextInstrumentNode.returnExceptional(node, vFrame, exception); | |
373 } | |
374 } | |
375 | |
376 public String instrumentationInfo() { | |
377 final String info = getInstrumentInfo(); | |
378 return info != null ? info : standardListener.getClass().getSimpleName(); | |
379 } | |
380 } | |
381 } | |
382 | |
383 /** | |
384 * An instrument that allows clients to provide an AST fragment to be executed directly from | |
385 * within a Probe's <em>instrumentation chain</em>, and thus directly in the executing Truffle | |
386 * AST with potential for full optimization. | |
387 */ | |
388 private static final class AdvancedInstrument extends Instrument { | |
389 | |
390 private final AdvancedInstrumentResultListener resultListener; | |
391 private final AdvancedInstrumentRootFactory rootFactory; | |
392 private final Class<?> requiredResultType; | |
393 | |
394 private AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) { | |
395 super(instrumentInfo); | |
396 this.resultListener = resultListener; | |
397 this.rootFactory = rootFactory; | |
398 this.requiredResultType = requiredResultType; | |
399 } | |
400 | |
401 @Override | |
402 AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { | |
403 return new AdvancedInstrumentNode(nextNode); | |
404 } | |
405 | |
406 @Override | |
407 AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { | |
408 boolean found = false; | |
409 if (instrumentNode != null) { | |
410 if (instrumentNode.getInstrument() == this) { | |
411 // Found the match at the head of the chain | |
412 return instrumentNode.nextInstrumentNode; | |
413 } | |
414 // Match not at the head of the chain; remove it. | |
415 found = instrumentNode.removeFromChain(AdvancedInstrument.this); | |
416 } | |
417 if (!found) { | |
418 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); | |
419 } | |
420 return instrumentNode; | |
421 } | |
422 | |
423 /** | |
424 * Node that implements a {@link AdvancedInstrument} in a particular AST. | |
425 */ | |
426 @NodeInfo(cost = NodeCost.NONE) | |
427 private final class AdvancedInstrumentNode extends AbstractInstrumentNode { | |
428 | |
429 @Child private AdvancedInstrumentRoot instrumentRoot; | |
430 | |
431 private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) { | |
432 super(nextNode); | |
433 } | |
434 | |
435 public void enter(Node node, VirtualFrame vFrame) { | |
436 if (instrumentRoot == null) { | |
437 try { | |
438 final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node); | |
439 if (newInstrumentRoot != null) { | |
440 instrumentRoot = newInstrumentRoot; | |
441 adoptChildren(); | |
442 AdvancedInstrument.this.probe.invalidateProbeUnchanged(); | |
443 } | |
444 } catch (RuntimeException ex) { | |
445 if (resultListener != null) { | |
446 resultListener.notifyFailure(node, vFrame, ex); | |
447 } | |
448 } | |
449 } | |
450 if (instrumentRoot != null) { | |
451 try { | |
452 final Object result = instrumentRoot.executeRoot(node, vFrame); | |
453 if (resultListener != null) { | |
454 checkResultType(result); | |
455 resultListener.notifyResult(node, vFrame, result); | |
456 } | |
457 } catch (RuntimeException ex) { | |
458 if (resultListener != null) { | |
459 resultListener.notifyFailure(node, vFrame, ex); | |
460 } | |
461 } | |
462 } | |
463 if (nextInstrumentNode != null) { | |
464 nextInstrumentNode.enter(node, vFrame); | |
465 } | |
466 } | |
467 | |
468 private void checkResultType(Object result) { | |
469 if (requiredResultType == null) { | |
470 return; | |
471 } | |
472 if (result == null) { | |
473 throw new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required"); | |
474 } | |
475 if (!(requiredResultType.isAssignableFrom(result.getClass()))) { | |
476 throw new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName()); | |
477 } | |
478 } | |
479 | |
480 public void returnVoid(Node node, VirtualFrame vFrame) { | |
481 if (nextInstrumentNode != null) { | |
482 nextInstrumentNode.returnVoid(node, vFrame); | |
483 } | |
484 } | |
485 | |
486 public void returnValue(Node node, VirtualFrame vFrame, Object result) { | |
487 if (nextInstrumentNode != null) { | |
488 nextInstrumentNode.returnValue(node, vFrame, result); | |
489 } | |
490 } | |
491 | |
492 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { | |
493 if (nextInstrumentNode != null) { | |
494 nextInstrumentNode.returnExceptional(node, vFrame, exception); | |
495 } | |
496 } | |
497 | |
498 public String instrumentationInfo() { | |
499 final String info = getInstrumentInfo(); | |
500 return info != null ? info : rootFactory.getClass().getSimpleName(); | |
501 } | |
502 } | |
503 } | |
504 | |
505 public interface TruffleOptListener { | |
506 void notifyIsCompiled(boolean isCompiled); | |
507 } | |
508 | |
509 private static final class TruffleOptInstrument extends Instrument { | |
510 | |
511 private final TruffleOptListener toolOptListener; | |
512 | |
513 private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) { | |
514 super(instrumentInfo); | |
515 this.toolOptListener = listener; | |
516 } | |
517 | |
518 @Override | |
519 AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { | |
520 return new TruffleOptInstrumentNode(nextNode); | |
521 } | |
522 | |
523 @Override | |
524 AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { | |
525 boolean found = false; | |
526 if (instrumentNode != null) { | |
527 if (instrumentNode.getInstrument() == this) { | |
528 // Found the match at the head of the chain | |
529 return instrumentNode.nextInstrumentNode; | |
530 } | |
531 // Match not at the head of the chain; remove it. | |
532 found = instrumentNode.removeFromChain(TruffleOptInstrument.this); | |
533 } | |
534 if (!found) { | |
535 throw new IllegalStateException("Couldn't find instrument node to remove: " + this); | |
536 } | |
537 return instrumentNode; | |
538 } | |
539 | |
540 @NodeInfo(cost = NodeCost.NONE) | |
541 private final class TruffleOptInstrumentNode extends AbstractInstrumentNode { | |
542 | |
543 private boolean isCompiled; | |
544 | |
545 private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) { | |
546 super(nextNode); | |
547 this.isCompiled = CompilerDirectives.inCompiledCode(); | |
548 } | |
549 | |
550 public void enter(Node node, VirtualFrame vFrame) { | |
551 if (this.isCompiled != CompilerDirectives.inCompiledCode()) { | |
552 this.isCompiled = CompilerDirectives.inCompiledCode(); | |
553 TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled); | |
554 } | |
555 if (nextInstrumentNode != null) { | |
556 nextInstrumentNode.enter(node, vFrame); | |
557 } | |
558 } | |
559 | |
560 public void returnVoid(Node node, VirtualFrame vFrame) { | |
561 if (nextInstrumentNode != null) { | |
562 nextInstrumentNode.returnVoid(node, vFrame); | |
563 } | |
564 } | |
565 | |
566 public void returnValue(Node node, VirtualFrame vFrame, Object result) { | |
567 if (nextInstrumentNode != null) { | |
568 nextInstrumentNode.returnValue(node, vFrame, result); | |
569 } | |
570 } | |
571 | |
572 public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { | |
573 if (nextInstrumentNode != null) { | |
574 nextInstrumentNode.returnExceptional(node, vFrame, exception); | |
575 } | |
576 } | |
577 | |
578 public String instrumentationInfo() { | |
579 final String info = getInstrumentInfo(); | |
580 return info != null ? info : toolOptListener.getClass().getSimpleName(); | |
581 } | |
582 } | |
583 } | |
584 | |
585 @NodeInfo(cost = NodeCost.NONE) | |
586 abstract class AbstractInstrumentNode extends Node implements TruffleEvents, InstrumentationNode { | |
587 | |
588 @Child protected AbstractInstrumentNode nextInstrumentNode; | |
589 | |
590 protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) { | |
591 this.nextInstrumentNode = nextNode; | |
592 } | |
593 | |
594 @Override | |
595 public boolean isInstrumentable() { | |
596 return false; | |
597 } | |
598 | |
599 /** | |
600 * Gets the instrument that created this node. | |
601 */ | |
602 private Instrument getInstrument() { | |
603 return Instrument.this; | |
604 } | |
605 | |
606 /** | |
607 * Removes the node from this chain that was added by a particular instrument, assuming that | |
608 * the head of the chain is not the one to be replaced. This is awkward, but is required | |
609 * because {@link Node#replace(Node)} won't take a {@code null} argument. This doesn't work | |
610 * for the tail of the list, which would be replacing itself with null. So the replacement | |
611 * must be directed the parent of the node being removed. | |
612 */ | |
613 private boolean removeFromChain(Instrument instrument) { | |
614 assert getInstrument() != instrument; | |
615 if (nextInstrumentNode == null) { | |
616 return false; | |
617 } | |
618 if (nextInstrumentNode.getInstrument() == instrument) { | |
619 // Next is the one to remove | |
620 if (nextInstrumentNode.nextInstrumentNode == null) { | |
621 // Next is at the tail; just forget | |
622 nextInstrumentNode = null; | |
623 } else { | |
624 // Replace next with its successor | |
625 nextInstrumentNode.replace(nextInstrumentNode.nextInstrumentNode); | |
626 } | |
627 return true; | |
628 } | |
629 return nextInstrumentNode.removeFromChain(instrument); | |
630 } | |
631 | |
632 protected String getInstrumentInfo() { | |
633 return Instrument.this.instrumentInfo; | |
634 } | |
635 } | |
636 } |