]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-44207: Add an internal version number to function objects. (GH-27078)
authorMark Shannon <mark@hotpy.org>
Mon, 12 Jul 2021 09:01:01 +0000 (10:01 +0100)
committerGitHub <noreply@github.com>
Mon, 12 Jul 2021 09:01:01 +0000 (10:01 +0100)
Include/funcobject.h
Lib/test/test_sys.py
Objects/funcobject.c

index d7acd18c6519e486c416771dcbdbfc09bcf4b9c4..6bc03f57d4cb39db6f35638a6ac1b5cbe2be37a6 100644 (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*
index a549d44c5210fc31db1e248c5b2a972a81031a6b..7d9a36a8366a7d6c9d1cfb69df0e7c38cc9ac389 100644 (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():
index 4eff6d2fcd65bc9ac15fe524e8f5369119c63147..f74d96dfc81c25bce486e049e325d3dda80385db 100644 (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);