mirror of https://github.com/python/cpython
bpo-44207: Add an internal version number to function objects. (GH-27078)
This commit is contained in:
parent
e14d5ae544
commit
9487a17e3c
|
@ -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*
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue