Skip to content
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

Implement finish (step-out) operation in debugger. #618

Merged
merged 1 commit into from
Apr 8, 2020

Conversation

zherczeg
Copy link
Contributor

@zherczeg zherczeg commented Apr 7, 2020

#617 should land first.

The finish operation requires to find the ExecutionState of the current function. The best idea I have is getting the FunctionEnvironment of the current state, and check its parent states until I find a different FunctionEnvironment. It works with try-catch and with, but does not work with eval, i.e. the debugger does not just exit from eval, but it also exits from the function called the eval. However this can be considered correct depending on how you want to handle this case.

Anyway if you have a better suggestion for this operation, please let me know.

@zherczeg zherczeg force-pushed the implement_finish branch 2 times, most recently from ed2045c to e4f633e Compare April 7, 2020 12:31
@ksh8281
Copy link
Contributor

ksh8281 commented Apr 8, 2020

Can I have a question?
What happened if there is yield or await while stepping out?

Comment on lines 159 to 161
if (record->isDeclarativeEnvironmentRecord()) {
DeclarativeEnvironmentRecord* declarativeRecord = record->asDeclarativeEnvironmentRecord();
if (declarativeRecord->isFunctionEnvironmentRecord()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These if conditional statements could be merged into one statement.

@clover2123
Copy link
Contributor

BTW is it possible to put a breakpoint inside eval code except function invoked during eval execution?

@zherczeg
Copy link
Contributor Author

zherczeg commented Apr 8, 2020

When you are in the eval code (after parsing), you can put breakpoints in there because they are regular functions (they have their own source code and byte code). However the IDE part is not simple for that, because the name of eval code is the same and any number of evals can be executed. If the IDE opens a separate editor for each eval code, it can insert single breakpoints for them. E.g.:

arr = []
for (var i = 0; i < 20; i++)
  arr.push(eval("(function() { return i })"))
for (var i = 0; i < 20; i++)
  arr[i]();

This code creates twenty different functions with the same source code. Each has their own byte code and source code, so the IDE can set separate breakpoints for each of them (the IDE can open twenty editor tabs, but these editors are not backed by real files). Opening hundreds of tabs for the user can be difficult to understand, but that is another story.

Is this what you wanted to know?

Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
@zherczeg
Copy link
Contributor Author

zherczeg commented Apr 8, 2020

Regarding yield / async the debugger should stop after the next instruction (similar to return) unless you prefer something different. There was an unhandled code path which prevented it, but I fixed it (and a new test is added).

@ksh8281
Copy link
Contributor

ksh8281 commented Apr 8, 2020

Sounds cool!

Copy link
Contributor

@ksh8281 ksh8281 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines +11 to +15
Stopped at tools/debugger/tests/do_finish.js:38
(escargot-debugger) b do_finish.js:41
Breakpoint 2 at tools/debugger/tests/do_finish.js:41 (in gen() at line:40, col:1)
(escargot-debugger) f
Stopped at breakpoint:2 tools/debugger/tests/do_finish.js:41 (in gen() at line:40, col:1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have one more question.
For the above case, when "finish" is executed on the global code debugger runs the program until the next breakpoint encountered inside gen() instead of finishing the program.
But from the description, "finish" is defined as follow.

finish : Continue running until just after function in the selected stack frame returns.

I'm wondering what is the correct operation when another breakpoint is met during the execution of "finish" command. Should we stop at the breakpoint or ignore it?

Copy link
Contributor Author

@zherczeg zherczeg Apr 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my experience breakpoints always takes priority over anything. So if a breakpoint is encountered the execution stops regardless of the last command.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: we can do this differently of course, but this is my experience with debuggers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your answer makes everything clear! Thanks.

Copy link
Contributor

@clover2123 clover2123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@clover2123 clover2123 merged commit 9f347d9 into Samsung:master Apr 8, 2020
@zherczeg zherczeg deleted the implement_finish branch April 8, 2020 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants