diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index f03b53ade92..00c749949c4 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -31,62 +31,6 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc); PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *); -PyAPI_DATA(int) _Py_CheckRecursionLimit; - -#ifdef USE_STACKCHECK -/* With USE_STACKCHECK macro defined, trigger stack checks in - _Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */ -static inline int _Py_MakeRecCheck(PyThreadState *tstate) { - return (++tstate->recursion_depth > _Py_CheckRecursionLimit - || ++tstate->stackcheck_counter > 64); -} -#else -static inline int _Py_MakeRecCheck(PyThreadState *tstate) { - return (++tstate->recursion_depth > _Py_CheckRecursionLimit); -} -#endif - -PyAPI_FUNC(int) _Py_CheckRecursiveCall( - PyThreadState *tstate, - const char *where); - -static inline int _Py_EnterRecursiveCall(PyThreadState *tstate, - const char *where) { - return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where)); -} - -static inline int _Py_EnterRecursiveCall_inline(const char *where) { - PyThreadState *tstate = PyThreadState_GET(); - return _Py_EnterRecursiveCall(tstate, where); -} - -#define Py_EnterRecursiveCall(where) _Py_EnterRecursiveCall_inline(where) - - -/* Compute the "lower-water mark" for a recursion limit. When - * Py_LeaveRecursiveCall() is called with a recursion depth below this mark, - * the overflowed flag is reset to 0. */ -#define _Py_RecursionLimitLowerWaterMark(limit) \ - (((limit) > 200) \ - ? ((limit) - 50) \ - : (3 * ((limit) >> 2))) - -#define _Py_MakeEndRecCheck(x) \ - (--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit)) - -static inline void _Py_LeaveRecursiveCall(PyThreadState *tstate) { - if (_Py_MakeEndRecCheck(tstate->recursion_depth)) { - tstate->overflowed = 0; - } -} - -static inline void _Py_LeaveRecursiveCall_inline(void) { - PyThreadState *tstate = PyThreadState_GET(); - _Py_LeaveRecursiveCall(tstate); -} - -#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_inline() - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 23d80916fde..ae6ef9aabac 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -56,6 +56,66 @@ extern PyObject *_PyEval_EvalCode( extern int _PyEval_ThreadsInitialized(_PyRuntimeState *runtime); extern PyStatus _PyEval_InitThreads(PyThreadState *tstate); + +/* --- _Py_EnterRecursiveCall() ----------------------------------------- */ + +PyAPI_DATA(int) _Py_CheckRecursionLimit; + +#ifdef USE_STACKCHECK +/* With USE_STACKCHECK macro defined, trigger stack checks in + _Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */ +static inline int _Py_MakeRecCheck(PyThreadState *tstate) { + return (++tstate->recursion_depth > _Py_CheckRecursionLimit + || ++tstate->stackcheck_counter > 64); +} +#else +static inline int _Py_MakeRecCheck(PyThreadState *tstate) { + return (++tstate->recursion_depth > _Py_CheckRecursionLimit); +} +#endif + +PyAPI_FUNC(int) _Py_CheckRecursiveCall( + PyThreadState *tstate, + const char *where); + +static inline int _Py_EnterRecursiveCall(PyThreadState *tstate, + const char *where) { + return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where)); +} + +static inline int _Py_EnterRecursiveCall_inline(const char *where) { + PyThreadState *tstate = PyThreadState_GET(); + return _Py_EnterRecursiveCall(tstate, where); +} + +#define Py_EnterRecursiveCall(where) _Py_EnterRecursiveCall_inline(where) + + +/* Compute the "lower-water mark" for a recursion limit. When + * Py_LeaveRecursiveCall() is called with a recursion depth below this mark, + * the overflowed flag is reset to 0. */ +#define _Py_RecursionLimitLowerWaterMark(limit) \ + (((limit) > 200) \ + ? ((limit) - 50) \ + : (3 * ((limit) >> 2))) + +#define _Py_MakeEndRecCheck(x) \ + (--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit)) + +static inline void _Py_LeaveRecursiveCall(PyThreadState *tstate) { + if (_Py_MakeEndRecCheck(tstate->recursion_depth)) { + tstate->overflowed = 0; + } +} + +static inline void _Py_LeaveRecursiveCall_inline(void) { + PyThreadState *tstate = PyThreadState_GET(); + _Py_LeaveRecursiveCall(tstate); +} + +#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_inline() + + #ifdef __cplusplus } #endif diff --git a/Misc/NEWS.d/next/C API/2020-03-13-00-15-19.bpo-39947.w3dIru.rst b/Misc/NEWS.d/next/C API/2020-03-13-00-15-19.bpo-39947.w3dIru.rst new file mode 100644 index 00000000000..f10161c06d4 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-03-13-00-15-19.bpo-39947.w3dIru.rst @@ -0,0 +1,4 @@ +Move the static inline function flavor of Py_EnterRecursiveCall() and +Py_LeaveRecursiveCall() to the internal C API: they access PyThreadState +attributes. The limited C API provides regular functions which hide +implementation details. diff --git a/Objects/abstract.c b/Objects/abstract.c index f9be4227890..02e4ad70718 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1,6 +1,7 @@ /* Abstract Object Interface (many thanks to Jim Fulton) */ #include "Python.h" +#include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_pyerrors.h" #include "pycore_pystate.h" #include diff --git a/Objects/descrobject.c b/Objects/descrobject.c index b448ec64268..cb7572b0d5d 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1,6 +1,7 @@ /* Descriptors -- a new, flexible way to describe attributes */ #include "Python.h" +#include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_object.h" #include "pycore_pystate.h" #include "pycore_tupleobject.h" diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 16abded3854..44ae00f7e00 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -2,6 +2,7 @@ /* Method object implementation */ #include "Python.h" +#include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pymem.h" diff --git a/Objects/object.c b/Objects/object.c index bb47cfa8585..72c4189d345 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2,6 +2,7 @@ /* Generic object operations; and implementation of None */ #include "Python.h" +#include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_context.h" #include "pycore_initconfig.h" #include "pycore_object.h"