]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-93649: Split gc- and allocation tests from _testcapimodule.c (GH-104403)
authorJurica Bradarić <jbradaric@users.noreply.github.com>
Fri, 12 May 2023 09:26:07 +0000 (11:26 +0200)
committerGitHub <noreply@github.com>
Fri, 12 May 2023 09:26:07 +0000 (10:26 +0100)
Modules/Setup.stdlib.in
Modules/_testcapi/gc.c [new file with mode: 0644]
Modules/_testcapi/parts.h
Modules/_testcapimodule.c
PCbuild/_testcapi.vcxproj
PCbuild/_testcapi.vcxproj.filters

index 8e66576b5c5f0031bf309c5a2a4d480f235d68af..95409d48c0da027b8eaf331a30e7aad4d10e2638 100644 (file)
 @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
 @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
 @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
-@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c
+@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c
 @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
 
 # Some testing modules MUST be built as shared libraries.
diff --git a/Modules/_testcapi/gc.c b/Modules/_testcapi/gc.c
new file mode 100644 (file)
index 0000000..829200a
--- /dev/null
@@ -0,0 +1,344 @@
+#include "parts.h"
+
+static PyObject*
+test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    int orig_enabled = PyGC_IsEnabled();
+    const char* msg = "ok";
+    int old_state;
+
+    old_state = PyGC_Enable();
+    msg = "Enable(1)";
+    if (old_state != orig_enabled) {
+        goto failed;
+    }
+    msg = "IsEnabled(1)";
+    if (!PyGC_IsEnabled()) {
+        goto failed;
+    }
+
+    old_state = PyGC_Disable();
+    msg = "disable(2)";
+    if (!old_state) {
+        goto failed;
+    }
+    msg = "IsEnabled(2)";
+    if (PyGC_IsEnabled()) {
+        goto failed;
+    }
+
+    old_state = PyGC_Enable();
+    msg = "enable(3)";
+    if (old_state) {
+        goto failed;
+    }
+    msg = "IsEnabled(3)";
+    if (!PyGC_IsEnabled()) {
+        goto failed;
+    }
+
+    if (!orig_enabled) {
+        old_state = PyGC_Disable();
+        msg = "disable(4)";
+        if (old_state) {
+            goto failed;
+        }
+        msg = "IsEnabled(4)";
+        if (PyGC_IsEnabled()) {
+            goto failed;
+        }
+    }
+
+    Py_RETURN_NONE;
+
+failed:
+    /* Try to clean up if we can. */
+    if (orig_enabled) {
+        PyGC_Enable();
+    } else {
+        PyGC_Disable();
+    }
+    PyErr_Format(PyExc_ValueError, "GC control failed in %s", msg);
+    return NULL;
+}
+
+static PyObject *
+without_gc(PyObject *Py_UNUSED(self), PyObject *obj)
+{
+    PyTypeObject *tp = (PyTypeObject*)obj;
+    if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
+        return PyErr_Format(PyExc_TypeError, "heap type expected, got %R", obj);
+    }
+    if (PyType_IS_GC(tp)) {
+        // Don't try this at home, kids:
+        tp->tp_flags -= Py_TPFLAGS_HAVE_GC;
+        tp->tp_free = PyObject_Del;
+        tp->tp_traverse = NULL;
+        tp->tp_clear = NULL;
+    }
+    assert(!PyType_IS_GC(tp));
+    return Py_NewRef(obj);
+}
+
+static void
+slot_tp_del(PyObject *self)
+{
+    PyObject *del, *res;
+
+    /* Temporarily resurrect the object. */
+    assert(Py_REFCNT(self) == 0);
+    Py_SET_REFCNT(self, 1);
+
+    /* Save the current exception, if any. */
+    PyObject *exc = PyErr_GetRaisedException();
+
+    PyObject *tp_del = PyUnicode_InternFromString("__tp_del__");
+    if (tp_del == NULL) {
+        PyErr_WriteUnraisable(NULL);
+        PyErr_SetRaisedException(exc);
+        return;
+    }
+    /* Execute __del__ method, if any. */
+    del = _PyType_Lookup(Py_TYPE(self), tp_del);
+    Py_DECREF(tp_del);
+    if (del != NULL) {
+        res = PyObject_CallOneArg(del, self);
+        if (res == NULL)
+            PyErr_WriteUnraisable(del);
+        else
+            Py_DECREF(res);
+    }
+
+    /* Restore the saved exception. */
+    PyErr_SetRaisedException(exc);
+
+    /* Undo the temporary resurrection; can't use DECREF here, it would
+     * cause a recursive call.
+     */
+    assert(Py_REFCNT(self) > 0);
+    Py_SET_REFCNT(self, Py_REFCNT(self) - 1);
+    if (Py_REFCNT(self) == 0) {
+        /* this is the normal path out */
+        return;
+    }
+
+    /* __del__ resurrected it!  Make it look like the original Py_DECREF
+     * never happened.
+     */
+    {
+        Py_ssize_t refcnt = Py_REFCNT(self);
+        _Py_NewReferenceNoTotal(self);
+        Py_SET_REFCNT(self, refcnt);
+    }
+    assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self));
+}
+
+static PyObject *
+with_tp_del(PyObject *self, PyObject *args)
+{
+    PyObject *obj;
+    PyTypeObject *tp;
+
+    if (!PyArg_ParseTuple(args, "O:with_tp_del", &obj))
+        return NULL;
+    tp = (PyTypeObject *) obj;
+    if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
+        PyErr_Format(PyExc_TypeError,
+                     "heap type expected, got %R", obj);
+        return NULL;
+    }
+    tp->tp_del = slot_tp_del;
+    return Py_NewRef(obj);
+}
+
+
+struct gc_visit_state_basic {
+    PyObject *target;
+    int found;
+};
+
+static int
+gc_visit_callback_basic(PyObject *obj, void *arg)
+{
+    struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg;
+    if (obj == state->target) {
+        state->found = 1;
+        return 0;
+    }
+    return 1;
+}
+
+static PyObject *
+test_gc_visit_objects_basic(PyObject *Py_UNUSED(self),
+                            PyObject *Py_UNUSED(ignored))
+{
+    PyObject *obj;
+    struct gc_visit_state_basic state;
+
+    obj = PyList_New(0);
+    if (obj == NULL) {
+        return NULL;
+    }
+    state.target = obj;
+    state.found = 0;
+
+    PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state);
+    Py_DECREF(obj);
+    if (!state.found) {
+        PyErr_SetString(
+             PyExc_AssertionError,
+             "test_gc_visit_objects_basic: Didn't find live list");
+         return NULL;
+    }
+    Py_RETURN_NONE;
+}
+
+static int
+gc_visit_callback_exit_early(PyObject *obj, void *arg)
+ {
+    int *visited_i = (int *)arg;
+    (*visited_i)++;
+    if (*visited_i == 2) {
+        return 0;
+    }
+    return 1;
+}
+
+static PyObject *
+test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self),
+                                 PyObject *Py_UNUSED(ignored))
+{
+    int visited_i = 0;
+    PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i);
+    if (visited_i != 2) {
+        PyErr_SetString(
+            PyExc_AssertionError,
+            "test_gc_visit_objects_exit_early: did not exit when expected");
+    }
+    Py_RETURN_NONE;
+}
+
+typedef struct {
+    PyObject_HEAD
+} ObjExtraData;
+
+static PyObject *
+obj_extra_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    size_t extra_size = sizeof(PyObject *);
+    PyObject *obj = PyUnstable_Object_GC_NewWithExtraData(type, extra_size);
+    if (obj == NULL) {
+        return PyErr_NoMemory();
+    }
+    PyObject_GC_Track(obj);
+    return obj;
+}
+
+static PyObject **
+obj_extra_data_get_extra_storage(PyObject *self)
+{
+    return (PyObject **)((char *)self + Py_TYPE(self)->tp_basicsize);
+}
+
+static PyObject *
+obj_extra_data_get(PyObject *self, void *Py_UNUSED(ignored))
+{
+    PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
+    PyObject *value = *extra_storage;
+    if (!value) {
+        Py_RETURN_NONE;
+    }
+    return Py_NewRef(value);
+}
+
+static int
+obj_extra_data_set(PyObject *self, PyObject *newval, void *Py_UNUSED(ignored))
+{
+    PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
+    Py_CLEAR(*extra_storage);
+    if (newval) {
+        *extra_storage = Py_NewRef(newval);
+    }
+    return 0;
+}
+
+static PyGetSetDef obj_extra_data_getset[] = {
+    {"extra", (getter)obj_extra_data_get, (setter)obj_extra_data_set, NULL},
+    {NULL}
+};
+
+static int
+obj_extra_data_traverse(PyObject *self, visitproc visit, void *arg)
+{
+    PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
+    PyObject *value = *extra_storage;
+    Py_VISIT(value);
+    return 0;
+}
+
+static int
+obj_extra_data_clear(PyObject *self)
+{
+    PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
+    Py_CLEAR(*extra_storage);
+    return 0;
+}
+
+static void
+obj_extra_data_dealloc(PyObject *self)
+{
+    PyTypeObject *tp = Py_TYPE(self);
+    PyObject_GC_UnTrack(self);
+    obj_extra_data_clear(self);
+    tp->tp_free(self);
+    Py_DECREF(tp);
+}
+
+static PyType_Slot ObjExtraData_Slots[] = {
+    {Py_tp_getset, obj_extra_data_getset},
+    {Py_tp_dealloc, obj_extra_data_dealloc},
+    {Py_tp_traverse, obj_extra_data_traverse},
+    {Py_tp_clear, obj_extra_data_clear},
+    {Py_tp_new, obj_extra_data_new},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec ObjExtraData_TypeSpec = {
+    .name = "_testcapi.ObjExtraData",
+    .basicsize = sizeof(ObjExtraData),
+    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
+    .slots = ObjExtraData_Slots,
+};
+
+static PyMethodDef test_methods[] = {
+    {"test_gc_control", test_gc_control, METH_NOARGS},
+    {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL},
+    {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL},
+    {"without_gc", without_gc, METH_O, NULL},
+    {"with_tp_del", with_tp_del, METH_VARARGS, NULL},
+    {NULL}
+};
+
+int _PyTestCapi_Init_GC(PyObject *mod)
+{
+    if (PyModule_AddFunctions(mod, test_methods) < 0) {
+        return -1;
+    }
+    if (PyModule_AddFunctions(mod, test_methods) < 0) {
+        return -1;
+    }
+
+    PyObject *ObjExtraData_Type = PyType_FromModuleAndSpec(
+        mod, &ObjExtraData_TypeSpec, NULL);
+    if (ObjExtraData_Type == 0) {
+        return -1;
+    }
+    int ret = PyModule_AddType(mod, (PyTypeObject*)ObjExtraData_Type);
+    Py_DECREF(ObjExtraData_Type);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
index 663d4f2255de881c9fa2d623ea319048d447cba1..d1991ac6b464f20f629feadbf83b6f4288ef3ab4 100644 (file)
@@ -41,6 +41,7 @@ int _PyTestCapi_Init_Code(PyObject *module);
 int _PyTestCapi_Init_Buffer(PyObject *module);
 int _PyTestCapi_Init_PyOS(PyObject *module);
 int _PyTestCapi_Init_Immortal(PyObject *module);
+int _PyTestCapi_Init_GC(PyObject *mod);
 
 #ifdef LIMITED_API_AVAILABLE
 int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
index 79ab7d3f5555c28b67afe8849ee57dbc9da60020..c29d29c4791134b831c435416799d4194a206a61 100644 (file)
@@ -154,68 +154,6 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored))
 #endif
 }
 
