@@ -2923,57 +2923,28 @@ Py_ReprLeave(PyObject *obj)
2923
2923
2924
2924
/* Trashcan support. */
2925
2925
2926
- #ifndef Py_GIL_DISABLED
2927
- /* We need to store a pointer in the refcount field of
2928
- * an object. It is important that we never store 0 (NULL).
2929
- * It is also important to not make the object appear immortal,
2930
- * or it might be untracked by the cycle GC. */
2931
- static uintptr_t
2932
- pointer_to_safe_refcount (void * ptr )
2933
- {
2934
- uintptr_t full = (uintptr_t )ptr ;
2935
- assert ((full & 3 ) == 0 );
2936
- #if SIZEOF_VOID_P > 4
2937
- uint32_t refcnt = (uint32_t )full ;
2938
- if (refcnt >= (uint32_t )_Py_IMMORTAL_MINIMUM_REFCNT ) {
2939
- full = full - ((uintptr_t )_Py_IMMORTAL_MINIMUM_REFCNT ) + 1 ;
2940
- }
2941
- return full + 2 ;
2942
- #else
2943
- // Make the top two bits 0, so it appears mortal.
2944
- return (full >> 2 ) + 1 ;
2945
- #endif
2946
- }
2947
-
2948
- static void *
2949
- safe_refcount_to_pointer (uintptr_t refcnt )
2950
- {
2951
- #if SIZEOF_VOID_P > 4
2952
- if (refcnt & 1 ) {
2953
- refcnt += _Py_IMMORTAL_MINIMUM_REFCNT - 1 ;
2954
- }
2955
- return (void * )(refcnt - 2 );
2956
- #else
2957
- return (void * )((refcnt - 1 ) << 2 );
2958
- #endif
2959
- }
2960
- #endif
2961
-
2962
2926
/* Add op to the gcstate->trash_delete_later list. Called when the current
2963
- * call-stack depth gets large. op must be a currently untracked gc'ed
2964
- * object, with refcount 0. Py_DECREF must already have been called on it.
2927
+ * call-stack depth gets large. op must be a gc'ed object, with refcount 0.
2928
+ * Py_DECREF must already have been called on it.
2965
2929
*/
2966
2930
void
2967
2931
_PyTrash_thread_deposit_object (PyThreadState * tstate , PyObject * op )
2968
2932
{
2969
2933
_PyObject_ASSERT (op , Py_REFCNT (op ) == 0 );
2934
+ PyTypeObject * tp = Py_TYPE (op );
2935
+ assert (tp -> tp_flags & Py_TPFLAGS_HAVE_GC );
2936
+ int tracked = 0 ;
2937
+ if (tp -> tp_is_gc == NULL || tp -> tp_is_gc (op )) {
2938
+ tracked = _PyObject_GC_IS_TRACKED (op );
2939
+ if (tracked ) {
2940
+ _PyObject_GC_UNTRACK (op );
2941
+ }
2942
+ }
2943
+ uintptr_t tagged_ptr = ((uintptr_t )tstate -> delete_later ) | tracked ;
2970
2944
#ifdef Py_GIL_DISABLED
2971
- op -> ob_tid = ( uintptr_t ) tstate -> delete_later ;
2945
+ op -> ob_tid = tagged_ptr ;
2972
2946
#else
2973
- /* Store the delete_later pointer in the refcnt field. */
2974
- uintptr_t refcnt = pointer_to_safe_refcount (tstate -> delete_later );
2975
- * ((uintptr_t * )op ) = refcnt ;
2976
- assert (!_Py_IsImmortal (op ));
2947
+ _Py_AS_GC (op )-> _gc_next = tagged_ptr ;
2977
2948
#endif
2978
2949
tstate -> delete_later = op ;
2979
2950
}
@@ -2988,17 +2959,17 @@ _PyTrash_thread_destroy_chain(PyThreadState *tstate)
2988
2959
destructor dealloc = Py_TYPE (op )-> tp_dealloc ;
2989
2960
2990
2961
#ifdef Py_GIL_DISABLED
2991
- tstate -> delete_later = ( PyObject * ) op -> ob_tid ;
2962
+ uintptr_t tagged_ptr = op -> ob_tid ;
2992
2963
op -> ob_tid = 0 ;
2993
2964
_Py_atomic_store_ssize_relaxed (& op -> ob_ref_shared , _Py_REF_MERGED );
2994
2965
#else
2995
- /* Get the delete_later pointer from the refcnt field.
2996
- * See _PyTrash_thread_deposit_object(). */
2997
- uintptr_t refcnt = * ((uintptr_t * )op );
2998
- tstate -> delete_later = safe_refcount_to_pointer (refcnt );
2999
- op -> ob_refcnt = 0 ;
2966
+ uintptr_t tagged_ptr = _Py_AS_GC (op )-> _gc_next ;
2967
+ _Py_AS_GC (op )-> _gc_next = 0 ;
3000
2968
#endif
3001
-
2969
+ tstate -> delete_later = (PyObject * )(tagged_ptr & ~1 );
2970
+ if (tagged_ptr & 1 ) {
2971
+ _PyObject_GC_TRACK (op );
2972
+ }
3002
2973
/* Call the deallocator directly. This used to try to
3003
2974
* fool Py_DECREF into calling it indirectly, but
3004
2975
* Py_DECREF was already called on this object, and in
@@ -3072,10 +3043,11 @@ void
3072
3043
_Py_Dealloc (PyObject * op )
3073
3044
{
3074
3045
PyTypeObject * type = Py_TYPE (op );
3046
+ unsigned long gc_flag = type -> tp_flags & Py_TPFLAGS_HAVE_GC ;
3075
3047
destructor dealloc = type -> tp_dealloc ;
3076
3048
PyThreadState * tstate = _PyThreadState_GET ();
3077
3049
intptr_t margin = _Py_RecursionLimit_GetMargin (tstate );
3078
- if (margin < 2 ) {
3050
+ if (margin < 2 && gc_flag ) {
3079
3051
_PyTrash_thread_deposit_object (tstate , (PyObject * )op );
3080
3052
return ;
3081
3053
}
@@ -3121,7 +3093,7 @@ _Py_Dealloc(PyObject *op)
3121
3093
Py_XDECREF (old_exc );
3122
3094
Py_DECREF (type );
3123
3095
#endif
3124
- if (tstate -> delete_later && margin >= 4 ) {
3096
+ if (tstate -> delete_later && margin >= 4 && gc_flag ) {
3125
3097
_PyTrash_thread_destroy_chain (tstate );
3126
3098
}
3127
3099
}
0 commit comments