From 1ea055bd53ccf976e88018983a3c13447c4502be Mon Sep 17 00:00:00 2001 From: penguin_wwy <940375606@qq.com> Date: Tue, 22 Mar 2022 04:33:02 +0800 Subject: bpo-47067: Optimize calling GenericAlias objects (GH-31996) Use vectorcall, and replace `PyObject_SetAttrString` with `PyObject_SetAttr` and a global string. --- Include/internal/pycore_global_strings.h | 1 + Include/internal/pycore_runtime_init.h | 1 + .../2022-03-20-17-15-56.bpo-47067.XXLnje.rst | 1 + Objects/genericaliasobject.c | 39 ++++++++++++++++++---- 4 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-03-20-17-15-56.bpo-47067.XXLnje.rst diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 35bffa7..1d83bf2 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -156,6 +156,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(__next__) STRUCT_FOR_ID(__note__) STRUCT_FOR_ID(__or__) + STRUCT_FOR_ID(__orig_class__) STRUCT_FOR_ID(__origin__) STRUCT_FOR_ID(__package__) STRUCT_FOR_ID(__parameters__) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 20d543a..d5690d8 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -779,6 +779,7 @@ extern "C" { INIT_ID(__next__), \ INIT_ID(__note__), \ INIT_ID(__or__), \ + INIT_ID(__orig_class__), \ INIT_ID(__origin__), \ INIT_ID(__package__), \ INIT_ID(__parameters__), \ diff --git a/Misc/NEWS.d/next/Library/2022-03-20-17-15-56.bpo-47067.XXLnje.rst b/Misc/NEWS.d/next/Library/2022-03-20-17-15-56.bpo-47067.XXLnje.rst new file mode 100644 index 0000000..28c0895 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-03-20-17-15-56.bpo-47067.XXLnje.rst @@ -0,0 +1 @@ +Optimize calling ``GenericAlias`` objects by using :pep:`590` ``vectorcall`` and by replacing ``PyObject_SetAttrString`` with ``PyObject_SetAttr``. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 224a2e9..3f03630 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -12,9 +12,10 @@ typedef struct { PyObject *origin; PyObject *args; PyObject *parameters; - PyObject* weakreflist; + PyObject *weakreflist; // Whether we're a starred type, e.g. *tuple[int]. bool starred; + vectorcallfunc vectorcall; } gaobject; typedef struct { @@ -383,13 +384,11 @@ ga_hash(PyObject *self) return h0 ^ h1; } -static PyObject * -ga_call(PyObject *self, PyObject *args, PyObject *kwds) +static inline PyObject * +set_orig_class(PyObject *obj, PyObject *self) { - gaobject *alias = (gaobject *)self; - PyObject *obj = PyObject_Call(alias->origin, args, kwds); if (obj != NULL) { - if (PyObject_SetAttrString(obj, "__orig_class__", self) < 0) { + if (PyObject_SetAttr(obj, &_Py_ID(__orig_class__), self) < 0) { if (!PyErr_ExceptionMatches(PyExc_AttributeError) && !PyErr_ExceptionMatches(PyExc_TypeError)) { @@ -402,6 +401,23 @@ ga_call(PyObject *self, PyObject *args, PyObject *kwds) return obj; } +static PyObject * +ga_call(PyObject *self, PyObject *args, PyObject *kwds) +{ + gaobject *alias = (gaobject *)self; + PyObject *obj = PyObject_Call(alias->origin, args, kwds); + return set_orig_class(obj, self); +} + +static PyObject * +ga_vectorcall(PyObject *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + gaobject *alias = (gaobject *) self; + PyObject *obj = PyVectorcall_Function(alias->origin)(alias->origin, args, nargsf, kwnames); + return set_orig_class(obj, self); +} + static const char* const attr_exceptions[] = { "__origin__", "__args__", @@ -588,6 +604,14 @@ setup_ga(gaobject *alias, PyObject *origin, PyObject *args) { alias->args = args; alias->parameters = NULL; alias->weakreflist = NULL; + + if (PyVectorcall_Function(origin) != NULL) { + alias->vectorcall = ga_vectorcall; + } + else { + alias->vectorcall = NULL; + } + return 1; } @@ -695,7 +719,7 @@ PyTypeObject Py_GenericAliasType = { .tp_hash = ga_hash, .tp_call = ga_call, .tp_getattro = ga_getattro, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL, .tp_traverse = ga_traverse, .tp_richcompare = ga_richcompare, .tp_weaklistoffset = offsetof(gaobject, weakreflist), @@ -706,6 +730,7 @@ PyTypeObject Py_GenericAliasType = { .tp_free = PyObject_GC_Del, .tp_getset = ga_properties, .tp_iter = (getiterfunc)ga_iter, + .tp_vectorcall_offset = offsetof(gaobject, vectorcall), }; PyObject * -- cgit v0.12