https://github.com/python/cpython/commit/54f74b80aef8b581f2b124d150903cec83aff005
commit: 54f74b80aef8b581f2b124d150903cec83aff005
branch: main
author: Mark Shannon <[email protected]>
committer: markshannon <[email protected]>
date: 2025-01-31T17:13:20Z
summary:

GH-128563: Move some labels, to simplify implementing tailcalling interpreter. 
(GH-129525)

files:
M Python/bytecodes.c
M Python/ceval.c
M Python/ceval_macros.h
M Python/generated_cases.c.h
M Tools/cases_generator/analyzer.py

diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index f659a5e5c920a7..effc8e0b6f6578 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -5303,14 +5303,40 @@ dummy_func(
                 tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
                 return NULL;
             }
-            goto resume_with_error;
+            next_instr = frame->instr_ptr;
+            stack_pointer = _PyFrame_GetStackPointer(frame);
+            goto error;
         }
 
-        label(resume_with_error) {
+        label(start_frame) {
+            if (_Py_EnterRecursivePy(tstate)) {
+                goto exit_unwind;
+            }
             next_instr = frame->instr_ptr;
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            goto error;
+
+        #ifdef LLTRACE
+            {
+                int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS());
+                frame->lltrace = lltrace;
+                if (lltrace < 0) {
+                    goto exit_unwind;
+                }
+            }
+        #endif
+
+        #ifdef Py_DEBUG
+            /* _PyEval_EvalFrameDefault() must not be called with an exception 
set,
+            because it can clear it (directly or indirectly) and so the
+            caller loses its exception */
+            assert(!_PyErr_Occurred(tstate));
+        #endif
+
+            DISPATCH();
         }
+
+
+
 // END BYTECODES //
 
     }
@@ -5320,7 +5346,6 @@ dummy_func(
  exit_unwind:
  handle_eval_breaker:
  resume_frame:
- resume_with_error:
  start_frame:
  unbound_local_error:
     ;
diff --git a/Python/ceval.c b/Python/ceval.c
index e3b87441f8088d..11518684c136bd 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -792,6 +792,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, 
_PyInterpreterFrame *frame, int
         return NULL;
     }
 
+    /* Local "register" variables.
+     * These are cached values from the frame and code object.  */
+    _Py_CODEUNIT *next_instr;
+    _PyStackRef *stack_pointer;
+
 #if defined(Py_DEBUG) && !defined(Py_STACKREF_DEBUG)
     /* Set these to invalid but identifiable values for debugging. */
     entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0};
@@ -819,67 +824,36 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, 
_PyInterpreterFrame *frame, int
     /* support for generator.throw() */
     if (throwflag) {
         if (_Py_EnterRecursivePy(tstate)) {
-            goto exit_unwind;
+            goto early_exit;
         }
-        /* Because this avoids the RESUME,
-         * we need to update instrumentation */
 #ifdef Py_GIL_DISABLED
         /* Load thread-local bytecode */
         if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) {
             _Py_CODEUNIT *bytecode =
                 _PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame));
             if (bytecode == NULL) {
-                goto exit_unwind;
+                goto early_exit;
             }
             ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(frame);
             frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index;
             frame->instr_ptr = bytecode + off;
         }
 #endif
+        /* Because this avoids the RESUME, we need to update instrumentation */
         _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
-        monitor_throw(tstate, frame, frame->instr_ptr);
-        /* TO DO -- Monitor throw entry. */
-        goto resume_with_error;
+        next_instr = frame->instr_ptr;
+        stack_pointer = _PyFrame_GetStackPointer(frame);
+        monitor_throw(tstate, frame, next_instr);
+        goto error;
     }
 
-    /* Local "register" variables.
-     * These are cached values from the frame and code object.  */
-    _Py_CODEUNIT *next_instr;
-    _PyStackRef *stack_pointer;
-
 #if defined(_Py_TIER2) && !defined(_Py_JIT)
     /* Tier 2 interpreter state */
     _PyExecutorObject *current_executor = NULL;
     const _PyUOpInstruction *next_uop = NULL;
 #endif
 
-start_frame:
-    if (_Py_EnterRecursivePy(tstate)) {
-        goto exit_unwind;
-    }
-
-    next_instr = frame->instr_ptr;
-resume_frame:
-    stack_pointer = _PyFrame_GetStackPointer(frame);
-
-#ifdef LLTRACE
-    {
-        int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS());
-        frame->lltrace = lltrace;
-        if (lltrace < 0) {
-            goto exit_unwind;
-        }
-    }
-#endif
-
-#ifdef Py_DEBUG
-    /* _PyEval_EvalFrameDefault() must not be called with an exception set,
-       because it can clear it (directly or indirectly) and so the
-       caller loses its exception */
-    assert(!_PyErr_Occurred(tstate));
-#endif
-
-    DISPATCH();
+    goto start_frame;
 
 #include "generated_cases.c.h"
 
@@ -983,10 +957,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, 
_PyInterpreterFrame *frame, int
     OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
     assert(next_uop[-1].format == UOP_FORMAT_TARGET);
     frame->return_offset = 0;  // Don't leave this random
-    _PyFrame_SetStackPointer(frame, stack_pointer);
     Py_DECREF(current_executor);
     tstate->previous_executor = NULL;
-    goto resume_with_error;
+    next_instr = frame->instr_ptr;
+    goto error;
 
 jump_to_jump_target:
     assert(next_uop[-1].format == UOP_FORMAT_JUMP);
@@ -1018,6 +992,20 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, 
_PyInterpreterFrame *frame, int
 
 #endif // _Py_TIER2
 
+early_exit:
+    assert(_PyErr_Occurred(tstate));
+    _Py_LeaveRecursiveCallPy(tstate);
+    assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
+    // GH-99729: We need to unlink the frame *before* clearing it:
+    _PyInterpreterFrame *dying = frame;
+    frame = tstate->current_frame = dying->previous;
+    _PyEval_FrameClearAndPop(tstate, dying);
+    frame->return_offset = 0;
+    assert(frame->owner == FRAME_OWNED_BY_INTERPRETER);
+    /* Restore previous frame and exit */
+    tstate->current_frame = frame->previous;
+    tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
+    return NULL;
 }
 
 #if defined(__GNUC__)
diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h
index 62c80c96e422fd..c2fc38f3c18e53 100644
--- a/Python/ceval_macros.h
+++ b/Python/ceval_macros.h
@@ -381,7 +381,9 @@ do {                                                   \
     tstate->previous_executor = NULL;                  \
     frame = tstate->current_frame;                     \
     if (next_instr == NULL) {                          \
-        goto resume_with_error;                        \
+        next_instr = frame->instr_ptr;                 \
+        stack_pointer = _PyFrame_GetStackPointer(frame); \
+        goto error;                                    \
     }                                                  \
     stack_pointer = _PyFrame_GetStackPointer(frame);   \
     DISPATCH();                                        \
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index ffdad70815caef..38ea63d71ab044 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -8703,14 +8703,36 @@
                 tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
                 return NULL;
             }
-            goto resume_with_error;
+            next_instr = frame->instr_ptr;
+            stack_pointer = _PyFrame_GetStackPointer(frame);
+            goto error;
         }
 
-        resume_with_error:
+        start_frame:
         {
+            if (_Py_EnterRecursivePy(tstate)) {
+                goto exit_unwind;
+            }
             next_instr = frame->instr_ptr;
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            goto error;
+            #ifdef LLTRACE
+            {
+                int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS());
+                frame->lltrace = lltrace;
+                if (lltrace < 0) {
+                    goto exit_unwind;
+                }
+            }
+            #endif
+
+            #ifdef Py_DEBUG
+            /* _PyEval_EvalFrameDefault() must not be called with an exception 
set,
+               because it can clear it (directly or indirectly) and so the
+               caller loses its exception */
+            assert(!_PyErr_Occurred(tstate));
+            #endif
+
+            DISPATCH();
         }
 
 /* END LABELS */
diff --git a/Tools/cases_generator/analyzer.py 
b/Tools/cases_generator/analyzer.py
index b9293ff4b19951..acf9458019fb4b 100644
--- a/Tools/cases_generator/analyzer.py
+++ b/Tools/cases_generator/analyzer.py
@@ -511,7 +511,6 @@ def has_error_with_pop(op: parser.InstDef) -> bool:
         variable_used(op, "ERROR_IF")
         or variable_used(op, "pop_1_error")
         or variable_used(op, "exception_unwind")
-        or variable_used(op, "resume_with_error")
     )
 
 
@@ -520,7 +519,6 @@ def has_error_without_pop(op: parser.InstDef) -> bool:
         variable_used(op, "ERROR_NO_POP")
         or variable_used(op, "pop_1_error")
         or variable_used(op, "exception_unwind")
-        or variable_used(op, "resume_with_error")
     )
 
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to