Mercurial > hg > graal-compiler
changeset 20911:518ce9a36939
Merge with f0d8a33aebd1e67d464ea8479d4777d73c146648
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Mon, 13 Apr 2015 16:26:28 -0700 |
parents | 0b2e4d40b683 (diff) f0d8a33aebd1 (current diff) |
children | b14a235f06eb 21298b90a6bf |
files | graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPluginIdHolder.java |
diffstat | 15 files changed, 425 insertions(+), 402 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Mon Apr 13 15:55:23 2015 -0700 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Mon Apr 13 16:26:28 2015 -0700 @@ -205,43 +205,45 @@ } @Test - public void constantValueInertToolNodeInstrumentListener() { + public void constantValueInertSpliceInstrumentListener() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - // A listener that could insert a "tool node" into the AST, but which never does. - Instrument instrument = Instrument.create(new ToolNodeInstrumentListener() { + // A listener that could insert a SplicedNode into the AST, but which never does. + Instrument instrument = Instrument.create(new SpliceInstrumentListener() { - public ToolNode getToolNode(Probe p) { + public SplicedNode getSpliceNode(Probe p) { return null; } }, null); probe.attach(instrument); + // It all gets compiled away assertPartialEvalEquals("constant42", root); } @Test - public void constantValueInertToolNode() { + public void constantValueInertSplicedNode() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - // A listener that inserts a "tool node" with empty methods into the AST. - Instrument instrument = Instrument.create(new ToolNodeInstrumentListener() { + // A listener that inserts a SplicedNode with empty methods into the AST. + Instrument instrument = Instrument.create(new SpliceInstrumentListener() { - public ToolNode getToolNode(Probe p) { - return new ToolNode() { + public SplicedNode getSpliceNode(Probe p) { + return new SplicedNode() { }; } }, null); probe.attach(instrument); + // It all gets compiled away. assertPartialEvalEquals("constant42", root); }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Mon Apr 13 15:55:23 2015 -0700 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Mon Apr 13 16:26:28 2015 -0700 @@ -86,7 +86,6 @@ public Object execute(VirtualFrame vFrame) { probeNode.enter(child, vFrame); Object result; - try { result = child.execute(vFrame); probeNode.returnValue(child, vFrame, result); @@ -96,7 +95,6 @@ probeNode.returnExceptional(child, vFrame, e); throw (e); } - return result; } } @@ -169,4 +167,17 @@ } } + static class TestSplicedCounterNode extends SplicedNode { + + private long count; + + @Override + public void enter(Node node, VirtualFrame vFrame) { + count++; + } + + public long getCount() { + return count; + } + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/SpliceInstrumentTest.java Mon Apr 13 16:26:28 2015 -0700 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.instrument; + +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestSplicedCounterNode; + +/** + * Tests the kind of instrumentation where a client can provide an AST fragment to be + * <em>spliced</em> directly into the AST. + */ +public class SpliceInstrumentTest { + + @Test + public void testSpliceInstrumentListener() { + // 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 CallTarget callTarget1 = runtime.createCallTarget(rootNode); + + // Ensure it executes correctly + assertEquals(13, callTarget1.call()); + + // Probe the addition node + final Probe probe = addNode.probe(); + + assertEquals(13, callTarget1.call()); + + // Attach a null listener; it never actually attaches a node. + final Instrument instrument = Instrument.create(new SpliceInstrumentListener() { + + public SplicedNode getSpliceNode(Probe p) { + return null; + } + + }, null); + probe.attach(instrument); + + assertEquals(13, callTarget1.call()); + + final TestSplicedCounterNode counter = new TestSplicedCounterNode(); + + // Attach a listener that splices an execution counter into the AST. + probe.attach(Instrument.create(new SpliceInstrumentListener() { + + public SplicedNode getSpliceNode(Probe p) { + return counter; + } + + }, null)); + assertEquals(0, counter.getCount()); + + assertEquals(13, callTarget1.call()); + + assertEquals(1, counter.getCount()); + + } + +}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolNodeInstrumentationTest.java Mon Apr 13 15:55:23 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.test.instrument; - -import static org.junit.Assert.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode; - -/** - * Tests instrumentation where a client can attach a node that gets attached into the AST. - */ -public class ToolNodeInstrumentationTest { - - @Test - public void testToolNodeListener() { - // 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 CallTarget callTarget1 = runtime.createCallTarget(rootNode); - - // Ensure it executes correctly - assertEquals(13, callTarget1.call()); - - // Probe the addition node - final Probe probe = addNode.probe(); - - assertEquals(13, callTarget1.call()); - - // Attach a listener that never actually attaches a node. - final Instrument instrument = Instrument.create(new ToolNodeInstrumentListener() { - - public ToolNode getToolNode(Probe p) { - return null; - } - - }, null); - probe.attach(instrument); - - assertEquals(13, callTarget1.call()); - - final int[] count = new int[1]; - - // Attach a listener that never actually attaches a node. - probe.attach(Instrument.create(new ToolNodeInstrumentListener() { - - public ToolNode getToolNode(Probe p) { - return new ToolNode() { - - @Override - public void enter(Node node, VirtualFrame vFrame) { - count[0] = count[0] + 1; - } - }; - } - - }, null)); - assertEquals(0, count[0]); - - assertEquals(13, callTarget1.call()); - - assertEquals(1, count[0]); - - } - -}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java Mon Apr 13 15:55:23 2015 -0700 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java Mon Apr 13 16:26:28 2015 -0700 @@ -54,9 +54,9 @@ // Initially has only the default tag assertEquals(source.getSourceTags().size(), 1); - assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL)); - assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL)); - assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source)); + assertTrue(source.getSourceTags().contains(Source.Tags.FROM_LITERAL)); + assertTrue(source.isTaggedAs(Source.Tags.FROM_LITERAL)); + assertTrue(Source.findSourcesTaggedAs(Source.Tags.FROM_LITERAL).contains(source)); assertFalse(source.isTaggedAs(testTag)); assertEquals(Source.findSourcesTaggedAs(testTag).size(), 0); @@ -67,9 +67,9 @@ // Now there are exactly two tags assertEquals(source.getSourceTags().size(), 2); - assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL)); - assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL)); - assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source)); + assertTrue(source.getSourceTags().contains(Source.Tags.FROM_LITERAL)); + assertTrue(source.isTaggedAs(Source.Tags.FROM_LITERAL)); + assertTrue(Source.findSourcesTaggedAs(Source.Tags.FROM_LITERAL).contains(source)); assertTrue(source.getSourceTags().contains(testTag)); assertTrue(source.isTaggedAs(testTag)); @@ -82,9 +82,9 @@ // Nothing has changed assertEquals(source.getSourceTags().size(), 2); - assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL)); - assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL)); - assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source)); + assertTrue(source.getSourceTags().contains(Source.Tags.FROM_LITERAL)); + assertTrue(source.isTaggedAs(Source.Tags.FROM_LITERAL)); + assertTrue(Source.findSourcesTaggedAs(Source.Tags.FROM_LITERAL).contains(source)); assertTrue(source.getSourceTags().contains(testTag)); assertTrue(source.isTaggedAs(testTag)); @@ -135,7 +135,7 @@ assertEquals(newSource[0], source); assertEquals(newTagEvents[0], 1); assertEquals(taggedSource[0], source); - assertEquals(newTag[0], StandardSourceTag.FROM_LITERAL); + assertEquals(newTag[0], Source.Tags.FROM_LITERAL); // reset newSource[0] = null;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Mon Apr 13 15:55:23 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Mon Apr 13 16:26:28 2015 -0700 @@ -30,8 +30,9 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; -// TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe), -// then break out some of the nested classes into package privates. +// TODO (mlvdv) these statics should not be global. Move them to some kind of context. +// TODO (mlvdv) migrate factory into .impl (together with Probe)? break out nested classes? + /** * A <em>binding</em> between: * <ol> @@ -41,8 +42,8 @@ * </ol> * <p> * Client-oriented documentation for the use of Instruments is available online at <a - * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events">Listening for - * Execution Events</a> + * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events" + * >https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events</a> * <p> * The implementation of Instruments is complicated by the requirement that Truffle be able to clone * ASTs at any time. In particular, any instrumentation-supporting Nodes that have been attached to @@ -62,29 +63,38 @@ * <ul> * <li>A new Instrument is created in permanent association with a client-provided * <em>listener.</em></li> + * * <li>Multiple Instruments may share a single listener.</li> + * * <li>An Instrument does nothing until it is {@linkplain Probe#attach(Instrument) attached} to a * Probe, at which time the Instrument begins routing execution events from the Probe's AST location * to the Instrument's listener.</li> + * * <li>Neither Instruments nor Probes are {@link Node}s.</li> + * * <li>A Probe has a single source-based location in an AST, but manages a separate * <em>instrumentation chain</em> of Nodes at the equivalent location in each clone of the AST.</li> * <li>When a probed AST is cloned, the instrumentation chain associated with each Probe is cloned * along with the rest of the AST.</li> + * * <li>When a new Instrument (for example an instance of {@link SimpleInstrument} is attached to a * Probe, the Instrument inserts a new instance of its private Node type, * {@link SimpleInstrument.SimpleInstrumentNode}, into <em>each of the instrument chains</em> * managed by the Probe, i.e. one node instance per existing clone of the AST.</li> + * * <li>If an Instrument is attached to a Probe in an AST that subsequently gets cloned, then the * Instrument's private Node type will be cloned along with the rest of the the AST.</li> * <li>Each Instrument's private Node type is a dynamic inner class whose only state is in the * shared (outer) Instrument instance; that state includes a reference to the Instrument's listener. * </li> + * * <li>When an Instrument that has been attached to a Probe is {@linkplain #dispose() disposed}, the * Instrument searches every instrument chain associated with the Probe and removes the instance of * its private Node type.</li> + * * <li>Attaching and disposing an Instrument at a Probe <em>deoptimizes</em> any compilations of the * AST.</li> + * * </ul> * * @see Probe @@ -118,15 +128,16 @@ /** * Creates an instrument that, when executed the first time in any particular AST location, - * invites the tool to provide an AST fragment for attachment/adoption into the running AST. + * invites the tool to provide an AST fragment for <em>splicing</em> directly into the running + * AST. * - * @param toolNodeListener a listener for the tool that can request an AST fragment + * @param spliceListener a callback to the client that requests an AST node to be splice. * @param instrumentInfo instrumentInfo optional description of the instrument's role, useful * for debugging. * @return a new instrument, ready for attachment at a probe. */ - public static Instrument create(ToolNodeInstrumentListener toolNodeListener, String instrumentInfo) { - return new ToolNodeInstrument(toolNodeListener, instrumentInfo); + public static Instrument create(SpliceInstrumentListener spliceListener, String instrumentInfo) { + return new SpliceInstrument(spliceListener, instrumentInfo); } // TODO (mlvdv) experimental @@ -187,6 +198,11 @@ abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode); /** + * Removes this instrument from an instrument chain. + */ + abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode); + + /** * An instrument that propagates events to an instance of {@link SimpleInstrumentListener}. */ private static final class SimpleInstrument extends Instrument { @@ -266,11 +282,6 @@ } /** - * Removes this instrument from an instrument chain. - */ - abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode); - - /** * An instrument that propagates events to an instance of {@link StandardInstrumentListener}. */ private static final class StandardInstrument extends Instrument { @@ -351,23 +362,24 @@ // TODO (mlvdv) EXPERIMENTAL- UNDER DEVELOPMENT /** - * An instrument that propagates events to an instance of {@link StandardInstrumentListener}. + * An instrument that allows clients to "splice" an AST fragment directly into a Probe's + * <em>instrumentation chain</em>, and thus directly into the executing Truffle AST. */ - private static final class ToolNodeInstrument extends Instrument { + private static final class SpliceInstrument extends Instrument { /** * Tool-supplied listener for AST events. */ - private final ToolNodeInstrumentListener toolNodeListener; + private final SpliceInstrumentListener spliceListener; - private ToolNodeInstrument(ToolNodeInstrumentListener toolNodeListener, String instrumentInfo) { + private SpliceInstrument(SpliceInstrumentListener spliceListener, String instrumentInfo) { super(instrumentInfo); - this.toolNodeListener = toolNodeListener; + this.spliceListener = spliceListener; } @Override AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { - return new ToolInstrumentNode(nextNode); + return new SpliceInstrumentNode(nextNode); } @Override @@ -379,7 +391,7 @@ return instrumentNode.nextInstrumentNode; } // Match not at the head of the chain; remove it. - found = instrumentNode.removeFromChain(ToolNodeInstrument.this); + found = instrumentNode.removeFromChain(SpliceInstrument.this); } if (!found) { throw new IllegalStateException("Couldn't find instrument node to remove: " + this); @@ -388,25 +400,25 @@ } @NodeInfo(cost = NodeCost.NONE) - private final class ToolInstrumentNode extends AbstractInstrumentNode { + private final class SpliceInstrumentNode extends AbstractInstrumentNode { - @Child ToolNode toolNode; + @Child SplicedNode splicedNode; - private ToolInstrumentNode(AbstractInstrumentNode nextNode) { + private SpliceInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); } public void enter(Node node, VirtualFrame vFrame) { - if (toolNode == null) { - final ToolNode newToolNode = ToolNodeInstrument.this.toolNodeListener.getToolNode(ToolNodeInstrument.this.probe); - if (newToolNode != null) { - toolNode = newToolNode; + if (splicedNode == null) { + final SplicedNode newSplicedNode = SpliceInstrument.this.spliceListener.getSpliceNode(SpliceInstrument.this.probe); + if (newSplicedNode != null) { + splicedNode = newSplicedNode; adoptChildren(); - ToolNodeInstrument.this.probe.invalidateProbeUnchanged(); + SpliceInstrument.this.probe.invalidateProbeUnchanged(); } } - if (toolNode != null) { - toolNode.enter(node, vFrame); + if (splicedNode != null) { + splicedNode.enter(node, vFrame); } if (nextInstrumentNode != null) { nextInstrumentNode.enter(node, vFrame); @@ -414,8 +426,8 @@ } public void returnVoid(Node node, VirtualFrame vFrame) { - if (toolNode != null) { - toolNode.returnVoid(node, vFrame); + if (splicedNode != null) { + splicedNode.returnVoid(node, vFrame); } if (nextInstrumentNode != null) { nextInstrumentNode.returnVoid(node, vFrame); @@ -423,8 +435,8 @@ } public void returnValue(Node node, VirtualFrame vFrame, Object result) { - if (toolNode != null) { - toolNode.returnValue(node, vFrame, result); + if (splicedNode != null) { + splicedNode.returnValue(node, vFrame, result); } if (nextInstrumentNode != null) { nextInstrumentNode.returnValue(node, vFrame, result); @@ -432,8 +444,8 @@ } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - if (toolNode != null) { - toolNode.returnExceptional(node, vFrame, exception); + if (splicedNode != null) { + splicedNode.returnExceptional(node, vFrame, exception); } if (nextInstrumentNode != null) { nextInstrumentNode.returnExceptional(node, vFrame, exception); @@ -442,7 +454,7 @@ public String instrumentationInfo() { final String info = getInstrumentInfo(); - return info != null ? info : toolNodeListener.getClass().getSimpleName(); + return info != null ? info : spliceListener.getClass().getSimpleName(); } } }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Mon Apr 13 15:55:23 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Mon Apr 13 16:26:28 2015 -0700 @@ -34,38 +34,62 @@ import com.oracle.truffle.api.source.*; import com.oracle.truffle.api.utilities.*; -//TODO (mlvdv) migrate some of this to external documentation. +//TODO (mlvdv) these statics should not be global. Move them to some kind of context. + /** - * A binding between a particular <em>location</em> in the Truffle AST representation of a running - * Guest Language (GL) program (i.e. a {@link Node}) and a dynamically managed collection of - * "attached" {@linkplain Instrument instrumentation} for use by external tools. The instrumentation - * is intended to persist at the location, even if the specific node instance is - * {@linkplain Node#replace(Node) replaced}. + * A <em>binding</em> between: + * <ol> + * <li>A program location in an executing Truffle AST (defined by a {@link SourceSection}), and</li> + * <li>A dynamically managed collection of "attached" {@linkplain Instrument Instruments} that + * receive event notifications on behalf of external clients.</li> + * </ol> * <p> - * The effect of a binding is to intercept {@linkplain TruffleEvents execution events} arriving at - * the node and notify each attached {@link Instrument} before execution is allowed to proceed to - * the child. + * Client-oriented documentation for the use of Probes is available online at <a + * HREF="https://wiki.openjdk.java.net/display/Graal/Finding+Probes" + * >https://wiki.openjdk.java.net/display/Graal/Finding+Probes</a> * <p> - * A Probe is "inserted" into a GL node via a call to {@link Node#probe()}. No more than one Probe - * can be inserted at a node. + * <h4>Implementation notes:</h4> * <p> - * The "probing" of a Truffle AST must be done after it is complete (i.e. with parent pointers - * correctly assigned), but before any executions. This is done by creating an instance of - * {@link ASTProber} and registering it via {@link #registerASTProber(ASTProber)}, after which it - * will be automatically applied to newly created ASTs. - * <p> - * Each Probe may also have assigned to it any number of {@link SyntaxTag}s, for example identifying - * a node as a {@linkplain StandardSyntaxTag#STATEMENT STATEMENT}. Tags can be queried by tools to - * configure behavior relevant to each probed node. - * <p> - * Instrumentation is implemented by modifying ASTs, both by inserting nodes into each AST at probed - * locations and by attaching additional nodes that implement dynamically attached instruments. - * Attached instrumentation code become, in effect, part of the GL program, and is subject to the - * same levels of optimization as other GL code. This implementation accounts properly for the fact - * that Truffle frequently <em>clones</em> ASTs, along with any attached instrumentation nodes. A - * {@link Probe}, along with attached {@link Instrument}s, represents a <em>logical</em> binding - * with a source code location, producing event notifications that are (mostly) independent of which - * AST clone is executing. + * <ul> + * <li>A Probe must be permanently associated with a <em>program location</em>, defined by a + * particular {@link SourceSection}, even though: + * <ul> + * <li>that location is represented in an AST as a {@link Node}, which might be replaced through + * optimizations such as specialization, and</li> + * <li>Truffle may <em>clone</em> the AST so that the location is actually represented by multiple + * Nodes in multiple ASTs.</li> + * </ul> + * </li> + * + * <li>The effect of the binding is to intercept {@linkplain TruffleEvents execution events} + * 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.</li> + * + * <li>A Probe is "inserted" into a GL node via a call to {@link Node#probe()}. No more than one + * Probe can be inserted at a node; a redundant call returns the existing Probe<./li> + * + * <li>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)}, after which it + * will be applied automatically to every newly created AST.</li> + * + * <li>An AST node becomes <em>probed</em> by insertion of a {@link ProbeNode.WrapperNode} into the + * AST, together with an associated {@link ProbeNode} that routes events to all the + * {@linkplain Instrument Instruments} attached to its <em>instrument chain</em>.</li> + * + * <li>When Truffle clones an AST, any attached WrapperNodes and ProbeNodes are cloned as well, + * together with their attached instrument chains. The {@link Probe} instance intercepts cloning + * events and keeps track of all copies.</li> + * + * <li>All attached {@link InstrumentationNode}s effectively become part of the running program: + * <ul> + * <li>Good News: instrumentation code implicitly benefits from every kind of Truffle optimization.</li> + * <li>Bad News: instrumentation code must be implemented carefully to avoid interfering with any + * Truffle optimizations.</li> + * </ul> + * </li> + * + * </ul> * * @see Instrument * @see ASTProber @@ -173,6 +197,7 @@ return taggedProbes; } + // TODO (mlvdv) can this be generalized to permit multiple traps without a performance hit? /** * Sets the current "tag trap"; there can be no more than one set at a time. * <ul>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SpliceInstrumentListener.java Mon Apr 13 16:26:28 2015 -0700 @@ -0,0 +1,58 @@ +/* + * 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; + +/** + * Instrument listener for a tool that works by providing an AST to be <em>spliced</em> directly + * into the AST. + */ +public interface SpliceInstrumentListener { + + /** + * Receive notification that a probed AST node to which the {@link Instrument} is attached is + * about to be executed for the first time. This is a lazy opportunity for the tool to + * optionally add the root of a newly created AST fragment that will be <em>spliced</em> + * directly into the executing AST. The new AST fragment will immediately begin receiving + * {@link InstrumentationNode.TruffleEvents}, beginning with the current execution event. + * <p> + * AST fragments must be written to Truffle conventions. Some of these conventions are + * especially important if the fragment is to be fully optimized along with it's new parent AST. + * <p> + * If this method returns {@code null} then it will be called again the next time the probed + * node is about to be executed. + * <p> + * In some situations, this method will be called more than once for a particular Probe, and a + * new instance must be supplied each time. Each instance will be attached at the equivalent + * location in clones of the AST, and so should be behave as if equivalent for most purposes. + * <p> + * In some situations the AST fragment supplied by this method maybe cloned for attachment to + * equivalent locations in cloned AST, so care should be taken about any state local to each + * instance of the AST fragment. + * + * @see Instrument + */ + SplicedNode getSpliceNode(Probe probe); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SplicedNode.java Mon Apr 13 16:26:28 2015 -0700 @@ -0,0 +1,55 @@ +/* + * 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 com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Root of a client-provided AST fragment that can be spliced directly into an executing AST via + * {@link Instrument#create(SpliceInstrumentListener, String)}. + * <p> + * <strong>Note:</strong> Instances of this class will in some situations be cloned by the + * instrumentation platform for attachment at equivalent locations in cloned ASTs. + */ +public abstract class SplicedNode extends Node implements InstrumentationNode.TruffleEvents, InstrumentationNode { + + public void enter(Node node, VirtualFrame vFrame) { + } + + public void returnVoid(Node node, VirtualFrame vFrame) { + } + + public void returnValue(Node node, VirtualFrame vFrame, Object result) { + } + + public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { + } + + public String instrumentationInfo() { + return null; + } + +}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolNode.java Mon Apr 13 15:55:23 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * 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 com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Root of a tool-provided AST fragment that can be attached directly into an executing AST via - * {@link Instrument#create(ToolNodeInstrumentListener, String)}. - * <p> - * <strong>Note:</strong> Instances of this class will in some situations be cloned by the - * instrumentation platform for attachment at equivalent locations in cloned parent ASTs. - */ -public abstract class ToolNode extends Node implements InstrumentationNode.TruffleEvents, InstrumentationNode { - - public void enter(Node node, VirtualFrame vFrame) { - } - - public void returnVoid(Node node, VirtualFrame vFrame) { - } - - public void returnValue(Node node, VirtualFrame vFrame, Object result) { - } - - public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - } - - public String instrumentationInfo() { - return null; - } - -}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolNodeInstrumentListener.java Mon Apr 13 15:55:23 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * 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; - -/** - * Instrument listener for a tool that works by providing an AST to be attached/adopted directly - * into the AST. - */ -public interface ToolNodeInstrumentListener { - - /** - * Receive notification that a probed AST node to which the {@link Instrument} is attached is - * about to be executed for the first time. This is a lazy opportunity for the tool to - * optionally add the root of a newly created AST fragment that will be attached/adopted - * directly into the executing AST. The new AST fragment will immediately begin receiving - * {@link InstrumentationNode.TruffleEvents}, beginning with the current execution event. - * <p> - * AST fragments must be written to Truffle conventions. Some of these conventions are - * especially important if the fragment is to be fully optimized along with it's new parent AST. - * <p> - * If this method returns {@code null} then it will be called again the next time the probed - * node is about to be executed. - * <p> - * In some situations, this method will be called more than once for a particular Probe, and a - * new instance must be supplied each time. Each instance will be attached at the equivalent - * location in clones of the AST, and so should be behave as if equivalent for most purposes. - * <p> - * In some situations the AST fragment supplied by this method maybe cloned for attachment to - * equivalent locations in cloned AST, so care should be taken about any state local to each - * instance of the AST fragment. - * - * @see Instrument - */ - ToolNode getToolNode(Probe probe); - -}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Mon Apr 13 15:55:23 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Mon Apr 13 16:26:28 2015 -0700 @@ -78,6 +78,51 @@ // TODO (mlvdv) consider canonicalizing and reusing SourceSection instances // TOOD (mlvdv) connect SourceSections into a spatial tree for fast geometric lookup + public enum Tags implements SourceTag { + + /** + * From bytes. + */ + FROM_BYTES("bytes", "read from bytes"), + + /** + * Read from a file. + */ + FROM_FILE("file", "read from a file"), + + /** + * From literal text. + */ + FROM_LITERAL("literal", "from literal text"), + + /** + * From a {@linkplain java.io.Reader Reader}. + */ + FROM_READER("reader", "read from a Java Reader"), + + /** + * Read from a URL. + */ + FROM_URL("URL", "read from a URL"); + + private final String name; + private final String description; + + private Tags(String name, String description) { + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + } + /** * All Sources that have been created. */ @@ -119,7 +164,7 @@ if (reset) { source.reset(); } - notifyNewSource(source).tagAs(StandardSourceTag.FROM_FILE); + notifyNewSource(source).tagAs(Tags.FROM_FILE); return source; } @@ -161,7 +206,7 @@ filePathToSource.put(path, new WeakReference<>(source)); } } - notifyNewSource(source).tagAs(StandardSourceTag.FROM_FILE); + notifyNewSource(source).tagAs(Tags.FROM_FILE); return source; } @@ -176,7 +221,7 @@ public static Source fromText(CharSequence chars, String description) { assert chars != null; final LiteralSource source = new LiteralSource(description, chars.toString()); - notifyNewSource(source).tagAs(StandardSourceTag.FROM_LITERAL); + notifyNewSource(source).tagAs(Tags.FROM_LITERAL); return source; } @@ -190,7 +235,7 @@ */ public static Source fromURL(URL url, String description) throws IOException { final URLSource source = URLSource.get(url, description); - notifyNewSource(source).tagAs(StandardSourceTag.FROM_URL); + notifyNewSource(source).tagAs(Tags.FROM_URL); return source; } @@ -204,7 +249,7 @@ */ public static Source fromReader(Reader reader, String description) throws IOException { final LiteralSource source = new LiteralSource(description, read(reader)); - notifyNewSource(source).tagAs(StandardSourceTag.FROM_READER); + notifyNewSource(source).tagAs(Tags.FROM_READER); return source; } @@ -237,7 +282,7 @@ */ public static Source fromBytes(byte[] bytes, int byteIndex, int length, String description, BytesDecoder decoder) { final BytesSource source = new BytesSource(description, bytes, byteIndex, length, decoder); - notifyNewSource(source).tagAs(StandardSourceTag.FROM_BYTES); + notifyNewSource(source).tagAs(Tags.FROM_BYTES); return source; } @@ -252,7 +297,7 @@ public static Source asPseudoFile(CharSequence chars, String pseudoFileName) { final Source source = new LiteralSource(pseudoFileName, chars.toString()); filePathToSource.put(pseudoFileName, new WeakReference<>(source)); - notifyNewSource(source).tagAs(StandardSourceTag.FROM_LITERAL); + notifyNewSource(source).tagAs(Tags.FROM_LITERAL); return source; }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceTag.java Mon Apr 13 15:55:23 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceTag.java Mon Apr 13 16:26:28 2015 -0700 @@ -27,16 +27,14 @@ /** * Categorical information (best implemented as enums} about particular sources of Guest Language * code that can be useful to configure behavior of both the language runtime and external tools. - * These might include {@linkplain StandardSourceTag standard tags} noting, for example, whether the + * These might include {@linkplain Source.Tags standard tags} noting, for example, whether the * source was read from a file and whether it should be considered library code. * <p> - * An untagged {@link Source} should by default be considered application code. - * <p> * The need for additional tags is likely to arise, in some cases because of issue specific to a * Guest Language, but also for help configuring the behavior of particular tools. * * @see Source - * @see StandardSourceTag + * @see Source.Tags */ public interface SourceTag {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/StandardSourceTag.java Mon Apr 13 15:55:23 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * 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.source; - -/** - * A general set of "properties" or "categories" that might be usefully attached to a particular - * source of code, both for use by the language runtime and by external tools. This set of tags - * includes some intended to be applied by default by {@link Source} factory methods or other - * services built into the Truffle platform. - * <p> - * The need for additional tags is likely to arise, in some cases because of issue specific to a - * Guest Language, but also for help configuring the behavior of particular tools. - * - * @see Source - */ -public enum StandardSourceTag implements SourceTag { - - /** - * Builtin. - */ - BUILTIN("builtin", "implementation of language builtins"), - - /** - * From bytes. - */ - FROM_BYTES("bytes", "read from bytes"), - - /** - * Read from a file. - */ - FROM_FILE("file", "read from a file"), - - /** - * From literal text. - */ - FROM_LITERAL("literal", "from literal text"), - - /** - * From a {@linkplain java.io.Reader Reader}. - */ - FROM_READER("reader", "read from a Java Reader"), - - /** - * Read from a URL. - */ - FROM_URL("URL", "read from a URL"), - - /** - * Treat as LIBRARY code. - */ - LIBRARY("library", "library code"); - - private final String name; - private final String description; - - private StandardSourceTag(String name, String description) { - this.name = name; - this.description = description; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - -}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java Mon Apr 13 15:55:23 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java Mon Apr 13 16:26:28 2015 -0700 @@ -35,10 +35,13 @@ /** * An {@link InstrumentationTool} that counts interpreter <em>execution calls</em> to AST nodes that - * hold a specified {@linkplain SyntaxTag tag}, tabulated by source and line number associated with - * each node. Tags are presumed to be applied external to the tool. If no tag is specified, - * {@linkplain StandardSyntaxTag#STATEMENT STATEMENT} is used, corresponding to conventional - * behavior for code coverage tools. + * hold a specified {@linkplain SyntaxTag syntax tag}, tabulated by source and line number + * associated with each node. Syntax tags are presumed to be applied external to the tool. If no tag + * is specified, {@linkplain StandardSyntaxTag#STATEMENT STATEMENT} is used, corresponding to + * conventional behavior for code coverage tools. + * <p> + * No counts will be kept for execution in sources that hold the {@link SourceTag} + * {@link Tags#NO_COVERAGE}. * <p> * <b>Tool Life Cycle</b> * <p> @@ -70,6 +73,30 @@ */ public final class CoverageTracker extends InstrumentationTool { + public enum Tags implements SourceTag { + + /** + * Report no counts for sources holding this tag. + */ + NO_COVERAGE("No Coverage", "Coverage Tracker will igore"); + + private final String name; + private final String description; + + private Tags(String name, String description) { + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + } + /** Counting data. */ private final Map<LineLocation, CoverageRecord> coverageMap = new HashMap<>(); @@ -264,7 +291,7 @@ final SourceSection srcSection = probe.getProbedSourceSection(); if (srcSection == null) { // TODO (mlvdv) report this? - } else { + } else if (!srcSection.getSource().isTaggedAs(Tags.NO_COVERAGE)) { // Get the source line where the final LineLocation lineLocation = srcSection.getLineLocation(); CoverageRecord record = coverageMap.get(lineLocation);