468663ddbb
Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
99 lines
2.5 KiB
C
99 lines
2.5 KiB
C
#include "private/gc_priv.h"
|
|
|
|
static struct hblk* GetNextFreeBlock(ptr_t ptr)
|
|
{
|
|
struct hblk* result = NULL;
|
|
unsigned i;
|
|
|
|
for (i = 0; i < N_HBLK_FLS + 1; i++)
|
|
{
|
|
struct hblk* freeBlock = GC_hblkfreelist[i];
|
|
|
|
for (freeBlock = GC_hblkfreelist[i]; freeBlock != NULL; freeBlock = HDR(freeBlock)->hb_next)
|
|
{
|
|
/* We're only interested in pointers after "ptr" argument */
|
|
if ((ptr_t)freeBlock < ptr)
|
|
continue;
|
|
|
|
/* If we haven't had a result before or our previous result is */
|
|
/* ahead of the current freeBlock, mark the current freeBlock as result */
|
|
if (result == NULL || result > freeBlock)
|
|
result = freeBlock;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void CallHeapSectionCallback(void* user_data, ptr_t start, ptr_t end, GC_heap_section_proc callback)
|
|
{
|
|
hdr *hhdr = HDR(start);
|
|
|
|
// Validate that the heap block is valid, then fire our callback.
|
|
if (IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr)) {
|
|
return;
|
|
}
|
|
|
|
callback(user_data, start, end);
|
|
}
|
|
|
|
void GC_foreach_heap_section(void* user_data, GC_heap_section_proc callback)
|
|
{
|
|
unsigned i;
|
|
struct hblk* nextFreeBlock = NULL;
|
|
|
|
GC_ASSERT(I_HOLD_LOCK());
|
|
|
|
if (callback == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < GC_n_heap_sects; i++)
|
|
{
|
|
ptr_t sectionStart = GC_heap_sects[i].hs_start;
|
|
ptr_t sectionEnd = sectionStart + GC_heap_sects[i].hs_bytes;
|
|
|
|
/* Merge in contiguous sections. Copied from GC_dump_regions
|
|
|
|
A free block might start in one heap section and extend
|
|
into the next one. Merging the section avoids crashes when
|
|
trying to copy the start of section that is a free block
|
|
continued from the previous section. */
|
|
while (i + 1 < GC_n_heap_sects && GC_heap_sects[i + 1].hs_start == sectionEnd)
|
|
{
|
|
++i;
|
|
sectionEnd = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
|
|
}
|
|
|
|
while (sectionStart < sectionEnd)
|
|
{
|
|
nextFreeBlock = GetNextFreeBlock(sectionStart);
|
|
|
|
if (nextFreeBlock == NULL || (ptr_t)nextFreeBlock > sectionEnd)
|
|
{
|
|
CallHeapSectionCallback(user_data, sectionStart, sectionEnd, callback);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
size_t sectionLength = (char*)nextFreeBlock - sectionStart;
|
|
if (sectionLength > 0)
|
|
CallHeapSectionCallback(user_data, sectionStart, sectionStart + sectionLength, callback);
|
|
sectionStart = (char*)nextFreeBlock + HDR(nextFreeBlock)->hb_sz;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void HeapSectionCountIncrementer(void* context, GC_PTR start, GC_PTR end)
|
|
{
|
|
GC_word* countPtr = (GC_word*)context;
|
|
(*countPtr)++;
|
|
}
|
|
|
|
GC_word GC_get_heap_section_count()
|
|
{
|
|
GC_word count = 0;
|
|
GC_foreach_heap_section(&count, HeapSectionCountIncrementer);
|
|
return count;
|
|
}
|