1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- #include "private/gc_priv.h"
- void GC_foreach_heap_section(void* user_data, GC_heap_section_proc callback)
- {
- GC_ASSERT(I_HOLD_LOCK());
- if (callback == NULL)
- return;
- // GC memory is organized in heap sections, which are split in heap blocks.
- // Each block has header (can get via HDR(ptr)) and it's size is aligned to HBLKSIZE
- // Block headers are kept separately from memory their points to, and quickly address
- // headers GC maintains 2-level cache structure which uses address as a hash key.
- for (unsigned 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.
- // A heap block might start in one heap section and extend
- // into the next one.
- 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;
- }
- ptr_t blockStart = sectionStart;
- while (blockStart < sectionEnd)
- {
- // This does lookup into 2 level tree data structure,
- // which uses address as hash key to find block header.
- hdr* hhdr = HDR(blockStart);
- if (IS_FORWARDING_ADDR_OR_NIL(hhdr))
- {
- // This pointer has no header registered in headers cache.
- // We skip one HBLKSIZE and attempt to get header for it.
- // We don't report it, as we don't know is mapped or not.
- blockStart = blockStart + HBLKSIZE;
- }
- else if (HBLK_IS_FREE(hhdr))
- {
- // We have a header, and the block is marked as free.
- // Note: for "free" blocks "hb_sz" = the size in bytes of the whole block.
- ptr_t blockEnd = blockStart + hhdr->hb_sz;
- #if USE_MUNMAP
- // Only report free block if it's mapped.
- if ((hhdr->hb_flags & WAS_UNMAPPED) != 0)
- {
- blockStart = blockEnd;
- continue;
- }
- #endif
- callback(user_data, blockStart, blockEnd);
- blockStart = blockEnd;
- }
- else
- {
- // This heap block is used, report it.
- // Note: for used blocks "hb_sz" = size in bytes, of objects in the block.
- ptr_t blockEnd = blockStart + HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
- ptr_t usedBlocknEnd = blockStart + hhdr->hb_sz;
- if (usedBlocknEnd > blockStart)
- callback(user_data, blockStart, usedBlocknEnd);
- if (blockEnd > usedBlocknEnd)
- callback(user_data, usedBlocknEnd, blockEnd);
- blockStart = blockEnd;
- }
- }
- }
- }
- 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;
- }
|