Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(10)

Unified Diff: Objects/abstract.c

Issue 29259: Add tp_fastcall to PyTypeObject: support FASTCALL calling convention for all callable objects
Patch Set: Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
--- a/Objects/abstract.c Wed Jan 25 23:33:27 2017 +0100
+++ b/Objects/abstract.c Thu Jan 26 02:43:18 2017 +0100
@@ -2249,7 +2249,17 @@ PyObject_Call(PyObject *callable, PyObje
if (Py_EnterRecursiveCall(" while calling a Python object"))
return NULL;
- result = (*call)(callable, args, kwargs);
+ if (PyType_HasFeature(Py_TYPE(callable), Py_TPFLAGS_HAVE_FASTCALL)
+ && Py_TYPE(callable)->tp_fastcall) {
+ result = _Py_RawFastCallDict(callable,
+ Py_TYPE(callable)->tp_fastcall,
+ &PyTuple_GET_ITEM(args, 0),
+ PyTuple_GET_SIZE(args),
+ kwargs);
+ }
+ else {
+ result = (*call)(callable, args, kwargs);
+ }
Py_LeaveRecursiveCall();
@@ -2277,6 +2287,33 @@ PyObject* _Py_NO_INLINE
return args;
}
+int _Py_NO_INLINE
haypo 2017/01/26 03:35:21 Not sure if _Py_NO_INLINE is needed here.
+_PyStack_AsTupleAndDict(PyObject **stack, Py_ssize_t nargs, PyObject *kwnames,
+ PyObject **p_args, PyObject **p_kwargs)
+{
+ PyObject *args, *kwargs;
+
+ args = _PyStack_AsTuple(stack, nargs);
+ if (args == NULL) {
+ return -1;
+ }
+
+ if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) != 0) {
+ kwargs = _PyStack_AsDict(stack + nargs, kwnames);
+ if (kwargs == NULL) {
+ Py_DECREF(args);
+ return -1;
+ }
+ }
+ else {
+ kwargs = NULL;
+ }
+
+ *p_args = args;
+ *p_kwargs = kwargs;
+ return 0;
+}
+
PyObject*
_PyStack_AsTupleSlice(PyObject **stack, Py_ssize_t nargs,
Py_ssize_t start, Py_ssize_t end)
@@ -2328,11 +2365,18 @@ PyObject *
else if (PyCFunction_Check(callable)) {
result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
}
+ else if (PyType_HasFeature(Py_TYPE(callable), Py_TPFLAGS_HAVE_FASTCALL)
+ && Py_TYPE(callable)->tp_fastcall) {
+ fastternaryfunc fastcall = Py_TYPE(callable)->tp_fastcall;
+
+ result = _Py_RawFastCallDict(callable, fastcall, args, nargs, kwargs);
+ result = _Py_CheckFunctionResult(callable, result, NULL);
+ }
else {
PyObject *tuple;
/* Slow-path: build a temporary tuple */
- call = callable->ob_type->tp_call;
+ call = Py_TYPE(callable)->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
@@ -2364,17 +2408,17 @@ PyObject *
{
PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
PyObject **stack;
- Py_ssize_t argcount;
+ Py_ssize_t nargs;
PyObject *result;
assert(PyTuple_Check(args));
- argcount = PyTuple_GET_SIZE(args);
- if (argcount + 1 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
+ nargs = PyTuple_GET_SIZE(args);
+ if (nargs + 1 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
stack = small_stack;
}
else {
- stack = PyMem_Malloc((argcount + 1) * sizeof(PyObject *));
+ stack = PyMem_Malloc((nargs + 1) * sizeof(PyObject *));
if (stack == NULL) {
PyErr_NoMemory();
return NULL;
@@ -2384,11 +2428,11 @@ PyObject *
/* use borrowed references */
stack[0] = obj;
memcpy(&stack[1],
- &PyTuple_GET_ITEM(args, 0),
- argcount * sizeof(PyObject *));
+ &PyTuple_GET_ITEM(args, 0),
+ nargs * sizeof(PyObject *));
result = _PyObject_FastCallDict(callable,
- stack, argcount + 1,
+ stack, nargs + 1,
kwargs);
if (stack != small_stack) {
PyMem_Free(stack);
@@ -2397,6 +2441,45 @@ PyObject *
}
PyObject *
+_PyObject_FastCall_Prepend(PyObject *func, PyObject *obj, PyObject **args,
+ Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
+ PyObject **stack;
+ PyObject *result;
+ Py_ssize_t alloc;
+
+ alloc = nargs + 1;
+ if (kwnames != NULL) {
+ alloc += PyTuple_GET_SIZE(kwnames);
+ }
+
+ if (alloc <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
+ stack = small_stack;
+ }
+ else {
+ stack = PyMem_Malloc(alloc * sizeof(PyObject *));
+ if (stack == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ }
+
+ /* use borrowed references */
+ stack[0] = obj;
+ memcpy(&stack[1], args, (alloc - 1) * sizeof(PyObject *));
+
+ result = _PyObject_FastCallKeywords(func,
+ stack, nargs + 1,
+ kwnames);
+ if (stack != small_stack) {
+ PyMem_Free(stack);
+ }
+
+ return result;
+}
+
+PyObject *
_PyStack_AsDict(PyObject **values, PyObject *kwnames)
{
Py_ssize_t nkwargs;
@@ -2436,6 +2519,7 @@ int
assert(kwargs == NULL || PyDict_CheckExact(kwargs));
if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE(kwargs)) == 0) {
+ /* Note: args can be NULL */
*p_stack = args;
*p_kwnames = NULL;
return 0;
@@ -2458,8 +2542,11 @@ int
return -1;
}
- /* Copy position arguments (borrowed references) */
- memcpy(stack, args, nargs * sizeof(stack[0]));
+ /* args is NULL if nargs==0: don't call memcpy(stack, NULL, 0) */
+ if (nargs) {
+ /* Copy position arguments (borrowed references) */
+ memcpy(stack, args, nargs * sizeof(stack[0]));
+ }
kwstack = stack + nargs;
pos = i = 0;
@@ -2480,6 +2567,30 @@ int
}
PyObject *
+_Py_RawFastCallDict(PyObject *self, fastternaryfunc fastcall,
+ PyObject **args, Py_ssize_t nargs, PyObject *kwargs)
+{
+ PyObject **stack;
+ PyObject *kwnames;
+ PyObject *result;
+
+ assert(!PyErr_Occurred());
+ assert(fastcall != NULL);
+ assert(kwargs == NULL || PyDict_Check(kwargs));
+
+ if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
+ return NULL;
+ }
+
+ result = fastcall(self, stack, nargs, kwnames);
+ if (stack != args) {
+ PyMem_Free(stack);
+ }
+ Py_XDECREF(kwnames);
+ return result;
+}
+
+PyObject *
_PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs,
PyObject *kwnames)
{
@@ -2496,11 +2607,28 @@ PyObject *
_PyArg_ParseStackAndKeywords(). */
if (PyFunction_Check(callable)) {
+ /* FIXME: should we use Py_EnterRecursiveCall() here? */
haypo 2017/01/26 03:35:21 The FIXME can be removed, the issue is now tracked
return _PyFunction_FastCallKeywords(callable, stack, nargs, kwnames);
}
if (PyCFunction_Check(callable)) {
return _PyCFunction_FastCallKeywords(callable, stack, nargs, kwnames);
}
+ else if (PyType_HasFeature(Py_TYPE(callable), Py_TPFLAGS_HAVE_FASTCALL)
+ && Py_TYPE(callable)->tp_fastcall) {
+ fastternaryfunc fastcall = Py_TYPE(callable)->tp_fastcall;
+ PyObject *result;
+
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
+
+ result = fastcall(callable, stack, nargs, kwnames);
+ result = _Py_CheckFunctionResult(callable, result, NULL);
+
+ Py_LeaveRecursiveCall();
+
+ return result;
+ }
else {
/* Slow-path: build a temporary tuple for positional arguments and a
temporary dictionary for keyword arguments (if any) */
@@ -2518,7 +2646,7 @@ PyObject *
return NULL;
}
- call = callable->ob_type->tp_call;
+ call = Py_TYPE(callable)->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
« no previous file with comments | « Modules/_operator.c ('k') | Objects/classobject.c » ('j') | Objects/descrobject.c » ('J')

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+