mirror of https://github.com/python/cpython
gh-116916: Remove separate next_func_version counter (#116918)
Somehow we ended up with two separate counter variables tracking "the next function version". Most likely this was a historical accident where an old branch was updated incorrectly. This PR merges the two counters into a single one: `interp->func_state.next_version`.
This commit is contained in:
parent
76d0868907
commit
7e1f38f2de
|
@ -245,7 +245,6 @@ struct _is {
|
||||||
|
|
||||||
uint16_t optimizer_side_threshold;
|
uint16_t optimizer_side_threshold;
|
||||||
|
|
||||||
uint32_t next_func_version;
|
|
||||||
_rare_events rare_events;
|
_rare_events rare_events;
|
||||||
PyDict_WatchCallback builtins_dict_watcher;
|
PyDict_WatchCallback builtins_dict_watcher;
|
||||||
|
|
||||||
|
|
|
@ -415,9 +415,9 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
|
||||||
co->co_ncellvars = ncellvars;
|
co->co_ncellvars = ncellvars;
|
||||||
co->co_nfreevars = nfreevars;
|
co->co_nfreevars = nfreevars;
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
co->co_version = interp->next_func_version;
|
co->co_version = interp->func_state.next_version;
|
||||||
if (interp->next_func_version != 0) {
|
if (interp->func_state.next_version != 0) {
|
||||||
interp->next_func_version++;
|
interp->func_state.next_version++;
|
||||||
}
|
}
|
||||||
co->_co_monitoring = NULL;
|
co->_co_monitoring = NULL;
|
||||||
co->_co_instrumentation_version = 0;
|
co->_co_instrumentation_version = 0;
|
||||||
|
|
|
@ -236,8 +236,9 @@ How does a function's `func_version` field get initialized?
|
||||||
- A new version is allocated by `_PyFunction_GetVersionForCurrentState`
|
- A new version is allocated by `_PyFunction_GetVersionForCurrentState`
|
||||||
when the specializer needs a version and the version is 0.
|
when the specializer needs a version and the version is 0.
|
||||||
|
|
||||||
The latter allocates versions using a counter in the interpreter state;
|
The latter allocates versions using a counter in the interpreter state,
|
||||||
when the counter wraps around to 0, no more versions are allocated.
|
`interp->func_state.next_version`.
|
||||||
|
When the counter wraps around to 0, no more versions are allocated.
|
||||||
There is one other special case: functions with a non-standard
|
There is one other special case: functions with a non-standard
|
||||||
`vectorcall` field are not given a version.
|
`vectorcall` field are not given a version.
|
||||||
|
|
||||||
|
@ -247,8 +248,7 @@ Code object versions
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
So where to code objects get their `co_version`?
|
So where to code objects get their `co_version`?
|
||||||
There is a per-interpreter counter, `next_func_version`.
|
They share the same counter, `interp->func_state.next_version`.
|
||||||
This is initialized to 1 when the interpreter is created.
|
|
||||||
|
|
||||||
Code objects get a new `co_version` allocated from this counter upon
|
Code objects get a new `co_version` allocated from this counter upon
|
||||||
creation. Since code objects are nominally immutable, `co_version` can
|
creation. Since code objects are nominally immutable, `co_version` can
|
||||||
|
|
|
@ -630,7 +630,6 @@ init_interpreter(PyInterpreterState *interp,
|
||||||
interp->sys_profile_initialized = false;
|
interp->sys_profile_initialized = false;
|
||||||
interp->sys_trace_initialized = false;
|
interp->sys_trace_initialized = false;
|
||||||
(void)_Py_SetOptimizer(interp, NULL);
|
(void)_Py_SetOptimizer(interp, NULL);
|
||||||
interp->next_func_version = 1;
|
|
||||||
interp->executor_list_head = NULL;
|
interp->executor_list_head = NULL;
|
||||||
if (interp != &runtime->_main_interpreter) {
|
if (interp != &runtime->_main_interpreter) {
|
||||||
/* Fix the self-referential, statically initialized fields. */
|
/* Fix the self-referential, statically initialized fields. */
|
||||||
|
|
Loading…
Reference in New Issue