# HG changeset patch # User Thomas Wuerthinger # Date 1423104162 -3600 # Node ID 183f7d3a93e55a113ff8bc297f7cc4cec42813bc # Parent 276bc2752feb7cf216f45a69bf8b46d80b76a85f# Parent b8b8f0fcb8c371581c74917e3b269ab005fb0e9e Merge. diff -r 276bc2752feb -r 183f7d3a93e5 CHANGELOG.md --- a/CHANGELOG.md Thu Feb 05 03:42:23 2015 +0100 +++ b/CHANGELOG.md Thu Feb 05 03:42:42 2015 +0100 @@ -12,6 +12,10 @@ ### Truffle * Added Node#deepCopy as primary method to copy ASTs. * Disable inlining across Truffle boundary by default. New option TruffleInlineAcrossTruffleBoundary default false. +* Node.replace(Node) now guards against non-assignable replacement, and Node.isReplacementSafe(Node) checks in advance. +* Instrumentation: AST "probing" is now safe and implemented by Node.probe(); language implementors need only implement Node.isInstrumentable() and Node.createWrapperNode(). +* Instrumentation: A new framework defines a category of simple "instrumentation tools" that can be created, configured, and installed, after which they autonomously collect execution data of some kind. +* Instrumentation: A new example "instrumentation tool" is a language-agnostic collector of code coverage information (CoverageTracker); there are two other examples. ### Truffle-DSL * All methods enclosed in a @TypeSystem must now be static. diff -r 276bc2752feb -r 183f7d3a93e5 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java Thu Feb 05 03:42:23 2015 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java Thu Feb 05 03:42:42 2015 +0100 @@ -39,12 +39,11 @@ public void testCorrectReplacement() { TestRootNode root = new TestRootNode(); final TestNode oldChild = new TestNode(); + final TestNode newChild = new TestNode(); root.child = oldChild; - assertFalse(oldChild.isReplaceable()); // No parent node + assertFalse(oldChild.isSafelyReplaceableBy(newChild)); // No parent node root.adoptChildren(); - assertTrue(oldChild.isReplaceable()); // Now adopted by parent - final TestNode newChild = new TestNode(); - assertTrue(oldChild.isSafelyReplaceableBy(newChild)); // Parent field type is assignable by + assertTrue(oldChild.isSafelyReplaceableBy(newChild)); // Now adopted by parent // new node oldChild.replace(newChild); root.execute(null); @@ -59,10 +58,11 @@ final TestNode oldChild = new TestNode(); root.child = oldChild; root.adoptChildren(); - final WrongTestNode newChild = new WrongTestNode(); - assertFalse(oldChild.isSafelyReplaceableBy(newChild)); - // Can't test: oldChild.replace(newChild); - // Fails if assertions checked; else unsafe assignment will eventually crash the VM + final TestNode newChild = new TestNode(); + final TestNode strayChild = new TestNode(); + assertFalse(strayChild.isSafelyReplaceableBy(newChild)); // Stray not a child of parent + final WrongTestNode wrongTypeNewChild = new WrongTestNode(); + assertFalse(oldChild.isSafelyReplaceableBy(wrongTypeNewChild)); } private static class TestNode extends Node { diff -r 276bc2752feb -r 183f7d3a93e5 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Thu Feb 05 03:42:23 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Thu Feb 05 03:42:42 2015 +0100 @@ -290,26 +290,10 @@ } /** - * Checks if this node is properly adopted by its parent. - * - * @return {@code true} if it is structurally safe to replace this node. - */ - public final boolean isReplaceable() { - if (getParent() != null) { - for (Node sibling : getParent().getChildren()) { - if (sibling == this) { - return true; - } - } - } - return false; - } - - /** - * Checks if this node can be replaced by another node, both structurally and with type safety. + * Checks if this node can be replaced by another node: tree structure & type. */ public final boolean isSafelyReplaceableBy(Node newNode) { - return isReplaceable() && NodeUtil.isReplacementSafe(getParent(), this, newNode); + return NodeUtil.isReplacementSafe(getParent(), this, newNode); } private void reportReplace(Node oldNode, Node newNode, CharSequence reason) { diff -r 276bc2752feb -r 183f7d3a93e5 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Thu Feb 05 03:42:23 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Thu Feb 05 03:42:42 2015 +0100 @@ -676,26 +676,24 @@ } /** - * Determines whether a proposed child replacement would be type safe. - * - * @param parent non-null node - * @param oldChild non-null existing child of parent - * @param newChild non-null proposed replacement for existing child + * Determines whether a proposed child replacement would be safe: structurally and type. */ public static boolean isReplacementSafe(Node parent, Node oldChild, Node newChild) { assert newChild != null; - final NodeField field = findChildField(parent, oldChild); - if (field == null) { - throw new IllegalArgumentException(); + if (parent != null) { + final NodeField field = findChildField(parent, oldChild); + if (field != null) { + switch (field.getKind()) { + case CHILD: + return field.getType().isAssignableFrom(newChild.getClass()); + case CHILDREN: + return field.getType().getComponentType().isAssignableFrom(newChild.getClass()); + default: + throw new IllegalStateException(); + } + } } - switch (field.getKind()) { - case CHILD: - return field.getType().isAssignableFrom(newChild.getClass()); - case CHILDREN: - return field.getType().getComponentType().isAssignableFrom(newChild.getClass()); - default: - throw new IllegalArgumentException(); - } + return false; } /** Returns all declared fields in the class hierarchy. */