Description
(Copied from faster-cpython/ideas#665.)
The idea here is to avoid function version cache misses for generator expressions. (See faster-cpython/ideas#664 (comment).)
We have a complicated mechanism to reset the function version whenever __code__
, __defaults__
and a few other critical attributes are mutated. (BTW: nothing is affected by changes to __annotations__
, and yet that is also considered critical; I will fix this.)
Why not instead just reset the function version to zero and stick to that? We then guarantee that the function version is either zero or matches the code object version.
Nothing changes for specialization except that _PyFunction_GetVersionForCurrentState()
returns 0 for mutated functions. This is unlikely to affect any benchmark or other perf-critical real-world code.
The function version cache will double in size, and store both the function and the code object. When a function is deallocated or its version is reset to zero, it evicts itself from the cache, but keeps the code object. Code objects remove themselves from the cache when deallocated (and probably also evict the function object).
For Tier 2, when generating _PUSH_FRAME
or _POP_FRAME
, we can handle the case where the function version maps to a pair (NULL, some_code_object)
-- we store NULL
in the operand, but we use some_code_object
to trace through. Globals removal will no longer work (boo hoo), but at least we still have a trace. Presumably at least some generator expressions don't use globals (they can still use builtins, which can be reached without the function object).