fix interaction of ephemerons and generations; use for weak hashtables

original commit: 6f7147e505aae5c2b9139eea6df8a9c25a35289d
This commit is contained in:
Matthew Flatt 2017-05-01 08:42:06 -06:00
parent 18cdcd977e
commit 0d5340c061
3 changed files with 48 additions and 4 deletions

46
c/gc.c
View File

@ -52,6 +52,7 @@ static void resweep_dirty_weak_pairs PROTO((void));
static void add_ephemeron_to_pending PROTO((ptr p));
static void add_trigger_ephemerons_to_repending PROTO((ptr p));
static void check_pending_ephemerons PROTO(());
static int check_dirty_ephemeron PROTO((ptr pe, int tg, int youngest));
static void clear_trigger_ephemerons PROTO(());
/* MAXPTR is used to pad the sorted_locked_object vector. The pad value must be greater than any heap address */
@ -1929,7 +1930,7 @@ static void sweep_dirty(void) {
} else if (s == space_ephemeron) {
while (pp < ppend && *pp != forward_marker) {
ptr p = TYPE((ptr)pp, type_pair);
add_ephemeron_to_pending(p);
youngest = check_dirty_ephemeron(p, tg, youngest);
pp += size_ephemeron / sizeof(ptr);
}
} else {
@ -2100,6 +2101,49 @@ static void check_pending_ephemerons() {
}
}
/* Like check_pending_ephemeron(), but for a dirty, old-generation
ephemeron (that was not yet added to the pending list), so we can
be less pessimistic than setting `youngest` to the target
generation: */
static int check_dirty_ephemeron(ptr pe, int tg, int youngest) {
ptr p;
seginfo *si;
p = Scar(pe);
if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL) {
if (si->space & space_old && !locked(p)) {
if (FWDMARKER(p) == forward_marker && TYPEBITS(p) != type_flonum) {
INITCAR(pe) = FWDADDRESS(p);
relocate(&INITCDR(pe))
youngest = tg;
} else {
/* Not reached, so far; install as trigger */
EPHEMERONTRIGGERNEXT(pe) = si->trigger_ephemerons;
si->trigger_ephemerons = pe;
EPHEMERONNEXT(pe) = trigger_ephemerons;
trigger_ephemerons = pe;
/* Make the consistent (but pessimistic w.r.t. to wrong-way
pointers) assumption that the key will stay live and move
to the target generation. That assumption covers the value
part, too, since it can't end up younger than the target
generation. */
youngest = tg;
}
} else {
int pg;
if ((pg = si->generation) < youngest)
youngest = pg;
relocate_dirty(&INITCDR(pe), tg, youngest)
}
} else {
/* Non-collectable key means that the value determines
`youngest`: */
relocate_dirty(&INITCDR(pe), tg, youngest)
}
return youngest;
}
static void clear_trigger_ephemerons() {
ptr pe;

View File

@ -1435,7 +1435,7 @@
[b (vector-ref vec idx)])
(lookup-keyval x b
values
(let ([keyval (if (eq-ht-weak? h) (weak-cons x v) (cons x v))])
(let ([keyval (if (eq-ht-weak? h) (ephemeron-cons x v) (cons x v))])
(vector-set! vec idx ($make-tlc h keyval b))
(incr-size! h vec)
keyval))))
@ -1451,7 +1451,7 @@
(begin
(vector-set! vec idx
($make-tlc h
(if (eq-ht-weak? h) (weak-cons x v) (cons x v))
(if (eq-ht-weak? h) (ephemeron-cons x v) (cons x v))
b))
(incr-size! h vec))))))

View File

@ -1019,7 +1019,7 @@ Documentation notes:
b
($make-tlc h2
(let* ([keyval ($tlc-keyval b)] [key (car keyval)] [val (cdr keyval)])
(if weak? (weak-cons key val) (cons key val)))
(if weak? (ephemeron-cons key val) (cons key val)))
(inner ($tlc-next b))))))
(outer (fx+ i 1)))))
h2))))