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

GH-128534: Fix behavior of branch monitoring for async for #130847

Merged
merged 10 commits into from
Mar 7, 2025

Conversation

markshannon
Copy link
Member

@markshannon markshannon commented Mar 4, 2025

This PR:

  • Makes sure that both the "left" and "right" branches have a common source
  • Adds the branches to co_branches.

@@ -0,0 +1,2 @@
Ensure that both and left branches have same source for ``async for`` loops.
Copy link
Member

Choose a reason for hiding this comment

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

grammar

@@ -632,6 +632,10 @@ makecode(_PyCompile_CodeUnitMetadata *umd, struct assembler *a, PyObject *const_
return co;
}


// The offset (in code units) of the END_SEND from the SEND in the `yield from` sequence.
#define END_SEND_OFFSET 5
Copy link
Member

Choose a reason for hiding this comment

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

What is this 5? Is it related to the size of the RESUME and JUMP instructions between the YIELD and END_SEND?

Copy link
Member Author

@markshannon markshannon Mar 6, 2025

Choose a reason for hiding this comment

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

It's the distance from the SEND to the END_SEND in the instructions code units in the yield from/await sequence

Copy link
Member

Choose a reason for hiding this comment

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

Can we assert that the instruction at that distance is a SEND?

@@ -670,7 +674,11 @@ resolve_jump_offsets(instr_sequence *instrs)
if (OPCODE_HAS_JUMP(instr->i_opcode)) {
instruction *target = &instrs->s_instrs[instr->i_target];
instr->i_oparg = target->i_offset;
if (instr->i_oparg < offset) {
if (instr->i_opcode == END_ASYNC_FOR) {
// Monitoring needs the target to be the END_SEND
Copy link
Member

Choose a reason for hiding this comment

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

I think this comment can be made clearer. We are not setting the target here, so I think what the comment is saying is "since the target is the end_send, we set the offset differently in this case". Right?

@@ -849,7 +849,7 @@ calculate_stackdepth(cfg_builder *g)
goto error;
}
maxdepth = Py_MAX(maxdepth, depth + effects.max);
if (HAS_TARGET(instr->i_opcode)) {
if (HAS_TARGET(instr->i_opcode) && instr->i_opcode != END_ASYNC_FOR) {
Copy link
Member

Choose a reason for hiding this comment

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

Are you skipping END_ASYNC_FOR here because its target is not instr->i_target? Apart from that the assertion should hold.

Copy link
Member Author

Choose a reason for hiding this comment

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

Its skipped because there is no flow control edge from the END_ASYNC_FOR to its "target". The "target" is where the control flow comes from, which makes sense for co_branches but not otherwise.

@markshannon markshannon merged commit 89df62c into python:main Mar 7, 2025
66 of 67 checks passed
@markshannon markshannon deleted the co-branch-async-for branch March 7, 2025 14:30
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.

2 participants