Skip to content

Commit 1ea055b

Browse files
authored
bpo-47067: Optimize calling GenericAlias objects (GH-31996)
Use vectorcall, and replace `PyObject_SetAttrString` with `PyObject_SetAttr` and a global string.
1 parent 5c3201e commit 1ea055b

File tree

4 files changed

+35
-7
lines changed

4 files changed

+35
-7
lines changed

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ struct _Py_global_strings {
156156
STRUCT_FOR_ID(__next__)
157157
STRUCT_FOR_ID(__note__)
158158
STRUCT_FOR_ID(__or__)
159+
STRUCT_FOR_ID(__orig_class__)
159160
STRUCT_FOR_ID(__origin__)
160161
STRUCT_FOR_ID(__package__)
161162
STRUCT_FOR_ID(__parameters__)

Include/internal/pycore_runtime_init.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,7 @@ extern "C" {
779779
INIT_ID(__next__), \
780780
INIT_ID(__note__), \
781781
INIT_ID(__or__), \
782+
INIT_ID(__orig_class__), \
782783
INIT_ID(__origin__), \
783784
INIT_ID(__package__), \
784785
INIT_ID(__parameters__), \
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Optimize calling ``GenericAlias`` objects by using :pep:`590` ``vectorcall`` and by replacing ``PyObject_SetAttrString`` with ``PyObject_SetAttr``.

Objects/genericaliasobject.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ typedef struct {
1212
PyObject *origin;
1313
PyObject *args;
1414
PyObject *parameters;
15-
PyObject* weakreflist;
15+
PyObject *weakreflist;
1616
// Whether we're a starred type, e.g. *tuple[int].
1717
bool starred;
18+
vectorcallfunc vectorcall;
1819
} gaobject;
1920

2021
typedef struct {
@@ -383,13 +384,11 @@ ga_hash(PyObject *self)
383384
return h0 ^ h1;
384385
}
385386

386-
static PyObject *
387-
ga_call(PyObject *self, PyObject *args, PyObject *kwds)
387+
static inline PyObject *
388+
set_orig_class(PyObject *obj, PyObject *self)
388389
{
389-
gaobject *alias = (gaobject *)self;
390-
PyObject *obj = PyObject_Call(alias->origin, args, kwds);
391390
if (obj != NULL) {
392-
if (PyObject_SetAttrString(obj, "__orig_class__", self) < 0) {
391+
if (PyObject_SetAttr(obj, &_Py_ID(__orig_class__), self) < 0) {
393392
if (!PyErr_ExceptionMatches(PyExc_AttributeError) &&
394393
!PyErr_ExceptionMatches(PyExc_TypeError))
395394
{
@@ -402,6 +401,23 @@ ga_call(PyObject *self, PyObject *args, PyObject *kwds)
402401
return obj;
403402
}
404403

404+
static PyObject *
405+
ga_call(PyObject *self, PyObject *args, PyObject *kwds)
406+
{
407+
gaobject *alias = (gaobject *)self;
408+
PyObject *obj = PyObject_Call(alias->origin, args, kwds);
409+
return set_orig_class(obj, self);
410+
}
411+
412+
static PyObject *
413+
ga_vectorcall(PyObject *self, PyObject *const *args,
414+
size_t nargsf, PyObject *kwnames)
415+
{
416+
gaobject *alias = (gaobject *) self;
417+
PyObject *obj = PyVectorcall_Function(alias->origin)(alias->origin, args, nargsf, kwnames);
418+
return set_orig_class(obj, self);
419+
}
420+
405421
static const char* const attr_exceptions[] = {
406422
"__origin__",
407423
"__args__",
@@ -588,6 +604,14 @@ setup_ga(gaobject *alias, PyObject *origin, PyObject *args) {
588604
alias->args = args;
589605
alias->parameters = NULL;
590606
alias->weakreflist = NULL;
607+
608+
if (PyVectorcall_Function(origin) != NULL) {
609+
alias->vectorcall = ga_vectorcall;
610+
}
611+
else {
612+
alias->vectorcall = NULL;
613+
}
614+
591615
return 1;
592616
}
593617

@@ -695,7 +719,7 @@ PyTypeObject Py_GenericAliasType = {
695719
.tp_hash = ga_hash,
696720
.tp_call = ga_call,
697721
.tp_getattro = ga_getattro,
698-
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
722+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
699723
.tp_traverse = ga_traverse,
700724
.tp_richcompare = ga_richcompare,
701725
.tp_weaklistoffset = offsetof(gaobject, weakreflist),
@@ -706,6 +730,7 @@ PyTypeObject Py_GenericAliasType = {
706730
.tp_free = PyObject_GC_Del,
707731
.tp_getset = ga_properties,
708732
.tp_iter = (getiterfunc)ga_iter,
733+
.tp_vectorcall_offset = offsetof(gaobject, vectorcall),
709734
};
710735

711736
PyObject *

0 commit comments

Comments
 (0)