gc_pmark.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /*
  2. * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
  3. * Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved.
  4. *
  5. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  6. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  7. *
  8. * Permission is hereby granted to use or copy this program
  9. * for any purpose, provided the above notices are retained on all copies.
  10. * Permission to modify the code and to distribute modified code is granted,
  11. * provided the above notices are retained, and a notice that the code was
  12. * modified is included with the above copyright notice.
  13. *
  14. */
  15. /* Private declarations of GC marker data structures and macros */
  16. /*
  17. * Declarations of mark stack. Needed by marker and client supplied mark
  18. * routines. Transitively include gc_priv.h.
  19. */
  20. #ifndef GC_PMARK_H
  21. #define GC_PMARK_H
  22. #ifdef HAVE_CONFIG_H
  23. # include "config.h"
  24. #endif
  25. #ifndef GC_BUILD
  26. # define GC_BUILD
  27. #endif
  28. #if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST)
  29. # include "dbg_mlc.h"
  30. #endif
  31. #ifndef GC_MARK_H
  32. # include "../gc_mark.h"
  33. #endif
  34. #ifndef GC_PRIVATE_H
  35. # include "gc_priv.h"
  36. #endif
  37. /* The real declarations of the following is in gc_priv.h, so that */
  38. /* we can avoid scanning the following table. */
  39. /*
  40. mark_proc GC_mark_procs[MAX_MARK_PROCS];
  41. */
  42. #ifndef MARK_DESCR_OFFSET
  43. # define MARK_DESCR_OFFSET sizeof(word)
  44. #endif
  45. /*
  46. * Mark descriptor stuff that should remain private for now, mostly
  47. * because it's hard to export WORDSZ without including gcconfig.h.
  48. */
  49. #define BITMAP_BITS (WORDSZ - GC_DS_TAG_BITS)
  50. #define PROC(descr) \
  51. (GC_mark_procs[((descr) >> GC_DS_TAG_BITS) & (GC_MAX_MARK_PROCS-1)])
  52. #define ENV(descr) \
  53. ((descr) >> (GC_DS_TAG_BITS + GC_LOG_MAX_MARK_PROCS))
  54. #define MAX_ENV \
  55. (((word)1 << (WORDSZ - GC_DS_TAG_BITS - GC_LOG_MAX_MARK_PROCS)) - 1)
  56. GC_EXTERN unsigned GC_n_mark_procs;
  57. /* Number of mark stack entries to discard on overflow. */
  58. #define GC_MARK_STACK_DISCARDS (INITIAL_MARK_STACK_SIZE/8)
  59. GC_EXTERN size_t GC_mark_stack_size;
  60. #ifdef PARALLEL_MARK
  61. /*
  62. * Allow multiple threads to participate in the marking process.
  63. * This works roughly as follows:
  64. * The main mark stack never shrinks, but it can grow.
  65. *
  66. * The initiating threads holds the GC lock, and sets GC_help_wanted.
  67. *
  68. * Other threads:
  69. * 1) update helper_count (while holding mark_lock.)
  70. * 2) allocate a local mark stack
  71. * repeatedly:
  72. * 3) Steal a global mark stack entry by atomically replacing
  73. * its descriptor with 0.
  74. * 4) Copy it to the local stack.
  75. * 5) Mark on the local stack until it is empty, or
  76. * it may be profitable to copy it back.
  77. * 6) If necessary, copy local stack to global one,
  78. * holding mark lock.
  79. * 7) Stop when the global mark stack is empty.
  80. * 8) decrement helper_count (holding mark_lock).
  81. *
  82. * This is an experiment to see if we can do something along the lines
  83. * of the University of Tokyo SGC in a less intrusive, though probably
  84. * also less performant, way.
  85. */
  86. /* GC_mark_stack_top is protected by mark lock. */
  87. /*
  88. * GC_notify_all_marker() is used when GC_help_wanted is first set,
  89. * when the last helper becomes inactive,
  90. * when something is added to the global mark stack, and just after
  91. * GC_mark_no is incremented.
  92. * This could be split into multiple CVs (and probably should be to
  93. * scale to really large numbers of processors.)
  94. */
  95. #endif /* PARALLEL_MARK */
  96. GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
  97. /* Push the object obj with corresponding heap block header hhdr onto */
  98. /* the mark stack. */
  99. #define PUSH_OBJ(obj, hhdr, mark_stack_top, mark_stack_limit) \
  100. do { \
  101. register word _descr = (hhdr) -> hb_descr; \
  102. GC_ASSERT(!HBLK_IS_FREE(hhdr)); \
  103. if (_descr != 0) { \
  104. mark_stack_top++; \
  105. if ((word)mark_stack_top >= (word)(mark_stack_limit)) { \
  106. mark_stack_top = GC_signal_mark_stack_overflow(mark_stack_top); \
  107. } \
  108. mark_stack_top -> mse_start = (obj); \
  109. mark_stack_top -> mse_descr.w = _descr; \
  110. } \
  111. } while (0)
  112. /* Push the contents of current onto the mark stack if it is a valid */
  113. /* ptr to a currently unmarked object. Mark it. */
  114. /* If we assumed a standard-conforming compiler, we could probably */
  115. /* generate the exit_label transparently. */
  116. #define PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, \
  117. source, exit_label) \
  118. do { \
  119. hdr * my_hhdr; \
  120. HC_GET_HDR(current, my_hhdr, source, exit_label); \
  121. PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
  122. source, exit_label, my_hhdr, TRUE); \
  123. exit_label: ; \
  124. } while (0)
  125. /* Set mark bit, exit if it was already set. */
  126. #ifdef USE_MARK_BYTES
  127. /* There is a race here, and we may set */
  128. /* the bit twice in the concurrent case. This can result in the */
  129. /* object being pushed twice. But that's only a performance issue. */
  130. # define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
  131. do { \
  132. char * mark_byte_addr = (char *)hhdr -> hb_marks + (bit_no); \
  133. if (*mark_byte_addr) goto exit_label; \
  134. *mark_byte_addr = 1; \
  135. } while (0)
  136. #else
  137. # ifdef PARALLEL_MARK
  138. /* This is used only if we explicitly set USE_MARK_BITS. */
  139. /* The following may fail to exit even if the bit was already set. */
  140. /* For our uses, that's benign: */
  141. # define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
  142. do { \
  143. if (!(*(addr) & (bits))) { \
  144. AO_or((volatile AO_t *)(addr), (AO_t)(bits)); \
  145. } else { \
  146. goto exit_label; \
  147. } \
  148. } while (0)
  149. # else
  150. # define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
  151. do { \
  152. word old = *(addr); \
  153. word my_bits = (bits); \
  154. if (old & my_bits) goto exit_label; \
  155. *(addr) = (old | my_bits); \
  156. } while (0)
  157. # endif /* !PARALLEL_MARK */
  158. # define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
  159. do { \
  160. word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(bit_no); \
  161. OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(bit_no), \
  162. exit_label); \
  163. } while (0)
  164. #endif /* !USE_MARK_BYTES */
  165. #ifdef PARALLEL_MARK
  166. # define INCR_MARKS(hhdr) \
  167. AO_store(&hhdr->hb_n_marks, AO_load(&hhdr->hb_n_marks) + 1)
  168. #else
  169. # define INCR_MARKS(hhdr) (void)(++hhdr->hb_n_marks)
  170. #endif
  171. #ifdef ENABLE_TRACE
  172. # define TRACE(source, cmd) \
  173. if (GC_trace_addr != 0 && (ptr_t)(source) == GC_trace_addr) cmd
  174. # define TRACE_TARGET(target, cmd) \
  175. if (GC_trace_addr != 0 && (target) == *(ptr_t *)GC_trace_addr) cmd
  176. #else
  177. # define TRACE(source, cmd)
  178. # define TRACE_TARGET(source, cmd)
  179. #endif
  180. #if defined(I386) && defined(__GNUC__)
  181. # define LONG_MULT(hprod, lprod, x, y) \
  182. do { \
  183. __asm__ __volatile__("mull %2" : "=a"(lprod), "=d"(hprod) \
  184. : "g"(y), "0"(x)); \
  185. } while (0)
  186. #else
  187. # define LONG_MULT(hprod, lprod, x, y) \
  188. do { \
  189. unsigned long long prod = (unsigned long long)(x) \
  190. * (unsigned long long)(y); \
  191. GC_STATIC_ASSERT(sizeof(x) + sizeof(y) <= sizeof(prod)); \
  192. hprod = prod >> 32; \
  193. lprod = (unsigned32)prod; \
  194. } while (0)
  195. #endif /* !I386 */
  196. /* If the mark bit corresponding to current is not set, set it, and */
  197. /* push the contents of the object on the mark stack. Current points */
  198. /* to the beginning of the object. We rely on the fact that the */
  199. /* preceding header calculation will succeed for a pointer past the */
  200. /* first page of an object, only if it is in fact a valid pointer */
  201. /* to the object. Thus we can omit the otherwise necessary tests */
  202. /* here. Note in particular that the "displ" value is the displacement */
  203. /* from the beginning of the heap block, which may itself be in the */
  204. /* interior of a large object. */
  205. #ifdef MARK_BIT_PER_GRANULE
  206. # define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
  207. source, exit_label, hhdr, do_offset_check) \
  208. do { \
  209. size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
  210. /* displ is always within range. If current doesn't point to */ \
  211. /* first block, then we are in the all_interior_pointers case, and */ \
  212. /* it is safe to use any displacement value. */ \
  213. size_t gran_displ = BYTES_TO_GRANULES(displ); \
  214. size_t gran_offset = hhdr -> hb_map[gran_displ]; \
  215. size_t byte_offset = displ & (GRANULE_BYTES - 1); \
  216. ptr_t base = current; \
  217. /* The following always fails for large block references. */ \
  218. if (EXPECT((gran_offset | byte_offset) != 0, FALSE)) { \
  219. if (hhdr -> hb_large_block) { \
  220. /* gran_offset is bogus. */ \
  221. size_t obj_displ; \
  222. base = (ptr_t)(hhdr -> hb_block); \
  223. obj_displ = (ptr_t)(current) - base; \
  224. if (obj_displ != displ) { \
  225. GC_ASSERT(obj_displ < hhdr -> hb_sz); \
  226. /* Must be in all_interior_pointer case, not first block */ \
  227. /* already did validity check on cache miss. */ \
  228. } else { \
  229. if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
  230. GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
  231. goto exit_label; \
  232. } \
  233. } \
  234. gran_displ = 0; \
  235. GC_ASSERT(hhdr -> hb_sz > HBLKSIZE || \
  236. hhdr -> hb_block == HBLKPTR(current)); \
  237. GC_ASSERT((word)hhdr->hb_block <= (word)(current)); \
  238. } else { \
  239. size_t obj_displ = GRANULES_TO_BYTES(gran_offset) \
  240. + byte_offset; \
  241. if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
  242. GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
  243. goto exit_label; \
  244. } \
  245. gran_displ -= gran_offset; \
  246. base -= obj_displ; \
  247. } \
  248. } \
  249. GC_ASSERT(hhdr == GC_find_header(base)); \
  250. GC_ASSERT(gran_displ % BYTES_TO_GRANULES(hhdr -> hb_sz) == 0); \
  251. TRACE(source, GC_log_printf("GC #%u: passed validity tests\n", \
  252. (unsigned)GC_gc_no)); \
  253. SET_MARK_BIT_EXIT_IF_SET(hhdr, gran_displ, exit_label); \
  254. TRACE(source, GC_log_printf("GC #%u: previously unmarked\n", \
  255. (unsigned)GC_gc_no)); \
  256. TRACE_TARGET(base, \
  257. GC_log_printf("GC #%u: marking %p from %p instead\n", \
  258. (unsigned)GC_gc_no, base, source)); \
  259. INCR_MARKS(hhdr); \
  260. GC_STORE_BACK_PTR((ptr_t)source, base); \
  261. PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
  262. } while (0)
  263. #endif /* MARK_BIT_PER_GRANULE */
  264. #ifdef MARK_BIT_PER_OBJ
  265. # define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
  266. source, exit_label, hhdr, do_offset_check) \
  267. do { \
  268. size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
  269. unsigned32 low_prod, high_prod; \
  270. unsigned32 inv_sz = hhdr -> hb_inv_sz; \
  271. ptr_t base = current; \
  272. LONG_MULT(high_prod, low_prod, displ, inv_sz); \
  273. /* product is > and within sz_in_bytes of displ * sz_in_bytes * 2**32 */ \
  274. if (EXPECT(low_prod >> 16 != 0, FALSE)) { \
  275. /* FIXME: fails if offset is a multiple of HBLKSIZE which becomes 0 */ \
  276. if (inv_sz == LARGE_INV_SZ) { \
  277. size_t obj_displ; \
  278. base = (ptr_t)(hhdr -> hb_block); \
  279. obj_displ = (ptr_t)(current) - base; \
  280. if (obj_displ != displ) { \
  281. GC_ASSERT(obj_displ < hhdr -> hb_sz); \
  282. /* Must be in all_interior_pointer case, not first block */ \
  283. /* already did validity check on cache miss. */ \
  284. } else { \
  285. if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
  286. GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
  287. goto exit_label; \
  288. } \
  289. } \
  290. GC_ASSERT(hhdr -> hb_sz > HBLKSIZE || \
  291. hhdr -> hb_block == HBLKPTR(current)); \
  292. GC_ASSERT((word)hhdr->hb_block < (word)(current)); \
  293. } else { \
  294. /* Accurate enough if HBLKSIZE <= 2**15. */ \
  295. GC_STATIC_ASSERT(HBLKSIZE <= (1 << 15)); \
  296. size_t obj_displ = (((low_prod >> 16) + 1) * (hhdr->hb_sz)) >> 16; \
  297. if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
  298. GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
  299. goto exit_label; \
  300. } \
  301. base -= obj_displ; \
  302. } \
  303. } \
  304. /* May get here for pointer to start of block not at */ \
  305. /* beginning of object. If so, it's valid, and we're fine. */ \
  306. GC_ASSERT(high_prod <= HBLK_OBJS(hhdr -> hb_sz)); \
  307. TRACE(source, GC_log_printf("GC #%u: passed validity tests\n", \
  308. (unsigned)GC_gc_no)); \
  309. SET_MARK_BIT_EXIT_IF_SET(hhdr, high_prod, exit_label); \
  310. TRACE(source, GC_log_printf("GC #%u: previously unmarked\n", \
  311. (unsigned)GC_gc_no)); \
  312. TRACE_TARGET(base, \
  313. GC_log_printf("GC #%u: marking %p from %p instead\n", \
  314. (unsigned)GC_gc_no, base, source)); \
  315. INCR_MARKS(hhdr); \
  316. GC_STORE_BACK_PTR((ptr_t)source, base); \
  317. PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
  318. } while (0)
  319. #endif /* MARK_BIT_PER_OBJ */
  320. #if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
  321. # define PUSH_ONE_CHECKED_STACK(p, source) \
  322. GC_mark_and_push_stack((ptr_t)(p), (ptr_t)(source))
  323. #else
  324. # define PUSH_ONE_CHECKED_STACK(p, source) \
  325. GC_mark_and_push_stack((ptr_t)(p))
  326. #endif
  327. /*
  328. * Push a single value onto mark stack. Mark from the object pointed to by p.
  329. * Invoke FIXUP_POINTER(p) before any further processing.
  330. * P is considered valid even if it is an interior pointer.
  331. * Previously marked objects are not pushed. Hence we make progress even
  332. * if the mark stack overflows.
  333. */
  334. #if NEED_FIXUP_POINTER
  335. /* Try both the raw version and the fixed up one. */
  336. # define GC_PUSH_ONE_STACK(p, source) \
  337. do { \
  338. if ((word)(p) >= (word)GC_least_plausible_heap_addr \
  339. && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
  340. PUSH_ONE_CHECKED_STACK(p, source); \
  341. } \
  342. FIXUP_POINTER(p); \
  343. if ((word)(p) >= (word)GC_least_plausible_heap_addr \
  344. && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
  345. PUSH_ONE_CHECKED_STACK(p, source); \
  346. } \
  347. } while (0)
  348. #else /* !NEED_FIXUP_POINTER */
  349. # define GC_PUSH_ONE_STACK(p, source) \
  350. do { \
  351. if ((word)(p) >= (word)GC_least_plausible_heap_addr \
  352. && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
  353. PUSH_ONE_CHECKED_STACK(p, source); \
  354. } \
  355. } while (0)
  356. #endif
  357. /* As above, but interior pointer recognition as for normal heap pointers. */
  358. #define GC_PUSH_ONE_HEAP(p,source,mark_stack_top) \
  359. do { \
  360. FIXUP_POINTER(p); \
  361. if ((word)(p) >= (word)GC_least_plausible_heap_addr \
  362. && (word)(p) < (word)GC_greatest_plausible_heap_addr) \
  363. mark_stack_top = GC_mark_and_push((void *)(p), mark_stack_top, \
  364. GC_mark_stack_limit, (void * *)(source)); \
  365. } while (0)
  366. /* Mark starting at mark stack entry top (incl.) down to */
  367. /* mark stack entry bottom (incl.). Stop after performing */
  368. /* about one page worth of work. Return the new mark stack */
  369. /* top entry. */
  370. GC_INNER mse * GC_mark_from(mse * top, mse * bottom, mse *limit);
  371. #define MARK_FROM_MARK_STACK() \
  372. GC_mark_stack_top = GC_mark_from(GC_mark_stack_top, \
  373. GC_mark_stack, \
  374. GC_mark_stack + GC_mark_stack_size);
  375. #define GC_mark_stack_empty() ((word)GC_mark_stack_top < (word)GC_mark_stack)
  376. /*
  377. * Mark from one finalizable object using the specified
  378. * mark proc. May not mark the object pointed to by
  379. * real_ptr. That is the job of the caller, if appropriate.
  380. * Note that this is called with the mutator running, but
  381. * with us holding the allocation lock. This is safe only if the
  382. * mutator needs the allocation lock to reveal hidden pointers.
  383. * FIXME: Why do we need the GC_mark_state test below?
  384. */
  385. #define GC_MARK_FO(real_ptr, mark_proc) \
  386. do { \
  387. (*(mark_proc))(real_ptr); \
  388. while (!GC_mark_stack_empty()) MARK_FROM_MARK_STACK(); \
  389. if (GC_mark_state != MS_NONE) { \
  390. GC_set_mark_bit(real_ptr); \
  391. while (!GC_mark_some((ptr_t)0)) { /* empty */ } \
  392. } \
  393. } while (0)
  394. GC_EXTERN GC_bool GC_mark_stack_too_small;
  395. /* We need a larger mark stack. May be */
  396. /* set by client supplied mark routines.*/
  397. typedef int mark_state_t; /* Current state of marking, as follows:*/
  398. /* Used to remember where we are during */
  399. /* concurrent marking. */
  400. /* We say something is dirty if it was */
  401. /* written since the last time we */
  402. /* retrieved dirty bits. We say it's */
  403. /* grungy if it was marked dirty in the */
  404. /* last set of bits we retrieved. */
  405. /* Invariant I: all roots and marked */
  406. /* objects p are either dirty, or point */
  407. /* to objects q that are either marked */
  408. /* or a pointer to q appears in a range */
  409. /* on the mark stack. */
  410. #define MS_NONE 0 /* No marking in progress. I holds. */
  411. /* Mark stack is empty. */
  412. #define MS_PUSH_RESCUERS 1 /* Rescuing objects are currently */
  413. /* being pushed. I holds, except */
  414. /* that grungy roots may point to */
  415. /* unmarked objects, as may marked */
  416. /* grungy objects above scan_ptr. */
  417. #define MS_PUSH_UNCOLLECTABLE 2 /* I holds, except that marked */
  418. /* uncollectible objects above scan_ptr */
  419. /* may point to unmarked objects. */
  420. /* Roots may point to unmarked objects */
  421. #define MS_ROOTS_PUSHED 3 /* I holds, mark stack may be nonempty */
  422. #define MS_PARTIALLY_INVALID 4 /* I may not hold, e.g. because of M.S. */
  423. /* overflow. However marked heap */
  424. /* objects below scan_ptr point to */
  425. /* marked or stacked objects. */
  426. #define MS_INVALID 5 /* I may not hold. */
  427. GC_EXTERN mark_state_t GC_mark_state;
  428. #endif /* GC_PMARK_H */