@@ -288,12 +288,30 @@ static inline Py_ALWAYS_INLINE int _Py_IsImmutable(PyObject *op)
288288#endif
289289#define Py_REQUIREWRITE (op , msg ) {if (Py_CHECKWRITE(op)) { _PyObject_ASSERT_FAILED_MSG(op, msg); }}
290290
291+ static inline Py_ALWAYS_INLINE int _Py_IsImmortalOrImmutable (PyObject * op )
292+ {
293+ // TODO(Immutable): Does this work for both 32 and 64bit?
294+ return op -> ob_refcnt >= _Py_IMMORTAL_REFCNT ;
295+ }
296+ #define _Py_IsImmortalOrImmutable (op ) _Py_IsImmortalOrImmutable(_PyObject_CAST(op))
297+
291298static inline void Py_SET_REFCNT (PyObject * ob , Py_ssize_t refcnt ) {
292299 // This immortal check is for code that is unaware of immortal objects.
293300 // The runtime tracks these objects and we should avoid as much
294301 // as possible having extensions inadvertently change the refcnt
295302 // of an immortalized object.
296- if (_Py_IsImmortal (ob )) {
303+ if (_Py_IsImmortalOrImmutable (ob ))
304+ {
305+ if (_Py_IsImmortal (ob )) {
306+ return ;
307+ }
308+ assert (_Py_IsImmutable (ob ));
309+ // TODO(Immutable): It is dangerous to set the reference count of an
310+ // immutable object. The majority of calls appear to be where the rc
311+ // has reached 0 and a finalizer is running. This seems a reasonable
312+ // place to allow the refcnt to be set to 1, and clear the immutable flag.
313+ assert ((ob -> ob_refcnt & _Py_REFCNT_MASK ) == 0 );
314+ ob -> ob_refcnt = refcnt ;
297315 return ;
298316 }
299317 ob -> ob_refcnt = (ob -> ob_refcnt & _Py_IMMUTABLE_MASK ) | (refcnt & _Py_REFCNT_MASK );
@@ -655,6 +673,8 @@ PyAPI_FUNC(void) Py_DecRef(PyObject *);
655673PyAPI_FUNC (void ) _Py_IncRef (PyObject * );
656674PyAPI_FUNC (void ) _Py_DecRef (PyObject * );
657675
676+ PyAPI_FUNC (int ) _Py_DecRef_Immutable (PyObject * op );
677+
658678static inline Py_ALWAYS_INLINE void Py_INCREF (PyObject * op )
659679{
660680#if defined(Py_LIMITED_API ) && (Py_LIMITED_API + 0 >= 0x030c0000 || defined(Py_REF_DEBUG ))
@@ -715,7 +735,15 @@ static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
715735 if (op -> ob_refcnt <= 0 ) {
716736 _Py_NegativeRefcount (filename , lineno , op );
717737 }
718- if (_Py_IsImmortal (op )) {
738+
739+ if (_Py_IsImmortalOrImmutable (op ))
740+ {
741+ if (_Py_IsImmortal (op )) {
742+ return ;
743+ }
744+ assert (_Py_IsImmutable (op ));
745+ if (_Py_DecRef_Immutable (op ))
746+ _Py_Dealloc (op );
719747 return ;
720748 }
721749 _Py_DECREF_STAT_INC ();
@@ -732,7 +760,14 @@ static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
732760{
733761 // Non-limited C API and limited C API for Python 3.9 and older access
734762 // directly PyObject.ob_refcnt.
735- if (_Py_IsImmortal (op )) {
763+ if (_Py_IsImmortalOrImmutable (op ))
764+ {
765+ if (_Py_IsImmortal (op )) {
766+ return ;
767+ }
768+ assert (_Py_IsImmutable (op ));
769+ if (_Py_DecRef_Immutable (op ))
770+ _Py_Dealloc (op );
736771 return ;
737772 }
738773 _Py_DECREF_STAT_INC ();
0 commit comments