02d81ed7cee8cd354b0fa76723ae31fb50f96fd2
[ghc-hetmet.git] / rts / Sanity.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2006
4  *
5  * Sanity checking code for the heap and stack.
6  *
7  * Used when debugging: check that everything reasonable.
8  *
9  *    - All things that are supposed to be pointers look like pointers.
10  *
11  *    - Objects in text space are marked as static closures, those
12  *      in the heap are dynamic.
13  *
14  * ---------------------------------------------------------------------------*/
15
16 #include "PosixSource.h"
17 #include "Rts.h"
18
19 #ifdef DEBUG                                                   /* whole file */
20
21 #include "RtsFlags.h"
22 #include "RtsUtils.h"
23 #include "BlockAlloc.h"
24 #include "Sanity.h"
25 #include "MBlock.h"
26 #include "Storage.h"
27 #include "Schedule.h"
28 #include "Apply.h"
29
30 /* -----------------------------------------------------------------------------
31    Forward decls.
32    -------------------------------------------------------------------------- */
33
34 static void      checkSmallBitmap    ( StgPtr payload, StgWord bitmap, nat );
35 static void      checkLargeBitmap    ( StgPtr payload, StgLargeBitmap*, nat );
36 static void      checkClosureShallow ( StgClosure * );
37
38 /* -----------------------------------------------------------------------------
39    Check stack sanity
40    -------------------------------------------------------------------------- */
41
42 static void
43 checkSmallBitmap( StgPtr payload, StgWord bitmap, nat size )
44 {
45     StgPtr p;
46     nat i;
47
48     p = payload;
49     for(i = 0; i < size; i++, bitmap >>= 1 ) {
50         if ((bitmap & 1) == 0) {
51             checkClosureShallow((StgClosure *)payload[i]);
52         }
53     }
54 }
55
56 static void
57 checkLargeBitmap( StgPtr payload, StgLargeBitmap* large_bitmap, nat size )
58 {
59     StgWord bmp;
60     nat i, j;
61
62     i = 0;
63     for (bmp=0; i < size; bmp++) {
64         StgWord bitmap = large_bitmap->bitmap[bmp];
65         j = 0;
66         for(; i < size && j < BITS_IN(W_); j++, i++, bitmap >>= 1 ) {
67             if ((bitmap & 1) == 0) {
68                 checkClosureShallow((StgClosure *)payload[i]);
69             }
70         }
71     }
72 }
73
74 /*
75  * check that it looks like a valid closure - without checking its payload
76  * used to avoid recursion between checking PAPs and checking stack
77  * chunks.
78  */
79  
80 static void 
81 checkClosureShallow( StgClosure* p )
82 {
83     StgClosure *q;
84
85     q = UNTAG_CLOSURE(p);
86     ASSERT(LOOKS_LIKE_CLOSURE_PTR(q));
87
88     /* Is it a static closure? */
89     if (!HEAP_ALLOCED(q)) {
90         ASSERT(closure_STATIC(q));
91     } else {
92         ASSERT(!closure_STATIC(q));
93     }
94 }
95
96 // check an individual stack object
97 StgOffset 
98 checkStackFrame( StgPtr c )
99 {
100     nat size;
101     const StgRetInfoTable* info;
102
103     info = get_ret_itbl((StgClosure *)c);
104
105     /* All activation records have 'bitmap' style layout info. */
106     switch (info->i.type) {
107     case RET_DYN: /* Dynamic bitmap: the mask is stored on the stack */
108     {
109         StgWord dyn;
110         StgPtr p;
111         StgRetDyn* r;
112         
113         r = (StgRetDyn *)c;
114         dyn = r->liveness;
115         
116         p = (P_)(r->payload);
117         checkSmallBitmap(p,RET_DYN_LIVENESS(r->liveness),RET_DYN_BITMAP_SIZE);
118         p += RET_DYN_BITMAP_SIZE + RET_DYN_NONPTR_REGS_SIZE;
119
120         // skip over the non-pointers
121         p += RET_DYN_NONPTRS(dyn);
122         
123         // follow the ptr words
124         for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
125             checkClosureShallow((StgClosure *)*p);
126             p++;
127         }
128         
129         return sizeofW(StgRetDyn) + RET_DYN_BITMAP_SIZE +
130             RET_DYN_NONPTR_REGS_SIZE +
131             RET_DYN_NONPTRS(dyn) + RET_DYN_PTRS(dyn);
132     }
133
134     case UPDATE_FRAME:
135       ASSERT(LOOKS_LIKE_CLOSURE_PTR(((StgUpdateFrame*)c)->updatee));
136     case ATOMICALLY_FRAME:
137     case CATCH_RETRY_FRAME:
138     case CATCH_STM_FRAME:
139     case CATCH_FRAME:
140       // small bitmap cases (<= 32 entries)
141     case STOP_FRAME:
142     case RET_SMALL:
143         size = BITMAP_SIZE(info->i.layout.bitmap);
144         checkSmallBitmap((StgPtr)c + 1, 
145                          BITMAP_BITS(info->i.layout.bitmap), size);
146         return 1 + size;
147
148     case RET_BCO: {
149         StgBCO *bco;
150         nat size;
151         bco = (StgBCO *)*(c+1);
152         size = BCO_BITMAP_SIZE(bco);
153         checkLargeBitmap((StgPtr)c + 2, BCO_BITMAP(bco), size);
154         return 2 + size;
155     }
156
157     case RET_BIG: // large bitmap (> 32 entries)
158         size = GET_LARGE_BITMAP(&info->i)->size;
159         checkLargeBitmap((StgPtr)c + 1, GET_LARGE_BITMAP(&info->i), size);
160         return 1 + size;
161
162     case RET_FUN:
163     {
164         StgFunInfoTable *fun_info;
165         StgRetFun *ret_fun;
166
167         ret_fun = (StgRetFun *)c;
168         fun_info = get_fun_itbl(UNTAG_CLOSURE(ret_fun->fun));
169         size = ret_fun->size;
170         switch (fun_info->f.fun_type) {
171         case ARG_GEN:
172             checkSmallBitmap((StgPtr)ret_fun->payload, 
173                              BITMAP_BITS(fun_info->f.b.bitmap), size);
174             break;
175         case ARG_GEN_BIG:
176             checkLargeBitmap((StgPtr)ret_fun->payload,
177                              GET_FUN_LARGE_BITMAP(fun_info), size);
178             break;
179         default:
180             checkSmallBitmap((StgPtr)ret_fun->payload,
181                              BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]),
182                              size);
183             break;
184         }
185         return sizeofW(StgRetFun) + size;
186     }
187
188     default:
189         barf("checkStackFrame: weird activation record found on stack (%p %d).",c,info->i.type);
190     }
191 }
192
193 // check sections of stack between update frames
194 void 
195 checkStackChunk( StgPtr sp, StgPtr stack_end )
196 {
197     StgPtr p;
198
199     p = sp;
200     while (p < stack_end) {
201         p += checkStackFrame( p );
202     }
203     // ASSERT( p == stack_end ); -- HWL
204 }
205
206 static void
207 checkPAP (StgClosure *tagged_fun, StgClosure** payload, StgWord n_args)
208
209     StgClosure *fun;
210     StgClosure *p;
211     StgFunInfoTable *fun_info;
212     
213     fun = UNTAG_CLOSURE(tagged_fun);
214     ASSERT(LOOKS_LIKE_CLOSURE_PTR(fun));
215     fun_info = get_fun_itbl(fun);
216     
217     p = (StgClosure *)payload;
218     switch (fun_info->f.fun_type) {
219     case ARG_GEN:
220         checkSmallBitmap( (StgPtr)payload, 
221                           BITMAP_BITS(fun_info->f.b.bitmap), n_args );
222         break;
223     case ARG_GEN_BIG:
224         checkLargeBitmap( (StgPtr)payload, 
225                           GET_FUN_LARGE_BITMAP(fun_info), 
226                           n_args );
227         break;
228     case ARG_BCO:
229         checkLargeBitmap( (StgPtr)payload, 
230                           BCO_BITMAP(fun), 
231                           n_args );
232         break;
233     default:
234         checkSmallBitmap( (StgPtr)payload, 
235                           BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]),
236                           n_args );
237         break;
238     }
239
240     ASSERT(fun_info->f.arity > TAG_MASK ? GET_CLOSURE_TAG(tagged_fun) == 1
241            : GET_CLOSURE_TAG(tagged_fun) == fun_info->f.arity);
242 }
243
244
245 StgOffset 
246 checkClosure( StgClosure* p )
247 {
248     const StgInfoTable *info;
249
250     ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
251
252     p = UNTAG_CLOSURE(p);
253     /* Is it a static closure (i.e. in the data segment)? */
254     if (!HEAP_ALLOCED(p)) {
255         ASSERT(closure_STATIC(p));
256     } else {
257         ASSERT(!closure_STATIC(p));
258     }
259
260     info = p->header.info;
261
262     if (IS_FORWARDING_PTR(info)) {
263         barf("checkClosure: found EVACUATED closure %d", info->type);
264     }
265     info = INFO_PTR_TO_STRUCT(info);
266
267     switch (info->type) {
268
269     case MVAR_CLEAN:
270     case MVAR_DIRTY:
271       { 
272         StgMVar *mvar = (StgMVar *)p;
273         ASSERT(LOOKS_LIKE_CLOSURE_PTR(mvar->head));
274         ASSERT(LOOKS_LIKE_CLOSURE_PTR(mvar->tail));
275         ASSERT(LOOKS_LIKE_CLOSURE_PTR(mvar->value));
276         return sizeofW(StgMVar);
277       }
278
279     case THUNK:
280     case THUNK_1_0:
281     case THUNK_0_1:
282     case THUNK_1_1:
283     case THUNK_0_2:
284     case THUNK_2_0:
285       {
286         nat i;
287         for (i = 0; i < info->layout.payload.ptrs; i++) {
288           ASSERT(LOOKS_LIKE_CLOSURE_PTR(((StgThunk *)p)->payload[i]));
289         }
290         return thunk_sizeW_fromITBL(info);
291       }
292
293     case FUN:
294     case FUN_1_0:
295     case FUN_0_1:
296     case FUN_1_1:
297     case FUN_0_2:
298     case FUN_2_0:
299     case CONSTR:
300     case CONSTR_1_0:
301     case CONSTR_0_1:
302     case CONSTR_1_1:
303     case CONSTR_0_2:
304     case CONSTR_2_0:
305     case IND_PERM:
306     case IND_OLDGEN:
307     case IND_OLDGEN_PERM:
308     case BLACKHOLE:
309     case CAF_BLACKHOLE:
310     case STABLE_NAME:
311     case MUT_VAR_CLEAN:
312     case MUT_VAR_DIRTY:
313     case CONSTR_STATIC:
314     case CONSTR_NOCAF_STATIC:
315     case THUNK_STATIC:
316     case FUN_STATIC:
317         {
318             nat i;
319             for (i = 0; i < info->layout.payload.ptrs; i++) {
320                 ASSERT(LOOKS_LIKE_CLOSURE_PTR(p->payload[i]));
321             }
322             return sizeW_fromITBL(info);
323         }
324
325     case BCO: {
326         StgBCO *bco = (StgBCO *)p;
327         ASSERT(LOOKS_LIKE_CLOSURE_PTR(bco->instrs));
328         ASSERT(LOOKS_LIKE_CLOSURE_PTR(bco->literals));
329         ASSERT(LOOKS_LIKE_CLOSURE_PTR(bco->ptrs));
330         return bco_sizeW(bco);
331     }
332
333     case IND_STATIC: /* (1, 0) closure */
334       ASSERT(LOOKS_LIKE_CLOSURE_PTR(((StgIndStatic*)p)->indirectee));
335       return sizeW_fromITBL(info);
336
337     case WEAK:
338       /* deal with these specially - the info table isn't
339        * representative of the actual layout.
340        */
341       { StgWeak *w = (StgWeak *)p;
342         ASSERT(LOOKS_LIKE_CLOSURE_PTR(w->key));
343         ASSERT(LOOKS_LIKE_CLOSURE_PTR(w->value));
344         ASSERT(LOOKS_LIKE_CLOSURE_PTR(w->finalizer));
345         if (w->link) {
346           ASSERT(LOOKS_LIKE_CLOSURE_PTR(w->link));
347         }
348         return sizeW_fromITBL(info);
349       }
350
351     case THUNK_SELECTOR:
352             ASSERT(LOOKS_LIKE_CLOSURE_PTR(((StgSelector *)p)->selectee));
353             return THUNK_SELECTOR_sizeW();
354
355     case IND:
356         { 
357             /* we don't expect to see any of these after GC
358              * but they might appear during execution
359              */
360             StgInd *ind = (StgInd *)p;
361             ASSERT(LOOKS_LIKE_CLOSURE_PTR(ind->indirectee));
362             return sizeofW(StgInd);
363         }
364
365     case RET_BCO:
366     case RET_SMALL:
367     case RET_BIG:
368     case RET_DYN:
369     case UPDATE_FRAME:
370     case STOP_FRAME:
371     case CATCH_FRAME:
372     case ATOMICALLY_FRAME:
373     case CATCH_RETRY_FRAME:
374     case CATCH_STM_FRAME:
375             barf("checkClosure: stack frame");
376
377     case AP:
378     {
379         StgAP* ap = (StgAP *)p;
380         checkPAP (ap->fun, ap->payload, ap->n_args);
381         return ap_sizeW(ap);
382     }
383
384     case PAP:
385     {
386         StgPAP* pap = (StgPAP *)p;
387         checkPAP (pap->fun, pap->payload, pap->n_args);
388         return pap_sizeW(pap);
389     }
390
391     case AP_STACK:
392     { 
393         StgAP_STACK *ap = (StgAP_STACK *)p;
394         ASSERT(LOOKS_LIKE_CLOSURE_PTR(ap->fun));
395         checkStackChunk((StgPtr)ap->payload, (StgPtr)ap->payload + ap->size);
396         return ap_stack_sizeW(ap);
397     }
398
399     case ARR_WORDS:
400             return arr_words_sizeW((StgArrWords *)p);
401
402     case MUT_ARR_PTRS_CLEAN:
403     case MUT_ARR_PTRS_DIRTY:
404     case MUT_ARR_PTRS_FROZEN:
405     case MUT_ARR_PTRS_FROZEN0:
406         {
407             StgMutArrPtrs* a = (StgMutArrPtrs *)p;
408             nat i;
409             for (i = 0; i < a->ptrs; i++) {
410                 ASSERT(LOOKS_LIKE_CLOSURE_PTR(a->payload[i]));
411             }
412             return mut_arr_ptrs_sizeW(a);
413         }
414
415     case TSO:
416         checkTSO((StgTSO *)p);
417         return tso_sizeW((StgTSO *)p);
418
419     case TVAR_WATCH_QUEUE:
420       {
421         StgTVarWatchQueue *wq = (StgTVarWatchQueue *)p;
422         ASSERT(LOOKS_LIKE_CLOSURE_PTR(wq->next_queue_entry));
423         ASSERT(LOOKS_LIKE_CLOSURE_PTR(wq->prev_queue_entry));
424         return sizeofW(StgTVarWatchQueue);
425       }
426
427     case INVARIANT_CHECK_QUEUE:
428       {
429         StgInvariantCheckQueue *q = (StgInvariantCheckQueue *)p;
430         ASSERT(LOOKS_LIKE_CLOSURE_PTR(q->invariant));
431         ASSERT(LOOKS_LIKE_CLOSURE_PTR(q->my_execution));
432         ASSERT(LOOKS_LIKE_CLOSURE_PTR(q->next_queue_entry));
433         return sizeofW(StgInvariantCheckQueue);
434       }
435
436     case ATOMIC_INVARIANT:
437       {
438         StgAtomicInvariant *invariant = (StgAtomicInvariant *)p;
439         ASSERT(LOOKS_LIKE_CLOSURE_PTR(invariant->code));
440         ASSERT(LOOKS_LIKE_CLOSURE_PTR(invariant->last_execution));
441         return sizeofW(StgAtomicInvariant);
442       }
443
444     case TVAR:
445       {
446         StgTVar *tv = (StgTVar *)p;
447         ASSERT(LOOKS_LIKE_CLOSURE_PTR(tv->current_value));
448         ASSERT(LOOKS_LIKE_CLOSURE_PTR(tv->first_watch_queue_entry));
449         return sizeofW(StgTVar);
450       }
451
452     case TREC_CHUNK:
453       {
454         nat i;
455         StgTRecChunk *tc = (StgTRecChunk *)p;
456         ASSERT(LOOKS_LIKE_CLOSURE_PTR(tc->prev_chunk));
457         for (i = 0; i < tc -> next_entry_idx; i ++) {
458           ASSERT(LOOKS_LIKE_CLOSURE_PTR(tc->entries[i].tvar));
459           ASSERT(LOOKS_LIKE_CLOSURE_PTR(tc->entries[i].expected_value));
460           ASSERT(LOOKS_LIKE_CLOSURE_PTR(tc->entries[i].new_value));
461         }
462         return sizeofW(StgTRecChunk);
463       }
464
465     case TREC_HEADER:
466       {
467         StgTRecHeader *trec = (StgTRecHeader *)p;
468         ASSERT(LOOKS_LIKE_CLOSURE_PTR(trec -> enclosing_trec));
469         ASSERT(LOOKS_LIKE_CLOSURE_PTR(trec -> current_chunk));
470         return sizeofW(StgTRecHeader);
471       }
472       
473     default:
474             barf("checkClosure (closure type %d)", info->type);
475     }
476 }
477
478
479 /* -----------------------------------------------------------------------------
480    Check Heap Sanity
481
482    After garbage collection, the live heap is in a state where we can
483    run through and check that all the pointers point to the right
484    place.  This function starts at a given position and sanity-checks
485    all the objects in the remainder of the chain.
486    -------------------------------------------------------------------------- */
487
488 void 
489 checkHeap(bdescr *bd)
490 {
491     StgPtr p;
492
493 #if defined(THREADED_RTS)
494     // heap sanity checking doesn't work with SMP, because we can't
495     // zero the slop (see Updates.h).
496     return;
497 #endif
498
499     for (; bd != NULL; bd = bd->link) {
500         p = bd->start;
501         while (p < bd->free) {
502             nat size = checkClosure((StgClosure *)p);
503             /* This is the smallest size of closure that can live in the heap */
504             ASSERT( size >= MIN_PAYLOAD_SIZE + sizeofW(StgHeader) );
505             p += size;
506             
507             /* skip over slop */
508             while (p < bd->free &&
509                    (*p < 0x1000 || !LOOKS_LIKE_INFO_PTR(*p))) { p++; } 
510         }
511     }
512 }
513
514 void 
515 checkHeapChunk(StgPtr start, StgPtr end)
516 {
517   StgPtr p;
518   nat size;
519
520   for (p=start; p<end; p+=size) {
521     ASSERT(LOOKS_LIKE_INFO_PTR(*p));
522     size = checkClosure((StgClosure *)p);
523     /* This is the smallest size of closure that can live in the heap. */
524     ASSERT( size >= MIN_PAYLOAD_SIZE + sizeofW(StgHeader) );
525   }
526 }
527
528 void
529 checkLargeObjects(bdescr *bd)
530 {
531   while (bd != NULL) {
532     if (!(bd->flags & BF_PINNED)) {
533       checkClosure((StgClosure *)bd->start);
534     }
535     bd = bd->link;
536   }
537 }
538
539 void
540 checkTSO(StgTSO *tso)
541 {
542     StgPtr sp = tso->sp;
543     StgPtr stack = tso->stack;
544     StgOffset stack_size = tso->stack_size;
545     StgPtr stack_end = stack + stack_size;
546
547     if (tso->what_next == ThreadRelocated) {
548       checkTSO(tso->_link);
549       return;
550     }
551
552     if (tso->what_next == ThreadKilled) {
553       /* The garbage collector doesn't bother following any pointers
554        * from dead threads, so don't check sanity here.  
555        */
556       return;
557     }
558
559     ASSERT(stack <= sp && sp < stack_end);
560
561     checkStackChunk(sp, stack_end);
562 }
563
564 /* 
565    Check that all TSOs have been evacuated.
566    Optionally also check the sanity of the TSOs.
567 */
568 void
569 checkGlobalTSOList (rtsBool checkTSOs)
570 {
571   StgTSO *tso;
572   nat s;
573
574   for (s = 0; s < total_steps; s++) {
575       for (tso=all_steps[s].threads; tso != END_TSO_QUEUE; 
576            tso = tso->global_link) {
577           ASSERT(LOOKS_LIKE_CLOSURE_PTR(tso));
578           ASSERT(get_itbl(tso)->type == TSO);
579           if (checkTSOs)
580               checkTSO(tso);
581
582           // If this TSO is dirty and in an old generation, it better
583           // be on the mutable list.
584           if (tso->what_next == ThreadRelocated) continue;
585           if (tso->flags & (TSO_DIRTY|TSO_LINK_DIRTY)) {
586               ASSERT(Bdescr((P_)tso)->gen_no == 0 || (tso->flags & TSO_MARKED));
587               tso->flags &= ~TSO_MARKED;
588           }
589       }
590   }
591 }
592
593 /* -----------------------------------------------------------------------------
594    Check mutable list sanity.
595    -------------------------------------------------------------------------- */
596
597 void
598 checkMutableList( bdescr *mut_bd, nat gen )
599 {
600     bdescr *bd;
601     StgPtr q;
602     StgClosure *p;
603
604     for (bd = mut_bd; bd != NULL; bd = bd->link) {
605         for (q = bd->start; q < bd->free; q++) {
606             p = (StgClosure *)*q;
607             ASSERT(!HEAP_ALLOCED(p) || Bdescr((P_)p)->gen_no == gen);
608             if (get_itbl(p)->type == TSO) {
609                 ((StgTSO *)p)->flags |= TSO_MARKED;
610             }
611         }
612     }
613 }
614
615 void
616 checkMutableLists (rtsBool checkTSOs)
617 {
618     nat g, i;
619
620     for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
621         checkMutableList(generations[g].mut_list, g);
622         for (i = 0; i < n_capabilities; i++) {
623             checkMutableList(capabilities[i].mut_lists[g], g);
624         }
625     }
626     checkGlobalTSOList(checkTSOs);
627 }
628
629 /*
630   Check the static objects list.
631 */
632 void
633 checkStaticObjects ( StgClosure* static_objects )
634 {
635   StgClosure *p = static_objects;
636   StgInfoTable *info;
637
638   while (p != END_OF_STATIC_LIST) {
639     checkClosure(p);
640     info = get_itbl(p);
641     switch (info->type) {
642     case IND_STATIC:
643       { 
644         StgClosure *indirectee = UNTAG_CLOSURE(((StgIndStatic *)p)->indirectee);
645
646         ASSERT(LOOKS_LIKE_CLOSURE_PTR(indirectee));
647         ASSERT(LOOKS_LIKE_INFO_PTR((StgWord)indirectee->header.info));
648         p = *IND_STATIC_LINK((StgClosure *)p);
649         break;
650       }
651
652     case THUNK_STATIC:
653       p = *THUNK_STATIC_LINK((StgClosure *)p);
654       break;
655
656     case FUN_STATIC:
657       p = *FUN_STATIC_LINK((StgClosure *)p);
658       break;
659
660     case CONSTR_STATIC:
661       p = *STATIC_LINK(info,(StgClosure *)p);
662       break;
663
664     default:
665       barf("checkStaticObjetcs: strange closure %p (%s)", 
666            p, info_type(p));
667     }
668   }
669 }
670
671 #endif /* DEBUG */