1 /* -----------------------------------------------------------------------------
2 * $Id: GCCompact.c,v 1.4 2001/07/25 11:55:57 simonmar Exp $
4 * (c) The GHC Team 2001
6 * Compacting garbage collector
8 * ---------------------------------------------------------------------------*/
14 #include "BlockAlloc.h"
16 #include "GCCompact.h"
18 #include "StablePriv.h"
20 /* -----------------------------------------------------------------------------
21 Threading / unthreading pointers.
23 The basic idea here is to chain together all the fields pointing at
24 a particular object, with the root of the chain in the object's
25 info table field. The original contents of the info pointer goes
26 at the end of the chain.
28 Adding a new field to the chain is a matter of swapping the
29 contents of the field with the contents of the object's info table
32 To unthread the chain, we walk down it updating all the fields on
33 the chain with the new location of the object. We stop when we
34 reach the info pointer at the end.
36 We use a trick to identify the info pointer, because the
37 LOOKS_LIKE_GHC_INFO() macro involves a function call and can be
38 expensive. The trick is that when swapping pointers for threading,
39 we set the low bit of the original pointer, with the result that
40 all the pointers in the chain have their low bits set except for
42 -------------------------------------------------------------------------- */
47 StgPtr q = (StgPtr)*p;
50 ASSERT(!LOOKS_LIKE_GHC_INFO(q));
51 if (HEAP_ALLOCED(q)) {
53 // a handy way to discover whether the ptr is into the
54 // compacted area of the old gen, is that the EVACUATED flag
55 // is zero (it's non-zero for all the other areas of live
57 if ((bd->flags & BF_EVACUATED) == 0) {
59 *q = (StgWord)p + 1; // set the low bit
65 unthread( StgPtr p, StgPtr free )
67 StgPtr q = (StgPtr)*p, r;
69 while (((StgWord)q & 1) != 0) {
70 (StgWord)q -= 1; // unset the low bit again
78 static inline StgInfoTable *
79 get_threaded_info( StgPtr p )
81 StgPtr q = (P_)GET_INFO((StgClosure *)p);
83 while (((StgWord)q & 1) != 0) {
84 q = (P_)*((StgPtr)((StgWord)q-1));
86 return INFO_PTR_TO_STRUCT((StgInfoTable *)q);
89 // A word-aligned memmove will be faster for small objects than libc's or gcc's.
90 // Remember, the two regions *might* overlap, but: to <= from.
92 move(StgPtr to, StgPtr from, nat size)
94 for(; size > 0; --size) {
100 obj_sizeW( StgClosure *p, StgInfoTable *info )
102 switch (info->type) {
107 return sizeofW(StgHeader) + 1;
119 return sizeofW(StgHeader) + 2; // MIN_UPD_SIZE
121 return THUNK_SELECTOR_sizeW();
124 return pap_sizeW((StgPAP *)p);
126 return arr_words_sizeW((StgArrWords *)p);
128 case MUT_ARR_PTRS_FROZEN:
129 return mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
131 return tso_sizeW((StgTSO *)p);
133 return sizeW_fromITBL(info);
138 thread_static( StgClosure* p )
140 const StgInfoTable *info;
142 // keep going until we've threaded all the objects on the linked
144 while (p != END_OF_STATIC_LIST) {
147 switch (info->type) {
150 thread((StgPtr)&((StgInd *)p)->indirectee);
151 p = IND_STATIC_LINK(p);
155 p = THUNK_STATIC_LINK(p);
158 p = FUN_STATIC_LINK(p);
161 p = STATIC_LINK(info,p);
165 barf("thread_static: strange closure %d", (int)(info->type));
172 thread_stack(StgPtr p, StgPtr stack_end)
175 const StgInfoTable* info;
178 // highly similar to scavenge_stack, but we do pointer threading here.
180 while (p < stack_end) {
183 // If we've got a tag, skip over that many words on the stack
184 if ( IS_ARG_TAG((W_)q) ) {
189 // Is q a pointer to a closure?
190 if ( !LOOKS_LIKE_GHC_INFO(q) ) {
196 // Otherwise, q must be the info pointer of an activation
197 // record. All activation records have 'bitmap' style layout
200 info = get_itbl((StgClosure *)p);
202 switch (info->type) {
204 // Dynamic bitmap: the mask is stored on the stack
206 bitmap = ((StgRetDyn *)p)->liveness;
207 p = (P_)&((StgRetDyn *)p)->payload[0];
210 // probably a slow-entry point return address:
216 // small bitmap (< 32 entries, or 64 on a 64-bit machine)
224 bitmap = info->layout.bitmap;
226 // this assumes that the payload starts immediately after the info-ptr
228 while (bitmap != 0) {
229 if ((bitmap & 1) == 0) {
233 bitmap = bitmap >> 1;
237 // large bitmap (> 32 entries)
242 StgLargeBitmap *large_bitmap;
245 large_bitmap = info->layout.large_bitmap;
248 for (i=0; i<large_bitmap->size; i++) {
249 bitmap = large_bitmap->bitmap[i];
250 q = p + sizeof(W_) * 8;
251 while (bitmap != 0) {
252 if ((bitmap & 1) == 0) {
256 bitmap = bitmap >> 1;
258 if (i+1 < large_bitmap->size) {
269 barf("thread_stack: weird activation record found on stack: %d",
276 update_fwd_large( bdescr *bd )
279 const StgInfoTable* info;
281 for (; bd != NULL; bd = bd->link) {
284 info = get_itbl((StgClosure *)p);
286 switch (info->type) {
293 case MUT_ARR_PTRS_FROZEN:
298 next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
299 for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
307 StgTSO *tso = (StgTSO *)p;
308 thread_stack(tso->sp, &(tso->stack[tso->stack_size]));
315 StgPAP* pap = (StgPAP *)p;
316 thread((StgPtr)&pap->fun);
317 thread_stack((P_)pap->payload, (P_)pap->payload + pap->n_args);
322 barf("update_fwd_large: unknown/strange object %d", (int)(info->type));
328 update_fwd( bdescr *blocks )
337 barf("update_fwd: ToDo");
340 // cycle through all the blocks in the step
341 for (; bd != NULL; bd = bd->link) {
344 // linearly scan the objects in this block
345 while (p < bd->free) {
347 info = get_itbl((StgClosure *)p);
349 ASSERT(p && (LOOKS_LIKE_GHC_INFO(info)
350 || IS_HUGS_CONSTR_INFO(info)));
352 switch (info->type) {
355 p += sizeofW(StgHeader) + 1;
360 thread((StgPtr)&((StgClosure *)p)->payload[0]);
361 p += sizeofW(StgHeader) + 1;
365 thread((StgPtr)&((StgClosure *)p)->payload[0]);
366 p += sizeofW(StgHeader) + 2; // MIN_UPD_SIZE
369 case THUNK_0_1: // MIN_UPD_SIZE
373 p += sizeofW(StgHeader) + 2;
379 thread((StgPtr)&((StgClosure *)p)->payload[0]);
380 p += sizeofW(StgHeader) + 2;
386 thread((StgPtr)&((StgClosure *)p)->payload[0]);
387 thread((StgPtr)&((StgClosure *)p)->payload[1]);
388 p += sizeofW(StgHeader) + 2;
401 case SE_CAF_BLACKHOLE:
408 end = (P_)((StgClosure *)p)->payload +
409 info->layout.payload.ptrs;
410 for (p = (P_)((StgClosure *)p)->payload; p < end; p++) {
413 p += info->layout.payload.nptrs;
417 // the info table for a weak ptr lies about the number of ptrs
418 // (because we have special GC routines for them, but we
419 // want to use the standard evacuate code). So we have to
420 // special case here.
423 StgWeak *w = (StgWeak *)p;
424 thread((StgPtr)&w->key);
425 thread((StgPtr)&w->value);
426 thread((StgPtr)&w->finalizer);
427 if (w->link != NULL) {
428 thread((StgPtr)&w->link);
430 p += sizeofW(StgWeak);
434 // again, the info table for MVar isn't suitable here (it includes
435 // the mut_link field as a pointer, and we don't want to
439 StgMVar *mvar = (StgMVar *)p;
440 thread((StgPtr)&mvar->head);
441 thread((StgPtr)&mvar->tail);
442 thread((StgPtr)&mvar->value);
443 p += sizeofW(StgMVar);
447 // specialise this case, because we want to update the
448 // mut_link field too.
450 case IND_OLDGEN_PERM:
452 StgIndOldGen *ind = (StgIndOldGen *)p;
453 thread((StgPtr)&ind->indirectee);
454 if (ind->mut_link != NULL) {
455 thread((StgPtr)&ind->mut_link);
462 StgSelector *s = (StgSelector *)p;
463 thread((StgPtr)&s->selectee);
464 p += THUNK_SELECTOR_sizeW();
468 case AP_UPD: // same as PAPs
471 StgPAP* pap = (StgPAP *)p;
473 thread((P_)&pap->fun);
474 thread_stack((P_)pap->payload, (P_)pap->payload + pap->n_args);
480 p += arr_words_sizeW((StgArrWords *)p);
484 case MUT_ARR_PTRS_FROZEN:
489 next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
490 for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
498 StgTSO *tso = (StgTSO *)p;
499 thread_stack(tso->sp, &(tso->stack[tso->stack_size]));
500 thread((StgPtr)&tso->link);
501 thread((StgPtr)&tso->global_link);
507 barf("update_fwd: unknown/strange object %d", (int)(info->type));
514 update_fwd_compact( bdescr *blocks )
518 bdescr *bd, *free_bd;
524 free = free_bd->start;
527 barf("update_fwd: ToDo");
530 // cycle through all the blocks in the step
531 for (; bd != NULL; bd = bd->link) {
534 while (p < bd->free ) {
536 while ( p < bd->free && !is_marked(p,bd) ) {
545 m = * ((StgPtr)bd->u.bitmap + ((p - bd->start) / (BITS_IN(StgWord))));
546 m >>= ((p - bd->start) & (BITS_IN(StgWord) - 1));
548 while ( p < bd->free ) {
553 if (((StgWord)p & (sizeof(W_) * BITS_IN(StgWord))) == 0) {
561 // Problem: we need to know the destination for this cell
562 // in order to unthread its info pointer. But we can't
563 // know the destination without the size, because we may
564 // spill into the next block. So we have to run down the
565 // threaded list and get the info ptr first.
566 info = get_threaded_info(p);
569 ASSERT(p && (LOOKS_LIKE_GHC_INFO(info)
570 || IS_HUGS_CONSTR_INFO(info)));
572 switch (info->type) {
575 p += sizeofW(StgHeader) + 1;
580 thread((StgPtr)&((StgClosure *)p)->payload[0]);
581 p += sizeofW(StgHeader) + 1;
585 thread((StgPtr)&((StgClosure *)p)->payload[0]);
586 p += sizeofW(StgHeader) + 2; // MIN_UPD_SIZE
589 case THUNK_0_1: // MIN_UPD_SIZE
593 p += sizeofW(StgHeader) + 2;
599 thread((StgPtr)&((StgClosure *)p)->payload[0]);
600 p += sizeofW(StgHeader) + 2;
606 thread((StgPtr)&((StgClosure *)p)->payload[0]);
607 thread((StgPtr)&((StgClosure *)p)->payload[1]);
608 p += sizeofW(StgHeader) + 2;
621 case SE_CAF_BLACKHOLE:
628 end = (P_)((StgClosure *)p)->payload +
629 info->layout.payload.ptrs;
630 for (p = (P_)((StgClosure *)p)->payload; p < end; p++) {
633 p += info->layout.payload.nptrs;
639 StgWeak *w = (StgWeak *)p;
640 thread((StgPtr)&w->key);
641 thread((StgPtr)&w->value);
642 thread((StgPtr)&w->finalizer);
643 if (w->link != NULL) {
644 thread((StgPtr)&w->link);
646 p += sizeofW(StgWeak);
652 StgMVar *mvar = (StgMVar *)p;
653 thread((StgPtr)&mvar->head);
654 thread((StgPtr)&mvar->tail);
655 thread((StgPtr)&mvar->value);
656 p += sizeofW(StgMVar);
661 case IND_OLDGEN_PERM:
662 // specialise this case, because we want to update the
663 // mut_link field too.
665 StgIndOldGen *ind = (StgIndOldGen *)p;
666 thread((StgPtr)&ind->indirectee);
667 if (ind->mut_link != NULL) {
668 thread((StgPtr)&ind->mut_link);
670 p += sizeofW(StgIndOldGen);
676 StgSelector *s = (StgSelector *)p;
677 thread((StgPtr)&s->selectee);
678 p += THUNK_SELECTOR_sizeW();
682 case AP_UPD: // same as PAPs
685 StgPAP* pap = (StgPAP *)p;
687 thread((P_)&pap->fun);
688 thread_stack((P_)pap->payload, (P_)pap->payload + pap->n_args);
694 p += arr_words_sizeW((StgArrWords *)p);
698 case MUT_ARR_PTRS_FROZEN:
703 next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
704 for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
712 StgTSO *tso = (StgTSO *)p;
713 thread_stack(tso->sp, &(tso->stack[tso->stack_size]));
714 thread((StgPtr)&tso->link);
715 thread((StgPtr)&tso->global_link);
721 barf("update_fwd: unknown/strange object %d", (int)(info->type));
725 if (free + size > free_bd->start + BLOCK_SIZE_W) {
726 free_bd = free_bd->link;
727 free = free_bd->start;
740 update_bkwd_compact( step *stp )
744 bdescr *bd, *free_bd;
746 nat size, free_blocks;
748 bd = free_bd = stp->blocks;
749 free = free_bd->start;
753 barf("update_bkwd: ToDo");
756 // cycle through all the blocks in the step
757 for (; bd != NULL; bd = bd->link) {
760 while (p < bd->free ) {
762 while ( p < bd->free && !is_marked(p,bd) ) {
771 m = * ((StgPtr)bd->u.bitmap + ((p - bd->start) / (BITS_IN(StgWord))));
772 m >>= ((p - bd->start) & (BITS_IN(StgWord) - 1));
774 while ( p < bd->free ) {
779 if (((StgWord)p & (sizeof(W_) * BITS_IN(StgWord))) == 0) {
787 // must unthread before we look at the info ptr...
788 info = get_threaded_info(p);
790 ASSERT(p && (LOOKS_LIKE_GHC_INFO(info)
791 || IS_HUGS_CONSTR_INFO(info)));
793 size = obj_sizeW((StgClosure *)p,info);
795 if (free + size > free_bd->start + BLOCK_SIZE_W) {
796 // don't forget to update the free ptr in the block desc.
797 free_bd->free = free;
798 free_bd = free_bd->link;
799 free = free_bd->start;
808 // Rebuild the mutable list for the old generation.
809 // (the mut_once list is updated using threading, with
810 // special cases for IND_OLDGEN and MUT_CONS above).
811 if (ip_MUTABLE(info)) {
812 recordMutable((StgMutClosure *)free);
816 if (info->type == TSO) {
817 move_TSO((StgTSO *)p, (StgTSO *)free);
828 // free the remaining blocks and count what's left.
829 free_bd->free = free;
830 if (free_bd->link != NULL) {
831 freeChain(free_bd->link);
832 free_bd->link = NULL;
834 stp->n_blocks = free_blocks;
840 compact( void (*get_roots)(evac_fn) )
844 extern StgWeak *old_weak_ptr_list; // tmp
846 // 1. thread the roots
847 get_roots((evac_fn)thread);
849 // the weak pointer lists...
850 if (weak_ptr_list != NULL) {
851 thread((StgPtr)&weak_ptr_list);
853 if (old_weak_ptr_list != NULL) {
854 thread((StgPtr)&old_weak_ptr_list); // tmp
858 for (g = 1; g < RtsFlags.GcFlags.generations; g++) {
859 thread((StgPtr)&generations[g].mut_list);
860 thread((StgPtr)&generations[g].mut_once_list);
863 // the global thread list
864 thread((StgPtr)&all_threads);
866 // the static objects
867 thread_static(scavenged_static_objects);
869 // the stable pointer table
870 threadStablePtrTable((evac_fn)thread);
872 // 2. update forward ptrs
873 for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
874 for (s = 0; s < generations[g].n_steps; s++) {
875 stp = &generations[g].steps[s];
876 IF_DEBUG(gc, fprintf(stderr,"update_fwd: %d.%d\n", stp->gen->no, stp->no););
878 update_fwd(stp->to_blocks);
879 update_fwd_large(stp->scavenged_large_objects);
880 if (g == RtsFlags.GcFlags.generations-1 && stp->blocks != NULL) {
881 IF_DEBUG(gc, fprintf(stderr,"update_fwd: %d.%d (compact)\n", stp->gen->no, stp->no););
882 update_fwd_compact(stp->blocks);
887 // 3. update backward ptrs
888 stp = &oldest_gen->steps[0];
889 if (stp->blocks != NULL) {
890 blocks = update_bkwd_compact(stp);
891 IF_DEBUG(gc, fprintf(stderr,"update_bkwd: %d.%d (compact, old: %d blocks, now %d blocks)\n",
892 stp->gen->no, stp->no,
893 stp->n_blocks, blocks););
894 stp->n_blocks = blocks;