Mercurial > hg > truffle
diff graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java @ 20106:2e3cc2a27711
Truffle/Instrumentation: a new flavor of Instrument that lazily provides an AST fragment to be attached/adopted directly into a running AST, and to which execution event notifications will be routed. Important use cases so far include conditional breakpoints (with optimizeable conditions) and Ruby set_trace_func.
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Tue, 31 Mar 2015 19:01:07 -0700 |
parents | 907128d02b31 |
children | e7ece52e1ff3 |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Tue Mar 31 18:58:36 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Tue Mar 31 19:01:07 2015 -0700 @@ -194,6 +194,19 @@ return new ASTInstrument(astListener, instrumentInfo); } + /** + * 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. + * + * @param toolNodeListener a listener for the tool that can request an AST fragment + * @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); + } + // TODO (mlvdv) experimental /** * For implementation testing. @@ -278,7 +291,7 @@ if (instrumentNode != null) { if (instrumentNode.getInstrument() == this) { // Found the match at the head of the chain - return instrumentNode.nextInstrument; + return instrumentNode.nextInstrumentNode; } // Match not at the head of the chain; remove it. found = instrumentNode.removeFromChain(BasicInstrument.this); @@ -298,29 +311,29 @@ public void enter(Node node, VirtualFrame vFrame) { BasicInstrument.this.instrumentListener.enter(BasicInstrument.this.probe); - if (nextInstrument != null) { - nextInstrument.enter(node, vFrame); + if (nextInstrumentNode != null) { + nextInstrumentNode.enter(node, vFrame); } } public void returnVoid(Node node, VirtualFrame vFrame) { BasicInstrument.this.instrumentListener.returnVoid(BasicInstrument.this.probe); - if (nextInstrument != null) { - nextInstrument.returnVoid(node, vFrame); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnVoid(node, vFrame); } } public void returnValue(Node node, VirtualFrame vFrame, Object result) { BasicInstrument.this.instrumentListener.returnValue(BasicInstrument.this.probe, result); - if (nextInstrument != null) { - nextInstrument.returnValue(node, vFrame, result); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnValue(node, vFrame, result); } } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { BasicInstrument.this.instrumentListener.returnExceptional(BasicInstrument.this.probe, exception); - if (nextInstrument != null) { - nextInstrument.returnExceptional(node, vFrame, exception); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnExceptional(node, vFrame, exception); } } @@ -362,7 +375,7 @@ if (instrumentNode != null) { if (instrumentNode.getInstrument() == this) { // Found the match at the head of the chain - return instrumentNode.nextInstrument; + return instrumentNode.nextInstrumentNode; } // Match not at the head of the chain; remove it. found = instrumentNode.removeFromChain(ASTInstrument.this); @@ -382,29 +395,29 @@ public void enter(Node node, VirtualFrame vFrame) { ASTInstrument.this.astListener.enter(ASTInstrument.this.probe, node, vFrame); - if (nextInstrument != null) { - nextInstrument.enter(node, vFrame); + if (nextInstrumentNode != null) { + nextInstrumentNode.enter(node, vFrame); } } public void returnVoid(Node node, VirtualFrame vFrame) { ASTInstrument.this.astListener.returnVoid(ASTInstrument.this.probe, node, vFrame); - if (nextInstrument != null) { - nextInstrument.returnVoid(node, vFrame); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnVoid(node, vFrame); } } public void returnValue(Node node, VirtualFrame vFrame, Object result) { ASTInstrument.this.astListener.returnValue(ASTInstrument.this.probe, node, vFrame, result); - if (nextInstrument != null) { - nextInstrument.returnValue(node, vFrame, result); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnValue(node, vFrame, result); } } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { ASTInstrument.this.astListener.returnExceptional(ASTInstrument.this.probe, node, vFrame, exception); - if (nextInstrument != null) { - nextInstrument.returnExceptional(node, vFrame, exception); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnExceptional(node, vFrame, exception); } } @@ -416,6 +429,104 @@ } + /** + * An instrument that propagates events to an instance of {@link ASTInstrumentListener}. + */ + private static final class ToolNodeInstrument extends Instrument { + + /** + * Tool-supplied listener for AST events. + */ + private final ToolNodeInstrumentListener toolNodeListener; + + private ToolNodeInstrument(ToolNodeInstrumentListener toolNodeListener, String instrumentInfo) { + super(instrumentInfo); + this.toolNodeListener = toolNodeListener; + } + + @Override + AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { + return new ToolInstrumentNode(nextNode); + } + + @Override + AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { + boolean found = false; + if (instrumentNode != null) { + if (instrumentNode.getInstrument() == this) { + // Found the match at the head of the chain + return instrumentNode.nextInstrumentNode; + } + // Match not at the head of the chain; remove it. + found = instrumentNode.removeFromChain(ToolNodeInstrument.this); + } + if (!found) { + throw new IllegalStateException("Couldn't find instrument node to remove: " + this); + } + return instrumentNode; + } + + @NodeInfo(cost = NodeCost.NONE) + private final class ToolInstrumentNode extends AbstractInstrumentNode { + + @Child ToolNode toolNode; + + private ToolInstrumentNode(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; + adoptChildren(); + ToolNodeInstrument.this.probe.invalidateProbeUnchanged(); + } + } + if (toolNode != null) { + toolNode.enter(node, vFrame); + } + if (nextInstrumentNode != null) { + nextInstrumentNode.enter(node, vFrame); + } + } + + public void returnVoid(Node node, VirtualFrame vFrame) { + if (toolNode != null) { + toolNode.returnVoid(node, vFrame); + } + if (nextInstrumentNode != null) { + nextInstrumentNode.returnVoid(node, vFrame); + } + } + + public void returnValue(Node node, VirtualFrame vFrame, Object result) { + if (toolNode != null) { + toolNode.returnValue(node, vFrame, result); + } + if (nextInstrumentNode != null) { + nextInstrumentNode.returnValue(node, vFrame, result); + } + } + + public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { + if (toolNode != null) { + toolNode.returnExceptional(node, vFrame, exception); + } + if (nextInstrumentNode != null) { + nextInstrumentNode.returnExceptional(node, vFrame, exception); + } + } + + public String instrumentationInfo() { + final String info = getInstrumentInfo(); + return info != null ? info : toolNodeListener.getClass().getSimpleName(); + } + } + + } + public interface TruffleOptListener { void notifyIsCompiled(boolean isCompiled); } @@ -440,7 +551,7 @@ if (instrumentNode != null) { if (instrumentNode.getInstrument() == this) { // Found the match at the head of the chain - return instrumentNode.nextInstrument; + return instrumentNode.nextInstrumentNode; } // Match not at the head of the chain; remove it. found = instrumentNode.removeFromChain(TruffleOptInstrument.this); @@ -466,26 +577,26 @@ this.isCompiled = CompilerDirectives.inCompiledCode(); TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled); } - if (nextInstrument != null) { - nextInstrument.enter(node, vFrame); + if (nextInstrumentNode != null) { + nextInstrumentNode.enter(node, vFrame); } } public void returnVoid(Node node, VirtualFrame vFrame) { - if (nextInstrument != null) { - nextInstrument.returnVoid(node, vFrame); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnVoid(node, vFrame); } } public void returnValue(Node node, VirtualFrame vFrame, Object result) { - if (nextInstrument != null) { - nextInstrument.returnValue(node, vFrame, result); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnValue(node, vFrame, result); } } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - if (nextInstrument != null) { - nextInstrument.returnExceptional(node, vFrame, exception); + if (nextInstrumentNode != null) { + nextInstrumentNode.returnExceptional(node, vFrame, exception); } } @@ -500,10 +611,10 @@ @NodeInfo(cost = NodeCost.NONE) abstract class AbstractInstrumentNode extends Node implements TruffleEvents, InstrumentationNode { - @Child protected AbstractInstrumentNode nextInstrument; + @Child protected AbstractInstrumentNode nextInstrumentNode; protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) { - this.nextInstrument = nextNode; + this.nextInstrumentNode = nextNode; } @Override @@ -527,21 +638,21 @@ */ private boolean removeFromChain(Instrument instrument) { assert getInstrument() != instrument; - if (nextInstrument == null) { + if (nextInstrumentNode == null) { return false; } - if (nextInstrument.getInstrument() == instrument) { + if (nextInstrumentNode.getInstrument() == instrument) { // Next is the one to remove - if (nextInstrument.nextInstrument == null) { + if (nextInstrumentNode.nextInstrumentNode == null) { // Next is at the tail; just forget - nextInstrument = null; + nextInstrumentNode = null; } else { // Replace next with its successor - nextInstrument.replace(nextInstrument.nextInstrument); + nextInstrumentNode.replace(nextInstrumentNode.nextInstrumentNode); } return true; } - return nextInstrument.removeFromChain(instrument); + return nextInstrumentNode.removeFromChain(instrument); } protected String getInstrumentInfo() {