diff options
author | Mark Shannon <mark@hotpy.org> | 2021-11-16 11:01:57 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-16 11:01:57 (GMT) |
commit | b9310773756f40f77e075f221a90dd41e6964efc (patch) | |
tree | 43674ba9f42f2ff81dfd3025956b0ce8e12251f9 /Python/ceval.c | |
parent | 9bf2cbc4c498812e14f20d86acb61c53928a5a57 (diff) | |
download | cpython-b9310773756f40f77e075f221a90dd41e6964efc.zip cpython-b9310773756f40f77e075f221a90dd41e6964efc.tar.gz cpython-b9310773756f40f77e075f221a90dd41e6964efc.tar.bz2 |
bpo-45753: Make recursion checks more efficient. (GH-29524)
* Uses recursion remaining, instead of recursion depth to speed up check against recursion limit.
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index e808aee..bf4e22d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -785,42 +785,49 @@ Py_GetRecursionLimit(void) void Py_SetRecursionLimit(int new_limit) { - PyThreadState *tstate = _PyThreadState_GET(); - tstate->interp->ceval.recursion_limit = new_limit; + PyInterpreterState *interp = _PyInterpreterState_GET(); + interp->ceval.recursion_limit = new_limit; + for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) { + int depth = p->recursion_limit - p->recursion_remaining; + p->recursion_limit = new_limit; + p->recursion_remaining = new_limit - depth; + } } /* The function _Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall() - if the recursion_depth reaches recursion_limit. - If USE_STACKCHECK, the macro decrements recursion_limit - to guarantee that _Py_CheckRecursiveCall() is regularly called. - Without USE_STACKCHECK, there is no need for this. */ + if the recursion_depth reaches recursion_limit. */ int _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) { - int recursion_limit = tstate->interp->ceval.recursion_limit; - + /* Check against global limit first. */ + int depth = tstate->recursion_limit - tstate->recursion_remaining; + if (depth < tstate->interp->ceval.recursion_limit) { + tstate->recursion_limit = tstate->interp->ceval.recursion_limit; + tstate->recursion_remaining = tstate->recursion_limit - depth; + assert(tstate->recursion_remaining > 0); + return 0; + } #ifdef USE_STACKCHECK - tstate->stackcheck_counter = 0; if (PyOS_CheckStack()) { - --tstate->recursion_depth; + ++tstate->recursion_remaining; _PyErr_SetString(tstate, PyExc_MemoryError, "Stack overflow"); return -1; } #endif if (tstate->recursion_headroom) { - if (tstate->recursion_depth > recursion_limit + 50) { + if (tstate->recursion_remaining < -50) { /* Overflowing while handling an overflow. Give up. */ Py_FatalError("Cannot recover from stack overflow."); } } else { - if (tstate->recursion_depth > recursion_limit) { + if (tstate->recursion_remaining <= 0) { tstate->recursion_headroom++; _PyErr_Format(tstate, PyExc_RecursionError, "maximum recursion depth exceeded%s", where); tstate->recursion_headroom--; - --tstate->recursion_depth; + ++tstate->recursion_remaining; return -1; } } @@ -1582,7 +1589,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr start_frame: if (_Py_EnterRecursiveCall(tstate, "")) { - tstate->recursion_depth++; + tstate->recursion_remaining--; goto exit_eval_frame; } @@ -5688,13 +5695,13 @@ fail: static int _PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame) { - ++tstate->recursion_depth; + --tstate->recursion_remaining; assert(frame->frame_obj == NULL || frame->frame_obj->f_own_locals_memory == 0); if (_PyFrame_Clear(frame, 0)) { - --tstate->recursion_depth; + ++tstate->recursion_remaining; return -1; } - --tstate->recursion_depth; + ++tstate->recursion_remaining; _PyThreadState_PopFrame(tstate, frame); return 0; } |