bpo-44207: Add an internal version number to function objects. (GH-27078)

This commit is contained in:
Mark Shannon 2021-07-12 10:01:01 +01:00 committed by GitHub
parent e14d5ae544
commit 9487a17e3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 2 deletions

View File

@ -42,6 +42,14 @@ typedef struct {
PyObject *func_module; /* The __module__ attribute, can be anything */
PyObject *func_annotations; /* Annotations, a dict or NULL */
vectorcallfunc vectorcall;
/* Version number for use by specializer.
* Can set to non-zero when we want to specialize.
* Will be set to zero if any of these change:
* defaults
* kwdefaults (only if the object changes, not the contents of the dict)
* code
* annotations */
uint32_t func_version;
/* Invariant:
* func_closure contains the bindings for func_code->co_freevars, so
@ -74,6 +82,8 @@ PyAPI_FUNC(PyObject *) _PyFunction_Vectorcall(
PyObject *const *stack,
size_t nargsf,
PyObject *kwnames);
uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);
#endif
/* Macros for direct access to these values. Type checks are *not*

View File

@ -1278,7 +1278,7 @@ class SizeofTest(unittest.TestCase):
check(x, size('4P3i4cP'))
# function
def func(): pass
check(func, size('14P'))
check(func, size('14Pi'))
class c():
@staticmethod
def foo():

View File

@ -7,6 +7,8 @@
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "structmember.h" // PyMemberDef
static uint32_t next_func_version = 1;
PyObject *
PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
{
@ -79,7 +81,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
op->func_module = module;
op->func_annotations = NULL;
op->vectorcall = _PyFunction_Vectorcall;
op->func_version = 0;
_PyObject_GC_TRACK(op);
return (PyObject *)op;
@ -94,6 +96,19 @@ error:
return NULL;
}
uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func)
{
if (func->func_version != 0) {
return func->func_version;
}
if (next_func_version == 0) {
return 0;
}
uint32_t v = next_func_version++;
func->func_version = v;
return v;
}
PyObject *
PyFunction_New(PyObject *code, PyObject *globals)
{
@ -156,6 +171,7 @@ PyFunction_SetDefaults(PyObject *op, PyObject *defaults)
PyErr_SetString(PyExc_SystemError, "non-tuple default args");
return -1;
}
((PyFunctionObject *)op)->func_version = 0;
Py_XSETREF(((PyFunctionObject *)op)->func_defaults, defaults);
return 0;
}
@ -187,6 +203,7 @@ PyFunction_SetKwDefaults(PyObject *op, PyObject *defaults)
"non-dict keyword only default args");
return -1;
}
((PyFunctionObject *)op)->func_version = 0;
Py_XSETREF(((PyFunctionObject *)op)->func_kwdefaults, defaults);
return 0;
}
@ -219,6 +236,7 @@ PyFunction_SetClosure(PyObject *op, PyObject *closure)
Py_TYPE(closure)->tp_name);
return -1;
}
((PyFunctionObject *)op)->func_version = 0;
Py_XSETREF(((PyFunctionObject *)op)->func_closure, closure);
return 0;
}
@ -250,6 +268,7 @@ PyFunction_SetAnnotations(PyObject *op, PyObject *annotations)
"non-dict annotations");
return -1;
}
((PyFunctionObject *)op)->func_version = 0;
Py_XSETREF(((PyFunctionObject *)op)->func_annotations, annotations);
return 0;
}
@ -308,6 +327,7 @@ func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
nclosure, nfree);
return -1;
}
op->func_version = 0;
Py_INCREF(value);
Py_XSETREF(op->func_code, value);
return 0;
@ -392,6 +412,7 @@ func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored
return -1;
}
op->func_version = 0;
Py_XINCREF(value);
Py_XSETREF(op->func_defaults, value);
return 0;
@ -433,6 +454,7 @@ func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignor
return -1;
}
op->func_version = 0;
Py_XINCREF(value);
Py_XSETREF(op->func_kwdefaults, value);
return 0;
@ -482,6 +504,7 @@ func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(igno
"__annotations__ must be set to a dict object");
return -1;
}
op->func_version = 0;
Py_XINCREF(value);
Py_XSETREF(op->func_annotations, value);
return 0;
@ -611,6 +634,7 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
static int
func_clear(PyFunctionObject *op)
{
op->func_version = 0;
Py_CLEAR(op->func_code);
Py_CLEAR(op->func_globals);
Py_CLEAR(op->func_builtins);