@@ -55,6 +55,26 @@ list_capacity(PyObject **items)
5555}
5656#endif
5757
58+ #ifdef Py_DEBUG
59+ static void validate (PyObject * op )
60+ {
61+ if (op == NULL ) {
62+ return ;
63+ }
64+ if (((PyListObject * )op )-> ob_item == NULL ) {
65+ return ;
66+ }
67+ if (!(op -> ob_flags & _Py_MORTAL_CHILDREN_FLAG )) {
68+ int i = Py_SIZE (op );
69+ while (-- i >= 0 ) {
70+ assert (((PyListObject * )op )-> ob_item [i ] == NULL || _Py_IsImmortal (((PyListObject * )op )-> ob_item [i ]));
71+ }
72+ }
73+ }
74+ #else
75+ #define validate (op ) ((void)0)
76+ #endif
77+
5878static void
5979free_list_items (PyObject * * items , bool use_qsbr )
6080{
@@ -464,6 +484,8 @@ PyList_SetItem(PyObject *op, Py_ssize_t i,
464484 }
465485 PyObject * tmp = self -> ob_item [i ];
466486 FT_ATOMIC_STORE_PTR_RELEASE (self -> ob_item [i ], newitem );
487+ _PyList_UPDATE_MORTAL (op , newitem );
488+ validate (op );
467489 Py_XDECREF (tmp );
468490 ret = 0 ;
469491end :;
@@ -496,6 +518,8 @@ ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
496518 for (i = n ; -- i >= where ; )
497519 FT_ATOMIC_STORE_PTR_RELAXED (items [i + 1 ], items [i ]);
498520 FT_ATOMIC_STORE_PTR_RELEASE (items [where ], Py_NewRef (v ));
521+ _PyList_UPDATE_MORTAL (self , v );
522+ validate ((PyObject * )self );
499523 return 0 ;
500524}
501525
@@ -520,11 +544,16 @@ _PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem)
520544{
521545 Py_ssize_t len = Py_SIZE (self );
522546 assert (self -> allocated == -1 || self -> allocated == len );
547+
548+ validate ((PyObject * )self );
549+
523550 if (list_resize (self , len + 1 ) < 0 ) {
524551 Py_DECREF (newitem );
525552 return -1 ;
526553 }
527554 FT_ATOMIC_STORE_PTR_RELEASE (self -> ob_item [len ], newitem );
555+ _PyList_UPDATE_MORTAL (self , newitem );
556+ validate ((PyObject * )self );
528557 return 0 ;
529558}
530559
@@ -556,9 +585,11 @@ list_dealloc(PyObject *self)
556585 There's a simple test case where somehow this reduces
557586 thrashing when a *very* large list is created and
558587 immediately deleted. */
559- i = Py_SIZE (op );
560- while (-- i >= 0 ) {
561- Py_XDECREF (op -> ob_item [i ]);
588+ if (!PyList_CheckExact (self ) || self -> ob_flags & _Py_MORTAL_CHILDREN_FLAG ) {
589+ i = Py_SIZE (op );
590+ while (-- i >= 0 ) {
591+ Py_XDECREF (op -> ob_item [i ]);
592+ }
562593 }
563594 free_list_items (op -> ob_item , false);
564595 op -> ob_item = NULL ;
@@ -700,8 +731,10 @@ list_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
700731 for (i = 0 ; i < len ; i ++ ) {
701732 PyObject * v = src [i ];
702733 dest [i ] = Py_NewRef (v );
734+ _PyList_UPDATE_MORTAL (np , v );
703735 }
704736 Py_SET_SIZE (np , len );
737+ validate ((PyObject * )np );
705738 return (PyObject * )np ;
706739}
707740
@@ -752,14 +785,20 @@ list_concat_lock_held(PyListObject *a, PyListObject *b)
752785 for (i = 0 ; i < Py_SIZE (a ); i ++ ) {
753786 PyObject * v = src [i ];
754787 dest [i ] = Py_NewRef (v );
788+ _PyList_UPDATE_MORTAL (np , v );
755789 }
756790 src = b -> ob_item ;
757791 dest = np -> ob_item + Py_SIZE (a );
758792 for (i = 0 ; i < Py_SIZE (b ); i ++ ) {
759793 PyObject * v = src [i ];
760794 dest [i ] = Py_NewRef (v );
795+ _PyList_UPDATE_MORTAL (np , v );
761796 }
762797 Py_SET_SIZE (np , size );
798+
799+ // TODO: Why doesn't this work?
800+ // ((PyObject *)np)->ob_flags |= ((((PyObject *)a)->ob_flags | ((PyObject *)b)->ob_flags) & _Py_MORTAL_CHILDREN_FLAG);
801+ validate ((PyObject * )np );
763802 return (PyObject * )np ;
764803}
765804
@@ -818,8 +857,10 @@ list_repeat_lock_held(PyListObject *a, Py_ssize_t n)
818857 _Py_memory_repeat ((char * )np -> ob_item , sizeof (PyObject * )* output_size ,
819858 sizeof (PyObject * )* input_size );
820859 }
860+ ((PyObject * )np )-> ob_flags |= (((PyObject * )a )-> ob_flags & _Py_MORTAL_CHILDREN_FLAG );
821861
822862 Py_SET_SIZE (np , output_size );
863+ validate ((PyObject * )np );
823864 return (PyObject * ) np ;
824865}
825866
@@ -848,8 +889,11 @@ list_clear_impl(PyListObject *a, bool is_resize)
848889 Py_SET_SIZE (a , 0 );
849890 FT_ATOMIC_STORE_PTR_RELEASE (a -> ob_item , NULL );
850891 a -> allocated = 0 ;
851- while (-- i >= 0 ) {
852- Py_XDECREF (items [i ]);
892+ if (((PyObject * )a )-> ob_flags & _Py_MORTAL_CHILDREN_FLAG ) {
893+ while (-- i >= 0 ) {
894+ Py_XDECREF (items [i ]);
895+ }
896+ ((PyObject * )a )-> ob_flags &= ~_Py_MORTAL_CHILDREN_FLAG ;
853897 }
854898#ifdef Py_GIL_DISABLED
855899 if (is_resize ) {
@@ -958,6 +1002,8 @@ list_ass_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyO
9581002 goto Error ;
9591003 }
9601004 item = a -> ob_item ;
1005+ // Technically we could check if all the remaining items are immortal,
1006+ // but that's an O(n) operation.
9611007 }
9621008 else if (d > 0 ) { /* Insert d items */
9631009 k = Py_SIZE (a );
@@ -972,6 +1018,7 @@ list_ass_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyO
9721018 for (k = 0 ; k < n ; k ++ , ilow ++ ) {
9731019 PyObject * w = vitem [k ];
9741020 FT_ATOMIC_STORE_PTR_RELEASE (item [ilow ], Py_XNewRef (w ));
1021+ _PyList_UPDATE_MORTAL (a , w );
9751022 }
9761023 for (k = norig - 1 ; k >= 0 ; -- k )
9771024 Py_XDECREF (recycle [k ]);
@@ -980,6 +1027,7 @@ list_ass_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyO
9801027 if (recycle != recycle_on_stack )
9811028 PyMem_Free (recycle );
9821029 Py_XDECREF (v_as_SF );
1030+ validate ((PyObject * )a );
9831031 return result ;
9841032#undef b
9851033}
@@ -1048,8 +1096,10 @@ list_inplace_repeat_lock_held(PyListObject *self, Py_ssize_t n)
10481096 }
10491097
10501098 PyObject * * items = self -> ob_item ;
1051- for (Py_ssize_t j = 0 ; j < input_size ; j ++ ) {
1052- _Py_RefcntAdd (items [j ], n - 1 );
1099+ if (((PyObject * )self )-> ob_flags & _Py_MORTAL_CHILDREN_FLAG ) {
1100+ for (Py_ssize_t j = 0 ; j < input_size ; j ++ ) {
1101+ _Py_RefcntAdd (items [j ], n - 1 );
1102+ }
10531103 }
10541104 // TODO: _Py_memory_repeat calls are not safe for shared lists in
10551105 // GIL_DISABLED builds. (See issue #129069)
@@ -1092,6 +1142,8 @@ list_ass_item_lock_held(PyListObject *a, Py_ssize_t i, PyObject *v)
10921142 }
10931143 else {
10941144 FT_ATOMIC_STORE_PTR_RELEASE (a -> ob_item [i ], Py_NewRef (v ));
1145+ _PyList_UPDATE_MORTAL (a , v );
1146+ validate ((PyObject * )a );
10951147 }
10961148 Py_DECREF (tmp );
10971149 return 0 ;
@@ -1212,7 +1264,9 @@ list_extend_fast(PyListObject *self, PyObject *iterable)
12121264 for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
12131265 PyObject * o = src [i ];
12141266 FT_ATOMIC_STORE_PTR_RELEASE (dest [i ], Py_NewRef (o ));
1267+ _PyList_UPDATE_MORTAL (self , o );
12151268 }
1269+ validate ((PyObject * )self );
12161270 return 0 ;
12171271}
12181272
@@ -1269,7 +1323,9 @@ list_extend_iter_lock_held(PyListObject *self, PyObject *iterable)
12691323 if (Py_SIZE (self ) < self -> allocated ) {
12701324 Py_ssize_t len = Py_SIZE (self );
12711325 FT_ATOMIC_STORE_PTR_RELEASE (self -> ob_item [len ], item ); // steals item ref
1326+ _PyList_UPDATE_MORTAL (self , item );
12721327 Py_SET_SIZE (self , len + 1 );
1328+ validate ((PyObject * )self );
12731329 }
12741330 else {
12751331 if (_PyList_AppendTakeRef (self , item ) < 0 )
@@ -1319,9 +1375,11 @@ list_extend_set(PyListObject *self, PySetObject *other)
13191375 PyObject * * dest = self -> ob_item + m ;
13201376 while (_PySet_NextEntryRef ((PyObject * )other , & setpos , & key , & hash )) {
13211377 FT_ATOMIC_STORE_PTR_RELEASE (* dest , key );
1378+ _PyList_UPDATE_MORTAL (self , key );
13221379 dest ++ ;
13231380 }
13241381 Py_SET_SIZE (self , m + n );
1382+ validate ((PyObject * )self );
13251383 return 0 ;
13261384}
13271385
@@ -1342,10 +1400,12 @@ list_extend_dict(PyListObject *self, PyDictObject *dict, int which_item)
13421400 PyObject * obj = keyvalue [which_item ];
13431401 Py_INCREF (obj );
13441402 FT_ATOMIC_STORE_PTR_RELEASE (* dest , obj );
1403+ _PyList_UPDATE_MORTAL (self , obj );
13451404 dest ++ ;
13461405 }
13471406
13481407 Py_SET_SIZE (self , m + n );
1408+ validate ((PyObject * )self );
13491409 return 0 ;
13501410}
13511411
@@ -1369,11 +1429,13 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict)
13691429 return -1 ;
13701430 }
13711431 FT_ATOMIC_STORE_PTR_RELEASE (* dest , item );
1432+ _PyList_UPDATE_MORTAL (self , item );
13721433 dest ++ ;
13731434 i ++ ;
13741435 }
13751436
13761437 Py_SET_SIZE (self , m + n );
1438+ validate ((PyObject * )self );
13771439 return 0 ;
13781440}
13791441
@@ -3221,6 +3283,8 @@ _PyList_AsTupleAndClear(PyListObject *self)
32213283 Py_SET_SIZE (self , 0 );
32223284 ret = _PyTuple_FromArraySteal (items , size );
32233285 free_list_items (items , false);
3286+ ((PyObject * )self )-> ob_flags &= ~_Py_MORTAL_CHILDREN_FLAG ;
3287+ validate ((PyObject * )self );
32243288 Py_END_CRITICAL_SECTION ();
32253289 return ret ;
32263290}
@@ -3240,6 +3304,7 @@ _PyList_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n)
32403304 PyObject * * dst = list -> ob_item ;
32413305 for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
32423306 dst [i ] = PyStackRef_AsPyObjectSteal (src [i ]);
3307+ _PyList_UPDATE_MORTAL (list , dst [i ]);
32433308 }
32443309
32453310 return (PyObject * )list ;
0 commit comments