1 /* -----------------------------------------------------------------------------
2 * $Id: Sanity.c,v 1.26 2001/02/09 13:09:16 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"
41 #include "StoragePriv.h" // for END_OF_STATIC_LIST
43 //@node Macros, Stack sanity, Includes
46 #define LOOKS_LIKE_PTR(r) ((LOOKS_LIKE_STATIC_CLOSURE(r) || \
47 ((HEAP_ALLOCED(r) && Bdescr((P_)r)->free != (void *)-1))) && \
48 ((StgWord)(*(StgPtr)r)!=0xaaaaaaaa))
50 //@node Stack sanity, Heap Sanity, Macros
51 //@subsection Stack sanity
53 /* -----------------------------------------------------------------------------
55 -------------------------------------------------------------------------- */
57 StgOffset checkStackClosure( StgClosure* c );
59 StgOffset checkStackObject( StgPtr sp );
61 void checkStackChunk( StgPtr sp, StgPtr stack_end );
63 static StgOffset checkSmallBitmap( StgPtr payload, StgWord32 bitmap );
65 static StgOffset checkLargeBitmap( StgPtr payload,
66 StgLargeBitmap* large_bitmap );
68 void checkClosureShallow( StgClosure* p );
70 //@cindex checkSmallBitmap
72 checkSmallBitmap( StgPtr payload, StgWord32 bitmap )
77 for(; bitmap != 0; ++i, bitmap >>= 1 ) {
78 if ((bitmap & 1) == 0) {
79 checkClosure(stgCast(StgClosure*,payload[i]));
85 //@cindex checkLargeBitmap
87 checkLargeBitmap( StgPtr payload, StgLargeBitmap* large_bitmap )
93 for (bmp=0; bmp<large_bitmap->size; bmp++) {
94 StgWord32 bitmap = large_bitmap->bitmap[bmp];
95 for(; bitmap != 0; ++i, bitmap >>= 1 ) {
96 if ((bitmap & 1) == 0) {
97 checkClosure(stgCast(StgClosure*,payload[i]));
104 //@cindex checkStackClosure
106 checkStackClosure( StgClosure* c )
108 const StgInfoTable* info = get_itbl(c);
110 /* All activation records have 'bitmap' style layout info. */
111 switch (info->type) {
112 case RET_DYN: /* Dynamic bitmap: the mask is stored on the stack */
114 StgRetDyn* r = (StgRetDyn *)c;
115 return sizeofW(StgRetDyn) +
116 checkSmallBitmap(r->payload,r->liveness);
118 case RET_BCO: /* small bitmap (<= 32 entries) */
121 return 1 + checkSmallBitmap((StgPtr)c + 1,info->layout.bitmap);
124 ASSERT(LOOKS_LIKE_PTR(((StgUpdateFrame*)c)->updatee));
127 /* check that the link field points to another stack frame */
128 ASSERT(get_itbl(((StgFrame*)c)->link)->type == UPDATE_FRAME ||
129 get_itbl(((StgFrame*)c)->link)->type == CATCH_FRAME ||
130 get_itbl(((StgFrame*)c)->link)->type == STOP_FRAME ||
131 get_itbl(((StgFrame*)c)->link)->type == SEQ_FRAME);
139 checkSmallBitmap((StgPtr)c + 1,info->layout.bitmap);
140 case RET_BIG: /* large bitmap (> 32 entries) */
142 return 1 + checkLargeBitmap((StgPtr)c + 1,info->layout.large_bitmap);
144 case FUN_STATIC: /* probably a slow-entry point return address: */
145 #if 0 && defined(GRAN)
151 /* if none of the above, maybe it's a closure which looks a
152 * little like an infotable
154 checkClosureShallow(*(StgClosure **)c);
156 /* barf("checkStackClosure: weird activation record found on stack (%p).",c); */
161 * check that it looks like a valid closure - without checking its payload
162 * used to avoid recursion between checking PAPs and checking stack
166 //@cindex checkClosureShallow
168 checkClosureShallow( StgClosure* p )
171 ASSERT(LOOKS_LIKE_GHC_INFO(p->header.info)
172 || IS_HUGS_CONSTR_INFO(GET_INFO(p)));
174 /* Is it a static closure (i.e. in the data segment)? */
175 if (LOOKS_LIKE_STATIC(p)) {
176 ASSERT(closure_STATIC(p));
178 ASSERT(!closure_STATIC(p));
179 ASSERT(LOOKS_LIKE_PTR(p));
183 /* check an individual stack object */
184 //@cindex checkStackObject
186 checkStackObject( StgPtr sp )
188 if (IS_ARG_TAG(*sp)) {
189 /* Tagged words might be "stubbed" pointers, so there's no
190 * point checking to see whether they look like pointers or
191 * not (some of them will).
193 return ARG_SIZE(*sp) + 1;
194 } else if (LOOKS_LIKE_GHC_INFO(*stgCast(StgPtr*,sp))) {
195 return checkStackClosure(stgCast(StgClosure*,sp));
196 } else { /* must be an untagged closure pointer in the stack */
197 checkClosureShallow(*stgCast(StgClosure**,sp));
202 /* check sections of stack between update frames */
203 //@cindex checkStackChunk
205 checkStackChunk( StgPtr sp, StgPtr stack_end )
210 while (p < stack_end) {
211 p += checkStackObject( p );
213 // ASSERT( p == stack_end ); -- HWL
216 //@cindex checkStackChunk
218 checkClosure( StgClosure* p )
220 const StgInfoTable *info;
222 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) {
237 StgMVar *mvar = (StgMVar *)p;
238 ASSERT(LOOKS_LIKE_PTR(mvar->head));
239 ASSERT(LOOKS_LIKE_PTR(mvar->tail));
240 ASSERT(LOOKS_LIKE_PTR(mvar->value));
243 checkBQ((StgBlockingQueueElement *)mvar->head, p);
245 checkBQ(mvar->head, p);
248 return sizeofW(StgMVar);
259 for (i = 0; i < info->layout.payload.ptrs; i++) {
260 ASSERT(LOOKS_LIKE_PTR(p->payload[i]));
262 return stg_max(sizeW_fromITBL(info), sizeofW(StgHeader) + MIN_UPD_SIZE);
266 checkBQ(((StgBlockingQueue *)p)->blocking_queue, p);
267 /* fall through to basic ptr check */
282 case IND_OLDGEN_PERM:
285 case SE_CAF_BLACKHOLE:
294 case CONSTR_CHARLIKE:
296 case CONSTR_NOCAF_STATIC:
301 for (i = 0; i < info->layout.payload.ptrs; i++) {
302 ASSERT(LOOKS_LIKE_PTR(p->payload[i]));
304 return sizeW_fromITBL(info);
307 case IND_STATIC: /* (1, 0) closure */
308 ASSERT(LOOKS_LIKE_PTR(((StgIndStatic*)p)->indirectee));
309 return sizeW_fromITBL(info);
312 /* deal with these specially - the info table isn't
313 * representative of the actual layout.
315 { StgWeak *w = (StgWeak *)p;
316 ASSERT(LOOKS_LIKE_PTR(w->key));
317 ASSERT(LOOKS_LIKE_PTR(w->value));
318 ASSERT(LOOKS_LIKE_PTR(w->finalizer));
320 ASSERT(LOOKS_LIKE_PTR(w->link));
322 return sizeW_fromITBL(info);
326 ASSERT(LOOKS_LIKE_PTR(stgCast(StgSelector*,p)->selectee));
327 return sizeofW(StgHeader) + MIN_UPD_SIZE;
331 /* we don't expect to see any of these after GC
332 * but they might appear during execution
335 StgInd *ind = stgCast(StgInd*,p);
336 ASSERT(LOOKS_LIKE_PTR(ind->indirectee));
337 q = (P_)p + sizeofW(StgInd);
338 while (!*q) { q++; }; /* skip padding words (see GC.c: evacuate())*/
352 barf("checkClosure: stack frame");
354 case AP_UPD: /* we can treat this as being the same as a PAP */
357 StgPAP *pap = stgCast(StgPAP*,p);
358 ASSERT(LOOKS_LIKE_PTR(pap->fun));
359 checkStackChunk((StgPtr)pap->payload,
360 (StgPtr)pap->payload + pap->n_args
362 return pap_sizeW(pap);
366 return arr_words_sizeW(stgCast(StgArrWords*,p));
369 case MUT_ARR_PTRS_FROZEN:
371 StgMutArrPtrs* a = stgCast(StgMutArrPtrs*,p);
373 for (i = 0; i < a->ptrs; i++) {
374 ASSERT(LOOKS_LIKE_PTR(a->payload[i]));
376 return mut_arr_ptrs_sizeW(a);
380 checkTSO((StgTSO *)p);
381 return tso_sizeW((StgTSO *)p);
386 ASSERT(LOOKS_LIKE_GA(&(((StgBlockedFetch *)p)->ga)));
387 ASSERT(LOOKS_LIKE_PTR((((StgBlockedFetch *)p)->node)));
388 return sizeofW(StgBlockedFetch); // see size used in evacuate()
391 ASSERT(LOOKS_LIKE_GA(((StgFetchMe *)p)->ga));
392 return sizeofW(StgFetchMe); // see size used in evacuate()
395 checkBQ(((StgFetchMeBlockingQueue *)p)->blocking_queue, (StgClosure *)p);
396 return sizeofW(StgFetchMeBlockingQueue); // see size used in evacuate()
399 /* In an RBH the BQ may be empty (ie END_BQ_QUEUE) but not NULL */
400 ASSERT(((StgRBH *)p)->blocking_queue!=NULL);
401 if (((StgRBH *)p)->blocking_queue!=END_BQ_QUEUE)
402 checkBQ(((StgRBH *)p)->blocking_queue, p);
403 ASSERT(LOOKS_LIKE_GHC_INFO(REVERT_INFOPTR(get_itbl((StgClosure *)p))));
404 return BLACKHOLE_sizeW(); // see size used in evacuate()
405 // sizeW_fromITBL(REVERT_INFOPTR(get_itbl((StgClosure *)p)));
410 barf("checkClosure: found EVACUATED closure %d",
413 barf("checkClosure (closure type %d)", info->type);
419 #define PVM_PE_MASK 0xfffc0000
420 #define MAX_PVM_PES MAX_PES
421 #define MAX_PVM_TIDS MAX_PES
422 #define MAX_SLOTS 100000
425 looks_like_tid(StgInt tid)
427 StgInt hi = (tid & PVM_PE_MASK) >> 18;
428 StgInt lo = (tid & ~PVM_PE_MASK);
429 rtsBool ok = (hi != 0) && (lo < MAX_PVM_TIDS) && (hi < MAX_PVM_TIDS);
434 looks_like_slot(StgInt slot)
436 /* if tid is known better use looks_like_ga!! */
437 rtsBool ok = slot<MAX_SLOTS;
438 // This refers only to the no. of slots on the current PE
439 // rtsBool ok = slot<=highest_slot();
444 looks_like_ga(globalAddr *ga)
446 rtsBool is_tid = looks_like_tid((ga)->payload.gc.gtid);
447 rtsBool is_slot = ((ga)->payload.gc.gtid==mytid) ?
448 (ga)->payload.gc.slot<=highest_slot() :
449 (ga)->payload.gc.slot<MAX_SLOTS;
450 rtsBool ok = is_tid && is_slot;
456 //@node Heap Sanity, TSO Sanity, Stack sanity
457 //@subsection Heap Sanity
459 /* -----------------------------------------------------------------------------
462 After garbage collection, the live heap is in a state where we can
463 run through and check that all the pointers point to the right
464 place. This function starts at a given position and sanity-checks
465 all the objects in the remainder of the chain.
466 -------------------------------------------------------------------------- */
470 checkHeap(bdescr *bd, StgPtr start)
473 nat xxx = 0; // tmp -- HWL
476 if (bd != NULL) p = bd->start;
482 while (p < bd->free) {
483 nat size = checkClosure(stgCast(StgClosure*,p));
484 /* This is the smallest size of closure that can live in the heap. */
485 ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
486 if (get_itbl(stgCast(StgClosure*,p))->type == IND_STATIC)
491 while (p < bd->free &&
492 (*p < 0x1000 || !LOOKS_LIKE_GHC_INFO((void*)*p))) { p++; }
499 fprintf(stderr,"@@@@ checkHeap: Heap ok; %d IND_STATIC closures checked\n",
504 Check heap between start and end. Used after unpacking graphs.
507 checkHeapChunk(StgPtr start, StgPtr end)
512 for (p=start; p<end; p+=size) {
513 ASSERT(LOOKS_LIKE_GHC_INFO((void*)*p));
514 size = checkClosure(stgCast(StgClosure*,p));
515 /* This is the smallest size of closure that can live in the heap. */
516 ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
522 checkChain(bdescr *bd)
525 checkClosure((StgClosure *)bd->start);
530 /* check stack - making sure that update frames are linked correctly */
533 checkStack(StgPtr sp, StgPtr stack_end, StgUpdateFrame* su )
535 /* check everything down to the first update frame */
536 checkStackChunk( sp, stgCast(StgPtr,su) );
537 while ( stgCast(StgPtr,su) < stack_end) {
538 sp = stgCast(StgPtr,su);
539 switch (get_itbl(su)->type) {
544 su = stgCast(StgSeqFrame*,su)->link;
547 su = stgCast(StgCatchFrame*,su)->link;
550 /* not quite: ASSERT(stgCast(StgPtr,su) == stack_end); */
553 barf("checkStack: weird record found on update frame list.");
555 checkStackChunk( sp, stgCast(StgPtr,su) );
557 ASSERT(stgCast(StgPtr,su) == stack_end);
560 //@node TSO Sanity, Thread Queue Sanity, Heap Sanity
561 //@subsection TSO Sanity
565 checkTSO(StgTSO *tso)
568 StgPtr stack = tso->stack;
569 StgUpdateFrame* su = tso->su;
570 StgOffset stack_size = tso->stack_size;
571 StgPtr stack_end = stack + stack_size;
573 if (tso->what_next == ThreadRelocated) {
578 if (tso->what_next == ThreadComplete || tso->what_next == ThreadKilled) {
579 /* The garbage collector doesn't bother following any pointers
580 * from dead threads, so don't check sanity here.
585 ASSERT(stack <= sp && sp < stack_end);
586 ASSERT(sp <= stgCast(StgPtr,su));
589 ASSERT(tso->par.magic==TSO_MAGIC);
591 switch (tso->why_blocked) {
593 checkClosureShallow(tso->block_info.closure);
594 ASSERT(/* Can't be a FETCH_ME because *this* closure is on its BQ */
595 get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ);
597 case BlockedOnGA_NoSend:
598 checkClosureShallow(tso->block_info.closure);
599 ASSERT(get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ);
601 case BlockedOnBlackHole:
602 checkClosureShallow(tso->block_info.closure);
603 ASSERT(/* Can't be a BLACKHOLE because *this* closure is on its BQ */
604 get_itbl(tso->block_info.closure)->type==BLACKHOLE_BQ ||
605 get_itbl(tso->block_info.closure)->type==RBH);
610 /* isOnBQ(blocked_queue) */
612 case BlockedOnException:
613 /* isOnSomeBQ(tso) */
614 ASSERT(get_itbl(tso->block_info.tso)->type==TSO);
617 ASSERT(get_itbl(tso->block_info.closure)->type==MVAR);
621 Could check other values of why_blocked but I am more
622 lazy than paranoid (bad combination) -- HWL
626 /* if the link field is non-nil it most point to one of these
627 three closure types */
628 ASSERT(tso->link == END_TSO_QUEUE ||
629 get_itbl(tso->link)->type == TSO ||
630 get_itbl(tso->link)->type == BLOCKED_FETCH ||
631 get_itbl(tso->link)->type == CONSTR);
634 checkStack(sp, stack_end, su);
638 //@cindex checkTSOsSanity
640 checkTSOsSanity(void) {
644 belch("Checking sanity of all runnable TSOs:");
646 for (i=0, tsos=0; i<RtsFlags.GranFlags.proc; i++) {
647 for (tso=run_queue_hds[i]; tso!=END_TSO_QUEUE; tso=tso->link) {
648 fprintf(stderr, "TSO %p on PE %d ...", tso, i);
650 fprintf(stderr, "OK, ");
655 belch(" checked %d TSOs on %d PEs; ok\n", tsos, RtsFlags.GranFlags.proc);
658 //@node Thread Queue Sanity, Blackhole Sanity, TSO Sanity
659 //@subsection Thread Queue Sanity
663 //@cindex checkThreadQSanity
665 checkThreadQSanity (PEs proc, rtsBool check_TSO_too)
669 /* the NIL value for TSOs is END_TSO_QUEUE; thus, finding NULL is an error */
670 ASSERT(run_queue_hds[proc]!=NULL);
671 ASSERT(run_queue_tls[proc]!=NULL);
672 /* if either head or tail is NIL then the other one must be NIL, too */
673 ASSERT(run_queue_hds[proc]!=END_TSO_QUEUE || run_queue_tls[proc]==END_TSO_QUEUE);
674 ASSERT(run_queue_tls[proc]!=END_TSO_QUEUE || run_queue_hds[proc]==END_TSO_QUEUE);
675 for (tso=run_queue_hds[proc], prev=END_TSO_QUEUE;
677 prev=tso, tso=tso->link) {
678 ASSERT((prev!=END_TSO_QUEUE || tso==run_queue_hds[proc]) &&
679 (prev==END_TSO_QUEUE || prev->link==tso));
683 ASSERT(prev==run_queue_tls[proc]);
686 //@cindex checkThreadQsSanity
688 checkThreadQsSanity (rtsBool check_TSO_too)
692 for (p=0; p<RtsFlags.GranFlags.proc; p++)
693 checkThreadQSanity(p, check_TSO_too);
698 Check that all TSOs have been evacuated.
699 Optionally also check the sanity of the TSOs.
702 checkGlobalTSOList (rtsBool checkTSOs)
704 extern StgTSO *all_threads;
706 for (tso=all_threads; tso != END_TSO_QUEUE; tso = tso->global_link) {
707 ASSERT(Bdescr((P_)tso)->evacuated == 1);
713 //@node Blackhole Sanity, GALA table sanity, Thread Queue Sanity
714 //@subsection Blackhole Sanity
716 /* -----------------------------------------------------------------------------
717 Check Blackhole Sanity
719 Test whether an object is already on the update list.
720 It isn't necessarily an rts error if it is - it might be a programming
723 Future versions might be able to test for a blackhole without traversing
724 the update frame list.
726 -------------------------------------------------------------------------- */
727 //@cindex isBlackhole
729 isBlackhole( StgTSO* tso, StgClosure* p )
731 StgUpdateFrame* su = tso->su;
733 switch (get_itbl(su)->type) {
735 if (su->updatee == p) {
742 su = stgCast(StgSeqFrame*,su)->link;
745 su = stgCast(StgCatchFrame*,su)->link;
750 barf("isBlackhole: weird record found on update frame list.");
756 Check the static objects list.
759 checkStaticObjects ( void ) {
760 extern StgClosure* static_objects;
761 StgClosure *p = static_objects;
764 while (p != END_OF_STATIC_LIST) {
767 switch (info->type) {
770 StgClosure *indirectee = stgCast(StgIndStatic*,p)->indirectee;
772 ASSERT(LOOKS_LIKE_PTR(indirectee));
773 ASSERT(LOOKS_LIKE_GHC_INFO(indirectee->header.info));
774 p = IND_STATIC_LINK((StgClosure *)p);
779 p = THUNK_STATIC_LINK((StgClosure *)p);
783 p = FUN_STATIC_LINK((StgClosure *)p);
787 p = STATIC_LINK(info,(StgClosure *)p);
791 barf("checkStaticObjetcs: strange closure %p (%s)",
798 Check the sanity of a blocking queue starting at bqe with closure being
799 the closure holding the blocking queue.
800 Note that in GUM we can have several different closure types in a
806 checkBQ (StgBlockingQueueElement *bqe, StgClosure *closure)
808 rtsBool end = rtsFalse;
809 StgInfoTable *info = get_itbl(closure);
811 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR
812 || info->type == FETCH_ME_BQ || info->type == RBH);
815 switch (get_itbl(bqe)->type) {
818 checkClosure((StgClosure *)bqe);
820 end = (bqe==END_BQ_QUEUE);
824 checkClosure((StgClosure *)bqe);
829 barf("checkBQ: strange closure %d in blocking queue for closure %p (%s)\n",
830 get_itbl(bqe)->type, closure, info_type(closure));
836 checkBQ (StgTSO *bqe, StgClosure *closure)
838 rtsBool end = rtsFalse;
839 StgInfoTable *info = get_itbl(closure);
841 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR);
844 switch (get_itbl(bqe)->type) {
847 checkClosure((StgClosure *)bqe);
849 end = (bqe==END_BQ_QUEUE);
853 barf("checkBQ: strange closure %d in blocking queue for closure %p (%s)\n",
854 get_itbl(bqe)->type, closure, info_type(closure));
860 checkBQ (StgTSO *bqe, StgClosure *closure)
862 rtsBool end = rtsFalse;
863 StgInfoTable *info = get_itbl(closure);
865 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR);
868 switch (get_itbl(bqe)->type) {
870 checkClosure((StgClosure *)bqe);
872 end = (bqe==END_TSO_QUEUE);
876 barf("checkBQ: strange closure %d in blocking queue for closure %p\n",
877 get_itbl(bqe)->type, closure, info->type);
885 //@node GALA table sanity, Index, Blackhole Sanity
886 //@subsection GALA table sanity
889 This routine checks the sanity of the LAGA and GALA tables. They are
890 implemented as lists through one hash table, LAtoGALAtable, because entries
891 in both tables have the same structure:
892 - the LAGA table maps local addresses to global addresses; it starts
893 with liveIndirections
894 - the GALA table maps global addresses to local addresses; it starts
901 /* hidden in parallel/Global.c; only accessed for testing here */
902 extern GALA *liveIndirections;
903 extern GALA *liveRemoteGAs;
904 extern HashTable *LAtoGALAtable;
906 //@cindex checkLAGAtable
908 checkLAGAtable(rtsBool check_closures)
911 nat n=0, m=0; // debugging
913 for (gala = liveIndirections; gala != NULL; gala = gala->next) {
915 gala0 = lookupHashTable(LAtoGALAtable, (StgWord) gala->la);
916 ASSERT(!gala->preferred || gala == gala0);
917 ASSERT(LOOKS_LIKE_GHC_INFO(((StgClosure *)gala->la)->header.info));
918 ASSERT(gala->next!=gala); // detect direct loops
920 if ( check_closures ) {
921 checkClosure(stgCast(StgClosure*,gala->la));
926 for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
928 gala0 = lookupHashTable(LAtoGALAtable, (StgWord) gala->la);
929 ASSERT(!gala->preferred || gala == gala0);
930 ASSERT(LOOKS_LIKE_GHC_INFO(((StgClosure *)gala->la)->header.info));
931 ASSERT(gala->next!=gala); // detect direct loops
933 if ( check_closures ) {
934 checkClosure(stgCast(StgClosure*,gala->la));
941 //@node Index, , GALA table sanity
947 //* checkBQ:: @cindex\s-+checkBQ
948 //* checkChain:: @cindex\s-+checkChain
949 //* checkClosureShallow:: @cindex\s-+checkClosureShallow
950 //* checkHeap:: @cindex\s-+checkHeap
951 //* checkLargeBitmap:: @cindex\s-+checkLargeBitmap
952 //* checkSmallBitmap:: @cindex\s-+checkSmallBitmap
953 //* checkStack:: @cindex\s-+checkStack
954 //* checkStackChunk:: @cindex\s-+checkStackChunk
955 //* checkStackChunk:: @cindex\s-+checkStackChunk
956 //* checkStackClosure:: @cindex\s-+checkStackClosure
957 //* checkStackObject:: @cindex\s-+checkStackObject
958 //* checkTSO:: @cindex\s-+checkTSO
959 //* checkTSOsSanity:: @cindex\s-+checkTSOsSanity
960 //* checkThreadQSanity:: @cindex\s-+checkThreadQSanity
961 //* checkThreadQsSanity:: @cindex\s-+checkThreadQsSanity
962 //* isBlackhole:: @cindex\s-+isBlackhole