https://github.com/python/cpython/commit/7099c75550c55050ac160cfe3519d49f2ef0c675
commit: 7099c75550c55050ac160cfe3519d49f2ef0c675
branch: main
author: Mark Shannon <m...@hotpy.org>
committer: markshannon <m...@hotpy.org>
date: 2025-04-04T17:59:36+01:00
summary:

GH-131498: Cases generator: manage stacks automatically (GH-132074)

files:
M Include/internal/pycore_opcode_metadata.h
M Include/internal/pycore_stackref.h
M Include/internal/pycore_structs.h
M Python/bytecodes.c
M Python/ceval.c
M Python/ceval_macros.h
M Python/executor_cases.c.h
M Python/generated_cases.c.h
M Python/optimizer_cases.c.h
M Python/stackrefs.c
M Tools/cases_generator/generators_common.py
M Tools/cases_generator/optimizer_generator.py
M Tools/cases_generator/stack.py
M Tools/cases_generator/tier1_generator.py
M Tools/cases_generator/tier2_generator.py

diff --git a/Include/internal/pycore_opcode_metadata.h 
b/Include/internal/pycore_opcode_metadata.h
index 5a165a5a3a2675..3a32967e721903 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -234,7 +234,7 @@ int _PyOpcode_num_popped(int opcode, int oparg)  {
         case INSTRUMENTED_END_SEND:
             return 2;
         case INSTRUMENTED_FOR_ITER:
-            return 0;
+            return 1;
         case INSTRUMENTED_INSTRUCTION:
             return 0;
         case INSTRUMENTED_JUMP_BACKWARD:
@@ -250,13 +250,13 @@ int _PyOpcode_num_popped(int opcode, int oparg)  {
         case INSTRUMENTED_POP_ITER:
             return 1;
         case INSTRUMENTED_POP_JUMP_IF_FALSE:
-            return 0;
+            return 1;
         case INSTRUMENTED_POP_JUMP_IF_NONE:
-            return 0;
+            return 1;
         case INSTRUMENTED_POP_JUMP_IF_NOT_NONE:
-            return 0;
+            return 1;
         case INSTRUMENTED_POP_JUMP_IF_TRUE:
-            return 0;
+            return 1;
         case INSTRUMENTED_RESUME:
             return 0;
         case INSTRUMENTED_RETURN_VALUE:
@@ -713,7 +713,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg)  {
         case INSTRUMENTED_END_SEND:
             return 1;
         case INSTRUMENTED_FOR_ITER:
-            return 0;
+            return 2;
         case INSTRUMENTED_INSTRUCTION:
             return 0;
         case INSTRUMENTED_JUMP_BACKWARD:
diff --git a/Include/internal/pycore_stackref.h 
b/Include/internal/pycore_stackref.h
index e6772c96eeb79c..5683b98470d3ea 100644
--- a/Include/internal/pycore_stackref.h
+++ b/Include/internal/pycore_stackref.h
@@ -4,11 +4,6 @@
 extern "C" {
 #endif
 
-// Define this to get precise tracking of closed stackrefs.
-// This will use unbounded memory, as it can only grow.
-// Use this to track double closes in short-lived programs
-// #define Py_STACKREF_CLOSE_DEBUG 1
-
 #ifndef Py_BUILD_CORE
 #  error "this header requires Py_BUILD_CORE define"
 #endif
diff --git a/Include/internal/pycore_structs.h 
b/Include/internal/pycore_structs.h
index b54d61197ad789..0d5f5dc7acc773 100644
--- a/Include/internal/pycore_structs.h
+++ b/Include/internal/pycore_structs.h
@@ -57,6 +57,12 @@ typedef struct {
 // Define this to get precise tracking of stackrefs.
 // #define Py_STACKREF_DEBUG 1
 
+// Define this to get precise tracking of closed stackrefs.
+// This will use unbounded memory, as it can only grow.
+// Use this to track double closes in short-lived programs
+// #define Py_STACKREF_CLOSE_DEBUG 1
+
+
 typedef union _PyStackRef {
 #if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG)
     uint64_t index;
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index b2900ba951a52f..a6cdc089d7a851 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -204,7 +204,7 @@ dummy_func(
                 ptrdiff_t off = this_instr - _PyFrame_GetBytecode(frame);
                 frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index;
                 frame->instr_ptr = bytecode + off;
-                // Make sure this_instr gets reset correctley for any uops that
+                // Make sure this_instr gets reset correctly for any uops that
                 // follow
                 next_instr = frame->instr_ptr;
                 DISPATCH();
@@ -1111,7 +1111,7 @@ dummy_func(
             tstate->current_frame = frame->previous;
             assert(!_PyErr_Occurred(tstate));
             PyObject *result = PyStackRef_AsPyObjectSteal(retval);
-            SYNC_SP(); /* Not strictly necessary, but prevents warnings */
+            LLTRACE_RESUME_FRAME();
             return result;
         }
 
@@ -1123,7 +1123,7 @@ dummy_func(
             _PyStackRef temp = PyStackRef_MakeHeapSafe(retval);
             DEAD(retval);
             SAVE_STACK();
-            assert(EMPTY());
+            assert(STACK_LEVEL() == 0);
             _Py_LeaveRecursiveCallPy(tstate);
             // GH-99729: We need to unlink the frame *before* clearing it:
             _PyInterpreterFrame *dying = frame;
@@ -1223,8 +1223,9 @@ dummy_func(
             {
                 PyGenObject *gen = (PyGenObject *)receiver_o;
                 _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
-                STACK_SHRINK(1);
                 _PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v));
+                DEAD(v);
+                SYNC_SP();
                 gen->gi_frame_state = FRAME_EXECUTING;
                 gen->gi_exc_state.previous_item = tstate->exc_info;
                 tstate->exc_info = &gen->gi_exc_state;
@@ -2436,10 +2437,10 @@ dummy_func(
             PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
             _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(
                 tstate, PyStackRef_FromPyObjectNew(f), 2, frame);
-            // Manipulate stack directly because we exit with 
DISPATCH_INLINED().
-            STACK_SHRINK(1);
             new_frame->localsplus[0] = owner;
             DEAD(owner);
+            // Manipulate stack directly because we exit with 
DISPATCH_INLINED().
+            SYNC_SP();
             new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name);
             frame->return_offset = INSTRUCTION_SIZE;
             DISPATCH_INLINED(new_frame);
@@ -3083,12 +3084,11 @@ dummy_func(
         macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER;
 
 
-        inst(INSTRUMENTED_FOR_ITER, (unused/1 -- )) {
-            _PyStackRef iter_stackref = TOP();
-            PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref);
-            PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
-            if (next != NULL) {
-                PUSH(PyStackRef_FromPyObjectSteal(next));
+        inst(INSTRUMENTED_FOR_ITER, (unused/1, iter -- iter, next)) {
+            PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
+            PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
+            if (next_o != NULL) {
+                next = PyStackRef_FromPyObjectSteal(next_o);
                 INSTRUMENTED_JUMP(this_instr, next_instr, 
PY_MONITORING_EVENT_BRANCH_LEFT);
             }
             else {
@@ -3105,6 +3105,7 @@ dummy_func(
                        next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
                 /* Skip END_FOR */
                 JUMPBY(oparg + 1);
+                DISPATCH();
             }
         }
 
@@ -4022,7 +4023,6 @@ dummy_func(
             _PUSH_FRAME;
 
         inst(EXIT_INIT_CHECK, (should_be_none -- )) {
-            assert(STACK_LEVEL() == 2);
             if (!PyStackRef_IsNone(should_be_none)) {
                 PyErr_Format(PyExc_TypeError,
                     "__init__() should return None, not '%.200s'",
@@ -4813,7 +4813,7 @@ dummy_func(
             PyFunctionObject *func = (PyFunctionObject 
*)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
             PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
             ERROR_IF(gen == NULL, error);
-            assert(EMPTY());
+            assert(STACK_LEVEL() == 0);
             SAVE_STACK();
             _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
             frame->instr_ptr++;
@@ -4932,6 +4932,7 @@ dummy_func(
                 }
                 next_instr = frame->instr_ptr;
                 if (next_instr != this_instr) {
+                    SYNC_SP();
                     DISPATCH();
                 }
             }
@@ -4976,46 +4977,48 @@ dummy_func(
             _CHECK_PERIODIC +
             _MONITOR_JUMP_BACKWARD;
 
-        inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1 -- )) {
-            _PyStackRef cond = POP();
+        inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1, cond -- )) {
             assert(PyStackRef_BoolCheck(cond));
             int jump = PyStackRef_IsTrue(cond);
+            DEAD(cond);
             RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
             if (jump) {
                 INSTRUMENTED_JUMP(this_instr, next_instr + oparg, 
PY_MONITORING_EVENT_BRANCH_RIGHT);
             }
         }
 
-        inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1 -- )) {
-            _PyStackRef cond = POP();
+        inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1, cond -- )) {
             assert(PyStackRef_BoolCheck(cond));
             int jump = PyStackRef_IsFalse(cond);
+            DEAD(cond);
             RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
             if (jump) {
                 INSTRUMENTED_JUMP(this_instr, next_instr + oparg, 
PY_MONITORING_EVENT_BRANCH_RIGHT);
             }
         }
 
-        inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1 -- )) {
-            _PyStackRef value_stackref = POP();
-            int jump = PyStackRef_IsNone(value_stackref);
+        inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1, value -- )) {
+            int jump = PyStackRef_IsNone(value);
             RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
             if (jump) {
+                DEAD(value);
                 INSTRUMENTED_JUMP(this_instr, next_instr + oparg, 
PY_MONITORING_EVENT_BRANCH_RIGHT);
             }
             else {
-                PyStackRef_CLOSE(value_stackref);
+                PyStackRef_CLOSE(value);
             }
         }
 
-        inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1 -- )) {
-            _PyStackRef value_stackref = POP();
-            int jump = !PyStackRef_IsNone(value_stackref);
+        inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1, value -- )) {
+            int jump = !PyStackRef_IsNone(value);
             RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
             if (jump) {
-                PyStackRef_CLOSE(value_stackref);
+                PyStackRef_CLOSE(value);
                 INSTRUMENTED_JUMP(this_instr, next_instr + oparg, 
PY_MONITORING_EVENT_BRANCH_RIGHT);
             }
+            else {
+                DEAD(value);
+            }
         }
 
         tier1 inst(EXTENDED_ARG, ( -- )) {
@@ -5219,22 +5222,26 @@ dummy_func(
         }
 
         label(pop_4_error) {
-            STACK_SHRINK(4);
+            stack_pointer -= 4;
+            assert(WITHIN_STACK_BOUNDS());
             goto error;
         }
 
         label(pop_3_error) {
-            STACK_SHRINK(3);
+            stack_pointer -= 3;
+            assert(WITHIN_STACK_BOUNDS());
             goto error;
         }
 
         label(pop_2_error) {
-            STACK_SHRINK(2);
+            stack_pointer -= 2;
+            assert(WITHIN_STACK_BOUNDS());
             goto error;
         }
 
         label(pop_1_error) {
-            STACK_SHRINK(1);
+            stack_pointer -= 1;
+            assert(WITHIN_STACK_BOUNDS());
             goto error;
         }
 
diff --git a/Python/ceval.c b/Python/ceval.c
index add8c2a28c74e3..a59b2b7a16866d 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -151,18 +151,6 @@ dump_item(_PyStackRef item)
         printf("<nil>");
         return;
     }
-    if (
-        obj == Py_None
-        || PyBool_Check(obj)
-        || PyLong_CheckExact(obj)
-        || PyFloat_CheckExact(obj)
-        || PyUnicode_CheckExact(obj)
-    ) {
-        if (PyObject_Print(obj, stdout, 0) == 0) {
-            return;
-        }
-        PyErr_Clear();
-    }
     // Don't call __repr__(), it might recurse into the interpreter.
     printf("<%s at %p>", Py_TYPE(obj)->tp_name, (void *)obj);
 }
@@ -182,14 +170,19 @@ dump_stack(_PyInterpreterFrame *frame, _PyStackRef 
*stack_pointer)
         dump_item(*ptr);
     }
     printf("]\n");
-    printf("    stack=[");
-    for (_PyStackRef *ptr = stack_base; ptr < stack_pointer; ptr++) {
-        if (ptr != stack_base) {
-            printf(", ");
+    if (stack_pointer < stack_base) {
+        printf("    stack=%d\n", (int)(stack_pointer-stack_base));
+    }
+    else {
+        printf("    stack=[");
+        for (_PyStackRef *ptr = stack_base; ptr < stack_pointer; ptr++) {
+            if (ptr != stack_base) {
+                printf(", ");
+            }
+            dump_item(*ptr);
         }
-        dump_item(*ptr);
+        printf("]\n");
     }
-    printf("]\n");
     fflush(stdout);
     PyErr_SetRaisedException(exc);
     _PyFrame_GetStackPointer(frame);
@@ -202,13 +195,13 @@ lltrace_instruction(_PyInterpreterFrame *frame,
                     int opcode,
                     int oparg)
 {
-    if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) {
-        return;
+    int offset = 0;
+    if (frame->owner < FRAME_OWNED_BY_INTERPRETER) {
+        dump_stack(frame, stack_pointer);
+        offset = (int)(next_instr - _PyFrame_GetBytecode(frame));
     }
-    dump_stack(frame, stack_pointer);
     const char *opname = _PyOpcode_OpName[opcode];
     assert(opname != NULL);
-    int offset = (int)(next_instr - _PyFrame_GetBytecode(frame));
     if (OPCODE_HAS_ARG((int)_PyOpcode_Deopt[opcode])) {
         printf("%d: %s %d\n", offset * 2, opname, oparg);
     }
@@ -986,8 +979,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, 
_PyInterpreterFrame *frame, int
      * 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)
+    entry_frame.localsplus[0] = PyStackRef_NULL;
+#ifdef Py_STACKREF_DEBUG
+    entry_frame.f_funcobj = PyStackRef_None;
+#elif defined(Py_DEBUG)
     /* Set these to invalid but identifiable values for debugging. */
     entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0};
     entry_frame.f_locals = (PyObject*)0xaaa1;
@@ -1044,7 +1039,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, 
_PyInterpreterFrame *frame, int
     _PyExecutorObject *current_executor = NULL;
     const _PyUOpInstruction *next_uop = NULL;
 #endif
-
 #if Py_TAIL_CALL_INTERP
     return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0);
 #else
diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h
index f19ffd23161ace..3dca4e46ee75e4 100644
--- a/Python/ceval_macros.h
+++ b/Python/ceval_macros.h
@@ -194,48 +194,8 @@ GETITEM(PyObject *v, Py_ssize_t i) {
 #define JUMPBY(x)       (next_instr += (x))
 #define SKIP_OVER(x)    (next_instr += (x))
 
-
-/* Stack manipulation macros */
-
-/* The stack can grow at most MAXINT deep, as co_nlocals and
-   co_stacksize are ints. */
 #define STACK_LEVEL()     ((int)(stack_pointer - _PyFrame_Stackbase(frame)))
 #define STACK_SIZE()      (_PyFrame_GetCode(frame)->co_stacksize)
-#define EMPTY()           (STACK_LEVEL() == 0)
-#define TOP()             (stack_pointer[-1])
-#define SECOND()          (stack_pointer[-2])
-#define THIRD()           (stack_pointer[-3])
-#define FOURTH()          (stack_pointer[-4])
-#define PEEK(n)           (stack_pointer[-(n)])
-#define POKE(n, v)        (stack_pointer[-(n)] = (v))
-#define SET_TOP(v)        (stack_pointer[-1] = (v))
-#define SET_SECOND(v)     (stack_pointer[-2] = (v))
-#define BASIC_STACKADJ(n) (stack_pointer += n)
-#define BASIC_PUSH(v)     (*stack_pointer++ = (v))
-#define BASIC_POP()       (*--stack_pointer)
-
-#ifdef Py_DEBUG
-#define PUSH(v)         do { \
-                            BASIC_PUSH(v); \
-                            assert(STACK_LEVEL() <= STACK_SIZE()); \
-                        } while (0)
-#define POP()           (assert(STACK_LEVEL() > 0), BASIC_POP())
-#define STACK_GROW(n)   do { \
-                            assert(n >= 0); \
-                            BASIC_STACKADJ(n); \
-                            assert(STACK_LEVEL() <= STACK_SIZE()); \
-                        } while (0)
-#define STACK_SHRINK(n) do { \
-                            assert(n >= 0); \
-                            assert(STACK_LEVEL() >= n); \
-                            BASIC_STACKADJ(-(n)); \
-                        } while (0)
-#else
-#define PUSH(v)                BASIC_PUSH(v)
-#define POP()                  BASIC_POP()
-#define STACK_GROW(n)          BASIC_STACKADJ(n)
-#define STACK_SHRINK(n)        BASIC_STACKADJ(-(n))
-#endif
 
 #define WITHIN_STACK_BOUNDS() \
    (frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && 
STACK_LEVEL() <= STACK_SIZE()))
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index ccdf74a575baa2..c0422d87bfd78b 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -714,7 +714,6 @@
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 res = PyStackRef_True;
                 stack_pointer += 1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -798,7 +797,6 @@
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 res = PyStackRef_True;
                 stack_pointer += 1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -1206,7 +1204,6 @@
                 Py_DECREF(slice);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 stack_pointer += 2;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer += -3;
             assert(WITHIN_STACK_BOUNDS());
