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

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
« no previous file with comments | « Modules/_operator.c ('k') | Objects/classobject.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
--- a/Objects/abstract.c Tue Jan 17 20:43:31 2017 -0800
+++ b/Objects/abstract.c Wed Jan 18 08:45:26 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();
@@ -2328,11 +2338,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 +2381,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 +2401,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 +2414,46 @@ 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);
+ }
+
+ result = _Py_CheckFunctionResult(func, result, NULL);
+ return result;
+}
+
+PyObject *
_PyStack_AsDict(PyObject **values, PyObject *kwnames)
{
Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames);
@@ -2421,9 +2478,9 @@ PyObject *
return kwdict;
}
-int
+static int
_PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs,
- PyObject ***p_stack, PyObject **p_kwnames, PyObject *func)
+ PyObject ***p_stack, PyObject **p_kwnames)
{
PyObject **stack, **kwstack;
Py_ssize_t nkwargs;
@@ -2435,6 +2492,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;
@@ -2457,8 +2515,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;
@@ -2479,6 +2540,29 @@ 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());
+
+ 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)
{
@@ -2495,6 +2579,22 @@ PyObject *
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) */
@@ -2512,7 +2612,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);
@@ -2539,6 +2639,8 @@ PyObject *
Py_DECREF(argtuple);
Py_XDECREF(kwdict);
+ result = _Py_CheckFunctionResult(callable, result, NULL);
+
exit:
Py_LeaveRecursiveCall();
return result;
« no previous file with comments | « Modules/_operator.c ('k') | Objects/classobject.c » ('j') | no next file with comments »

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