@@ -3034,57 +3034,28 @@ Py_ReprLeave(PyObject *obj)
3034
3034
3035
3035
/* Trashcan support. */
3036
3036
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
-
3073
3037
/* 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.
3076
3040
*/
3077
3041
void
3078
3042
_PyTrash_thread_deposit_object (PyThreadState * tstate , PyObject * op )
3079
3043
{
3080
3044
_PyObject_ASSERT (op , Py_REFCNT (op ) == 0 );
3045
+ PyTypeObject * tp = Py_TYPE (op );
3046
+ assert (tp -> tp_flags & Py_TPFLAGS_HAVE_GC );
3047
+ int tracked = 0 ;
3048
+ if (tp -> tp_is_gc == NULL || tp -> tp_is_gc (op )) {
3049
+ tracked = _PyObject_GC_IS_TRACKED (op );
3050
+ if (tracked ) {
3051
+ _PyObject_GC_UNTRACK (op );
3052
+ }
3053
+ }
3054
+ uintptr_t tagged_ptr = ((uintptr_t )tstate -> delete_later ) | tracked ;
3081
3055
#ifdef Py_GIL_DISABLED
3082
- op -> ob_tid = ( uintptr_t ) tstate -> delete_later ;
3056
+ op -> ob_tid = tagged_ptr ;
3083
3057
#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 ));
3058
+ _Py_AS_GC (op )-> _gc_next = tagged_ptr ;
3088
3059
#endif
3089
3060
tstate -> delete_later = op ;
3090
3061
}
@@ -3099,17 +3070,17 @@ _PyTrash_thread_destroy_chain(PyThreadState *tstate)
3099
3070
destructor dealloc = Py_TYPE (op )-> tp_dealloc ;
3100
3071
3101
3072
#ifdef Py_GIL_DISABLED
3102
- tstate -> delete_later = ( PyObject * ) op -> ob_tid ;
3073
+ uintptr_t tagged_ptr = op -> ob_tid ;
3103
3074
op -> ob_tid = 0 ;
3104
3075
_Py_atomic_store_ssize_relaxed (& op -> ob_ref_shared , _Py_REF_MERGED );
3105
3076
#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 ;
3077
+ uintptr_t tagged_ptr = _Py_AS_GC (op )-> _gc_next ;
3078
+ _Py_AS_GC (op )-> _gc_next = 0 ;
3111
3079
#endif
3112
-
3080
+ tstate -> delete_later = (PyObject * )(tagged_ptr & ~1 );
3081
+ if (tagged_ptr & 1 ) {
3082
+ _PyObject_GC_TRACK (op );
3083
+ }
3113
3084
/* Call the deallocator directly. This used to try to
3114
3085
* fool Py_DECREF into calling it indirectly, but
3115
3086
* Py_DECREF was already called on this object, and in
@@ -3183,10 +3154,11 @@ void
3183
3154
_Py_Dealloc (PyObject * op )
3184
3155
{
3185
3156
PyTypeObject * type = Py_TYPE (op );
3157
+ unsigned long gc_flag = type -> tp_flags & Py_TPFLAGS_HAVE_GC ;
3186
3158
destructor dealloc = type -> tp_dealloc ;
3187
3159
PyThreadState * tstate = _PyThreadState_GET ();
3188
3160
intptr_t margin = _Py_RecursionLimit_GetMargin (tstate );
3189
- if (margin < 2 ) {
3161
+ if (margin < 2 && gc_flag ) {
3190
3162
_PyTrash_thread_deposit_object (tstate , (PyObject * )op );
3191
3163
return ;
3192
3164
}
@@ -3232,7 +3204,7 @@ _Py_Dealloc(PyObject *op)
3232
3204
Py_XDECREF (old_exc );
3233
3205
Py_DECREF (type );
3234
3206
#endif
3235
- if (tstate -> delete_later && margin >= 4 ) {
3207
+ if (tstate -> delete_later && margin >= 4 && gc_flag ) {
3236
3208
_PyTrash_thread_destroy_chain (tstate );
3237
3209
}
3238
3210
}
0 commit comments