1 /* -----------------------------------------------------------------------------
2 * $Id: Sanity.c,v 1.23 2000/12/04 12:31:21 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Sanity checking code for the heap and stack.
8 * Used when debugging: check that the stack looks reasonable.
10 * - All things that are supposed to be pointers look like pointers.
12 * - Objects in text space are marked as static closures, those
13 * in the heap are dynamic.
15 * ---------------------------------------------------------------------------*/
23 //* Thread Queue Sanity::
24 //* Blackhole Sanity::
27 //@node Includes, Macros
28 //@subsection Includes
32 #ifdef DEBUG /* whole file */
36 #include "BlockAlloc.h"
39 #include "StoragePriv.h" // for END_OF_STATIC_LIST
41 //@node Macros, Stack sanity, Includes
44 #define LOOKS_LIKE_PTR(r) ((LOOKS_LIKE_STATIC_CLOSURE(r) || \
45 ((HEAP_ALLOCED(r) && Bdescr((P_)r)->free != (void *)-1))) && \
46 ((StgWord)(*(StgPtr)r)!=0xaaaaaaaa))
48 //@node Stack sanity, Heap Sanity, Macros
49 //@subsection Stack sanity
51 /* -----------------------------------------------------------------------------
53 -------------------------------------------------------------------------- */
55 StgOffset checkStackClosure( StgClosure* c );
57 StgOffset checkStackObject( StgPtr sp );
59 void checkStackChunk( StgPtr sp, StgPtr stack_end );
61 static StgOffset checkSmallBitmap( StgPtr payload, StgWord32 bitmap );
63 static StgOffset checkLargeBitmap( StgPtr payload,
64 StgLargeBitmap* large_bitmap );
66 void checkClosureShallow( StgClosure* p );
68 //@cindex checkSmallBitmap
70 checkSmallBitmap( StgPtr payload, StgWord32 bitmap )
75 for(; bitmap != 0; ++i, bitmap >>= 1 ) {
76 if ((bitmap & 1) == 0) {
77 checkClosure(stgCast(StgClosure*,payload[i]));
83 //@cindex checkLargeBitmap
85 checkLargeBitmap( StgPtr payload, StgLargeBitmap* large_bitmap )
91 for (bmp=0; bmp<large_bitmap->size; bmp++) {
92 StgWord32 bitmap = large_bitmap->bitmap[bmp];
93 for(; bitmap != 0; ++i, bitmap >>= 1 ) {
94 if ((bitmap & 1) == 0) {
95 checkClosure(stgCast(StgClosure*,payload[i]));
102 //@cindex checkStackClosure
104 checkStackClosure( StgClosure* c )
106 const StgInfoTable* info = get_itbl(c);
108 /* All activation records have 'bitmap' style layout info. */
109 switch (info->type) {
110 case RET_DYN: /* Dynamic bitmap: the mask is stored on the stack */
112 StgRetDyn* r = (StgRetDyn *)c;
113 return sizeofW(StgRetDyn) +
114 checkSmallBitmap(r->payload,r->liveness);
116 case RET_BCO: /* small bitmap (<= 32 entries) */
119 return 1 + checkSmallBitmap((StgPtr)c + 1,info->layout.bitmap);
122 ASSERT(LOOKS_LIKE_PTR(((StgUpdateFrame*)c)->updatee));
125 /* check that the link field points to another stack frame */
126 ASSERT(get_itbl(((StgFrame*)c)->link)->type == UPDATE_FRAME ||
127 get_itbl(((StgFrame*)c)->link)->type == CATCH_FRAME ||
128 get_itbl(((StgFrame*)c)->link)->type == STOP_FRAME ||
129 get_itbl(((StgFrame*)c)->link)->type == SEQ_FRAME);
137 checkSmallBitmap((StgPtr)c + 1,info->layout.bitmap);
138 case RET_BIG: /* large bitmap (> 32 entries) */
140 return 1 + checkLargeBitmap((StgPtr)c + 1,info->layout.large_bitmap);
142 case FUN_STATIC: /* probably a slow-entry point return address: */
143 #if 0 && defined(GRAN)
149 /* if none of the above, maybe it's a closure which looks a
150 * little like an infotable
152 checkClosureShallow(*(StgClosure **)c);
154 /* barf("checkStackClosure: weird activation record found on stack (%p).",c); */
159 * check that it looks like a valid closure - without checking its payload
160 * used to avoid recursion between checking PAPs and checking stack
164 //@cindex checkClosureShallow
166 checkClosureShallow( StgClosure* p )
169 ASSERT(LOOKS_LIKE_GHC_INFO(p->header.info)
170 || IS_HUGS_CONSTR_INFO(GET_INFO(p)));
172 /* Is it a static closure (i.e. in the data segment)? */
173 if (LOOKS_LIKE_STATIC(p)) {
174 ASSERT(closure_STATIC(p));
176 ASSERT(!closure_STATIC(p));
177 ASSERT(LOOKS_LIKE_PTR(p));
181 /* check an individual stack object */
182 //@cindex checkStackObject
184 checkStackObject( StgPtr sp )
186 if (IS_ARG_TAG(*sp)) {
187 /* Tagged words might be "stubbed" pointers, so there's no
188 * point checking to see whether they look like pointers or
189 * not (some of them will).
191 return ARG_SIZE(*sp) + 1;
192 } else if (LOOKS_LIKE_GHC_INFO(*stgCast(StgPtr*,sp))) {
193 return checkStackClosure(stgCast(StgClosure*,sp));
194 } else { /* must be an untagged closure pointer in the stack */
195 checkClosureShallow(*stgCast(StgClosure**,sp));
200 /* check sections of stack between update frames */
201 //@cindex checkStackChunk
203 checkStackChunk( StgPtr sp, StgPtr stack_end )
208 while (p < stack_end) {
209 p += checkStackObject( p );
211 // ASSERT( p == stack_end ); -- HWL
214 //@cindex checkStackChunk
216 checkClosure( StgClosure* p )
218 const StgInfoTable *info;
221 ASSERT(LOOKS_LIKE_GHC_INFO(p->header.info));
224 /* Is it a static closure (i.e. in the data segment)? */
225 if (LOOKS_LIKE_STATIC(p)) {
226 ASSERT(closure_STATIC(p));
228 ASSERT(!closure_STATIC(p));
229 ASSERT(LOOKS_LIKE_PTR(p));
233 switch (info->type) {
236 StgBCO* bco = stgCast(StgBCO*,p);
238 for(i=0; i < bco->n_ptrs; ++i) {
239 ASSERT(LOOKS_LIKE_PTR(bcoConstPtr(bco,i)));
241 return bco_sizeW(bco);
246 StgMVar *mvar = (StgMVar *)p;
247 ASSERT(LOOKS_LIKE_PTR(mvar->head));
248 ASSERT(LOOKS_LIKE_PTR(mvar->tail));
249 ASSERT(LOOKS_LIKE_PTR(mvar->value));
252 checkBQ((StgBlockingQueueElement *)mvar->head, p);
254 checkBQ(mvar->head, p);
257 return sizeofW(StgMVar);
268 for (i = 0; i < info->layout.payload.ptrs; i++) {
269 ASSERT(LOOKS_LIKE_PTR(p->payload[i]));
271 return stg_max(sizeW_fromITBL(info), sizeofW(StgHeader) + MIN_UPD_SIZE);
275 checkBQ(((StgBlockingQueue *)p)->blocking_queue, p);
276 /* fall through to basic ptr check */
291 case IND_OLDGEN_PERM:
296 case SE_CAF_BLACKHOLE:
304 case CONSTR_CHARLIKE:
306 case CONSTR_NOCAF_STATIC:
311 for (i = 0; i < info->layout.payload.ptrs; i++) {
312 ASSERT(LOOKS_LIKE_PTR(p->payload[i]));
314 return sizeW_fromITBL(info);
317 case IND_STATIC: /* (1, 0) closure */
318 ASSERT(LOOKS_LIKE_PTR(((StgIndStatic*)p)->indirectee));
319 return sizeW_fromITBL(info);
322 /* deal with these specially - the info table isn't
323 * representative of the actual layout.
325 { StgWeak *w = (StgWeak *)p;
326 ASSERT(LOOKS_LIKE_PTR(w->key));
327 ASSERT(LOOKS_LIKE_PTR(w->value));
328 ASSERT(LOOKS_LIKE_PTR(w->finalizer));
330 ASSERT(LOOKS_LIKE_PTR(w->link));
332 return sizeW_fromITBL(info);
336 ASSERT(LOOKS_LIKE_PTR(stgCast(StgSelector*,p)->selectee));
337 return sizeofW(StgHeader) + MIN_UPD_SIZE;
341 /* we don't expect to see any of these after GC
342 * but they might appear during execution
345 StgInd *ind = stgCast(StgInd*,p);
346 ASSERT(LOOKS_LIKE_PTR(ind->indirectee));
347 q = (P_)p + sizeofW(StgInd);
348 while (!*q) { q++; }; /* skip padding words (see GC.c: evacuate())*/
362 barf("checkClosure: stack frame");
364 case AP_UPD: /* we can treat this as being the same as a PAP */
367 StgPAP *pap = stgCast(StgPAP*,p);
368 ASSERT(LOOKS_LIKE_PTR(pap->fun));
369 checkStackChunk((StgPtr)pap->payload,
370 (StgPtr)pap->payload + pap->n_args
372 return pap_sizeW(pap);
376 return arr_words_sizeW(stgCast(StgArrWords*,p));
379 case MUT_ARR_PTRS_FROZEN:
381 StgMutArrPtrs* a = stgCast(StgMutArrPtrs*,p);
383 for (i = 0; i < a->ptrs; i++) {
384 ASSERT(LOOKS_LIKE_PTR(a->payload[i]));
386 return mut_arr_ptrs_sizeW(a);
390 checkTSO((StgTSO *)p);
391 return tso_sizeW((StgTSO *)p);
396 ASSERT(LOOKS_LIKE_GA(&(((StgBlockedFetch *)p)->ga)));
397 ASSERT(LOOKS_LIKE_PTR((((StgBlockedFetch *)p)->node)));
398 return sizeofW(StgBlockedFetch); // see size used in evacuate()
401 ASSERT(LOOKS_LIKE_GA(((StgFetchMe *)p)->ga));
402 return sizeofW(StgFetchMe); // see size used in evacuate()
405 checkBQ(((StgFetchMeBlockingQueue *)p)->blocking_queue, (StgClosure *)p);
406 return sizeofW(StgFetchMeBlockingQueue); // see size used in evacuate()
409 /* In an RBH the BQ may be empty (ie END_BQ_QUEUE) but not NULL */
410 ASSERT(((StgRBH *)p)->blocking_queue!=NULL);
411 if (((StgRBH *)p)->blocking_queue!=END_BQ_QUEUE)
412 checkBQ(((StgRBH *)p)->blocking_queue, p);
413 ASSERT(LOOKS_LIKE_GHC_INFO(REVERT_INFOPTR(get_itbl((StgClosure *)p))));
414 return BLACKHOLE_sizeW(); // see size used in evacuate()
415 // sizeW_fromITBL(REVERT_INFOPTR(get_itbl((StgClosure *)p)));
420 barf("checkClosure: found EVACUATED closure %d",
423 barf("checkClosure (closure type %d)", info->type);
429 #define PVM_PE_MASK 0xfffc0000
430 #define MAX_PVM_PES MAX_PES
431 #define MAX_PVM_TIDS MAX_PES
432 #define MAX_SLOTS 100000
435 looks_like_tid(StgInt tid)
437 StgInt hi = (tid & PVM_PE_MASK) >> 18;
438 StgInt lo = (tid & ~PVM_PE_MASK);
439 rtsBool ok = (hi != 0) && (lo < MAX_PVM_TIDS) && (hi < MAX_PVM_TIDS);
444 looks_like_slot(StgInt slot)
446 /* if tid is known better use looks_like_ga!! */
447 rtsBool ok = slot<MAX_SLOTS;
448 // This refers only to the no. of slots on the current PE
449 // rtsBool ok = slot<=highest_slot();
454 looks_like_ga(globalAddr *ga)
456 rtsBool is_tid = looks_like_tid((ga)->payload.gc.gtid);
457 rtsBool is_slot = ((ga)->payload.gc.gtid==mytid) ?
458 (ga)->payload.gc.slot<=highest_slot() :
459 (ga)->payload.gc.slot<MAX_SLOTS;
460 rtsBool ok = is_tid && is_slot;
466 //@node Heap Sanity, TSO Sanity, Stack sanity
467 //@subsection Heap Sanity
469 /* -----------------------------------------------------------------------------
472 After garbage collection, the live heap is in a state where we can
473 run through and check that all the pointers point to the right
474 place. This function starts at a given position and sanity-checks
475 all the objects in the remainder of the chain.
476 -------------------------------------------------------------------------- */
480 checkHeap(bdescr *bd, StgPtr start)
483 nat xxx = 0; // tmp -- HWL
486 if (bd != NULL) p = bd->start;
492 while (p < bd->free) {
493 nat size = checkClosure(stgCast(StgClosure*,p));
494 /* This is the smallest size of closure that can live in the heap. */
495 ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
496 if (get_itbl(stgCast(StgClosure*,p))->type == IND_STATIC)
501 while (p < bd->free &&
502 (*p < 0x1000 || !LOOKS_LIKE_GHC_INFO((void*)*p))) { p++; }
509 fprintf(stderr,"@@@@ checkHeap: Heap ok; %d IND_STATIC closures checked\n",
514 Check heap between start and end. Used after unpacking graphs.
517 checkHeapChunk(StgPtr start, StgPtr end)
522 for (p=start; p<end; p+=size) {
523 ASSERT(LOOKS_LIKE_GHC_INFO((void*)*p));
524 size = checkClosure(stgCast(StgClosure*,p));
525 /* This is the smallest size of closure that can live in the heap. */
526 ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
532 checkChain(bdescr *bd)
535 checkClosure((StgClosure *)bd->start);
540 /* check stack - making sure that update frames are linked correctly */
543 checkStack(StgPtr sp, StgPtr stack_end, StgUpdateFrame* su )
545 /* check everything down to the first update frame */
546 checkStackChunk( sp, stgCast(StgPtr,su) );
547 while ( stgCast(StgPtr,su) < stack_end) {
548 sp = stgCast(StgPtr,su);
549 switch (get_itbl(su)->type) {
554 su = stgCast(StgSeqFrame*,su)->link;
557 su = stgCast(StgCatchFrame*,su)->link;
560 /* not quite: ASSERT(stgCast(StgPtr,su) == stack_end); */
563 barf("checkStack: weird record found on update frame list.");
565 checkStackChunk( sp, stgCast(StgPtr,su) );
567 ASSERT(stgCast(StgPtr,su) == stack_end);
570 //@node TSO Sanity, Thread Queue Sanity, Heap Sanity
571 //@subsection TSO Sanity
575 checkTSO(StgTSO *tso)
578 StgPtr stack = tso->stack;
579 StgUpdateFrame* su = tso->su;
580 StgOffset stack_size = tso->stack_size;
581 StgPtr stack_end = stack + stack_size;
583 if (tso->what_next == ThreadRelocated) {
588 if (tso->what_next == ThreadComplete || tso->what_next == ThreadKilled) {
589 /* The garbage collector doesn't bother following any pointers
590 * from dead threads, so don't check sanity here.
595 ASSERT(stack <= sp && sp < stack_end);
596 ASSERT(sp <= stgCast(StgPtr,su));
599 ASSERT(tso->par.magic==TSO_MAGIC);
601 switch (tso->why_blocked) {
603 checkClosureShallow(tso->block_info.closure);
604 ASSERT(/* Can't be a FETCH_ME because *this* closure is on its BQ */
605 get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ);
607 case BlockedOnGA_NoSend:
608 checkClosureShallow(tso->block_info.closure);
609 ASSERT(get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ);
611 case BlockedOnBlackHole:
612 checkClosureShallow(tso->block_info.closure);
613 ASSERT(/* Can't be a BLACKHOLE because *this* closure is on its BQ */
614 get_itbl(tso->block_info.closure)->type==BLACKHOLE_BQ ||
615 get_itbl(tso->block_info.closure)->type==RBH);
620 /* isOnBQ(blocked_queue) */
622 case BlockedOnException:
623 /* isOnSomeBQ(tso) */
624 ASSERT(get_itbl(tso->block_info.tso)->type==TSO);
627 ASSERT(get_itbl(tso->block_info.closure)->type==MVAR);
631 Could check other values of why_blocked but I am more
632 lazy than paranoid (bad combination) -- HWL
636 /* if the link field is non-nil it most point to one of these
637 three closure types */
638 ASSERT(tso->link == END_TSO_QUEUE ||
639 get_itbl(tso->link)->type == TSO ||
640 get_itbl(tso->link)->type == BLOCKED_FETCH ||
641 get_itbl(tso->link)->type == CONSTR);
644 checkStack(sp, stack_end, su);
648 //@cindex checkTSOsSanity
650 checkTSOsSanity(void) {
654 belch("Checking sanity of all runnable TSOs:");
656 for (i=0, tsos=0; i<RtsFlags.GranFlags.proc; i++) {
657 for (tso=run_queue_hds[i]; tso!=END_TSO_QUEUE; tso=tso->link) {
658 fprintf(stderr, "TSO %p on PE %d ...", tso, i);
660 fprintf(stderr, "OK, ");
665 belch(" checked %d TSOs on %d PEs; ok\n", tsos, RtsFlags.GranFlags.proc);
668 //@node Thread Queue Sanity, Blackhole Sanity, TSO Sanity
669 //@subsection Thread Queue Sanity
673 //@cindex checkThreadQSanity
675 checkThreadQSanity (PEs proc, rtsBool check_TSO_too)
679 /* the NIL value for TSOs is END_TSO_QUEUE; thus, finding NULL is an error */
680 ASSERT(run_queue_hds[proc]!=NULL);
681 ASSERT(run_queue_tls[proc]!=NULL);
682 /* if either head or tail is NIL then the other one must be NIL, too */
683 ASSERT(run_queue_hds[proc]!=END_TSO_QUEUE || run_queue_tls[proc]==END_TSO_QUEUE);
684 ASSERT(run_queue_tls[proc]!=END_TSO_QUEUE || run_queue_hds[proc]==END_TSO_QUEUE);
685 for (tso=run_queue_hds[proc], prev=END_TSO_QUEUE;
687 prev=tso, tso=tso->link) {
688 ASSERT((prev!=END_TSO_QUEUE || tso==run_queue_hds[proc]) &&
689 (prev==END_TSO_QUEUE || prev->link==tso));
693 ASSERT(prev==run_queue_tls[proc]);
696 //@cindex checkThreadQsSanity
698 checkThreadQsSanity (rtsBool check_TSO_too)
702 for (p=0; p<RtsFlags.GranFlags.proc; p++)
703 checkThreadQSanity(p, check_TSO_too);
708 Check that all TSOs have been evacuated.
709 Optionally also check the sanity of the TSOs.
712 checkGlobalTSOList (rtsBool checkTSOs)
714 extern StgTSO *all_threads;
716 for (tso=all_threads; tso != END_TSO_QUEUE; tso = tso->global_link) {
717 ASSERT(Bdescr((P_)tso)->evacuated == 1);
723 //@node Blackhole Sanity, GALA table sanity, Thread Queue Sanity
724 //@subsection Blackhole Sanity
726 /* -----------------------------------------------------------------------------
727 Check Blackhole Sanity
729 Test whether an object is already on the update list.
730 It isn't necessarily an rts error if it is - it might be a programming
733 Future versions might be able to test for a blackhole without traversing
734 the update frame list.
736 -------------------------------------------------------------------------- */
737 //@cindex isBlackhole
739 isBlackhole( StgTSO* tso, StgClosure* p )
741 StgUpdateFrame* su = tso->su;
743 switch (get_itbl(su)->type) {
745 if (su->updatee == p) {
752 su = stgCast(StgSeqFrame*,su)->link;
755 su = stgCast(StgCatchFrame*,su)->link;
760 barf("isBlackhole: weird record found on update frame list.");
766 Check the static objects list.
769 checkStaticObjects ( void ) {
770 extern StgClosure* static_objects;
771 StgClosure *p = static_objects;
774 while (p != END_OF_STATIC_LIST) {
777 switch (info->type) {
780 StgClosure *indirectee = stgCast(StgIndStatic*,p)->indirectee;
782 ASSERT(LOOKS_LIKE_PTR(indirectee));
783 ASSERT(LOOKS_LIKE_GHC_INFO(indirectee->header.info));
784 p = IND_STATIC_LINK((StgClosure *)p);
789 p = THUNK_STATIC_LINK((StgClosure *)p);
793 p = FUN_STATIC_LINK((StgClosure *)p);
797 p = STATIC_LINK(info,(StgClosure *)p);
801 barf("checkStaticObjetcs: strange closure %p (%s)",
808 Check the sanity of a blocking queue starting at bqe with closure being
809 the closure holding the blocking queue.
810 Note that in GUM we can have several different closure types in a
816 checkBQ (StgBlockingQueueElement *bqe, StgClosure *closure)
818 rtsBool end = rtsFalse;
819 StgInfoTable *info = get_itbl(closure);
821 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR
822 || info->type == FETCH_ME_BQ || info->type == RBH);
825 switch (get_itbl(bqe)->type) {
828 checkClosure((StgClosure *)bqe);
830 end = (bqe==END_BQ_QUEUE);
834 checkClosure((StgClosure *)bqe);
839 barf("checkBQ: strange closure %d in blocking queue for closure %p (%s)\n",
840 get_itbl(bqe)->type, closure, info_type(closure));
846 checkBQ (StgTSO *bqe, StgClosure *closure)
848 rtsBool end = rtsFalse;
849 StgInfoTable *info = get_itbl(closure);
851 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR);
854 switch (get_itbl(bqe)->type) {
857 checkClosure((StgClosure *)bqe);
859 end = (bqe==END_BQ_QUEUE);
863 barf("checkBQ: strange closure %d in blocking queue for closure %p (%s)\n",
864 get_itbl(bqe)->type, closure, info_type(closure));
870 checkBQ (StgTSO *bqe, StgClosure *closure)
872 rtsBool end = rtsFalse;
873 StgInfoTable *info = get_itbl(closure);
875 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR);
878 switch (get_itbl(bqe)->type) {
880 checkClosure((StgClosure *)bqe);
882 end = (bqe==END_TSO_QUEUE);
886 barf("checkBQ: strange closure %d in blocking queue for closure %p\n",
887 get_itbl(bqe)->type, closure, info->type);
895 //@node GALA table sanity, Index, Blackhole Sanity
896 //@subsection GALA table sanity
899 This routine checks the sanity of the LAGA and GALA tables. They are
900 implemented as lists through one hash table, LAtoGALAtable, because entries
901 in both tables have the same structure:
902 - the LAGA table maps local addresses to global addresses; it starts
903 with liveIndirections
904 - the GALA table maps global addresses to local addresses; it starts
911 /* hidden in parallel/Global.c; only accessed for testing here */
912 extern GALA *liveIndirections;
913 extern GALA *liveRemoteGAs;
914 extern HashTable *LAtoGALAtable;
916 //@cindex checkLAGAtable
918 checkLAGAtable(rtsBool check_closures)
921 nat n=0, m=0; // debugging
923 for (gala = liveIndirections; gala != NULL; gala = gala->next) {
925 gala0 = lookupHashTable(LAtoGALAtable, (StgWord) gala->la);
926 ASSERT(!gala->preferred || gala == gala0);
927 ASSERT(LOOKS_LIKE_GHC_INFO(((StgClosure *)gala->la)->header.info));
928 ASSERT(gala->next!=gala); // detect direct loops
930 if ( check_closures ) {
931 checkClosure(stgCast(StgClosure*,gala->la));
936 for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
938 gala0 = lookupHashTable(LAtoGALAtable, (StgWord) gala->la);
939 ASSERT(!gala->preferred || gala == gala0);
940 ASSERT(LOOKS_LIKE_GHC_INFO(((StgClosure *)gala->la)->header.info));
941 ASSERT(gala->next!=gala); // detect direct loops
943 if ( check_closures ) {
944 checkClosure(stgCast(StgClosure*,gala->la));
951 //@node Index, , GALA table sanity
957 //* checkBQ:: @cindex\s-+checkBQ
958 //* checkChain:: @cindex\s-+checkChain
959 //* checkClosureShallow:: @cindex\s-+checkClosureShallow
960 //* checkHeap:: @cindex\s-+checkHeap
961 //* checkLargeBitmap:: @cindex\s-+checkLargeBitmap
962 //* checkSmallBitmap:: @cindex\s-+checkSmallBitmap
963 //* checkStack:: @cindex\s-+checkStack
964 //* checkStackChunk:: @cindex\s-+checkStackChunk
965 //* checkStackChunk:: @cindex\s-+checkStackChunk
966 //* checkStackClosure:: @cindex\s-+checkStackClosure
967 //* checkStackObject:: @cindex\s-+checkStackObject
968 //* checkTSO:: @cindex\s-+checkTSO
969 //* checkTSOsSanity:: @cindex\s-+checkTSOsSanity
970 //* checkThreadQSanity:: @cindex\s-+checkThreadQSanity
971 //* checkThreadQsSanity:: @cindex\s-+checkThreadQsSanity
972 //* isBlackhole:: @cindex\s-+isBlackhole