private synchronized void setNextStrategy(SteppingStrategy nextStrategy) { verifyValidState(true); if (this.nextStrategy == null) { this.nextStrategy = nextStrategy; } else if (this.nextStrategy.isKill()) { throw new IllegalStateException("Calls to prepareKill() cannot be followed by any other preparation call."); } else if (this.nextStrategy.isDone()) { throw new IllegalStateException("Calls to prepareContinue() cannot be followed by any other preparation call."); } else if (this.nextStrategy.isComposable()) { this.nextStrategy.add(nextStrategy); } else { this.nextStrategy = SteppingStrategy.createComposed(this.nextStrategy, nextStrategy); } }
@Override void consume() { assert current == last; last.consume(); }
private synchronized SteppingStrategy notifyNewThread(Thread currentThread) { SteppingStrategy s = getSteppingStrategy(currentThread); // double checked locking if (s == null) { if (suspendAll) { // all suspended s = SteppingStrategy.createAlwaysHalt(); } else { // not suspended continue execution for this thread s = SteppingStrategy.createContinue(); } setSteppingStrategy(currentThread, s, true); } assert s != null; return s; }
s = SteppingStrategy.createAlwaysHalt(); setSteppingStrategy(currentThread, s, true); suspendNext = false; boolean hitStepping = s.step(this, source.getContext(), suspendAnchor); boolean hitBreakpoint = breaks != null && !breaks.isEmpty(); if (hitStepping || hitBreakpoint) { s.consume(); doSuspend(SuspendedContext.create(source.getContext()), suspendAnchor, frame, inputValuesProvider, returnValue, breaks, breakpointFailures); } else { if (s.isKill()) { // ComposedStrategy can become kill throw new KillException();
/** * Suspends the current or the next execution on all threads. All new executing threads will * start suspended until {@link #resumeAll()} is called or the session is closed. Will throw an * {@link IllegalStateException} if the session is already closed. */ // TODO make part of public API as soon as PolyglotEngine is thread-safe synchronized void suspendAll() { if (Debugger.TRACE) { trace("suspend all threads"); } if (closed) { throw new IllegalStateException("session closed"); } suspendAll = true; // iterating concurrent hashmap should be save for (Thread t : strategyMap.keySet()) { SteppingStrategy s = strategyMap.get(t); assert s != null; if (s.isDone() || s.isConsumed()) { setSteppingStrategy(t, SteppingStrategy.createAlwaysHalt(), false); } } updateStepping(); }
boolean hitStepping = s.step(this, source.getContext(), suspendAnchor); boolean hitBreakpoint = breaks != null && !breaks.isEmpty(); Object newReturnValue = returnValue; if (hitStepping || hitBreakpoint) { s.consume(); newReturnValue = doSuspend(contextSupplier.get(), suspendAnchor, frame, source, inputValuesProvider, returnValue, exception, breaks, breakpointFailures); if (s.isKill()) { // ComposedStrategy can become kill throw new KillException(source.getContext().getInstrumentedNode());
SteppingStrategy getNextStrategy() { SteppingStrategy strategy = nextStrategy; if (strategy == null) { return SteppingStrategy.createContinue(); } return strategy; }
/** * Suspends the current or the next execution of a given thread. Will throw an * {@link IllegalStateException} if the session is already closed. */ // TODO make part of public API as soon as PolyglotEngine is thread-safe void suspend(Thread t) { if (Debugger.TRACE) { trace("suspend thread %s ", t); } if (closed) { throw new IllegalStateException("session closed"); } setSteppingStrategy(t, SteppingStrategy.createAlwaysHalt(), true); }
/** * Prepare to unwind a frame. This frame and all frames above it are unwound off the execution * stack. The frame needs to be on the {@link #getStackFrames() execution stack of this event}. * * @param frame the frame to unwind * @throws IllegalArgumentException when the frame is not on the execution stack of this event * @since 0.31 */ public void prepareUnwindFrame(DebugStackFrame frame) throws IllegalArgumentException { if (frame.event != this) { throw new IllegalArgumentException("The stack frame is not in the scope of this event."); } setNextStrategy(SteppingStrategy.createUnwind(frame.getDepth())); }
/** * Prepare to terminate the suspended execution represented by this event. One use-case for this * method is to shield an execution of an unknown code with a timeout: * * <p> * This method is thread-safe and the prepared termination is appended to any other previously * prepared modes. No further modes can be prepared after kill. * * @throws IllegalStateException when {@link #prepareContinue() continue} or * {@link #prepareKill() kill} is prepared already. * @since 0.12 */ public void prepareKill() { setNextStrategy(SteppingStrategy.createKill()); }
/** * Prepare to execute in <strong>step out</strong> mode when guest language program execution * resumes. In this mode, the current thread continues until it arrives to an enclosing code * location with one of the enabled {@link StepConfig.Builder#sourceElements(SourceElement...) * source elements} and repeats that process {@link StepConfig.Builder#count(int) step count} * times. See {@link StepConfig} for the details about the stepping behavior. * <p> * This mode persists until the thread resumes and then suspends, at which time the mode reverts * to {@linkplain #prepareContinue() Continue}, or the thread dies. * <p> * A breakpoint set at a location where execution would suspend is treated specially as a single * event, to avoid multiple suspensions at a single location. * <p> * This method is thread-safe and the prepared StepInto mode is appended to any other previously * prepared modes. * * @param stepConfig the step configuration * @return this event instance for an easy concatenation of method calls * @throws IllegalStateException when {@link #prepareContinue() continue} or * {@link #prepareKill() kill} is prepared already, or when the current debugger * session has no source elements enabled for stepping. * @throws IllegalArgumentException when the {@link StepConfig} contains source elements not * enabled for stepping in the current debugger session. * @since 0.33 */ public SuspendedEvent prepareStepOut(StepConfig stepConfig) { verifyConfig(stepConfig); setNextStrategy(SteppingStrategy.createStepOut(session, stepConfig)); return this; }
/** * Prepare to execute in <strong>step into</strong> mode when guest language program execution * resumes. In this mode, the current thread continues until it arrives to a code location with * one of the enabled {@link StepConfig.Builder#sourceElements(SourceElement...) source * elements} and repeats that process {@link StepConfig.Builder#count(int) step count} times. * See {@link StepConfig} for the details about the stepping behavior. * <p> * This mode persists until the thread resumes and then suspends, at which time the mode reverts * to {@linkplain #prepareContinue() Continue}, or the thread dies. * <p> * A breakpoint set at a location where execution would suspend is treated specially as a single * event, to avoid multiple suspensions at a single location. * <p> * This method is thread-safe and the prepared StepInto mode is appended to any other previously * prepared modes. * * @param stepConfig the step configuration * @return this event instance for an easy concatenation of method calls * @throws IllegalStateException when {@link #prepareContinue() continue} or * {@link #prepareKill() kill} is prepared already, or when the current debugger * session has no source elements enabled for stepping. * @throws IllegalArgumentException when the {@link StepConfig} contains source elements not * enabled for stepping in the current debugger session. * @since 0.33 */ public SuspendedEvent prepareStepInto(StepConfig stepConfig) { verifyConfig(stepConfig); setNextStrategy(SteppingStrategy.createStepInto(session, stepConfig)); return this; }
setNextStrategy(SteppingStrategy.createStepOver(session, stepConfig)); return this;
/** * Suspends the current or the next execution on all threads. All new executing threads will * start suspended until {@link #resumeAll()} is called or the session is closed. Will throw an * {@link IllegalStateException} if the session is already closed. */ // TODO make part of public API as soon as PolyglotEngine is thread-safe synchronized void suspendAll() { if (Debugger.TRACE) { trace("suspend all threads"); } if (closed) { throw new IllegalStateException("session closed"); } suspendAll = true; // iterating concurrent hashmap should be save for (Thread t : strategyMap.keySet()) { SteppingStrategy s = strategyMap.get(t); assert s != null; if (s.isDone() || s.isConsumed()) { setSteppingStrategy(t, SteppingStrategy.createAlwaysHalt(), false); } } updateStepping(); }
SteppingStrategy getNextStrategy() { SteppingStrategy strategy = nextStrategy; if (strategy == null) { return SteppingStrategy.createContinue(); } return strategy; }
/** * Suspends the current or the next execution of a given thread. Will throw an * {@link IllegalStateException} if the session is already closed. */ // TODO make part of public API as soon as PolyglotEngine is thread-safe void suspend(Thread t) { if (Debugger.TRACE) { trace("suspend thread %s ", t); } if (closed) { throw new IllegalStateException("session closed"); } setSteppingStrategy(t, SteppingStrategy.createAlwaysHalt(), true); }
/** * Prepare to unwind a frame. This frame and all frames above it are unwound off the execution * stack. The frame needs to be on the {@link #getStackFrames() execution stack of this event}. * * @param frame the frame to unwind * @throws IllegalArgumentException when the frame is not on the execution stack of this event * @since 0.31 */ public void prepareUnwindFrame(DebugStackFrame frame) throws IllegalArgumentException { if (frame.event != this) { throw new IllegalArgumentException("The stack frame is not in the scope of this event."); } setNextStrategy(SteppingStrategy.createUnwind(frame.getDepth())); }
/** * Prepare to terminate the suspended execution represented by this event. One use-case for this * method is to shield an execution of an unknown code with a timeout: * * {@link com.oracle.truffle.tck.ExecWithTimeOut#tckSnippets} * * <p> * This method is thread-safe and the prepared termination is appended to any other previously * prepared modes. No further modes can be prepared after kill. * * @throws IllegalStateException when {@link #prepareContinue() continue} or * {@link #prepareKill() kill} is prepared already. * @since 0.12 */ public void prepareKill() { setNextStrategy(SteppingStrategy.createKill()); }