Each sparse RSet has two tables: cur and next. At the beginning, both tables are the same (i.e., the two references _cur and _next point to the same table). When a sparse table needs to be expanded during a GC, the flag _expanded on the table is set, a new table is created (pointed to by _next) and the RSet is added to the expanded list. After the collection (in fact, at the beginning of the next collection), we iterate over the expanded list, we get rid of the _cur tables, and set _cur to point to _next (so the _next table basically replaces the _cur table). Unfortunately, at that time, the _expanded flag is not reset. So, if the sparse table is expanded again, it is not added to the expanded list (that operation is conditional on !_expanded, so that the table is not added twice during the same GC). As a result, some of the sparse tables are left in an inconsistent state, which causes some entries not to be scanned correctly during a GC (see 6659663 for more information).
There is an additional issue with the sparse RSets. When we iterate over a sparse RSet, we actually use the _next table, instead of the _cur one. This creates a race between the _next table being expanded and the iteration. The whole point of having two tables is to have a stable one (_cur) and one that might be modified (_next) so that we can look at the stable one safely during a GC. Iterating over _next is plain wrong. This fix, along with the fix related to the _expanded check, seem to have resolved all the "missing rem set" issues related to sparse tables.