checksums.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright (c) 1992-1994 by Xerox Corporation. All rights reserved.
  3. *
  4. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  5. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  6. *
  7. * Permission is hereby granted to use or copy this program
  8. * for any purpose, provided the above notices are retained on all copies.
  9. * Permission to modify the code and to distribute modified code is granted,
  10. * provided the above notices are retained, and a notice that the code was
  11. * modified is included with the above copyright notice.
  12. */
  13. #include "private/gc_priv.h"
  14. #ifdef CHECKSUMS
  15. /* This is debugging code intended to verify the results of dirty bit */
  16. /* computations. Works only in a single threaded environment. */
  17. #define NSUMS 10000
  18. #define OFFSET 0x10000
  19. typedef struct {
  20. GC_bool new_valid;
  21. word old_sum;
  22. word new_sum;
  23. struct hblk * block; /* Block to which this refers + OFFSET */
  24. /* to hide it from collector. */
  25. } page_entry;
  26. page_entry GC_sums[NSUMS];
  27. STATIC word GC_faulted[NSUMS] = { 0 };
  28. /* Record of pages on which we saw a write fault. */
  29. STATIC size_t GC_n_faulted = 0;
  30. #if defined(MPROTECT_VDB) && !defined(DARWIN)
  31. void GC_record_fault(struct hblk * h)
  32. {
  33. word page = (word)h & ~(GC_page_size - 1);
  34. GC_ASSERT(GC_page_size != 0);
  35. if (GC_n_faulted >= NSUMS) ABORT("write fault log overflowed");
  36. GC_faulted[GC_n_faulted++] = page;
  37. }
  38. #endif
  39. STATIC GC_bool GC_was_faulted(struct hblk *h)
  40. {
  41. size_t i;
  42. word page = (word)h & ~(GC_page_size - 1);
  43. for (i = 0; i < GC_n_faulted; ++i) {
  44. if (GC_faulted[i] == page) return TRUE;
  45. }
  46. return FALSE;
  47. }
  48. STATIC word GC_checksum(struct hblk *h)
  49. {
  50. word *p = (word *)h;
  51. word *lim = (word *)(h+1);
  52. word result = 0;
  53. while ((word)p < (word)lim) {
  54. result += *p++;
  55. }
  56. return(result | 0x80000000 /* doesn't look like pointer */);
  57. }
  58. int GC_n_dirty_errors = 0;
  59. int GC_n_faulted_dirty_errors = 0;
  60. unsigned long GC_n_clean = 0;
  61. unsigned long GC_n_dirty = 0;
  62. STATIC void GC_update_check_page(struct hblk *h, int index)
  63. {
  64. page_entry *pe = GC_sums + index;
  65. hdr * hhdr = HDR(h);
  66. struct hblk *b;
  67. if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed");
  68. pe -> old_sum = pe -> new_sum;
  69. pe -> new_sum = GC_checksum(h);
  70. # if !defined(MSWIN32) && !defined(MSWINCE)
  71. if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) {
  72. GC_err_printf("GC_page_was_ever_dirty(%p) is wrong\n", (void *)h);
  73. }
  74. # endif
  75. if (GC_page_was_dirty(h)) {
  76. GC_n_dirty++;
  77. } else {
  78. GC_n_clean++;
  79. }
  80. b = h;
  81. while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) {
  82. b -= (word)hhdr;
  83. hhdr = HDR(b);
  84. }
  85. if (pe -> new_valid
  86. && hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */
  87. && pe -> old_sum != pe -> new_sum) {
  88. if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) {
  89. GC_bool was_faulted = GC_was_faulted(h);
  90. /* Set breakpoint here */GC_n_dirty_errors++;
  91. if (was_faulted) GC_n_faulted_dirty_errors++;
  92. }
  93. }
  94. pe -> new_valid = TRUE;
  95. pe -> block = h + OFFSET;
  96. }
  97. word GC_bytes_in_used_blocks = 0;
  98. STATIC void GC_add_block(struct hblk *h, word dummy GC_ATTR_UNUSED)
  99. {
  100. hdr * hhdr = HDR(h);
  101. GC_bytes_in_used_blocks += (hhdr->hb_sz + HBLKSIZE-1) & ~(HBLKSIZE-1);
  102. }
  103. STATIC void GC_check_blocks(void)
  104. {
  105. word bytes_in_free_blocks = GC_large_free_bytes;
  106. GC_bytes_in_used_blocks = 0;
  107. GC_apply_to_all_blocks(GC_add_block, (word)0);
  108. GC_COND_LOG_PRINTF("GC_bytes_in_used_blocks = %lu,"
  109. " bytes_in_free_blocks = %lu, heapsize = %lu\n",
  110. (unsigned long)GC_bytes_in_used_blocks,
  111. (unsigned long)bytes_in_free_blocks,
  112. (unsigned long)GC_heapsize);
  113. if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) {
  114. GC_err_printf("LOST SOME BLOCKS!!\n");
  115. }
  116. }
  117. /* Should be called immediately after GC_read_dirty. */
  118. void GC_check_dirty(void)
  119. {
  120. int index;
  121. unsigned i;
  122. struct hblk *h;
  123. ptr_t start;
  124. GC_check_blocks();
  125. GC_n_dirty_errors = 0;
  126. GC_n_faulted_dirty_errors = 0;
  127. GC_n_clean = 0;
  128. GC_n_dirty = 0;
  129. index = 0;
  130. for (i = 0; i < GC_n_heap_sects; i++) {
  131. start = GC_heap_sects[i].hs_start;
  132. for (h = (struct hblk *)start;
  133. (word)h < (word)(start + GC_heap_sects[i].hs_bytes); h++) {
  134. GC_update_check_page(h, index);
  135. index++;
  136. if (index >= NSUMS) goto out;
  137. }
  138. }
  139. out:
  140. GC_COND_LOG_PRINTF("Checked %lu clean and %lu dirty pages\n",
  141. GC_n_clean, GC_n_dirty);
  142. if (GC_n_dirty_errors > 0) {
  143. GC_err_printf("Found %d dirty bit errors (%d were faulted)\n",
  144. GC_n_dirty_errors, GC_n_faulted_dirty_errors);
  145. }
  146. for (i = 0; i < GC_n_faulted; ++i) {
  147. GC_faulted[i] = 0; /* Don't expose block pointers to GC */
  148. }
  149. GC_n_faulted = 0;
  150. }
  151. #endif /* CHECKSUMS */