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 363f263ad2a083..795fbf0b90c366 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -151,18 +151,6 @@ dump_item(_PyStackRef item) printf(""); 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