static void reset_finalizer_tree(GCTYPE *gc) /* After a GC, move gen0 finalizers to the old finalizer list. Note that the old gen0 splay tree is otherwise broken, since object addresses have moved. */ { Fnl *fnl, *next; fnl = gc->gen0_finalizers; gc->gen0_finalizers = NULL; gc->splayed_gen0_finalizers = NULL; for (; fnl; fnl = next) { next = fnl->next; /* Checking both `fnl` and `fnl->p` is redundant, since `fnl` is always allocated after `fnl->p`, but check both just in case the order of allocation somehow changes in the future. */ if (is_in_generation_half(gc, fnl) || is_in_generation_half(gc, fnl->f) || is_in_generation_half(gc, fnl->p) || is_in_generation_half(gc, fnl->data)) add_finalizer(fnl, 1, gc); else add_finalizer(fnl, 0, gc); } }
static int mark_ready_ephemerons(GCTYPE *gc, int inc_gen1) { GC_Ephemeron *waiting, *next, *eph; int did_one = 0, j; GC_mark_no_recur(gc, 1); for (j = 0; j < (inc_gen1 ? 1 : 2); j++) { if (inc_gen1) eph = gc->inc_ephemerons; else if (j == 0) eph = gc->ephemerons; else eph = gc->bp_ephemerons; waiting = NULL; for (; eph; eph = next) { if (inc_gen1) next = eph->inc_next; else next = eph->next; if (is_marked(gc, eph->key)) { if (!inc_gen1) eph->key = GC_resolve2(eph->key, gc); gcMARK2(eph->val, gc); gc->num_last_seen_ephemerons++; did_one = 1; if (!inc_gen1 && (j == 0) && !gc->gc_full && gc->started_incremental) { /* Need to preserve the ephemeron in the incremental list, unless it's kept in generation 1/2 nistead of promoted to generation 1. */ if (!is_in_generation_half(gc, eph)) { eph->inc_next = gc->inc_ephemerons; gc->inc_ephemerons = eph; } } } else { if (inc_gen1) { /* Ensure that we can write to the page containing the emphemeron: */ check_incremental_unprotect(gc, pagemap_find_page(gc->page_maps, eph)); eph->inc_next = waiting; } else eph->next = waiting; waiting = eph; } } if (inc_gen1) gc->inc_ephemerons = waiting; else if (j == 0) gc->ephemerons = waiting; else gc->bp_ephemerons = waiting; } GC_mark_no_recur(gc, 0); return did_one; }
static int zero_weak_arrays(GCTYPE *gc, int force_zero, int from_inc, int fuel) { GC_Weak_Array *wa; int i, num_gen0; if (from_inc) { wa = gc->inc_weak_arrays; num_gen0 = 0; } else wa = append_weak_arrays(gc->weak_arrays, gc->bp_weak_arrays, &num_gen0); if (gc->gc_full || !gc->started_incremental) num_gen0 = 0; while (wa) { void **data; data = wa->data; for (i = wa->count; i--; ) { void *p = data[i]; if (p && (force_zero || !is_marked(gc, p))) data[i] = wa->replace_val; else data[i] = GC_resolve2(p, gc); } if (fuel > 0) fuel = ((fuel > wa->count) ? (fuel - wa->count) : 0); if (num_gen0 > 0) { if (!is_in_generation_half(gc, wa)) { /* For incremental mode, preserve this weak box in the incremental list for re-checking later. */ wa->data[wa->count] = gc->inc_weak_arrays; gc->inc_weak_arrays = wa; } } if (from_inc) { GC_Weak_Array *next; next = (GC_Weak_Array *)wa->data[wa->count]; wa->data[wa->count] = gc->weak_incremental_done; wa = next; } else wa = wa->next; num_gen0--; } if (from_inc) gc->inc_weak_arrays = NULL; else { gc->weak_arrays = NULL; gc->bp_weak_arrays = NULL; } return fuel; }
static int zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero, int from_inc, int fuel) { GC_Weak_Box *wb; int num_gen0; if (from_inc) { wb = gc->inc_weak_boxes[is_late]; num_gen0 = 0; } else { wb = append_weak_boxes(gc->weak_boxes[is_late], gc->bp_weak_boxes[is_late], &num_gen0); if (gc->gc_full || !gc->started_incremental) num_gen0 = 0; } while (wb) { GC_ASSERT(is_marked(gc, wb)); if (!wb->val) { /* nothing to do */ } else if (force_zero || !is_marked(gc, wb->val)) { wb->val = NULL; if (wb->secondary_erase) { void **p; mpage *page; /* it's possible for the secondary to be in an old generation and therefore on an mprotected page: */ page = pagemap_find_page(gc->page_maps, wb->secondary_erase); if (page->mprotected) { page->mprotected = 0; mmu_write_unprotect_page(gc->mmu, page->addr, APAGE_SIZE, page_mmu_type(page), &page->mmu_src_block); page->reprotect_next = gc->reprotect_next; gc->reprotect_next = page; page->reprotect = 1; } p = (void **)GC_resolve2(wb->secondary_erase, gc); *(p + wb->soffset) = NULL; wb->secondary_erase = NULL; } } else { wb->val = GC_resolve2(wb->val, gc); } if (num_gen0 > 0) { if (!is_in_generation_half(gc, wb)) { /* For incremental mode, preserve this weak box in the incremental list for re-checking later. */ check_weak_box_not_already_in_inc_chain(wb, gc->inc_weak_boxes[wb->is_late]); wb->inc_next = gc->inc_weak_boxes[is_late]; gc->inc_weak_boxes[is_late] = wb; } } if (from_inc) { GC_Weak_Box *next; next = wb->inc_next; wb->inc_next = gc->weak_incremental_done; wb = next; } else wb = wb->next; num_gen0--; if (fuel >= 0) { if (fuel > 0) fuel--; else { GC_ASSERT(from_inc); gc->inc_weak_boxes[is_late] = wb; return 0; } } } /* reset, in case we have a second round */ if (from_inc) { gc->inc_weak_boxes[is_late] = NULL; } else { gc->weak_boxes[is_late] = NULL; gc->bp_weak_boxes[is_late] = NULL; } return fuel; }