# HG changeset patch # User Michael Van De Vanter # Date 1407778538 25200 # Node ID 8c606e8053b8d1ef6e30b673f2e47c78dcdb2854 # Parent 9d55732d0880d933940a4b3cfe44bef978f201bb Truffle/API test: additional documentation on the new instrumentation tests; move into project with other tests and add an entry in package-info.java diff -r 9d55732d0880 -r 8c606e8053b8 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java Mon Aug 11 10:35:38 2014 -0700 @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test; + +import java.util.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.*; + +/** + *

AST Instrumentation

+ * + * Instrumentation allows the insertion into Truffle ASTs language-specific instances of + * {@link Wrapper} that propagate {@link ExecutionEvents} through a {@link Probe} to any instances + * of {@link Instrument} that might be attached to the particular probe by tools. + *
    + *
  1. Creates a simple add AST
  2. + *
  3. Verifies its structure
  4. + *
  5. "Probes" the add node by adding a {@link Wrapper} and associated {@link Probe}
  6. + *
  7. Attaches a simple {@link Instrument} to the node via its {@link Probe}
  8. + *
  9. Verifies the structure of the probed AST
  10. + *
  11. Verifies the execution of the probed AST
  12. + *
  13. Verifies the results observed by the instrument.
  14. + *
+ * To do these tests, several required classes have been implemented in their most basic form, only + * implementing the methods necessary for the tests to pass, with stubs elsewhere. + */ +public class InstrumentationTest { + + @Test + public void test() { + // Build a tree + TruffleRuntime runtime = Truffle.getRuntime(); + TestChildNode leftChild = new TestChildNode(); + TestChildNode rightChild = new TestChildNode(); + TestSourceSection sourceSection = new TestSourceSection(); + TestAddNode addNode = new TestAddNode(leftChild, rightChild, sourceSection); + TestRootNode rootNode = new TestRootNode(addNode); + + // Have to create a call target before checking parent/child relationships + CallTarget target = runtime.createCallTarget(rootNode); + + // Check tree structure + Assert.assertEquals(addNode, leftChild.getParent()); + Assert.assertEquals(addNode, rightChild.getParent()); + Iterator iterator = addNode.getChildren().iterator(); + Assert.assertEquals(leftChild, iterator.next()); + Assert.assertEquals(rightChild, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + Assert.assertEquals(rootNode, addNode.getParent()); + iterator = rootNode.getChildren().iterator(); + Assert.assertEquals(addNode, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + Object result = target.call(); + Assert.assertEquals(42, result); + + // Create another call target, this time with the "probed" add node + TestExecutionContext context = new TestExecutionContext(); + TestWrapper wrapper = new TestWrapper(addNode, context); + rootNode = new TestRootNode(wrapper); + target = runtime.createCallTarget(rootNode); + + // Check the new tree structure + Assert.assertEquals(addNode, leftChild.getParent()); + Assert.assertEquals(addNode, rightChild.getParent()); + iterator = addNode.getChildren().iterator(); + Assert.assertEquals(leftChild, iterator.next()); + Assert.assertEquals(rightChild, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + Assert.assertEquals(wrapper, addNode.getParent()); + iterator = wrapper.getChildren().iterator(); + Assert.assertEquals(addNode, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + Assert.assertEquals(rootNode, wrapper.getParent()); + iterator = rootNode.getChildren().iterator(); + Assert.assertEquals(wrapper, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + result = target.call(); + Assert.assertEquals(42, result); + + // Create some instruments + final TestInstrument instrumentA = new TestInstrument(); + final TestInstrument instrumentB = new TestInstrument(); + + wrapper.getProbe().addInstrument(instrumentA); + + result = target.call(); + Assert.assertEquals(instrumentA.numInstrumentEnter, 1); + Assert.assertEquals(instrumentA.numInstrumentLeave, 1); + Assert.assertEquals(instrumentB.numInstrumentEnter, 0); + Assert.assertEquals(instrumentB.numInstrumentLeave, 0); + Assert.assertEquals(42, result); + + wrapper.getProbe().addInstrument(instrumentB); + + result = target.call(); + Assert.assertEquals(instrumentA.numInstrumentEnter, 2); + Assert.assertEquals(instrumentA.numInstrumentLeave, 2); + Assert.assertEquals(instrumentB.numInstrumentEnter, 1); + Assert.assertEquals(instrumentB.numInstrumentLeave, 1); + Assert.assertEquals(42, result); + + wrapper.getProbe().removeInstrument(instrumentA); + + result = target.call(); + Assert.assertEquals(instrumentA.numInstrumentEnter, 2); + Assert.assertEquals(instrumentA.numInstrumentLeave, 2); + Assert.assertEquals(instrumentB.numInstrumentEnter, 2); + Assert.assertEquals(instrumentB.numInstrumentLeave, 2); + Assert.assertEquals(42, result); + + } + + private class TestRootNode extends RootNode { + @Child private RootNode child; + + public TestRootNode(RootNode child) { + super(null); + this.child = child; + } + + @Override + public Object execute(VirtualFrame frame) { + return child.execute(frame); + } + } + + private class TestAddNode extends RootNode { + + @Child private TestChildNode left; + @Child private TestChildNode right; + + public TestAddNode(TestChildNode left, TestChildNode right, TestSourceSection sourceSection) { + super(sourceSection); + this.left = left; + this.right = right; + } + + @Override + public Object execute(VirtualFrame frame) { + return left.execute() + right.execute(); + } + } + + private class TestChildNode extends Node { + + public TestChildNode() { + super(null); + } + + public int execute() { + return 21; + } + } + + /** + * The wrapper node class is usually language-specific and inherits from the language-specific + * subclass of {@link Node}, not {@RootNode}. + */ + private class TestWrapper extends RootNode implements Wrapper { + @Child private RootNode child; + private Probe probe; + + public TestWrapper(RootNode child, ExecutionContext context) { + this.child = insert(child); + this.probe = context.getProbe(child.getSourceSection()); + } + + public boolean isTaggedAs(SyntaxTag tag) { + return false; + } + + public Iterable getSyntaxTags() { + return null; + } + + public Node getChild() { + return child; + } + + public Probe getProbe() { + return probe; + } + + @Override + public Object execute(VirtualFrame frame) { + probe.enter(child, frame); + Object result; + + try { + result = child.execute(frame); + probe.leave(child, frame, result); + } catch (Exception e) { + probe.leaveExceptional(child, frame, e); + throw (e); + } + return result; + } + } + + /** + * An "empty" description of the source code that might correspond to a particular AST node. The + * instrumentation framework tracks probes that have been inserted by their source location, + * using this as a key. + */ + private class TestSourceSection implements SourceSection { + + public Source getSource() { + return null; + } + + public int getStartLine() { + return 0; + } + + public LineLocation getLineLocation() { + return null; + } + + public int getStartColumn() { + return 0; + } + + public int getCharIndex() { + return 0; + } + + public int getCharLength() { + return 0; + } + + public int getCharEndIndex() { + return 0; + } + + public String getIdentifier() { + return null; + } + + public String getCode() { + return null; + } + + public String getShortDescription() { + return null; + } + + } + + private class TestExecutionContext extends ExecutionContext { + + @Override + public String getLanguageShortName() { + return "test"; + } + + @Override + protected void setSourceCallback(SourceCallback sourceCallback) { + } + + } + + private class TestInstrument extends Instrument { + + public int numInstrumentEnter = 0; + public int numInstrumentLeave = 0; + + @Override + public void enter(Node astNode, VirtualFrame frame) { + numInstrumentEnter++; + } + + @Override + public void leave(Node astNode, VirtualFrame frame, Object result) { + numInstrumentLeave++; + } + } + +} diff -r 9d55732d0880 -r 8c606e8053b8 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/WrapperTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/WrapperTest.java Fri Aug 08 15:54:39 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.test.instrument; - -import java.util.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.source.*; - -/** - * This test does the following: - *
    - *
  1. Creates a simple add AST
  2. - *
  3. Verifies its structure
  4. - *
  5. Instruments the add node
  6. - *
  7. Attaches a simple probe to the instrumented node
  8. - *
  9. Verifies the structure of the instrumented AST
  10. - *
  11. Verifies the execution of the instrumented AST
  12. - *
- * To do these tests, several required classes have been implemented in their most basic form, only - * implementing the methods necessary for the tests to pass, with stubs elsewhere. - */ -public class WrapperTest { - - @Test - public void test() { - // Build a tree - TruffleRuntime runtime = Truffle.getRuntime(); - TestChildNode leftChild = new TestChildNode(); - TestChildNode rightChild = new TestChildNode(); - TestSourceSection sourceSection = new TestSourceSection(); - TestAddNode addNode = new TestAddNode(leftChild, rightChild, sourceSection); - TestRootNode rootNode = new TestRootNode(addNode); - - // Have to create a call target before checking parent/child relationships - CallTarget target = runtime.createCallTarget(rootNode); - - // Check tree structure - Assert.assertEquals(addNode, leftChild.getParent()); - Assert.assertEquals(addNode, rightChild.getParent()); - Iterator iterator = addNode.getChildren().iterator(); - Assert.assertEquals(leftChild, iterator.next()); - Assert.assertEquals(rightChild, iterator.next()); - Assert.assertFalse(iterator.hasNext()); - Assert.assertEquals(rootNode, addNode.getParent()); - iterator = rootNode.getChildren().iterator(); - Assert.assertEquals(addNode, iterator.next()); - Assert.assertFalse(iterator.hasNext()); - Object result = target.call(); - Assert.assertEquals(42, result); - - // Add a wrapper - TestExecutionContext context = new TestExecutionContext(); - TestWrapper wrapper = new TestWrapper(addNode, context); - rootNode = new TestRootNode(wrapper); - target = runtime.createCallTarget(rootNode); - - // Check the new tree structure - Assert.assertEquals(addNode, leftChild.getParent()); - Assert.assertEquals(addNode, rightChild.getParent()); - iterator = addNode.getChildren().iterator(); - Assert.assertEquals(leftChild, iterator.next()); - Assert.assertEquals(rightChild, iterator.next()); - Assert.assertFalse(iterator.hasNext()); - Assert.assertEquals(wrapper, addNode.getParent()); - iterator = wrapper.getChildren().iterator(); - Assert.assertEquals(addNode, iterator.next()); - Assert.assertFalse(iterator.hasNext()); - Assert.assertEquals(rootNode, wrapper.getParent()); - iterator = rootNode.getChildren().iterator(); - Assert.assertEquals(wrapper, iterator.next()); - Assert.assertFalse(iterator.hasNext()); - result = target.call(); - Assert.assertEquals(42, result); - - // Add an instrument - wrapper.getProbe().addInstrument(new TestInstrument()); - - // Check instrument and result - result = target.call(); - Assert.assertEquals(Counter.numInstrumentEnter, 1); - Assert.assertEquals(Counter.numInstrumentLeave, 1); - Assert.assertEquals(42, result); - - } - - private class TestRootNode extends RootNode { - @Child private RootNode child; - - public TestRootNode(RootNode child) { - super(null); - this.child = child; - } - - @Override - public Object execute(VirtualFrame frame) { - return child.execute(frame); - } - } - - private class TestAddNode extends RootNode { - - @Child private TestChildNode left; - @Child private TestChildNode right; - - public TestAddNode(TestChildNode left, TestChildNode right, TestSourceSection sourceSection) { - super(sourceSection); - this.left = left; - this.right = right; - } - - @Override - public Object execute(VirtualFrame frame) { - return left.execute() + right.execute(); - } - } - - private class TestChildNode extends Node { - - public TestChildNode() { - super(null); - } - - public int execute() { - return 21; - } - } - - private class TestWrapper extends RootNode implements Wrapper { - @Child private RootNode child; - private Probe probe; - - public TestWrapper(RootNode child, ExecutionContext context) { - this.child = insert(child); - this.probe = context.getProbe(child.getSourceSection()); - } - - public boolean isTaggedAs(SyntaxTag tag) { - return false; - } - - public Iterable getSyntaxTags() { - return null; - } - - public Node getChild() { - return child; - } - - public Probe getProbe() { - return probe; - } - - @Override - public Object execute(VirtualFrame frame) { - probe.enter(child, frame); - Object result; - - try { - result = child.execute(frame); - probe.leave(child, frame, result); - } catch (Exception e) { - probe.leaveExceptional(child, frame, e); - throw (e); - } - return result; - } - } - - private class TestSourceSection implements SourceSection { - - public Source getSource() { - return null; - } - - public int getStartLine() { - return 0; - } - - public LineLocation getLineLocation() { - return null; - } - - public int getStartColumn() { - return 0; - } - - public int getCharIndex() { - return 0; - } - - public int getCharLength() { - return 0; - } - - public int getCharEndIndex() { - return 0; - } - - public String getIdentifier() { - return null; - } - - public String getCode() { - return null; - } - - public String getShortDescription() { - return null; - } - - } - - private class TestExecutionContext extends ExecutionContext { - - @Override - public String getLanguageShortName() { - return "test"; - } - - @Override - protected void setSourceCallback(SourceCallback sourceCallback) { - - } - - } - - private class TestInstrument extends Instrument { - @Override - public void enter(Node astNode, VirtualFrame frame) { - Counter.numInstrumentEnter++; - } - - @Override - public void leave(Node astNode, VirtualFrame frame, Object result) { - Counter.numInstrumentLeave++; - } - } - - public static class Counter { - - public static int numInstrumentEnter = 0; - public static int numInstrumentLeave = 0; - } -} diff -r 9d55732d0880 -r 8c606e8053b8 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java Fri Aug 08 15:54:39 2014 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java Mon Aug 11 10:35:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ *
  • How to use frames and frame slots to store values local to an activation? {@link com.oracle.truffle.api.test.FrameTest}
  • *
  • How to use type specialization and speculation for frame slots? {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}
  • *
  • How to use type specialization and speculation for node return values? {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}
  • + *
  • How to "instrument" an AST with nodes that can provide access to runtime state from external tools {@link com.oracle.truffle.api.test.InstrumentationTest}
  • * * *