bpo-37207: Use PEP 590 vectorcall to speed up frozenset() (GH-19053)

This commit is contained in:
Dong-hee Na 2020-03-19 02:30:50 +09:00 committed by GitHub
parent d18de46117
commit 1c60567b9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 18 deletions

View File

@ -0,0 +1,2 @@
Speed up calls to ``frozenset()`` by using the :pep:`590` ``vectorcall``
calling convention. Patch by Dong-hee Na.

View File

@ -1024,6 +1024,7 @@ PyDoc_STRVAR(update_doc,
static PyObject * static PyObject *
make_new_set(PyTypeObject *type, PyObject *iterable) make_new_set(PyTypeObject *type, PyObject *iterable)
{ {
assert(PyType_Check(type));
PySetObject *so; PySetObject *so;
so = (PySetObject *)type->tp_alloc(type, 0); so = (PySetObject *)type->tp_alloc(type, 0);
@ -1064,37 +1065,67 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
static PyObject *emptyfrozenset = NULL; static PyObject *emptyfrozenset = NULL;
static PyObject * static PyObject *
frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds) make_new_frozenset(PyTypeObject *type, PyObject *iterable)
{ {
PyObject *iterable = NULL, *result; if (type != &PyFrozenSet_Type) {
if (type == &PyFrozenSet_Type && !_PyArg_NoKeywords("frozenset", kwds))
return NULL;
if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable))
return NULL;
if (type != &PyFrozenSet_Type)
return make_new_set(type, iterable); return make_new_set(type, iterable);
}
if (iterable != NULL) { if (iterable != NULL) {
/* frozenset(f) is idempotent */
if (PyFrozenSet_CheckExact(iterable)) { if (PyFrozenSet_CheckExact(iterable)) {
/* frozenset(f) is idempotent */
Py_INCREF(iterable); Py_INCREF(iterable);
return iterable; return iterable;
} }
result = make_new_set(type, iterable); PyObject *res = make_new_set((PyTypeObject *)type, iterable);
if (result == NULL || PySet_GET_SIZE(result)) if (res == NULL || PySet_GET_SIZE(res) != 0) {
return result; return res;
Py_DECREF(result); }
/* If the created frozenset is empty, return the empty frozenset singleton instead */
Py_DECREF(res);
}
// The empty frozenset is a singleton
if (emptyfrozenset == NULL) {
emptyfrozenset = make_new_set((PyTypeObject *)type, NULL);
} }
/* The empty frozenset is a singleton */
if (emptyfrozenset == NULL)
emptyfrozenset = make_new_set(type, NULL);
Py_XINCREF(emptyfrozenset); Py_XINCREF(emptyfrozenset);
return emptyfrozenset; return emptyfrozenset;
} }
static PyObject *
frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *iterable = NULL;
if (type == &PyFrozenSet_Type && !_PyArg_NoKeywords("frozenset", kwds)) {
return NULL;
}
if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) {
return NULL;
}
return make_new_frozenset(type, iterable);
}
static PyObject *
frozenset_vectorcall(PyObject *type, PyObject * const*args,
size_t nargsf, PyObject *kwnames)
{
if (!_PyArg_NoKwnames("frozenset", kwnames)) {
return NULL;
}
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (!_PyArg_CheckPositional("frozenset", nargs, 0, 1)) {
return NULL;
}
PyObject *iterable = (nargs ? args[0] : NULL);
return make_new_frozenset((PyTypeObject *)type, iterable);
}
static PyObject * static PyObject *
set_new(PyTypeObject *type, PyObject *args, PyObject *kwds) set_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
@ -2283,6 +2314,7 @@ PyTypeObject PyFrozenSet_Type = {
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
frozenset_new, /* tp_new */ frozenset_new, /* tp_new */
PyObject_GC_Del, /* tp_free */ PyObject_GC_Del, /* tp_free */
.tp_vectorcall = frozenset_vectorcall,
}; };