Skip to content

Commit d716a0d

Browse files
authored
Use static inline function Py_EnterRecursiveCall() (#91988)
Currently, calling Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() may use a function call or a static inline function call, depending if the internal pycore_ceval.h header file is included or not. Use a different name for the static inline function to ensure that the static inline function is always used in Python internals for best performance. Similar approach than PyThreadState_GET() (function call) and _PyThreadState_GET() (static inline function). * Rename _Py_EnterRecursiveCall() to _Py_EnterRecursiveCallTstate() * Rename _Py_LeaveRecursiveCall() to _Py_LeaveRecursiveCallTstate() * pycore_ceval.h: Rename Py_EnterRecursiveCall() to _Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() and _Py_LeaveRecursiveCall()
1 parent 1424336 commit d716a0d

File tree

15 files changed

+524
-521
lines changed

15 files changed

+524
-521
lines changed

Include/internal/pycore_ceval.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ extern void _PyEval_DeactivateOpCache(void);
9191

9292
#ifdef USE_STACKCHECK
9393
/* With USE_STACKCHECK macro defined, trigger stack checks in
94-
_Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */
94+
_Py_CheckRecursiveCall() on every 64th call to _Py_EnterRecursiveCall. */
9595
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
9696
return (tstate->recursion_remaining-- <= 0
9797
|| (tstate->recursion_remaining & 63) == 0);
@@ -106,29 +106,25 @@ PyAPI_FUNC(int) _Py_CheckRecursiveCall(
106106
PyThreadState *tstate,
107107
const char *where);
108108

109-
static inline int _Py_EnterRecursiveCall(PyThreadState *tstate,
110-
const char *where) {
109+
static inline int _Py_EnterRecursiveCallTstate(PyThreadState *tstate,
110+
const char *where) {
111111
return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where));
112112
}
113113

114-
static inline int _Py_EnterRecursiveCall_inline(const char *where) {
114+
static inline int _Py_EnterRecursiveCall(const char *where) {
115115
PyThreadState *tstate = _PyThreadState_GET();
116-
return _Py_EnterRecursiveCall(tstate, where);
116+
return _Py_EnterRecursiveCallTstate(tstate, where);
117117
}
118118

119-
#define Py_EnterRecursiveCall(where) _Py_EnterRecursiveCall_inline(where)
120-
121-
static inline void _Py_LeaveRecursiveCall(PyThreadState *tstate) {
119+
static inline void _Py_LeaveRecursiveCallTstate(PyThreadState *tstate) {
122120
tstate->recursion_remaining++;
123121
}
124122

125-
static inline void _Py_LeaveRecursiveCall_inline(void) {
123+
static inline void _Py_LeaveRecursiveCall(void) {
126124
PyThreadState *tstate = _PyThreadState_GET();
127-
_Py_LeaveRecursiveCall(tstate);
125+
_Py_LeaveRecursiveCallTstate(tstate);
128126
}
129127

130-
#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_inline()
131-
132128
extern struct _PyInterpreterFrame* _PyEval_GetFrame(void);
133129

134130
extern PyObject* _Py_MakeCoro(PyFunctionObject *func);

Modules/_ctypes/_ctypes.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ bytes(cdata)
112112
#endif
113113

114114
#include "pycore_call.h" // _PyObject_CallNoArgs()
115+
#include "pycore_ceval.h" // _Py_EnterRecursiveCall()
115116
#include "structmember.h" // PyMemberDef
116117

117118
#include <ffi.h>
@@ -2270,12 +2271,12 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value)
22702271
return NULL;
22712272
}
22722273
if (as_parameter) {
2273-
if (Py_EnterRecursiveCall("while processing _as_parameter_")) {
2274+
if (_Py_EnterRecursiveCall("while processing _as_parameter_")) {
22742275
Py_DECREF(as_parameter);
22752276
return NULL;
22762277
}
22772278
value = PyCSimpleType_from_param(type, as_parameter);
2278-
Py_LeaveRecursiveCall();
2279+
_Py_LeaveRecursiveCall();
22792280
Py_DECREF(as_parameter);
22802281
return value;
22812282
}

Modules/_json.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define NEEDS_PY_IDENTIFIER
1111

1212
#include "Python.h"
13+
#include "pycore_ceval.h" // _Py_EnterRecursiveCall()
1314
#include "structmember.h" // PyMemberDef
1415
#include "pycore_accu.h"
1516

@@ -1059,19 +1060,19 @@ scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
10591060
return scanstring_unicode(pystr, idx + 1, s->strict, next_idx_ptr);
10601061
case '{':
10611062
/* object */
1062-
if (Py_EnterRecursiveCall(" while decoding a JSON object "
1063-
"from a unicode string"))
1063+
if (_Py_EnterRecursiveCall(" while decoding a JSON object "
1064+
"from a unicode string"))
10641065
return NULL;
10651066
res = _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr);
1066-
Py_LeaveRecursiveCall();
1067+
_Py_LeaveRecursiveCall();
10671068
return res;
10681069
case '[':
10691070
/* array */
1070-
if (Py_EnterRecursiveCall(" while decoding a JSON array "
1071-
"from a unicode string"))
1071+
if (_Py_EnterRecursiveCall(" while decoding a JSON array "
1072+
"from a unicode string"))
10721073
return NULL;
10731074
res = _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr);
1074-
Py_LeaveRecursiveCall();
1075+
_Py_LeaveRecursiveCall();
10751076
return res;
10761077
case 'n':
10771078
/* null */
@@ -1430,17 +1431,17 @@ encoder_listencode_obj(PyEncoderObject *s, _PyAccu *acc,
14301431
return _steal_accumulate(acc, encoded);
14311432
}
14321433
else if (PyList_Check(obj) || PyTuple_Check(obj)) {
1433-
if (Py_EnterRecursiveCall(" while encoding a JSON object"))
1434+
if (_Py_EnterRecursiveCall(" while encoding a JSON object"))
14341435
return -1;
14351436
rv = encoder_listencode_list(s, acc, obj, indent_level);
1436-
Py_LeaveRecursiveCall();
1437+
_Py_LeaveRecursiveCall();
14371438
return rv;
14381439
}
14391440
else if (PyDict_Check(obj)) {
1440-
if (Py_EnterRecursiveCall(" while encoding a JSON object"))
1441+
if (_Py_EnterRecursiveCall(" while encoding a JSON object"))
14411442
return -1;
14421443
rv = encoder_listencode_dict(s, acc, obj, indent_level);
1443-
Py_LeaveRecursiveCall();
1444+
_Py_LeaveRecursiveCall();
14441445
return rv;
14451446
}
14461447
else {
@@ -1468,13 +1469,13 @@ encoder_listencode_obj(PyEncoderObject *s, _PyAccu *acc,
14681469
return -1;
14691470
}
14701471

1471-
if (Py_EnterRecursiveCall(" while encoding a JSON object")) {
1472+
if (_Py_EnterRecursiveCall(" while encoding a JSON object")) {
14721473
Py_DECREF(newobj);
14731474
Py_XDECREF(ident);
14741475
return -1;
14751476
}
14761477
rv = encoder_listencode_obj(s, acc, newobj, indent_level);
1477-
Py_LeaveRecursiveCall();
1478+
_Py_LeaveRecursiveCall();
14781479

14791480
Py_DECREF(newobj);
14801481
if (rv) {

Modules/_pickle.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#endif
1010

1111
#include "Python.h"
12+
#include "pycore_ceval.h" // _Py_EnterRecursiveCall()
1213
#include "pycore_moduleobject.h" // _PyModule_GetState()
1314
#include "pycore_runtime.h" // _Py_ID()
1415
#include "pycore_pystate.h" // _PyThreadState_GET()
@@ -3068,21 +3069,21 @@ save_list(PicklerObject *self, PyObject *obj)
30683069
if (len != 0) {
30693070
/* Materialize the list elements. */
30703071
if (PyList_CheckExact(obj) && self->proto > 0) {
3071-
if (Py_EnterRecursiveCall(" while pickling an object"))
3072+
if (_Py_EnterRecursiveCall(" while pickling an object"))
30723073
goto error;
30733074
status = batch_list_exact(self, obj);
3074-
Py_LeaveRecursiveCall();
3075+
_Py_LeaveRecursiveCall();
30753076
} else {
30763077
PyObject *iter = PyObject_GetIter(obj);
30773078
if (iter == NULL)
30783079
goto error;
30793080

3080-
if (Py_EnterRecursiveCall(" while pickling an object")) {
3081+
if (_Py_EnterRecursiveCall(" while pickling an object")) {
30813082
Py_DECREF(iter);
30823083
goto error;
30833084
}
30843085
status = batch_list(self, iter);
3085-
Py_LeaveRecursiveCall();
3086+
_Py_LeaveRecursiveCall();
30863087
Py_DECREF(iter);
30873088
}
30883089
}
@@ -3327,10 +3328,10 @@ save_dict(PicklerObject *self, PyObject *obj)
33273328
if (PyDict_CheckExact(obj) && self->proto > 0) {
33283329
/* We can take certain shortcuts if we know this is a dict and
33293330
not a dict subclass. */
3330-
if (Py_EnterRecursiveCall(" while pickling an object"))
3331+
if (_Py_EnterRecursiveCall(" while pickling an object"))
33313332
goto error;
33323333
status = batch_dict_exact(self, obj);
3333-
Py_LeaveRecursiveCall();
3334+
_Py_LeaveRecursiveCall();
33343335
} else {
33353336
items = PyObject_CallMethodNoArgs(obj, &_Py_ID(items));
33363337
if (items == NULL)
@@ -3339,12 +3340,12 @@ save_dict(PicklerObject *self, PyObject *obj)
33393340
Py_DECREF(items);
33403341
if (iter == NULL)
33413342
goto error;
3342-
if (Py_EnterRecursiveCall(" while pickling an object")) {
3343+
if (_Py_EnterRecursiveCall(" while pickling an object")) {
33433344
Py_DECREF(iter);
33443345
goto error;
33453346
}
33463347
status = batch_dict(self, iter);
3347-
Py_LeaveRecursiveCall();
3348+
_Py_LeaveRecursiveCall();
33483349
Py_DECREF(iter);
33493350
}
33503351
}
@@ -4300,9 +4301,9 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
43004301
return save_unicode(self, obj);
43014302
}
43024303

4303-
/* We're only calling Py_EnterRecursiveCall here so that atomic
4304+
/* We're only calling _Py_EnterRecursiveCall here so that atomic
43044305
types above are pickled faster. */
4305-
if (Py_EnterRecursiveCall(" while pickling an object")) {
4306+
if (_Py_EnterRecursiveCall(" while pickling an object")) {
43064307
return -1;
43074308
}
43084309

@@ -4460,7 +4461,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
44604461
}
44614462
done:
44624463

4463-
Py_LeaveRecursiveCall();
4464+
_Py_LeaveRecursiveCall();
44644465
Py_XDECREF(reduce_func);
44654466
Py_XDECREF(reduce_value);
44664467

Objects/abstract.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "Python.h"
44
#include "pycore_abstract.h" // _PyIndex_Check()
55
#include "pycore_call.h" // _PyObject_CallNoArgs()
6-
#include "pycore_ceval.h" // _Py_EnterRecursiveCall()
6+
#include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate()
77
#include "pycore_object.h" // _Py_CheckSlotResult()
88
#include "pycore_pyerrors.h" // _PyErr_Occurred()
99
#include "pycore_pystate.h" // _PyThreadState_GET()
@@ -2546,7 +2546,7 @@ abstract_issubclass(PyObject *derived, PyObject *cls)
25462546
break;
25472547
}
25482548
assert(n >= 2);
2549-
if (Py_EnterRecursiveCall(" in __issubclass__")) {
2549+
if (_Py_EnterRecursiveCall(" in __issubclass__")) {
25502550
Py_DECREF(bases);
25512551
return -1;
25522552
}
@@ -2556,7 +2556,7 @@ abstract_issubclass(PyObject *derived, PyObject *cls)
25562556
break;
25572557
}
25582558
}
2559-
Py_LeaveRecursiveCall();
2559+
_Py_LeaveRecursiveCall();
25602560
Py_DECREF(bases);
25612561
return r;
25622562
}
@@ -2633,7 +2633,7 @@ object_recursive_isinstance(PyThreadState *tstate, PyObject *inst, PyObject *cls
26332633
if (PyTuple_Check(cls)) {
26342634
/* Not a general sequence -- that opens up the road to
26352635
recursion and stack overflow. */
2636-
if (_Py_EnterRecursiveCall(tstate, " in __instancecheck__")) {
2636+
if (_Py_EnterRecursiveCallTstate(tstate, " in __instancecheck__")) {
26372637
return -1;
26382638
}
26392639
Py_ssize_t n = PyTuple_GET_SIZE(cls);
@@ -2646,19 +2646,19 @@ object_recursive_isinstance(PyThreadState *tstate, PyObject *inst, PyObject *cls
26462646
break;
26472647
}
26482648
}
2649-
_Py_LeaveRecursiveCall(tstate);
2649+
_Py_LeaveRecursiveCallTstate(tstate);
26502650
return r;
26512651
}
26522652

26532653
PyObject *checker = _PyObject_LookupSpecial(cls, &_Py_ID(__instancecheck__));
26542654
if (checker != NULL) {
2655-
if (_Py_EnterRecursiveCall(tstate, " in __instancecheck__")) {
2655+
if (_Py_EnterRecursiveCallTstate(tstate, " in __instancecheck__")) {
26562656
Py_DECREF(checker);
26572657
return -1;
26582658
}
26592659

26602660
PyObject *res = PyObject_CallOneArg(checker, inst);
2661-
_Py_LeaveRecursiveCall(tstate);
2661+
_Py_LeaveRecursiveCallTstate(tstate);
26622662
Py_DECREF(checker);
26632663

26642664
if (res == NULL) {
@@ -2725,7 +2725,7 @@ object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls)
27252725

27262726
if (PyTuple_Check(cls)) {
27272727

2728-
if (_Py_EnterRecursiveCall(tstate, " in __subclasscheck__")) {
2728+
if (_Py_EnterRecursiveCallTstate(tstate, " in __subclasscheck__")) {
27292729
return -1;
27302730
}
27312731
Py_ssize_t n = PyTuple_GET_SIZE(cls);
@@ -2737,19 +2737,19 @@ object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls)
27372737
/* either found it, or got an error */
27382738
break;
27392739
}
2740-
_Py_LeaveRecursiveCall(tstate);
2740+
_Py_LeaveRecursiveCallTstate(tstate);
27412741
return r;
27422742
}
27432743

27442744
checker = _PyObject_LookupSpecial(cls, &_Py_ID(__subclasscheck__));
27452745
if (checker != NULL) {
27462746
int ok = -1;
2747-
if (_Py_EnterRecursiveCall(tstate, " in __subclasscheck__")) {
2747+
if (_Py_EnterRecursiveCallTstate(tstate, " in __subclasscheck__")) {
27482748
Py_DECREF(checker);
27492749
return ok;
27502750
}
27512751
PyObject *res = PyObject_CallOneArg(checker, derived);
2752-
_Py_LeaveRecursiveCall(tstate);
2752+
_Py_LeaveRecursiveCallTstate(tstate);
27532753
Py_DECREF(checker);
27542754
if (res != NULL) {
27552755
ok = PyObject_IsTrue(res);

Objects/bytesobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3489,7 +3489,7 @@ _PyBytesWriter_Alloc(_PyBytesWriter *writer, Py_ssize_t size)
34893489
Don't modify the _PyBytesWriter structure (use a shorter small buffer)
34903490
in debug mode to also be able to detect stack overflow when running
34913491
tests in debug mode. The _PyBytesWriter is large (more than 512 bytes),
3492-
if Py_EnterRecursiveCall() is not used in deep C callback, we may hit a
3492+
if _Py_EnterRecursiveCall() is not used in deep C callback, we may hit a
34933493
stack overflow. */
34943494
writer->allocated = Py_MIN(writer->allocated, 10);
34953495
/* _PyBytesWriter_CheckConsistency() requires the last byte to be 0,

Objects/call.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,11 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
209209
}
210210

211211
PyObject *result = NULL;
212-
if (_Py_EnterRecursiveCall(tstate, " while calling a Python object") == 0)
212+
if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object") == 0)
213213
{
214214
result = _PyCFunctionWithKeywords_TrampolineCall(
215215
(PyCFunctionWithKeywords)call, callable, argstuple, kwdict);
216-
_Py_LeaveRecursiveCall(tstate);
216+
_Py_LeaveRecursiveCallTstate(tstate);
217217
}
218218

219219
Py_DECREF(argstuple);
@@ -336,13 +336,13 @@ _PyObject_Call(PyThreadState *tstate, PyObject *callable,
336336
return NULL;
337337
}
338338

339-
if (_Py_EnterRecursiveCall(tstate, " while calling a Python object")) {
339+
if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
340340
return NULL;
341341
}
342342

343343
result = (*call)(callable, args, kwargs);
344344

345-
_Py_LeaveRecursiveCall(tstate);
345+
_Py_LeaveRecursiveCallTstate(tstate);
346346

347347
return _Py_CheckFunctionResult(tstate, callable, result, NULL);
348348
}

0 commit comments

Comments
 (0)