-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
gh-89013: Improve the performance of methodcaller (lazy version) #107201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
12a80bd
3d19683
035456c
8be0aed
83c76bb
09e3ee3
5d715c5
a6c465b
486c498
f174256
d70a8ad
1ceea51
608828a
ad7d6bd
3c3d73f
9335d6d
0c050fc
626169f
0634f66
5c56b64
812856b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1556,6 +1556,52 @@ typedef struct { | |
vectorcallfunc vectorcall; | ||
} methodcallerobject; | ||
|
||
static void * _methodcaller_initialize_vectorcall(methodcallerobject* mc) | ||
{ | ||
PyObject* args = mc->xargs; | ||
PyObject* kwds = mc->kwds; | ||
|
||
Py_ssize_t nargs = PyTuple_GET_SIZE(args); | ||
mc->vectorcall_args = PyMem_Calloc( | ||
corona10 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
nargs + (kwds ? PyDict_Size(kwds) : 0), | ||
sizeof(PyObject*)); | ||
if (!mc->vectorcall_args) { | ||
return PyErr_NoMemory(); | ||
} | ||
/* The first item of vectorcall_args will be filled with obj later */ | ||
if (nargs > 1) { | ||
memcpy(mc->vectorcall_args, PySequence_Fast_ITEMS(args), | ||
nargs * sizeof(PyObject*)); | ||
} | ||
if (kwds) { | ||
const Py_ssize_t nkwds = PyDict_Size(kwds); | ||
|
||
mc->vectorcall_kwnames = PyTuple_New(nkwds); | ||
if (!mc->vectorcall_kwnames) { | ||
return NULL; | ||
} | ||
Py_ssize_t i = 0, ppos = 0; | ||
PyObject* key, * value; | ||
while (PyDict_Next(kwds, &ppos, &key, &value)) { | ||
PyTuple_SET_ITEM(mc->vectorcall_kwnames, i, Py_NewRef(key)); | ||
mc->vectorcall_args[nargs + i] = value; // borrowed reference | ||
++i; | ||
} | ||
} | ||
else { | ||
mc->vectorcall_kwnames = NULL; | ||
} | ||
return (void *)1; | ||
} | ||
|
||
static _methodcaller_clear_vectorcall(methodcallerobject* mc) | ||
{ | ||
if (mc->vectorcall_args != NULL) { | ||
PyMem_Free(mc->vectorcall_args); | ||
Py_CLEAR(mc->vectorcall_kwnames); | ||
} | ||
} | ||
|
||
static PyObject * | ||
methodcaller_vectorcall( | ||
methodcallerobject *mc, PyObject *const *args, size_t nargsf, PyObject* kwnames) | ||
|
@@ -1564,19 +1610,28 @@ methodcaller_vectorcall( | |
|| !_PyArg_NoKwnames("methodcaller", kwnames)) { | ||
return NULL; | ||
} | ||
if (mc->vectorcall_args == NULL) { | ||
void *ret = _methodcaller_initialize_vectorcall(mc); | ||
if (ret == NULL) { | ||
return NULL; | ||
} | ||
eendebakpt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
assert(mc->vectorcall_args != 0); | ||
mc->vectorcall_args[0] = args[0]; | ||
return PyObject_VectorcallMethod( | ||
mc->name, mc->vectorcall_args, | ||
(PyTuple_GET_SIZE(mc->xargs)) | PY_VECTORCALL_ARGUMENTS_OFFSET, | ||
mc->vectorcall_kwnames); | ||
} | ||
|
||
|
||
/* AC 3.5: variable number of arguments, not currently support by AC */ | ||
static PyObject * | ||
methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | ||
{ | ||
methodcallerobject *mc; | ||
PyObject *name, *key, *value; | ||
PyObject* name; | ||
eendebakpt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (PyTuple_GET_SIZE(args) < 1) { | ||
PyErr_SetString(PyExc_TypeError, "methodcaller needs at least " | ||
|
@@ -1604,36 +1659,9 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |
|
||
mc->xargs = Py_XNewRef(args); // allows us to use borrowed references | ||
mc->kwds = Py_XNewRef(kwds); | ||
mc->vectorcall_args = 0; | ||
|
||
Py_ssize_t nargs = PyTuple_GET_SIZE(args); | ||
mc->vectorcall_args = PyMem_Calloc( | ||
nargs + (kwds ? PyDict_Size(kwds) : 0), | ||
sizeof(PyObject *)); | ||
if (!mc->vectorcall_args) { | ||
return PyErr_NoMemory(); | ||
} | ||
/* The first item of vectorcall_args will be filled with obj later */ | ||
if (nargs>1) { | ||
memcpy(mc->vectorcall_args, PySequence_Fast_ITEMS(args), | ||
nargs * sizeof(PyObject *)); | ||
} | ||
if (kwds) { | ||
const Py_ssize_t nkwds = PyDict_Size(kwds); | ||
|
||
mc->vectorcall_kwnames = PyTuple_New(nkwds); | ||
if (!mc->vectorcall_kwnames) { | ||
return NULL; | ||
} | ||
Py_ssize_t i = 0, ppos = 0; | ||
while (PyDict_Next(kwds, &ppos, &key, &value)) { | ||
PyTuple_SET_ITEM(mc->vectorcall_kwnames, i, Py_NewRef(key)); | ||
mc->vectorcall_args[nargs + i] = value; // borrowed reference | ||
++i; | ||
} | ||
} | ||
else { | ||
mc->vectorcall_kwnames = NULL; | ||
} | ||
mc->vectorcall = (vectorcallfunc)methodcaller_vectorcall; | ||
|
||
PyObject_GC_Track(mc); | ||
|
@@ -1646,7 +1674,9 @@ methodcaller_clear(methodcallerobject *mc) | |
Py_CLEAR(mc->name); | ||
Py_CLEAR(mc->xargs); | ||
Py_CLEAR(mc->kwds); | ||
Py_CLEAR(mc->vectorcall_kwnames); | ||
|
||
_methodcaller_clear_vectorcall(mc); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you separate the function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make it more symmetric with the |
||
|
||
return 0; | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.