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

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

Open
Tracked by #122548
markshannon opened this issue Jan 6, 2025 · 1 comment
Open
Tracked by #122548

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

markshannon opened this issue Jan 6, 2025 · 1 comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement

Comments

@markshannon
Copy link
Member

markshannon commented Jan 6, 2025

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.

@markshannon
Copy link
Member Author

markshannon commented Jan 6, 2025

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.

@picnixz picnixz added type-feature A feature request or enhancement interpreter-core (Objects, Python, Grammar, and Parser dirs) labels Jan 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

2 participants