-static PyObject*
-test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
-    int orig_enabled = PyGC_IsEnabled();
-    const char* msg = "ok";
-    int old_state;
-
-    old_state = PyGC_Enable();
-    msg = "Enable(1)";
-    if (old_state != orig_enabled) {
-        goto failed;
-    }
-    msg = "IsEnabled(1)";
-    if (!PyGC_IsEnabled()) {
-        goto failed;
-    }
-
-    old_state = PyGC_Disable();
-    msg = "disable(2)";
-    if (!old_state) {
-        goto failed;
-    }
-    msg = "IsEnabled(2)";
-    if (PyGC_IsEnabled()) {
-        goto failed;
-    }
-
-    old_state = PyGC_Enable();
-    msg = "enable(3)";
-    if (old_state) {
-        goto failed;
-    }
-    msg = "IsEnabled(3)";
-    if (!PyGC_IsEnabled()) {
-        goto failed;
-    }
-
-    if (!orig_enabled) {
-        old_state = PyGC_Disable();
-        msg = "disable(4)";
-        if (old_state) {
-            goto failed;
-        }
-        msg = "IsEnabled(4)";
-        if (PyGC_IsEnabled()) {
-            goto failed;
-        }
-    }
-
-    Py_RETURN_NONE;
-
-failed:
-    /* Try to clean up if we can. */
-    if (orig_enabled) {
-        PyGC_Enable();
-    } else {
-        PyGC_Disable();
-    }
-    PyErr_Format(TestError, "GC control failed in %s", msg);
-    return NULL;
-}
-
 static PyObject*
 test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
