mirror of https://github.com/python/cpython
PyObject_CallMethodObjArgs() now uses fast call
Issue #27809: * PyObject_CallMethodObjArgs(), _PyObject_CallMethodIdObjArgs() and PyObject_CallFunctionObjArgs() now use fast call to avoid the creation of a temporary tuple * Rename objargs_mktuple() to objargs_mkstack() * objargs_mkstack() now stores objects in a C array using borrowed references, instead of storing arguments into a tuple objargs_mkstack() uses a small buffer allocated on the C stack for 5 arguments or less, or allocates a buffer in the heap memory. Note: this change is different than the change 0e4f26083bbb, I fixed the test to decide if the small stack can be used or not. sizeof(PyObject**) was also replaced with sizeof(stack[0]) since the sizeof() was wrong (but gave the same result).
This commit is contained in:
parent
d48af09043
commit
dd69564c38
|
@ -2499,32 +2499,52 @@ _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject **
|
||||||
objargs_mktuple(va_list va)
|
objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size,
|
||||||
|
va_list va, Py_ssize_t *p_nargs)
|
||||||
{
|
{
|
||||||
int i, n = 0;
|
Py_ssize_t i, n;
|
||||||
va_list countva;
|
va_list countva;
|
||||||
PyObject *result, *tmp;
|
PyObject **stack;
|
||||||
|
|
||||||
|
/* Count the number of arguments */
|
||||||
Py_VA_COPY(countva, va);
|
Py_VA_COPY(countva, va);
|
||||||
|
|
||||||
while (((PyObject *)va_arg(countva, PyObject *)) != NULL)
|
n = 0;
|
||||||
++n;
|
while (1) {
|
||||||
result = PyTuple_New(n);
|
PyObject *arg = (PyObject *)va_arg(countva, PyObject *);
|
||||||
if (result != NULL && n > 0) {
|
if (arg == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
*p_nargs = n;
|
||||||
|
|
||||||
|
/* Copy arguments */
|
||||||
|
if (n <= small_stack_size) {
|
||||||
|
stack = small_stack;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stack = PyMem_Malloc(n * sizeof(stack[0]));
|
||||||
|
if (stack == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
tmp = (PyObject *)va_arg(va, PyObject *);
|
stack[i] = va_arg(va, PyObject *);
|
||||||
PyTuple_SET_ITEM(result, i, tmp);
|
|
||||||
Py_INCREF(tmp);
|
|
||||||
}
|
}
|
||||||
}
|
return stack;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...)
|
PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...)
|
||||||
{
|
{
|
||||||
PyObject *args, *tmp;
|
PyObject *small_stack[5];
|
||||||
|
PyObject **stack;
|
||||||
|
Py_ssize_t nargs;
|
||||||
|
PyObject *result;
|
||||||
va_list vargs;
|
va_list vargs;
|
||||||
|
|
||||||
if (callable == NULL || name == NULL) {
|
if (callable == NULL || name == NULL) {
|
||||||
|
@ -2537,24 +2557,31 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...)
|
||||||
|
|
||||||
/* count the args */
|
/* count the args */
|
||||||
va_start(vargs, name);
|
va_start(vargs, name);
|
||||||
args = objargs_mktuple(vargs);
|
stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack),
|
||||||
|
vargs, &nargs);
|
||||||
va_end(vargs);
|
va_end(vargs);
|
||||||
if (args == NULL) {
|
if (stack == NULL) {
|
||||||
Py_DECREF(callable);
|
Py_DECREF(callable);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
tmp = PyObject_Call(callable, args, NULL);
|
|
||||||
Py_DECREF(args);
|
|
||||||
Py_DECREF(callable);
|
|
||||||
|
|
||||||
return tmp;
|
result = _PyObject_FastCall(callable, stack, nargs);
|
||||||
|
Py_DECREF(callable);
|
||||||
|
if (stack != small_stack) {
|
||||||
|
PyMem_Free(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyObject_CallMethodIdObjArgs(PyObject *callable,
|
_PyObject_CallMethodIdObjArgs(PyObject *callable,
|
||||||
struct _Py_Identifier *name, ...)
|
struct _Py_Identifier *name, ...)
|
||||||
{
|
{
|
||||||
PyObject *args, *tmp;
|
PyObject *small_stack[5];
|
||||||
|
PyObject **stack;
|
||||||
|
Py_ssize_t nargs;
|
||||||
|
PyObject *result;
|
||||||
va_list vargs;
|
va_list vargs;
|
||||||
|
|
||||||
if (callable == NULL || name == NULL) {
|
if (callable == NULL || name == NULL) {
|
||||||
|
@ -2567,23 +2594,30 @@ _PyObject_CallMethodIdObjArgs(PyObject *callable,
|
||||||
|
|
||||||
/* count the args */
|
/* count the args */
|
||||||
va_start(vargs, name);
|
va_start(vargs, name);
|
||||||
args = objargs_mktuple(vargs);
|
stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack),
|
||||||
|
vargs, &nargs);
|
||||||
va_end(vargs);
|
va_end(vargs);
|
||||||
if (args == NULL) {
|
if (stack == NULL) {
|
||||||
Py_DECREF(callable);
|
Py_DECREF(callable);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
tmp = PyObject_Call(callable, args, NULL);
|
|
||||||
Py_DECREF(args);
|
|
||||||
Py_DECREF(callable);
|
|
||||||
|
|
||||||
return tmp;
|
result = _PyObject_FastCall(callable, stack, nargs);
|
||||||
|
Py_DECREF(callable);
|
||||||
|
if (stack != small_stack) {
|
||||||
|
PyMem_Free(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyObject_CallFunctionObjArgs(PyObject *callable, ...)
|
PyObject_CallFunctionObjArgs(PyObject *callable, ...)
|
||||||
{
|
{
|
||||||
PyObject *args, *tmp;
|
PyObject *small_stack[5];
|
||||||
|
PyObject **stack;
|
||||||
|
Py_ssize_t nargs;
|
||||||
|
PyObject *result;
|
||||||
va_list vargs;
|
va_list vargs;
|
||||||
|
|
||||||
if (callable == NULL) {
|
if (callable == NULL) {
|
||||||
|
@ -2592,14 +2626,19 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...)
|
||||||
|
|
||||||
/* count the args */
|
/* count the args */
|
||||||
va_start(vargs, callable);
|
va_start(vargs, callable);
|
||||||
args = objargs_mktuple(vargs);
|
stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack),
|
||||||
|
vargs, &nargs);
|
||||||
va_end(vargs);
|
va_end(vargs);
|
||||||
if (args == NULL)
|
if (stack == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
tmp = PyObject_Call(callable, args, NULL);
|
}
|
||||||
Py_DECREF(args);
|
|
||||||
|
|
||||||
return tmp;
|
result = _PyObject_FastCall(callable, stack, nargs);
|
||||||
|
if (stack != small_stack) {
|
||||||
|
PyMem_Free(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue