Skip to content

Find a way to handle branch events in async for #128534

Description

@markshannon

When instrumenting regular for loops, we instrument the FOR_ITER instruction as the LEFT branch and the POP_ITER instruction as the RIGHT branch.

This doesn't work for async for as it uses exceptions to exit the loop.
Raising an exception is the documented behavior for exiting a [async] generator, so we will still need to generate an event for the exception being raised, much as we do in INSTRUMENTED_END_FOR as well as the BRANCH events.

Linked PRs

Activity

  1. markshannon commented on Jan 6, 2025

    @markshannon
    MemberAuthor

    The bytecode for

    async def foo(x):
        async for y in x:
            A

    is

       1            RETURN_GENERATOR
                    POP_TOP
            L1:     RESUME                   0
    
       2            LOAD_FAST                0 (x)
                    GET_AITER
            L2:     GET_ANEXT
                    LOAD_CONST               0 (None)
            L3:     SEND                     3 (to L6)
            L4:     YIELD_VALUE              1
            L5:     RESUME                   3
                    JUMP_BACKWARD_NO_INTERRUPT 5 (to L3)
            L6:     END_SEND
            L7:     STORE_FAST               1 (y)
    
       3            LOAD_GLOBAL              0 (A)
                    POP_TOP
                    JUMP_BACKWARD           17 (to L2)
    
       2    L8:     CLEANUP_THROW
            L9:     JUMP_BACKWARD_NO_INTERRUPT 12 (to L6)
           L10:     END_ASYNC_FOR
                    LOAD_CONST               0 (None)
                    RETURN_VALUE
    
      --   L11:     CALL_INTRINSIC_1         3 (INTRINSIC_STOPITERATION_ERROR)
                    RERAISE                  1
    ExceptionTable:
      L1 to L2 -> L11 [0] lasti
      L2 to L4 -> L10 [1]
      L4 to L5 -> L8 [3]
      L5 to L7 -> L10 [1]
      L7 to L8 -> L11 [0] lasti
      L8 to L9 -> L10 [1]
      L10 to L11 -> L11 [0] lasti
    

    One way to instrument this would be to add a NOT_TAKEN after the END_SEND or instrument the END_SEND for the LEFT branch, For the RIGHT branch we could instrument END_ASYNC_FOR.
    This shouldn't prevent future specialization of async for as that would require splitting END_ASYNC_FOR into two instructions. We would then instrument the second.

  2. added
    type-featureA feature request or enhancement
    interpreter-core(Objects, Python, Grammar, and Parser dirs)
    on Jan 6, 2025
  3. added a commit that references this issue on Feb 27, 2025
  4. markshannon commented on Mar 3, 2025

    @markshannon
    MemberAuthor

    We still need to add these new branches to co_branches()

  5. added a commit that references this issue on Mar 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions