diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2016-08-23 22:01:56 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2016-08-23 22:01:56 (GMT) |
commit | e62b85260542df5a7cb0c5b47507875ca7ffff23 (patch) | |
tree | cd6692cc4880940693e88244462ce85161aec43c | |
parent | a9ba1ab21b44abea9775b076573f9c69c9e7153a (diff) | |
download | cpython-e62b85260542df5a7cb0c5b47507875ca7ffff23.zip cpython-e62b85260542df5a7cb0c5b47507875ca7ffff23.tar.gz cpython-e62b85260542df5a7cb0c5b47507875ca7ffff23.tar.bz2 |
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.
-rw-r--r-- | Objects/abstract.c | 103 |
1 files changed, 71 insertions, 32 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index 0e67693..14021ba 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2499,32 +2499,52 @@ _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, return retval; } -static PyObject * -objargs_mktuple(va_list va) +static PyObject ** +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; - 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; - result = PyTuple_New(n); - if (result != NULL && n > 0) { - for (i = 0; i < n; ++i) { - tmp = (PyObject *)va_arg(va, PyObject *); - PyTuple_SET_ITEM(result, i, tmp); - Py_INCREF(tmp); + n = 0; + while (1) { + PyObject *arg = (PyObject *)va_arg(countva, PyObject *); + if (arg == NULL) { + break; } + 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_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL || name == NULL) { @@ -2537,24 +2557,31 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) /* count the args */ va_start(vargs, name); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) { + if (stack == NULL) { Py_DECREF(callable); return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); + + result = _PyObject_FastCall(callable, stack, nargs); Py_DECREF(callable); + if (stack != small_stack) { + PyMem_Free(stack); + } - return tmp; + return result; } PyObject * _PyObject_CallMethodIdObjArgs(PyObject *callable, struct _Py_Identifier *name, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL || name == NULL) { @@ -2567,23 +2594,30 @@ _PyObject_CallMethodIdObjArgs(PyObject *callable, /* count the args */ va_start(vargs, name); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) { + if (stack == NULL) { Py_DECREF(callable); return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); + + result = _PyObject_FastCall(callable, stack, nargs); Py_DECREF(callable); + if (stack != small_stack) { + PyMem_Free(stack); + } - return tmp; + return result; } PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL) { @@ -2592,14 +2626,19 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) /* count the args */ va_start(vargs, callable); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) + if (stack == 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; } |