@@ -1248,21 +1245,18 @@
                 Py_DECREF(slice);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 stack_pointer += 2;
-                assert(WITHIN_STACK_BOUNDS());
             }
-            stack_pointer += -2;
-            assert(WITHIN_STACK_BOUNDS());
             _PyFrame_SetStackPointer(frame, stack_pointer);
             _PyStackRef tmp = container;
             container = PyStackRef_NULL;
-            stack_pointer[-1] = container;
+            stack_pointer[-3] = container;
             PyStackRef_CLOSE(tmp);
             tmp = v;
             v = PyStackRef_NULL;
-            stack_pointer[-2] = v;
+            stack_pointer[-4] = v;
             PyStackRef_CLOSE(tmp);
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            stack_pointer += -2;
+            stack_pointer += -4;
             assert(WITHIN_STACK_BOUNDS());
             if (err) {
                 JUMP_TO_ERROR();
@@ -1732,7 +1726,7 @@
             stack_pointer += -1;
             assert(WITHIN_STACK_BOUNDS());
             _PyFrame_SetStackPointer(frame, stack_pointer);
-            assert(EMPTY());
+            assert(STACK_LEVEL() == 0);
             _Py_LeaveRecursiveCallPy(tstate);
             _PyInterpreterFrame *dying = frame;
             frame = tstate->current_frame = dying->previous;
@@ -2073,7 +2067,6 @@
             _PyFrame_SetStackPointer(frame, stack_pointer);
             PyStackRef_CLOSE(seq);
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            stack_pointer[-1] = val0;
             break;
         }
 
