# HG changeset patch # User Michael Van De Vanter # Date 1443916695 25200 # Node ID 1fc7ee8c9443c6432696dc475c430126333a047b # Parent 4d8fc9f88d30a4d1b3c30a2763db31a86a2690e3 Truffle/Instrumentation: rewrite InstrumentationPartialEvaluationTest to work in PolyglotEngine after Instrumentation merge diff -r 4d8fc9f88d30 -r 1fc7ee8c9443 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPETestLanguage.java --- /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 16:58:15 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 { + + 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; + } + } + +} diff -r 4d8fc9f88d30 -r 1fc7ee8c9443 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Wed Sep 30 22:24:46 2015 -0700 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Sat Oct 03 16:58:15 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. + *

+ * A specialized test language produces a root with a single constant-valued child, no matter what + * source is eval'd. + *

+ * 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 + + } }