changeset 22755:a48f9b3e01f5

Merge with f74225bf6671d84f00ccf48c3a01040bfa1f6b3b
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Sat, 03 Oct 2015 17:25:59 -0700
parents 1fc7ee8c9443 (diff) f74225bf6671 (current diff)
children c2ce8dd9be05
files
diffstat 2 files changed, 712 insertions(+), 351 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPETestLanguage.java	Sat Oct 03 17:25:59 2015 -0700
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2014, 2015, 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.graal.truffle.test;
+
+import java.io.IOException;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.TruffleRuntime;
+import com.oracle.truffle.api.frame.MaterializedFrame;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.instrument.ASTProber;
+import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener;
+import com.oracle.truffle.api.instrument.AdvancedInstrumentRoot;
+import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory;
+import com.oracle.truffle.api.instrument.EventHandlerNode;
+import com.oracle.truffle.api.instrument.Instrumenter;
+import com.oracle.truffle.api.instrument.KillException;
+import com.oracle.truffle.api.instrument.Probe;
+import com.oracle.truffle.api.instrument.SyntaxTag;
+import com.oracle.truffle.api.instrument.Visualizer;
+import com.oracle.truffle.api.instrument.WrapperNode;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.NodeCost;
+import com.oracle.truffle.api.nodes.NodeInfo;
+import com.oracle.truffle.api.nodes.NodeVisitor;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.api.source.Source;
+
+@TruffleLanguage.Registration(name = "instrumentationPETestLanguage", version = "0", mimeType = "text/x-instPETest")
+public final class InstrumentationPETestLanguage extends TruffleLanguage<Object> {
+
+    public static final InstrumentationPETestLanguage INSTANCE = new InstrumentationPETestLanguage();
+
+    static enum InstrumentTestTag implements SyntaxTag {
+
+        ADD_TAG("addition", "test language addition node"),
+
+        VALUE_TAG("value", "test language value node");
+
+        private final String name;
+        private final String description;
+
+        private InstrumentTestTag(String name, String description) {
+            this.name = name;
+            this.description = description;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+    }
+
+    private InstrumentationPETestLanguage() {
+    }
+
+    @Override
+    protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
+        final TestValueNode valueNode = new TestValueNode(42);
+        final TestRootNode rootNode = new TestRootNode(null, valueNode);
+        final TruffleRuntime runtime = Truffle.getRuntime();
+        final CallTarget callTarget = runtime.createCallTarget(rootNode);
+        return callTarget;
+    }
+
+    @Override
+    protected Object findExportedSymbol(Object context, String globalName, boolean onlyExplicit) {
+        return null;
+    }
+
+    @Override
+    protected Object getLanguageGlobal(Object context) {
+        return null;
+    }
+
+    @Override
+    protected boolean isObjectOfLanguage(Object object) {
+        return false;
+    }
+
+    @Override
+    protected Visualizer getVisualizer() {
+        return null;
+    }
+
+    @Override
+    protected boolean isInstrumentable(Node node) {
+        return node instanceof TestAdditionNode || node instanceof TestValueNode;
+    }
+
+    @Override
+    protected WrapperNode createWrapperNode(Node node) {
+        if (isInstrumentable(node)) {
+            return new TestLanguageWrapperNode((TestLanguageNode) node);
+        }
+        return null;
+    }
+
+    @Override
+    protected Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws IOException {
+        return null;
+    }
+
+    @Override
+    protected AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(String expr, AdvancedInstrumentResultListener resultListener) throws IOException {
+        return null;
+    }
+
+    @Override
+    protected Object createContext(Env env) {
+        return null;
+    }
+
+    static final class TestASTProber implements ASTProber {
+
+        public void probeAST(final Instrumenter instrumenter, RootNode startNode) {
+            startNode.accept(new NodeVisitor() {
+
+                @Override
+                public boolean visit(Node node) {
+                    if (node instanceof TestLanguageNode) {
+
+                        final TestLanguageNode testNode = (TestLanguageNode) node;
+
+                        if (node instanceof TestValueNode) {
+                            instrumenter.probe(testNode).tagAs(InstrumentTestTag.VALUE_TAG, null);
+
+                        } else if (node instanceof TestAdditionNode) {
+                            instrumenter.probe(testNode).tagAs(InstrumentTestTag.ADD_TAG, null);
+
+                        }
+                    }
+                    return true;
+                }
+            });
+        }
+    }
+
+    abstract static class TestLanguageNode extends Node {
+        public abstract int execute(VirtualFrame vFrame);
+
+    }
+
+    @NodeInfo(cost = NodeCost.NONE)
+    static class TestLanguageWrapperNode extends TestLanguageNode implements WrapperNode {
+        @Child private TestLanguageNode child;
+        @Child private EventHandlerNode eventHandlerNode;
+
+        public TestLanguageWrapperNode(TestLanguageNode child) {
+            assert !(child instanceof TestLanguageWrapperNode);
+            this.child = child;
+        }
+
+        @Override
+        public String instrumentationInfo() {
+            return "Wrapper node for testing";
+        }
+
+        @Override
+        public void insertEventHandlerNode(EventHandlerNode eventHandler) {
+            this.eventHandlerNode = eventHandler;
+        }
+
+        @Override
+        public Probe getProbe() {
+            return eventHandlerNode.getProbe();
+        }
+
+        @Override
+        public Node getChild() {
+            return child;
+        }
+
+        @Override
+        public int execute(VirtualFrame vFrame) {
+            eventHandlerNode.enter(child, vFrame);
+            int result;
+            try {
+                result = child.execute(vFrame);
+                eventHandlerNode.returnValue(child, vFrame, result);
+            } catch (KillException e) {
+                throw (e);
+            } catch (Exception e) {
+                eventHandlerNode.returnExceptional(child, vFrame, e);
+                throw (e);
+            }
+            return result;
+        }
+    }
+
+    /**
+     * A simple node for our test language to store a value.
+     */
+    static class TestValueNode extends TestLanguageNode {
+        private final int value;
+
+        public TestValueNode(int value) {
+            this.value = value;
+        }
+
+        @Override
+        public int execute(VirtualFrame vFrame) {
+            return value;
+        }
+    }
+
+    /**
+     * A node for our test language that adds up two {@link TestValueNode}s.
+     */
+    static class TestAdditionNode extends TestLanguageNode {
+        @Child private TestLanguageNode leftChild;
+        @Child private TestLanguageNode rightChild;
+
+        public TestAdditionNode(TestValueNode leftChild, TestValueNode rightChild) {
+            this.leftChild = insert(leftChild);
+            this.rightChild = insert(rightChild);
+        }
+
+        @Override
+        public int execute(VirtualFrame vFrame) {
+            return leftChild.execute(vFrame) + rightChild.execute(vFrame);
+        }
+    }
+
+    /**
+     * Truffle requires that all guest languages to have a {@link RootNode} which sits atop any AST
+     * of the guest language. This is necessary since creating a {@link CallTarget} is how Truffle
+     * completes an AST. The root nodes serves as our entry point into a program.
+     */
+    static class TestRootNode extends RootNode {
+        private final String name;
+        @Child private TestLanguageNode body;
+
+        /**
+         * This constructor emulates the global machinery that applies registered probers to every
+         * newly created AST. Global registry is not used, since that would interfere with other
+         * tests run in the same environment.
+         */
+        public TestRootNode(String name, TestLanguageNode body) {
+            super(InstrumentationPETestLanguage.class, null, null);
+            this.name = name;
+            this.body = body;
+        }
+
+        @Override
+        public Object execute(VirtualFrame vFrame) {
+            return body.execute(vFrame);
+        }
+
+        @Override
+        public boolean isCloningAllowed() {
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        /** for testing. */
+        public TestLanguageNode getBody() {
+            return body;
+        }
+    }
+
+    static class TestAdvancedInstrumentCounterRoot extends AdvancedInstrumentRoot {
+
+        private long count;
+
+        @Override
+        public Object executeRoot(Node node, VirtualFrame vFrame) {
+            count++;
+            return null;
+        }
+
+        public long getCount() {
+            return count;
+        }
+
+        public String instrumentationInfo() {
+            return null;
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Sat Oct 03 00:05:38 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Sat Oct 03 17:25:59 2015 -0700
@@ -22,363 +22,414 @@
  */
 package com.oracle.graal.truffle.test;
 
+import java.io.IOException;
+import java.lang.reflect.Field;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.oracle.graal.truffle.test.InstrumentationPETestLanguage.TestRootNode;
+import com.oracle.truffle.api.instrument.ASTProber;
+import com.oracle.truffle.api.instrument.Instrument;
+import com.oracle.truffle.api.instrument.Instrumenter;
+import com.oracle.truffle.api.instrument.Probe;
+import com.oracle.truffle.api.instrument.impl.DefaultSimpleInstrumentListener;
+import com.oracle.truffle.api.instrument.impl.DefaultStandardInstrumentListener;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+
+// TODO add some tests for the replacement for AdvancedInstrumentRootFactory
+
 /**
- * Tests for a single simple PE test with various combinations of instrumentation attached. None of
- * the instrumentation ultimate does anything, so should compile away.
+ * Partial evaluation tests on a constant valued RootNode with various instrumentation operations
+ * applied to it. None of the instrumentation ultimately does anything, so should compile away.
+ * <p>
+ * A specialized test language produces a root with a single constant-valued child, no matter what
+ * source is eval'd.
+ * <p>
+ * Taking care to avoid creating sources that appear equal so there won't be any sharing in the
+ * engine.
  */
 public class InstrumentationPartialEvaluationTest extends PartialEvaluationTest {
 
+    PolyglotEngine vm;
+    Instrumenter instrumenter;
+
     public static Object constant42() {
         return 42;
     }
 
-    // @Test
-    // public void constantValueUninstrumented() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedNoInstruments() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // result.probe();
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedNullInstrument1() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument");
-    // probe.attach(instrument);
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedNullInstrument2() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument");
-    // probe.attach(instrument);
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedNullInstrumentDisposed1() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument");
-    // probe.attach(instrument);
-    // instrument.dispose();
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedNullInstrumentDisposed2() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument");
-    // probe.attach(instrument);
-    // instrument.dispose();
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedTwoNullInstruments1() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument 1");
-    // probe.attach(instrument1);
-    // Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument 2");
-    // probe.attach(instrument2);
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedTwoNullInstruments2() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument 1");
-    // probe.attach(instrument1);
-    // Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument 2");
-    // probe.attach(instrument2);
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedThreeNullInstruments1() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument 1");
-    // probe.attach(instrument1);
-    // Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument 2");
-    // probe.attach(instrument2);
-    // Instrument instrument3 = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument 3");
-    // probe.attach(instrument3);
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedThreeNullInstruments2() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument 1");
-    // probe.attach(instrument1);
-    // Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument 2");
-    // probe.attach(instrument2);
-    // Instrument instrument3 = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument 3");
-    // probe.attach(instrument3);
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedThreeNullInstrumentsOneDisposed1() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument 1");
-    // probe.attach(instrument1);
-    // Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument 2");
-    // probe.attach(instrument2);
-    // Instrument instrument3 = Instrument.create(new DefaultSimpleInstrumentListener(),
-    // "Null test Instrument 3");
-    // probe.attach(instrument3);
-    // instrument2.dispose();
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueProbedThreeNullInstrumentsOneDisposed2() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe probe = result.probe();
-    // Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument 1");
-    // probe.attach(instrument1);
-    // Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument 2");
-    // probe.attach(instrument2);
-    // Instrument instrument3 = Instrument.create(new DefaultStandardInstrumentListener(),
-    // "Null test Instrument 3");
-    // probe.attach(instrument3);
-    // instrument2.dispose();
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueInertAdvancedInstrumentRootFactory() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode result = new ConstantTestNode(42);
-    // RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // root.adoptChildren();
-    // Probe testProbe = result.probe();
-    // // A factory that could insert a AdvancedInstrumentRoot into the AST, but which never does.
-    // Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
-    //
-    // public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
-    // return null;
-    // }
-    // }, null, "test AdvancedInstrument");
-    // testProbe.attach(instrument);
-    //
-    // // It all gets compiled away
-    // assertPartialEvalEquals("constant42", root);
-    // }
-    //
-    // @Test
-    // public void constantValueInertAdvancedInstrumentRoot() {
-    // FrameDescriptor fd = new FrameDescriptor();
-    // AbstractTestNode resultTestNode = new ConstantTestNode(42);
-    // RootTestNode rootTestNode = new RootTestNode(fd, "constantValue", resultTestNode);
-    // rootTestNode.adoptChildren();
-    // Probe testProbe = resultTestNode.probe();
-    // // Factory inserts a AdvancedInstrumentRoot with empty methods into instrumentation .
-    // Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
-    //
-    // @Override
-    // public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
-    // return new AdvancedInstrumentRoot() {
-    //
-    // public String instrumentationInfo() {
-    // return null;
-    // }
-    //
-    // @Override
-    // public Object executeRoot(Node n, VirtualFrame frame) {
-    // return null;
-    // }
-    // };
-    // }
-    // }, null, "test AdvancedInstrument");
-    // testProbe.attach(instrument);
-    //
-    // // It all gets compiled away.
-    // assertPartialEvalEquals("constant42", rootTestNode);
-    // }
-    //
-    // @Test
-    // public void instrumentDeopt() {
-    // final FrameDescriptor fd = new FrameDescriptor();
-    // final AbstractTestNode result = new ConstantTestNode(42);
-    // final RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // final Probe[] probe = new Probe[1];
-    // final int[] count = {1};
-    // count[0] = 0;
-    // // Register a "prober" that will get applied when CallTarget gets created.
-    // final ASTProber prober = new ASTProber() {
-    //
-    // @Override
-    // public void probeAST(Node node) {
-    // node.accept(new NodeVisitor() {
-    //
-    // @Override
-    // public boolean visit(Node visitedNode) {
-    // if (visitedNode instanceof ConstantTestNode) {
-    // probe[0] = visitedNode.probe();
-    // }
-    // return true;
-    // }
-    //
-    // });
-    // }
-    // };
-    // Probe.registerASTProber(prober);
-    // try {
-    // final RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(root);
-    //
-    // // The CallTarget has one Probe, attached to the ConstantTestNode, ready to run
-    // Assert.assertEquals(42, callTarget.call()); // Correct result
-    // Assert.assertEquals(0, count[0]); // Didn't count anything
-    //
-    // // Add a counting instrument; this changes the "Probe state" and should cause a deopt
-    // final Instrument countingInstrument = Instrument.create(new DefaultSimpleInstrumentListener()
-    // {
-    //
-    // @Override
-    // public void enter(Probe p) {
-    // count[0] = count[0] + 1;
-    // }
-    // }, null);
-    // probe[0].attach(countingInstrument);
-    //
-    // Assert.assertEquals(42, callTarget.call()); // Correct result
-    // Assert.assertEquals(1, count[0]); // Counted the first call
-    //
-    // // Remove the counting instrument; this changes the "Probe state" and should cause a
-    // // deopt
-    // countingInstrument.dispose();
-    //
-    // Assert.assertEquals(42, callTarget.call()); // Correct result
-    // Assert.assertEquals(1, count[0]); // Didn't count this time
-    // } finally {
-    // Probe.unregisterASTProber(prober);
-    // }
-    //
-    // }
-    //
-    // /**
-    // * Experimental feature; not yet validated.
-    // */
-    // @Test
-    // public void specialOptInstrument() {
-    // final FrameDescriptor fd = new FrameDescriptor();
-    // final AbstractTestNode result = new ConstantTestNode(42);
-    // final RootTestNode root = new RootTestNode(fd, "constantValue", result);
-    // final Probe[] probe = new Probe[1];
-    // final int[] count = {1};
-    // count[0] = 0;
-    // // Register a "prober" that will get applied when CallTarget gets created.
-    // final ASTProber prober = new ASTProber() {
-    //
-    // @Override
-    // public void probeAST(Node node) {
-    // node.accept(new NodeVisitor() {
-    //
-    // @Override
-    // public boolean visit(Node visitedNode) {
-    // if (visitedNode instanceof ConstantTestNode) {
-    // probe[0] = visitedNode.probe();
-    // }
-    // return true;
-    // }
-    // });
-    // }
-    // };
-    // Probe.registerASTProber(prober);
-    // try {
-    // final RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(root);
-    //
-    // // The CallTarget has one Probe, attached to the ConstantTestNode, ready to run
-    // Assert.assertEquals(42, callTarget.call()); // Correct result
-    //
-    // final boolean[] isCurrentlyCompiled = {false};
-    // final Instrument optInstrument = Instrument.create(new Instrument.TruffleOptListener() {
-    //
-    // @Override
-    // public void notifyIsCompiled(boolean isCompiled) {
-    // isCurrentlyCompiled[0] = isCompiled;
-    // }
-    // });
-    // probe[0].attach(optInstrument);
-    //
-    // Assert.assertEquals(42, callTarget.call()); // Correct result
-    // Assert.assertFalse(isCurrentlyCompiled[0]);
-    //
-    // // TODO (mlvdv) compile, call again, and assert that isCurrentlyCompiled == true
-    //
-    // } finally {
-    // Probe.unregisterASTProber(prober);
-    // }
-    //
-    // }
+    @Before
+    public void before() {
+        // TODO (mlvdv) eventually abstract this
+        try {
+            vm = PolyglotEngine.buildNew().build();
+            final Field field = PolyglotEngine.class.getDeclaredField("instrumenter");
+            field.setAccessible(true);
+            instrumenter = (Instrumenter) field.get(vm);
+            final java.lang.reflect.Field testVMField = Instrumenter.class.getDeclaredField("testVM");
+            testVMField.setAccessible(true);
+            testVMField.set(instrumenter, vm);
+        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
+            fail("Reflective access to Instrumenter for testing");
+        }
+    }
+
+    @Override
+    @After
+    public void after() {
+        vm.dispose();
+        vm = null;
+        instrumenter = null;
+        super.after();
+    }
+
+    // TODO (mlvdv) fix other PE tests; move down the before/after setup
+
+    @Test
+    public void uninstrumented() throws IOException {
+
+        final Source source = Source.fromText("uninstrumented", "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+                root[0] = rootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedNoListeners() throws IOException {
+        final String testName = "probedNoListeners";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node, but attach no listeners
+                instrumenter.probe(testRootNode.getBody());
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithNullSimpleListener() throws IOException {
+        final String testName = "probedWithNullSimpleListener";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach a "simple" empty listener
+                instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithNullStandardListener() throws IOException {
+        final String testName = "probedWithNullStandardListener";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach a "standard" empty listener
+                instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithNullSimpleListenerDisposed() throws IOException {
+        final String testName = "probedWithNullSimpleListenerDisposed";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach a "simple" empty listener
+                final Instrument instrument = instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+                // Detach the listener
+                instrument.dispose();
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithNullStandardListenerDisposed() throws IOException {
+        final String testName = "probedWithNullStandardListenerDisposed";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach a "standard" empty listener
+                final Instrument instrument = instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+                // Detach the listener
+                instrument.dispose();
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithTwoSimpleListeners() throws IOException {
+        final String testName = "probedWithTwoSimpleListeners";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach two "simple" empty listeners
+                instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+                instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithTwoStandardListeners() throws IOException {
+        final String testName = "probedWithTwoStandardListeners";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRotoNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRotoNode.getBody());
+                // Attach two "standard" empty listeners
+                instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+                instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+
+                root[0] = testRotoNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithThreeSimpleListeners() throws IOException {
+        final String testName = "probedWithThreeSimpleListeners";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach three "simple" empty listeners
+                instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+                instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+                instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithThreeStandardListeners() throws IOException {
+        final String testName = "probedWithThreeStandardListeners";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach three "standard" empty listeners
+                instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+                instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+                instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithThreeSimpleListenersOneDisposed() throws IOException {
+        final String testName = "probedWithThreeSimpleListenersOneDisposed";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        // Abuse instrumentation to get a copy of the root node before execution
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach three "simple" empty listeners
+                instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+                final Instrument disposeMe = instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+                instrumenter.attach(probe, new DefaultSimpleInstrumentListener(), testName);
+                disposeMe.dispose();
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    @Test
+    public void probedWithThreeStandardListenersOneDisposed() throws IOException {
+        final String testName = "probedWithThreeStandardListenersOneDisposed";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        instrumenter.registerASTProber(new ASTProber() {
+
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                final Probe probe = instrumenter.probe(testRootNode.getBody());
+                // Attach three "standard" empty listeners
+                instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+                final Instrument disposeMe = instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+                instrumenter.attach(probe, new DefaultStandardInstrumentListener(), testName);
+                disposeMe.dispose();
+
+                root[0] = testRootNode;
+            }
+        });
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        assertPartialEvalEquals("constant42", root[0]);
+    }
+
+    /**
+     * Sketch of how a test for deopt might work.
+     */
+    @Test
+    public void instrumentDeopt() throws IOException {
+
+        final String testName = "instrumentDeopt";
+        final Source source = Source.fromText(testName, "any text").withMimeType("text/x-instPETest");
+        final RootNode[] root = new RootNode[1];
+        final Probe[] probe = new Probe[1];
+        final int[] count = {0};
+
+        // Register a "prober" that will get applied when CallTarget gets created.
+        instrumenter.registerASTProber(new ASTProber() {
+
+            @Override
+            public void probeAST(Instrumenter inst, RootNode rootNode) {
+                instrumenter.unregisterASTProber(this);
+
+                final TestRootNode testRootNode = (TestRootNode) rootNode;
+                // Probe the value node
+                probe[0] = instrumenter.probe(testRootNode.getBody());
+                root[0] = testRootNode;
+            }
+        });
+
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        Assert.assertEquals(0, count[0]); // Didn't count anything
+
+        // Add a counting instrument; this changes the "Probe state" and should cause a deopt
+        final Instrument countingInstrument = instrumenter.attach(probe[0], new DefaultSimpleInstrumentListener() {
+
+            @Override
+            public void onEnter(Probe p) {
+                count[0] = count[0] + 1;
+            }
+        }, testName);
+
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        Assert.assertEquals(1, count[0]); // Counted the first call
+
+        // Remove the counting instrument; this changes the "Probe state" and should cause a
+        // deopt
+        countingInstrument.dispose();
+
+        Assert.assertEquals(vm.eval(source).get(), 42);
+        Assert.assertEquals(1, count[0]); // Didn't count this time
+
+    }
 }