# HG changeset patch # User Michael Van De Vanter # Date 1442442982 25200 # Node ID 1c0f490984d52648fd2ed5cd77472da8be378ef2 # Parent 0599e2df6a9fb403f6c24a65c62bab1ba30591fe# Parent f47b601edbc626dcfe8b3636933b4834c89f7779 Merge with f47b601edbc626dcfe8b3636933b4834c89f7779 diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java --- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java Wed Sep 16 15:36:22 2015 -0700 @@ -22,13 +22,19 @@ */ package com.oracle.truffle.api.dsl.test; +import java.io.IOException; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.debug.DebugSupportProvider; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.instrument.ASTProber; +import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; +import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; import com.oracle.truffle.api.instrument.ToolSupportProvider; +import com.oracle.truffle.api.instrument.Visualizer; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; -import java.io.IOException; public final class TestingLanguage extends TruffleLanguage { public static final TestingLanguage INSTANCE = new TestingLanguage(); @@ -58,13 +64,41 @@ } @Override - protected ToolSupportProvider getToolSupport() { + protected Visualizer getVisualizer() { return null; } @Override + protected ASTProber getDefaultASTProber() { + return null; + } + + @SuppressWarnings("deprecation") + @Override + protected void enableASTProbing(ASTProber astProber) { + throw new UnsupportedOperationException(); + } + + @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; + } + + @SuppressWarnings("deprecation") + @Override + protected ToolSupportProvider getToolSupport() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override protected DebugSupportProvider getDebugSupport() { - return null; + throw new UnsupportedOperationException(); } @Override diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java --- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -22,14 +22,20 @@ */ package com.oracle.truffle.api.dsl.test.processor; +import java.io.IOException; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.debug.DebugSupportProvider; import com.oracle.truffle.api.dsl.test.ExpectError; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.instrument.ASTProber; +import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; +import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; import com.oracle.truffle.api.instrument.ToolSupportProvider; +import com.oracle.truffle.api.instrument.Visualizer; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; -import java.io.IOException; public class LanguageRegistrationTest { @@ -76,13 +82,41 @@ } @Override - protected ToolSupportProvider getToolSupport() { + protected Visualizer getVisualizer() { + return null; + } + + @Override + protected ASTProber getDefaultASTProber() { + 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; + } + + @SuppressWarnings("deprecation") + @Override + protected ToolSupportProvider getToolSupport() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override protected DebugSupportProvider getDebugSupport() { - return null; + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override + protected void enableASTProbing(ASTProber astProber) { + throw new UnsupportedOperationException(); } @Override @@ -120,13 +154,41 @@ } @Override - protected ToolSupportProvider getToolSupport() { + protected Visualizer getVisualizer() { + return null; + } + + @Override + protected ASTProber getDefaultASTProber() { + 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; + } + + @SuppressWarnings("deprecation") + @Override + protected ToolSupportProvider getToolSupport() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override protected DebugSupportProvider getDebugSupport() { - return null; + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override + protected void enableASTProbing(ASTProber astProber) { + throw new UnsupportedOperationException(); } @Override @@ -160,13 +222,41 @@ } @Override - protected ToolSupportProvider getToolSupport() { + protected Visualizer getVisualizer() { + return null; + } + + @Override + protected ASTProber getDefaultASTProber() { + 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; + } + + @SuppressWarnings("deprecation") + @Override + protected ToolSupportProvider getToolSupport() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override protected DebugSupportProvider getDebugSupport() { - return null; + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override + protected void enableASTProbing(ASTProber astProber) { + throw new UnsupportedOperationException(); } @Override diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -22,14 +22,15 @@ */ package com.oracle.truffle.api.test; +import org.junit.Assert; +import org.junit.Test; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; -import org.junit.Assert; -import org.junit.Test; /** *

Passing Arguments

diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java Wed Sep 16 15:36:22 2015 -0700 @@ -22,13 +22,19 @@ */ package com.oracle.truffle.api.test; +import java.io.IOException; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.debug.DebugSupportProvider; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.instrument.ASTProber; +import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; +import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; import com.oracle.truffle.api.instrument.ToolSupportProvider; +import com.oracle.truffle.api.instrument.Visualizer; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; -import java.io.IOException; public final class TestingLanguage extends TruffleLanguage { public static final TestingLanguage INSTANCE = new TestingLanguage(); @@ -57,13 +63,41 @@ } @Override - protected ToolSupportProvider getToolSupport() { + protected Visualizer getVisualizer() { return null; } @Override + protected ASTProber getDefaultASTProber() { + return null; + } + + @SuppressWarnings("deprecation") + @Override + protected void enableASTProbing(ASTProber astProber) { + throw new UnsupportedOperationException(); + } + + @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; + } + + @SuppressWarnings("deprecation") + @Override + protected ToolSupportProvider getToolSupport() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override protected DebugSupportProvider getDebugSupport() { - return null; + throw new UnsupportedOperationException(); } @Override diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -22,20 +22,23 @@ */ package com.oracle.truffle.api.test.instrument; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.instrument.AdvancedInstrumentRoot; import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; 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.nodes.Node; import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode; import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdvancedInstrumentCounterRoot; import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode; import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode; -import static org.junit.Assert.assertEquals; -import org.junit.Test; /** * Tests the kind of instrumentation where a client can provide an AST fragment to be @@ -44,20 +47,22 @@ public class AdvancedInstrumentTest { @Test - public void testAdvancedInstrumentListener() { + public void testAdvancedInstrumentListener() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = InstrumentationTestNodes.createInstrumenter(); + // Create a simple addition AST final TruffleRuntime runtime = Truffle.getRuntime(); final TestValueNode leftValueNode = new TestValueNode(6); final TestValueNode rightValueNode = new TestValueNode(7); final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); - final TestRootNode rootNode = new TestRootNode(addNode); + final TestRootNode rootNode = new TestRootNode(addNode, instrumenter); final CallTarget callTarget1 = runtime.createCallTarget(rootNode); // Ensure it executes correctly assertEquals(13, callTarget1.call()); // Probe the addition node - final Probe probe = addNode.probe(); + final Probe probe = instrumenter.probe(addNode); assertEquals(13, callTarget1.call()); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -28,6 +28,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; 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.ProbeException; import com.oracle.truffle.api.instrument.ProbeFailure.Reason; @@ -47,11 +48,14 @@ import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestLanguageWrapperNode; import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode; import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode; + import java.util.Iterator; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; + import org.junit.Test; /** @@ -101,7 +105,9 @@ }; @Test - public void testInstrumentationStructure() { + public void testInstrumentationStructure() throws IllegalAccessException, SecurityException, IllegalArgumentException, NoSuchFieldException { + + final Instrumenter instrumenter = InstrumentationTestNodes.createInstrumenter(); // Create a simple addition AST final TruffleRuntime runtime = Truffle.getRuntime(); final TestValueNode leftValueNode = new TestValueNode(6); @@ -109,11 +115,11 @@ final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); try { - addNode.probe(); + instrumenter.probe(addNode); } catch (ProbeException e) { assertEquals(e.getFailure().getReason(), Reason.NO_PARENT); } - final TestRootNode rootNode = new TestRootNode(addNode); + final TestRootNode rootNode = new TestRootNode(addNode, instrumenter); // Creating a call target sets the parent pointers in this tree and is necessary prior to // checking any parent/child relationships @@ -135,7 +141,7 @@ assertEquals(13, callTarget1.call()); // Probe the addition node - addNode.probe(); + instrumenter.probe(addNode); // Check the modified tree structure assertEquals(addNode, leftValueNode.getParent()); @@ -162,7 +168,7 @@ // Check that you can't probe the WrapperNodes TestLanguageWrapperNode wrapper = (TestLanguageWrapperNode) wrapperNode; try { - wrapper.probe(); + instrumenter.probe(wrapper); fail(); } catch (ProbeException e) { assertEquals(e.getFailure().getReason(), Reason.WRAPPER_NODE); @@ -173,20 +179,22 @@ } @Test - public void testListeners() { + public void testListeners() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + + final Instrumenter instrumenter = InstrumentationTestNodes.createInstrumenter(); // Create a simple addition AST final TruffleRuntime runtime = Truffle.getRuntime(); final TestValueNode leftValueNode = new TestValueNode(6); final TestValueNode rightValueNode = new TestValueNode(7); final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); - final TestRootNode rootNode = new TestRootNode(addNode); + final TestRootNode rootNode = new TestRootNode(addNode, instrumenter); // Creating a call target sets the parent pointers in this tree and is necessary prior to // checking any parent/child relationships final CallTarget callTarget = runtime.createCallTarget(rootNode); // Probe the addition node - final Probe probe = addNode.probe(); + final Probe probe = instrumenter.probe(addNode); // Check instrumentation with the simplest kind of counters. // They should all be removed when the check is finished. @@ -294,14 +302,16 @@ } @Test - public void testTagging() { + public void testTagging() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = InstrumentationTestNodes.createInstrumenter(); + // Applies appropriate tags - final TestASTProber astProber = new TestASTProber(); - Probe.registerASTProber(astProber); + final TestASTProber astProber = new TestASTProber(instrumenter); + instrumenter.registerASTProber(astProber); // Listens for probes and tags being added final TestProbeListener probeListener = new TestProbeListener(); - Probe.addProbeListener(probeListener); + instrumenter.addProbeListener(probeListener); // Counts all entries to all instances of addition nodes final TestMultiCounter additionCounter = new TestMultiCounter(); @@ -315,7 +325,7 @@ final TestValueNode rightValueNode = new TestValueNode(7); final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); - final TestRootNode rootNode = new TestRootNode(addNode); + final TestRootNode rootNode = new TestRootNode(addNode, instrumenter); final CallTarget callTarget = runtime.createCallTarget(rootNode); @@ -323,18 +333,18 @@ assertEquals(probeListener.probeCount, 3); assertEquals(probeListener.tagCount, 3); - assertEquals(Probe.findProbesTaggedAs(ADD_TAG).size(), 1); - assertEquals(Probe.findProbesTaggedAs(VALUE_TAG).size(), 2); + assertEquals(instrumenter.findProbesTaggedAs(ADD_TAG).size(), 1); + assertEquals(instrumenter.findProbesTaggedAs(VALUE_TAG).size(), 2); // Check that it executes correctly assertEquals(13, callTarget.call()); // Dynamically attach a counter for all executions of all Addition nodes - for (Probe probe : Probe.findProbesTaggedAs(ADD_TAG)) { + for (Probe probe : instrumenter.findProbesTaggedAs(ADD_TAG)) { additionCounter.attachCounter(probe); } // Dynamically attach a counter for all executions of all Value nodes - for (Probe probe : Probe.findProbesTaggedAs(VALUE_TAG)) { + for (Probe probe : instrumenter.findProbesTaggedAs(VALUE_TAG)) { valueCounter.attachCounter(probe); } @@ -349,7 +359,7 @@ assertEquals(additionCounter.count, 1); assertEquals(valueCounter.count, 2); - Probe.unregisterASTProber(astProber); + instrumenter.unregisterASTProber(astProber); } private interface TestCounter { @@ -472,6 +482,12 @@ */ private static final class TestASTProber implements NodeVisitor, ASTProber { + private final Instrumenter instrumenter; + + TestASTProber(Instrumenter instrumenter) { + this.instrumenter = instrumenter; + } + @Override public boolean visit(Node node) { if (node instanceof TestLanguageNode) { @@ -479,10 +495,10 @@ final TestLanguageNode testNode = (TestLanguageNode) node; if (node instanceof TestValueNode) { - testNode.probe().tagAs(VALUE_TAG, null); + instrumenter.probe(testNode).tagAs(VALUE_TAG, null); } else if (node instanceof TestAdditionNode) { - testNode.probe().tagAs(ADD_TAG, null); + instrumenter.probe(testNode).tagAs(ADD_TAG, null); } } @@ -490,7 +506,7 @@ } @Override - public void probeAST(Node node) { + public void probeAST(Instrumenter inst, Node node) { node.accept(this); } } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Wed Sep 16 15:36:22 2015 -0700 @@ -22,9 +22,14 @@ */ package com.oracle.truffle.api.test.instrument; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrument.AdvancedInstrumentRoot; +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.ProbeNode; @@ -34,12 +39,21 @@ import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.test.TestingLanguage; +import com.oracle.truffle.api.vm.TruffleVM; /** * Tests instrumentation where a client can attach a node that gets attached into the AST. */ class InstrumentationTestNodes { + static Instrumenter createInstrumenter() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + TruffleVM vm = TruffleVM.newVM().build(); + final Field field = TruffleVM.class.getDeclaredField("instrumenter"); + field.setAccessible(true); + final Instrumenter instrument = (Instrumenter) field.get(vm); + return instrument; + } + abstract static class TestLanguageNode extends Node { public abstract Object execute(VirtualFrame vFrame); @@ -148,13 +162,16 @@ static class TestRootNode extends RootNode { @Child private TestLanguageNode body; + final Instrumenter instrumenter; + /** * 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(TestLanguageNode body) { + public TestRootNode(TestLanguageNode body, Instrumenter instrumenter) { super(TestingLanguage.class, null, null); + this.instrumenter = instrumenter; this.body = body; } @@ -170,7 +187,14 @@ @Override public void applyInstrumentation() { - Probe.applyASTProbers(body); + Method method; + try { + method = Instrumenter.class.getDeclaredMethod("applyInstrumentation", Node.class); + method.setAccessible(true); + method.invoke(instrumenter, body); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException("InstrumentationTestNodes"); + } } } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -91,7 +91,8 @@ w.write(text); } - Source s1 = Source.fromFileName(file.getPath()); + // JDK8 default fails on OS X: https://bugs.openjdk.java.net/browse/JDK-8129632 + Source s1 = Source.fromFileName(file.getPath()).withMimeType("text/x-java"); assertEquals("Recognized as Java", "text/x-java", s1.getMimeType()); Source s2 = s1.withMimeType("text/x-c"); assertEquals("They have the same content", s1.getCode(), s2.getCode()); @@ -107,7 +108,8 @@ String text = "// Hello"; - Source s1 = Source.fromFileName(text, file.getPath()); + // JDK8 default fails on OS X: https://bugs.openjdk.java.net/browse/JDK-8129632 + Source s1 = Source.fromFileName(text, file.getPath()).withMimeType("text/x-java"); assertEquals("Recognized as Java", "text/x-java", s1.getMimeType()); Source s2 = s1.withMimeType("text/x-c"); assertEquals("They have the same content", s1.getCode(), s2.getCode()); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -22,16 +22,10 @@ */ package com.oracle.truffle.api.test.vm; -import com.oracle.truffle.api.CallTarget; -import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.TruffleLanguage.Env; -import com.oracle.truffle.api.debug.DebugSupportProvider; -import com.oracle.truffle.api.instrument.ToolSupportProvider; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.api.source.Source; -import com.oracle.truffle.api.vm.TruffleVM; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.io.Reader; import java.util.Enumeration; @@ -39,13 +33,27 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.Executors; + import org.junit.After; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.TruffleLanguage.Env; +import com.oracle.truffle.api.debug.DebugSupportProvider; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.instrument.ASTProber; +import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; +import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; +import com.oracle.truffle.api.instrument.ToolSupportProvider; +import com.oracle.truffle.api.instrument.Visualizer; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.TruffleVM; + public class ImplicitExplicitExportTest { private static Thread mainThread; private TruffleVM vm; @@ -172,13 +180,41 @@ } @Override - protected ToolSupportProvider getToolSupport() { + protected Visualizer getVisualizer() { + return null; + } + + @Override + protected ASTProber getDefaultASTProber() { + 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; + } + + @SuppressWarnings("deprecation") + @Override + protected ToolSupportProvider getToolSupport() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override protected DebugSupportProvider getDebugSupport() { - return null; + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override + protected void enableASTProbing(ASTProber astProber) { + throw new UnsupportedOperationException(); } private Object importExport(Source code) { diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/InitializationTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/InitializationTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/InitializationTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -22,12 +22,20 @@ */ package com.oracle.truffle.api.test.vm; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; + +import org.junit.Test; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.debug.Breakpoint; -import com.oracle.truffle.api.debug.DebugSupportException; import com.oracle.truffle.api.debug.DebugSupportProvider; import com.oracle.truffle.api.debug.Debugger; import com.oracle.truffle.api.debug.ExecutionEvent; @@ -36,23 +44,19 @@ import com.oracle.truffle.api.instrument.ASTProber; import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; +import com.oracle.truffle.api.instrument.Instrumenter; import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.instrument.ProbeNode; import com.oracle.truffle.api.instrument.StandardSyntaxTag; import com.oracle.truffle.api.instrument.ToolSupportProvider; import com.oracle.truffle.api.instrument.Visualizer; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeVisitor; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.vm.EventConsumer; import com.oracle.truffle.api.vm.TruffleVM; -import java.io.IOException; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import org.junit.Test; /** * Bug report validating test. @@ -102,13 +106,17 @@ super(AbstractLanguage.class, ss, null); node = new ANode(42); adoptChildren(); - node.probe().tagAs(StandardSyntaxTag.STATEMENT, this); } @Override public Object execute(VirtualFrame frame) { return node.constant(); } + + @Override + public void applyInstrumentation() { + super.applyInstrumentation(node); + } } private static class ANode extends Node { @@ -130,34 +138,7 @@ @Override public ProbeNode.WrapperNode createWrapperNode() { - class WN extends ANode implements ProbeNode.WrapperNode { - private ProbeNode probeNode; - - public WN(int constant) { - super(constant); - } - - @Override - public Node getChild() { - return ANode.this; - } - - @Override - public Probe getProbe() { - return probeNode.getProbe(); - } - - @Override - public void insertProbe(ProbeNode pn) { - this.probeNode = pn; - } - - @Override - public String instrumentationInfo() { - throw new UnsupportedOperationException(); - } - } - return new WN(constant); + return new ANodeWrapper(this); } Object constant() { @@ -166,6 +147,36 @@ } + private static class ANodeWrapper extends ANode implements ProbeNode.WrapperNode { + @Child ANode child; + private ProbeNode probeNode; + + ANodeWrapper(ANode node) { + super(1); // dummy + this.child = node; + } + + @Override + public Node getChild() { + return child; + } + + @Override + public Probe getProbe() { + return probeNode.getProbe(); + } + + @Override + public void insertProbe(ProbeNode pn) { + this.probeNode = pn; + } + + @Override + public String instrumentationInfo() { + throw new UnsupportedOperationException(); + } + } + private abstract static class AbstractLanguage extends TruffleLanguage { } @@ -173,6 +184,22 @@ public static final class TestLanguage extends AbstractLanguage implements DebugSupportProvider { public static final TestLanguage INSTANCE = new TestLanguage(); + private final ASTProber prober = new ASTProber() { + + public void probeAST(final Instrumenter instrumenter, Node startNode) { + startNode.accept(new NodeVisitor() { + + public boolean visit(Node node) { + + if (node instanceof ANode) { + instrumenter.probe(node).tagAs(StandardSyntaxTag.STATEMENT, null); + } + return true; + } + }); + } + }; + @Override protected Object createContext(Env env) { assertNull("Not defined symbol", env.importSymbol("unknown")); @@ -199,23 +226,25 @@ throw new UnsupportedOperationException(); } + @SuppressWarnings("deprecation") @Override protected ToolSupportProvider getToolSupport() { throw new UnsupportedOperationException(); } + @SuppressWarnings("deprecation") @Override protected DebugSupportProvider getDebugSupport() { - return this; - } - - @Override - public Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws DebugSupportException { throw new UnsupportedOperationException(); } @Override - public AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(String expr, AdvancedInstrumentResultListener resultListener) throws DebugSupportException { + public Object evalInContext(Source source, Node node, MaterializedFrame mFrame) { + throw new UnsupportedOperationException(); + } + + @Override + public AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(String expr, AdvancedInstrumentResultListener resultListener) { throw new InstrumentOKException(); } @@ -225,6 +254,12 @@ } @Override + protected ASTProber getDefaultASTProber() { + return prober; + } + + @SuppressWarnings("deprecation") + @Override public void enableASTProbing(ASTProber astProber) { throw new UnsupportedOperationException(); } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/SymbolInvokerImpl.java --- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/SymbolInvokerImpl.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/SymbolInvokerImpl.java Wed Sep 16 15:36:22 2015 -0700 @@ -28,6 +28,7 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.impl.Accessor; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.TruffleObject; @@ -82,6 +83,11 @@ Object tmp = ForeignAccess.execute(foreignAccess, frame, function, args); return convert.convert(frame, tmp); } + + @Override + public void applyInstrumentation() { + SymbolInvokerImpl.ACCESSOR_INTEROP.applyInstrumentation(foreignAccess); + } } private static final class ConvertNode extends Node { @@ -125,4 +131,14 @@ return obj; } } + + static final class AccessorInterop extends Accessor { + + @Override + protected void applyInstrumentation(Node node) { + super.applyInstrumentation(node); + } + } + + static final AccessorInterop ACCESSOR_INTEROP = new AccessorInterop(); } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java --- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,20 +24,6 @@ */ package com.oracle.truffle.api.vm; -import com.oracle.truffle.api.CallTarget; -import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.TruffleLanguage.Env; -import com.oracle.truffle.api.TruffleLanguage.Registration; -import com.oracle.truffle.api.debug.DebugSupportProvider; -import com.oracle.truffle.api.debug.Debugger; -import com.oracle.truffle.api.debug.ExecutionEvent; -import com.oracle.truffle.api.debug.SuspendedEvent; -import com.oracle.truffle.api.impl.Accessor; -import com.oracle.truffle.api.instrument.Probe; -import com.oracle.truffle.api.instrument.ToolSupportProvider; -import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.interop.java.JavaInterop; -import com.oracle.truffle.api.source.Source; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -65,6 +51,23 @@ import java.util.logging.Level; import java.util.logging.Logger; +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.TruffleLanguage.Env; +import com.oracle.truffle.api.TruffleLanguage.Registration; +import com.oracle.truffle.api.debug.DebugSupportProvider; +import com.oracle.truffle.api.debug.Debugger; +import com.oracle.truffle.api.debug.ExecutionEvent; +import com.oracle.truffle.api.debug.SuspendedEvent; +import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.instrument.ASTProber; +import com.oracle.truffle.api.instrument.Instrumenter; +import com.oracle.truffle.api.instrument.Probe; +import com.oracle.truffle.api.instrument.ToolSupportProvider; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.java.JavaInterop; +import com.oracle.truffle.api.source.Source; + /** * Virtual machine for Truffle based languages. Term virtual machine is a bit overloaded, * so don't think of Java virtual machine here - while we are running and using @@ -109,6 +112,7 @@ private final Writer out; private final EventConsumer[] handlers; private final Map globals; + private final Instrumenter instrumenter; private Debugger debugger; /** @@ -123,6 +127,7 @@ this.handlers = null; this.globals = null; this.executor = null; + this.instrumenter = null; } /** @@ -136,6 +141,7 @@ this.handlers = handlers; this.initThread = Thread.currentThread(); this.globals = new HashMap<>(globals); + this.instrumenter = SPI.createInstrumenter(); Map map = new HashMap<>(); for (Map.Entry en : LanguageCache.languages().entrySet()) { map.put(en.getKey(), new Language(en.getValue())); @@ -436,7 +442,6 @@ try (Closeable d = SPI.executionStart(this, fillIn, s)) { TruffleLanguage langImpl = l.getImpl(true); fillLang[0] = langImpl; - TruffleVM.findDebuggerSupport(langImpl); if (debugger == null) { debugger = fillIn[0]; } @@ -598,7 +603,7 @@ * delegates to * {@link JavaInterop#asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject)} * just handles primitive types as well. - * + * * @param the type of the view one wants to obtain * @param representation the class of the view interface (it has to be an interface) * @return instance of the view wrapping the object of this symbol @@ -769,7 +774,14 @@ TruffleLanguage getImpl(boolean create) { getEnv(create); - return info.getImpl(false); + TruffleLanguage impl = info.getImpl(false); + if (impl != null) { + ASTProber prober = SPI.getDefaultASTProber(impl); + if (prober != null) { + instrumenter.registerASTProber(prober); + } + } + return impl; } TruffleLanguage.Env getEnv(boolean create) { @@ -789,8 +801,7 @@ // Accessor helper methods // - TruffleLanguage findLanguage(Probe probe) { - Class languageClazz = SPI.findLanguage(probe); + TruffleLanguage findLanguage(Class languageClazz) { for (Map.Entry entrySet : langs.entrySet()) { Language languageDescription = entrySet.getValue(); final TruffleLanguage impl = languageDescription.getImpl(false); @@ -801,6 +812,10 @@ throw new IllegalStateException("Cannot find language " + languageClazz + " among " + langs); } + TruffleLanguage findLanguage(Probe probe) { + return findLanguage(SPI.findLanguage(probe)); + } + Env findEnv(Class languageClazz) { for (Map.Entry entrySet : langs.entrySet()) { Language languageDescription = entrySet.getValue(); @@ -812,10 +827,6 @@ throw new IllegalStateException("Cannot find language " + languageClazz + " among " + langs); } - static DebugSupportProvider findDebuggerSupport(TruffleLanguage l) { - return SPI.getDebugSupport(l); - } - private static class SPIAccessor extends Accessor { @Override public Object importSymbol(Object vmObj, TruffleLanguage ownLang, String globalName) { @@ -871,14 +882,32 @@ return super.languageGlobal(env); } + @SuppressWarnings("deprecation") @Override public ToolSupportProvider getToolSupport(TruffleLanguage l) { - return super.getToolSupport(l); + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("deprecation") + @Override + public DebugSupportProvider getDebugSupport(TruffleLanguage l) { + throw new UnsupportedOperationException(); } @Override - public DebugSupportProvider getDebugSupport(TruffleLanguage l) { - return super.getDebugSupport(l); + protected Instrumenter createInstrumenter() { + return super.createInstrumenter(); + } + + @Override + protected ASTProber getDefaultASTProber(TruffleLanguage impl) { + return super.getDefaultASTProber(impl); + } + + @Override + protected Instrumenter getInstrumenter(Object obj) { + final TruffleVM vm = (TruffleVM) obj; + return vm.instrumenter; } @Override @@ -893,6 +922,12 @@ } @Override + protected TruffleLanguage findLanguageImpl(Object obj, Class languageClazz) { + final TruffleVM vm = (TruffleVM) obj; + return vm.findLanguage(languageClazz); + } + + @Override protected Closeable executionStart(Object obj, Debugger[] fillIn, Source s) { TruffleVM vm = (TruffleVM) obj; return super.executionStart(vm, fillIn, s); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,12 +24,6 @@ */ package com.oracle.truffle.api; -import com.oracle.truffle.api.debug.DebugSupportProvider; -import com.oracle.truffle.api.impl.Accessor; -import com.oracle.truffle.api.impl.FindContextNode; -import com.oracle.truffle.api.instrument.ToolSupportProvider; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.source.Source; import java.io.IOException; import java.io.Reader; import java.io.Writer; @@ -41,6 +35,20 @@ import java.util.Map; import java.util.WeakHashMap; +import com.oracle.truffle.api.debug.DebugSupportProvider; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.impl.FindContextNode; +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.Instrument; +import com.oracle.truffle.api.instrument.ToolSupportProvider; +import com.oracle.truffle.api.instrument.Visualizer; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.source.Source; + /** * An entry point for everyone who wants to implement a Truffle based language. By providing an * implementation of this type and registering it using {@link Registration} annotation, your @@ -179,11 +187,58 @@ */ protected abstract boolean isObjectOfLanguage(Object object); + @Deprecated protected abstract ToolSupportProvider getToolSupport(); + @Deprecated protected abstract DebugSupportProvider getDebugSupport(); /** + * Gets visualization services for language-specific information. + */ + protected abstract Visualizer getVisualizer(); + + /** + * Enables AST probing on all subsequently created ASTs (sources parsed). + * + * @param astProber optional AST prober to enable; the default for the language used if + * {@code null} + */ + @Deprecated + protected abstract void enableASTProbing(ASTProber astProber); + + /** + * Gets the current specification for AST instrumentation for the language. + */ + protected abstract ASTProber getDefaultASTProber(); + + /** + * Runs source code in a halted execution context, or at top level. + * + * @param source the code to run + * @param node node where execution halted, {@code null} if no execution context + * @param mFrame frame where execution halted, {@code null} if no execution context + * @return result of running the code in the context, or at top level if no execution context. + * @throws IOException if the evaluation cannot be performed + */ + protected abstract Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws IOException; + + /** + * Creates a language-specific factory to produce instances of {@link AdvancedInstrumentRoot} + * that, when executed, computes the result of a textual expression in the language; used to + * create an + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument}. + * + * @param expr a guest language expression + * @param resultListener optional listener for the result of each evaluation. + * @return a new factory + * @throws IOException if the factory cannot be created, for example if the expression is badly + * formed. + */ + protected abstract AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(String expr, AdvancedInstrumentResultListener resultListener) throws IOException; + + /** * Allows a language implementor to create a node that can effectively lookup up the context * associated with current execution. The context is created by * {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)} method. @@ -338,6 +393,14 @@ } @Override + protected AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Object vm, Class languageClass, String expr, + AdvancedInstrumentResultListener resultListener) throws IOException { + + final TruffleLanguage language = findLanguageImpl(vm, languageClass); + return language.createAdvancedInstrumentRootFactory(expr, resultListener); + } + + @Override protected Object findExportedSymbol(TruffleLanguage.Env env, String globalName, boolean onlyExplicit) { return env.langCtx.findExportedSymbol(globalName, onlyExplicit); } @@ -363,10 +426,17 @@ } @Override + protected ASTProber getDefaultASTProber(TruffleLanguage language) { + return language.getDefaultASTProber(); + } + + @SuppressWarnings("deprecation") + @Override protected ToolSupportProvider getToolSupport(TruffleLanguage l) { return l.getToolSupport(); } + @SuppressWarnings("deprecation") @Override protected DebugSupportProvider getDebugSupport(TruffleLanguage l) { return l.getDebugSupport(); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,6 +24,13 @@ */ package com.oracle.truffle.api.debug; +import java.io.Closeable; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; @@ -35,6 +42,7 @@ import com.oracle.truffle.api.instrument.AdvancedInstrumentRoot; import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; import com.oracle.truffle.api.instrument.Instrument; +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.StandardSyntaxTag; @@ -43,12 +51,6 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.LineLocation; import com.oracle.truffle.api.source.Source; -import java.io.Closeable; -import java.io.IOException; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; /** * Represents debugging related state of a {@link com.oracle.truffle.api.vm.TruffleVM}. Instance of @@ -60,7 +62,7 @@ public final class Debugger { private static final boolean TRACE = false; - private static final String TRACE_PREFIX = "DEBUG ENGINE: "; + private static final String TRACE_PREFIX = "Debugger: "; private static final PrintStream OUT = System.out; @@ -73,6 +75,7 @@ } } + private final Instrumenter instrumenter; private final Object vm; private Source lastSource; @@ -92,6 +95,9 @@ void addWarning(String warning); } + private final BreakpointCallback breakpointCallback; + private final WarningLog warningLog; + /** * Implementation of line-oriented breakpoints. */ @@ -107,9 +113,9 @@ */ private DebugExecutionContext debugContext; - Debugger(Object vm) { + Debugger(Object vm, Instrumenter instrumenter) { this.vm = vm; - + this.instrumenter = instrumenter; Source.setFileCaching(true); // Initialize execution context stack @@ -117,7 +123,7 @@ prepareContinue(); debugContext.contextTrace("START EXEC DEFAULT"); - final BreakpointCallback breakpointCallback = new BreakpointCallback() { + breakpointCallback = new BreakpointCallback() { @TruffleBoundary public void haltedAt(Node astNode, MaterializedFrame mFrame, String haltReason) { @@ -125,7 +131,7 @@ } }; - final WarningLog warningLog = new WarningLog() { + warningLog = new WarningLog() { public void addWarning(String warning) { assert debugContext != null; @@ -137,10 +143,6 @@ this.tagBreaks = new TagBreakpointFactory(this, breakpointCallback, warningLog); } - Object vm() { - return vm; - } - /** * Sets a breakpoint to halt at a source line. * @@ -269,6 +271,7 @@ debugContext.setStrategy(new StepOver(stepCount)); } + // TODO (mlvdv) used by the breakpoint factories; to be deprecated/replaced. /** * Creates a language-specific factory to produce instances of {@link AdvancedInstrumentRoot} * that, when executed, computes the result of a textual expression in the language; used to @@ -284,15 +287,12 @@ */ @SuppressWarnings("rawtypes") AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Probe probe, String expr, AdvancedInstrumentResultListener resultListener) throws IOException { - try { - Class langugageClass = ACCESSOR.findLanguage(probe); - TruffleLanguage.Env env = ACCESSOR.findLanguage(vm, langugageClass); - TruffleLanguage l = ACCESSOR.findLanguage(env); - DebugSupportProvider dsp = ACCESSOR.getDebugSupport(l); - return dsp.createAdvancedInstrumentRootFactory(expr, resultListener); - } catch (DebugSupportException ex) { - throw new IOException(ex); - } + Class languageClass = ACCESSOR.findLanguage(probe); + return ACCESSOR.createAdvancedInstrumentRootFactory(vm, languageClass, expr, resultListener); + } + + Instrumenter getInstrumenter() { + return instrumenter; } /** @@ -416,7 +416,7 @@ @Override protected void setStrategy(final int stackDepth) { - Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { + instrumenter.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { @TruffleBoundary @Override public void tagTrappedAt(Node node, MaterializedFrame mFrame) { @@ -430,7 +430,7 @@ strategyTrace("RESUME BEFORE", ""); } }); - Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { + instrumenter.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { @TruffleBoundary @Override public void tagTrappedAt(Node node, MaterializedFrame mFrame) { @@ -449,8 +449,8 @@ @Override protected void unsetStrategy() { - Probe.setBeforeTagTrap(null); - Probe.setAfterTagTrap(null); + instrumenter.setBeforeTagTrap(null); + instrumenter.setAfterTagTrap(null); } } @@ -473,7 +473,7 @@ @Override protected void setStrategy(final int stackDepth) { - Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { + instrumenter.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { @TruffleBoundary @Override @@ -491,7 +491,7 @@ @Override protected void unsetStrategy() { - Probe.setAfterTagTrap(null); + instrumenter.setAfterTagTrap(null); } } @@ -517,7 +517,7 @@ @Override protected void setStrategy(final int stackDepth) { - Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { + instrumenter.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { @TruffleBoundary @Override public void tagTrappedAt(Node node, MaterializedFrame mFrame) { @@ -542,7 +542,7 @@ } }); - Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { + instrumenter.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { @TruffleBoundary @Override public void tagTrappedAt(Node node, MaterializedFrame mFrame) { @@ -563,8 +563,8 @@ @Override protected void unsetStrategy() { - Probe.setBeforeTagTrap(null); - Probe.setAfterTagTrap(null); + instrumenter.setBeforeTagTrap(null); + instrumenter.setAfterTagTrap(null); } } @@ -592,7 +592,7 @@ @Override protected void setStrategy(final int stackDepth) { - Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { + instrumenter.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { @TruffleBoundary @Override public void tagTrappedAt(Node node, MaterializedFrame mFrame) { @@ -613,7 +613,7 @@ @Override protected void unsetStrategy() { - Probe.setBeforeTagTrap(null); + instrumenter.setBeforeTagTrap(null); } } @@ -813,7 +813,8 @@ protected Closeable executionStart(Object vm, Debugger[] fillIn, Source s) { final Debugger d; if (fillIn[0] == null) { - d = fillIn[0] = new Debugger(vm); + final Instrumenter instrumenter = ACCESSOR.getInstrumenter(vm); + d = fillIn[0] = new Debugger(vm, instrumenter); } else { d = fillIn[0]; } @@ -842,8 +843,14 @@ } @Override - protected DebugSupportProvider getDebugSupport(TruffleLanguage l) { - return super.getDebugSupport(l); + protected Instrumenter getInstrumenter(Object vm) { + return super.getInstrumenter(vm); + } + + @Override + protected AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Object vm, Class languageClass, String expr, + AdvancedInstrumentResultListener resultListener) throws IOException { + return super.createAdvancedInstrumentRootFactory(vm, languageClass, expr, resultListener); } @Override diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,20 +24,32 @@ */ package com.oracle.truffle.api.debug; -import com.oracle.truffle.api.Assumption; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.Truffle; import static com.oracle.truffle.api.debug.Breakpoint.State.DISABLED; import static com.oracle.truffle.api.debug.Breakpoint.State.DISABLED_UNRESOLVED; import static com.oracle.truffle.api.debug.Breakpoint.State.DISPOSED; import static com.oracle.truffle.api.debug.Breakpoint.State.ENABLED; import static com.oracle.truffle.api.debug.Breakpoint.State.ENABLED_UNRESOLVED; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.debug.Debugger.BreakpointCallback; import com.oracle.truffle.api.debug.Debugger.WarningLog; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; 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.StandardSyntaxTag; import com.oracle.truffle.api.instrument.SyntaxTag; @@ -48,15 +60,6 @@ import com.oracle.truffle.api.source.LineLocation; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.utilities.CyclicAssumption; -import java.io.IOException; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; //TODO (mlvdv) some common functionality could be factored out of this and TagBreakpointSupport @@ -83,7 +86,7 @@ private static final boolean TRACE = false; private static final PrintStream OUT = System.out; - private static final String BREAKPOINT_NAME = "LINE BREAKPOINT"; + private static final String BREAKPOINT_NAME = "Line Breakpoints"; @TruffleBoundary private static void trace(String format, Object... args) { @@ -106,6 +109,7 @@ } }; + private final Debugger debugger; private final BreakpointCallback breakpointCallback; private final WarningLog warningLog; @@ -127,17 +131,17 @@ */ @CompilationFinal private boolean breakpointsActive = true; private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active"); - private final Debugger debugger; LineBreakpointFactory(Debugger debugger, BreakpointCallback breakpointCallback, final WarningLog warningLog) { this.debugger = debugger; this.breakpointCallback = breakpointCallback; this.warningLog = warningLog; + final Instrumenter instrumenter = debugger.getInstrumenter(); lineToProbesMap = new LineToProbesMap(); - lineToProbesMap.install(); + lineToProbesMap.install(instrumenter); - Probe.addProbeListener(new DefaultProbeListener() { + instrumenter.addProbeListener(new DefaultProbeListener() { @Override public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) { diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineToProbesMap.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineToProbesMap.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineToProbesMap.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,6 +24,13 @@ */ package com.oracle.truffle.api.debug; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import com.oracle.truffle.api.instrument.InstrumentationTool; import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.instrument.ProbeListener; @@ -31,12 +38,6 @@ import com.oracle.truffle.api.source.LineLocation; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; /** * An {@link InstrumentationTool} that builds a map of every {@link Probe} attached to some AST, @@ -68,7 +69,7 @@ @Override protected boolean internalInstall() { - Probe.addProbeListener(probeListener); + getInstrumenter().addProbeListener(probeListener); return true; } @@ -79,7 +80,7 @@ @Override protected void internalDispose() { - Probe.removeProbeListener(probeListener); + getInstrumenter().removeProbeListener(probeListener); } /** diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java Wed Sep 16 15:36:22 2015 -0700 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; 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.SyntaxTag; import com.oracle.truffle.api.instrument.SyntaxTagTrap; @@ -62,10 +63,10 @@ * Support class for creating and managing "Tag Breakpoints". A Tag Breakpoint halts execution just * before reaching any node whose Probe carries a specified {@linkplain SyntaxTag Tag}. *

- * The {@linkplain Probe#setBeforeTagTrap(SyntaxTagTrap) Tag Trap}, which is built directly into the - * Instrumentation Framework, does the same thing more efficiently, but there may only be one Tag - * Trap active at a time. Any number of tag breakpoints may coexist with the Tag Trap, but it would - * be confusing to have a Tag Breakpoint set for the same Tag as the current Tag Trap. + * The {@linkplain Instrumenter#setBeforeTagTrap(SyntaxTagTrap) Tag Trap}, which is built directly + * into the Instrumentation Framework, does the same thing more efficiently, but there may only be + * one Tag Trap active at a time. Any number of tag breakpoints may coexist with the Tag Trap, but + * it would be confusing to have a Tag Breakpoint set for the same Tag as the current Tag Trap. *

* Notes: *

    @@ -103,6 +104,7 @@ } }; + private final Debugger debugger; private final BreakpointCallback breakpointCallback; private final WarningLog warningLog; @@ -117,14 +119,13 @@ */ @CompilationFinal private boolean breakpointsActive = true; private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active"); - private final Debugger debugger; TagBreakpointFactory(Debugger debugger, BreakpointCallback breakpointCallback, final WarningLog warningLog) { this.debugger = debugger; this.breakpointCallback = breakpointCallback; this.warningLog = warningLog; - Probe.addProbeListener(new DefaultProbeListener() { + debugger.getInstrumenter().addProbeListener(new DefaultProbeListener() { @Override public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) { @@ -195,7 +196,7 @@ tagToBreakpoint.put(tag, breakpoint); - for (Probe probe : Probe.findProbesTaggedAs(tag)) { + for (Probe probe : debugger.getInstrumenter().findProbesTaggedAs(tag)) { breakpoint.attach(probe); } } else { diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,6 +24,13 @@ */ package com.oracle.truffle.api.impl; +import java.io.Closeable; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.Truffle; @@ -31,27 +38,29 @@ import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.debug.DebugSupportProvider; import com.oracle.truffle.api.debug.Debugger; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.instrument.ASTProber; +import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; +import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; +import com.oracle.truffle.api.instrument.Instrumenter; import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.instrument.ToolSupportProvider; +import com.oracle.truffle.api.instrument.Visualizer; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.Source; -import java.io.Closeable; -import java.io.IOException; -import java.io.Reader; -import java.io.Writer; -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; /** - * Communication between TruffleVM and TruffleLanguage API/SPI. + * Communication between TruffleVM, TruffleLanguage API/SPI, and other services. */ @SuppressWarnings("rawtypes") public abstract class Accessor { private static Accessor API; private static Accessor SPI; private static Accessor NODES; + private static Accessor INTEROP; private static Accessor INSTRUMENT; + private static Accessor TOOL; private static Accessor DEBUG; private static final ThreadLocal CURRENT_VM = new ThreadLocal<>(); @@ -72,11 +81,13 @@ return false; } + @SuppressWarnings("deprecation") @Override protected ToolSupportProvider getToolSupport() { - return null; + throw new UnsupportedOperationException(); } + @SuppressWarnings("deprecation") @Override protected DebugSupportProvider getDebugSupport() { return null; @@ -91,12 +102,39 @@ protected Object createContext(TruffleLanguage.Env env) { return null; } + + @Override + protected ASTProber getDefaultASTProber() { + return null; + } + + @Override + protected Visualizer getVisualizer() { + return null; + } + + @SuppressWarnings("deprecation") + @Override + protected void enableASTProbing(ASTProber astProber) { + throw new UnsupportedOperationException(); + } + + @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; + } }; lng.hashCode(); new Node(null) { }.getRootNode(); try { + Class.forName(Instrumenter.class.getName(), true, Instrumenter.class.getClassLoader()); Class.forName(Debugger.class.getName(), true, Debugger.class.getClassLoader()); } catch (ClassNotFoundException ex) { throw new IllegalStateException(ex); @@ -114,6 +152,11 @@ throw new IllegalStateException(); } NODES = this; + } else if (this.getClass().getSimpleName().endsWith("Interop")) { + if (INTEROP != null) { + throw new IllegalStateException(); + } + INTEROP = this; } else if (this.getClass().getSimpleName().endsWith("Instrument")) { if (INSTRUMENT != null) { throw new IllegalStateException(); @@ -124,6 +167,11 @@ throw new IllegalStateException(); } DEBUG = this; + } else if (this.getClass().getSimpleName().endsWith("Tool")) { + if (TOOL != null) { + throw new IllegalStateException(); + } + TOOL = this; } else { if (SPI != null) { throw new IllegalStateException(); @@ -152,12 +200,23 @@ return API.languageGlobal(env); } - protected ToolSupportProvider getToolSupport(TruffleLanguage l) { - return API.getToolSupport(l); + @Deprecated + protected ToolSupportProvider getToolSupport(@SuppressWarnings("unused") TruffleLanguage l) { + throw new UnsupportedOperationException(); } - protected DebugSupportProvider getDebugSupport(TruffleLanguage l) { - return API.getDebugSupport(l); + @Deprecated + protected DebugSupportProvider getDebugSupport(@SuppressWarnings("unused") TruffleLanguage l) { + throw new UnsupportedOperationException(); + } + + protected ASTProber getDefaultASTProber(TruffleLanguage language) { + return API.getDefaultASTProber(language); + } + + protected AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Object vm, Class languageClass, String expr, AdvancedInstrumentResultListener resultListener) + throws IOException { + return API.createAdvancedInstrumentRootFactory(vm, languageClass, expr, resultListener); } protected Class findLanguage(RootNode n) { @@ -184,6 +243,36 @@ return SPI.findLanguage(vm, languageClass); } + protected TruffleLanguage findLanguageImpl(Object known, Class languageClass) { + Object vm; + if (known == null) { + vm = CURRENT_VM.get(); + if (vm == null) { + throw new IllegalStateException(); + } + } else { + vm = known; + } + return SPI.findLanguageImpl(vm, languageClass); + } + + protected Instrumenter getInstrumenter(Object known) { + Object vm; + if (known == null) { + vm = CURRENT_VM.get(); + if (vm == null) { + throw new IllegalStateException(); + } + } else { + vm = known; + } + return SPI.getInstrumenter(vm); + } + + protected Instrumenter createInstrumenter() { + return INSTRUMENT.createInstrumenter(); + } + private static Reference previousVM = new WeakReference<>(null); private static Assumption oneVM = Truffle.getRuntime().createAssumption(); @@ -237,4 +326,8 @@ protected TruffleLanguage findLanguage(Env env) { return API.findLanguage(env); } + + protected void applyInstrumentation(Node node) { + INSTRUMENT.applyInstrumentation(node); + } } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTProber.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTProber.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTProber.java Wed Sep 16 15:36:22 2015 -0700 @@ -31,7 +31,7 @@ * not yet executed) AST. * * @see Probe - * @see Probe#addProbeListener(ProbeListener) + * @see Instrumenter#addProbeListener(ProbeListener) */ public interface ASTProber { @@ -40,6 +40,6 @@ * {@linkplain Probe Probes} to them. Ignore {@linkplain Node#isInstrumentable() * non-instrumentable} nodes. */ - void probeAST(Node node); + void probeAST(Instrumenter instrumenter, Node node); } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationTool.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationTool.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationTool.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,13 +24,15 @@ */ package com.oracle.truffle.api.instrument; +import com.oracle.truffle.api.impl.Accessor; + /** * {@linkplain Instrument Instrumentation}-based tools that gather data during Guest Language * program execution. *

    * Tools share a common life cycle: *

      - *
    • A newly created tool is inert until {@linkplain #install() installed}.
    • + *
    • A newly created tool is inert until {@linkplain #install(Instrumenter) installed}.
    • *
    • An installed tool becomes enabled and immediately begins installing * {@linkplain Instrument instrumentation} on subsequently created ASTs and collecting data from * those instruments
    • @@ -83,6 +85,8 @@ private ToolState toolState = ToolState.UNINSTALLED; + private Instrumenter instrumenter; + protected InstrumentationTool() { } @@ -92,8 +96,11 @@ * * @throws IllegalStateException if the tool has previously been installed. */ - public final void install() { + public final void install(Instrumenter inst) { checkUninstalled(); + if (inst != null) { + this.instrumenter = inst; + } if (internalInstall()) { toolState = ToolState.ENABLED; } @@ -157,6 +164,13 @@ protected abstract void internalDispose(); + protected final Instrumenter getInstrumenter() { + if (instrumenter == null) { + instrumenter = ACCESSOR.getInstrumenter(null); + } + return instrumenter; + } + /** * Ensure that the tool is currently installed. * @@ -182,4 +196,14 @@ } } + static final class AccessorTool extends Accessor { + + @Override + protected Instrumenter getInstrumenter(Object vm) { + return super.getInstrumenter(null); + } + } + + static final AccessorTool ACCESSOR = new AccessorTool(); + } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java Wed Sep 16 15:36:22 2015 -0700 @@ -0,0 +1,354 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.instrument; + +import java.io.PrintStream; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeVisitor; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.source.SourceSection; + +/** + * Access to instrumentation services in an instance of {@link TruffleVM}. + */ +public final class Instrumenter { + + private static final boolean TRACE = false; + private static final String TRACE_PREFIX = "Instrumenter: "; + private static final PrintStream OUT = System.out; + + private static void trace(String format, Object... args) { + if (TRACE) { + OUT.println(TRACE_PREFIX + String.format(format, args)); + } + } + + /** + * Walks an AST, looking for the first node with an assigned {@link SourceSection} and returning + * the {@link Source}. + */ + private static Source findSource(Node node) { + final FindSourceVisitor visitor = new FindSourceVisitor(); + node.accept(visitor); + return visitor.source; + } + + private final Set astProbers = Collections.synchronizedSet(new LinkedHashSet()); + + private final List probeListeners = new ArrayList<>(); + + /** + * All Probes that have been created. + */ + private final List> probes = new ArrayList<>(); + + /** + * A global trap that triggers notification just before executing any Node that is Probed with a + * matching tag. + */ + @CompilationFinal private SyntaxTagTrap beforeTagTrap = null; + + /** + * A global trap that triggers notification just after executing any Node that is Probed with a + * matching tag. + */ + @CompilationFinal private SyntaxTagTrap afterTagTrap = null; + + private static final class FindSourceVisitor implements NodeVisitor { + + Source source = null; + + public boolean visit(Node node) { + final SourceSection sourceSection = node.getSourceSection(); + if (sourceSection != null) { + source = sourceSection.getSource(); + return false; + } + return true; + } + } + + Instrumenter() { + } + + /** + * Enables {@linkplain Instrument instrumentation} of a node, where the node is presumed to be + * part of a well-formed Truffle AST that is not being executed. If this node has not already + * been probed, modifies the AST by inserting a {@linkplain WrapperNode wrapper node} between + * the node and its parent; the wrapper node must be provided by implementations of + * {@link Node#createWrapperNode()}. No more than one {@link Probe} may be associated with a + * node, so a {@linkplain WrapperNode wrapper} may not wrap another {@linkplain WrapperNode + * wrapper}. + * + * @return a (possibly newly created) {@link Probe} associated with this node. + * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged + */ + @SuppressWarnings("rawtypes") + public Probe probe(Node node) { + + final Node parent = node.getParent(); + + if (node instanceof WrapperNode) { + throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, node, null); + } + + if (parent == null) { + throw new ProbeException(ProbeFailure.Reason.NO_PARENT, null, node, null); + } + + if (parent instanceof WrapperNode) { + final WrapperNode wrapper = (WrapperNode) parent; + if (TRACE) { + final Probe probe = wrapper.getProbe(); + final SourceSection sourceSection = wrapper.getChild().getSourceSection(); + final String location = sourceSection == null ? "" : sourceSection.getShortDescription(); + trace("PROBE FOUND %s %s %s", "Probe@", location, probe.getTagsDescription()); + } + return wrapper.getProbe(); + } + + if (!(node.isInstrumentable())) { + throw new ProbeException(ProbeFailure.Reason.NOT_INSTRUMENTABLE, parent, node, null); + } + + // Create a new wrapper/probe with this node as its child. + final WrapperNode wrapper = node.createWrapperNode(); + + if (wrapper == null || !(wrapper instanceof Node)) { + throw new ProbeException(ProbeFailure.Reason.NO_WRAPPER, parent, node, wrapper); + } + + final Node wrapperNode = (Node) wrapper; + + if (!node.isSafelyReplaceableBy(wrapperNode)) { + throw new ProbeException(ProbeFailure.Reason.WRAPPER_TYPE, parent, node, wrapper); + } + + final SourceSection sourceSection = wrapper.getChild().getSourceSection(); + final ProbeNode probeNode = new ProbeNode(); + Class l = ACCESSOR.findLanguage(wrapper.getChild().getRootNode()); + final Probe probe = new Probe(this, l, probeNode, sourceSection); + probes.add(new WeakReference<>(probe)); + probeNode.probe = probe; // package private access + wrapper.insertProbe(probeNode); + node.replace(wrapperNode); + if (TRACE) { + final String location = sourceSection == null ? "" : sourceSection.getShortDescription(); + trace("PROBED %s %s %s", "Probe@", location, probe.getTagsDescription()); + } + for (ProbeListener listener : probeListeners) { + listener.newProbeInserted(probe); + } + return probe; + } + + /** + * Adds a {@link ProbeListener} to receive events. + */ + public void addProbeListener(ProbeListener listener) { + assert listener != null; + probeListeners.add(listener); + } + + /** + * Removes a {@link ProbeListener}. Ignored if listener not found. + */ + public void removeProbeListener(ProbeListener listener) { + probeListeners.remove(listener); + } + + /** + * Returns all {@link Probe}s holding a particular {@link SyntaxTag}, or the whole collection of + * probes if the specified tag is {@code null}. + * + * @return A collection of probes containing the given tag. + */ + public Collection findProbesTaggedAs(SyntaxTag tag) { + final List taggedProbes = new ArrayList<>(); + for (WeakReference ref : probes) { + Probe probe = ref.get(); + if (probe != null) { + if (tag == null || probe.isTaggedAs(tag)) { + taggedProbes.add(ref.get()); + } + } + } + return taggedProbes; + } + + // TODO (mlvdv) generalize to permit multiple "before traps" without a performance hit? + /** + * Sets the current "before tag trap"; there can be no more than one in effect. + *
        + *
      • The before-trap triggers a callback just before execution + * reaches any {@link Probe} (either existing or subsequently created) + * with the specified {@link SyntaxTag}.
      • + *
      • Setting the before-trap to {@code null} clears an existing before-trap.
      • + *
      • Setting a non{@code -null} before-trap when one is already set clears the previously set + * before-trap.
      • + *
      + * + * @param newBeforeTagTrap The new "before" {@link SyntaxTagTrap} to set. + */ + public void setBeforeTagTrap(SyntaxTagTrap newBeforeTagTrap) { + beforeTagTrap = newBeforeTagTrap; + for (WeakReference ref : probes) { + final Probe probe = ref.get(); + if (probe != null) { + probe.notifyTrapsChanged(); + } + } + } + + // TODO (mlvdv) generalize to permit multiple "after traps" without a performance hit? + /** + * Sets the current "after tag trap"; there can be no more than one in effect. + *
        + *
      • The after-trap triggers a callback just after execution leaves + * any {@link Probe} (either existing or subsequently created) with + * the specified {@link SyntaxTag}.
      • + *
      • Setting the after-trap to {@code null} clears an existing after-trap.
      • + *
      • Setting a non{@code -null} after-trap when one is already set clears the previously set + * after-trap.
      • + *
      + * + * @param newAfterTagTrap The new "after" {@link SyntaxTagTrap} to set. + */ + public void setAfterTagTrap(SyntaxTagTrap newAfterTagTrap) { + afterTagTrap = newAfterTagTrap; + for (WeakReference ref : probes) { + final Probe probe = ref.get(); + if (probe != null) { + probe.notifyTrapsChanged(); + } + } + } + + /** + * Enables instrumentation at selected nodes in all subsequently constructed ASTs. Ignored if + * the argument is already registered, runtime error if argument is {@code null}. + */ + public void registerASTProber(ASTProber prober) { + if (prober == null) { + throw new IllegalArgumentException("Register non-null ASTProbers"); + } + astProbers.add(prober); + } + + public void unregisterASTProber(ASTProber prober) { + astProbers.remove(prober); + } + + @SuppressWarnings("unused") + void executionStarted(Source s) { + } + + void executionEnded() { + } + + void tagAdded(Probe probe, SyntaxTag tag, Object tagValue) { + for (ProbeListener listener : probeListeners) { + listener.probeTaggedAs(probe, tag, tagValue); + } + } + + SyntaxTagTrap getBeforeTagTrap() { + return beforeTagTrap; + } + + SyntaxTagTrap getAfterTagTrap() { + return afterTagTrap; + } + + /** + * Enables instrumentation in a newly created AST by applying all registered instances of + * {@link ASTProber}. + */ + private void applyInstrumentation(Node node) { + + String name = ""; + final Source source = findSource(node); + if (source != null) { + name = source.getShortName(); + } else { + final SourceSection sourceSection = node.getEncapsulatingSourceSection(); + if (sourceSection != null) { + name = sourceSection.getShortDescription(); + } + } + trace("START %s", name); + for (ProbeListener listener : probeListeners) { + listener.startASTProbing(source); + } + for (ASTProber prober : astProbers) { + prober.probeAST(this, node); // TODO (mlvdv) + } + for (ProbeListener listener : probeListeners) { + listener.endASTProbing(source); + } + trace("FINISHED %s", name); + } + + static final class AccessorInstrument extends Accessor { + + @Override + protected Instrumenter createInstrumenter() { + return new Instrumenter(); + } + + @SuppressWarnings("rawtypes") + @Override + protected Class findLanguage(RootNode n) { + return super.findLanguage(n); + } + + @SuppressWarnings("rawtypes") + @Override + protected Class findLanguage(Probe probe) { + return probe.getLanguage(); + } + + @Override + protected void applyInstrumentation(Node node) { + super.getInstrumenter(null).applyInstrumentation(node); + } + } + + static final AccessorInstrument ACCESSOR = new AccessorInstrument(); + +} diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,18 +24,6 @@ */ package com.oracle.truffle.api.instrument; -import com.oracle.truffle.api.Assumption; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.impl.Accessor; -import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; -import com.oracle.truffle.api.nodes.InvalidAssumptionException; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeVisitor; -import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.api.source.Source; -import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.api.utilities.CyclicAssumption; import java.io.PrintStream; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -43,7 +31,14 @@ import java.util.Collections; import java.util.List; -//TODO (mlvdv) these statics should not be global. Move them to some kind of context. +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; +import com.oracle.truffle.api.nodes.InvalidAssumptionException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.api.utilities.CyclicAssumption; /** * A binding between: @@ -75,13 +70,14 @@ * arriving at the "probed" AST Node and notify each attached {@link Instrument} before execution is * allowed to proceed to the child and again after execution completes. * - *
    • The method {@link Node#probe()} creates a Probe on an AST Node; redundant calls return the - * same Probe.
    • + *
    • The method {@link Instrumenter#probe(Node)} creates a Probe on an AST Node; redundant calls + * return the same Probe.
    • * *
    • The "probing" of a Truffle AST must be done after the AST is complete (i.e. parent pointers - * correctly assigned), but before any cloning or executions. This is done by creating an instance - * of {@link ASTProber} and registering it via {@link #registerASTProber(ASTProber)}. Once - * registered, it will be applied automatically to every newly created AST.
    • + * correctly assigned), but before any cloning or executions. This is done by applying instances of + * {@link ASTProber} provided by each language implementation, combined with any instances + * registered by tools via {@link Instrumenter#registerASTProber(ASTProber)}. Once registered, these + * will be applied automatically to every newly created AST. * *
    • The "probing" of an AST Node is implemented by insertion of a {@link ProbeNode.WrapperNode} * into the AST (as new parent of the Node being probed), together with an associated @@ -121,173 +117,7 @@ } } - private static final List astProbers = new ArrayList<>(); - - private static final List probeListeners = new ArrayList<>(); - - /** - * All Probes that have been created. - */ - private static final List> probes = new ArrayList<>(); - - /** - * A global trap that triggers notification just before executing any Node that is Probed with a - * matching tag. - */ - @CompilationFinal private static SyntaxTagTrap beforeTagTrap = null; - - /** - * A global trap that triggers notification just after executing any Node that is Probed with a - * matching tag. - */ - @CompilationFinal private static SyntaxTagTrap afterTagTrap = null; - - private static final class FindSourceVisitor implements NodeVisitor { - - Source source = null; - - public boolean visit(Node node) { - final SourceSection sourceSection = node.getSourceSection(); - if (sourceSection != null) { - source = sourceSection.getSource(); - return false; - } - return true; - } - } - - /** - * Walks an AST, looking for the first node with an assigned {@link SourceSection} and returning - * the {@link Source}. - */ - private static Source findSource(Node node) { - final FindSourceVisitor visitor = new FindSourceVisitor(); - node.accept(visitor); - return visitor.source; - } - - /** - * Enables instrumentation at selected nodes in all subsequently constructed ASTs. - */ - public static void registerASTProber(ASTProber prober) { - astProbers.add(prober); - } - - public static void unregisterASTProber(ASTProber prober) { - astProbers.remove(prober); - } - - /** - * Enables instrumentation in a newly created AST by applying all registered instances of - * {@link ASTProber}. - */ - public static void applyASTProbers(Node node) { - - String name = ""; - final Source source = findSource(node); - if (source != null) { - name = source.getShortName(); - } else { - final SourceSection sourceSection = node.getEncapsulatingSourceSection(); - if (sourceSection != null) { - name = sourceSection.getShortDescription(); - } - } - trace("START %s", name); - for (ProbeListener listener : probeListeners) { - listener.startASTProbing(source); - } - for (ASTProber prober : astProbers) { - prober.probeAST(node); - } - for (ProbeListener listener : probeListeners) { - listener.endASTProbing(source); - } - trace("FINISHED %s", name); - } - - /** - * Adds a {@link ProbeListener} to receive events. - */ - public static void addProbeListener(ProbeListener listener) { - assert listener != null; - probeListeners.add(listener); - } - - /** - * Removes a {@link ProbeListener}. Ignored if listener not found. - */ - public static void removeProbeListener(ProbeListener listener) { - probeListeners.remove(listener); - } - - /** - * Returns all {@link Probe}s holding a particular {@link SyntaxTag}, or the whole collection of - * probes if the specified tag is {@code null}. - * - * @return A collection of probes containing the given tag. - */ - public static Collection findProbesTaggedAs(SyntaxTag tag) { - final List taggedProbes = new ArrayList<>(); - for (WeakReference ref : probes) { - Probe probe = ref.get(); - if (probe != null) { - if (tag == null || probe.isTaggedAs(tag)) { - taggedProbes.add(ref.get()); - } - } - } - return taggedProbes; - } - - // TODO (mlvdv) generalize to permit multiple "before traps" without a performance hit? - /** - * Sets the current "before tag trap"; there can be no more than one in effect. - *
        - *
      • The before-trap triggers a callback just before execution - * reaches any {@link Probe} (either existing or subsequently created) - * with the specified {@link SyntaxTag}.
      • - *
      • Setting the before-trap to {@code null} clears an existing before-trap.
      • - *
      • Setting a non{@code -null} before-trap when one is already set clears the previously set - * before-trap.
      • - *
      - * - * @param newBeforeTagTrap The new "before" {@link SyntaxTagTrap} to set. - */ - public static void setBeforeTagTrap(SyntaxTagTrap newBeforeTagTrap) { - beforeTagTrap = newBeforeTagTrap; - for (WeakReference ref : probes) { - final Probe probe = ref.get(); - if (probe != null) { - probe.notifyTrapsChanged(); - } - } - } - - // TODO (mlvdv) generalize to permit multiple "after traps" without a performance hit? - /** - * Sets the current "after tag trap"; there can be no more than one in effect. - *
        - *
      • The after-trap triggers a callback just after execution leaves - * any {@link Probe} (either existing or subsequently created) with - * the specified {@link SyntaxTag}.
      • - *
      • Setting the after-trap to {@code null} clears an existing after-trap.
      • - *
      • Setting a non{@code -null} after-trap when one is already set clears the previously set - * after-trap.
      • - *
      - * - * @param newAfterTagTrap The new "after" {@link SyntaxTagTrap} to set. - */ - public static void setAfterTagTrap(SyntaxTagTrap newAfterTagTrap) { - afterTagTrap = newAfterTagTrap; - for (WeakReference ref : probes) { - final Probe probe = ref.get(); - if (probe != null) { - probe.notifyTrapsChanged(); - } - } - } - + private final Instrumenter instrumenter; private final SourceSection sourceSection; private final ArrayList tags = new ArrayList<>(); private final List> probeNodeClones = new ArrayList<>(); @@ -313,17 +143,10 @@ /** * Intended for use only by {@link ProbeNode}. */ - Probe(Class l, ProbeNode probeNode, SourceSection sourceSection) { + Probe(Instrumenter instrumenter, Class l, ProbeNode probeNode, SourceSection sourceSection) { + this.instrumenter = instrumenter; this.sourceSection = sourceSection; - probes.add(new WeakReference<>(this)); registerProbeNodeClone(probeNode); - if (TRACE) { - final String location = this.sourceSection == null ? "" : sourceSection.getShortDescription(); - trace("ADDED %s %s %s", "Probe@", location, getTagsDescription()); - } - for (ProbeListener listener : probeListeners) { - listener.newProbeInserted(this); - } this.language = l; } @@ -351,16 +174,16 @@ assert tag != null; if (!tags.contains(tag)) { tags.add(tag); - for (ProbeListener listener : probeListeners) { - listener.probeTaggedAs(this, tag, tagValue); - } + instrumenter.tagAdded(this, tag, tagValue); // Update the status of this Probe with respect to global tag traps boolean tagTrapsChanged = false; + final SyntaxTagTrap beforeTagTrap = instrumenter.getBeforeTagTrap(); if (beforeTagTrap != null && tag == beforeTagTrap.getTag()) { this.isBeforeTrapActive = true; tagTrapsChanged = true; } + final SyntaxTagTrap afterTagTrap = instrumenter.getAfterTagTrap(); if (afterTagTrap != null && tag == afterTagTrap.getTag()) { this.isAfterTrapActive = true; tagTrapsChanged = true; @@ -439,23 +262,27 @@ /** * Gets the currently active before {@linkplain SyntaxTagTrap Tag * Trap} at this Probe. Non{@code -null} if the global - * {@linkplain Probe#setBeforeTagTrap(SyntaxTagTrap) Before Tag Trap} is set and if this Probe - * holds the {@link SyntaxTag} specified in the trap. + * {@linkplain Instrumenter#setBeforeTagTrap(SyntaxTagTrap) Before Tag Trap} is set and if this + * Probe holds the {@link SyntaxTag} specified in the trap. */ SyntaxTagTrap getBeforeTrap() { checkProbeUnchanged(); - return isBeforeTrapActive ? beforeTagTrap : null; + return isBeforeTrapActive ? instrumenter.getBeforeTagTrap() : null; } /** * Gets the currently active after {@linkplain SyntaxTagTrap Tag Trap} * at this Probe. Non{@code -null} if the global - * {@linkplain Probe#setAfterTagTrap(SyntaxTagTrap) After Tag Trap} is set and if this Probe - * holds the {@link SyntaxTag} specified in the trap. + * {@linkplain Instrumenter#setAfterTagTrap(SyntaxTagTrap) After Tag Trap} is set and if this + * Probe holds the {@link SyntaxTag} specified in the trap. */ SyntaxTagTrap getAfterTrap() { checkProbeUnchanged(); - return isAfterTrapActive ? afterTagTrap : null; + return isAfterTrapActive ? instrumenter.getAfterTagTrap() : null; + } + + Class getLanguage() { + return language; } /** @@ -476,13 +303,15 @@ probeStateUnchangedCyclic.invalidate(); } - private void notifyTrapsChanged() { + void notifyTrapsChanged() { + final SyntaxTagTrap beforeTagTrap = instrumenter.getBeforeTagTrap(); this.isBeforeTrapActive = beforeTagTrap != null && this.isTaggedAs(beforeTagTrap.getTag()); + final SyntaxTagTrap afterTagTrap = instrumenter.getAfterTagTrap(); this.isAfterTrapActive = afterTagTrap != null && this.isTaggedAs(afterTagTrap.getTag()); invalidateProbeUnchanged(); } - private String getTagsDescription() { + String getTagsDescription() { final StringBuilder sb = new StringBuilder(); sb.append("["); String prefix = ""; @@ -494,18 +323,4 @@ sb.append("]"); return sb.toString(); } - - static final class AccessorInstrument extends Accessor { - @Override - protected Class findLanguage(RootNode n) { - return super.findLanguage(n); - } - - @Override - protected Class findLanguage(Probe probe) { - return probe.language; - } - } - - static final AccessorInstrument ACCESSOR = new AccessorInstrument(); } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeException.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeException.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeException.java Wed Sep 16 15:36:22 2015 -0700 @@ -28,7 +28,8 @@ import com.oracle.truffle.api.nodes.Node; /** - * An exception thrown when {@link Node#probe()} fails because of an implementation failure. + * An exception thrown when {@link Instrumenter#probe(Node)} fails because of an implementation + * failure. *

      * Language and tool implementations should ensure that clients of tools never see this exception. */ diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java Wed Sep 16 15:36:22 2015 -0700 @@ -78,7 +78,7 @@ private final Object wrapper; /** - * Description of an internal failure of {@link Node#probe()}. + * Description of an internal failure of {@link Instrumenter#probe(Node)}. * * @param reason what caused the failure * @param parent the parent, if known, of the child being probed diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java Wed Sep 16 15:36:22 2015 -0700 @@ -41,10 +41,11 @@ void startASTProbing(Source source); /** - * Notifies that a {@link Probe} has been newly attached to an AST via {@link Node#probe()}. + * Notifies that a {@link Probe} has been newly attached to an AST via + * {@link Instrumenter#probe(Node)}. *

      * There can be no more than one {@link Probe} at a node; this notification will only be - * delivered the first time {@linkplain Node#probe() probe()} is called at a particular AST + * delivered the first time {@linkplain Instrumenter#probe(Node)} is called at a particular AST * node. There will also be no notification when the AST to which the Probe is attached is * cloned. */ diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Wed Sep 16 15:36:22 2015 -0700 @@ -26,14 +26,12 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrument.Instrument.AbstractInstrumentNode; import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; 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.source.SourceSection; /** * Implementation class & interface for enabling the attachment of {@linkplain Probe Probes} to @@ -116,20 +114,6 @@ void insertProbe(ProbeNode probeNode); } - /** - * Create a new {@link Probe} associated with, and attached to, a Guest Language specific - * instance of {@link WrapperNode}. - */ - @SuppressWarnings("rawtypes") - public static Probe insertProbe(WrapperNode wrapper) { - final SourceSection sourceSection = wrapper.getChild().getSourceSection(); - final ProbeNode probeNode = new ProbeNode(); // private constructor - Class l = Probe.ACCESSOR.findLanguage(wrapper.getChild().getRootNode()); - probeNode.probe = new Probe(l, probeNode, sourceSection); // package private access - wrapper.insertProbe(probeNode); - return probeNode.probe; - } - // Never changed once set. @CompilationFinal Probe probe = null; /** diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,6 +24,15 @@ */ package com.oracle.truffle.api.nodes; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.Callable; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; @@ -34,20 +43,9 @@ import com.oracle.truffle.api.impl.Accessor; import com.oracle.truffle.api.instrument.Instrument; import com.oracle.truffle.api.instrument.Probe; -import com.oracle.truffle.api.instrument.ProbeException; -import com.oracle.truffle.api.instrument.ProbeFailure; -import com.oracle.truffle.api.instrument.ProbeNode; import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.utilities.JSONHelper; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.Callable; /** * Abstract base class for all Truffle nodes. @@ -449,57 +447,6 @@ } /** - * Enables {@linkplain Instrument instrumentation} of a node, where the node is presumed to be - * part of a well-formed Truffle AST that is not being executed. If this node has not already - * been probed, modifies the AST by inserting a {@linkplain WrapperNode wrapper node} between - * the node and its parent; the wrapper node must be provided by implementations of - * {@link #createWrapperNode()}. No more than one {@link Probe} may be associated with a node, - * so a {@linkplain WrapperNode wrapper} may not wrap another {@linkplain WrapperNode wrapper}. - * - * @return a (possibly newly created) {@link Probe} associated with this node. - * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged - */ - public final Probe probe() { - - if (this instanceof WrapperNode) { - throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null); - } - - if (parent == null) { - throw new ProbeException(ProbeFailure.Reason.NO_PARENT, null, this, null); - } - - if (parent instanceof WrapperNode) { - return ((WrapperNode) parent).getProbe(); - } - - if (!isInstrumentable()) { - throw new ProbeException(ProbeFailure.Reason.NOT_INSTRUMENTABLE, parent, this, null); - } - - // Create a new wrapper/probe with this node as its child. - final WrapperNode wrapper = createWrapperNode(); - - if (wrapper == null || !(wrapper instanceof Node)) { - throw new ProbeException(ProbeFailure.Reason.NO_WRAPPER, parent, this, wrapper); - } - - final Node wrapperNode = (Node) wrapper; - - if (!this.isSafelyReplaceableBy(wrapperNode)) { - throw new ProbeException(ProbeFailure.Reason.WRAPPER_TYPE, parent, this, wrapper); - } - - // Connect it to a Probe - final Probe probe = ProbeNode.insertProbe(wrapper); - - // Replace this node in the AST with the wrapper - this.replace(wrapperNode); - - return probe; - } - - /** * Converts this node to a textual representation useful for debugging. */ @Override @@ -576,6 +523,10 @@ return ""; } + protected void applyInstrumentation(Node node) { + ACCESSOR.applyInstrumentation(node); + } + private static final Object GIL = new Object(); private static final ThreadLocal IN_ATOMIC_BLOCK = new ThreadLocal() { @@ -605,8 +556,13 @@ protected Class findLanguage(RootNode n) { return n.language; } + + @Override + protected void applyInstrumentation(Node node) { + super.applyInstrumentation(node); + } } // registers into Accessor.NODES - @SuppressWarnings("unused") private static final AccessorNodes ACCESSOR = new AccessorNodes(); + private static final AccessorNodes ACCESSOR = new AccessorNodes(); } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Sep 16 15:36:22 2015 -0700 @@ -36,7 +36,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.impl.DefaultCompilerOptions; import com.oracle.truffle.api.instrument.ASTProber; -import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.source.SourceSection; /** @@ -162,7 +161,7 @@ * stack) without prior knowledge of the language it has come from. * * Used for instance to determine the language of a RootNode: - * + * *

            * 
            * rootNode.getExecutionContext().getLanguageShortName();
      @@ -188,9 +187,10 @@
           }
       
           /**
      -     * Apply all registered instances of {@link ASTProber} to the AST, if any, held by this root
      -     * node. This can only be done once the AST is complete, notably once all parent pointers are
      -     * correctly assigned. But it also must be done before any AST cloning or execution.
      +     * Apply to the AST all instances of {@link ASTProber} specified for the language, if any, held
      +     * by this root node. This can only be done once the AST is complete, notably once all parent
      +     * pointers are correctly assigned. But it also must be done before any AST cloning or
      +     * execution.
            * 

      * If this is not done, then the AST will not be subject to debugging or any other * instrumentation-supported tooling. @@ -198,7 +198,7 @@ * Implementations should ensure that instrumentation is never applied more than once to an AST, * as this is not guaranteed to be error-free. * - * @see Probe#registerASTProber(com.oracle.truffle.api.instrument.ASTProber) + * @see TruffleLanguage */ public void applyInstrumentation() { } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,8 +24,6 @@ */ package com.oracle.truffle.api.source; -import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.TruffleLanguage.Registration; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; @@ -54,6 +52,9 @@ import java.util.logging.Level; import java.util.logging.Logger; +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.TruffleLanguage.Registration; + /** * Representation of a guest language source code unit and its contents. Sources originate in * several ways: @@ -425,7 +426,7 @@ /** * The URL if the source is retrieved via URL. - * + * * @return URL or null */ public abstract URL getURL(); @@ -909,6 +910,8 @@ return "text/x-c"; } else if (file.getName().endsWith(".R") || file.getName().endsWith(".r")) { return "application/x-r"; + } else if (file.getName().endsWith(".js") || file.getName().endsWith(".JS")) { + return "application/javascript"; } else { try { return Files.probeContentType(file.toPath()); @@ -997,6 +1000,8 @@ return "text/x-c"; } else if (file.getName().endsWith(".R") || file.getName().endsWith(".r")) { return "application/x-r"; + } else if (file.getName().endsWith(".js") || file.getName().endsWith(".JS")) { + return "application/javascript"; } else { try { return Files.probeContentType(file.toPath()); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java --- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Wed Sep 16 15:36:22 2015 -0700 @@ -40,23 +40,13 @@ */ package com.oracle.truffle.sl.test.instrument; -import com.oracle.truffle.api.instrument.ASTProber; -import com.oracle.truffle.api.instrument.Instrument; -import com.oracle.truffle.api.instrument.Probe; -import com.oracle.truffle.api.instrument.StandardSyntaxTag; -import com.oracle.truffle.api.instrument.impl.DefaultSimpleInstrumentListener; -import com.oracle.truffle.api.source.Source; -import com.oracle.truffle.api.vm.TruffleVM; -import com.oracle.truffle.sl.nodes.instrument.SLStandardASTProber; -import com.oracle.truffle.sl.nodes.local.SLWriteLocalVariableNode; -import com.oracle.truffle.sl.test.SLTestRunner; -import com.oracle.truffle.sl.test.instrument.SLInstrumentTestRunner.InstrumentTestCase; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; +import java.lang.reflect.Field; import java.nio.charset.Charset; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; @@ -66,6 +56,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; + import org.junit.Assert; import org.junit.internal.TextListener; import org.junit.runner.Description; @@ -78,6 +69,19 @@ import org.junit.runners.ParentRunner; import org.junit.runners.model.InitializationError; +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.StandardSyntaxTag; +import com.oracle.truffle.api.instrument.impl.DefaultSimpleInstrumentListener; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.TruffleVM; +import com.oracle.truffle.sl.nodes.instrument.SLStandardASTProber; +import com.oracle.truffle.sl.nodes.local.SLWriteLocalVariableNode; +import com.oracle.truffle.sl.test.SLTestRunner; +import com.oracle.truffle.sl.test.instrument.SLInstrumentTestRunner.InstrumentTestCase; + /** * This class builds and executes the tests for instrumenting SL. Although much of this class is * written with future automation in mind, at the moment the tests that are created are hard-coded @@ -95,7 +99,7 @@ private static final String LF = System.getProperty("line.separator"); - static class InstrumentTestCase { + static final class InstrumentTestCase { protected final Description name; protected final Path path; protected final String baseName; @@ -116,16 +120,12 @@ private final List testCases; - public SLInstrumentTestRunner(Class testClass) throws InitializationError { + public SLInstrumentTestRunner(Class testClass) throws InitializationError, SecurityException, IllegalArgumentException { super(testClass); - final SLStandardASTProber prober = new SLStandardASTProber(); - Probe.registerASTProber(prober); try { testCases = createTests(testClass); } catch (IOException e) { throw new InitializationError(e); - } finally { - Probe.unregisterASTProber(prober); } } @@ -237,18 +237,23 @@ ByteArrayOutputStream out = new ByteArrayOutputStream(); PrintWriter printer = new PrintWriter(out); final ASTProber prober = new SLStandardASTProber(); - Probe.registerASTProber(prober); + try { // We use the name of the file to determine what visitor to attach to it. if (testCase.baseName.endsWith(ASSIGNMENT_VALUE_SUFFIX)) { // Set up the execution context for Simple and register our two listeners TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(testCase.testInput))).stdOut(printer).build(); + final Field field = TruffleVM.class.getDeclaredField("instrumenter"); + field.setAccessible(true); + final Instrumenter instrumenter = (Instrumenter) field.get(vm); + instrumenter.registerASTProber(prober); + final String src = readAllLines(testCase.path); vm.eval(Source.fromText(src, testCase.path.toString()).withMimeType("application/x-sl")); // Attach an instrument to every probe tagged as an assignment - for (Probe probe : Probe.findProbesTaggedAs(StandardSyntaxTag.ASSIGNMENT)) { + for (Probe probe : instrumenter.findProbesTaggedAs(StandardSyntaxTag.ASSIGNMENT)) { SLPrintAssigmentValueListener slPrintAssigmentValueListener = new SLPrintAssigmentValueListener(printer); probe.attach(Instrument.create(slPrintAssigmentValueListener, "SL print assignment value")); } @@ -265,13 +270,12 @@ } catch (Throwable ex) { notifier.fireTestFailure(new Failure(testCase.name, ex)); } finally { - Probe.unregisterASTProber(prober); notifier.fireTestFinished(testCase.name); } } - public static void runInMain(Class testClass, String[] args) throws InitializationError, NoTestsRemainException { + public static void runInMain(Class testClass, String[] args) throws InitializationError, NoTestsRemainException, SecurityException, IllegalArgumentException { JUnitCore core = new JUnitCore(); core.addListener(new TextListener(System.out)); SLInstrumentTestRunner suite = new SLInstrumentTestRunner(testClass); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java --- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java Wed Sep 16 15:36:22 2015 -0700 @@ -40,11 +40,19 @@ */ package com.oracle.truffle.sl; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.math.BigInteger; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.debug.DebugSupportException; import com.oracle.truffle.api.debug.DebugSupportProvider; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.UnsupportedSpecializationException; @@ -52,7 +60,6 @@ import com.oracle.truffle.api.instrument.ASTProber; import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener; import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory; -import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.instrument.ToolSupportProvider; import com.oracle.truffle.api.instrument.Visualizer; import com.oracle.truffle.api.nodes.GraphPrintVisitor; @@ -102,14 +109,6 @@ import com.oracle.truffle.sl.runtime.SLFunction; import com.oracle.truffle.sl.runtime.SLFunctionRegistry; import com.oracle.truffle.sl.runtime.SLNull; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.math.BigInteger; -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; /** * SL is a simple language to demonstrate and showcase features of Truffle. The implementation is as @@ -186,7 +185,7 @@ */ /* - * + * *

      Tools:
      The use of some of Truffle's support for developer tools (based on the * Truffle Instrumentation Framework) are demonstrated in this file, for example:

      • a * {@linkplain NodeExecCounter counter for node executions}, tabulated by node type; and
      • a @@ -198,8 +197,7 @@ public final class SLLanguage extends TruffleLanguage { private static List> builtins = Collections.emptyList(); private static Visualizer visualizer = new SLDefaultVisualizer(); - private static ASTProber registeredASTProber; // non-null if prober already registered - private DebugSupportProvider debugSupport; + private ASTProber astProber = new SLStandardASTProber(); private SLLanguage() { } @@ -254,6 +252,7 @@ /** * Temporary method during API evolution, supports debugger integration. */ + @Deprecated public static void run(Source source) throws IOException { TruffleVM vm = TruffleVM.newVM().build(); assert vm.getLanguages().containsKey("application/x-sl"); @@ -476,28 +475,56 @@ } @Override - protected ToolSupportProvider getToolSupport() { - return getDebugSupport(); + protected Visualizer getVisualizer() { + if (visualizer == null) { + visualizer = new SLDefaultVisualizer(); + } + return visualizer; + } + + @Override + protected ASTProber getDefaultASTProber() { + return astProber; + } + + @SuppressWarnings("deprecation") + @Override + protected void enableASTProbing(ASTProber prober) { + throw new UnsupportedOperationException(); } @Override + protected Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws IOException { + throw new IllegalStateException("evalInContext not supported in this language"); + } + + @Override + protected AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(String expr, AdvancedInstrumentResultListener resultListener) throws IOException { + throw new IllegalStateException("createAdvancedInstrumentRootFactory not supported in this language"); + } + + @SuppressWarnings("deprecation") + @Override + protected ToolSupportProvider getToolSupport() { + return null; + } + + @SuppressWarnings("deprecation") + @Override protected DebugSupportProvider getDebugSupport() { - if (debugSupport == null) { - debugSupport = new SLDebugProvider(); - } - return debugSupport; + return null; + } + + public Node createFindContextNode0() { + return createFindContextNode(); + } + + public SLContext findContext0(Node contextNode) { + return findContext(contextNode); } // TODO (mlvdv) remove the static hack when we no longer have the static demo variables private static void setupToolDemos() { - // if (statementCounts || coverage) { - // if (registeredASTProber == null) { - // final ASTProber newProber = new SLStandardASTProber(); - // // This should be registered on the TruffleVM - // Probe.registerASTProber(newProber); - // registeredASTProber = newProber; - // } - // } // if (nodeExecCounts) { // nodeExecCounter = new NodeExecCounter(); // nodeExecCounter.install(); @@ -529,46 +556,4 @@ // } } - public Node createFindContextNode0() { - return createFindContextNode(); - } - - public SLContext findContext0(Node contextNode) { - return findContext(contextNode); - } - - private final class SLDebugProvider implements DebugSupportProvider { - - public SLDebugProvider() { - if (registeredASTProber == null) { - registeredASTProber = new SLStandardASTProber(); - // This should be registered on the TruffleVM - Probe.registerASTProber(registeredASTProber); - } - } - - public Visualizer getVisualizer() { - if (visualizer == null) { - visualizer = new SLDefaultVisualizer(); - } - return visualizer; - } - - public void enableASTProbing(ASTProber prober) { - if (prober != null) { - // This should be registered on the TruffleVM - Probe.registerASTProber(prober); - } - } - - public Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws DebugSupportException { - throw new DebugSupportException("evalInContext not supported in this language"); - } - - public AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(String expr, AdvancedInstrumentResultListener resultListener) throws DebugSupportException { - throw new DebugSupportException("createAdvancedInstrumentRootFactory not supported in this language"); - } - - } - } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java --- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Sep 16 15:36:22 2015 -0700 @@ -43,7 +43,6 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.sl.SLLanguage; @@ -100,7 +99,7 @@ @Override public void applyInstrumentation() { - Probe.applyASTProbers(bodyNode); + super.applyInstrumentation(bodyNode); } @Override diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStandardASTProber.java --- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStandardASTProber.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStandardASTProber.java Wed Sep 16 15:36:22 2015 -0700 @@ -40,12 +40,14 @@ */ package com.oracle.truffle.sl.nodes.instrument; -import com.oracle.truffle.api.instrument.ASTProber; -import com.oracle.truffle.api.instrument.InstrumentationNode; -import com.oracle.truffle.api.instrument.Probe; import static com.oracle.truffle.api.instrument.StandardSyntaxTag.ASSIGNMENT; import static com.oracle.truffle.api.instrument.StandardSyntaxTag.START_LOOP; import static com.oracle.truffle.api.instrument.StandardSyntaxTag.STATEMENT; + +import com.oracle.truffle.api.instrument.ASTProber; +import com.oracle.truffle.api.instrument.InstrumentationNode; +import com.oracle.truffle.api.instrument.Instrumenter; +import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeVisitor; import com.oracle.truffle.sl.nodes.SLExpressionNode; @@ -57,39 +59,39 @@ * A visitor which traverses a completely parsed Simple AST (presumed not yet executed) and enables * instrumentation at a few standard kinds of nodes. */ -public class SLStandardASTProber implements NodeVisitor, ASTProber { +public class SLStandardASTProber implements ASTProber { + + public void probeAST(final Instrumenter instrumenter, Node startNode) { + startNode.accept(new NodeVisitor() { - /** - * {@inheritDoc} - *

        - * Instruments and tags all relevant {@link SLStatementNode}s and {@link SLExpressionNode}s. - * Currently, only SLStatementNodes that are not SLExpressionNodes are tagged as statements. - */ - public boolean visit(Node node) { + /** + * Instruments and tags all relevant {@link SLStatementNode}s and + * {@link SLExpressionNode}s. Currently, only SLStatementNodes that are not + * SLExpressionNodes are tagged as statements. + */ + public boolean visit(Node node) { - if (!(node instanceof InstrumentationNode) && node instanceof SLStatementNode && node.getParent() != null && node.getSourceSection() != null) { - // All SL nodes are instrumentable, but treat expressions specially + if (!(node instanceof InstrumentationNode) && node instanceof SLStatementNode && node.getParent() != null && node.getSourceSection() != null) { + // All SL nodes are instrumentable, but treat expressions specially - if (node instanceof SLExpressionNode) { - SLExpressionNode expressionNode = (SLExpressionNode) node; - Probe probe = expressionNode.probe(); - if (node instanceof SLWriteLocalVariableNode) { - probe.tagAs(STATEMENT, null); - probe.tagAs(ASSIGNMENT, null); + if (node instanceof SLExpressionNode) { + SLExpressionNode expressionNode = (SLExpressionNode) node; + final Probe probe = instrumenter.probe(expressionNode); + if (node instanceof SLWriteLocalVariableNode) { + probe.tagAs(STATEMENT, null); + probe.tagAs(ASSIGNMENT, null); + } + } else { + SLStatementNode statementNode = (SLStatementNode) node; + final Probe probe = instrumenter.probe(statementNode); + probe.tagAs(STATEMENT, null); + if (node instanceof SLWhileNode) { + probe.tagAs(START_LOOP, null); + } + } } - } else { - SLStatementNode statementNode = (SLStatementNode) node; - Probe probe = statementNode.probe(); - probe.tagAs(STATEMENT, null); - if (node instanceof SLWhileNode) { - probe.tagAs(START_LOOP, null); - } + return true; } - } - return true; - } - - public void probeAST(Node node) { - node.accept(this); + }); } } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/CoverageTrackerTest.java --- a/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/CoverageTrackerTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/CoverageTrackerTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,25 +24,29 @@ */ package com.oracle.truffle.tools.test; -import com.oracle.truffle.api.instrument.Probe; -import com.oracle.truffle.api.instrument.StandardSyntaxTag; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.tools.CoverageTracker; import static com.oracle.truffle.tools.test.TestNodes.createExpr13TestRootNode; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; + import org.junit.Test; +import com.oracle.truffle.api.instrument.Instrumenter; +import com.oracle.truffle.api.instrument.Probe; +import com.oracle.truffle.api.instrument.StandardSyntaxTag; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.tools.CoverageTracker; + public class CoverageTrackerTest { @Test - public void testNoExecution() { + public void testNoExecution() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final CoverageTracker tool = new CoverageTracker(); assertEquals(tool.getCounts().entrySet().size(), 0); - tool.install(); + tool.install(instrumenter); assertEquals(tool.getCounts().entrySet().size(), 0); tool.setEnabled(false); assertEquals(tool.getCounts().entrySet().size(), 0); @@ -55,37 +59,40 @@ } @Test - public void testToolCreatedTooLate() { - final RootNode expr13rootNode = createExpr13TestRootNode(); + public void testToolCreatedTooLate() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); + final RootNode expr13rootNode = TestNodes.createExpr13TestRootNode(instrumenter); final CoverageTracker tool = new CoverageTracker(); - tool.install(); + tool.install(instrumenter); assertEquals(13, expr13rootNode.execute(null)); assertTrue(tool.getCounts().isEmpty()); tool.dispose(); } @Test - public void testToolInstalledcTooLate() { + public void testToolInstalledcTooLate() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final CoverageTracker tool = new CoverageTracker(); - final RootNode expr13rootNode = createExpr13TestRootNode(); - tool.install(); + final RootNode expr13rootNode = createExpr13TestRootNode(instrumenter); + tool.install(instrumenter); assertEquals(13, expr13rootNode.execute(null)); assertTrue(tool.getCounts().isEmpty()); tool.dispose(); } @Test - public void testCountingCoverage() { + public void testCountingCoverage() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final CoverageTracker tool = new CoverageTracker(); - tool.install(); - final RootNode expr13rootNode = createExpr13TestRootNode(); + tool.install(instrumenter); + final RootNode expr13rootNode = createExpr13TestRootNode(instrumenter); // Not probed yet. assertEquals(13, expr13rootNode.execute(null)); assertTrue(tool.getCounts().isEmpty()); final Node addNode = expr13rootNode.getChildren().iterator().next(); - final Probe probe = addNode.probe(); + final Probe probe = instrumenter.probe(addNode); // Probed but not tagged yet. assertEquals(13, expr13rootNode.execute(null)); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/LineToProbesMapTest.java --- a/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/LineToProbesMapTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/LineToProbesMapTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,30 +24,34 @@ */ package com.oracle.truffle.tools.test; -import com.oracle.truffle.api.instrument.Probe; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.api.source.LineLocation; -import com.oracle.truffle.tools.LineToProbesMap; import static com.oracle.truffle.tools.test.TestNodes.createExpr13TestRootNode; import static com.oracle.truffle.tools.test.TestNodes.expr13Line1; import static com.oracle.truffle.tools.test.TestNodes.expr13Line2; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; + import org.junit.Test; +import com.oracle.truffle.api.instrument.Instrumenter; +import com.oracle.truffle.api.instrument.Probe; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.source.LineLocation; +import com.oracle.truffle.tools.LineToProbesMap; + public class LineToProbesMapTest { @Test - public void testToolCreatedTooLate() { - final RootNode expr13rootNode = createExpr13TestRootNode(); + public void testToolCreatedTooLate() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); + final RootNode expr13rootNode = createExpr13TestRootNode(instrumenter); final Node addNode = expr13rootNode.getChildren().iterator().next(); - final Probe probe = addNode.probe(); + final Probe probe = instrumenter.probe(addNode); final LineLocation lineLocation = probe.getProbedSourceSection().getLineLocation(); assertEquals(lineLocation, expr13Line2); final LineToProbesMap tool = new LineToProbesMap(); - tool.install(); + tool.install(instrumenter); assertNull(tool.findFirstProbe(expr13Line1)); assertNull(tool.findFirstProbe(expr13Line2)); @@ -55,16 +59,17 @@ } @Test - public void testToolInstalledTooLate() { + public void testToolInstalledTooLate() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final LineToProbesMap tool = new LineToProbesMap(); - final RootNode expr13rootNode = createExpr13TestRootNode(); + final RootNode expr13rootNode = createExpr13TestRootNode(instrumenter); final Node addNode = expr13rootNode.getChildren().iterator().next(); - final Probe probe = addNode.probe(); + final Probe probe = instrumenter.probe(addNode); final LineLocation lineLocation = probe.getProbedSourceSection().getLineLocation(); assertEquals(lineLocation, expr13Line2); - tool.install(); + tool.install(instrumenter); assertNull(tool.findFirstProbe(expr13Line1)); assertNull(tool.findFirstProbe(expr13Line2)); @@ -72,13 +77,14 @@ } @Test - public void testMapping() { + public void testMapping() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final LineToProbesMap tool = new LineToProbesMap(); - tool.install(); + tool.install(instrumenter); - final RootNode expr13rootNode = createExpr13TestRootNode(); + final RootNode expr13rootNode = createExpr13TestRootNode(instrumenter); final Node addNode = expr13rootNode.getChildren().iterator().next(); - final Probe probe = addNode.probe(); + final Probe probe = instrumenter.probe(addNode); final LineLocation lineLocation = probe.getProbedSourceSection().getLineLocation(); assertEquals(lineLocation, expr13Line2); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/NodeExecCounterTest.java --- a/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/NodeExecCounterTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/NodeExecCounterTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,7 +24,16 @@ */ package com.oracle.truffle.tools.test; +import static com.oracle.truffle.tools.test.TestNodes.createExpr13TestCallTarget; +import static com.oracle.truffle.tools.test.TestNodes.createExpr13TestRootNode; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import org.junit.Test; + import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.instrument.Instrumenter; import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.instrument.StandardSyntaxTag; import com.oracle.truffle.api.nodes.Node; @@ -33,20 +42,15 @@ import com.oracle.truffle.tools.NodeExecCounter.NodeExecutionCount; import com.oracle.truffle.tools.test.TestNodes.TestAddNode; import com.oracle.truffle.tools.test.TestNodes.TestValueNode; -import static com.oracle.truffle.tools.test.TestNodes.createExpr13TestCallTarget; -import static com.oracle.truffle.tools.test.TestNodes.createExpr13TestRootNode; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; -import org.junit.Test; public class NodeExecCounterTest { @Test - public void testNoExecution() { + public void testNoExecution() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final NodeExecCounter tool = new NodeExecCounter(); assertEquals(tool.getCounts().length, 0); - tool.install(); + tool.install(instrumenter); assertEquals(tool.getCounts().length, 0); tool.setEnabled(false); assertEquals(tool.getCounts().length, 0); @@ -59,30 +63,33 @@ } @Test - public void testToolCreatedTooLate() { - final CallTarget expr13callTarget = createExpr13TestCallTarget(); + public void testToolCreatedTooLate() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); + final CallTarget expr13callTarget = createExpr13TestCallTarget(instrumenter); final NodeExecCounter tool = new NodeExecCounter(); - tool.install(); + tool.install(instrumenter); assertEquals(13, expr13callTarget.call()); assertEquals(tool.getCounts().length, 0); tool.dispose(); } @Test - public void testToolInstalledcTooLate() { + public void testToolInstalledcTooLate() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final NodeExecCounter tool = new NodeExecCounter(); - final CallTarget expr13callTarget = createExpr13TestCallTarget(); - tool.install(); + final CallTarget expr13callTarget = createExpr13TestCallTarget(instrumenter); + tool.install(instrumenter); assertEquals(13, expr13callTarget.call()); assertEquals(tool.getCounts().length, 0); tool.dispose(); } @Test - public void testCountingAll() { + public void testCountingAll() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final NodeExecCounter tool = new NodeExecCounter(); - tool.install(); - final CallTarget expr13callTarget = createExpr13TestCallTarget(); + tool.install(instrumenter); + final CallTarget expr13callTarget = createExpr13TestCallTarget(instrumenter); // execute once assertEquals(13, expr13callTarget.call()); @@ -124,17 +131,18 @@ } @Test - public void testCountingTagged() { + public void testCountingTagged() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final NodeExecCounter tool = new NodeExecCounter(StandardSyntaxTag.STATEMENT); - tool.install(); - final RootNode expr13rootNode = createExpr13TestRootNode(); + tool.install(instrumenter); + final RootNode expr13rootNode = createExpr13TestRootNode(instrumenter); // Not probed yet. assertEquals(13, expr13rootNode.execute(null)); assertEquals(tool.getCounts().length, 0); final Node addNode = expr13rootNode.getChildren().iterator().next(); - final Probe probe = addNode.probe(); + final Probe probe = instrumenter.probe(addNode); // Probed but not tagged yet. assertEquals(13, expr13rootNode.execute(null)); diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TestNodes.java --- a/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TestNodes.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TestNodes.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,10 +24,15 @@ */ package com.oracle.truffle.tools.test; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.VirtualFrame; +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.ProbeNode; @@ -39,6 +44,7 @@ import com.oracle.truffle.api.source.LineLocation; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.api.vm.TruffleVM; /** * Nodes and an {@linkplain CallTarget executable ASTs} for testing. @@ -55,21 +61,29 @@ /** * An executable addition expression that evaluates to 13. */ - static CallTarget createExpr13TestCallTarget() { - final RootNode rootNode = createExpr13TestRootNode(); + static CallTarget createExpr13TestCallTarget(Instrumenter instrumenter) { + final RootNode rootNode = createExpr13TestRootNode(instrumenter); return Truffle.getRuntime().createCallTarget(rootNode); } /** * Root holding an addition expression that evaluates to 13. */ - static RootNode createExpr13TestRootNode() { + static RootNode createExpr13TestRootNode(Instrumenter instrumenter) { final TestLanguageNode ast = createExpr13AST(); - final TestRootNode rootNode = new TestRootNode(ast); + final TestRootNode rootNode = new TestRootNode(ast, instrumenter); rootNode.adoptChildren(); return rootNode; } + static Instrumenter createInstrumenter() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + TruffleVM vm = TruffleVM.newVM().build(); + final Field field = TruffleVM.class.getDeclaredField("instrumenter"); + field.setAccessible(true); + final Instrumenter instrument = (Instrumenter) field.get(vm); + return instrument; + } + /** * Addition expression that evaluates to 13, with faked source attribution. */ @@ -165,13 +179,16 @@ static class TestRootNode extends RootNode { @Child private TestLanguageNode body; + private final Instrumenter instrumenter; + /** * 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(TestLanguageNode body) { + public TestRootNode(TestLanguageNode body, Instrumenter instrumenter) { super(TruffleLanguage.class, null, null); + this.instrumenter = instrumenter; this.body = body; } @@ -187,7 +204,14 @@ @Override public void applyInstrumentation() { - Probe.applyASTProbers(body); + Method method; + try { + method = Instrumenter.class.getDeclaredMethod("applyInstrumentation", Node.class); + method.setAccessible(true); + method.invoke(instrumenter, body); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException("TestNodes"); + } } } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TruffleToolTest.java --- a/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TruffleToolTest.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TruffleToolTest.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,21 +24,25 @@ */ package com.oracle.truffle.tools.test; -import com.oracle.truffle.api.instrument.InstrumentationTool; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; + import org.junit.Test; +import com.oracle.truffle.api.instrument.InstrumentationTool; +import com.oracle.truffle.api.instrument.Instrumenter; + /** * Test the basic life cycle properties shared by all instances of {@link InstrumentationTool}. */ public class TruffleToolTest { @Test - public void testEmptyLifeCycle() { + public void testEmptyLifeCycle() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final DummyTruffleTool tool = new DummyTruffleTool(); assertFalse(tool.isEnabled()); - tool.install(); + tool.install(instrumenter); assertTrue(tool.isEnabled()); tool.reset(); assertTrue(tool.isEnabled()); @@ -73,40 +77,45 @@ } @Test(expected = IllegalStateException.class) - public void testAlreadyInstalled() { + public void testAlreadyInstalled() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final DummyTruffleTool tool = new DummyTruffleTool(); - tool.install(); - tool.install(); + tool.install(instrumenter); + tool.install(instrumenter); } @Test(expected = IllegalStateException.class) - public void testAlreadyDisposed1() { + public void testAlreadyDisposed1() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final DummyTruffleTool tool = new DummyTruffleTool(); - tool.install(); + tool.install(instrumenter); tool.dispose(); - tool.install(); + tool.install(instrumenter); } @Test(expected = IllegalStateException.class) - public void testAlreadyDisposed2() { + public void testAlreadyDisposed2() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final DummyTruffleTool tool = new DummyTruffleTool(); - tool.install(); + tool.install(instrumenter); tool.dispose(); tool.reset(); } @Test(expected = IllegalStateException.class) - public void testAlreadyDisposed3() { + public void testAlreadyDisposed3() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final DummyTruffleTool tool = new DummyTruffleTool(); - tool.install(); + tool.install(instrumenter); tool.dispose(); tool.setEnabled(true); } @Test(expected = IllegalStateException.class) - public void testAlreadyDisposed4() { + public void testAlreadyDisposed4() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + final Instrumenter instrumenter = TestNodes.createInstrumenter(); final DummyTruffleTool tool = new DummyTruffleTool(); - tool.install(); + tool.install(instrumenter); tool.dispose(); tool.dispose(); } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/CoverageTracker.java --- a/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/CoverageTracker.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/CoverageTracker.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,6 +24,15 @@ */ package com.oracle.truffle.tools; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeSet; + import com.oracle.truffle.api.instrument.Instrument; import com.oracle.truffle.api.instrument.InstrumentationTool; import com.oracle.truffle.api.instrument.Probe; @@ -37,14 +46,6 @@ import com.oracle.truffle.api.source.LineLocation; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeSet; /** * An {@link InstrumentationTool} that counts interpreter execution calls to AST nodes that @@ -115,7 +116,7 @@ @Override protected boolean internalInstall() { - Probe.addProbeListener(probeListener); + getInstrumenter().addProbeListener(probeListener); return true; } @@ -126,7 +127,7 @@ @Override protected void internalDispose() { - Probe.removeProbeListener(probeListener); + getInstrumenter().removeProbeListener(probeListener); for (Instrument instrument : instruments) { instrument.dispose(); } diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/LineToProbesMap.java --- a/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/LineToProbesMap.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/LineToProbesMap.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,6 +24,13 @@ */ package com.oracle.truffle.tools; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import com.oracle.truffle.api.instrument.InstrumentationTool; import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.instrument.ProbeListener; @@ -31,12 +38,6 @@ import com.oracle.truffle.api.source.LineLocation; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; /** * An {@link InstrumentationTool} that builds a map of every {@link Probe} attached to some AST, @@ -68,7 +69,7 @@ @Override protected boolean internalInstall() { - Probe.addProbeListener(probeListener); + getInstrumenter().addProbeListener(probeListener); return true; } @@ -79,7 +80,7 @@ @Override protected void internalDispose() { - Probe.removeProbeListener(probeListener); + getInstrumenter().removeProbeListener(probeListener); } /** diff -r 0599e2df6a9f -r 1c0f490984d5 truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/NodeExecCounter.java --- a/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/NodeExecCounter.java Wed Sep 16 12:27:08 2015 +0200 +++ b/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/NodeExecCounter.java Wed Sep 16 15:36:22 2015 -0700 @@ -24,11 +24,22 @@ */ package com.oracle.truffle.tools; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrument.ASTProber; import com.oracle.truffle.api.instrument.Instrument; import com.oracle.truffle.api.instrument.InstrumentationTool; +import com.oracle.truffle.api.instrument.Instrumenter; import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.instrument.ProbeException; import com.oracle.truffle.api.instrument.ProbeFailure; @@ -40,15 +51,6 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.nodes.NodeVisitor; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; /** * An {@link InstrumentationTool} that counts interpreter execution calls to AST nodes, @@ -170,7 +172,7 @@ * Create a per node-type execution counting tool for all nodes in subsequently created ASTs. */ public NodeExecCounter() { - this.countingTag = null; + this(null); } /** @@ -185,10 +187,10 @@ protected boolean internalInstall() { if (countingTag == null) { astProber = new ExecCounterASTProber(); - Probe.registerASTProber(astProber); + getInstrumenter().registerASTProber(astProber); } else { probeListener = new NodeExecCounterProbeListener(); - Probe.addProbeListener(probeListener); + getInstrumenter().addProbeListener(probeListener); } return true; } @@ -202,10 +204,10 @@ @Override protected void internalDispose() { if (astProber != null) { - Probe.unregisterASTProber(astProber); + getInstrumenter().unregisterASTProber(astProber); } if (probeListener != null) { - Probe.removeProbeListener(probeListener); + getInstrumenter().removeProbeListener(probeListener); } for (Instrument instrument : instruments) { instrument.dispose(); @@ -289,24 +291,27 @@ /** * A prober that attempts to probe and instrument every node. */ - private class ExecCounterASTProber implements ASTProber, NodeVisitor { + private class ExecCounterASTProber implements ASTProber { + + public void probeAST(final Instrumenter instrumenter, final Node startNode) { - public boolean visit(Node node) { + startNode.accept(new NodeVisitor() { + + public boolean visit(Node node) { - if (node.isInstrumentable()) { - try { - final Instrument instrument = Instrument.create(instrumentListener, "NodeExecCounter"); - instruments.add(instrument); - node.probe().attach(instrument); - } catch (ProbeException ex) { - failures.add(ex.getFailure()); + if (node.isInstrumentable()) { + try { + final Instrument instrument = Instrument.create(instrumentListener, "NodeExecCounter"); + instruments.add(instrument); + instrumenter.probe(node).attach(instrument); + } catch (ProbeException ex) { + failures.add(ex.getFailure()); + } + } + return true; } - } - return true; - } - public void probeAST(Node node) { - node.accept(this); + }); } }