# HG changeset patch # User Michael Van De Vanter # Date 1443414879 25200 # Node ID 75e5db92973a81c26c659e1722a501ae8b16cdb2 # Parent e7643754d982888fe1dfbd7a6ec21001638050e8 TruffleInstrumentation: fold the "TagTrap" mechanism into the general framework of Instruments, Listeners, and management via Instrumenter.attach() methods. diff -r e7643754d982 -r 75e5db92973a 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 Fri Sep 25 14:58:35 2015 -0700 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java Sun Sep 27 21:34:39 2015 -0700 @@ -34,6 +34,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.FrameInstance; import com.oracle.truffle.api.frame.FrameInstanceVisitor; import com.oracle.truffle.api.frame.MaterializedFrame; @@ -44,9 +45,11 @@ 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.StandardAfterInstrumentListener; +import com.oracle.truffle.api.instrument.StandardBeforeInstrumentListener; import com.oracle.truffle.api.instrument.StandardSyntaxTag; import com.oracle.truffle.api.instrument.SyntaxTag; -import com.oracle.truffle.api.instrument.SyntaxTagTrap; +import com.oracle.truffle.api.instrument.TagInstrument; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.LineLocation; import com.oracle.truffle.api.source.Source; @@ -406,6 +409,8 @@ * @see Debugger#prepareStepInto(int) */ private final class StepInto extends StepStrategy { + private TagInstrument beforeTagInstrument; + private TagInstrument afterTagInstrument; private int unfinishedStepCount; StepInto(int stepCount) { @@ -415,26 +420,40 @@ @Override protected void setStrategy(final int stackDepth) { - instrumenter.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { + + beforeTagInstrument = instrumenter.attach(STEPPING_TAG, new StandardBeforeInstrumentListener() { @TruffleBoundary @Override - public void tagTrappedAt(Node node, MaterializedFrame mFrame) { + public void onEnter(Probe probe, Node node, VirtualFrame vFrame) { // HALT: just before statement --unfinishedStepCount; - strategyTrace("TRAP BEFORE", "unfinished steps=%d", unfinishedStepCount); + strategyTrace("HALT BEFORE", "unfinished steps=%d", unfinishedStepCount); // Should run in fast path if (unfinishedStepCount <= 0) { - halt(node, mFrame, true); + halt(node, vFrame.materialize(), true); } strategyTrace("RESUME BEFORE", ""); } - }); - instrumenter.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { + }, "Debugger StepInto"); + + afterTagInstrument = instrumenter.attach(CALL_TAG, new StandardAfterInstrumentListener() { + + public void onReturnVoid(Probe probe, Node node, VirtualFrame vFrame) { + doHalt(node, vFrame.materialize()); + } + + public void onReturnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { + doHalt(node, vFrame.materialize()); + } + + public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) { + doHalt(node, vFrame.materialize()); + } + @TruffleBoundary - @Override - public void tagTrappedAt(Node node, MaterializedFrame mFrame) { + private void doHalt(Node node, MaterializedFrame mFrame) { --unfinishedStepCount; - strategyTrace(null, "TRAP AFTER unfinished steps=%d", unfinishedStepCount); + strategyTrace(null, "HALT AFTER unfinished steps=%d", unfinishedStepCount); if (currentStackDepth() < stackDepth) { // HALT: just "stepped out" if (unfinishedStepCount <= 0) { @@ -443,13 +462,13 @@ } strategyTrace("RESUME AFTER", ""); } - }); + }, "Debugger StepInto"); } @Override protected void unsetStrategy() { - instrumenter.setBeforeTagTrap(null); - instrumenter.setAfterTagTrap(null); + beforeTagInstrument.dispose(); + afterTagInstrument.dispose(); } } @@ -470,27 +489,41 @@ */ private final class StepOut extends StepStrategy { + private TagInstrument afterTagInstrument; + @Override protected void setStrategy(final int stackDepth) { - instrumenter.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { + + afterTagInstrument = instrumenter.attach(CALL_TAG, new StandardAfterInstrumentListener() { + + public void onReturnVoid(Probe probe, Node node, VirtualFrame vFrame) { + doHalt(node, vFrame.materialize()); + } + + public void onReturnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { + doHalt(node, vFrame.materialize()); + } + + public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) { + doHalt(node, vFrame.materialize()); + } @TruffleBoundary - @Override - public void tagTrappedAt(Node node, MaterializedFrame mFrame) { + private void doHalt(Node node, MaterializedFrame mFrame) { // HALT: final int currentStackDepth = currentStackDepth(); - strategyTrace("TRAP AFTER", "stackDepth: start=%d current=%d", stackDepth, currentStackDepth); + strategyTrace("HALT AFTER", "stackDepth: start=%d current=%d", stackDepth, currentStackDepth); if (currentStackDepth < stackDepth) { halt(node, mFrame, false); } strategyTrace("RESUME AFTER", ""); } - }); + }, "Debugger StepOut"); } @Override protected void unsetStrategy() { - instrumenter.setAfterTagTrap(null); + afterTagInstrument.dispose(); } } @@ -508,6 +541,8 @@ * */ private final class StepOver extends StepStrategy { + private TagInstrument beforeTagInstrument; + private TagInstrument afterTagInstrument; private int unfinishedStepCount; StepOver(int stepCount) { @@ -516,20 +551,21 @@ @Override protected void setStrategy(final int stackDepth) { - instrumenter.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { + beforeTagInstrument = instrumenter.attach(STEPPING_TAG, new StandardBeforeInstrumentListener() { + @TruffleBoundary @Override - public void tagTrappedAt(Node node, MaterializedFrame mFrame) { + public void onEnter(Probe probe, Node node, VirtualFrame vFrame) { final int currentStackDepth = currentStackDepth(); if (currentStackDepth <= stackDepth) { // HALT: stack depth unchanged or smaller; treat like StepInto --unfinishedStepCount; if (TRACE) { - strategyTrace("TRAP BEFORE", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth); + strategyTrace("HALT BEFORE", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth); } // Test should run in fast path if (unfinishedStepCount <= 0) { - halt(node, mFrame, true); + halt(node, vFrame.materialize(), true); } } else { // CONTINUE: Stack depth increased; don't count as a step @@ -539,17 +575,29 @@ } strategyTrace("RESUME BEFORE", ""); } - }); + }, "Debugger StepOver"); + + afterTagInstrument = instrumenter.attach(CALL_TAG, new StandardAfterInstrumentListener() { + + public void onReturnVoid(Probe probe, Node node, VirtualFrame vFrame) { + doHalt(node, vFrame.materialize()); + } - instrumenter.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) { + public void onReturnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { + doHalt(node, vFrame.materialize()); + } + + public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) { + doHalt(node, vFrame.materialize()); + } + @TruffleBoundary - @Override - public void tagTrappedAt(Node node, MaterializedFrame mFrame) { + private void doHalt(Node node, MaterializedFrame mFrame) { final int currentStackDepth = currentStackDepth(); if (currentStackDepth < stackDepth) { // HALT: just "stepped out" --unfinishedStepCount; - strategyTrace("TRAP AFTER", "unfinished steps=%d stackDepth: start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth); + strategyTrace("HALT AFTER", "unfinished steps=%d stackDepth: start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth); // Should run in fast path if (unfinishedStepCount <= 0) { halt(node, mFrame, false); @@ -557,13 +605,13 @@ strategyTrace("RESUME AFTER", ""); } } - }); + }, "Debugger StepOver"); } @Override protected void unsetStrategy() { - instrumenter.setBeforeTagTrap(null); - instrumenter.setAfterTagTrap(null); + beforeTagInstrument.dispose(); + afterTagInstrument.dispose(); } } @@ -581,6 +629,7 @@ * */ private final class StepOverNested extends StepStrategy { + private TagInstrument beforeTagInstrument; private int unfinishedStepCount; private final int startStackDepth; @@ -591,28 +640,28 @@ @Override protected void setStrategy(final int stackDepth) { - instrumenter.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) { + beforeTagInstrument = instrumenter.attach(STEPPING_TAG, new StandardBeforeInstrumentListener() { @TruffleBoundary @Override - public void tagTrappedAt(Node node, MaterializedFrame mFrame) { + public void onEnter(Probe probe, Node node, VirtualFrame vFrame) { final int currentStackDepth = currentStackDepth(); if (currentStackDepth <= startStackDepth) { // At original step depth (or smaller) after being nested --unfinishedStepCount; - strategyTrace("TRAP AFTER", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth); + strategyTrace("HALT AFTER", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth); if (unfinishedStepCount <= 0) { - halt(node, mFrame, false); + halt(node, vFrame.materialize(), false); } // TODO (mlvdv) fixme for multiple steps strategyTrace("RESUME BEFORE", ""); } } - }); + }, "Debuger StepOverNested"); } @Override protected void unsetStrategy() { - instrumenter.setBeforeTagTrap(null); + beforeTagInstrument.dispose(); } } diff -r e7643754d982 -r 75e5db92973a 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 Fri Sep 25 14:58:35 2015 -0700 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java Sun Sep 27 21:34:39 2015 -0700 @@ -46,11 +46,10 @@ 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.ProbeInstrument; import com.oracle.truffle.api.instrument.Instrumenter; import com.oracle.truffle.api.instrument.Probe; +import com.oracle.truffle.api.instrument.ProbeInstrument; import com.oracle.truffle.api.instrument.SyntaxTag; -import com.oracle.truffle.api.instrument.SyntaxTagTrap; import com.oracle.truffle.api.instrument.impl.DefaultProbeListener; import com.oracle.truffle.api.instrument.impl.DefaultStandardInstrumentListener; import com.oracle.truffle.api.nodes.InvalidAssumptionException; @@ -63,18 +62,20 @@ * 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 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. + * The + * {@linkplain Instrumenter#attach(SyntaxTag, com.oracle.truffle.api.instrument.StandardBeforeInstrumentListener, String) + * before TagInstrument}, does the same thing more efficiently, but there may only be one + * before TagInstrument active at a time. Any number of {@link TagBreakpoint}s may coexist + * with the before TagInstrument, but it would be confusing to have a {@link TagBreakpoint} + * set for the same Tag as the current before TagInstrument. *

