-
Notifications
You must be signed in to change notification settings - Fork 14
[New Feature] Adding a JumpToCaret command to move the caret back and forth in the debugger suspended context without executing anything in between #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
StevenCostiou
merged 25 commits into
pharo-spec:master
from
adri09070:30-Request-We-should-have-a-command-to-move-the-cursor-back-and-forth-in-the-debugger-without-executing-anything
Feb 6, 2023
Merged
[New Feature] Adding a JumpToCaret command to move the caret back and forth in the debugger suspended context without executing anything in between #56
StevenCostiou
merged 25 commits into
pharo-spec:master
from
adri09070:30-Request-We-should-have-a-command-to-move-the-cursor-back-and-forth-in-the-debugger-without-executing-anything
Feb 6, 2023
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
… checking that the receiver and arguments are pushed on the stack and that nothing is executed
…arguments is pushed on the stack (without executing any instruction)
…e to go to a pc associated to a method or sequence node that are not (necessarily) contained in a statement
…a variable node that has (or doesn't have) an associated pc + making moveToNode: work if the aimed node is a method node that has an assicuated pc
… no associated pc
… session's interrupted context
…ossibility to modify interrupted context in debug session
…ck, instead of going back to where we were before jumping inside a block
Member
|
Adrien, I would merge it. |
…e-the-cursor-back-and-forth-in-the-debugger-without-executing-anything
Collaborator
Author
|
Ok, it's fixed. If you merge it, I think there will be conflicts with the other PR that uses double dispatch instead of ifs to skip nodes |
Collaborator
Author
|
The error is not related. The Pharo CI is completely broken at the moment |
…e-the-cursor-back-and-forth-in-the-debugger-without-executing-anything
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #30.
Needs #53 and #54 to be merged first.
This PR introduces a new JumpToCaret command that allows to move the program execution to the first PC associated to the specific AST node associated to where the caret has been placed.
The command itself can be accessed via the advanced steps menu in the debugger toolbar:
You should put your caret somewhere in the code before using this command, otherwise it will go back to the beginning of the method (even before the creation of temporaries).
Tutorial: What you can do with JumpToCaret
In the screnshot below,
ais equal to 1 and we jump to caret that is on thea * 42message node:After jumping to caret, the next instruction that will be executed is the
a * 42message node. You can also see thatais still equal to 1 as the assignmenta := a +2has been skipped:In the screenshot below, we put our caret inside the ifFalse: block:
After jumping to caret, we have entered the ifFalse: block and
ais still nil, as the assignmenta := truehas been skipped.Then, you can enter the ifTrue: block if you want too:
In this screenshot below,
ais equal to 1, and we want to jump to caret on the message nodea + 2:After jumping to caret, as you'd expect, the next instruction that will be executed is the message node:
If you step twice, the message node
a + 2and the assignment nodea := a +2will be executed andawill be equal to 3:Now, what you can do with jumpToCaret and that you can't do with skipUpTo is jumping back to caret on the
a + 2message node:Then you can step twice again to execute the message node and the assignment node and
awill be equal to 5:So, jumpToCaret is very useful if you want to see and debug what happens when a piece of code is executed several times.
In the screenshot below,
ais equal to 1 and the next instruction that will be executed is the message nodea + 2, whose receiver value 1 has already been pushed on the stack:If we move to caret, inside the block, on the
a + 1message node, then, as you'd expect, the next instruction that will be executed is thea + 1message node inside the block. However, as the block is not inlined, a context has been created for it and it has become the suspended context:Now, stepping twice will execute the
a + 1message node and thea := a + 1assignment node AND the block return. So the result of the block is put on the stack. After exiting the block context via these steps, you go back in the parent context right after the block creation:You should be really careful when exiting a block via steps if you have entered this block via the jumpToCaret command, as the result of the block is pushed on the stack and becomes the argument of the next bytecode that should be executed (as its real argument had already been pushed on the stack before jumping to caret). If this is not intended, you should reexecute the jumpToCaret command to jump to where you are in order to clean the stack:
After jumping to caret, the stack has been cleaned (stackTop is not 2 that was the result of the block anymore).
Note that you can enter embedded blocks. In this case, as many contexts as there are embedding levels are created:
So, jumpToCaret is useful to see and debug what happens when a block that is never evaluated is actually evaluated.
In the screenshot below, we have entered an embedded block thanks to the
jumpToCaretcommand and the next instruction that is going to be executed is thea + 1message node:After jumping to caret outside the block, on the
a + 2message node, then as this message node is in the home context method node, all contexts above the suspended context are discarded and, as you'd expect, the next instruction that is going to be executed is thea + 2message node:Note that if the aimed node was outside the suspended context block node, but inside another context (let's call it C) block node whose context is between the suspended context and its home context, then only the contexts above the context C are discarded:
So, jumpToCaret is useful to exit non-inlined blocks, in order to go back to a context between its sender context and its home context, without executing the rest of the block closure.
Except when the return node is in a non-inlined block (non-local return) as jumping outside non-inlined block discards the entire context, it is not possible to jump over a return bytecode.
This is a problem inherited from skipUpTo, as we didn't allow skipUpTo to skip return bytecodes because a context needs to return something.
Of course, you will never see any code after a return node that is not in a block because Pharo does not allow to write unreachable code (except in DoIts and unreachable code after ifTrue: ifFalse: blocks that contain returns , but we don't take these cases into account, as anyway this code is never executed normally).
However, this can become a problem in the case below:
Here, we want to jump to caret on the
a := 3assignment node, after an ifFalse: ifTrue: message. However, jumping to caret does not stop on the assignment but it stops on the return node in theifTrue:block because it has a return node and this block is inlined in the method bytecode, before the aimed node:The bug also appears with skipUpTo and this is a problem as the assignment
a := 3is reachable so this should be possible to jump to it.Here, it is possible to go there without executing anything by:
° jump to caret at the end of the ifFalse: block :
° skipping the last instruction of the ifFalse: block that doesn't return:
° stepping over (that keeps the program state as it is. Here, it just jumps after the ifTrue: block as it considers that the ifFalse: block has been executed):
However this is really tedious and we have to think about a way to make it work. Furthermore, there are some cases for which no easy workaround exists. In the screenshot below, we want to enter the inlined ifTrue: block in the ifTrue:ifFalse: message:
After jumping to caret, we stop on the return node in the inlined ifFalse: block because it is before the inlined ifTrue: block:
Implementation notes:
moveToNode:to jump to the aimed node in the new context.Known related issues: