1 /* -----------------------------------------------------------------------------
2 * $Id: Sanity.c,v 1.25 2001/01/29 17:23:41 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;
223 ASSERT(LOOKS_LIKE_GHC_INFO(p->header.info));
226 /* Is it a static closure (i.e. in the data segment)? */
227 if (LOOKS_LIKE_STATIC(p)) {
228 ASSERT(closure_STATIC(p));
230 ASSERT(!closure_STATIC(p));
231 ASSERT(LOOKS_LIKE_PTR(p));
235 switch (info->type) {
239 StgMVar *mvar = (StgMVar *)p;
240 ASSERT(LOOKS_LIKE_PTR(mvar->head));
241 ASSERT(LOOKS_LIKE_PTR(mvar->tail));
242 ASSERT(LOOKS_LIKE_PTR(mvar->value));
245 checkBQ((StgBlockingQueueElement *)mvar->head, p);
247 checkBQ(mvar->head, p);
250 return sizeofW(StgMVar);
261 for (i = 0; i < info->layout.payload.ptrs; i++) {
262 ASSERT(LOOKS_LIKE_PTR(p->payload[i]));
264 return stg_max(sizeW_fromITBL(info), sizeofW(StgHeader) + MIN_UPD_SIZE);
268 checkBQ(((StgBlockingQueue *)p)->blocking_queue, p);
269 /* fall through to basic ptr check */
284 case IND_OLDGEN_PERM:
287 case SE_CAF_BLACKHOLE:
296 case CONSTR_CHARLIKE:
298 case CONSTR_NOCAF_STATIC:
303 for (i = 0; i < info->layout.payload.ptrs; i++) {
304 ASSERT(LOOKS_LIKE_PTR(p->payload[i]));
306 return sizeW_fromITBL(info);
309 case IND_STATIC: /* (1, 0) closure */
310 ASSERT(LOOKS_LIKE_PTR(((StgIndStatic*)p)->indirectee));
311 return sizeW_fromITBL(info);
314 /* deal with these specially - the info table isn't
315 * representative of the actual layout.
317 { StgWeak *w = (StgWeak *)p;
318 ASSERT(LOOKS_LIKE_PTR(w->key));
319 ASSERT(LOOKS_LIKE_PTR(w->value));
320 ASSERT(LOOKS_LIKE_PTR(w->finalizer));
322 ASSERT(LOOKS_LIKE_PTR(w->link));
324 return sizeW_fromITBL(info);
328 ASSERT(LOOKS_LIKE_PTR(stgCast(StgSelector*,p)->selectee));
329 return sizeofW(StgHeader) + MIN_UPD_SIZE;
333 /* we don't expect to see any of these after GC
334 * but they might appear during execution
337 StgInd *ind = stgCast(StgInd*,p);
338 ASSERT(LOOKS_LIKE_PTR(ind->indirectee));
339 q = (P_)p + sizeofW(StgInd);
340 while (!*q) { q++; }; /* skip padding words (see GC.c: evacuate())*/
354 barf("checkClosure: stack frame");
356 case AP_UPD: /* we can treat this as being the same as a PAP */
359 StgPAP *pap = stgCast(StgPAP*,p);
360 ASSERT(LOOKS_LIKE_PTR(pap->fun));
361 checkStackChunk((StgPtr)pap->payload,
362 (StgPtr)pap->payload + pap->n_args
364 return pap_sizeW(pap);
368 return arr_words_sizeW(stgCast(StgArrWords*,p));
371 case MUT_ARR_PTRS_FROZEN:
373 StgMutArrPtrs* a = stgCast(StgMutArrPtrs*,p);
375 for (i = 0; i < a->ptrs; i++) {
376 ASSERT(LOOKS_LIKE_PTR(a->payload[i]));
378 return mut_arr_ptrs_sizeW(a);
382 checkTSO((StgTSO *)p);
383 return tso_sizeW((StgTSO *)p);
388 ASSERT(LOOKS_LIKE_GA(&(((StgBlockedFetch *)p)->ga)));
389 ASSERT(LOOKS_LIKE_PTR((((StgBlockedFetch *)p)->node)));
390 return sizeofW(StgBlockedFetch); // see size used in evacuate()
393 ASSERT(LOOKS_LIKE_GA(((StgFetchMe *)p)->ga));
394 return sizeofW(StgFetchMe); // see size used in evacuate()
397 checkBQ(((StgFetchMeBlockingQueue *)p)->blocking_queue, (StgClosure *)p);
398 return sizeofW(StgFetchMeBlockingQueue); // see size used in evacuate()
401 /* In an RBH the BQ may be empty (ie END_BQ_QUEUE) but not NULL */
402 ASSERT(((StgRBH *)p)->blocking_queue!=NULL);
403 if (((StgRBH *)p)->blocking_queue!=END_BQ_QUEUE)
404 checkBQ(((StgRBH *)p)->blocking_queue, p);
405 ASSERT(LOOKS_LIKE_GHC_INFO(REVERT_INFOPTR(get_itbl((StgClosure *)p))));
406 return BLACKHOLE_sizeW(); // see size used in evacuate()
407 // sizeW_fromITBL(REVERT_INFOPTR(get_itbl((StgClosure *)p)));
412 barf("checkClosure: found EVACUATED closure %d",
415 barf("checkClosure (closure type %d)", info->type);
421 #define PVM_PE_MASK 0xfffc0000
422 #define MAX_PVM_PES MAX_PES
423 #define MAX_PVM_TIDS MAX_PES
424 #define MAX_SLOTS 100000
427 looks_like_tid(StgInt tid)
429 StgInt hi = (tid & PVM_PE_MASK) >> 18;
430 StgInt lo = (tid & ~PVM_PE_MASK);
431 rtsBool ok = (hi != 0) && (lo < MAX_PVM_TIDS) && (hi < MAX_PVM_TIDS);
436 looks_like_slot(StgInt slot)
438 /* if tid is known better use looks_like_ga!! */
439 rtsBool ok = slot<MAX_SLOTS;
440 // This refers only to the no. of slots on the current PE
441 // rtsBool ok = slot<=highest_slot();
446 looks_like_ga(globalAddr *ga)
448 rtsBool is_tid = looks_like_tid((ga)->payload.gc.gtid);
449 rtsBool is_slot = ((ga)->payload.gc.gtid==mytid) ?
450 (ga)->payload.gc.slot<=highest_slot() :
451 (ga)->payload.gc.slot<MAX_SLOTS;
452 rtsBool ok = is_tid && is_slot;
458 //@node Heap Sanity, TSO Sanity, Stack sanity
459 //@subsection Heap Sanity
461 /* -----------------------------------------------------------------------------
464 After garbage collection, the live heap is in a state where we can
465 run through and check that all the pointers point to the right
466 place. This function starts at a given position and sanity-checks
467 all the objects in the remainder of the chain.
468 -------------------------------------------------------------------------- */
472 checkHeap(bdescr *bd, StgPtr start)
475 nat xxx = 0; // tmp -- HWL
478 if (bd != NULL) p = bd->start;
484 while (p < bd->free) {
485 nat size = checkClosure(stgCast(StgClosure*,p));
486 /* This is the smallest size of closure that can live in the heap. */
487 ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
488 if (get_itbl(stgCast(StgClosure*,p))->type == IND_STATIC)
493 while (p < bd->free &&
494 (*p < 0x1000 || !LOOKS_LIKE_GHC_INFO((void*)*p))) { p++; }
501 fprintf(stderr,"@@@@ checkHeap: Heap ok; %d IND_STATIC closures checked\n",
506 Check heap between start and end. Used after unpacking graphs.
509 checkHeapChunk(StgPtr start, StgPtr end)
514 for (p=start; p<end; p+=size) {
515 ASSERT(LOOKS_LIKE_GHC_INFO((void*)*p));
516 size = checkClosure(stgCast(StgClosure*,p));
517 /* This is the smallest size of closure that can live in the heap. */
518 ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
524 checkChain(bdescr *bd)
527 checkClosure((StgClosure *)bd->start);
532 /* check stack - making sure that update frames are linked correctly */
535 checkStack(StgPtr sp, StgPtr stack_end, StgUpdateFrame* su )
537 /* check everything down to the first update frame */
538 checkStackChunk( sp, stgCast(StgPtr,su) );
539 while ( stgCast(StgPtr,su) < stack_end) {
540 sp = stgCast(StgPtr,su);
541 switch (get_itbl(su)->type) {
546 su = stgCast(StgSeqFrame*,su)->link;
549 su = stgCast(StgCatchFrame*,su)->link;
552 /* not quite: ASSERT(stgCast(StgPtr,su) == stack_end); */
555 barf("checkStack: weird record found on update frame list.");
557 checkStackChunk( sp, stgCast(StgPtr,su) );
559 ASSERT(stgCast(StgPtr,su) == stack_end);
562 //@node TSO Sanity, Thread Queue Sanity, Heap Sanity
563 //@subsection TSO Sanity
567 checkTSO(StgTSO *tso)
570 StgPtr stack = tso->stack;
571 StgUpdateFrame* su = tso->su;
572 StgOffset stack_size = tso->stack_size;
573 StgPtr stack_end = stack + stack_size;
575 if (tso->what_next == ThreadRelocated) {
580 if (tso->what_next == ThreadComplete || tso->what_next == ThreadKilled) {
581 /* The garbage collector doesn't bother following any pointers
582 * from dead threads, so don't check sanity here.
587 ASSERT(stack <= sp && sp < stack_end);
588 ASSERT(sp <= stgCast(StgPtr,su));
591 ASSERT(tso->par.magic==TSO_MAGIC);
593 switch (tso->why_blocked) {
595 checkClosureShallow(tso->block_info.closure);
596 ASSERT(/* Can't be a FETCH_ME because *this* closure is on its BQ */
597 get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ);
599 case BlockedOnGA_NoSend:
600 checkClosureShallow(tso->block_info.closure);
601 ASSERT(get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ);
603 case BlockedOnBlackHole:
604 checkClosureShallow(tso->block_info.closure);
605 ASSERT(/* Can't be a BLACKHOLE because *this* closure is on its BQ */
606 get_itbl(tso->block_info.closure)->type==BLACKHOLE_BQ ||
607 get_itbl(tso->block_info.closure)->type==RBH);
612 /* isOnBQ(blocked_queue) */
614 case BlockedOnException:
615 /* isOnSomeBQ(tso) */
616 ASSERT(get_itbl(tso->block_info.tso)->type==TSO);
619 ASSERT(get_itbl(tso->block_info.closure)->type==MVAR);
623 Could check other values of why_blocked but I am more
624 lazy than paranoid (bad combination) -- HWL
628 /* if the link field is non-nil it most point to one of these
629 three closure types */
630 ASSERT(tso->link == END_TSO_QUEUE ||
631 get_itbl(tso->link)->type == TSO ||
632 get_itbl(tso->link)->type == BLOCKED_FETCH ||
633 get_itbl(tso->link)->type == CONSTR);
636 checkStack(sp, stack_end, su);
640 //@cindex checkTSOsSanity
642 checkTSOsSanity(void) {
646 belch("Checking sanity of all runnable TSOs:");
648 for (i=0, tsos=0; i<RtsFlags.GranFlags.proc; i++) {
649 for (tso=run_queue_hds[i]; tso!=END_TSO_QUEUE; tso=tso->link) {
650 fprintf(stderr, "TSO %p on PE %d ...", tso, i);
652 fprintf(stderr, "OK, ");
657 belch(" checked %d TSOs on %d PEs; ok\n", tsos, RtsFlags.GranFlags.proc);
660 //@node Thread Queue Sanity, Blackhole Sanity, TSO Sanity
661 //@subsection Thread Queue Sanity
665 //@cindex checkThreadQSanity
667 checkThreadQSanity (PEs proc, rtsBool check_TSO_too)
671 /* the NIL value for TSOs is END_TSO_QUEUE; thus, finding NULL is an error */
672 ASSERT(run_queue_hds[proc]!=NULL);
673 ASSERT(run_queue_tls[proc]!=NULL);
674 /* if either head or tail is NIL then the other one must be NIL, too */
675 ASSERT(run_queue_hds[proc]!=END_TSO_QUEUE || run_queue_tls[proc]==END_TSO_QUEUE);
676 ASSERT(run_queue_tls[proc]!=END_TSO_QUEUE || run_queue_hds[proc]==END_TSO_QUEUE);
677 for (tso=run_queue_hds[proc], prev=END_TSO_QUEUE;
679 prev=tso, tso=tso->link) {
680 ASSERT((prev!=END_TSO_QUEUE || tso==run_queue_hds[proc]) &&
681 (prev==END_TSO_QUEUE || prev->link==tso));
685 ASSERT(prev==run_queue_tls[proc]);
688 //@cindex checkThreadQsSanity
690 checkThreadQsSanity (rtsBool check_TSO_too)
694 for (p=0; p<RtsFlags.GranFlags.proc; p++)
695 checkThreadQSanity(p, check_TSO_too);
700 Check that all TSOs have been evacuated.
701 Optionally also check the sanity of the TSOs.
704 checkGlobalTSOList (rtsBool checkTSOs)
706 extern StgTSO *all_threads;
708 for (tso=all_threads; tso != END_TSO_QUEUE; tso = tso->global_link) {
709 ASSERT(Bdescr((P_)tso)->evacuated == 1);
715 //@node Blackhole Sanity, GALA table sanity, Thread Queue Sanity
716 //@subsection Blackhole Sanity
718 /* -----------------------------------------------------------------------------
719 Check Blackhole Sanity
721 Test whether an object is already on the update list.
722 It isn't necessarily an rts error if it is - it might be a programming
725 Future versions might be able to test for a blackhole without traversing
726 the update frame list.
728 -------------------------------------------------------------------------- */
729 //@cindex isBlackhole
731 isBlackhole( StgTSO* tso, StgClosure* p )
733 StgUpdateFrame* su = tso->su;
735 switch (get_itbl(su)->type) {
737 if (su->updatee == p) {
744 su = stgCast(StgSeqFrame*,su)->link;
747 su = stgCast(StgCatchFrame*,su)->link;
752 barf("isBlackhole: weird record found on update frame list.");
758 Check the static objects list.
761 checkStaticObjects ( void ) {
762 extern StgClosure* static_objects;
763 StgClosure *p = static_objects;
766 while (p != END_OF_STATIC_LIST) {
769 switch (info->type) {
772 StgClosure *indirectee = stgCast(StgIndStatic*,p)->indirectee;
774 ASSERT(LOOKS_LIKE_PTR(indirectee));
775 ASSERT(LOOKS_LIKE_GHC_INFO(indirectee->header.info));
776 p = IND_STATIC_LINK((StgClosure *)p);
781 p = THUNK_STATIC_LINK((StgClosure *)p);
785 p = FUN_STATIC_LINK((StgClosure *)p);
789 p = STATIC_LINK(info,(StgClosure *)p);
793 barf("checkStaticObjetcs: strange closure %p (%s)",
800 Check the sanity of a blocking queue starting at bqe with closure being
801 the closure holding the blocking queue.
802 Note that in GUM we can have several different closure types in a
808 checkBQ (StgBlockingQueueElement *bqe, StgClosure *closure)
810 rtsBool end = rtsFalse;
811 StgInfoTable *info = get_itbl(closure);
813 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR
814 || info->type == FETCH_ME_BQ || info->type == RBH);
817 switch (get_itbl(bqe)->type) {
820 checkClosure((StgClosure *)bqe);
822 end = (bqe==END_BQ_QUEUE);
826 checkClosure((StgClosure *)bqe);
831 barf("checkBQ: strange closure %d in blocking queue for closure %p (%s)\n",
832 get_itbl(bqe)->type, closure, info_type(closure));
838 checkBQ (StgTSO *bqe, StgClosure *closure)
840 rtsBool end = rtsFalse;
841 StgInfoTable *info = get_itbl(closure);
843 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR);
846 switch (get_itbl(bqe)->type) {
849 checkClosure((StgClosure *)bqe);
851 end = (bqe==END_BQ_QUEUE);
855 barf("checkBQ: strange closure %d in blocking queue for closure %p (%s)\n",
856 get_itbl(bqe)->type, closure, info_type(closure));
862 checkBQ (StgTSO *bqe, StgClosure *closure)
864 rtsBool end = rtsFalse;
865 StgInfoTable *info = get_itbl(closure);
867 ASSERT(info->type == BLACKHOLE_BQ || info->type == MVAR);
870 switch (get_itbl(bqe)->type) {
872 checkClosure((StgClosure *)bqe);
874 end = (bqe==END_TSO_QUEUE);
878 barf("checkBQ: strange closure %d in blocking queue for closure %p\n",
879 get_itbl(bqe)->type, closure, info->type);
887 //@node GALA table sanity, Index, Blackhole Sanity
888 //@subsection GALA table sanity
891 This routine checks the sanity of the LAGA and GALA tables. They are
892 implemented as lists through one hash table, LAtoGALAtable, because entries
893 in both tables have the same structure:
894 - the LAGA table maps local addresses to global addresses; it starts
895 with liveIndirections
896 - the GALA table maps global addresses to local addresses; it starts
903 /* hidden in parallel/Global.c; only accessed for testing here */
904 extern GALA *liveIndirections;
905 extern GALA *liveRemoteGAs;
906 extern HashTable *LAtoGALAtable;
908 //@cindex checkLAGAtable
910 checkLAGAtable(rtsBool check_closures)
913 nat n=0, m=0; // debugging
915 for (gala = liveIndirections; gala != NULL; gala = gala->next) {
917 gala0 = lookupHashTable(LAtoGALAtable, (StgWord) gala->la);
918 ASSERT(!gala->preferred || gala == gala0);
919 ASSERT(LOOKS_LIKE_GHC_INFO(((StgClosure *)gala->la)->header.info));
920 ASSERT(gala->next!=gala); // detect direct loops
922 if ( check_closures ) {
923 checkClosure(stgCast(StgClosure*,gala->la));
928 for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
930 gala0 = lookupHashTable(LAtoGALAtable, (StgWord) gala->la);
931 ASSERT(!gala->preferred || gala == gala0);
932 ASSERT(LOOKS_LIKE_GHC_INFO(((StgClosure *)gala->la)->header.info));
933 ASSERT(gala->next!=gala); // detect direct loops
935 if ( check_closures ) {
936 checkClosure(stgCast(StgClosure*,gala->la));
943 //@node Index, , GALA table sanity
949 //* checkBQ:: @cindex\s-+checkBQ
950 //* checkChain:: @cindex\s-+checkChain
951 //* checkClosureShallow:: @cindex\s-+checkClosureShallow
952 //* checkHeap:: @cindex\s-+checkHeap
953 //* checkLargeBitmap:: @cindex\s-+checkLargeBitmap
954 //* checkSmallBitmap:: @cindex\s-+checkSmallBitmap
955 //* checkStack:: @cindex\s-+checkStack
956 //* checkStackChunk:: @cindex\s-+checkStackChunk
957 //* checkStackChunk:: @cindex\s-+checkStackChunk
958 //* checkStackClosure:: @cindex\s-+checkStackClosure
959 //* checkStackObject:: @cindex\s-+checkStackObject
960 //* checkTSO:: @cindex\s-+checkTSO
961 //* checkTSOsSanity:: @cindex\s-+checkTSOsSanity
962 //* checkThreadQSanity:: @cindex\s-+checkThreadQSanity
963 //* checkThreadQsSanity:: @cindex\s-+checkThreadQsSanity
964 //* isBlackhole:: @cindex\s-+isBlackhole