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

ZSTEP OVER and ZSTEP OUTOF work correctly across extrinsic function returns using QUIT @ syntax #141

Closed
nars1 opened this issue Jan 29, 2018 · 0 comments
Assignees
Milestone

Comments

@nars1
Copy link
Collaborator

nars1 commented Jan 29, 2018

Final Release Note

ZSTEP OVER and ZSTEP OUTOF work correctly across extrinsic function calls which return using the QUIT @ syntax. Previously, the ZSTEP would not pause (and execute the ZSTEP action) after the return from such function calls. (YDB#141)

Description

Below is an example that illustrates the ZSTEP OVER issue.

> cat zstover1.m
        do ^zstepover
        set x1=$$y
        quit
y()
        set x2=""
        quit x2

> cat zstepover.m
        set $zstep="write:$x ! write $zpos,?30,"":"" zprint @$zpos zstep  "
        zb +3:"zstep into"
        write !,"Stepping STARTED",!

First a case that works (without the @ usage).

> mumps -run zstover1

Stepping STARTED
+2^zstover1                   : set x1=$$y
+3^zstover1                   : quit

$ZSTEP is defined to print each M line as it gets executed (starting from +2^zstover1). The line "set x1=$$y" does get printed. And since this is a ZSTEP OVER usage, lines executed inside the $$y call do not get printed but the M line executed after returning from $$y does get printed (+3^zstover1). This is the correct behavior.

But if the above example is slightly modified so the quit (at y+2^zstover1) is replaced with a quit @ syntax, things no longer work. Below is the revised example.

> cat zstover2.m
        do ^zstepover
        set x1=$$y
        quit
y()
        set xx="x2",x2=""
        quit @xx

> mumps -run zstover2

Stepping STARTED
+2^zstover2                   : set x1=$$y

Notice the missing +3^zstover2 line.

And below is an example that illustrates a similar issue with ZSTEP OUTOF.

> cat zstoutof1.m
x       ;
        set x1=$$helper
        quit

helper();
        do ^zstepoutof
        set x2=$$y
        quit x2

y()
        set xx="x3",x3=""
        quit @xx

> cat zstepoutof.m
        set $zstep="write:$x ! write $zpos,?30,"":"" zprint @$zpos zstep outof"
        zb +3:"zstep into"
        write !,"Stepping STARTED",!

> cat zstoutof2.m
x       ;
        set x1=$$helper
        quit

helper();
        do ^zstepoutof
        set x2=$$y
        set xx="x2"
        quit @xx

y()
        set xx="x3",x3=""
        quit @xx

> mumps -run zstoutof1

Stepping STARTED
helper+2^zstoutof1            : set x2=$$y
x+2^zstoutof1                 : quit

> mumps -run zstoutof2

Stepping STARTED
helper+2^zstoutof2            : set x2=$$y

zstoutof2 does not work correctly (does not display x+2^zstoutof2) like zstoutof1 does.

Draft Release Note

ZSTEP OVER and ZSTEP OUTOF work correctly even across extrinsic function calls which return using the QUIT @ syntax. Previously, the ZSTEP would not pause (and execute the ZSTEP action) after the return from such function calls.

@nars1 nars1 added this to the r120 milestone Jan 29, 2018
@nars1 nars1 self-assigned this Jan 29, 2018
nars1 added a commit to nars1/YottaDB that referenced this issue Jan 29, 2018
…function returns using QUIT @ syntax

ZSTEP OVER operates (in op_zstep.c) by noting down the current $zlevel in the global variable
"zstep_level" and changing the transfer table so "opp_zst_over_retarg" is invoked instead of
"op_retarg" but otherwise leaves the transfer table untouched so op_linestart etc. are still
executed as normal as long as nested levels of M frames are invoked. If the nested level
invocation is an extrinsic function (that returns a value) "opp_zst_over_retarg" is invoked as
part of returning from that level. "opp_zst_over_retarg" (in op_bkpt.s) checks if "zstep_level"
is the same as frame_pointer->old_frame_pointer and if so, it calls "op_zstepret" to fix the
transfer table so "op_zst_st_over" is invoked instead of "op_linestart" (and so on). That is,
the ZSTEP action which was hidden during nested levels of invocations becomes active the moment
the return from nested level occurs. This check did not take into account that in case of a
QUIT @ usage, due to the indirection usage, there is an extra nested uncounted frame that is
where the OC_RETARG opcode happens. So "opp_zst_over_retarg" gets invoked while the global
variable "frame_pointer" is 2 levels deeper than "zstep_level" but one of those 2 levels
is an uncounted frame. In this case the "frame_pointer->old_frame_pointer == zstep_level"
check in "opp_zst_over_retarg" incorrectly decided it was not yet time to make the ZSTEP
action active. This is now fixed by invoking a C helper function "op_zst_over_retarg_helper"
which takes these uncounted frames into account and ensures (by adjusting "zstep_level") that
"opp_zst_over_retarg" does the right thing even in this case.

A similar issue with ZSTEP OUTOF which now has "op_zstepretarg_helper" ensuring "opp_zstepretarg"
does the right thing.

Since assembly modules are involved, the fix is needed separately for the x86_64 and armv7l
architectures. But the more complicated part of the fix (traversing the frame_pointer linked
list and checking for counted frames) was done in C helper functions to minimize assembly changes.
nars1 added a commit to nars1/YottaDB that referenced this issue Jan 29, 2018
…function returns using QUIT @ syntax

ZSTEP OVER operates (in op_zstep.c) by noting down the current $zlevel in the global variable
"zstep_level" and changing the transfer table so "opp_zst_over_retarg" is invoked instead of
"op_retarg" but otherwise leaves the transfer table untouched so op_linestart etc. are still
executed as normal as long as nested levels of M frames are invoked. If the nested level
invocation is an extrinsic function (that returns a value) "opp_zst_over_retarg" is invoked as
part of returning from that level. "opp_zst_over_retarg" (in op_bkpt.s) checks if "zstep_level"
is the same as frame_pointer->old_frame_pointer and if so, it calls "op_zstepret" to fix the
transfer table so "op_zst_st_over" is invoked instead of "op_linestart" (and so on). That is,
the ZSTEP action which was hidden during nested levels of invocations becomes active the moment
the return from nested level occurs. This check did not take into account that in case of a
QUIT @ usage, due to the indirection usage, there is an extra nested uncounted frame that is
where the OC_RETARG opcode happens. So "opp_zst_over_retarg" gets invoked while the global
variable "frame_pointer" is 2 levels deeper than "zstep_level" but one of those 2 levels
is an uncounted frame. In this case the "frame_pointer->old_frame_pointer == zstep_level"
check in "opp_zst_over_retarg" incorrectly decided it was not yet time to make the ZSTEP
action active. This is now fixed by invoking a C helper function "op_zst_over_retarg_helper"
which takes these uncounted frames into account and ensures (by adjusting "zstep_level") that
"opp_zst_over_retarg" does the right thing even in this case.

A similar issue with ZSTEP OUTOF which now has "op_zstepretarg_helper" ensuring "opp_zstepretarg"
does the right thing.

Since assembly modules are involved, the fix is needed separately for the x86_64 and armv7l
architectures. But the more complicated part of the fix (traversing the frame_pointer linked
list and checking for counted frames) was done in C helper functions to minimize assembly changes.
nars1 added a commit to nars1/YottaDBtest that referenced this issue Jan 29, 2018
nars1 added a commit that referenced this issue Jan 29, 2018
…n returns using QUIT @ syntax

ZSTEP OVER operates (in op_zstep.c) by noting down the current $zlevel in the global variable
"zstep_level" and changing the transfer table so "opp_zst_over_retarg" is invoked instead of
"op_retarg" but otherwise leaves the transfer table untouched so op_linestart etc. are still
executed as normal as long as nested levels of M frames are invoked. If the nested level
invocation is an extrinsic function (that returns a value) "opp_zst_over_retarg" is invoked as
part of returning from that level. "opp_zst_over_retarg" (in op_bkpt.s) checks if "zstep_level"
is the same as frame_pointer->old_frame_pointer and if so, it calls "op_zstepret" to fix the
transfer table so "op_zst_st_over" is invoked instead of "op_linestart" (and so on). That is,
the ZSTEP action which was hidden during nested levels of invocations becomes active the moment
the return from nested level occurs. This check did not take into account that in case of a
QUIT @ usage, due to the indirection usage, there is an extra nested uncounted frame that is
where the OC_RETARG opcode happens. So "opp_zst_over_retarg" gets invoked while the global
variable "frame_pointer" is 2 levels deeper than "zstep_level" but one of those 2 levels
is an uncounted frame. In this case the "frame_pointer->old_frame_pointer == zstep_level"
check in "opp_zst_over_retarg" incorrectly decided it was not yet time to make the ZSTEP
action active. This is now fixed by invoking a C helper function "op_zst_over_retarg_helper"
which takes these uncounted frames into account and ensures (by adjusting "zstep_level") that
"opp_zst_over_retarg" does the right thing even in this case.

A similar issue with ZSTEP OUTOF which now has "op_zstepretarg_helper" ensuring "opp_zstepretarg"
does the right thing.

Since assembly modules are involved, the fix is needed separately for the x86_64 and armv7l
architectures. But the more complicated part of the fix (traversing the frame_pointer linked
list and checking for counted frames) was done in C helper functions to minimize assembly changes.
nars1 added a commit to YottaDB/YDBTest that referenced this issue Jan 29, 2018
@nars1 nars1 closed this as completed Jan 29, 2018
@ksbhaskar ksbhaskar changed the title ZSTEP OVER and ZSTEP OUTOF do not work if an extrinsic function returns using QUIT @ syntax ZSTEP OVER and ZSTEP OUTOF work correctly across extrinsic function returns using QUIT @ syntax Mar 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant