diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 5683b98470d3ea..5e66b91e7f10bc 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -210,8 +210,32 @@ _PyStackRef_FromPyObjectNewMortal(PyObject *obj, const char *filename, int linen extern int PyStackRef_Is(_PyStackRef a, _PyStackRef b); +extern _PyStackRef PyStackRef_TagInt(intptr_t i); + #else +#define Py_INT_TAG 3 + +static inline bool +PyStackRef_IsTaggedInt(_PyStackRef i) +{ + return (i.bits & Py_INT_TAG) == Py_INT_TAG; +} + +static inline _PyStackRef +PyStackRef_TagInt(intptr_t i) +{ + assert(Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (i << 2), 2) == i); + return (_PyStackRef){ .bits = ((((uintptr_t)i) << 2) | Py_INT_TAG) }; +} + +static inline intptr_t +PyStackRef_UntagInt(_PyStackRef i) +{ + assert((i.bits & Py_INT_TAG) == Py_INT_TAG); + return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, i.bits, 2); +} + #ifdef Py_GIL_DISABLED @@ -232,6 +256,8 @@ static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED}; #define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True) #define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False) +#define PyStackRef_IsNullOrInt(stackref) (PyStackRef_IsNull(stackref) || PyStackRef_IsTaggedInt(stackref)) + static inline PyObject * PyStackRef_AsPyObjectBorrow(_PyStackRef stackref) { @@ -451,6 +477,7 @@ PyStackRef_RefcountOnObject(_PyStackRef ref) static inline PyObject * PyStackRef_AsPyObjectBorrow(_PyStackRef ref) { + assert(!PyStackRef_IsTaggedInt(ref)); return BITS_TO_PTR_MASKED(ref); } @@ -587,6 +614,12 @@ PyStackRef_CLOSE(_PyStackRef ref) } #endif +static inline bool +PyStackRef_IsNullOrInt(_PyStackRef ref) +{ + return PyStackRef_IsNull(ref) || PyStackRef_IsTaggedInt(ref); +} + static inline void PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct) { @@ -726,7 +759,7 @@ _Py_TryXGetStackRef(PyObject **src, _PyStackRef *out) // Like Py_VISIT but for _PyStackRef fields #define _Py_VISIT_STACKREF(ref) \ do { \ - if (!PyStackRef_IsNull(ref)) { \ + if (!PyStackRef_IsNullOrInt(ref)) { \ int vret = _PyGC_VisitStackRef(&(ref), visit, arg); \ if (vret) \ return vret; \ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e9dced654d1492..0f11d6723f508d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1385,16 +1385,7 @@ dummy_func( assert(oparg >= 0 && oparg <= 2); if (oparg) { - PyObject *lasti = PyStackRef_AsPyObjectBorrow(values[0]); - if (PyLong_Check(lasti)) { - frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyLong_AsLong(lasti); - assert(!_PyErr_Occurred(tstate)); - } - else { - _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); - Py_DECREF(exc); - ERROR_NO_POP(); - } + frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyStackRef_UntagInt(values[0]); } assert(exc && PyExceptionInstance_Check(exc)); _PyErr_SetRaisedException(tstate, exc); @@ -3458,7 +3449,7 @@ dummy_func( if (tb == NULL) { tb = Py_None; } - assert(PyStackRef_LongCheck(lasti)); + assert(PyStackRef_IsTaggedInt(lasti)); (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); @@ -5351,11 +5342,8 @@ dummy_func( } if (lasti) { int frame_lasti = _PyInterpreterFrame_LASTI(frame); - PyObject *lasti = PyLong_FromLong(frame_lasti); - if (lasti == NULL) { - goto exception_unwind; - } - _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti)); + _PyStackRef lasti = PyStackRef_TagInt(frame_lasti); + _PyFrame_StackPush(frame, lasti); } /* Make the raw exception data diff --git a/Python/ceval.c b/Python/ceval.c index 8ab0c6318c1c91..80a61e50313b7f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -146,6 +146,9 @@ dump_item(_PyStackRef item) printf(""); return; } + if (PyStackRef_IsTaggedInt(item)) { + printf("%ld", PyStackRef_UntagInt(item)); + } PyObject *obj = PyStackRef_AsPyObjectBorrow(item); if (obj == NULL) { printf(""); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 938a80fe665c0b..f1ded61c094fc8 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4462,7 +4462,9 @@ if (tb == NULL) { tb = Py_None; } - assert(PyStackRef_LongCheck(lasti)); + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(PyStackRef_IsTaggedInt(lasti)); + stack_pointer = _PyFrame_GetStackPointer(frame); (void)lasti; PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); diff --git a/Python/gc.c b/Python/gc.c index dad088e09f872f..58224acff2cdd9 100644 --- a/Python/gc.c +++ b/Python/gc.c @@ -547,6 +547,7 @@ _PyGC_VisitStackRef(_PyStackRef *ref, visitproc visit, void *arg) // This is a bit tricky! We want to ignore stackrefs with embedded // refcounts when computing the incoming references, but otherwise treat // them like normal. + assert(!PyStackRef_IsTaggedInt(*ref)); if (!PyStackRef_RefcountOnObject(*ref) && (visit == visit_decref)) { return 0; } @@ -560,7 +561,9 @@ _PyGC_VisitFrameStack(_PyInterpreterFrame *frame, visitproc visit, void *arg) _PyStackRef *ref = _PyFrame_GetLocalsArray(frame); /* locals and stack */ for (; ref < frame->stackpointer; ref++) { - _Py_VISIT_STACKREF(*ref); + if (!PyStackRef_IsTaggedInt(*ref)) { + _Py_VISIT_STACKREF(*ref); + } } return 0; } @@ -1495,8 +1498,11 @@ mark_stacks(PyInterpreterState *interp, PyGC_Head *visited, int visited_space, b objects_marked += move_to_reachable(func, &reachable, visited_space); while (sp > locals) { sp--; + if (PyStackRef_IsNullOrInt(*sp)) { + continue; + } PyObject *op = PyStackRef_AsPyObjectBorrow(*sp); - if (op == NULL || _Py_IsImmortal(op)) { + if (_Py_IsImmortal(op)) { continue; } if (_PyObject_IS_GC(op)) { diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 4c459b02ce2b8f..fdbcd257062cf5 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -420,7 +420,7 @@ gc_visit_heaps(PyInterpreterState *interp, mi_block_visit_fun *visitor, static inline void gc_visit_stackref(_PyStackRef stackref) { - if (PyStackRef_IsDeferred(stackref) && !PyStackRef_IsNull(stackref)) { + if (PyStackRef_IsDeferred(stackref) && !PyStackRef_IsNullOrInt(stackref)) { PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref); if (_PyObject_GC_IS_TRACKED(obj) && !gc_is_frozen(obj)) { gc_add_refs(obj, 1); @@ -805,7 +805,7 @@ gc_abort_mark_alive(PyInterpreterState *interp, static int gc_visit_stackref_mark_alive(gc_mark_args_t *args, _PyStackRef stackref) { - if (!PyStackRef_IsNull(stackref)) { + if (!PyStackRef_IsNullOrInt(stackref)) { PyObject *op = PyStackRef_AsPyObjectBorrow(stackref); if (gc_mark_enqueue(op, args) < 0) { return -1; @@ -1694,6 +1694,7 @@ _PyGC_VisitStackRef(_PyStackRef *ref, visitproc visit, void *arg) // This is a bit tricky! We want to ignore deferred references when // computing the incoming references, but otherwise treat them like // regular references. + assert(!PyStackRef_IsTaggedInt(*ref)); if (!PyStackRef_IsDeferred(*ref) || (visit != visit_decref && visit != visit_decref_unreachable)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 97bffce8d82767..5445e62a848b6d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -10120,20 +10120,12 @@ PyObject *exc = PyStackRef_AsPyObjectSteal(exc_st); assert(oparg >= 0 && oparg <= 2); if (oparg) { - PyObject *lasti = PyStackRef_AsPyObjectBorrow(values[0]); - if (PyLong_Check(lasti)) { - frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyLong_AsLong(lasti); - assert(!_PyErr_Occurred(tstate)); - } - else { - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); - Py_DECREF(exc); - stack_pointer = _PyFrame_GetStackPointer(frame); - JUMP_TO_LABEL(error); - } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyStackRef_UntagInt(values[0]); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += 1; } assert(exc && PyExceptionInstance_Check(exc)); stack_pointer += -1; @@ -11986,7 +11978,9 @@ if (tb == NULL) { tb = Py_None; } - assert(PyStackRef_LongCheck(lasti)); + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(PyStackRef_IsTaggedInt(lasti)); + stack_pointer = _PyFrame_GetStackPointer(frame); (void)lasti; PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); @@ -12158,11 +12152,8 @@ JUMP_TO_LABEL(error); } if (lasti) { int frame_lasti = _PyInterpreterFrame_LASTI(frame); - PyObject *lasti = PyLong_FromLong(frame_lasti); - if (lasti == NULL) { - JUMP_TO_LABEL(exception_unwind); - } - _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti)); + _PyStackRef lasti = PyStackRef_TagInt(frame_lasti); + _PyFrame_StackPush(frame, lasti); } PyObject *exc = _PyErr_GetRaisedException(tstate); _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(exc));