assert(prev == GC_PREV(head));
}
+static void
+gc_list_validate_space(PyGC_Head *head, int space) {
+ PyGC_Head *gc = GC_NEXT(head);
+ while (gc != head) {
+ assert(gc_old_space(gc) == space);
+ gc = GC_NEXT(gc);
+ }
+}
+
#else
#define validate_list(x, y) do{}while(0)
#define validate_old(g) do{}while(0)
#define validate_consistent_old_space(l) do{}while(0)
+#define gc_list_validate_space(l, s) do{}while(0)
#endif
/*** end of list stuff ***/
/* Invoke the callbacks we decided to honor. It's safe to invoke them
* because they can't reference unreachable objects.
*/
+ int visited_space = get_gc_state()->visited_space;
while (! gc_list_is_empty(&wrcb_to_call)) {
PyObject *temp;
PyObject *callback;
Py_DECREF(op);
if (wrcb_to_call._gc_next == (uintptr_t)gc) {
/* object is still alive -- move it */
+ gc_set_old_space(gc, visited_space);
gc_list_move(gc, old);
}
else {
assert(gc_list_is_empty(not_visited));
#endif
gcstate->visited_space = flip_old_space(gcstate->visited_space);
+ /* Make sure all young objects have old space bit set correctly */
+ PyGC_Head *young = &gcstate->young.head;
+ PyGC_Head *gc = GC_NEXT(young);
+ while (gc != young) {
+ PyGC_Head *next = GC_NEXT(gc);
+ gc_set_old_space(gc, gcstate->visited_space);
+ gc = next;
+ }
gcstate->work_to_do = 0;
}
}
gc_list_merge(&gcstate->young.head, &increment);
gcstate->young.count = 0;
- if (gcstate->visited_space) {
- /* objects in visited space have bit set, so we set it here */
- gc_list_set_space(&increment, 1);
- }
+ gc_list_validate_space(&increment, gcstate->visited_space);
Py_ssize_t increment_size = 0;
while (increment_size < gcstate->work_to_do) {
if (gc_list_is_empty(not_visited)) {
gc_set_old_space(gc, gcstate->visited_space);
increment_size += expand_region_transitively_reachable(&increment, gc, gcstate);
}
+ gc_list_validate_space(&increment, gcstate->visited_space);
PyGC_Head survivors;
gc_list_init(&survivors);
gc_collect_region(tstate, &increment, &survivors, UNTRACK_TUPLES, stats);
+ gc_list_validate_space(&survivors, gcstate->visited_space);
gc_list_merge(&survivors, visited);
assert(gc_list_is_empty(&increment));
gcstate->work_to_do += gcstate->heap_size / SCAN_RATE_DIVISOR / scale_factor;
GCState *gcstate = &tstate->interp->gc;
validate_old(gcstate);
PyGC_Head *young = &gcstate->young.head;
- PyGC_Head *old0 = &gcstate->old[0].head;
- PyGC_Head *old1 = &gcstate->old[1].head;
- /* merge all generations into old0 */
- gc_list_merge(young, old0);
+ PyGC_Head *pending = &gcstate->old[gcstate->visited_space^1].head;
+ PyGC_Head *visited = &gcstate->old[gcstate->visited_space].head;
+ /* merge all generations into visited */
+ gc_list_validate_space(young, gcstate->visited_space);
+ gc_list_set_space(pending, gcstate->visited_space);
+ gc_list_merge(young, pending);
gcstate->young.count = 0;
- PyGC_Head *gc = GC_NEXT(old1);
- while (gc != old1) {
- PyGC_Head *next = GC_NEXT(gc);
- gc_set_old_space(gc, 0);
- gc = next;
- }
- gc_list_merge(old1, old0);
+ gc_list_merge(pending, visited);
- gc_collect_region(tstate, old0, old0,
+ gc_collect_region(tstate, visited, visited,
UNTRACK_TUPLES | UNTRACK_DICTS,
stats);
- gcstate->visited_space = 1;
gcstate->young.count = 0;
gcstate->old[0].count = 0;
gcstate->old[1].count = 0;
/* Clear weakrefs and invoke callbacks as necessary. */
stats->collected += handle_weakrefs(&unreachable, to);
+ gc_list_validate_space(to, gcstate->visited_space);
validate_list(to, collecting_clear_unreachable_clear);
validate_list(&unreachable, collecting_set_unreachable_clear);
* this if they insist on creating this type of structure.
*/
handle_legacy_finalizers(tstate, gcstate, &finalizers, to);
+ gc_list_validate_space(to, gcstate->visited_space);
validate_list(to, collecting_clear_unreachable_clear);
}
_PyGC_Freeze(PyInterpreterState *interp)
{
GCState *gcstate = &interp->gc;
+ /* The permanent_generation has its old space bit set to zero */
+ if (gcstate->visited_space) {
+ gc_list_set_space(&gcstate->young.head, 0);
+ }
gc_list_merge(&gcstate->young.head, &gcstate->permanent_generation.head);
gcstate->young.count = 0;
PyGC_Head*old0 = &gcstate->old[0].head;