Commit e62b8526 authored by Victor Stinner's avatar Victor Stinner

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.
parent a9ba1ab2
...@@ -2499,32 +2499,52 @@ _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, ...@@ -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;
Py_VA_COPY(countva, va); /* Count the number of arguments */
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) {
for (i = 0; i < n; ++i) { break;
tmp = (PyObject *)va_arg(va, PyObject *);
PyTuple_SET_ITEM(result, i, tmp);
Py_INCREF(tmp);
} }
n++;
} }
return result; *p_nargs = n;
/* Copy arguments */
if (small_stack_size <= n) {
stack = small_stack;
}
else {
stack = PyMem_Malloc(n * sizeof(PyObject**));
if (stack == NULL) {
PyErr_NoMemory();
return NULL;
}
}
for (i = 0; i < n; ++i) {
stack[i] = va_arg(va, PyObject *);
}
return stack;
} }
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, ...) ...@@ -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); result = _PyObject_FastCall(callable, stack, nargs);
Py_DECREF(callable); Py_DECREF(callable);
if (stack != small_stack) {
PyMem_Free(stack);
}
return tmp; 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, ...@@ -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); result = _PyObject_FastCall(callable, stack, nargs);
Py_DECREF(callable); Py_DECREF(callable);
if (stack != small_stack) {
PyMem_Free(stack);
}
return tmp; 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, ...) ...@@ -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);
result = _PyObject_FastCall(callable, stack, nargs);
if (stack != small_stack) {
PyMem_Free(stack);
}
return tmp; return result;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment