heapsections.c 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #include "private/gc_priv.h"
  2. void GC_foreach_heap_section(void* user_data, GC_heap_section_proc callback)
  3. {
  4. GC_ASSERT(I_HOLD_LOCK());
  5. if (callback == NULL)
  6. return;
  7. // GC memory is organized in heap sections, which are split in heap blocks.
  8. // Each block has header (can get via HDR(ptr)) and it's size is aligned to HBLKSIZE
  9. // Block headers are kept separately from memory their points to, and quickly address
  10. // headers GC maintains 2-level cache structure which uses address as a hash key.
  11. for (unsigned i = 0; i < GC_n_heap_sects; i++)
  12. {
  13. ptr_t sectionStart = GC_heap_sects[i].hs_start;
  14. ptr_t sectionEnd = sectionStart + GC_heap_sects[i].hs_bytes;
  15. // Merge in contiguous sections.
  16. // A heap block might start in one heap section and extend
  17. // into the next one.
  18. while (i + 1 < GC_n_heap_sects && GC_heap_sects[i + 1].hs_start == sectionEnd)
  19. {
  20. ++i;
  21. sectionEnd = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
  22. }
  23. ptr_t blockStart = sectionStart;
  24. while (blockStart < sectionEnd)
  25. {
  26. // This does lookup into 2 level tree data structure,
  27. // which uses address as hash key to find block header.
  28. hdr* hhdr = HDR(blockStart);
  29. if (IS_FORWARDING_ADDR_OR_NIL(hhdr))
  30. {
  31. // This pointer has no header registered in headers cache.
  32. // We skip one HBLKSIZE and attempt to get header for it.
  33. // We don't report it, as we don't know is mapped or not.
  34. blockStart = blockStart + HBLKSIZE;
  35. }
  36. else if (HBLK_IS_FREE(hhdr))
  37. {
  38. // We have a header, and the block is marked as free.
  39. // Note: for "free" blocks "hb_sz" = the size in bytes of the whole block.
  40. ptr_t blockEnd = blockStart + hhdr->hb_sz;
  41. #if USE_MUNMAP
  42. // Only report free block if it's mapped.
  43. if ((hhdr->hb_flags & WAS_UNMAPPED) != 0)
  44. {
  45. blockStart = blockEnd;
  46. continue;
  47. }
  48. #endif
  49. callback(user_data, blockStart, blockEnd);
  50. blockStart = blockEnd;
  51. }
  52. else
  53. {
  54. // This heap block is used, report it.
  55. // Note: for used blocks "hb_sz" = size in bytes, of objects in the block.
  56. ptr_t blockEnd = blockStart + HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
  57. ptr_t usedBlocknEnd = blockStart + hhdr->hb_sz;
  58. if (usedBlocknEnd > blockStart)
  59. callback(user_data, blockStart, usedBlocknEnd);
  60. if (blockEnd > usedBlocknEnd)
  61. callback(user_data, usedBlocknEnd, blockEnd);
  62. blockStart = blockEnd;
  63. }
  64. }
  65. }
  66. }
  67. void HeapSectionCountIncrementer(void* context, GC_PTR start, GC_PTR end)
  68. {
  69. GC_word* countPtr = (GC_word*)context;
  70. (*countPtr)++;
  71. }
  72. GC_word GC_get_heap_section_count()
  73. {
  74. GC_word count = 0;
  75. GC_foreach_heap_section(&count, HeapSectionCountIncrementer);
  76. return count;
  77. }