diff options
-rw-r--r-- | Include/funcobject.h | 10 | ||||
-rw-r--r-- | Lib/test/test_sys.py | 2 | ||||
-rw-r--r-- | Objects/funcobject.c | 26 |
3 files changed, 36 insertions, 2 deletions
diff --git a/Include/funcobject.h b/Include/funcobject.h index d7acd18..6bc03f5 100644 --- a/Include/funcobject.h +++ b/Include/funcobject.h @@ -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* diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index a549d44..7d9a36a 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -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(): diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 4eff6d2..f74d96d 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -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); |