Mercurial > hg > truffle
changeset 22482:e4dd15f04c7d
Merge with 825d0d0301c9a923065d5c52ecb4dd17e649ddab
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Mon, 07 Dec 2015 21:23:02 -0800 |
parents | 07f3efb4e321 (diff) 825d0d0301c9 (current diff) |
children | 8d19a118c109 |
files | truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceSection.java |
diffstat | 10 files changed, 315 insertions(+), 285 deletions(-) [+] |
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Mon Dec 07 21:23:02 2015 -0800 @@ -33,7 +33,6 @@ import java.lang.annotation.Target; import java.util.Map; import java.util.Objects; -import java.util.WeakHashMap; import com.oracle.truffle.api.debug.Debugger; import com.oracle.truffle.api.debug.SuspendedEvent;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java Mon Dec 07 21:23:02 2015 -0800 @@ -33,10 +33,13 @@ import com.oracle.truffle.api.source.Source; /** - * Breakpoint in an executing {@link com.oracle.truffle.api.vm.PolyglotEngine}. - * - * @see Debugger + * Breakpoint in a {@link com.oracle.truffle.api.vm.PolyglotEngine} with + * {@link com.oracle.truffle.api.debug debugging turned on}. You can ask + * {@link Debugger#setLineBreakpoint(int, com.oracle.truffle.api.source.LineLocation, boolean)} or + * {@link Debugger#setTagBreakpoint(int, com.oracle.truffle.api.instrument.SyntaxTag, boolean)} to + * create an instance of {@link Breakpoint}. */ +@SuppressWarnings("javadoc") public abstract class Breakpoint { /** @@ -108,7 +111,7 @@ private State state; - protected Breakpoint(State state, int ignoreCount, boolean isOneShot) { + Breakpoint(State state, int ignoreCount, boolean isOneShot) { this.state = state; this.isOneShot = isOneShot; this.ignoreCount = ignoreCount; @@ -197,7 +200,7 @@ assert state == s; } - protected final void setState(State state) { + final void setState(State state) { this.state = state; }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java Mon Dec 07 21:23:02 2015 -0800 @@ -154,7 +154,7 @@ * @throws IOException if the breakpoint can not be set. */ @TruffleBoundary - public LineBreakpoint setLineBreakpoint(int ignoreCount, LineLocation lineLocation, boolean oneShot) throws IOException { + public Breakpoint setLineBreakpoint(int ignoreCount, LineLocation lineLocation, boolean oneShot) throws IOException { return lineBreaks.create(ignoreCount, lineLocation, oneShot); } @@ -167,7 +167,7 @@ * @throws IOException if the breakpoint already set */ @TruffleBoundary - public TagBreakpoint setTagBreakpoint(int ignoreCount, SyntaxTag tag, boolean oneShot) throws IOException { + public Breakpoint setTagBreakpoint(int ignoreCount, SyntaxTag tag, boolean oneShot) throws IOException { return tagBreaks.create(ignoreCount, tag, oneShot); } @@ -680,8 +680,11 @@ */ private MaterializedFrame haltedFrame; - /** Subset of the Truffle stack corresponding to the current execution. */ - private List<FrameDebugDescription> contextStack; + /** + * Subset of the Truffle stack corresponding to the current execution, not including the + * current frame. + */ + private List<FrameInstance> contextStack; private DebugExecutionContext(Source executionSource, DebugExecutionContext previousContext) { this(executionSource, previousContext, -1); @@ -759,11 +762,10 @@ final List<String> recentWarnings = new ArrayList<>(warnings); warnings.clear(); - final List<FrameDebugDescription> frames = new ArrayList<>(); + final List<FrameInstance> frames = new ArrayList<>(); // Map the Truffle stack for this execution, ignore nested executions // Ignore frames for which no CallNode is available. - // The top/current/0 frame is not produced by the iterator. - frames.add(new FrameDebugDescription(0, haltedNode, haltedFrame)); + // The top/current/0 frame is not produced by the iterator; reported separately Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<FrameInstance>() { int stackIndex = 1; int frameIndex = 1; @@ -774,8 +776,8 @@ final Node callNode = frameInstance.getCallNode(); if (callNode != null) { final SourceSection sourceSection = callNode.getEncapsulatingSourceSection(); - if (sourceSection != null && sourceSection.getIdentifier() != SourceSection.UNKNOWN) { - frames.add(new FrameDebugDescription(frameIndex, frameInstance)); + if (sourceSection != null && !sourceSection.getIdentifier().equals("<unknown>")) { + frames.add(frameInstance); frameIndex++; } else if (TRACE) { if (callNode != null) { @@ -783,7 +785,7 @@ } else { contextTrace("HIDDEN frame added"); } - frames.add(new FrameDebugDescription(frameIndex, frameInstance)); + frames.add(frameInstance); frameIndex++; } } else if (TRACE) { @@ -792,7 +794,7 @@ } else { contextTrace("HIDDEN frame added"); } - frames.add(new FrameDebugDescription(frameIndex, frameInstance)); + frames.add(frameInstance); frameIndex++; } stackIndex++; @@ -813,7 +815,7 @@ try { // Pass control to the debug client with current execution suspended - ACCESSOR.dispatchEvent(vm, new SuspendedEvent(Debugger.this, contextStack, recentWarnings)); + ACCESSOR.dispatchEvent(vm, new SuspendedEvent(Debugger.this, haltedNode, haltedFrame, contextStack, recentWarnings)); // Debug client finished normally, execution resumes // Presume that the client has set a new strategy (or default to Continue) running = true;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpoint.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpoint.java Mon Dec 07 21:23:02 2015 -0800 @@ -31,25 +31,16 @@ * * @see Debugger */ -public abstract class LineBreakpoint extends Breakpoint { - - private final LineLocation lineLocation; +abstract class LineBreakpoint extends Breakpoint { - protected LineBreakpoint(State state, LineLocation lineLocation, int ignoreCount, boolean isOneShot) { + LineBreakpoint(State state, int ignoreCount, boolean isOneShot) { super(state, ignoreCount, isOneShot); - this.lineLocation = lineLocation; } /** * Gets the {@linkplain LineLocation source line location} that specifies where this breakpoint * will trigger. */ - public final LineLocation getLineLocation() { - return lineLocation; - } + public abstract LineLocation getLineLocation(); - @Override - public String getLocationDescription() { - return "Line: " + lineLocation.getShortDescription(); - } }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java Mon Dec 07 21:23:02 2015 -0800 @@ -271,6 +271,8 @@ private static final String SHOULD_NOT_HAPPEN = "LineBreakpointImpl: should not happen"; + private final LineLocation lineLocation; + // Cached assumption that the global status of line breakpoint activity has not changed. private Assumption breakpointsActiveAssumption; @@ -287,7 +289,9 @@ private List<ProbeInstrument> instruments = new ArrayList<>(); public LineBreakpointImpl(int ignoreCount, LineLocation lineLocation, boolean oneShot) { - super(ENABLED_UNRESOLVED, lineLocation, ignoreCount, oneShot); + super(ENABLED_UNRESOLVED, ignoreCount, oneShot); + this.lineLocation = lineLocation; + this.breakpointsActiveAssumption = LineBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption(); this.isEnabled = true; this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption(BREAKPOINT_NAME + " enabled state unchanged"); @@ -464,6 +468,16 @@ warningLog.addWarning(String.format("Exception in %s: %s", getShortDescription(), ex.getMessage())); } + @Override + public String getLocationDescription() { + return "Line: " + lineLocation.getShortDescription(); + } + + @Override + public LineLocation getLineLocation() { + return lineLocation; + } + private final class UnconditionalLineBreakInstrumentListener extends DefaultStandardInstrumentListener { @Override
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java Mon Dec 07 21:23:02 2015 -0800 @@ -30,6 +30,8 @@ import java.util.List; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.FrameInstance; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.instrument.StandardSyntaxTag; import com.oracle.truffle.api.nodes.Node; @@ -58,15 +60,19 @@ } private final Debugger debugger; - private final List<FrameDebugDescription> stack; + private final Node haltedNode; + private final MaterializedFrame haltedFrame; + private final List<FrameInstance> stack; private final List<String> warnings; - SuspendedEvent(Debugger debugger, List<FrameDebugDescription> stack, List<String> warnings) { + SuspendedEvent(Debugger debugger, Node haltedNode, MaterializedFrame haltedFrame, List<FrameInstance> stack, List<String> warnings) { this.debugger = debugger; + this.haltedNode = haltedNode; + this.haltedFrame = haltedFrame; this.stack = stack; this.warnings = warnings; if (TRACE) { - trace("Execution suspended at Node=" + stack.get(0).node()); + trace("Execution suspended at Node=" + haltedNode); } } @@ -83,11 +89,11 @@ } public Node getNode() { - return stack.get(0).node(); + return haltedNode; } public MaterializedFrame getFrame() { - return stack.get(0).frame(); + return haltedFrame; } public List<String> getRecentWarnings() { @@ -96,12 +102,13 @@ /** * Gets the stack frames from the currently halted - * {@link com.oracle.truffle.api.vm.PolyglotEngine} execution. + * {@link com.oracle.truffle.api.vm.PolyglotEngine} execution, not counting the Node and Frame + * where halted. * * @return list of stack frames */ @CompilerDirectives.TruffleBoundary - public List<FrameDebugDescription> getStack() { + public List<FrameInstance> getStack() { return stack; } @@ -188,20 +195,20 @@ * Evaluates given code snippet in the context of currently suspended execution. * * @param code the snippet to evaluate - * @param frameNumber <code>null</code> in case the evaluation should happen in top most frame, - * non-null value to specify a frame from those {@link #getStack() currently on - * stack} to perform the evaluation in context of + * @param frameNumber specify a frame from those {@link #getStack() currently on stack} to + * perform the evaluation in context of * @return the computed value * @throws IOException in case an evaluation goes wrong */ public Object eval(String code, Integer frameNumber) throws IOException { - int n = 0; - if (frameNumber != null) { - if (frameNumber < 0 || frameNumber >= stack.size()) { - throw new IOException("invalid frame number"); - } - n = frameNumber; + if (frameNumber < 0 || frameNumber >= stack.size()) { + throw new IOException("invalid frame number"); } - return debugger.evalInContext(this, code, stack.get(n).node(), stack.get(n).frame()); + if (frameNumber == 0) { + return debugger.evalInContext(this, code, haltedNode, haltedFrame); + } + final FrameInstance instance = stack.get(frameNumber - 1); + final MaterializedFrame frame = instance.getFrame(FrameAccess.MATERIALIZE, true).materialize(); + return debugger.evalInContext(this, code, instance.getCallNode(), frame); } }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpoint.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpoint.java Mon Dec 07 21:23:02 2015 -0800 @@ -31,24 +31,15 @@ * * @see Debugger */ -public abstract class TagBreakpoint extends Breakpoint { - - private final SyntaxTag tag; +abstract class TagBreakpoint extends Breakpoint { - protected TagBreakpoint(State state, SyntaxTag tag, int ignoreCount, boolean isOneShot) { + TagBreakpoint(State state, int ignoreCount, boolean isOneShot) { super(state, ignoreCount, isOneShot); - this.tag = tag; } /** * Gets the tag that specifies where this breakpoint will trigger. */ - public final SyntaxTag getTag() { - return tag; - } + public abstract SyntaxTag getTag(); - @Override - public String getLocationDescription() { - return "Tag " + tag.name(); - } }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java Mon Dec 07 21:23:02 2015 -0800 @@ -240,6 +240,8 @@ private static final String SHOULD_NOT_HAPPEN = "TagBreakpointImpl: should not happen"; + private final SyntaxTag tag; + // Cached assumption that the global status of tag breakpoint activity has not changed. private Assumption breakpointsActiveAssumption; @@ -256,7 +258,8 @@ private List<ProbeInstrument> instruments = new ArrayList<>(); private TagBreakpointImpl(int ignoreCount, SyntaxTag tag, boolean oneShot) { - super(ENABLED, tag, ignoreCount, oneShot); + super(ENABLED, ignoreCount, oneShot); + this.tag = tag; this.breakpointsActiveAssumption = TagBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption(); this.isEnabled = true; this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption(BREAKPOINT_NAME + " enabled state unchanged"); @@ -353,7 +356,7 @@ @TruffleBoundary private String getShortDescription() { - return BREAKPOINT_NAME + "@" + getTag().name(); + return BREAKPOINT_NAME + "@" + tag.name(); } private void changeState(State after) { @@ -427,6 +430,16 @@ warningLog.addWarning(String.format("Exception in %s: %s", getShortDescription(), ex.getMessage())); } + @Override + public String getLocationDescription() { + return "Tag " + tag.name(); + } + + @Override + public SyntaxTag getTag() { + return tag; + } + private final class UnconditionalTagBreakInstrumentListener extends DefaultStandardInstrumentListener { @Override
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLHandler.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLHandler.java Mon Dec 07 21:23:02 2015 -0800 @@ -29,10 +29,10 @@ import java.util.Collection; import java.util.List; -import com.oracle.truffle.api.debug.Breakpoint; -import com.oracle.truffle.api.debug.FrameDebugDescription; -import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.frame.FrameInstance; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.instrument.ASTPrinter; import com.oracle.truffle.api.instrument.KillException; import com.oracle.truffle.api.instrument.QuitException; @@ -43,6 +43,7 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.vm.PolyglotEngine.Language; import com.oracle.truffle.tools.debug.shell.REPLMessage; +import com.oracle.truffle.tools.debug.shell.server.REPLServer.BreakpointInfo; import com.oracle.truffle.tools.debug.shell.server.REPLServer.Context; /** @@ -108,15 +109,15 @@ return replies; } - protected static final REPLMessage createBreakpointInfoMessage(Breakpoint breakpoint, REPLServer replServer) { + protected static final REPLMessage createBreakpointInfoMessage(BreakpointInfo info) { final REPLMessage infoMessage = new REPLMessage(REPLMessage.OP, REPLMessage.BREAKPOINT_INFO); - infoMessage.put(REPLMessage.BREAKPOINT_ID, Integer.toString(replServer.getBreakpointID(breakpoint))); - infoMessage.put(REPLMessage.BREAKPOINT_STATE, breakpoint.getState().getName()); - infoMessage.put(REPLMessage.BREAKPOINT_HIT_COUNT, Integer.toString(breakpoint.getHitCount())); - infoMessage.put(REPLMessage.BREAKPOINT_IGNORE_COUNT, Integer.toString(breakpoint.getIgnoreCount())); - infoMessage.put(REPLMessage.INFO_VALUE, breakpoint.getLocationDescription().toString()); - if (breakpoint.getCondition() != null) { - infoMessage.put(REPLMessage.BREAKPOINT_CONDITION, breakpoint.getCondition().getCode()); + infoMessage.put(REPLMessage.BREAKPOINT_ID, Integer.toString(info.getID())); + infoMessage.put(REPLMessage.BREAKPOINT_STATE, info.describeState()); + infoMessage.put(REPLMessage.BREAKPOINT_HIT_COUNT, Integer.toString(info.getHitCount())); + infoMessage.put(REPLMessage.BREAKPOINT_IGNORE_COUNT, Integer.toString(info.getIgnoreCount())); + infoMessage.put(REPLMessage.INFO_VALUE, info.describeLocation()); + if (info.getCondition() != null) { + infoMessage.put(REPLMessage.BREAKPOINT_CONDITION, info.getCondition()); } infoMessage.put(REPLMessage.STATUS, REPLMessage.SUCCEEDED); return infoMessage; @@ -150,10 +151,11 @@ public REPLMessage[] receive(REPLMessage request, REPLServer replServer) { final Visualizer visualizer = replServer.getVisualizer(); final ArrayList<REPLMessage> replies = new ArrayList<>(); - final List<FrameDebugDescription> stack = replServer.getCurrentContext().getStack(); - - for (int i = 0; i < stack.size(); i++) { - replies.add(btMessage(i, stack.get(i).node(), visualizer)); + final Context currentContext = replServer.getCurrentContext(); + final List<FrameInstance> stack = currentContext.getStack(); + replies.add(btMessage(0, currentContext.getNode(), visualizer)); + for (int i = 1; i <= stack.size(); i++) { + replies.add(btMessage(i, stack.get(i - 1).getCallNode(), visualizer)); } if (replies.size() > 0) { return replies.toArray(new REPLMessage[0]); @@ -199,7 +201,7 @@ if (source == null) { return finishReplyFailed(reply, fileName + " not found"); } - Integer lineNumber = request.getIntValue(REPLMessage.LINE_NUMBER); + final Integer lineNumber = request.getIntValue(REPLMessage.LINE_NUMBER); if (lineNumber == null) { return finishReplyFailed(reply, "missing line number"); } @@ -207,15 +209,10 @@ if (ignoreCount == null) { ignoreCount = 0; } - Breakpoint breakpoint; - try { - breakpoint = replServer.setLineBreakpoint(DEFAULT_IGNORE_COUNT, source.createLineLocation(lineNumber), false); - } catch (IOException ex) { - return finishReplyFailed(reply, ex); - } + final BreakpointInfo breakpointInfo = replServer.setLineBreakpoint(DEFAULT_IGNORE_COUNT, source.createLineLocation(lineNumber), false); reply.put(REPLMessage.SOURCE_NAME, fileName); reply.put(REPLMessage.FILE_PATH, source.getPath()); - reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(replServer.getBreakpointID(breakpoint))); + reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointInfo.getID())); reply.put(REPLMessage.LINE_NUMBER, Integer.toString(lineNumber)); reply.put(REPLMessage.BREAKPOINT_IGNORE_COUNT, ignoreCount.toString()); return finishReplySucceeded(reply, "Breakpoint set"); @@ -239,19 +236,14 @@ if (source == null) { return finishReplyFailed(reply, fileName + " not found"); } - Integer lineNumber = request.getIntValue(REPLMessage.LINE_NUMBER); + final Integer lineNumber = request.getIntValue(REPLMessage.LINE_NUMBER); if (lineNumber == null) { return finishReplyFailed(reply, "missing line number"); } - Breakpoint breakpoint; - try { - breakpoint = replServer.setLineBreakpoint(DEFAULT_IGNORE_COUNT, source.createLineLocation(lineNumber), true); - } catch (IOException ex) { - return finishReplyFailed(reply, ex); - } + final BreakpointInfo breakpointInfo = replServer.setLineBreakpoint(DEFAULT_IGNORE_COUNT, source.createLineLocation(lineNumber), true); reply.put(REPLMessage.SOURCE_NAME, fileName); reply.put(REPLMessage.FILE_PATH, source.getPath()); - reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(replServer.getBreakpointID(breakpoint))); + reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointInfo.getID())); reply.put(REPLMessage.LINE_NUMBER, Integer.toString(lineNumber)); return finishReplySucceeded(reply, "One-shot line breakpoint set"); } @@ -291,8 +283,8 @@ public REPLMessage[] receive(REPLMessage request, REPLServer replServer) { final REPLMessage reply = createReply(); final ArrayList<REPLMessage> infoMessages = new ArrayList<>(); - for (Breakpoint breakpoint : replServer.getBreakpoints()) { - infoMessages.add(createBreakpointInfoMessage(breakpoint, replServer)); + for (BreakpointInfo breakpointInfo : replServer.getBreakpoints()) { + infoMessages.add(createBreakpointInfoMessage(breakpointInfo)); } if (infoMessages.size() > 0) { return infoMessages.toArray(new REPLMessage[0]); @@ -338,15 +330,15 @@ @Override public REPLMessage[] receive(REPLMessage request, REPLServer replServer) { final REPLMessage reply = createReply(); - Integer breakpointNumber = request.getIntValue(REPLMessage.BREAKPOINT_ID); + final Integer breakpointNumber = request.getIntValue(REPLMessage.BREAKPOINT_ID); if (breakpointNumber == null) { return finishReplyFailed(reply, "missing breakpoint number"); } - final Breakpoint breakpoint = replServer.findBreakpoint(breakpointNumber); - if (breakpoint == null) { + final BreakpointInfo breakpointInfo = replServer.findBreakpoint(breakpointNumber); + if (breakpointInfo == null) { return finishReplyFailed(reply, "no breakpoint number " + breakpointNumber); } - replServer.clearBreakpoint(breakpoint); + breakpointInfo.dispose(); reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointNumber)); return finishReplySucceeded(reply, "Breakpoint " + breakpointNumber + " cleared"); } @@ -367,12 +359,12 @@ @Override public REPLMessage[] receive(REPLMessage request, REPLServer replServer) { final REPLMessage reply = createReply(); - final Collection<Breakpoint> breakpoints = replServer.getBreakpoints(); + final Collection<BreakpointInfo> breakpoints = replServer.getBreakpoints(); if (breakpoints.isEmpty()) { return finishReplyFailed(reply, "no breakpoints to delete"); } - for (Breakpoint breakpoint : breakpoints) { - breakpoint.dispose(); + for (BreakpointInfo breakpointInfo : breakpoints) { + breakpointInfo.dispose(); } return finishReplySucceeded(reply, Integer.toString(breakpoints.size()) + " breakpoints deleted"); } @@ -387,11 +379,11 @@ if (breakpointNumber == null) { return finishReplyFailed(reply, "missing breakpoint number"); } - final Breakpoint breakpoint = replServer.findBreakpoint(breakpointNumber); - if (breakpoint == null) { + final BreakpointInfo breakpointInfo = replServer.findBreakpoint(breakpointNumber); + if (breakpointInfo == null) { return finishReplyFailed(reply, "no breakpoint number " + breakpointNumber); } - breakpoint.setEnabled(false); + breakpointInfo.setEnabled(false); reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointNumber)); return finishReplySucceeded(reply, "Breakpoint " + breakpointNumber + " disabled"); } @@ -406,11 +398,11 @@ if (breakpointNumber == null) { return finishReplyFailed(reply, "missing breakpoint number"); } - final Breakpoint breakpoint = replServer.findBreakpoint(breakpointNumber); - if (breakpoint == null) { + final BreakpointInfo breakpointInfo = replServer.findBreakpoint(breakpointNumber); + if (breakpointInfo == null) { return finishReplyFailed(reply, "no breakpoint number " + breakpointNumber); } - breakpoint.setEnabled(true); + breakpointInfo.setEnabled(true); reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointNumber)); return finishReplySucceeded(reply, "Breakpoint " + breakpointNumber + " enabled"); } @@ -479,17 +471,24 @@ if (frameNumber == null) { return finishReplyFailed(createReply(), "no frame number specified"); } - final List<FrameDebugDescription> stack = replServer.getCurrentContext().getStack(); - if (frameNumber < 0 || frameNumber >= stack.size()) { + final Context currentContext = replServer.getCurrentContext(); + final List<FrameInstance> stack = currentContext.getStack(); + if (frameNumber < 0 || frameNumber > stack.size()) { return finishReplyFailed(createReply(), "frame number " + frameNumber + " out of range"); } final Visualizer visualizer = replServer.getVisualizer(); - final FrameDebugDescription frameDescription = stack.get(frameNumber); - final Frame frame = frameDescription.frame(); - final Node node = frameDescription.node(); + MaterializedFrame frame; + Node node; + if (frameNumber == 0) { + frame = currentContext.getFrame(); + node = currentContext.getNode(); + } else { + final FrameInstance instance = stack.get(frameNumber - 1); + frame = instance.getFrame(FrameAccess.MATERIALIZE, true).materialize(); + node = instance.getCallNode(); + } List<? extends FrameSlot> slots = frame.getFrameDescriptor().getSlots(); - if (slots.size() == 0) { final REPLMessage emptyFrameMessage = createFrameInfoMessage(replServer, frameNumber, node); return finishReplySucceeded(emptyFrameMessage, "empty frame"); @@ -628,8 +627,8 @@ return finishReplyFailed(message, "missing breakpoint number"); } message.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointNumber)); - final Breakpoint breakpoint = replServer.findBreakpoint(breakpointNumber); - if (breakpoint == null) { + final BreakpointInfo breakpointInfo = replServer.findBreakpoint(breakpointNumber); + if (breakpointInfo == null) { return finishReplyFailed(message, "no breakpoint number " + breakpointNumber); } final String expr = request.get(REPLMessage.BREAKPOINT_CONDITION); @@ -637,7 +636,7 @@ return finishReplyFailed(message, "missing condition for " + breakpointNumber); } try { - breakpoint.setCondition(expr); + breakpointInfo.setCondition(expr); } catch (IOException ex) { return finishReplyFailed(message, "invalid condition for " + breakpointNumber); } catch (UnsupportedOperationException ex) { @@ -735,12 +734,12 @@ return finishReplyFailed(message, "missing breakpoint number"); } message.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointNumber)); - final Breakpoint breakpoint = replServer.findBreakpoint(breakpointNumber); - if (breakpoint == null) { + final BreakpointInfo breakpointInfo = replServer.findBreakpoint(breakpointNumber); + if (breakpointInfo == null) { return finishReplyFailed(message, "no breakpoint number " + breakpointNumber); } try { - breakpoint.setCondition(null); + breakpointInfo.setCondition(null); } catch (Exception ex) { return finishReplyFailed(message, ex); }
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServer.java Mon Dec 07 12:51:32 2015 -0800 +++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServer.java Mon Dec 07 21:23:02 2015 -0800 @@ -36,12 +36,11 @@ import java.util.WeakHashMap; import com.oracle.truffle.api.debug.Breakpoint; +import com.oracle.truffle.api.debug.Breakpoint.State; import com.oracle.truffle.api.debug.Debugger; import com.oracle.truffle.api.debug.ExecutionEvent; -import com.oracle.truffle.api.debug.FrameDebugDescription; -import com.oracle.truffle.api.debug.LineBreakpoint; import com.oracle.truffle.api.debug.SuspendedEvent; -import com.oracle.truffle.api.debug.TagBreakpoint; +import com.oracle.truffle.api.frame.FrameInstance; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.instrument.StandardSyntaxTag; import com.oracle.truffle.api.instrument.SyntaxTag; @@ -64,6 +63,13 @@ */ public final class REPLServer { + enum BreakpointKind { + LINE, + TAG + } + + private static int nextBreakpointUID = 0; + // Language-agnostic private final PolyglotEngine engine; private Debugger db; @@ -87,19 +93,7 @@ private PolyglotEngine.Language defaultLanguage; private final Visualizer visualizer; - private int nextBreakpointUID = 0; - - /** - * Map: breakpoints => breakpoint UID. - * <ul> - * <li>Contains only pending breakpoints when the Debugger not yet available.</li> - * <li>When the Debugger becomes available, each pending breakpoint is replaced with a Debugger - * breakpoint, keeping same UID.</li> - * <li>Contains no disposed breakpoints.</li> - * <li>UIDs for disposed breakpoints are never reused.</li> - * </ul> - */ - private Map<Breakpoint, Integer> breakpoints = new WeakHashMap<>(); + private Map<Integer, BreakpointInfo> breakpoints = new WeakHashMap<>(); public REPLServer(String defaultMIMEType, Visualizer visualizer) { this.visualizer = visualizer == null ? new DefaultVisualizer() : visualizer; @@ -135,27 +129,8 @@ protected void on(ExecutionEvent event) { if (db == null) { db = event.getDebugger(); - if (!breakpoints.isEmpty()) { - ArrayList<? extends Breakpoint> pendingBreakpoints = new ArrayList<>(breakpoints.keySet()); - try { - for (Breakpoint pending : pendingBreakpoints) { - - Integer uid = breakpoints.get(pending); - pending.dispose(); - Breakpoint replacement = null; - if (pending instanceof PendingLineBreakpoint) { - final PendingLineBreakpoint lineBreak = (PendingLineBreakpoint) pending; - replacement = db.setLineBreakpoint(lineBreak.getIgnoreCount(), lineBreak.getLineLocation(), lineBreak.isOneShot()); - - } else if (pending instanceof PendingTagBreakpoint) { - final PendingTagBreakpoint tagBreak = (PendingTagBreakpoint) pending; - replacement = db.setTagBreakpoint(tagBreak.getIgnoreCount(), tagBreak.getTag(), tagBreak.isOneShot()); - } - breakpoints.put(replacement, uid); - } - } catch (IOException e) { - throw new IllegalStateException("pending breakpoints should all be valid"); - } + for (BreakpointInfo breakpointInfo : breakpoints.values()) { + breakpointInfo.activate(db); } } if (currentServerContext.steppingInto) { @@ -329,7 +304,7 @@ } this.steppingInto = stepInto; try { - return symbol.invoke(null, args.toArray(new Object[0])).get(); + return symbol.execute(args.toArray(new Object[0])).get(); } finally { this.steppingInto = false; } @@ -402,11 +377,25 @@ } /** - * Provides access to the execution stack. + * @return Node where halted + */ + Node getNode() { + return event.getNode(); + } + + /** + * @return Frame where halted + */ + MaterializedFrame getFrame() { + return event.getFrame(); + } + + /** + * Provides access to the execution stack, not counting the node/frame where halted. * * @return immutable list of stack elements */ - List<FrameDebugDescription> getStack() { + List<FrameInstance> getStack() { return event.getStack(); } @@ -500,168 +489,190 @@ return language.getMimeTypes().iterator().next(); } - Breakpoint setLineBreakpoint(int ignoreCount, LineLocation lineLocation, boolean oneShot) throws IOException { - Breakpoint breakpoint; - if (db == null) { - breakpoint = new PendingLineBreakpoint(ignoreCount, lineLocation, oneShot); - } else { - breakpoint = db.setLineBreakpoint(ignoreCount, lineLocation, oneShot); - } - registerNewBreakpoint(breakpoint); - return breakpoint; + BreakpointInfo setLineBreakpoint(int ignoreCount, LineLocation lineLocation, boolean oneShot) { + return new BreakpointInfo(db, lineLocation, ignoreCount, oneShot); } - Breakpoint setTagBreakpoint(int ignoreCount, StandardSyntaxTag tag, boolean oneShot) throws IOException { - Breakpoint breakpoint; - if (db == null) { - breakpoint = new PendingTagBreakpoint(ignoreCount, tag, oneShot); - } else { - breakpoint = db.setTagBreakpoint(ignoreCount, tag, oneShot); - } - registerNewBreakpoint(breakpoint); - return breakpoint; + BreakpointInfo setTagBreakpoint(int ignoreCount, StandardSyntaxTag tag, boolean oneShot) { + return new BreakpointInfo(db, tag, ignoreCount, oneShot); } - private synchronized void registerNewBreakpoint(Breakpoint breakpoint) { - breakpoints.put(breakpoint, nextBreakpointUID++); - } - - synchronized Breakpoint findBreakpoint(int id) { - for (Map.Entry<Breakpoint, Integer> entrySet : breakpoints.entrySet()) { - if (id == entrySet.getValue()) { - return entrySet.getKey(); - } - } - return null; + synchronized BreakpointInfo findBreakpoint(int id) { + return breakpoints.get(id); } /** * Gets a list of the currently existing breakpoints. */ - Collection<Breakpoint> getBreakpoints() { - return new ArrayList<>(breakpoints.keySet()); - } - - synchronized int getBreakpointID(Breakpoint breakpoint) { - final Integer id = breakpoints.get(breakpoint); - return id == null ? -1 : id; + Collection<BreakpointInfo> getBreakpoints() { + return new ArrayList<>(breakpoints.values()); } - void clearBreakpoint(Breakpoint breakpoint) { - breakpoint.dispose(); - breakpoints.remove(breakpoint); - } + final class BreakpointInfo { + + private final BreakpointKind kind; + + /** Null before created in debugger or after disposal. */ + private Breakpoint breakpoint; - /** - * The intention to create a line breakpoint. - */ - private final class PendingLineBreakpoint extends LineBreakpoint { + /** Non-null only when breakpoint == null. */ + private State state; // non-null iff haven't "activated" yet + + private final int uid; + + private boolean oneShot; + + private int ignoreCount; private Source conditionSource; - PendingLineBreakpoint(int ignoreCount, LineLocation lineLocation, boolean oneShot) { - super(Breakpoint.State.ENABLED_UNRESOLVED, lineLocation, ignoreCount, oneShot); + private final LineLocation lineLocation; + + private final SyntaxTag tag; + + private BreakpointInfo(Debugger debugger, LineLocation lineLocation, int ignoreCount, boolean oneShot) { + this.kind = BreakpointKind.LINE; + this.lineLocation = lineLocation; + this.tag = null; + this.ignoreCount = ignoreCount; + this.oneShot = oneShot; + this.uid = nextBreakpointUID++; + if (debugger == null) { + this.state = State.ENABLED_UNRESOLVED; + } else { + activate(debugger); + } + breakpoints.put(uid, this); } - @Override - public void setEnabled(boolean enabled) { - switch (getState()) { - case ENABLED_UNRESOLVED: - if (!enabled) { - setState(State.DISABLED_UNRESOLVED); - } - break; - case DISABLED_UNRESOLVED: - if (enabled) { - setState(State.ENABLED_UNRESOLVED); - } - break; - case DISPOSED: - throw new IllegalStateException("Disposed breakpoints must stay disposed"); - default: - throw new IllegalStateException("Unexpected breakpoint state"); + private BreakpointInfo(Debugger debugger, SyntaxTag tag, int ignoreCount, boolean oneShot) { + this.kind = BreakpointKind.TAG; + this.lineLocation = null; + this.tag = tag; + this.ignoreCount = ignoreCount; + this.oneShot = oneShot; + this.uid = nextBreakpointUID++; + if (debugger == null) { + this.state = State.ENABLED_UNRESOLVED; + } else { + activate(debugger); + } + breakpoints.put(uid, this); + } + + private void activate(Debugger debugger) { + if (breakpoint != null) { + throw new IllegalStateException("Breakpoint already activated"); + } + if (state == State.DISPOSED) { + throw new IllegalStateException("Breakpoint already disposed"); + } + try { + switch (kind) { + case LINE: + breakpoint = debugger.setLineBreakpoint(ignoreCount, lineLocation, oneShot); + break; + case TAG: + breakpoint = debugger.setTagBreakpoint(ignoreCount, tag, oneShot); + break; + default: + throw new IllegalStateException("Unexpected breakpoint kind"); + } + if (conditionSource != null) { + breakpoint.setCondition(conditionSource.getCode()); + conditionSource = null; + } + if (state == State.DISABLED_UNRESOLVED) { + breakpoint.setEnabled(false); + } + state = null; + } catch (IOException ex) { + throw new IllegalStateException("Failure to activate breakpoint " + uid + ": " + ex.getMessage()); } } - @Override - public boolean isEnabled() { - return getState() == State.ENABLED_UNRESOLVED; + int getID() { + return uid; } - @Override - public void setCondition(String expr) throws IOException { - - this.conditionSource = expr == null ? null : Source.fromText(expr, "breakpoint condition from text: " + expr); - } - - @Override - public Source getCondition() { - return conditionSource; + String describeState() { + return (breakpoint == null ? state : breakpoint.getState()).getName(); } - @Override - public void dispose() { - if (getState() == State.DISPOSED) { - throw new IllegalStateException("Breakpoint already disposed"); + String describeLocation() { + if (breakpoint == null) { + switch (kind) { + case LINE: + return "Line: " + lineLocation.getShortDescription(); + case TAG: + return "Tag " + tag.name(); + default: + throw new IllegalStateException("Unexpected breakpoint state"); + } } - setState(State.DISPOSED); - breakpoints.remove(this); - } - } - - /** - * The intention to create a line breakpoint. - */ - private final class PendingTagBreakpoint extends TagBreakpoint { - - private Source conditionSource; - - PendingTagBreakpoint(int ignoreCount, SyntaxTag tag, boolean oneShot) { - super(Breakpoint.State.ENABLED_UNRESOLVED, tag, ignoreCount, oneShot); + return breakpoint.getLocationDescription(); } - @Override - public void setEnabled(boolean enabled) { - switch (getState()) { - case ENABLED_UNRESOLVED: - if (!enabled) { - setState(State.DISABLED_UNRESOLVED); - } - break; - case DISABLED_UNRESOLVED: - if (enabled) { - setState(State.ENABLED_UNRESOLVED); - } - break; - case DISPOSED: - throw new IllegalStateException("Disposed breakpoints must stay disposed"); - default: - throw new IllegalStateException("Unexpected breakpoint state"); + void setEnabled(boolean enabled) { + if (breakpoint == null) { + switch (state) { + case ENABLED_UNRESOLVED: + if (!enabled) { + state = State.DISABLED_UNRESOLVED; + } + break; + case DISABLED_UNRESOLVED: + if (enabled) { + state = State.ENABLED_UNRESOLVED; + } + break; + case DISPOSED: + throw new IllegalStateException("Disposed breakpoints must stay disposed"); + default: + throw new IllegalStateException("Unexpected breakpoint state"); + } + } else { + breakpoint.setEnabled(enabled); } } - @Override - public boolean isEnabled() { - return getState() == State.ENABLED_UNRESOLVED; + boolean isEnabled() { + return breakpoint == null ? (state == State.ENABLED_UNRESOLVED) : breakpoint.isEnabled(); } - @Override - public void setCondition(String expr) throws IOException { - this.conditionSource = Source.fromText(expr, "breakpoint condition from text: " + expr); + void setCondition(String expr) throws IOException { + if (breakpoint == null) { + conditionSource = expr == null ? null : Source.fromText(expr, "breakpoint condition from text: " + expr); + } else { + breakpoint.setCondition(expr); + } + } + + String getCondition() { + final Source source = breakpoint == null ? conditionSource : breakpoint.getCondition(); + return source == null ? null : source.getCode(); } - @Override - public Source getCondition() { - return conditionSource; + int getIgnoreCount() { + return breakpoint == null ? ignoreCount : breakpoint.getIgnoreCount(); + } + + int getHitCount() { + return breakpoint == null ? 0 : breakpoint.getHitCount(); } - @Override - public void dispose() { - if (getState() == State.DISPOSED) { - throw new IllegalStateException("Breakpoint already disposed"); + void dispose() { + if (breakpoint == null) { + if (state == State.DISPOSED) { + throw new IllegalStateException("Breakpoint already disposed"); + } + } else { + breakpoint.dispose(); + breakpoint = null; } - setState(State.DISPOSED); - breakpoints.remove(this); + state = State.DISPOSED; + breakpoints.remove(uid); + conditionSource = null; } } }