I can image a few ways to go from here:
- leave as is, fix this when it really bothers us (risk:
exchange a known
problem for unknown hard-to-debug and/or hard-to-reproduce
problems)
- instrument if_marked functions like the one for
value_expr_for_decl to
assert if the from field is live and the to field is not live,
and fix
the
asserts
- extend garbage colllector to handle the problematic case
(problem: more
runtime and/or memory usage for garbage collection)
Any suggestions on which way to go?
Or make sure to walk all if_marked roots last (isn't the problem an
ordering one only?)
That is already done. The problem is not what happens after that
walk, but
during that walk. The code at that point assumes that the set of
marked
non-hashtable-entry objects is already stable, while the problematic
if_marked functions have the effect that that set is enlarged
during that
walk.
Hm, indeed - I know that this happens and it is not easy to avoid.
If we want to fix that in the garbage collector, we could walk the
problematic if_marked roots iteratively (without deleting unmarked
entries),
until fixed point is reached. After that we would walk (and delete
unmarked
entries) for both problematic and normal if_marked roots. However,
I don't
have good idea how we can iterate to fixed-point efficiently.
Me neither. I suppose it would be nice to avoid the situation by
dropping if_marked from problematic hashes. Can we at least
somehow figure out which one are those? (for example by
doing inefficient iteration with ENABLE_CHECKING and ICEing if
the 2nd iteration changes anything?)
I also considered that check, and implemented it, but later wondered
whether that method would only detect problems which surface given
the actual order of traversal of hash-tables and entries, and leave
other problems lurking.
So I created the following check: besides in_use_p and save_in_use_p,
I created two other per page_entry bitmaps: root_marked_p and
mark_locked_p. in_use_p is copied to root_marked_p after traversal of
the root tab.
During traversal of the if_marked roots, whenever an if_marked field
is tested and found unmarked, it is locked to unmarked by setting
mark_locked_p.
This allows us to detect:
- when an object that is locked to unmarked, is marked (an entry is
found dead and deleted, but later found live)
- when if_marked field is tested and found marked, but not root
marked (an entry is live only thanks to the specific order in which
we traverse over hash tables and hash table entries)
Tom