Mercurial > hg > graal-compiler
view graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java @ 20106:2e3cc2a27711
Truffle/Instrumentation: a new flavor of Instrument that lazily provides an AST fragment to be attached/adopted directly into a running AST, and to which execution event notifications will be routed. Important use cases so far include conditional breakpoints (with optimizeable conditions) and Ruby set_trace_func.
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Tue, 31 Mar 2015 19:01:07 -0700 |
parents | 907128d02b31 |
children | 73b1844b5b14 |
line wrap: on
line source
/* * Copyright (c) 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 org.junit.*; import com.oracle.graal.truffle.test.nodes.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.instrument.impl.*; import com.oracle.truffle.api.nodes.*; /** * Tests for a single simple PE test with various combinations of instrumentation attached. None of * the instrumentation ultimate does anything, so should compile away. */ public class InstrumentationPartialEvaluationTest extends PartialEvaluationTest { 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 DefaultInstrumentListener(), "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 DefaultASTInstrumentListener(), "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 DefaultInstrumentListener(), "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 DefaultASTInstrumentListener(), "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 DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "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 DefaultASTInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "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 DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "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 DefaultASTInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "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 DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "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 DefaultASTInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); instrument2.dispose(); assertPartialEvalEquals("constant42", root); } @Test public void constantValueInertToolNodeInstrumentListener() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); // A listener that could insert a "tool node" into the AST, but which never does. Instrument instrument = Instrument.create(new ToolNodeInstrumentListener() { public ToolNode getToolNode(Probe p) { return null; } }, null); probe.attach(instrument); assertPartialEvalEquals("constant42", root); } @Test public void constantValueInertToolNode() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); // A listener that inserts a "tool node" with empty methods into the AST. Instrument instrument = Instrument.create(new ToolNodeInstrumentListener() { public ToolNode getToolNode(Probe p) { return new ToolNode() { }; } }, null); probe.attach(instrument); assertPartialEvalEquals("constant42", root); } @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 DefaultInstrumentListener() { @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() { 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); } } }