Mercurial > hg > truffle
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java @ 18985:867058575979
Truffle: Improved support for "probing" AST nodes:
- Node.isSafelyReplacaeableBy(Node) checks in advance if Node.replace(Node) would be unsafe (crash the VM).
- Hoist Probe() from language imlementations into Node; now completely language agnostic.
- Language implementations support probing by implementing Node.isInstrumentable() and Node.createWrapperNode()
- Node.Probe() throws ProbeException (without side effects) if the probe fails.
-- ProbeException contains an instance of ProbeFailure that diagnoses the failure in detail
- Additional measures to prevent instrumentation from being applied to internal InstrumentationNodes.
- Promote ProbeListener to top level interface and add a default implementation
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Tue, 27 Jan 2015 20:24:54 -0800 |
parents | 8a758dce7d80 |
children | c7e57dffc5ad |
comparison
equal
deleted
inserted
replaced
18984:0f462015296f | 18985:867058575979 |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 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 | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this | 7 * published by the Free Software Foundation. Oracle designates this |
28 import java.util.*; | 28 import java.util.*; |
29 import java.util.concurrent.*; | 29 import java.util.concurrent.*; |
30 | 30 |
31 import com.oracle.truffle.api.*; | 31 import com.oracle.truffle.api.*; |
32 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; | 32 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; |
33 import com.oracle.truffle.api.instrument.*; | |
34 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode; | |
33 import com.oracle.truffle.api.source.*; | 35 import com.oracle.truffle.api.source.*; |
34 import com.oracle.truffle.api.utilities.*; | 36 import com.oracle.truffle.api.utilities.*; |
35 | 37 |
36 /** | 38 /** |
37 * Abstract base class for all Truffle nodes. | 39 * Abstract base class for all Truffle nodes. |
286 reportReplace(this, newNode, reason); | 288 reportReplace(this, newNode, reason); |
287 onReplace(newNode, reason); | 289 onReplace(newNode, reason); |
288 } | 290 } |
289 | 291 |
290 /** | 292 /** |
291 * Checks if this node is properly adopted by a parent and can be replaced. | 293 * Checks if this node is properly adopted by its parent. |
292 * | 294 * |
293 * @return {@code true} if it is safe to replace this node. | 295 * @return {@code true} if it is structurally safe to replace this node. |
294 */ | 296 */ |
295 public final boolean isReplaceable() { | 297 public final boolean isReplaceable() { |
296 if (getParent() != null) { | 298 if (getParent() != null) { |
297 for (Node sibling : getParent().getChildren()) { | 299 for (Node sibling : getParent().getChildren()) { |
298 if (sibling == this) { | 300 if (sibling == this) { |
299 return true; | 301 return true; |
300 } | 302 } |
301 } | 303 } |
302 } | 304 } |
303 return false; | 305 return false; |
306 } | |
307 | |
308 /** | |
309 * Checks if this node can be replaced by another node, both structurally and with type safety. | |
310 */ | |
311 public final boolean isSafelyReplaceableBy(Node newNode) { | |
312 return isReplaceable() && NodeUtil.isReplacementSafe(getParent(), this, newNode); | |
304 } | 313 } |
305 | 314 |
306 private void reportReplace(Node oldNode, Node newNode, CharSequence reason) { | 315 private void reportReplace(Node oldNode, Node newNode, CharSequence reason) { |
307 Node node = this; | 316 Node node = this; |
308 while (node != null) { | 317 while (node != null) { |
422 } | 431 } |
423 return null; | 432 return null; |
424 } | 433 } |
425 | 434 |
426 /** | 435 /** |
436 * Any node for which this is {@code true} can be "instrumented" by installing a {@link Probe} | |
437 * that intercepts execution events at the node and routes them to any {@link Instrument}s that | |
438 * have been attached to the {@link Probe}. Only one {@link Probe} may be installed at each | |
439 * node; subsequent calls return the one already installed. | |
440 * | |
441 * @see Instrument | |
442 */ | |
443 public boolean isInstrumentable() { | |
444 return false; | |
445 } | |
446 | |
447 /** | |
448 * For any node that {@link #isInstrumentable()}, this method must return a {@link Node} that: | |
449 * <ol> | |
450 * <li>implements {@link WrapperNode}</li> | |
451 * <li>has {@code this} as it's child, and</li> | |
452 * <li>whose type is suitable for (unsafe) replacement of {@code this} in the parent.</li> | |
453 * </ol> | |
454 * | |
455 * @return an appropriately typed {@link WrapperNode} if {@link #isInstrumentable()}. | |
456 */ | |
457 public WrapperNode createWrapperNode() { | |
458 return null; | |
459 } | |
460 | |
461 /** | |
462 * Enables {@linkplain Instrument instrumentation} of a node, where the node is presumed to be | |
463 * part of a well-formed Truffle AST that is not being executed. If this node has not already | |
464 * been probed, modifies the AST by inserting a {@linkplain WrapperNode wrapper node} between | |
465 * the node and its parent; the wrapper node must be provided by implementations of | |
466 * {@link #createWrapperNode()}. No more than one {@link Probe} may be associated with a node, | |
467 * so a {@linkplain WrapperNode wrapper} may not wrap another {@linkplain WrapperNode wrapper}. | |
468 * | |
469 * @return a (possibly newly created) {@link Probe} associated with this node. | |
470 * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged | |
471 */ | |
472 public final Probe probe() { | |
473 | |
474 if (this instanceof WrapperNode) { | |
475 throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null); | |
476 } | |
477 | |
478 if (parent == null) { | |
479 throw new ProbeException(ProbeFailure.Reason.NO_PARENT, null, this, null); | |
480 } | |
481 | |
482 if (parent instanceof WrapperNode) { | |
483 return ((WrapperNode) parent).getProbe(); | |
484 } | |
485 | |
486 if (!isInstrumentable()) { | |
487 throw new ProbeException(ProbeFailure.Reason.NOT_INSTRUMENTABLE, parent, this, null); | |
488 } | |
489 | |
490 // Create a new wrapper/probe with this node as its child. | |
491 final WrapperNode wrapper = createWrapperNode(); | |
492 | |
493 if (wrapper == null || !(wrapper instanceof Node)) { | |
494 throw new ProbeException(ProbeFailure.Reason.NO_WRAPPER, parent, this, wrapper); | |
495 } | |
496 | |
497 final Node wrapperNode = (Node) wrapper; | |
498 | |
499 if (!this.isSafelyReplaceableBy(wrapperNode)) { | |
500 throw new ProbeException(ProbeFailure.Reason.WRAPPER_TYPE, parent, this, wrapper); | |
501 } | |
502 | |
503 // Connect it to a Probe | |
504 final Probe probe = ProbeNode.insertProbe(wrapper); | |
505 | |
506 // Replace this node in the AST with the wrapper | |
507 this.replace(wrapperNode); | |
508 | |
509 return probe; | |
510 } | |
511 | |
512 /** | |
513 * Enables "one-shot", unmodifiable {@linkplain Instrument instrumentation} of a node, where the | |
514 * node is presumed to be part of a well-formed Truffle AST that is not being executed. | |
515 * <p> | |
516 * Modifies the AST by inserting a {@linkplain WrapperNode wrapper node} between the node and | |
517 * its parent; the wrapper node must be provided by implementations of | |
518 * {@link #createWrapperNode()}. | |
519 * <p> | |
520 * Unlike {@link #probe()}, once {@link #probeLite(TruffleEventReceiver)} is called at a node, | |
521 * no additional probing can be added and no additional instrumentation can be attached. | |
522 * <p> | |
523 * This restricted form of instrumentation is intended for special cases where only one kind of | |
524 * instrumentation is desired, and for which performance is a concern | |
525 * | |
526 * @param eventReceiver | |
527 * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged | |
528 */ | |
529 public final void probeLite(TruffleEventReceiver eventReceiver) { | |
530 | |
531 if (this instanceof WrapperNode) { | |
532 throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null); | |
533 } | |
534 | |
535 if (parent == null) { | |
536 throw new ProbeException(ProbeFailure.Reason.NO_PARENT, null, this, null); | |
537 } | |
538 | |
539 if (parent instanceof WrapperNode) { | |
540 throw new ProbeException(ProbeFailure.Reason.LITE_VIOLATION, null, this, null); | |
541 } | |
542 | |
543 if (!isInstrumentable()) { | |
544 throw new ProbeException(ProbeFailure.Reason.NOT_INSTRUMENTABLE, parent, this, null); | |
545 } | |
546 | |
547 // Create a new wrapper/probe with this node as its child. | |
548 final WrapperNode wrapper = createWrapperNode(); | |
549 | |
550 if (wrapper == null || !(wrapper instanceof Node)) { | |
551 throw new ProbeException(ProbeFailure.Reason.NO_WRAPPER, parent, this, wrapper); | |
552 } | |
553 | |
554 final Node wrapperNode = (Node) wrapper; | |
555 | |
556 if (!this.isSafelyReplaceableBy(wrapperNode)) { | |
557 throw new ProbeException(ProbeFailure.Reason.WRAPPER_TYPE, parent, this, wrapper); | |
558 } | |
559 | |
560 // Connect it to a Probe | |
561 ProbeNode.insertProbeLite(wrapper, eventReceiver); | |
562 | |
563 // Replace this node in the AST with the wrapper | |
564 this.replace(wrapperNode); | |
565 } | |
566 | |
567 /** | |
427 * Converts this node to a textual representation useful for debugging. | 568 * Converts this node to a textual representation useful for debugging. |
428 */ | 569 */ |
429 @Override | 570 @Override |
430 public String toString() { | 571 public String toString() { |
431 StringBuilder sb = new StringBuilder(getClass().getSimpleName()); | 572 StringBuilder sb = new StringBuilder(getClass().getSimpleName()); |