@@ -3004,7 +2997,6 @@
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 self_or_null = PyStackRef_NULL;
                 stack_pointer += 1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer += -1;
             assert(WITHIN_STACK_BOUNDS());
@@ -3057,7 +3049,6 @@
                     }
                     self_or_null[0] = PyStackRef_NULL;
                     stack_pointer += 1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             else {
@@ -3073,7 +3064,6 @@
                     JUMP_TO_ERROR();
                 }
                 stack_pointer += 1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             attr = PyStackRef_FromPyObjectSteal(attr_o);
             stack_pointer[-1] = attr;
@@ -5289,7 +5279,6 @@
         case _EXIT_INIT_CHECK: {
             _PyStackRef should_be_none;
             should_be_none = stack_pointer[-1];
-            assert(STACK_LEVEL() == 2);
             if (!PyStackRef_IsNone(should_be_none)) {
                 _PyFrame_SetStackPointer(frame, stack_pointer);
                 PyErr_Format(PyExc_TypeError,
@@ -6347,7 +6336,6 @@
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 tuple = PyStackRef_FromPyObjectSteal(tuple_o);
                 stack_pointer += 2;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-2] = tuple;
             stack_pointer[-1] = kwargs_out;
@@ -6414,7 +6402,7 @@
             if (gen == NULL) {
                 JUMP_TO_ERROR();
             }
-            assert(EMPTY());
+            assert(STACK_LEVEL() == 0);
             _PyFrame_SetStackPointer(frame, stack_pointer);
             _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
             frame->instr_ptr++;
@@ -6513,7 +6501,6 @@
             else {
                 res = value;
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[0] = res;
             stack_pointer += 1;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index c75371d12b0ba1..4a3884b9568b98 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -1062,7 +1062,6 @@
                     Py_DECREF(slice);
                     stack_pointer = _PyFrame_GetStackPointer(frame);
                     stack_pointer += 2;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
                 stack_pointer += -3;
                 assert(WITHIN_STACK_BOUNDS());
@@ -1498,7 +1497,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -1983,7 +1981,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -2097,7 +2094,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -2212,7 +2208,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -2305,7 +2300,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -2366,7 +2360,6 @@
                     stack_pointer = _PyFrame_GetStackPointer(frame);
                     tuple = PyStackRef_FromPyObjectSteal(tuple_o);
                     stack_pointer += 2;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             // _DO_CALL_FUNCTION_EX
@@ -2494,7 +2487,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = result;
@@ -2736,7 +2728,6 @@
                 }
                 STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
                 if (CONVERSION_FAILED(args_o)) {
-                    stack_pointer[-1] = kwnames;
                     _PyFrame_SetStackPointer(frame, stack_pointer);
                     _PyStackRef tmp = kwnames;
                     kwnames = PyStackRef_NULL;
@@ -3070,7 +3061,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -3422,7 +3412,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -3544,7 +3533,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -3646,7 +3634,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -3759,7 +3746,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -3879,7 +3865,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -4154,7 +4139,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -4227,7 +4211,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -5310,7 +5293,6 @@
             INSTRUCTION_STATS(EXIT_INIT_CHECK);
             _PyStackRef should_be_none;
             should_be_none = stack_pointer[-1];
-            assert(STACK_LEVEL() == 2);
             if (!PyStackRef_IsNone(should_be_none)) {
                 _PyFrame_SetStackPointer(frame, stack_pointer);
                 PyErr_Format(PyExc_TypeError,
@@ -5369,7 +5351,6 @@
             else {
                 res = value;
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[0] = res;
             stack_pointer += 1;
@@ -6130,8 +6111,9 @@
             }
             // _DO_CALL
             {
-                self_or_null = maybe_self;
-                callable = func;
+                args = &stack_pointer[-oparg];
+                self_or_null = &stack_pointer[-1 - oparg];
+                callable = &stack_pointer[-2 - oparg];
                 PyObject *callable_o = 
PyStackRef_AsPyObjectBorrow(callable[0]);
                 int total_args = oparg;
                 _PyStackRef *arguments = args;
@@ -6246,7 +6228,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = res;
@@ -6307,7 +6288,6 @@
                     stack_pointer = _PyFrame_GetStackPointer(frame);
                     tuple = PyStackRef_FromPyObjectSteal(tuple_o);
                     stack_pointer += 2;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             // _DO_CALL_FUNCTION_EX
@@ -6435,7 +6415,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += -1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[0] = result;
@@ -6753,14 +6732,16 @@
             frame->instr_ptr = next_instr;
             next_instr += 2;
             INSTRUCTION_STATS(INSTRUMENTED_FOR_ITER);
+            _PyStackRef iter;
+            _PyStackRef next;
             /* Skip 1 cache entry */
-            _PyStackRef iter_stackref = TOP();
-            PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref);
+            iter = stack_pointer[-1];
+            PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
             _PyFrame_SetStackPointer(frame, stack_pointer);
-            PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
+            PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            if (next != NULL) {
-                PUSH(PyStackRef_FromPyObjectSteal(next));
+            if (next_o != NULL) {
+                next = PyStackRef_FromPyObjectSteal(next_o);
                 INSTRUMENTED_JUMP(this_instr, next_instr, 
PY_MONITORING_EVENT_BRANCH_LEFT);
             }
             else {
@@ -6779,7 +6760,11 @@
                 assert(next_instr[oparg].op.code == END_FOR ||
                        next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
                 JUMPBY(oparg + 1);
+                DISPATCH();
             }
+            stack_pointer[0] = next;
+            stack_pointer += 1;
+            assert(WITHIN_STACK_BOUNDS());
             DISPATCH();
         }
 
@@ -7063,14 +7048,17 @@
             frame->instr_ptr = next_instr;
             next_instr += 2;
             INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_FALSE);
+            _PyStackRef cond;
             /* Skip 1 cache entry */
-            _PyStackRef cond = POP();
+            cond = stack_pointer[-1];
             assert(PyStackRef_BoolCheck(cond));
             int jump = PyStackRef_IsFalse(cond);
             RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
             if (jump) {
                 INSTRUMENTED_JUMP(this_instr, next_instr + oparg, 
PY_MONITORING_EVENT_BRANCH_RIGHT);
             }
+            stack_pointer += -1;
+            assert(WITHIN_STACK_BOUNDS());
             DISPATCH();
         }
 
@@ -7084,18 +7072,24 @@
             frame->instr_ptr = next_instr;
             next_instr += 2;
             INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NONE);
+            _PyStackRef value;
             /* Skip 1 cache entry */
-            _PyStackRef value_stackref = POP();
-            int jump = PyStackRef_IsNone(value_stackref);
+            value = stack_pointer[-1];
+            int jump = PyStackRef_IsNone(value);
             RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
             if (jump) {
                 INSTRUMENTED_JUMP(this_instr, next_instr + oparg, 
PY_MONITORING_EVENT_BRANCH_RIGHT);
             }
             else {
+                stack_pointer += -1;
+                assert(WITHIN_STACK_BOUNDS());
                 _PyFrame_SetStackPointer(frame, stack_pointer);
-                PyStackRef_CLOSE(value_stackref);
+                PyStackRef_CLOSE(value);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
+                stack_pointer += 1;
             }
+            stack_pointer += -1;
+            assert(WITHIN_STACK_BOUNDS());
             DISPATCH();
         }
 
@@ -7109,16 +7103,22 @@
             frame->instr_ptr = next_instr;
             next_instr += 2;
             INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NOT_NONE);
+            _PyStackRef value;
             /* Skip 1 cache entry */
-            _PyStackRef value_stackref = POP();
-            int jump = !PyStackRef_IsNone(value_stackref);
+            value = stack_pointer[-1];
+            int jump = !PyStackRef_IsNone(value);
             RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
             if (jump) {
+                stack_pointer += -1;
+                assert(WITHIN_STACK_BOUNDS());
                 _PyFrame_SetStackPointer(frame, stack_pointer);
-                PyStackRef_CLOSE(value_stackref);
+                PyStackRef_CLOSE(value);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 INSTRUMENTED_JUMP(this_instr, next_instr + oparg, 
PY_MONITORING_EVENT_BRANCH_RIGHT);
             }
+            else {
+                stack_pointer += -1;
+            }
             DISPATCH();
         }
 
