-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
gh-99360: Avoid exc=None; del exc
in bytecode where unnecessary
#99361
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
base: main
Are you sure you want to change the base?
Conversation
Python/compile.c
Outdated
expand_del_noerror(basicblock *entryblock, int none_oparg) | ||
{ | ||
for (basicblock *b = entryblock; b != NULL; b = b->b_next) { | ||
int room_needed = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function would be simpler if you use insert_instruction(). Is it for optimization that you aren't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was trying to avoid quadratic time, but I suppose that could only happen if one long basicblock had many DELETE_FAST_CHECK
instructions, e.g.
def f(x):
del x; del x; del x; del x; del x
del x; del x; del x; del x; del x
del x; del x; del x; del x; del x
But such code is useless, so I'll try to clean this up.
The DELETE_NOERROR
instructions should typically happen at basicblock boundaries, so I believe there shouldn't be any performance issues there.
Python/compile.c
Outdated
break; | ||
} | ||
b->b_instr[i].i_opcode = del_opcode; | ||
if (insert_instruction(b, i, &(struct instr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we can avoid shifting here:
in compiler_nameop, add a couple of NOPs so that there is space for this expansion. If no expansion happens, the NOPs can be removed by a final remove_redundant_nops().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optimize_cfg removes NOPs already, so we'd have to either introduce another pseudo-opcode or shuffle around assemble()
a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could have a new pseudo instruction called BLANK that is ignored by the assembler (has size 0 and emits nothing).
Is it really worthwhile extending this to global, nonlocal and class-local variables? They will be vanishingly rare. I thought the original idea was to change the code for The peepholer can convert any residual |
I agree that anything other than a local is not worth it, and the PR doesn't change compiler output except when deleting fast locals. I've updated the PR so that it's clearer that there are no changes to those other cases. Adding an extra Over half of the code added is tests and docs. The tests are checking the bytecode for using
The
Assuming this approach, there's a need for the dataflow analysis to turn This PR's solution is to emit It might be fine to move |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure the benefit this brings us is worth the additional complexity.
Is this still being considered for 3.13? Perhaps a future superoptimizer (#102869) could build on our already-existing liveness analysis for fast locals to achieve the same effect...
FWIW now that PEP 709 is merged, I've considered whether the same sub-scope isolation could be used for handling isolation of exception handler variables, instead of using a DELETE_FAST. I think it could, and wouldn't be too complex, and the resulting behavior would be nicer. But it would be a visible behavior change (after an |
Eh, if anything that would be better than what we currently do. It is a bit weird, though. It personally feels like a Discuss thread more than a PEP (unless it's super controversial)... |
The following commit authors need to sign the Contributor License Agreement: |
Functional changes:
DELETE_FAST
now assumes its argument is bound; it no longer raisesUnboundLocalError
by itself.del x
compiles toLOAD_FAST_CHECK x; POP_TOP; DELETE_FAST x
except E as exc: ...
, theexc=None
before thedel exc
is omitted when not needed.
exc=None; del exc
in bytecode where unnecessary #99360