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