Skip to content
  • Rodrigo Mesquita's avatar
    e7e021fa
    debugger: Allow BRK_FUNs to head case continuation BCOs · e7e021fa
    Rodrigo Mesquita authored and Marge Bot's avatar Marge Bot committed
    When we start executing a BCO, we may want to yield to the scheduler:
    this may be triggered by a heap/stack check, context switch, or a
    breakpoint. To yield, we need to put the stack in a state such that
    when execution is resumed we are back to where we yielded from.
    
    Previously, a BKR_FUN could only head a function BCO because we only
    knew how to construct a valid stack for yielding from one -- simply add
    `apply_interp_info` + the BCO to resume executing. This is valid because
    the stack at the start of run_BCO is headed by that BCO's arguments.
    
    However, in case continuation BCOs (as per Note [Case continuation BCOs]),
    we couldn't easily reconstruct a valid stack that could be resumed
    because we dropped too soon the stack frames regarding the value
    returned (stg_ret) and received (stg_ctoi) by that continuation.
    This is especially tricky because of the variable type and size return
    frames (e.g. pointer ret_p/ctoi_R1p vs a tuple ret_t/ctoi_t2).
    
    The trick to being able to yield from a BRK_FUN at the start of a case
    cont BCO is to stop removing the ret frame headers eagerly and instead
    keep them until the BCO starts executing. The new layout at the start of
    a case cont. BCO is described by the new Note [Stack layout when entering run_BCO].
    
    Now, we keep the ret_* and ctoi_* frames when entering run_BCO.
    A BRK_FUN is then executed if found, and the stack is yielded as-is with
    the preserved ret and ctoi frames.
    Then, a case cont BCO's instructions always SLIDE off the headers of the
    ret and ctoi frames, in StgToByteCode.doCase, turning a stack like
    
       |     ....      |
       +---------------+
       |     fv2       |
       +---------------+
       |     fv1       |
       +---------------+
       |     BCO       |
       +---------------+
       | stg_ctoi_ret_ |
       +---------------+
       |    retval     |
       +---------------+
       | stg_ret_..... |
       +---------------+
    
    into
    
       |     ....      |
       +---------------+
       |     fv2       |
       +---------------+
       |     fv1       |
       +---------------+
       |    retval     |
       +---------------+
    
    for the remainder of the BCO.
    
    Moreover, this more uniform approach of keeping the ret and ctoi frames
    means we need less ad-hoc logic concerning the variable size of
    ret_tuple vs ret_p/np frames in the code generator and interpreter:
    Always keep the return to cont. stack intact at the start of run_BCO,
    and the statically generated instructions will take care of adjusting
    it.
    
    Unlocks BRK_FUNs at the start of case cont. BCOs which will enable a
    better user-facing step-out (#26042) which is free of the bugs the
    current BRK_ALTS implementation suffers from (namely, using BRK_FUN
    rather than BRK_ALTS in a case cont. means we'll never accidentally end
    up in a breakpoint "deeper" than the continuation, because we stop at
    the case cont itself rather than on the first breakpoint we evaluate
    after it).
    e7e021fa
    debugger: Allow BRK_FUNs to head case continuation BCOs
    Rodrigo Mesquita authored and Marge Bot's avatar Marge Bot committed
    When we start executing a BCO, we may want to yield to the scheduler:
    this may be triggered by a heap/stack check, context switch, or a
    breakpoint. To yield, we need to put the stack in a state such that
    when execution is resumed we are back to where we yielded from.
    
    Previously, a BKR_FUN could only head a function BCO because we only
    knew how to construct a valid stack for yielding from one -- simply add
    `apply_interp_info` + the BCO to resume executing. This is valid because
    the stack at the start of run_BCO is headed by that BCO's arguments.
    
    However, in case continuation BCOs (as per Note [Case continuation BCOs]),
    we couldn't easily reconstruct a valid stack that could be resumed
    because we dropped too soon the stack frames regarding the value
    returned (stg_ret) and received (stg_ctoi) by that continuation.
    This is especially tricky because of the variable type and size return
    frames (e.g. pointer ret_p/ctoi_R1p vs a tuple ret_t/ctoi_t2).
    
    The trick to being able to yield from a BRK_FUN at the start of a case
    cont BCO is to stop removing the ret frame headers eagerly and instead
    keep them until the BCO starts executing. The new layout at the start of
    a case cont. BCO is described by the new Note [Stack layout when entering run_BCO].
    
    Now, we keep the ret_* and ctoi_* frames when entering run_BCO.
    A BRK_FUN is then executed if found, and the stack is yielded as-is with
    the preserved ret and ctoi frames.
    Then, a case cont BCO's instructions always SLIDE off the headers of the
    ret and ctoi frames, in StgToByteCode.doCase, turning a stack like
    
       |     ....      |
       +---------------+
       |     fv2       |
       +---------------+
       |     fv1       |
       +---------------+
       |     BCO       |
       +---------------+
       | stg_ctoi_ret_ |
       +---------------+
       |    retval     |
       +---------------+
       | stg_ret_..... |
       +---------------+
    
    into
    
       |     ....      |
       +---------------+
       |     fv2       |
       +---------------+
       |     fv1       |
       +---------------+
       |    retval     |
       +---------------+
    
    for the remainder of the BCO.
    
    Moreover, this more uniform approach of keeping the ret and ctoi frames
    means we need less ad-hoc logic concerning the variable size of
    ret_tuple vs ret_p/np frames in the code generator and interpreter:
    Always keep the return to cont. stack intact at the start of run_BCO,
    and the statically generated instructions will take care of adjusting
    it.
    
    Unlocks BRK_FUNs at the start of case cont. BCOs which will enable a
    better user-facing step-out (#26042) which is free of the bugs the
    current BRK_ALTS implementation suffers from (namely, using BRK_FUN
    rather than BRK_ALTS in a case cont. means we'll never accidentally end
    up in a breakpoint "deeper" than the continuation, because we stop at
    the case cont itself rather than on the first breakpoint we evaluate
    after it).
Loading