diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2016-08-19 14:11:43 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2016-08-19 14:11:43 (GMT) |
commit | 9be7e7b52fa4b48012e956167a344df691195a04 (patch) | |
tree | b556a431bb06664b814b206dee3790eb2ac00464 /Objects/abstract.c | |
parent | fa46aa78996cbeb30ccbeb9c405a54459d5d55de (diff) | |
download | cpython-9be7e7b52fa4b48012e956167a344df691195a04.zip cpython-9be7e7b52fa4b48012e956167a344df691195a04.tar.gz cpython-9be7e7b52fa4b48012e956167a344df691195a04.tar.bz2 |
Add _PyObject_FastCall()
Issue #27128: Add _PyObject_FastCall(), a new calling convention avoiding a
temporary tuple to pass positional parameters in most cases, but create a
temporary tuple if needed (ex: for the tp_call slot).
The API is prepared to support keyword parameters, but the full implementation
will come later (_PyFunction_FastCall() doesn't support keyword parameters
yet).
Add also:
* _PyStack_AsTuple() helper function: convert a "stack" of parameters to
a tuple.
* _PyCFunction_FastCall(): fast call implementation for C functions
* _PyFunction_FastCall(): fast call implementation for Python functions
Diffstat (limited to 'Objects/abstract.c')
-rw-r--r-- | Objects/abstract.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index 5d8a44b..36401a8 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2193,6 +2193,82 @@ PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) return _Py_CheckFunctionResult(func, result, NULL); } +PyObject* +_PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) +{ + PyObject *args; + Py_ssize_t i; + + args = PyTuple_New(nargs); + if (args == NULL) { + return NULL; + } + + for (i=0; i < nargs; i++) { + PyObject *item = stack[i]; + Py_INCREF(item); + PyTuple_SET_ITEM(args, i, item); + } + + return args; +} + +PyObject * +_PyObject_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) +{ + ternaryfunc call; + PyObject *result = NULL; + + /* _PyObject_FastCall() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(func != NULL); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + /* issue #27128: support for keywords will come later: + _PyFunction_FastCall() doesn't support keyword arguments yet */ + assert(kwargs == NULL); + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + if (PyFunction_Check(func)) { + result = _PyFunction_FastCall(func, args, nargs, kwargs); + } + else if (PyCFunction_Check(func)) { + result = _PyCFunction_FastCall(func, args, nargs, kwargs); + } + else { + PyObject *tuple; + + /* Slow-path: build a temporary tuple */ + call = func->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + func->ob_type->tp_name); + goto exit; + } + + tuple = _PyStack_AsTuple(args, nargs); + if (tuple == NULL) { + goto exit; + } + + result = (*call)(func, tuple, kwargs); + Py_DECREF(tuple); + } + + result = _Py_CheckFunctionResult(func, result, NULL); + +exit: + Py_LeaveRecursiveCall(); + + return result; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { |