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 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy