/** * Adds a new breakpoint to this session and makes it capable of suspending execution. * <p> * The breakpoint suspends execution by making a {@link SuspendedCallback callback} to this * session, together with an event description that includes * {@linkplain SuspendedEvent#getBreakpoints() which breakpoint(s)} were hit. * * @param breakpoint a new breakpoint * @return the installed breakpoint * @throws IllegalStateException if the session has been closed * * @since 0.17 */ public synchronized Breakpoint install(Breakpoint breakpoint) { install(breakpoint, false); return breakpoint; }
/** * Starts a new {@link DebuggerSession session} provided with a callback that gets notified * whenever the execution is suspended and with a list of source syntax elements on which it is * possible to step. Only steps created with one of these element kinds are accepted in this * session. All specified elements are used by steps by default, if not specified otherwise by * {@link StepConfig.Builder#sourceElements(SourceElement...)}. When no elements are provided, * stepping is not possible and the session itself has no instrumentation overhead. * * @param callback the callback to notify * @param defaultSourceElements a list of source elements, an explicit empty list disables * stepping * @see DebuggerSession * @see SuspendedEvent * @since 0.33 */ public DebuggerSession startSession(SuspendedCallback callback, SourceElement... defaultSourceElements) { DebuggerSession session = new DebuggerSession(this, callback, defaultSourceElements); Breakpoint[] bpts; synchronized (this) { sessions.add(session); bpts = breakpoints.toArray(new Breakpoint[]{}); } for (Breakpoint b : bpts) { session.install(b, true); } session.install(alwaysHaltBreakpoint, true); return session; }
DebuggerSession(Debugger debugger, SuspendedCallback callback, SourceElement... sourceElements) { this.sessionId = SESSIONS.incrementAndGet(); this.debugger = debugger; this.callback = callback; switch (sourceElements.length) { case 0: this.sourceElements = Collections.emptySet(); break; case 1: this.sourceElements = Collections.singleton(sourceElements[0]); break; default: this.sourceElements = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(sourceElements))); break; } this.hasExpressionElement = this.sourceElements.contains(SourceElement.EXPRESSION); if (Debugger.TRACE) { trace("open with callback %s", callback); } addBindings(includeInternal, sourceFilter); executionLifecycle = new DebuggerExecutionLifecycle(debugger); }
/** * Resumes all suspended executions that have not yet been notified. * * @since 0.17 */ public synchronized void resumeAll() { if (Debugger.TRACE) { trace("resume all threads"); } if (closed) { throw new IllegalStateException("session closed"); } clearStrategies(); }
/** * Closes the current debugging session and disposes all installed breakpoints. * * @since 0.17 */ public synchronized void close() { if (Debugger.TRACE) { trace("close session"); } if (closed) { throw new IllegalStateException("session already closed"); } clearStrategies(); removeBindings(); for (Breakpoint breakpoint : this.breakpoints) { breakpoint.sessionClosed(this); } currentSuspendedEventMap.clear(); debugger.disposedSession(this); closed = true; }
if (event != null) { if (Debugger.TRACE) { trace("ignored suspended reason: recursive from source:%s context:%s location:%s", source, source.getContext(), source.getSuspendAnchors()); trace("ignored suspended reason: duplicate from source:%s context:%s location:%s", source, source.getContext(), source.getSuspendAnchors()); List<DebuggerNode> nodes = collectDebuggerNodes(source.getContext(), suspendAnchor); for (DebuggerNode node : nodes) { if (node == source) { SteppingStrategy s = getSteppingStrategy(currentThread); if (suspendNext) { synchronized (this) { setSteppingStrategy(currentThread, s, true); suspendNext = false; s = notifyNewThread(currentThread); for (DebuggerNode node : nodes) { Breakpoint breakpoint = node.getBreakpoint(); if (breakpoint == null || !isBreakpointsActive()) { continue; // not a breakpoint node if (hitStepping || hitBreakpoint) { s.consume(); doSuspend(SuspendedContext.create(source.getContext()), suspendAnchor, frame, inputValuesProvider, returnValue, breaks, breakpointFailures); } else { if (Debugger.TRACE) {
if (event != null) { if (Debugger.TRACE) { trace("ignored suspended reason: recursive from source:%s context:%s location:%s", source, source.getContext(), source.getSuspendAnchors()); trace("ignored suspended reason: duplicate from source:%s context:%s location:%s", source, source.getContext(), source.getSuspendAnchors()); List<DebuggerNode> nodes = collectDebuggerNodes(source, suspendAnchor); for (DebuggerNode node : nodes) { if (node == source) { SteppingStrategy s = getSteppingStrategy(currentThread); if (suspendNext) { synchronized (this) { setSteppingStrategy(currentThread, s, true); suspendNext = false; s = notifyNewThread(currentThread); Object newReturnValue = processBreakpointsAndStep(nodes, s, source, frame, suspendAnchor, inputValuesProvider, returnValue, exception, breakpointFailures, new Supplier<SuspendedContext>() {
private void notifyUnwindCallback(MaterializedFrame frame) { Thread currentThread = Thread.currentThread(); SteppingStrategy s = getSteppingStrategy(currentThread); assert s.step(this, null, null); s.consume(); clearFrame(frame); // Clear the frame that is to be re-entered doSuspend(context, SuspendAnchor.AFTER, caller.frame, null, null, Collections.emptyList(), Collections.emptyMap());
for (DebuggerNode node : nodes) { Breakpoint breakpoint = node.getBreakpoint(); if (breakpoint == null || !isBreakpointsActive(breakpoint.getKind())) { continue; // not a breakpoint node if (hitStepping || hitBreakpoint) { s.consume(); newReturnValue = doSuspend(contextSupplier.get(), suspendAnchor, frame, source, inputValuesProvider, returnValue, exception, breaks, breakpointFailures); } else { if (Debugger.TRACE) { trace("ignored suspended reason: strategy(%s) from source:%s context:%s location:%s", s, source, source.getContext(), source.getSuspendAnchors());
List<DebuggerNode> nodes = collectDebuggerNodes(caller.node, suspendAnchor); for (DebuggerNode node : nodes) { Breakpoint breakpoint = node.getBreakpoint(); if (breakpoint == null || isBreakpointsActive(breakpoint.getKind()) && breakpoint.getCondition() == null) { node.markAsDuplicate(this); Object newReturnValue = processBreakpointsAndStep(nodes, s, source, caller.frame, suspendAnchor, null, returnValue, null, null, new Supplier<SuspendedContext>() { @Override public SuspendedContext get() {
/** * Set a stepping suspension filter. Prepared steps skip code that match this filter. * * @since 0.26 */ public void setSteppingFilter(SuspensionFilter steppingFilter) { this.ignoreLanguageContextInitialization.set(steppingFilter.isIgnoreLanguageContextInitialization()); synchronized (this) { boolean oldIncludeInternal = this.includeInternal; this.includeInternal = steppingFilter.isInternalIncluded(); Predicate<Source> oldSourceFilter = this.sourceFilter; this.sourceFilter = steppingFilter.getSourcePredicate(); if (oldIncludeInternal != this.includeInternal || oldSourceFilter != this.sourceFilter) { removeBindings(); addBindings(this.includeInternal, this.sourceFilter); } } }
/** * Evaluates the given code in the state of the current execution and in the same guest language * as the current language is defined in. Returns a heap value that remains valid even if this * stack frame becomes invalid. * * <p> * This method is not thread-safe and will throw an {@link IllegalStateException} if called on * another thread than it was created with. * * @param code the code to evaluate * @return the return value of the expression * @since 0.17 */ public DebugValue eval(String code) { verifyValidState(false); Object result; try { result = DebuggerSession.evalInContext(event, code, currentFrame); } catch (IOException e) { throw new RuntimeException(e); } return wrapHeapValue(result); }
/** * Permanently prevents this breakpoint from affecting execution. When not * {@link #isModifiable() modifiable}, {@link IllegalStateException} is thrown. * * @since 0.9 */ public synchronized void dispose() { if (!disposed) { setEnabled(false); if (sourceBinding != null) { sourceBinding.dispose(); sourceBinding = null; } for (DebuggerSession session : sessions) { session.disposeBreakpoint(this); } if (debugger != null) { debugger.disposeBreakpoint(this); debugger = null; } disposed = true; } }
this.rootBinding = createBinding(includeInternalCode, sFilter, new ExecutionEventNodeFactory() { @Override public ExecutionEventNode create(EventContext context) { syntaxTags[i] = elementsIterator.next().getTag(); this.syntaxElementsBinding = createBinding(includeInternalCode, sFilter, new ExecutionEventNodeFactory() { @Override public ExecutionEventNode create(EventContext context) { this.callBinding = createBinding(includeInternalCode, sFilter, new ExecutionEventNodeFactory() { @Override public ExecutionEventNode create(EventContext context) {
/** * Closes the current debugging session and disposes all installed breakpoints. * * @since 0.17 */ public synchronized void close() { if (Debugger.TRACE) { trace("close session"); } if (closed) { throw new IllegalStateException("session already closed"); } clearStrategies(); removeBindings(); for (Breakpoint breakpoint : this.breakpoints) { breakpoint.sessionClosed(this); } currentSuspendedEventMap.clear(); allBindings.clear(); debugger.disposedSession(this); closed = true; }
private void notifyUnwindCallback(MaterializedFrame frame, InsertableNode insertableNode) { Thread currentThread = Thread.currentThread(); SteppingStrategy s = getSteppingStrategy(currentThread); s.consume(); clearFrame(((Node) insertableNode).getRootNode(), frame); doSuspend(context, SuspendAnchor.AFTER, caller.frame, insertableNode, null, null, null, Collections.emptyList(), Collections.emptyMap());
/** * Resumes all suspended executions that have not yet been notified. * * @since 0.17 */ public synchronized void resumeAll() { if (Debugger.TRACE) { trace("resume all threads"); } if (closed) { throw new IllegalStateException("session closed"); } clearStrategies(); }
/** * Set a stepping suspension filter. Prepared steps skip code that does not match this filter. * * @since 0.26 */ public void setSteppingFilter(SuspensionFilter steppingFilter) { this.ignoreLanguageContextInitialization.set(steppingFilter.isIgnoreLanguageContextInitialization()); synchronized (this) { boolean oldIncludeInternal = this.includeInternal; this.includeInternal = steppingFilter.isInternalIncluded(); Predicate<Source> oldSourceFilter = this.sourceFilter; this.sourceFilter = steppingFilter.getSourcePredicate(); if (oldIncludeInternal != this.includeInternal || oldSourceFilter != this.sourceFilter) { removeBindings(); addBindings(this.includeInternal, this.sourceFilter); } } }
/** * Evaluates the given code in the state of the current execution and in the same guest language * as the current language is defined in. Returns a heap value that remains valid even if this * stack frame becomes invalid. * * <p> * This method is not thread-safe and will throw an {@link IllegalStateException} if called on * another thread than it was created with. * * @param code the code to evaluate * @return the return value of the expression * @throws DebugException when guest language code throws an exception * @throws IllegalStateException if called on another thread than this frame was created with, * or if {@link #getLanguage() language} of this frame is not * {@link LanguageInfo#isInteractive() interactive}. * @since 0.17 */ public DebugValue eval(String code) throws DebugException { verifyValidState(false); Object result = DebuggerSession.evalInContext(event, code, currentFrame); return wrapHeapValue(result); }
/** * Permanently prevents this breakpoint from affecting execution. When not * {@link #isModifiable() modifiable}, {@link IllegalStateException} is thrown. * * @since 0.9 */ public synchronized void dispose() { if (!disposed) { setEnabled(false); if (sourceBinding != null) { sourceBinding.dispose(); sourceBinding = null; } for (DebuggerSession session : sessions) { session.disposeBreakpoint(this); } if (debugger != null) { debugger.disposeBreakpoint(this); debugger = null; } disposed = true; } }