1 /* -----------------------------------------------------------------------------
2 * $Id: GCCompact.c,v 1.2 2001/07/24 14:29:13 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;
48 ASSERT(!LOOKS_LIKE_GHC_INFO(q));
49 if (HEAP_ALLOCED(q)) {
50 if (Bdescr(q)->gen_no > 0) {
52 *q = (StgWord)p + 1; // set the low bit
58 unthread( StgPtr p, StgPtr free )
60 StgPtr q = (StgPtr)*p, r;
62 while (((StgWord)q & 1) != 0) {
63 (StgWord)q -= 1; // unset the low bit again
71 static inline StgInfoTable *
72 get_threaded_info( StgPtr p )
74 StgPtr q = (P_)GET_INFO((StgClosure *)p);
76 while (((StgWord)q & 1) != 0) {
77 q = (P_)*((StgPtr)((StgWord)q-1));
79 return INFO_PTR_TO_STRUCT((StgInfoTable *)q);
82 // A word-aligned memmove will be faster for small objects than libc's or gcc's.
83 // Remember, the two regions *might* overlap, but: to <= from.
85 move(StgPtr to, StgPtr from, nat size)
87 for(; size > 0; --size) {
93 obj_sizeW( StgClosure *p, StgInfoTable *info )
100 return sizeofW(StgHeader) + 1;
112 return sizeofW(StgHeader) + 2; // MIN_UPD_SIZE
114 return THUNK_SELECTOR_sizeW();
117 return pap_sizeW((StgPAP *)p);
119 return arr_words_sizeW((StgArrWords *)p);
121 case MUT_ARR_PTRS_FROZEN:
122 return mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
124 return tso_sizeW((StgTSO *)p);
126 return sizeW_fromITBL(info);
131 thread_static( StgClosure* p )
133 const StgInfoTable *info;
135 // keep going until we've threaded all the objects on the linked
137 while (p != END_OF_STATIC_LIST) {
140 switch (info->type) {
143 thread((StgPtr)&((StgInd *)p)->indirectee);
152 barf("thread_static: strange closure %d", (int)(info->type));
155 p = STATIC_LINK(info,p);
160 thread_stack(StgPtr p, StgPtr stack_end)
163 const StgInfoTable* info;
166 // highly similar to scavenge_stack, but we do pointer threading here.
168 while (p < stack_end) {
171 // If we've got a tag, skip over that many words on the stack
172 if ( IS_ARG_TAG((W_)q) ) {
177 // Is q a pointer to a closure?
178 if ( !LOOKS_LIKE_GHC_INFO(q) ) {
184 // Otherwise, q must be the info pointer of an activation
185 // record. All activation records have 'bitmap' style layout
188 info = get_itbl((StgClosure *)p);
190 switch (info->type) {
192 // Dynamic bitmap: the mask is stored on the stack
194 bitmap = ((StgRetDyn *)p)->liveness;
195 p = (P_)&((StgRetDyn *)p)->payload[0];
198 // probably a slow-entry point return address:
204 // small bitmap (< 32 entries, or 64 on a 64-bit machine)
212 bitmap = info->layout.bitmap;
214 // this assumes that the payload starts immediately after the info-ptr
216 while (bitmap != 0) {
217 if ((bitmap & 1) == 0) {
221 bitmap = bitmap >> 1;
225 // large bitmap (> 32 entries)
230 StgLargeBitmap *large_bitmap;
233 large_bitmap = info->layout.large_bitmap;
236 for (i=0; i<large_bitmap->size; i++) {
237 bitmap = large_bitmap->bitmap[i];
238 q = p + sizeof(W_) * 8;
239 while (bitmap != 0) {
240 if ((bitmap & 1) == 0) {
244 bitmap = bitmap >> 1;
246 if (i+1 < large_bitmap->size) {
257 barf("thread_stack: weird activation record found on stack: %d",
264 update_fwd_large( bdescr *bd )
267 const StgInfoTable* info;
269 for (; bd != NULL; bd = bd->link) {
273 info = get_itbl((StgClosure *)p);
275 switch (info->type) {
282 case MUT_ARR_PTRS_FROZEN:
287 next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
288 for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
296 StgTSO *tso = (StgTSO *)p;
297 thread_stack(tso->sp, &(tso->stack[tso->stack_size]));
304 StgPAP* pap = (StgPAP *)p;
305 thread((StgPtr)&pap->fun);
306 thread_stack((P_)pap->payload, (P_)pap->payload + pap->n_args);
311 barf("update_fwd_large: unknown/strange object %d", (int)(info->type));
317 update_fwd( bdescr *blocks )
326 barf("update_fwd: ToDo");
329 // cycle through all the blocks in the step
330 for (; bd != NULL; bd = bd->link) {
333 // linearly scan the objects in this block
334 while (p < bd->free) {
336 /* unthread the info ptr */
338 info = get_itbl((StgClosure *)p);
340 ASSERT(p && (LOOKS_LIKE_GHC_INFO(info)
341 || IS_HUGS_CONSTR_INFO(info)));
343 switch (info->type) {
346 p += sizeofW(StgHeader) + 1;
351 thread((StgPtr)&((StgClosure *)p)->payload[0]);
352 p += sizeofW(StgHeader) + 1;
356 thread((StgPtr)&((StgClosure *)p)->payload[0]);
357 p += sizeofW(StgHeader) + 2; // MIN_UPD_SIZE
360 case THUNK_0_1: // MIN_UPD_SIZE
364 p += sizeofW(StgHeader) + 2;
370 thread((StgPtr)&((StgClosure *)p)->payload[0]);
371 p += sizeofW(StgHeader) + 2;
377 thread((StgPtr)&((StgClosure *)p)->payload[0]);
378 thread((StgPtr)&((StgClosure *)p)->payload[1]);
379 p += sizeofW(StgHeader) + 2;
392 case SE_CAF_BLACKHOLE:
399 end = (P_)((StgClosure *)p)->payload +
400 info->layout.payload.ptrs;
401 for (p = (P_)((StgClosure *)p)->payload; p < end; p++) {
404 p += info->layout.payload.nptrs;
408 // the info table for a weak ptr lies about the number of ptrs
409 // (because we have special GC routines for them, but we
410 // want to use the standard evacuate code). So we have to
411 // special case here.
414 StgWeak *w = (StgWeak *)p;
415 thread((StgPtr)&w->key);
416 thread((StgPtr)&w->value);
417 thread((StgPtr)&w->finalizer);
418 if (w->link != NULL) {
419 thread((StgPtr)&w->link);
421 p += sizeofW(StgWeak);
425 // again, the info table for MVar isn't suitable here (it includes
426 // the mut_link field as a pointer, and we don't want to
430 StgMVar *mvar = (StgMVar *)p;
431 thread((StgPtr)&mvar->head);
432 thread((StgPtr)&mvar->tail);
433 thread((StgPtr)&mvar->value);
434 p += sizeofW(StgMVar);
438 // specialise this case, because we want to update the
439 // mut_link field too.
441 case IND_OLDGEN_PERM:
443 StgIndOldGen *ind = (StgIndOldGen *)p;
444 thread((StgPtr)&ind->indirectee);
445 if (ind->mut_link != NULL) {
446 thread((StgPtr)&ind->mut_link);
453 StgSelector *s = (StgSelector *)p;
454 thread((StgPtr)&s->selectee);
455 p += THUNK_SELECTOR_sizeW();
459 case AP_UPD: // same as PAPs
462 StgPAP* pap = (StgPAP *)p;
464 thread((P_)&pap->fun);
465 thread_stack((P_)pap->payload, (P_)pap->payload + pap->n_args);
471 p += arr_words_sizeW((StgArrWords *)p);
475 case MUT_ARR_PTRS_FROZEN:
480 next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
481 for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
489 StgTSO *tso = (StgTSO *)p;
490 thread_stack(tso->sp, &(tso->stack[tso->stack_size]));
491 thread((StgPtr)&tso->link);
492 thread((StgPtr)&tso->global_link);
498 barf("update_fwd: unknown/strange object %d", (int)(info->type));
505 update_fwd_compact( bdescr *blocks )
509 bdescr *bd, *free_bd;
515 free = free_bd->start;
518 barf("update_fwd: ToDo");
521 // cycle through all the blocks in the step
522 for (; bd != NULL; bd = bd->link) {
525 while (p < bd->free ) {
527 while ( p < bd->free && !is_marked(p,bd) ) {
536 m = * ((StgPtr)bd->u.bitmap + ((p - bd->start) / (BITS_IN(StgWord))));
537 m >>= ((p - bd->start) & (BITS_IN(StgWord) - 1));
539 while ( p < bd->free ) {
544 if (((StgWord)p & (sizeof(W_) * BITS_IN(StgWord))) == 0) {
552 // Problem: we need to know the destination for this cell
553 // in order to unthread its info pointer. But we can't
554 // know the destination without the size, because we may
555 // spill into the next block. So we have to run down the
556 // threaded list and get the info ptr first.
557 info = get_threaded_info(p);
560 ASSERT(p && (LOOKS_LIKE_GHC_INFO(info)
561 || IS_HUGS_CONSTR_INFO(info)));
563 switch (info->type) {
566 p += sizeofW(StgHeader) + 1;
571 thread((StgPtr)&((StgClosure *)p)->payload[0]);
572 p += sizeofW(StgHeader) + 1;
576 thread((StgPtr)&((StgClosure *)p)->payload[0]);
577 p += sizeofW(StgHeader) + 2; // MIN_UPD_SIZE
580 case THUNK_0_1: // MIN_UPD_SIZE
584 p += sizeofW(StgHeader) + 2;
590 thread((StgPtr)&((StgClosure *)p)->payload[0]);
591 p += sizeofW(StgHeader) + 2;
597 thread((StgPtr)&((StgClosure *)p)->payload[0]);
598 thread((StgPtr)&((StgClosure *)p)->payload[1]);
599 p += sizeofW(StgHeader) + 2;
612 case SE_CAF_BLACKHOLE:
619 end = (P_)((StgClosure *)p)->payload +
620 info->layout.payload.ptrs;
621 for (p = (P_)((StgClosure *)p)->payload; p < end; p++) {
624 p += info->layout.payload.nptrs;
630 StgWeak *w = (StgWeak *)p;
631 thread((StgPtr)&w->key);
632 thread((StgPtr)&w->value);
633 thread((StgPtr)&w->finalizer);
634 if (w->link != NULL) {
635 thread((StgPtr)&w->link);
637 p += sizeofW(StgWeak);
643 StgMVar *mvar = (StgMVar *)p;
644 thread((StgPtr)&mvar->head);
645 thread((StgPtr)&mvar->tail);
646 thread((StgPtr)&mvar->value);
647 p += sizeofW(StgMVar);
652 case IND_OLDGEN_PERM:
653 // specialise this case, because we want to update the
654 // mut_link field too.
656 StgIndOldGen *ind = (StgIndOldGen *)p;
657 thread((StgPtr)&ind->indirectee);
658 if (ind->mut_link != NULL) {
659 thread((StgPtr)&ind->mut_link);
661 p += sizeofW(StgIndOldGen);
667 StgSelector *s = (StgSelector *)p;
668 thread((StgPtr)&s->selectee);
669 p += THUNK_SELECTOR_sizeW();
673 case AP_UPD: // same as PAPs
676 StgPAP* pap = (StgPAP *)p;
678 thread((P_)&pap->fun);
679 thread_stack((P_)pap->payload, (P_)pap->payload + pap->n_args);
685 p += arr_words_sizeW((StgArrWords *)p);
689 case MUT_ARR_PTRS_FROZEN:
694 next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
695 for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
703 StgTSO *tso = (StgTSO *)p;
704 thread_stack(tso->sp, &(tso->stack[tso->stack_size]));
705 thread((StgPtr)&tso->link);
706 thread((StgPtr)&tso->global_link);
712 barf("update_fwd: unknown/strange object %d", (int)(info->type));
716 if (free + size > free_bd->start + BLOCK_SIZE_W) {
717 free_bd = free_bd->link;
718 free = free_bd->start;
731 update_bkwd( bdescr *blocks )
740 barf("update_bkwd: ToDo");
743 // cycle through all the blocks in the step
744 for (; bd != NULL; bd = bd->link) {
747 // linearly scan the objects in this block
748 while (p < bd->free) {
750 // must unthread before we look at the info ptr...
753 info = get_itbl((StgClosure *)p);
754 ASSERT(p && (LOOKS_LIKE_GHC_INFO(info)
755 || IS_HUGS_CONSTR_INFO(info)));
757 p += obj_sizeW((StgClosure *)p,info);
763 update_bkwd_compact( step *stp )
767 bdescr *bd, *free_bd;
769 nat size, free_blocks;
771 bd = free_bd = stp->blocks;
772 free = free_bd->start;
776 barf("update_bkwd: ToDo");
779 // cycle through all the blocks in the step
780 for (; bd != NULL; bd = bd->link) {
783 while (p < bd->free ) {
785 while ( p < bd->free && !is_marked(p,bd) ) {
794 m = * ((StgPtr)bd->u.bitmap + ((p - bd->start) / (BITS_IN(StgWord))));
795 m >>= ((p - bd->start) & (BITS_IN(StgWord) - 1));
797 while ( p < bd->free ) {
802 if (((StgWord)p & (sizeof(W_) * BITS_IN(StgWord))) == 0) {
810 // must unthread before we look at the info ptr...
811 info = get_threaded_info(p);
813 ASSERT(p && (LOOKS_LIKE_GHC_INFO(info)
814 || IS_HUGS_CONSTR_INFO(info)));
816 size = obj_sizeW((StgClosure *)p,info);
818 if (free + size > free_bd->start + BLOCK_SIZE_W) {
819 // don't forget to update the free ptr in the block desc.
820 free_bd->free = free;
821 free_bd = free_bd->link;
822 free = free_bd->start;
829 // Rebuild the mutable list for the old generation.
830 // (the mut_once list is updated using threading, with
831 // special cases for IND_OLDGEN and MUT_CONS above).
832 if (ip_MUTABLE(info)) {
833 recordMutable((StgMutClosure *)free);
837 if (info->type == TSO) {
838 move_TSO((StgTSO *)p, (StgTSO *)free);
849 // free the remaining blocks and count what's left.
850 free_bd->free = free;
851 if (free_bd->link != NULL) {
852 freeChain(free_bd->link);
853 free_bd->link = NULL;
855 stp->n_blocks = free_blocks;
861 update_bkwd_large( bdescr *blocks )
865 for (bd = blocks; bd != NULL; bd = bd->link ) {
866 unthread(bd->start, bd->start);
872 compact( void (*get_roots)(evac_fn) )
876 extern StgWeak *old_weak_ptr_list; // tmp
878 // 1. thread the roots
879 get_roots((evac_fn)thread);
881 // the weak pointer lists...
882 if (weak_ptr_list != NULL) {
883 thread((StgPtr)&weak_ptr_list);
885 if (old_weak_ptr_list != NULL) {
886 thread((StgPtr)&old_weak_ptr_list); // tmp
889 // mutable lists (ToDo: all gens)
890 thread((StgPtr)&oldest_gen->mut_list);
891 thread((StgPtr)&oldest_gen->mut_once_list);
893 // the global thread list
894 thread((StgPtr)&all_threads);
896 // the static objects
897 thread_static(scavenged_static_objects);
899 // the stable pointer table
900 threadStablePtrTable((evac_fn)thread);
902 // 2. update forward ptrs
903 for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
904 for (s = 0; s < generations[g].n_steps; s++) {
905 stp = &generations[g].steps[s];
906 IF_DEBUG(gc, fprintf(stderr,"update_fwd: %d.%d\n", stp->gen->no, stp->no););
908 update_fwd(stp->to_blocks);
909 update_fwd_large(stp->scavenged_large_objects);
910 if (g == RtsFlags.GcFlags.generations-1 && stp->blocks != NULL) {
911 IF_DEBUG(gc, fprintf(stderr,"update_fwd: %d.%d (compact)\n", stp->gen->no, stp->no););
912 update_fwd_compact(stp->blocks);
917 // 3. update backward ptrs
918 for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
919 for (s = 0; s < generations[g].n_steps; s++) {
920 stp = &generations[g].steps[s];
921 IF_DEBUG(gc, fprintf(stderr,"update_bkwd: %d.%d\n", stp->gen->no, stp->no););
922 update_bkwd(stp->to_blocks);
923 update_bkwd_large(stp->scavenged_large_objects);
924 if (g == RtsFlags.GcFlags.generations-1 && stp->blocks != NULL) {
925 IF_DEBUG(gc, fprintf(stderr,"update_bkwd: %d.%d (compact)\n", stp->gen->no, stp->no););
926 blocks = update_bkwd_compact(stp);
927 IF_DEBUG(gc, fprintf(stderr,"update_bkwd: %d.%d (compact, old: %d blocks, now %d blocks)\n",
928 stp->gen->no, stp->no,
929 stp->n_blocks, blocks););
930 stp->n_blocks = blocks;