@@ -1627,95 +1565,6 @@ restore_crossinterp_data(PyObject *self, PyObject *args)
     return _PyCrossInterpreterData_NewObject(data);
 }
 
-static void
-slot_tp_del(PyObject *self)
-{
-    PyObject *del, *res;
-
-    /* Temporarily resurrect the object. */
-    assert(Py_REFCNT(self) == 0);
-    Py_SET_REFCNT(self, 1);
-
-    /* Save the current exception, if any. */
-    PyObject *exc = PyErr_GetRaisedException();
-
-    PyObject *tp_del = PyUnicode_InternFromString("__tp_del__");
-    if (tp_del == NULL) {
-        PyErr_WriteUnraisable(NULL);
-        PyErr_SetRaisedException(exc);
-        return;
-    }
-    /* Execute __del__ method, if any. */
-    del = _PyType_Lookup(Py_TYPE(self), tp_del);
-    Py_DECREF(tp_del);
-    if (del != NULL) {
-        res = PyObject_CallOneArg(del, self);
-        if (res == NULL)
-            PyErr_WriteUnraisable(del);
-        else
-            Py_DECREF(res);
-    }
-
-    /* Restore the saved exception. */
-    PyErr_SetRaisedException(exc);
-
-    /* Undo the temporary resurrection; can't use DECREF here, it would
-     * cause a recursive call.
-     */
-    assert(Py_REFCNT(self) > 0);
-    Py_SET_REFCNT(self, Py_REFCNT(self) - 1);
-    if (Py_REFCNT(self) == 0) {
-        /* this is the normal path out */
-        return;
-    }
-
-    /* __del__ resurrected it!  Make it look like the original Py_DECREF
-     * never happened.
-     */
-    {
-        Py_ssize_t refcnt = Py_REFCNT(self);
-        _Py_NewReferenceNoTotal(self);
-        Py_SET_REFCNT(self, refcnt);
-    }
-    assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self));
-}
-
-static PyObject *
-with_tp_del(PyObject *self, PyObject *args)
-{
-    PyObject *obj;
-    PyTypeObject *tp;
-
-    if (!PyArg_ParseTuple(args, "O:with_tp_del", &obj))
-        return NULL;
-    tp = (PyTypeObject *) obj;
-    if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
-        PyErr_Format(PyExc_TypeError,
-                     "heap type expected, got %R", obj);
-        return NULL;
-    }
-    tp->tp_del = slot_tp_del;
-    return Py_NewRef(obj);
-}
-
-static PyObject *
-without_gc(PyObject *Py_UNUSED(self), PyObject *obj)
-{
-    PyTypeObject *tp = (PyTypeObject*)obj;
-    if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
-        return PyErr_Format(PyExc_TypeError, "heap type expected, got %R", obj);
-    }
-    if (PyType_IS_GC(tp)) {
-        // Don't try this at home, kids:
-        tp->tp_flags -= Py_TPFLAGS_HAVE_GC;
-        tp->tp_free = PyObject_Del;
-        tp->tp_traverse = NULL;
-        tp->tp_clear = NULL;
-    }
-    assert(!PyType_IS_GC(tp));
-    return Py_NewRef(obj);
-}
-
 static PyMethodDef ml;
 
 static PyObject *
@@ -3342,165 +3191,6 @@ function_set_kw_defaults(PyObject *self, PyObject *args)
     Py_RETURN_NONE;
 }
 
-struct gc_visit_state_basic {
-    PyObject *target;
-    int found;
-};
-
-static int
-gc_visit_callback_basic(PyObject *obj, void *arg)
-{
-    struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg;
-    if (obj == state->target) {
-        state->found = 1;
-        return 0;
-    }
-    return 1;
-}
-
-static PyObject *
-test_gc_visit_objects_basic(PyObject *Py_UNUSED(self),
-                            PyObject *Py_UNUSED(ignored))
-{
-    PyObject *obj;
-    struct gc_visit_state_basic state;
-
-    obj = PyList_New(0);
-    if (obj == NULL) {
-        return NULL;
-    }
-    state.target = obj;
-    state.found = 0;
-
-    PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state);
-    Py_DECREF(obj);
-    if (!state.found) {
-        PyErr_SetString(
-             PyExc_AssertionError,
-             "test_gc_visit_objects_basic: Didn't find live list");
-         return NULL;
-    }
-    Py_RETURN_NONE;
-}
-
-static int
-gc_visit_callback_exit_early(PyObject *obj, void *arg)
- {
-    int *visited_i = (int *)arg;
-    (*visited_i)++;
-    if (*visited_i == 2) {
-        return 0;
-    }
-    return 1;
-}
-
-static PyObject *
-test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self),
-                                 PyObject *Py_UNUSED(ignored))
-{
-    int visited_i = 0;
-    PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i);
-    if (visited_i != 2) {
-        PyErr_SetString(
-            PyExc_AssertionError,
-            "test_gc_visit_objects_exit_early: did not exit when expected");
-    }
-    Py_RETURN_NONE;
-}
-
-typedef struct {
-    PyObject_HEAD
-} ObjExtraData;
-
-static PyObject *
-obj_extra_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    size_t extra_size = sizeof(PyObject *);
-    PyObject *obj = PyUnstable_Object_GC_NewWithExtraData(type, extra_size);
-    if (obj == NULL) {
-        return PyErr_NoMemory();
-    }
-    PyObject_GC_Track(obj);
-    return obj;
-}
-
-static PyObject **
-obj_extra_data_get_extra_storage(PyObject *self)
-{
-    return (PyObject **)((char *)self + Py_TYPE(self)->tp_basicsize);
-}
-
-static PyObject *
-obj_extra_data_get(PyObject *self, void *Py_UNUSED(ignored))
-{
-    PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
-    PyObject *value = *extra_storage;
-    if (!value) {
-        Py_RETURN_NONE;
-    }
-    return Py_NewRef(value);
-}
-
-static int
-obj_extra_data_set(PyObject *self, PyObject *newval, void *Py_UNUSED(ignored))
-{
-    PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
-    Py_CLEAR(*extra_storage);
-    if (newval) {
-        *extra_storage = Py_NewRef(newval);
-    }
-    return 0;
-}
-
-static PyGetSetDef obj_extra_data_getset[] = {
-    {"extra", (getter)obj_extra_data_get, (setter)obj_extra_data_set, NULL},
-    {NULL}
-};
-
-static int
-obj_extra_data_traverse(PyObject *self, visitproc visit, void *arg)
-{
-    PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
-    PyObject *value = *extra_storage;
-    Py_VISIT(value);
-    return 0;
-}
-
-static int
-obj_extra_data_clear(PyObject *self)
-{
-    PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
-    Py_CLEAR(*extra_storage);
-    return 0;
-}
-
-static void
-obj_extra_data_dealloc(PyObject *self)
-{
-    PyTypeObject *tp = Py_TYPE(self);
-    PyObject_GC_UnTrack(self);
-    obj_extra_data_clear(self);
-    tp->tp_free(self);
-    Py_DECREF(tp);
-}
-
-static PyType_Slot ObjExtraData_Slots[] = {
-    {Py_tp_getset, obj_extra_data_getset},
-    {Py_tp_dealloc, obj_extra_data_dealloc},
-    {Py_tp_traverse, obj_extra_data_traverse},
-    {Py_tp_clear, obj_extra_data_clear},
-    {Py_tp_new, obj_extra_data_new},
-    {Py_tp_free, PyObject_GC_Del},
-    {0, NULL},
-};
-
-static PyType_Spec ObjExtraData_TypeSpec = {
-    .name = "_testcapi.ObjExtraData",
-    .basicsize = sizeof(ObjExtraData),
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
-    .slots = ObjExtraData_Slots,
-};
-
 struct atexit_data {
     int called;
 };
@@ -3538,7 +3228,6 @@ static PyMethodDef TestMethods[] = {
     {"set_errno",               set_errno,                       METH_VARARGS},
     {"test_config",             test_config,                     METH_NOARGS},
     {"test_sizeof_c_types",     test_sizeof_c_types,             METH_NOARGS},
-    {"test_gc_control",         test_gc_control,                 METH_NOARGS},
     {"test_list_api",           test_list_api,                   METH_NOARGS},
     {"test_dict_iteration",     test_dict_iteration,             METH_NOARGS},
     {"dict_getitem_knownhash",  dict_getitem_knownhash,          METH_VARARGS},
@@ -3590,7 +3279,6 @@ static PyMethodDef TestMethods[] = {
      METH_VARARGS | METH_KEYWORDS},
     {"get_crossinterp_data",    get_crossinterp_data,            METH_VARARGS},
     {"restore_crossinterp_data", restore_crossinterp_data,       METH_VARARGS},
-    {"with_tp_del",             with_tp_del,                     METH_VARARGS},
     {"create_cfunction",        create_cfunction,                METH_NOARGS},
     {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_VARARGS,
      PyDoc_STR("set_error_class(error_class) -> None")},
@@ -3641,7 +3329,6 @@ static PyMethodDef TestMethods[] = {
     {"meth_fastcall", _PyCFunction_CAST(meth_fastcall), METH_FASTCALL},
     {"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS},
     {"pynumber_tobase", pynumber_tobase, METH_VARARGS},
-    {"without_gc", without_gc, METH_O},
     {"test_set_type_size", test_set_type_size, METH_NOARGS},
     {"test_py_clear", test_py_clear, METH_NOARGS},
     {"test_py_setref", test_py_setref, METH_NOARGS},
@@ -3675,8 +3362,6 @@ static PyMethodDef TestMethods[] = {
     {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL},
     {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
     {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
-    {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL},
-    {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL},
     {"test_atexit", test_atexit, METH_NOARGS},
     {NULL, NULL} /* sentinel */
 };
@@ -4223,17 +3908,6 @@ PyInit__testcapi(void)
     Py_INCREF(&MethStatic_Type);
     PyModule_AddObject(m, "MethStatic", (PyObject *)&MethStatic_Type);
 
-    PyObject *ObjExtraData_Type = PyType_FromModuleAndSpec(
-        m, &ObjExtraData_TypeSpec, NULL);
-    if (ObjExtraData_Type == 0) {
-        return NULL;
-    }
-    int ret = PyModule_AddType(m, (PyTypeObject*)ObjExtraData_Type);
-    Py_DECREF(ObjExtraData_Type);
-    if (ret < 0) {
-        return NULL;
-    }
-
     PyModule_AddObject(m, "CHAR_MAX", PyLong_FromLong(CHAR_MAX));
     PyModule_AddObject(m, "CHAR_MIN", PyLong_FromLong(CHAR_MIN));
     PyModule_AddObject(m, "UCHAR_MAX", PyLong_FromLong(UCHAR_MAX));
@@ -4327,6 +4001,9 @@ PyInit__testcapi(void)
     if (_PyTestCapi_Init_Immortal(m) < 0) {
         return NULL;
     }
+    if (_PyTestCapi_Init_GC(m) < 0) {
+        return NULL;
+    }
 
 #ifndef LIMITED_API_AVAILABLE
     PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False);
index 350f97f8ff41aa9863017c4fa1e5ad71f9066b36..3db9426d1a25ff37594ce47c55d8341374c0e7aa 100644 (file)
     <ClCompile Include="..\Modules\_testcapi\buffer.c" />
     <ClCompile Include="..\Modules\_testcapi\pyos.c" />
     <ClCompile Include="..\Modules\_testcapi\immortal.c" />
+    <ClCompile Include="..\Modules\_testcapi\gc.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\PC\python_nt.rc" />
index af80f1eebb3c4d63034513c3868d822db2bfb727..8df4874659fa1cad11281e122f970f10bf6f6c43 100644 (file)
@@ -66,6 +66,9 @@
     <ClCompile Include="..\Modules\_testcapi\pyos.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\Modules\_testcapi\gc.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\PC\python_nt.rc">