@@ -3034,57 +3034,24 @@ Py_ReprLeave(PyObject *obj)
30343034
30353035/* Trashcan support. */
30363036
3037- #ifndef Py_GIL_DISABLED
3038- /* We need to store a pointer in the refcount field of
3039- * an object. It is important that we never store 0 (NULL).
3040- * It is also important to not make the object appear immortal,
3041- * or it might be untracked by the cycle GC. */
3042- static uintptr_t
3043- pointer_to_safe_refcount (void * ptr )
3044- {
3045- uintptr_t full = (uintptr_t )ptr ;
3046- assert ((full & 3 ) == 0 );
3047- #if SIZEOF_VOID_P > 4
3048- uint32_t refcnt = (uint32_t )full ;
3049- if (refcnt >= (uint32_t )_Py_IMMORTAL_MINIMUM_REFCNT ) {
3050- full = full - ((uintptr_t )_Py_IMMORTAL_MINIMUM_REFCNT ) + 1 ;
3051- }
3052- return full + 2 ;
3053- #else
3054- // Make the top two bits 0, so it appears mortal.
3055- return (full >> 2 ) + 1 ;
3056- #endif
3057- }
3058-
3059- static void *
3060- safe_refcount_to_pointer (uintptr_t refcnt )
3061- {
3062- #if SIZEOF_VOID_P > 4
3063- if (refcnt & 1 ) {
3064- refcnt += _Py_IMMORTAL_MINIMUM_REFCNT - 1 ;
3065- }
3066- return (void * )(refcnt - 2 );
3067- #else
3068- return (void * )((refcnt - 1 ) << 2 );
3069- #endif
3070- }
3071- #endif
3072-
30733037/* Add op to the gcstate->trash_delete_later list. Called when the current
3074- * call-stack depth gets large. op must be a currently untracked gc'ed
3075- * object, with refcount 0. Py_DECREF must already have been called on it.
3038+ * call-stack depth gets large. op must be a gc'ed object, with refcount 0.
3039+ * Py_DECREF must already have been called on it.
30763040 */
30773041void
30783042_PyTrash_thread_deposit_object (PyThreadState * tstate , PyObject * op )
30793043{
30803044 _PyObject_ASSERT (op , Py_REFCNT (op ) == 0 );
3045+ assert (PyObject_IS_GC (op ));
3046+ int tracked = _PyObject_GC_IS_TRACKED (op );
3047+ if (tracked ) {
3048+ _PyObject_GC_UNTRACK (op );
3049+ }
3050+ uintptr_t tagged_ptr = ((uintptr_t )tstate -> delete_later ) | tracked ;
30813051#ifdef Py_GIL_DISABLED
3082- op -> ob_tid = ( uintptr_t ) tstate -> delete_later ;
3052+ op -> ob_tid = tagged_ptr ;
30833053#else
3084- /* Store the delete_later pointer in the refcnt field. */
3085- uintptr_t refcnt = pointer_to_safe_refcount (tstate -> delete_later );
3086- * ((uintptr_t * )op ) = refcnt ;
3087- assert (!_Py_IsImmortal (op ));
3054+ _Py_AS_GC (op )-> _gc_next = tagged_ptr ;
30883055#endif
30893056 tstate -> delete_later = op ;
30903057}
@@ -3099,25 +3066,28 @@ _PyTrash_thread_destroy_chain(PyThreadState *tstate)
30993066 destructor dealloc = Py_TYPE (op )-> tp_dealloc ;
31003067
31013068#ifdef Py_GIL_DISABLED
3102- tstate -> delete_later = ( PyObject * ) op -> ob_tid ;
3069+ uintptr_t tagged_ptr = op -> ob_tid ;
31033070 op -> ob_tid = 0 ;
31043071 _Py_atomic_store_ssize_relaxed (& op -> ob_ref_shared , _Py_REF_MERGED );
31053072#else
3106- /* Get the delete_later pointer from the refcnt field.
3107- * See _PyTrash_thread_deposit_object(). */
3108- uintptr_t refcnt = * ((uintptr_t * )op );
3109- tstate -> delete_later = safe_refcount_to_pointer (refcnt );
3110- op -> ob_refcnt = 0 ;
3073+ uintptr_t tagged_ptr = _Py_AS_GC (op )-> _gc_next ;
3074+ _Py_AS_GC (op )-> _gc_next = 0 ;
31113075#endif
3112-
3113- /* Call the deallocator directly. This used to try to
3114- * fool Py_DECREF into calling it indirectly, but
3115- * Py_DECREF was already called on this object, and in
3116- * assorted non-release builds calling Py_DECREF again ends
3117- * up distorting allocation statistics.
3118- */
3119- _PyObject_ASSERT (op , Py_REFCNT (op ) == 0 );
3120- (* dealloc )(op );
3076+ tstate -> delete_later = (PyObject * )(tagged_ptr & ~1 );
3077+ if (tagged_ptr & 1 ) {
3078+ _PyObject_GC_TRACK (op );
3079+ }
3080+ /* It is possible that the object has been accessed through
3081+ * a weak ref, so only free if refcount == 0) */
3082+ if (Py_REFCNT (op ) == 0 ) {
3083+ /* Call the deallocator directly. This used to try to
3084+ * fool Py_DECREF into calling it indirectly, but
3085+ * Py_DECREF was already called on this object, and in
3086+ * assorted non-release builds calling Py_DECREF again ends
3087+ * up distorting allocation statistics.
3088+ */
3089+ (* dealloc )(op );
3090+ }
31213091 }
31223092}
31233093
@@ -3186,7 +3156,7 @@ _Py_Dealloc(PyObject *op)
31863156 destructor dealloc = type -> tp_dealloc ;
31873157 PyThreadState * tstate = _PyThreadState_GET ();
31883158 intptr_t margin = _Py_RecursionLimit_GetMargin (tstate );
3189- if (margin < 2 ) {
3159+ if (margin < 2 && PyObject_IS_GC ( op ) ) {
31903160 _PyTrash_thread_deposit_object (tstate , (PyObject * )op );
31913161 return ;
31923162 }
0 commit comments