in src/heap/hh_shared.c [1091:1170]
CAMLprim value hh_mark_slice(value work_val) {
CAMLparam1(work_val);
assert(info->gc_phase == Phase_mark);
// We are able to partially scan an object for pointers and resume scanning in
// a subsequent slice. This is useful in the event of large objects which
// would otherwise cause long pauses if we needed to scan them all at once.
//
// If we stop in the middle of an object, we will store the address of that
// object and the index of the field where we should resume. Otherwise, these
// values will be NULL_ADDR and 0 respectively.
static addr_t current_value = NULL_ADDR;
static uintnat current_index = 0;
intnat work = Long_val(work_val);
intnat hashtbl_slots = info->hashtbl_slots;
addr_t v;
hh_header_t hd;
hh_tag_t tag;
uintnat i, size, start, end;
// If the previous slice stopped in the middle of scanning an object, the
// first thing we do in this slice is resume scanning where we left off.
v = current_value;
start = current_index;
// Work through the mark stack, scanning all gray objects for pointers.
// Because roots are colored gray but not added to the mark stack, also walk
// the heap to find marked roots.
while (work > 0) {
if (v == NULL_ADDR && mark_stack_ptr > mark_stack) {
v = *--mark_stack_ptr;
}
if (v != NULL_ADDR) {
hd = Deref(v);
tag = Obj_tag(hd);
size = Obj_wosize_tag(hd, tag);
if (tag == Entity_tag) {
mark_entity(v);
v = NULL_ADDR;
start = 0;
} else if (should_scan(tag)) {
// Avoid scanning large objects all at once
end = start + work;
if (size < end) {
end = size;
}
for (i = start; i < end; i++) {
mark_slice_darken(Deref(Obj_field(v, i)));
}
if (end < size) {
// We did not finish scanning this object. We will resume scanning
// this object in the next slice.
start = end;
} else {
v = NULL_ADDR;
start = 0;
}
} else {
v = NULL_ADDR;
}
work--;
} else if (roots_ptr < hashtbl_slots) {
// Visit roots in shared hash table
mark_slice_darken(hashtbl[roots_ptr++].addr);
work--;
} else {
// Done marking, transition to sweep phase.
mark_stack_reset();
info->gc_phase = Phase_sweep;
break;
}
}
current_value = v;
current_index = start;
CAMLreturn(Val_long(work));
}