@@ -7132,14 +7132,17 @@
             frame->instr_ptr = next_instr;
             next_instr += 2;
             INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_TRUE);
+            _PyStackRef cond;
             /* Skip 1 cache entry */
-            _PyStackRef cond = POP();
+            cond = stack_pointer[-1];
             assert(PyStackRef_BoolCheck(cond));
             int jump = PyStackRef_IsTrue(cond);
             RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
             if (jump) {
                 INSTRUMENTED_JUMP(this_instr, next_instr + oparg, 
PY_MONITORING_EVENT_BRANCH_RIGHT);
             }
+            stack_pointer += -1;
+            assert(WITHIN_STACK_BOUNDS());
             DISPATCH();
         }
 
@@ -7254,7 +7257,7 @@
                 stack_pointer += -1;
                 assert(WITHIN_STACK_BOUNDS());
                 _PyFrame_SetStackPointer(frame, stack_pointer);
-                assert(EMPTY());
+                assert(STACK_LEVEL() == 0);
                 _Py_LeaveRecursiveCallPy(tstate);
                 _PyInterpreterFrame *dying = frame;
                 frame = tstate->current_frame = dying->previous;
@@ -7353,9 +7356,11 @@
             tstate->current_frame = frame->previous;
             assert(!_PyErr_Occurred(tstate));
             PyObject *result = PyStackRef_AsPyObjectSteal(retval);
