summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/gcmodule.c49
1 files changed, 20 insertions, 29 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 729e9d5..91df906 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -361,7 +361,15 @@ has_finalizer(PyObject *op)
return 0;
}
-/* Move all objects out of unreachable and into collectable or finalizers.
+/* Move all objects out of unreachable, into collectable or finalizers.
+ * It's possible that some objects will get collected (via refcount falling
+ * to 0), or resurrected, as a side effect of checking for __del__ methods.
+ * After, finalizers contains all the objects from unreachable that haven't
+ * been collected by magic, and that have a finalizer. gc_refs is
+ * GC_REACHABLE for all of those. collectable contains all the remaining
+ * objects from unreachable, and gc_refs remains GC_TENTATIVELY_UNREACHABLE
+ * for those (we're still not sure they're reclaimable after this! Some
+ * may yet by reachable *from* the objects in finalizers).
*/
static void
move_finalizers(PyGC_Head *unreachable, PyGC_Head *collectable,
@@ -372,36 +380,19 @@ move_finalizers(PyGC_Head *unreachable, PyGC_Head *collectable,
PyObject *op = FROM_GC(gc);
int finalizer;
- if (PyInstance_Check(op)) {
- /* The HasAttr() check may run enough Python
- code to deallocate the object or make it
- reachable again. INCREF the object before
- calling HasAttr() to guard against the client
- code deallocating the object.
- */
- Py_INCREF(op);
- finalizer = PyObject_HasAttr(op, delstr);
- if (op->ob_refcnt == 1) {
- /* The object will be deallocated.
- Nothing left to do.
- */
- Py_DECREF(op);
- continue;
- }
- Py_DECREF(op);
- }
- else
- finalizer = has_finalizer(op);
- if (finalizer) {
- gc_list_remove(gc);
- gc_list_append(gc, finalizers);
- gc->gc.gc_refs = GC_REACHABLE;
- }
- else {
+ assert(IS_TENTATIVELY_UNREACHABLE(op));
+
+ finalizer = has_finalizer(op);
+ if (unreachable->gc.gc_next == gc) {
gc_list_remove(gc);
- gc_list_append(gc, collectable);
- /* XXX change gc_refs? */
+ if (finalizer) {
+ gc_list_append(gc, finalizers);
+ gc->gc.gc_refs = GC_REACHABLE;
+ }
+ else
+ gc_list_append(gc, collectable);
}
+ /* else has_finalizer() deleted op via side effect */
}
}