GH-132508: Use tagged integers on the evaluation stack for the last instruction offset (GH-132545)

This commit is contained in:
Mark Shannon 2025-04-29 18:00:35 +01:00 committed by GitHub
parent caee16f052
commit ccf1b0b1c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 129 additions and 60 deletions

View file

@ -18,6 +18,7 @@ extern "C" {
((int)((IF)->instr_ptr - _PyFrame_GetBytecode((IF)))) ((int)((IF)->instr_ptr - _PyFrame_GetBytecode((IF))))
static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) {
assert(!PyStackRef_IsNull(f->f_executable));
PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable);
assert(PyCode_Check(executable)); assert(PyCode_Check(executable));
return (PyCodeObject *)executable; return (PyCodeObject *)executable;

View file

@ -63,11 +63,13 @@ extern void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _P
static const _PyStackRef PyStackRef_NULL = { .index = 0 }; static const _PyStackRef PyStackRef_NULL = { .index = 0 };
#define PyStackRef_None ((_PyStackRef){ .index = 1 } ) // Use the first 3 even numbers for None, True and False.
#define PyStackRef_False ((_PyStackRef){ .index = 2 }) // Odd numbers are reserved for (tagged) integers
#define PyStackRef_True ((_PyStackRef){ .index = 3 }) #define PyStackRef_None ((_PyStackRef){ .index = 2 } )
#define PyStackRef_False ((_PyStackRef){ .index = 4 })
#define PyStackRef_True ((_PyStackRef){ .index = 6 })
#define LAST_PREDEFINED_STACKREF_INDEX 3 #define INITIAL_STACKREF_INDEX 8
static inline int static inline int
PyStackRef_IsNull(_PyStackRef ref) PyStackRef_IsNull(_PyStackRef ref)
@ -96,6 +98,7 @@ PyStackRef_IsNone(_PyStackRef ref)
static inline PyObject * static inline PyObject *
_PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumber) _PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumber)
{ {
assert((ref.index & 1) == 0);
_Py_stackref_record_borrow(ref, filename, linenumber); _Py_stackref_record_borrow(ref, filename, linenumber);
return _Py_stackref_get_object(ref); return _Py_stackref_get_object(ref);
} }
@ -132,31 +135,45 @@ _PyStackRef_FromPyObjectImmortal(PyObject *obj, const char *filename, int linenu
} }
#define PyStackRef_FromPyObjectImmortal(obj) _PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj), __FILE__, __LINE__) #define PyStackRef_FromPyObjectImmortal(obj) _PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj), __FILE__, __LINE__)
static inline bool
PyStackRef_IsTaggedInt(_PyStackRef ref)
{
return (ref.index & 1) == 1;
}
static inline void static inline void
_PyStackRef_CLOSE(_PyStackRef ref, const char *filename, int linenumber) _PyStackRef_CLOSE(_PyStackRef ref, const char *filename, int linenumber)
{ {
if (PyStackRef_IsTaggedInt(ref)) {
return;
}
PyObject *obj = _Py_stackref_close(ref, filename, linenumber); PyObject *obj = _Py_stackref_close(ref, filename, linenumber);
Py_DECREF(obj); Py_DECREF(obj);
} }
#define PyStackRef_CLOSE(REF) _PyStackRef_CLOSE((REF), __FILE__, __LINE__) #define PyStackRef_CLOSE(REF) _PyStackRef_CLOSE((REF), __FILE__, __LINE__)
static inline void static inline void
_PyStackRef_XCLOSE(_PyStackRef ref, const char *filename, int linenumber) _PyStackRef_XCLOSE(_PyStackRef ref, const char *filename, int linenumber)
{ {
if (PyStackRef_IsNull(ref)) { if (PyStackRef_IsNull(ref)) {
return; return;
} }
PyObject *obj = _Py_stackref_close(ref, filename, linenumber); _PyStackRef_CLOSE(ref, filename, linenumber);
Py_DECREF(obj);
} }
#define PyStackRef_XCLOSE(REF) _PyStackRef_XCLOSE((REF), __FILE__, __LINE__) #define PyStackRef_XCLOSE(REF) _PyStackRef_XCLOSE((REF), __FILE__, __LINE__)
static inline _PyStackRef static inline _PyStackRef
_PyStackRef_DUP(_PyStackRef ref, const char *filename, int linenumber) _PyStackRef_DUP(_PyStackRef ref, const char *filename, int linenumber)
{ {
PyObject *obj = _Py_stackref_get_object(ref); if (PyStackRef_IsTaggedInt(ref)) {
Py_INCREF(obj); return ref;
return _Py_stackref_create(obj, filename, linenumber); }
else {
PyObject *obj = _Py_stackref_get_object(ref);
Py_INCREF(obj);
return _Py_stackref_create(obj, filename, linenumber);
}
} }
#define PyStackRef_DUP(REF) _PyStackRef_DUP(REF, __FILE__, __LINE__) #define PyStackRef_DUP(REF) _PyStackRef_DUP(REF, __FILE__, __LINE__)
@ -210,8 +227,40 @@ _PyStackRef_FromPyObjectNewMortal(PyObject *obj, const char *filename, int linen
extern int PyStackRef_Is(_PyStackRef a, _PyStackRef b); extern int PyStackRef_Is(_PyStackRef a, _PyStackRef b);
extern bool PyStackRef_IsTaggedInt(_PyStackRef ref);
extern intptr_t PyStackRef_UntagInt(_PyStackRef ref);
extern _PyStackRef PyStackRef_TagInt(intptr_t i);
extern bool
PyStackRef_IsNullOrInt(_PyStackRef ref);
#else #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);
intptr_t val = (intptr_t)i.bits;
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, 2);
}
#ifdef Py_GIL_DISABLED #ifdef Py_GIL_DISABLED
@ -232,6 +281,8 @@ static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED};
#define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True) #define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True)
#define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False) #define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False)
#define PyStackRef_IsNullOrInt(stackref) (PyStackRef_IsNull(stackref) || PyStackRef_IsTaggedInt(stackref))
static inline PyObject * static inline PyObject *
PyStackRef_AsPyObjectBorrow(_PyStackRef stackref) PyStackRef_AsPyObjectBorrow(_PyStackRef stackref)
{ {
@ -451,6 +502,7 @@ PyStackRef_RefcountOnObject(_PyStackRef ref)
static inline PyObject * static inline PyObject *
PyStackRef_AsPyObjectBorrow(_PyStackRef ref) PyStackRef_AsPyObjectBorrow(_PyStackRef ref)
{ {
assert(!PyStackRef_IsTaggedInt(ref));
return BITS_TO_PTR_MASKED(ref); return BITS_TO_PTR_MASKED(ref);
} }
@ -587,6 +639,12 @@ PyStackRef_CLOSE(_PyStackRef ref)
} }
#endif #endif
static inline bool
PyStackRef_IsNullOrInt(_PyStackRef ref)
{
return PyStackRef_IsNull(ref) || PyStackRef_IsTaggedInt(ref);
}
static inline void static inline void
PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct) PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct)
{ {
@ -726,7 +784,7 @@ _Py_TryXGetStackRef(PyObject **src, _PyStackRef *out)
// Like Py_VISIT but for _PyStackRef fields // Like Py_VISIT but for _PyStackRef fields
#define _Py_VISIT_STACKREF(ref) \ #define _Py_VISIT_STACKREF(ref) \
do { \ do { \
if (!PyStackRef_IsNull(ref)) { \ if (!PyStackRef_IsNullOrInt(ref)) { \
int vret = _PyGC_VisitStackRef(&(ref), visit, arg); \ int vret = _PyGC_VisitStackRef(&(ref), visit, arg); \
if (vret) \ if (vret) \
return vret; \ return vret; \

View file

@ -0,0 +1,3 @@
Uses tagged integers on the evaluation stack to represent the instruction
offsets when reraising an exception. This avoids the need to box the integer
which could fail in low memory conditions.

View file

@ -1813,15 +1813,16 @@ frame_lineno_set_impl(PyFrameObject *self, PyObject *value)
start_stack = pop_value(start_stack); start_stack = pop_value(start_stack);
} }
while (start_stack > best_stack) { while (start_stack > best_stack) {
_PyStackRef popped = _PyFrame_StackPop(self->f_frame);
if (top_of_stack(start_stack) == Except) { if (top_of_stack(start_stack) == Except) {
/* Pop exception stack as well as the evaluation stack */ /* Pop exception stack as well as the evaluation stack */
PyObject *exc = PyStackRef_AsPyObjectBorrow(_PyFrame_StackPop(self->f_frame)); PyObject *exc = PyStackRef_AsPyObjectBorrow(popped);
assert(PyExceptionInstance_Check(exc) || exc == Py_None); assert(PyExceptionInstance_Check(exc) || exc == Py_None);
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
Py_XSETREF(tstate->exc_info->exc_value, exc == Py_None ? NULL : exc); Py_XSETREF(tstate->exc_info->exc_value, exc == Py_None ? NULL : exc);
} }
else { else {
PyStackRef_XCLOSE(_PyFrame_StackPop(self->f_frame)); PyStackRef_XCLOSE(popped);
} }
start_stack = pop_value(start_stack); start_stack = pop_value(start_stack);
} }

View file

@ -1384,16 +1384,7 @@ dummy_func(
assert(oparg >= 0 && oparg <= 2); assert(oparg >= 0 && oparg <= 2);
if (oparg) { if (oparg) {
PyObject *lasti = PyStackRef_AsPyObjectBorrow(values[0]); frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyStackRef_UntagInt(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();
}
} }
assert(exc && PyExceptionInstance_Check(exc)); assert(exc && PyExceptionInstance_Check(exc));
_PyErr_SetRaisedException(tstate, exc); _PyErr_SetRaisedException(tstate, exc);
@ -3472,7 +3463,7 @@ dummy_func(
if (tb == NULL) { if (tb == NULL) {
tb = Py_None; tb = Py_None;
} }
assert(PyStackRef_LongCheck(lasti)); assert(PyStackRef_IsTaggedInt(lasti));
(void)lasti; // Shut up compiler warning if asserts are off (void)lasti; // Shut up compiler warning if asserts are off
PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb};
int has_self = !PyStackRef_IsNull(exit_self); int has_self = !PyStackRef_IsNull(exit_self);
@ -5378,11 +5369,8 @@ dummy_func(
} }
if (lasti) { if (lasti) {
int frame_lasti = _PyInterpreterFrame_LASTI(frame); int frame_lasti = _PyInterpreterFrame_LASTI(frame);
PyObject *lasti = PyLong_FromLong(frame_lasti); _PyStackRef lasti = PyStackRef_TagInt(frame_lasti);
if (lasti == NULL) { _PyFrame_StackPush(frame, lasti);
goto exception_unwind;
}
_PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti));
} }
/* Make the raw exception data /* Make the raw exception data

View file

@ -146,6 +146,10 @@ dump_item(_PyStackRef item)
printf("<NULL>"); printf("<NULL>");
return; return;
} }
if (PyStackRef_IsTaggedInt(item)) {
printf("%" PRId64, (int64_t)PyStackRef_UntagInt(item));
return;
}
PyObject *obj = PyStackRef_AsPyObjectBorrow(item); PyObject *obj = PyStackRef_AsPyObjectBorrow(item);
if (obj == NULL) { if (obj == NULL) {
printf("<nil>"); printf("<nil>");

View file

@ -4470,7 +4470,7 @@
if (tb == NULL) { if (tb == NULL) {
tb = Py_None; tb = Py_None;
} }
assert(PyStackRef_LongCheck(lasti)); assert(PyStackRef_IsTaggedInt(lasti));
(void)lasti; (void)lasti;
PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb};
int has_self = !PyStackRef_IsNull(exit_self); int has_self = !PyStackRef_IsNull(exit_self);

View file

@ -547,6 +547,7 @@ _PyGC_VisitStackRef(_PyStackRef *ref, visitproc visit, void *arg)
// This is a bit tricky! We want to ignore stackrefs with embedded // This is a bit tricky! We want to ignore stackrefs with embedded
// refcounts when computing the incoming references, but otherwise treat // refcounts when computing the incoming references, but otherwise treat
// them like normal. // them like normal.
assert(!PyStackRef_IsTaggedInt(*ref));
if (!PyStackRef_RefcountOnObject(*ref) && (visit == visit_decref)) { if (!PyStackRef_RefcountOnObject(*ref) && (visit == visit_decref)) {
return 0; return 0;
} }
@ -560,7 +561,9 @@ _PyGC_VisitFrameStack(_PyInterpreterFrame *frame, visitproc visit, void *arg)
_PyStackRef *ref = _PyFrame_GetLocalsArray(frame); _PyStackRef *ref = _PyFrame_GetLocalsArray(frame);
/* locals and stack */ /* locals and stack */
for (; ref < frame->stackpointer; ref++) { for (; ref < frame->stackpointer; ref++) {
_Py_VISIT_STACKREF(*ref); if (!PyStackRef_IsTaggedInt(*ref)) {
_Py_VISIT_STACKREF(*ref);
}
} }
return 0; 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); objects_marked += move_to_reachable(func, &reachable, visited_space);
while (sp > locals) { while (sp > locals) {
sp--; sp--;
if (PyStackRef_IsNullOrInt(*sp)) {
continue;
}
PyObject *op = PyStackRef_AsPyObjectBorrow(*sp); PyObject *op = PyStackRef_AsPyObjectBorrow(*sp);
if (op == NULL || _Py_IsImmortal(op)) { if (_Py_IsImmortal(op)) {
continue; continue;
} }
if (_PyObject_IS_GC(op)) { if (_PyObject_IS_GC(op)) {

View file

@ -265,7 +265,7 @@ frame_disable_deferred_refcounting(_PyInterpreterFrame *frame)
frame->f_funcobj = PyStackRef_AsStrongReference(frame->f_funcobj); frame->f_funcobj = PyStackRef_AsStrongReference(frame->f_funcobj);
for (_PyStackRef *ref = frame->localsplus; ref < frame->stackpointer; ref++) { for (_PyStackRef *ref = frame->localsplus; ref < frame->stackpointer; ref++) {
if (!PyStackRef_IsNull(*ref) && PyStackRef_IsDeferred(*ref)) { if (!PyStackRef_IsNullOrInt(*ref) && PyStackRef_IsDeferred(*ref)) {
*ref = PyStackRef_AsStrongReference(*ref); *ref = PyStackRef_AsStrongReference(*ref);
} }
} }
@ -420,7 +420,7 @@ gc_visit_heaps(PyInterpreterState *interp, mi_block_visit_fun *visitor,
static inline void static inline void
gc_visit_stackref(_PyStackRef stackref) gc_visit_stackref(_PyStackRef stackref)
{ {
if (PyStackRef_IsDeferred(stackref) && !PyStackRef_IsNull(stackref)) { if (PyStackRef_IsDeferred(stackref) && !PyStackRef_IsNullOrInt(stackref)) {
PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref); PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref);
if (_PyObject_GC_IS_TRACKED(obj) && !gc_is_frozen(obj)) { if (_PyObject_GC_IS_TRACKED(obj) && !gc_is_frozen(obj)) {
gc_add_refs(obj, 1); gc_add_refs(obj, 1);
@ -817,7 +817,7 @@ gc_abort_mark_alive(PyInterpreterState *interp,
static int static int
gc_visit_stackref_mark_alive(gc_mark_args_t *args, _PyStackRef stackref) 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); PyObject *op = PyStackRef_AsPyObjectBorrow(stackref);
if (gc_mark_enqueue(op, args) < 0) { if (gc_mark_enqueue(op, args) < 0) {
return -1; return -1;
@ -1706,6 +1706,7 @@ _PyGC_VisitStackRef(_PyStackRef *ref, visitproc visit, void *arg)
// This is a bit tricky! We want to ignore deferred references when // This is a bit tricky! We want to ignore deferred references when
// computing the incoming references, but otherwise treat them like // computing the incoming references, but otherwise treat them like
// regular references. // regular references.
assert(!PyStackRef_IsTaggedInt(*ref));
if (!PyStackRef_IsDeferred(*ref) || if (!PyStackRef_IsDeferred(*ref) ||
(visit != visit_decref && visit != visit_decref_unreachable)) (visit != visit_decref && visit != visit_decref_unreachable))
{ {

View file

@ -10191,20 +10191,7 @@
PyObject *exc = PyStackRef_AsPyObjectSteal(exc_st); PyObject *exc = PyStackRef_AsPyObjectSteal(exc_st);
assert(oparg >= 0 && oparg <= 2); assert(oparg >= 0 && oparg <= 2);
if (oparg) { if (oparg) {
PyObject *lasti = PyStackRef_AsPyObjectBorrow(values[0]); frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyStackRef_UntagInt(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);
}
} }
assert(exc && PyExceptionInstance_Check(exc)); assert(exc && PyExceptionInstance_Check(exc));
stack_pointer += -1; stack_pointer += -1;
@ -12059,7 +12046,7 @@
if (tb == NULL) { if (tb == NULL) {
tb = Py_None; tb = Py_None;
} }
assert(PyStackRef_LongCheck(lasti)); assert(PyStackRef_IsTaggedInt(lasti));
(void)lasti; (void)lasti;
PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb};
int has_self = !PyStackRef_IsNull(exit_self); int has_self = !PyStackRef_IsNull(exit_self);
@ -12231,11 +12218,8 @@ JUMP_TO_LABEL(error);
} }
if (lasti) { if (lasti) {
int frame_lasti = _PyInterpreterFrame_LASTI(frame); int frame_lasti = _PyInterpreterFrame_LASTI(frame);
PyObject *lasti = PyLong_FromLong(frame_lasti); _PyStackRef lasti = PyStackRef_TagInt(frame_lasti);
if (lasti == NULL) { _PyFrame_StackPush(frame, lasti);
JUMP_TO_LABEL(exception_unwind);
}
_PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti));
} }
PyObject *exc = _PyErr_GetRaisedException(tstate); PyObject *exc = _PyErr_GetRaisedException(tstate);
_PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(exc)); _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(exc));

View file

@ -684,7 +684,7 @@ init_interpreter(PyInterpreterState *interp,
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
} }
#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) #if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG)
interp->next_stackref = 1; interp->next_stackref = INITIAL_STACKREF_INDEX;
_Py_hashtable_allocator_t alloc = { _Py_hashtable_allocator_t alloc = {
.malloc = malloc, .malloc = malloc,
.free = free, .free = free,

View file

@ -70,7 +70,7 @@ _Py_stackref_close(_PyStackRef ref, const char *filename, int linenumber)
} }
PyObject *obj; PyObject *obj;
if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) { if (ref.index < INITIAL_STACKREF_INDEX) {
if (ref.index == 0) { if (ref.index == 0) {
_Py_FatalErrorFormat(__func__, "Passing NULL to PyStackRef_CLOSE at %s:%d\n", filename, linenumber); _Py_FatalErrorFormat(__func__, "Passing NULL to PyStackRef_CLOSE at %s:%d\n", filename, linenumber);
} }
@ -113,7 +113,8 @@ _Py_stackref_create(PyObject *obj, const char *filename, int linenumber)
Py_FatalError("Cannot create a stackref for NULL"); Py_FatalError("Cannot create a stackref for NULL");
} }
PyInterpreterState *interp = PyInterpreterState_Get(); PyInterpreterState *interp = PyInterpreterState_Get();
uint64_t new_id = interp->next_stackref++; uint64_t new_id = interp->next_stackref;
interp->next_stackref = new_id + 2;
TableEntry *entry = make_table_entry(obj, filename, linenumber); TableEntry *entry = make_table_entry(obj, filename, linenumber);
if (entry == NULL) { if (entry == NULL) {
Py_FatalError("No memory left for stackref debug table"); Py_FatalError("No memory left for stackref debug table");
@ -127,7 +128,7 @@ _Py_stackref_create(PyObject *obj, const char *filename, int linenumber)
void void
_Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber) _Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber)
{ {
if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) { if (ref.index < INITIAL_STACKREF_INDEX) {
return; return;
} }
PyInterpreterState *interp = PyInterpreterState_Get(); PyInterpreterState *interp = PyInterpreterState_Get();
@ -151,8 +152,7 @@ _Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber
void void
_Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref) _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref)
{ {
assert(interp->next_stackref >= ref.index); assert(ref.index < INITIAL_STACKREF_INDEX);
interp->next_stackref = ref.index+1;
TableEntry *entry = make_table_entry(obj, "builtin-object", 0); TableEntry *entry = make_table_entry(obj, "builtin-object", 0);
if (entry == NULL) { if (entry == NULL) {
Py_FatalError("No memory left for stackref debug table"); Py_FatalError("No memory left for stackref debug table");
@ -197,4 +197,23 @@ _PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct, const char *
_Py_DECREF_SPECIALIZED(obj, destruct); _Py_DECREF_SPECIALIZED(obj, destruct);
} }
_PyStackRef PyStackRef_TagInt(intptr_t i)
{
return (_PyStackRef){ .index = (i << 1) + 1 };
}
intptr_t
PyStackRef_UntagInt(_PyStackRef i)
{
assert(PyStackRef_IsTaggedInt(i));
intptr_t val = (intptr_t)i.index;
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, 1);
}
bool
PyStackRef_IsNullOrInt(_PyStackRef ref)
{
return PyStackRef_IsNull(ref) || PyStackRef_IsTaggedInt(ref);
}
#endif #endif

View file

@ -678,6 +678,9 @@ NON_ESCAPING_FUNCTIONS = (
"JUMP_TO_LABEL", "JUMP_TO_LABEL",
"restart_backoff_counter", "restart_backoff_counter",
"_Py_ReachedRecursionLimit", "_Py_ReachedRecursionLimit",
"PyStackRef_IsTaggedInt",
"PyStackRef_TagInt",
"PyStackRef_UntagInt",
) )
def check_escaping_calls(instr: parser.CodeDef, escapes: dict[SimpleStmt, EscapingCall]) -> None: def check_escaping_calls(instr: parser.CodeDef, escapes: dict[SimpleStmt, EscapingCall]) -> None:

View file

@ -293,6 +293,7 @@ class StencilGroup:
hole.kind hole.kind
in {"R_AARCH64_CALL26", "R_AARCH64_JUMP26", "ARM64_RELOC_BRANCH26"} in {"R_AARCH64_CALL26", "R_AARCH64_JUMP26", "ARM64_RELOC_BRANCH26"}
and hole.value is HoleValue.ZERO and hole.value is HoleValue.ZERO
and hole.symbol not in self.symbols
): ):
hole.func = "patch_aarch64_trampoline" hole.func = "patch_aarch64_trampoline"
hole.need_state = True hole.need_state = True