@@ -762,10 +762,28 @@ typedef struct lru_list_elem {
762
762
PyObject * key , * result ;
763
763
} lru_list_elem ;
764
764
765
+ static int
766
+ lru_list_elem_clear (lru_list_elem * link )
767
+ {
768
+ Py_CLEAR (link -> key );
769
+ Py_CLEAR (link -> result );
770
+ return 0 ;
771
+ }
772
+
773
+ static int
774
+ lru_list_elem_traverse (lru_list_elem * link , visitproc visit , void * arg )
775
+ {
776
+ Py_VISIT (link -> key );
777
+ Py_VISIT (link -> result );
778
+ Py_VISIT (Py_TYPE (link ));
779
+ return 0 ;
780
+ }
781
+
765
782
static void
766
783
lru_list_elem_dealloc (lru_list_elem * link )
767
784
{
768
785
PyTypeObject * tp = Py_TYPE (link );
786
+ PyObject_GC_UnTrack (link );
769
787
Py_XDECREF (link -> key );
770
788
Py_XDECREF (link -> result );
771
789
tp -> tp_free (link );
@@ -774,13 +792,16 @@ lru_list_elem_dealloc(lru_list_elem *link)
774
792
775
793
static PyType_Slot lru_list_elem_type_slots [] = {
776
794
{Py_tp_dealloc , lru_list_elem_dealloc },
795
+ {Py_tp_traverse , lru_list_elem_traverse },
796
+ {Py_tp_clear , lru_list_elem_clear },
777
797
{0 , 0 }
778
798
};
779
799
780
800
static PyType_Spec lru_list_elem_type_spec = {
781
801
.name = "functools._lru_list_elem" ,
782
802
.basicsize = sizeof (lru_list_elem ),
783
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION ,
803
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
804
+ Py_TPFLAGS_HAVE_GC ),
784
805
.slots = lru_list_elem_type_slots
785
806
};
786
807
@@ -1045,8 +1066,8 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
1045
1066
self -> root .next == & self -> root )
1046
1067
{
1047
1068
/* Cache is not full, so put the result in a new link */
1048
- link = (lru_list_elem * )PyObject_New (lru_list_elem ,
1049
- self -> lru_list_elem_type );
1069
+ link = (lru_list_elem * )PyObject_GC_New (lru_list_elem ,
1070
+ self -> lru_list_elem_type );
1050
1071
if (link == NULL ) {
1051
1072
Py_DECREF (key );
1052
1073
Py_DECREF (result );
@@ -1056,6 +1077,7 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
1056
1077
link -> hash = hash ;
1057
1078
link -> key = key ;
1058
1079
link -> result = result ;
1080
+ PyObject_GC_Track (link );
1059
1081
/* What is really needed here is a SetItem variant with a "no clobber"
1060
1082
option. If the __eq__ call triggers a reentrant call that adds
1061
1083
this same key, then this setitem call will update the cache dict
@@ -1345,9 +1367,7 @@ lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1345
1367
lru_list_elem * link = self -> root .next ;
1346
1368
while (link != & self -> root ) {
1347
1369
lru_list_elem * next = link -> next ;
1348
- Py_VISIT (link -> key );
1349
- Py_VISIT (link -> result );
1350
- Py_VISIT (Py_TYPE (link ));
1370
+ Py_VISIT (link );
1351
1371
link = next ;
1352
1372
}
1353
1373
Py_VISIT (self -> cache );
0 commit comments