* Notes: *

    *
  1. Only one Tag Breakpoint can be active for a specific {@linkplain SyntaxTag Tag}.
  2. *
  3. A newly created breakpoint looks for probes matching the tag, attaches to them if found by * installing an {@link ProbeInstrument}.
  4. - *
  5. When Truffle "splits" or otherwise copies an AST, any attached {@link ProbeInstrument} will be - * copied along with the rest of the AST and will call back to the same breakpoint.
  6. + *
  7. When Truffle "splits" or otherwise copies an AST, any attached {@link ProbeInstrument} will + * be copied along with the rest of the AST and will call back to the same breakpoint.
  8. *
  9. When notification is received that the breakpoint's Tag has been newly added to a Node, then * the breakpoint will attach a new Instrument at the probe to activate the breakpoint at that * location.
  10. diff -r e7643754d982 -r 75e5db92973a truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Sun Sep 27 21:34:39 2015 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 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; + +/** + * A binding between: + *
      + *
    1. Some source of execution events in an executing Truffle AST, and
    2. + *
    3. A listener: a consumer of execution events on behalf of an external client. + *
    + *

    + * Client-oriented documentation for the use of Instruments is available online at https:// + * wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events + * + * @See Instrumenter + */ +abstract class Instrument { + + protected Instrument() { + } + + /** + * Removes this from its source of execution events and renders itself Instrument inert. + * + * @throws IllegalStateException if this has already been disposed + */ + public abstract void dispose() throws IllegalStateException; + + /** + * Has this been detached from its source of execution events. + */ + public abstract boolean isDisposed(); + +} diff -r e7643754d982 -r 75e5db92973a truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java Fri Sep 25 14:58:35 2015 -0700 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java Sun Sep 27 21:34:39 2015 -0700 @@ -37,6 +37,8 @@ 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.TagInstrument.AfterTagInstrument; +import com.oracle.truffle.api.instrument.TagInstrument.BeforeTagInstrument; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.Source; @@ -80,7 +82,8 @@ *