+            LLTRACE_RESUME_FRAME();
+            return result;
             stack_pointer += -1;
             assert(WITHIN_STACK_BOUNDS());
-            return result;
+            DISPATCH();
         }
 
         TARGET(IS_OP) {
@@ -7684,7 +7689,6 @@
                         }
                         self_or_null[0] = PyStackRef_NULL;
                         stack_pointer += 1;
-                        assert(WITHIN_STACK_BOUNDS());
                     }
                 }
                 else {
@@ -7700,7 +7704,6 @@
                         JUMP_TO_LABEL(error);
                     }
                     stack_pointer += 1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
                 attr = PyStackRef_FromPyObjectSteal(attr_o);
             }
@@ -7886,8 +7889,9 @@
             PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
             _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(
                 tstate, PyStackRef_FromPyObjectNew(f), 2, frame);
-            STACK_SHRINK(1);
             new_frame->localsplus[0] = owner;
+            stack_pointer += -1;
+            assert(WITHIN_STACK_BOUNDS());
             new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name);
             frame->return_offset = 10 ;
             DISPATCH_INLINED(new_frame);
@@ -9551,7 +9555,6 @@
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 self_or_null = PyStackRef_NULL;
                 stack_pointer += 1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer += -1;
             assert(WITHIN_STACK_BOUNDS());
@@ -10243,7 +10246,7 @@
             if (gen == NULL) {
                 JUMP_TO_LABEL(error);
             }
-            assert(EMPTY());
+            assert(STACK_LEVEL() == 0);
             _PyFrame_SetStackPointer(frame, stack_pointer);
             _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
             frame->instr_ptr++;
@@ -10281,7 +10284,7 @@
             stack_pointer += -1;
             assert(WITHIN_STACK_BOUNDS());
             _PyFrame_SetStackPointer(frame, stack_pointer);
-            assert(EMPTY());
+            assert(STACK_LEVEL() == 0);
             _Py_LeaveRecursiveCallPy(tstate);
             _PyInterpreterFrame *dying = frame;
             frame = tstate->current_frame = dying->previous;
@@ -10339,8 +10342,9 @@
                 {
                     PyGenObject *gen = (PyGenObject *)receiver_o;
                     _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
-                    STACK_SHRINK(1);
                     _PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v));
+                    stack_pointer += -1;
+                    assert(WITHIN_STACK_BOUNDS());
                     gen->gi_frame_state = FRAME_EXECUTING;
                     gen->gi_exc_state.previous_item = tstate->exc_info;
                     tstate->exc_info = &gen->gi_exc_state;
@@ -11095,21 +11099,18 @@
                     Py_DECREF(slice);
                     stack_pointer = _PyFrame_GetStackPointer(frame);
                     stack_pointer += 2;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
-                stack_pointer += -2;
-                assert(WITHIN_STACK_BOUNDS());
                 _PyFrame_SetStackPointer(frame, stack_pointer);
                 _PyStackRef tmp = container;
                 container = PyStackRef_NULL;
-                stack_pointer[-1] = container;
+                stack_pointer[-3] = container;
                 PyStackRef_CLOSE(tmp);
                 tmp = v;
                 v = PyStackRef_NULL;
-                stack_pointer[-2] = v;
+                stack_pointer[-4] = v;
                 PyStackRef_CLOSE(tmp);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
-                stack_pointer += -2;
+                stack_pointer += -4;
                 assert(WITHIN_STACK_BOUNDS());
                 if (err) {
                     JUMP_TO_LABEL(error);
@@ -11465,7 +11466,6 @@
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 res = PyStackRef_True;
                 stack_pointer += 1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             DISPATCH();
@@ -11573,7 +11573,6 @@
                     stack_pointer = _PyFrame_GetStackPointer(frame);
                     res = PyStackRef_True;
                     stack_pointer += 1;
-                    assert(WITHIN_STACK_BOUNDS());
                 }
             }
             stack_pointer[-1] = res;
@@ -11861,7 +11860,6 @@
             _PyFrame_SetStackPointer(frame, stack_pointer);
             PyStackRef_CLOSE(seq);
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            stack_pointer[-1] = val0;
             DISPATCH();
         }
 
