Skip to content

Commit b408b2b

Browse files
committed
Cache borrowed references, cleared in func_dealloc
1 parent ece96f4 commit b408b2b

File tree

5 files changed

+23
-30
lines changed

5 files changed

+23
-30
lines changed

Include/internal/pycore_function.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ extern PyObject* _PyFunction_Vectorcall(
1919
#define FUNC_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */
2020
struct _py_func_state {
2121
uint32_t next_version;
22-
// Function objects whose func_version % FUNC_VERSION_CACHE_SIZE
23-
// once equaled the index in the table. The references are owned:
24-
// Call _PyFunction_ClearByVersionCache() to clear.
22+
// Borrowed references to function objects whose
23+
// func_version % FUNC_VERSION_CACHE_SIZE
24+
// once was equal to the index in the table.
25+
// They are cleared when the function is deallocated.
2526
PyFunctionObject *func_version_cache[FUNC_VERSION_CACHE_SIZE];
2627
};
2728

@@ -30,7 +31,6 @@ extern PyFunctionObject* _PyFunction_FromConstructor(PyFrameConstructor *constr)
3031
extern uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);
3132
extern void _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version);
3233
PyFunctionObject *_PyFunction_LookupByVersion(uint32_t version);
33-
void _PyFunction_ClearByVersionCache(PyInterpreterState *interp);
3434

3535
extern PyObject *_Py_set_function_type_params(
3636
PyThreadState* unused, PyObject *func, PyObject *type_params);

Objects/funcobject.c

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -271,35 +271,23 @@ _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version)
271271
func->func_version = version;
272272
if (version != 0) {
273273
PyInterpreterState *interp = _PyInterpreterState_GET();
274-
PyFunctionObject **slot =
275-
interp->func_state.func_version_cache
276-
+ (version % FUNC_VERSION_CACHE_SIZE);
277-
Py_XSETREF(*slot, (PyFunctionObject *)Py_NewRef(func));
274+
interp->func_state.func_version_cache[
275+
version % FUNC_VERSION_CACHE_SIZE] = func;
278276
}
279277
}
280278

281279
PyFunctionObject *
282280
_PyFunction_LookupByVersion(uint32_t version)
283281
{
284282
PyInterpreterState *interp = _PyInterpreterState_GET();
285-
PyFunctionObject **slot =
286-
interp->func_state.func_version_cache
287-
+ (version % FUNC_VERSION_CACHE_SIZE);
288-
if (*slot != NULL && (*slot)->func_version == version) {
289-
return (PyFunctionObject *)Py_NewRef(*slot);
283+
PyFunctionObject *func = interp->func_state.func_version_cache[
284+
version % FUNC_VERSION_CACHE_SIZE];
285+
if (func != NULL && func->func_version == version) {
286+
return (PyFunctionObject *)Py_NewRef(func);
290287
}
291288
return NULL;
292289
}
293290

294-
void
295-
_PyFunction_ClearByVersionCache(PyInterpreterState *interp)
296-
{
297-
for (int i = 0; i < FUNC_VERSION_CACHE_SIZE; i++) {
298-
PyFunctionObject **slot = interp->func_state.func_version_cache + i;
299-
Py_CLEAR(*slot);
300-
}
301-
}
302-
303291
uint32_t
304292
_PyFunction_GetVersionForCurrentState(PyFunctionObject *func)
305293
{
@@ -929,6 +917,15 @@ func_dealloc(PyFunctionObject *op)
929917
if (op->func_weakreflist != NULL) {
930918
PyObject_ClearWeakRefs((PyObject *) op);
931919
}
920+
if (op->func_version != 0) {
921+
PyInterpreterState *interp = _PyInterpreterState_GET();
922+
PyFunctionObject **slot =
923+
interp->func_state.func_version_cache
924+
+ (op->func_version % FUNC_VERSION_CACHE_SIZE);
925+
if (*slot == op) {
926+
*slot = NULL;
927+
}
928+
}
932929
(void)func_clear(op);
933930
// These aren't cleared by func_clear().
934931
Py_DECREF(op->func_code);

Python/abstract_interp_cases.c.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/pylifecycle.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,11 +1767,6 @@ Py_FinalizeEx(void)
17671767
// XXX assert(_Py_IsMainInterpreter(tstate->interp));
17681768
// XXX assert(_Py_IsMainThread());
17691769

1770-
// The function version cache keeps functions alive, so clear it.
1771-
// It's used for optimizations, which we don't need in this stage.
1772-
tstate->interp->func_state.next_version = 0; // No more new versions
1773-
_PyFunction_ClearByVersionCache(tstate->interp);
1774-
17751770
// Block some operations.
17761771
tstate->interp->finalizing = 1;
17771772

Python/sysmodule.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,9 +2079,6 @@ sys__clear_type_cache_impl(PyObject *module)
20792079
/*[clinic end generated code: output=20e48ca54a6f6971 input=127f3e04a8d9b555]*/
20802080
{
20812081
PyType_ClearCache();
2082-
// Also clear the function-by-version cache
2083-
PyInterpreterState *interp = _PyInterpreterState_GET();
2084-
_PyFunction_ClearByVersionCache(interp);
20852082
Py_RETURN_NONE;
20862083
}
20872084

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy