diff --git a/Include/objimpl.h b/Include/objimpl.h --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -231,12 +231,17 @@ /* C equivalent of gc.collect(). */ PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); +/* return flags value of the tp_is_gc slot function */ +#define PyGC_HAS_GC 1 /* instance has a GC head */ +#define PyGC_UNCOLLECTABLE 2 /* instance can't be collected now */ + /* Test if a type has a GC head */ #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) /* Test if an object has a GC head */ #define PyObject_IS_GC(o) (PyType_IS_GC(Py_TYPE(o)) && \ - (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o))) + (Py_TYPE(o)->tp_is_gc == NULL || \ + (Py_TYPE(o)->tp_is_gc(o) & PyGC_HAS_GC))) PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t); #define PyObject_GC_Resize(type, op, n) \ diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -457,14 +457,18 @@ } } -/* Return true if object has a finalization method. */ +/* Return true if object has a finalization method, or signals + * itself as not being collectable at this time + */ static int has_finalizer(PyObject *op) { - if (PyGen_CheckExact(op)) - return PyGen_NeedsFinalizing((PyGenObject *)op); - else - return op->ob_type->tp_del != NULL; + if (Py_TYPE(op)->tp_is_gc != NULL && \ + (Py_TYPE(op)->tp_is_gc(op) & PyGC_UNCOLLECTABLE)) + { + return 1; + } + return op->ob_type->tp_del != NULL; } /* Move the objects in unreachable with __del__ methods into `finalizers`. diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -469,6 +469,24 @@ return name; } +static int +gen_is_gc(PyGenObject *gen) +{ + int i, result = PyGC_HAS_GC; + PyFrameObject *f = gen->gi_frame; + + /* no frame or empty blockstack == no finalization */ + if (f == NULL || f->f_stacktop == NULL) + return result; + + /* Any block type besides a loop requires cleanup. */ + for (i = 0; i < f->f_iblock; i++) + if (f->f_blockstack[i].b_type != SETUP_LOOP) + return result | PyGC_UNCOLLECTABLE; + + /* No blocks except loops, it's safe to skip finalization. */ + return result; +} PyDoc_STRVAR(gen__name__doc__, "Return the name of the generator's associated code object."); @@ -535,7 +553,7 @@ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ - 0, /* tp_is_gc */ + (inquiry)gen_is_gc, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ @@ -564,17 +582,5 @@ int PyGen_NeedsFinalizing(PyGenObject *gen) { - int i; - PyFrameObject *f = gen->gi_frame; - - if (f == NULL || f->f_stacktop == NULL) - return 0; /* no frame or empty blockstack == no finalization */ - - /* Any block type besides a loop requires cleanup. */ - for (i = 0; i < f->f_iblock; i++) - if (f->f_blockstack[i].b_type != SETUP_LOOP) - return 1; - - /* No blocks except loops, it's safe to skip finalization. */ - return 0; + return (gen_is_gc(gen) & PyGC_UNCOLLECTABLE) ? 1 : 0; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2811,7 +2811,7 @@ static int type_is_gc(PyTypeObject *type) { - return type->tp_flags & Py_TPFLAGS_HEAPTYPE; + return (type->tp_flags & Py_TPFLAGS_HEAPTYPE) ? PyGC_HAS_GC : 0; } PyTypeObject PyType_Type = {