[Python-checkins] cpython: Issue #29306: Fix usage of Py_EnterRecursiveCall()

victor.stinner python-checkins at python.org
Wed Feb 8 06:25:16 EST 2017


https://hg.python.org/cpython/rev/88ed9d9eabc1
changeset: 106466:88ed9d9eabc1
user: Victor Stinner <victor.stinner at gmail.com>
date: Wed Feb 08 12:06:00 2017 +0100
summary:
 Issue #29306: Fix usage of Py_EnterRecursiveCall()
* *PyCFunction_*Call*() functions now call Py_EnterRecursiveCall().
* PyObject_Call() now calls directly _PyFunction_FastCallDict() and
 PyCFunction_Call() to avoid calling Py_EnterRecursiveCall() twice per
 function call
files:
 Objects/abstract.c | 112 +++++++++++++++-------------
 Objects/methodobject.c | 61 +++++++++------
 2 files changed, 95 insertions(+), 78 deletions(-)
diff --git a/Objects/abstract.c b/Objects/abstract.c
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2239,21 +2239,32 @@
 assert(PyTuple_Check(args));
 assert(kwargs == NULL || PyDict_Check(kwargs));
 
- call = callable->ob_type->tp_call;
- if (call == NULL) {
- PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
- callable->ob_type->tp_name);
- return NULL;
+ if (PyFunction_Check(callable)) {
+ return _PyFunction_FastCallDict(callable,
+ &PyTuple_GET_ITEM(args, 0),
+ PyTuple_GET_SIZE(args),
+ kwargs);
 }
-
- if (Py_EnterRecursiveCall(" while calling a Python object"))
- return NULL;
-
- result = (*call)(callable, args, kwargs);
-
- Py_LeaveRecursiveCall();
-
- return _Py_CheckFunctionResult(callable, result, NULL);
+ else if (PyCFunction_Check(callable)) {
+ return PyCFunction_Call(callable, args, kwargs);
+ }
+ else {
+ call = callable->ob_type->tp_call;
+ if (call == NULL) {
+ PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
+ callable->ob_type->tp_name);
+ return NULL;
+ }
+
+ if (Py_EnterRecursiveCall(" while calling a Python object"))
+ return NULL;
+
+ result = (*call)(callable, args, kwargs);
+
+ Py_LeaveRecursiveCall();
+
+ return _Py_CheckFunctionResult(callable, result, NULL);
+ }
 }
 
 /* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their
@@ -2305,9 +2316,6 @@
 _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
 PyObject *kwargs)
 {
- ternaryfunc call;
- PyObject *result = NULL;
-
 /* _PyObject_FastCallDict() must not be called with an exception set,
 because it can clear it (directly or indirectly) and so the
 caller loses its exception */
@@ -2318,42 +2326,41 @@
 assert(nargs == 0 || args != NULL);
 assert(kwargs == NULL || PyDict_Check(kwargs));
 
- if (Py_EnterRecursiveCall(" while calling a Python object")) {
- return NULL;
- }
-
 if (PyFunction_Check(callable)) {
- result = _PyFunction_FastCallDict(callable, args, nargs, kwargs);
+ return _PyFunction_FastCallDict(callable, args, nargs, kwargs);
 }
 else if (PyCFunction_Check(callable)) {
- result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
+ return _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
 }
 else {
- PyObject *tuple;
+ PyObject *argstuple, *result;
+ ternaryfunc call;
 
 /* Slow-path: build a temporary tuple */
 call = callable->ob_type->tp_call;
 if (call == NULL) {
 PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
 callable->ob_type->tp_name);
- goto exit;
+ return NULL;
 }
 
- tuple = _PyStack_AsTuple(args, nargs);
- if (tuple == NULL) {
- goto exit;
+ argstuple = _PyStack_AsTuple(args, nargs);
+ if (argstuple == NULL) {
+ return NULL;
 }
 
- result = (*call)(callable, tuple, kwargs);
- Py_DECREF(tuple);
-
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
+
+ result = (*call)(callable, argstuple, kwargs);
+
+ Py_LeaveRecursiveCall();
+
+ Py_DECREF(argstuple);
 result = _Py_CheckFunctionResult(callable, result, NULL);
+ return result;
 }
-
-exit:
- Py_LeaveRecursiveCall();
-
- return result;
 }
 
 /* Positional arguments are obj followed by args:
@@ -2506,49 +2513,48 @@
 temporary dictionary for keyword arguments (if any) */
 
 ternaryfunc call;
- PyObject *argtuple;
+ PyObject *argstuple;
 PyObject *kwdict, *result;
 Py_ssize_t nkwargs;
 
- result = NULL;
 nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
 assert((nargs == 0 && nkwargs == 0) || stack != NULL);
 
- if (Py_EnterRecursiveCall(" while calling a Python object")) {
- return NULL;
- }
-
 call = callable->ob_type->tp_call;
 if (call == NULL) {
 PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
 callable->ob_type->tp_name);
- goto exit;
+ return NULL;
 }
 
