Skip to content

Commit 675f317

Browse files
committed
Add function-by-version cache
1 parent 94630d4 commit 675f317

File tree

6 files changed

+56
-5
lines changed

6 files changed

+56
-5
lines changed

Include/internal/pycore_function.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,22 @@ extern PyObject* _PyFunction_Vectorcall(
1616

1717
#define FUNC_MAX_WATCHERS 8
1818

19+
#define FUNC_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */
1920
struct _py_func_state {
2021
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.
25+
PyFunctionObject *func_version_cache[FUNC_VERSION_CACHE_SIZE];
2126
};
2227

2328
extern PyFunctionObject* _PyFunction_FromConstructor(PyFrameConstructor *constr);
2429

2530
extern uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);
31+
extern void _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version);
32+
PyFunctionObject *_PyFunction_LookupByVersion(uint32_t version);
33+
void _PyFunction_ClearByVersionCache(void);
34+
2635
extern PyObject *_Py_set_function_type_params(
2736
PyThreadState* unused, PyObject *func, PyObject *type_params);
2837

Objects/funcobject.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,44 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
223223
return NULL;
224224
}
225225

226-
uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func)
226+
void
227+
_PyFunction_SetVersion(PyFunctionObject *func, uint32_t version)
228+
{
229+
func->func_version = version;
230+
if (version != 0) {
231+
PyInterpreterState *interp = _PyInterpreterState_GET();
232+
PyFunctionObject **slot =
233+
interp->func_state.func_version_cache
234+
+ (version % FUNC_VERSION_CACHE_SIZE);
235+
Py_XSETREF(*slot, (PyFunctionObject *)Py_NewRef(func));
236+
}
237+
}
238+
239+
PyFunctionObject *
240+
_PyFunction_LookupByVersion(uint32_t version)
241+
{
242+
PyInterpreterState *interp = _PyInterpreterState_GET();
243+
PyFunctionObject **slot =
244+
interp->func_state.func_version_cache
245+
+ (version % FUNC_VERSION_CACHE_SIZE);
246+
if (*slot != NULL && (*slot)->func_version == version) {
247+
return (PyFunctionObject *)Py_NewRef(*slot);
248+
}
249+
return NULL;
250+
}
251+
252+
void
253+
_PyFunction_ClearByVersionCache(void)
254+
{
255+
PyInterpreterState *interp = _PyInterpreterState_GET();
256+
for (int i = 0; i < FUNC_VERSION_CACHE_SIZE; i++) {
257+
PyFunctionObject **slot = interp->func_state.func_version_cache + i;
258+
Py_CLEAR(*slot);
259+
}
260+
}
261+
262+
uint32_t
263+
_PyFunction_GetVersionForCurrentState(PyFunctionObject *func)
227264
{
228265
if (func->func_version != 0) {
229266
return func->func_version;
@@ -236,7 +273,7 @@ uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func)
236273
return 0;
237274
}
238275
uint32_t v = interp->func_state.next_version++;
239-
func->func_version = v;
276+
_PyFunction_SetVersion(func, v);
240277
return v;
241278
}
242279

Python/bytecodes.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3542,7 +3542,8 @@ dummy_func(
35423542
goto error;
35433543
}
35443544

3545-
func_obj->func_version = ((PyCodeObject *)codeobj)->co_version;
3545+
_PyFunction_SetVersion(
3546+
func_obj, ((PyCodeObject *)codeobj)->co_version);
35463547
func = (PyObject *)func_obj;
35473548
}
35483549

Python/executor_cases.c.h

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/sysmodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,6 +2079,8 @@ 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+
_PyFunction_ClearByVersionCache();
20822084
Py_RETURN_NONE;
20832085
}
20842086

0 commit comments

Comments
 (0)