@@ -11984,25 +11982,29 @@ JUMP_TO_LABEL(error);
 
         LABEL(pop_4_error)
         {
-            STACK_SHRINK(4);
+            stack_pointer -= 4;
+            assert(WITHIN_STACK_BOUNDS());
             JUMP_TO_LABEL(error);
         }
 
         LABEL(pop_3_error)
         {
-            STACK_SHRINK(3);
+            stack_pointer -= 3;
+            assert(WITHIN_STACK_BOUNDS());
             JUMP_TO_LABEL(error);
         }
 
         LABEL(pop_2_error)
         {
-            STACK_SHRINK(2);
+            stack_pointer -= 2;
+            assert(WITHIN_STACK_BOUNDS());
             JUMP_TO_LABEL(error);
         }
 
         LABEL(pop_1_error)
         {
-            STACK_SHRINK(1);
+            stack_pointer -= 1;
+            assert(WITHIN_STACK_BOUNDS());
             JUMP_TO_LABEL(error);
         }
 
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index ea25b8224a459b..f5cd1697fbacda 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -310,7 +310,6 @@
             else {
                 res = sym_new_type(ctx, &PyLong_Type);
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -339,7 +338,6 @@
             else {
                 res = sym_new_type(ctx, &PyLong_Type);
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -368,7 +366,6 @@
             else {
                 res = sym_new_type(ctx, &PyLong_Type);
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -418,7 +415,6 @@
             else {
                 res = sym_new_type(ctx, &PyFloat_Type);
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -448,7 +444,6 @@
             else {
                 res = sym_new_type(ctx, &PyFloat_Type);
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -478,7 +473,6 @@
             else {
                 res = sym_new_type(ctx, &PyFloat_Type);
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -506,7 +500,6 @@
             else {
                 res = sym_new_type(ctx, &PyUnicode_Type);
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -1257,7 +1250,6 @@
             else {
                 res = sym_new_type(ctx, &PyBool_Type);
                 stack_pointer += -1;
-                assert(WITHIN_STACK_BOUNDS());
             }
             stack_pointer[-1] = res;
             break;
@@ -2031,7 +2023,6 @@
             if (co == NULL) {
                 ctx->done = true;
             }
-            stack_pointer[-1] = res;
             break;
         }
 
diff --git a/Python/stackrefs.c b/Python/stackrefs.c
index 450dacde6d29e5..1a2f66feb04c4d 100644
--- a/Python/stackrefs.c
+++ b/Python/stackrefs.c
@@ -71,6 +71,9 @@ _Py_stackref_close(_PyStackRef ref, const char *filename, int 
linenumber)
     }
     PyObject *obj;
     if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) {
+        if (ref.index == 0) {
+            _Py_FatalErrorFormat(__func__, "Passing NULL to PyStackRef_CLOSE 
at %s:%d\n", filename, linenumber);
+        }
         // Pre-allocated reference to None, False or True -- Do not clear
         TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, 
(void *)ref.index);
         obj = entry->obj;
diff --git a/Tools/cases_generator/generators_common.py 
b/Tools/cases_generator/generators_common.py
index 4571811bcdff3c..ca6104705fb3f2 100644
--- a/Tools/cases_generator/generators_common.py
+++ b/Tools/cases_generator/generators_common.py
@@ -13,9 +13,8 @@
 from lexer import Token
 from stack import Storage, StackError
 from parser import Stmt, SimpleStmt, BlockStmt, IfStmt, ForStmt, WhileStmt, 
MacroIfStmt
-
-# Set this to true for voluminous output showing state of stack and locals
-PRINT_STACKS = False
+from stack import PRINT_STACKS
+DEBUG = False
 
 class TokenIterator:
 
@@ -161,7 +160,7 @@ def deopt_if(
         self.emit(") {\n")
         next(tkn_iter)  # Semi colon
         assert inst is not None
-        assert inst.family is not None, inst
+        assert inst.family is not None
         family_name = inst.family.name
         self.emit(f"UPDATE_MISS_STATS({family_name});\n")
         self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n")
@@ -242,6 +241,7 @@ def decref_inputs(
         next(tkn_iter)
         next(tkn_iter)
         next(tkn_iter)
+        self._print_storage("DECREF_INPUTS", storage)
         try:
             storage.close_inputs(self.out)
         except StackError as ex:
@@ -249,7 +249,6 @@ def decref_inputs(
         except Exception as ex:
             ex.args = (ex.args[0] + str(tkn),)
             raise
-        self._print_storage(storage)
         return True
 
     def kill_inputs(
@@ -372,7 +371,7 @@ def sync_sp(
         next(tkn_iter)
         storage.clear_inputs("when syncing stack")
         storage.flush(self.out)
-        self._print_storage(storage)
+        storage.stack.clear(self.out)
         return True
 
     def stack_pointer(
@@ -406,7 +405,6 @@ def goto_label(self, goto: Token, label: Token, storage: 
Storage) -> None:
     def emit_save(self, storage: Storage) -> None:
         storage.flush(self.out)
         storage.save(self.out)
-        self._print_storage(storage)
 
     def save_stack(
         self,
@@ -424,7 +422,6 @@ def save_stack(
 
     def emit_reload(self, storage: Storage) -> None:
         storage.reload(self.out)
-        self._print_storage(storage)
 
     def reload_stack(
         self,
@@ -453,9 +450,10 @@ def instruction_size(self,
         self.out.emit(f" {uop.instruction_size} ")
         return True
 
-    def _print_storage(self, storage: Storage) -> None:
-        if PRINT_STACKS:
+    def _print_storage(self, reason:str, storage: Storage) -> None:
+        if DEBUG:
             self.out.start_line()
+            self.emit(f"/* {reason} */\n")
             self.emit(storage.as_comment())
             self.out.start_line()
 
@@ -514,7 +512,6 @@ def emit_SimpleStmt(
                                     var.memory_offset = None
                                     break
                         if tkn.text.startswith("DISPATCH"):
-                            self._print_storage(storage)
                             reachable = False
                         self.out.emit(tkn)
                 else:
@@ -536,6 +533,8 @@ def emit_MacroIfStmt(
         self.out.emit(stmt.condition)
         branch = stmt.else_ is not None
         reachable = True
+        if branch:
+            else_storage = storage.copy()
         for s in stmt.body:
             r, tkn, storage = self._emit_stmt(s, uop, storage, inst)
             if tkn is not None:
@@ -543,7 +542,6 @@ def emit_MacroIfStmt(
             if not r:
                 reachable = False
         if branch:
-            else_storage = storage.copy()
             assert stmt.else_ is not None
             self.out.emit(stmt.else_)
             assert stmt.else_body is not None
@@ -553,7 +551,8 @@ def emit_MacroIfStmt(
                     self.out.emit(tkn)
                 if not r:
                     reachable = False
-            storage.merge(else_storage, self.out)
+            else_storage.merge(storage, self.out)  # type: 
ignore[possibly-undefined]
+            storage = else_storage
         self.out.emit(stmt.endif)
         return reachable, None, storage
 
@@ -596,7 +595,6 @@ def emit_IfStmt(
                     reachable = True
             return reachable, rbrace, storage
         except StackError as ex:
-            self._print_storage(if_storage)
             assert rbrace is not None
             raise analysis_error(ex.args[0], rbrace) from None
 
@@ -659,20 +657,18 @@ def emit_tokens(
         storage: Storage,
         inst: Instruction | None,
         emit_braces: bool = True
-    ) -> Storage:
+    ) -> tuple[bool, Storage]:
         self.out.start_line()
         reachable, tkn, storage = self.emit_BlockStmt(code.body, code, 
storage, inst, emit_braces)
         assert tkn is not None
         try:
             if reachable:
-                self._print_storage(storage)
                 storage.push_outputs()
-                self._print_storage(storage)
             if emit_braces:
                 self.out.emit(tkn)
         except StackError as ex:
             raise analysis_error(ex.args[0], tkn) from None
-        return storage
+        return reachable, storage
 
     def emit(self, txt: str | Token) -> None:
         self.out.emit(txt)
diff --git a/Tools/cases_generator/optimizer_generator.py 
b/Tools/cases_generator/optimizer_generator.py
index f515bb6fdc9213..7a32275347e896 100644
--- a/Tools/cases_generator/optimizer_generator.py
+++ b/Tools/cases_generator/optimizer_generator.py
@@ -145,7 +145,7 @@ def write_uop(
             # No reference management of inputs needed.
             for var in storage.inputs:  # type: ignore[possibly-undefined]
                 var.in_local = False
-            storage = emitter.emit_tokens(override, storage, None, False)
+            _, storage = emitter.emit_tokens(override, storage, None, False)
             out.start_line()
             storage.flush(out)
         else:
diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py
index 76dfc48a6b594e..14d06948ba1602 100644
--- a/Tools/cases_generator/stack.py
+++ b/Tools/cases_generator/stack.py
@@ -6,6 +6,8 @@
 
 UNUSED = {"unused"}
 
+# Set this to true for voluminous output showing state of stack and locals
+PRINT_STACKS = False
 
 def maybe_parenthesize(sym: str) -> str:
     """Add parentheses around a string if it contains an operator
@@ -131,9 +133,6 @@ def as_int(self) -> int | None:
             return None
         return self.numeric
 
-    def __bool__(self) -> bool:
-        return self.numeric != 0 or bool(self.positive) or bool(self.negative)
-
     def __str__(self) -> str:
         return self.to_c()
 
@@ -151,7 +150,7 @@ def __repr__(self) -> str:
 
     def compact_str(self) -> str:
         mtag = "M" if self.memory_offset else ""
-        dtag = "D" if self.in_local else ""
+        dtag = "L" if self.in_local else ""
         atag = "A" if self.is_array() else ""
         return f"'{self.item.name}'{mtag}{dtag}{atag}"
 
@@ -167,6 +166,11 @@ def undefined(defn: StackItem) -> "Local":
     def from_memory(defn: StackItem, offset: PointerOffset) -> "Local":
         return Local(defn, offset, True)
 
+    @staticmethod
+    def register(name: str) -> "Local":
+        item = StackItem(name, None, "", False, True)
+        return Local(item, None, True)
+
     def kill(self) -> None:
         self.in_local = False
         self.memory_offset = None
@@ -230,20 +234,16 @@ def drop(self, var: StackItem, check_liveness: bool) -> 
None:
             raise StackError(f"Dropping live value '{var.name}'")
 
     def pop(self, var: StackItem, out: CWriter) -> Local:
+        if self.variables:
+            top = self.variables[-1]
+            if var.is_array() != top.is_array() or top.size != var.size:
+                # Mismatch in variables
+                self.clear(out)
         self.logical_sp = self.logical_sp.pop(var)
         indirect = "&" if var.is_array() else ""
         if self.variables:
             popped = self.variables.pop()
-            if var.is_array() ^ popped.is_array():
-                raise StackError(
-                    f"Array mismatch when popping '{popped.name}' from stack 
to assign to '{var.name}'. "
-                    f"Expected {array_or_scalar(var)} got 
{array_or_scalar(popped)}"
-                )
-            if popped.size != var.size:
-                raise StackError(
-                    f"Size mismatch when popping '{popped.name}' from stack to 
assign to '{var.name}'. "
-                    f"Expected {var_size(var)} got {var_size(popped.item)}"
-                )
+            assert var.is_array() == popped.is_array() and popped.size == 
var.size
             if not var.used:
                 return popped
             if popped.name != var.name:
@@ -255,27 +255,33 @@ def pop(self, var: StackItem, out: CWriter) -> Local:
                 if popped.memory_offset is None:
                     popped.memory_offset = self.logical_sp
                 assert popped.memory_offset == self.logical_sp, (popped, 
self.as_comment())
-                offset = popped.memory_offset.to_c()
+                offset = popped.memory_offset - self.physical_sp
                 if var.is_array():
-                    defn = f"{var.name} = &stack_pointer[{offset}];\n"
+                    defn = f"{var.name} = &stack_pointer[{offset.to_c()}];\n"
                 else:
-                    defn = f"{var.name} = stack_pointer[{offset}];\n"
+                    defn = f"{var.name} = stack_pointer[{offset.to_c()}];\n"
                     popped.in_local = True
             else:
                 defn = rename
             out.emit(defn)
             return popped
-
         self.base_offset = self.logical_sp
         if var.name in UNUSED or not var.used:
             return Local.unused(var, self.base_offset)
         cast = f"({var.type})" if (not indirect and var.type) else ""
         bits = ".bits" if cast and self.extract_bits else ""
-        offset = (self.base_offset - self.physical_sp).to_c()
-        assign = f"{var.name} = 
{cast}{indirect}stack_pointer[{offset}]{bits};\n"
+        c_offset = (self.base_offset - self.physical_sp).to_c()
+        assign = f"{var.name} = 
{cast}{indirect}stack_pointer[{c_offset}]{bits};\n"
         out.emit(assign)
+        self._print(out)
         return Local.from_memory(var, self.base_offset)
 
+    def clear(self, out: CWriter) -> None:
+        "Flush to memory and clear variables stack"
+        self.flush(out)
+        self.variables = []
+        self.base_offset = self.logical_sp
+
     def push(self, var: Local) -> None:
         assert(var not in self.variables)
         self.variables.append(var)
@@ -298,10 +304,11 @@ def _save_physical_sp(self, out: CWriter) -> None:
             diff = self.logical_sp - self.physical_sp
             out.start_line()
             out.emit(f"stack_pointer += {diff.to_c()};\n")
-            out.emit("assert(WITHIN_STACK_BOUNDS());\n")
+            out.emit(f"assert(WITHIN_STACK_BOUNDS());\n")
             self.physical_sp = self.logical_sp
+            self._print(out)
 
-    def flush(self, out: CWriter) -> None:
+    def save_variables(self, out: CWriter) -> None:
         out.start_line()
         var_offset = self.base_offset
         for var in self.variables:
@@ -310,10 +317,15 @@ def flush(self, out: CWriter) -> None:
                 not var.memory_offset and
                 not var.is_array()
             ):
+                self._print(out)
                 var.memory_offset = var_offset
                 stack_offset = var_offset - self.physical_sp
                 Stack._do_emit(out, var.item, stack_offset, self.cast_type, 
self.extract_bits)
+                self._print(out)
             var_offset = var_offset.push(var.item)
+
+    def flush(self, out: CWriter) -> None:
+        self.save_variables(out)
         self._save_physical_sp(out)
         out.start_line()
 
@@ -329,9 +341,13 @@ def sp_offset(self) -> str:
     def as_comment(self) -> str:
         variables = ", ".join([v.compact_str() for v in self.variables])
         return (
-            f"/* Variables: {variables}. base: {self.base_offset.to_c()}. sp: 
{self.physical_sp.to_c()}. logical_sp: {self.logical_sp.to_c()} */"
+            f"/* Variables=[{variables}]; base={self.base_offset.to_c()}; 
sp={self.physical_sp.to_c()}; logical_sp={self.logical_sp.to_c()} */"
         )
 
+    def _print(self, out: CWriter) -> None:
+        if PRINT_STACKS:
+            out.emit(self.as_comment() + "\n")
+
     def copy(self) -> "Stack":
         other = Stack(self.extract_bits, self.cast_type)
         other.base_offset = self.base_offset
@@ -358,7 +374,6 @@ def align(self, other: "Stack", out: CWriter) -> None:
         diff = other.physical_sp - self.physical_sp
         out.start_line()
         out.emit(f"stack_pointer += {diff.to_c()};\n")
-        out.emit("assert(WITHIN_STACK_BOUNDS());\n")
         self.physical_sp = other.physical_sp
 
     def merge(self, other: "Stack", out: CWriter) -> None:
@@ -621,10 +636,10 @@ def push_outputs(self) -> None:
 
     def as_comment(self) -> str:
         stack_comment = self.stack.as_comment()
-        next_line = "\n               "
+        next_line = "\n                  "
         inputs = ", ".join([var.compact_str() for var in self.inputs])
         outputs = ", ".join([var.compact_str() for var in self.outputs])
-        return f"{stack_comment[:-2]}{next_line}inputs: 
{inputs}{next_line}outputs: {outputs}*/"
+        return f"{stack_comment[:-2]}{next_line}inputs: {inputs} outputs: 
{outputs}*/"
 
     def close_inputs(self, out: CWriter) -> None:
 
@@ -637,7 +652,7 @@ def close_named(close: str, name: str, overwrite: str) -> 
None:
                     tmp_defined = True
                 out.emit(f"tmp = {name};\n")
                 out.emit(f"{name} = {overwrite};\n")
-                self.stack.flush(out)
+                self.stack.save_variables(out)
                 out.emit(f"{close}(tmp);\n")
             else:
                 out.emit(f"{close}({name});\n")
@@ -678,7 +693,6 @@ def close_variable(var: Local, overwrite: str) -> None:
                 if output is not None:
                     raise StackError("Cannot call DECREF_INPUTS with more than 
one live output")
                 output = var
-        self.stack.flush(out)
         if output is not None:
             if output.is_array():
                 assert len(self.inputs) == 1
@@ -691,6 +705,7 @@ def close_variable(var: Local, overwrite: str) -> None:
                 return
             if var_size(lowest.item) != var_size(output.item):
                 raise StackError("Cannot call DECREF_INPUTS with live output 
not matching first input size")
+            self.stack.flush(out)
             lowest.in_local = True
             close_variable(lowest, output.name)
             assert lowest.memory_offset is not None
diff --git a/Tools/cases_generator/tier1_generator.py 
b/Tools/cases_generator/tier1_generator.py
index ccf2dfe2d2e684..5a49c239ed1aa7 100644
--- a/Tools/cases_generator/tier1_generator.py
+++ b/Tools/cases_generator/tier1_generator.py
@@ -9,6 +9,8 @@
     Analysis,
     Instruction,
     Uop,
+    Label,
+    CodeSection,
     Part,
     analyze_files,
     Skip,
@@ -22,9 +24,13 @@
     write_header,
     type_and_null,
     Emitter,
+    TokenIterator,
+    always_true,
+    emit_to,
 )
 from cwriter import CWriter
 from typing import TextIO
+from lexer import Token
 from stack import Local, Stack, StackError, get_stack_effect, Storage
 
 DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h"
@@ -69,23 +75,23 @@ def write_uop(
     stack: Stack,
     inst: Instruction,
     braces: bool,
-) -> tuple[int, Stack]:
+) -> tuple[bool, int, Stack]:
     # out.emit(stack.as_comment() + "\n")
     if isinstance(uop, Skip):
         entries = "entries" if uop.size > 1 else "entry"
         emitter.emit(f"/* Skip {uop.size} cache {entries} */\n")
-        return (offset + uop.size), stack
+        return True, (offset + uop.size), stack
     if isinstance(uop, Flush):
         emitter.emit(f"// flush\n")
         stack.flush(emitter.out)
-        return offset, stack
+        return True, offset, stack
     locals: dict[str, Local] = {}
     emitter.out.start_line()
     if braces:
         emitter.out.emit(f"// {uop.name}\n")
         emitter.emit("{\n")
+        stack._print(emitter.out)
     storage = Storage.for_uop(stack, uop, emitter.out)
-    emitter._print_storage(storage)
 
     for cache in uop.caches:
         if cache.name != "unused":
@@ -102,12 +108,12 @@ def write_uop(
                 emitter.emit(f"(void){cache.name};\n")
         offset += cache.size
 
-    storage = emitter.emit_tokens(uop, storage, inst, False)
+    reachable, storage = emitter.emit_tokens(uop, storage, inst, False)
     if braces:
         emitter.out.start_line()
         emitter.emit("}\n")
     # emitter.emit(stack.as_comment() + "\n")
-    return offset, storage.stack
+    return reachable, offset, storage.stack
 
 
 def uses_this(inst: Instruction) -> bool:
@@ -204,6 +210,9 @@ def generate_tier1_labels(
         emitter.emit_tokens(label, storage, None)
         emitter.emit("\n\n")
 
+def get_popped(inst: Instruction, analysis: Analysis) -> str:
+    stack = get_stack_effect(inst)
+    return (-stack.base_offset).to_c()
 
 def generate_tier1_cases(
     analysis: Analysis, outfile: TextIO, lines: bool
@@ -214,6 +223,7 @@ def generate_tier1_cases(
     for name, inst in sorted(analysis.instructions.items()):
         out.emit("\n")
         out.emit(f"TARGET({name}) {{\n")
+        popped = get_popped(inst, analysis)
         # We need to ifdef it because this breaks platforms
         # without computed gotos/tail calling.
         out.emit(f"#if Py_TAIL_CALL_INTERP\n")
@@ -251,11 +261,10 @@ def generate_tier1_cases(
         for part in inst.parts:
             # Only emit braces if more than one uop
             insert_braces = len([p for p in inst.parts if isinstance(p, Uop)]) 
> 1
-            offset, stack = write_uop(part, emitter, offset, stack, inst, 
insert_braces)
+            reachable, offset, stack = write_uop(part, emitter, offset, stack, 
inst, insert_braces)
         out.start_line()
-
-        stack.flush(out)
-        if not inst.parts[-1].properties.always_exits:
+        if reachable: # type: ignore[possibly-undefined]
+            stack.flush(out)
             out.emit("DISPATCH();\n")
         out.start_line()
         out.emit("}")
diff --git a/Tools/cases_generator/tier2_generator.py 
b/Tools/cases_generator/tier2_generator.py
index 75b0d5cb51072c..0ac2a0497e5d02 100644
--- a/Tools/cases_generator/tier2_generator.py
+++ b/Tools/cases_generator/tier2_generator.py
@@ -154,7 +154,7 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> 
Stack:
                     cast = f"uint{cache.size*16}_t"
                 emitter.emit(f"{type}{cache.name} = 
({cast})CURRENT_OPERAND{idx}();\n")
                 idx += 1
-        storage = emitter.emit_tokens(uop, storage, None, False)
+        _, storage = emitter.emit_tokens(uop, storage, None, False)
         storage.flush(emitter.out)
     except StackError as ex:
         raise analysis_error(ex.args[0], uop.body.open) from None

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to