@@ -3363,7 +3363,7 @@ test_gc_visit_objects_basic(PyObject *Py_UNUSED(self),
33633363 }
33643364 state .target = obj ;
33653365 state .found = 0 ;
3366-
3366+
33673367 PyUnstable_GC_VisitObjects (gc_visit_callback_basic , & state );
33683368 Py_DECREF (obj );
33693369 if (!state .found ) {
@@ -3400,6 +3400,98 @@ test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self),
34003400 Py_RETURN_NONE ;
34013401}
34023402
3403+ typedef struct {
3404+ PyObject_HEAD
3405+ } ObjExtraData ;
3406+
3407+ static PyObject *
3408+ obj_extra_data_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
3409+ {
3410+ size_t extra_size = sizeof (PyObject * );
3411+ PyObject * obj = PyUnstable_Object_GC_NewWithExtraData (type , extra_size );
3412+ if (obj == NULL ) {
3413+ return PyErr_NoMemory ();
3414+ }
3415+ PyObject_GC_Track (obj );
3416+ return obj ;
3417+ }
3418+
3419+ static PyObject * *
3420+ obj_extra_data_get_extra_storage (PyObject * self )
3421+ {
3422+ return (PyObject * * )((char * )self + Py_TYPE (self )-> tp_basicsize );
3423+ }
3424+
3425+ static PyObject *
3426+ obj_extra_data_get (PyObject * self , void * Py_UNUSED (ignored ))
3427+ {
3428+ PyObject * * extra_storage = obj_extra_data_get_extra_storage (self );
3429+ PyObject * value = * extra_storage ;
3430+ if (!value ) {
3431+ Py_RETURN_NONE ;
3432+ }
3433+ return Py_NewRef (value );
3434+ }
3435+
3436+ static int
3437+ obj_extra_data_set (PyObject * self , PyObject * newval , void * Py_UNUSED (ignored ))
3438+ {
3439+ PyObject * * extra_storage = obj_extra_data_get_extra_storage (self );
3440+ Py_CLEAR (* extra_storage );
3441+ if (newval ) {
3442+ * extra_storage = Py_NewRef (newval );
3443+ }
3444+ return 0 ;
3445+ }
3446+
3447+ static PyGetSetDef obj_extra_data_getset [] = {
3448+ {"extra" , (getter )obj_extra_data_get , (setter )obj_extra_data_set , NULL },
3449+ {NULL }
3450+ };
3451+
3452+ static int
3453+ obj_extra_data_traverse (PyObject * self , visitproc visit , void * arg )
3454+ {
3455+ PyObject * * extra_storage = obj_extra_data_get_extra_storage (self );
3456+ PyObject * value = * extra_storage ;
3457+ Py_VISIT (value );
3458+ return 0 ;
3459+ }
3460+
3461+ static int
3462+ obj_extra_data_clear (PyObject * self )
3463+ {
3464+ PyObject * * extra_storage = obj_extra_data_get_extra_storage (self );
3465+ Py_CLEAR (* extra_storage );
3466+ return 0 ;
3467+ }
3468+
3469+ static void
3470+ obj_extra_data_dealloc (PyObject * self )
3471+ {
3472+ PyTypeObject * tp = Py_TYPE (self );
3473+ PyObject_GC_UnTrack (self );
3474+ obj_extra_data_clear (self );
3475+ tp -> tp_free (self );
3476+ Py_DECREF (tp );
3477+ }
3478+
3479+ static PyType_Slot ObjExtraData_Slots [] = {
3480+ {Py_tp_getset , obj_extra_data_getset },
3481+ {Py_tp_dealloc , obj_extra_data_dealloc },
3482+ {Py_tp_traverse , obj_extra_data_traverse },
3483+ {Py_tp_clear , obj_extra_data_clear },
3484+ {Py_tp_new , obj_extra_data_new },
3485+ {Py_tp_free , PyObject_GC_Del },
3486+ {0 , NULL },
3487+ };
3488+
3489+ static PyType_Spec ObjExtraData_TypeSpec = {
3490+ .name = "_testcapi.ObjExtraData" ,
3491+ .basicsize = sizeof (ObjExtraData ),
3492+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC ,
3493+ .slots = ObjExtraData_Slots ,
3494+ };
34033495
34043496struct atexit_data {
34053497 int called ;
@@ -4124,6 +4216,17 @@ PyInit__testcapi(void)
41244216 Py_INCREF (& MethStatic_Type );
41254217 PyModule_AddObject (m , "MethStatic" , (PyObject * )& MethStatic_Type );
41264218
4219+ PyObject * ObjExtraData_Type = PyType_FromModuleAndSpec (
4220+ m , & ObjExtraData_TypeSpec , NULL );
4221+ if (ObjExtraData_Type == 0 ) {
4222+ return NULL ;
4223+ }
4224+ int ret = PyModule_AddType (m , (PyTypeObject * )ObjExtraData_Type );
4225+ Py_DECREF (& ObjExtraData_Type );
4226+ if (ret < 0 ) {
4227+ return NULL ;
4228+ }
4229+
41274230 PyModule_AddObject (m , "CHAR_MAX" , PyLong_FromLong (CHAR_MAX ));
41284231 PyModule_AddObject (m , "CHAR_MIN" , PyLong_FromLong (CHAR_MIN ));
41294232 PyModule_AddObject (m , "UCHAR_MAX" , PyLong_FromLong (UCHAR_MAX ));
0 commit comments