- argtuple = _PyStack_AsTuple(stack, nargs);
- if (argtuple == NULL) {
- goto exit;
+ argstuple = _PyStack_AsTuple(stack, nargs);
+ if (argstuple == NULL) {
+ return NULL;
 }
 
 if (nkwargs > 0) {
 kwdict = _PyStack_AsDict(stack + nargs, kwnames);
 if (kwdict == NULL) {
- Py_DECREF(argtuple);
- goto exit;
+ Py_DECREF(argstuple);
+ return NULL;
 }
 }
 else {
 kwdict = NULL;
 }
 
- result = (*call)(callable, argtuple, kwdict);
- Py_DECREF(argtuple);
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
+
+ result = (*call)(callable, argstuple, kwdict);
+
+ Py_LeaveRecursiveCall();
+
+ Py_DECREF(argstuple);
 Py_XDECREF(kwdict);
 
 result = _Py_CheckFunctionResult(callable, result, NULL);
-
- exit:
- Py_LeaveRecursiveCall();
 return result;
 }
 }
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -90,11 +90,6 @@
 _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args,
 Py_ssize_t nargs, PyObject *kwargs)
 {
- PyCFunction meth;
- PyObject *result;
- int flags;
- PyObject *argstuple;
-
 /* _PyMethodDef_RawFastCallDict() must not be called with an exception set,
 because it can clear it (directly or indirectly) and so the
 caller loses its exception */
@@ -105,18 +100,23 @@
 assert(nargs == 0 || args != NULL);
 assert(kwargs == NULL || PyDict_Check(kwargs));
 
- meth = method->ml_meth;
- flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
+ PyCFunction meth = method->ml_meth;
+ int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
+ PyObject *result = NULL;
+
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
 
 switch (flags)
 {
 case METH_NOARGS:
- if (nargs != 0) {
+ if (nargs != 0) {
 PyErr_Format(PyExc_TypeError,
 "%.200s() takes no arguments (%zd given)",
 method->ml_name, nargs);
- return NULL;
- }
+ goto exit;
+ }
 
 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
 goto no_keyword_error;
@@ -130,7 +130,7 @@
 PyErr_Format(PyExc_TypeError,
 "%.200s() takes exactly one argument (%zd given)",
 method->ml_name, nargs);
- return NULL;
+ goto exit;
 }
 
 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
@@ -148,10 +148,11 @@
 /* fall through next case */
 
 case METH_VARARGS | METH_KEYWORDS:
+ {
 /* Slow-path: create a temporary tuple for positional arguments */
- argstuple = _PyStack_AsTuple(args, nargs);
+ PyObject *argstuple = _PyStack_AsTuple(args, nargs);
 if (argstuple == NULL) {
- return NULL;
+ goto exit;
 }
 
 if (flags & METH_KEYWORDS) {
@@ -162,6 +163,7 @@
 }
 Py_DECREF(argstuple);
 break;
+ }
 
 case METH_FASTCALL:
 {
@@ -170,7 +172,7 @@
 _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth;
 
 if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
- return NULL;
+ goto exit;
 }
 
 result = (*fastmeth) (self, stack, nargs, kwnames);
@@ -185,17 +187,19 @@
 PyErr_SetString(PyExc_SystemError,
 "Bad call flags in _PyMethodDef_RawFastCallDict. "
 "METH_OLDARGS is no longer supported!");
- return NULL;
+ goto exit;
 }
 
- return result;
+ goto exit;
 
 no_keyword_error:
 PyErr_Format(PyExc_TypeError,
 "%.200s() takes no keyword arguments",
 method->ml_name, nargs);
 
- return NULL;
+exit:
+ Py_LeaveRecursiveCall();
+ return result;
 }
 
 PyObject *
@@ -232,7 +236,11 @@
 PyCFunction meth = method->ml_meth;
 int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
 Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames);
- PyObject *result;
+ PyObject *result = NULL;
+
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
 
 switch (flags)
 {
@@ -241,7 +249,7 @@
 PyErr_Format(PyExc_TypeError,
 "%.200s() takes no arguments (%zd given)",
 method->ml_name, nargs);
- return NULL;
+ goto exit;
 }
 
 if (nkwargs) {
@@ -256,7 +264,7 @@
 PyErr_Format(PyExc_TypeError,
 "%.200s() takes exactly one argument (%zd given)",
 method->ml_name, nargs);
- return NULL;
+ goto exit;
 }
 
 if (nkwargs) {
@@ -284,7 +292,7 @@
 
 argtuple = _PyStack_AsTuple(args, nargs);
 if (argtuple == NULL) {
- return NULL;
+ goto exit;
 }
 
 if (flags & METH_KEYWORDS) {
@@ -294,7 +302,7 @@
 kwdict = _PyStack_AsDict(args + nargs, kwnames);
 if (kwdict == NULL) {
 Py_DECREF(argtuple);
- return NULL;
+ goto exit;
 }
 }
 else {
@@ -315,16 +323,19 @@
 PyErr_SetString(PyExc_SystemError,
 "Bad call flags in _PyCFunction_FastCallKeywords. "
 "METH_OLDARGS is no longer supported!");
- return NULL;
+ goto exit;
 }
 
- return result;
+ goto exit;
 
 no_keyword_error:
 PyErr_Format(PyExc_TypeError,
 "%.200s() takes no keyword arguments",
 method->ml_name);
- return NULL;
+
+exit:
+ Py_LeaveRecursiveCall();
+ return result;
 }
 
 PyObject *
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /