[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / runtime / storage / SMdu.lc
1 ***************************************************************************
2
3                       COMPACTING GARBAGE COLLECTION
4
5 Global heap requirements as for 1s and 2s collectors.
6
7 ***************************************************************************
8
9 ToDo: soft heap limits.
10
11 \begin{code}
12
13 #if defined(GCdu)
14
15 #define SCAV_REG_MAP
16 #include "SMinternal.h"
17 #include "SMcopying.h"
18 #include "SMcompacting.h"
19 #include "SMextn.h"
20
21 REGDUMP(ScavRegDump);
22
23 dualmodeData dualmodeInfo = {TWO_SPACE_BOT,
24                              DEFAULT_RESID_TO_COMPACT,
25                              DEFAULT_RESID_FROM_COMPACT,
26                              {{0,0,0,"low->high"},
27                               {0,0,0,"high->low"},
28                               {0,0,0,"compacting"}},
29                              0, 0
30                             };
31
32 P_ heap_space = 0;              /* Address of first word of slab 
33                                    of memory allocated for heap */
34
35 P_ hp_start;            /* Value of Hp when reduction was resumed */
36
37 I_
38 initHeap( sm )
39     smInfo *sm;    
40 {
41     if (heap_space == 0) { /* allocates if it doesn't already exist */
42
43         I_ semispaceSize = SM_word_heap_size / 2;
44
45         /* Allocate the roots space */
46         sm->roots = (P_ *) xmalloc( SM_MAXROOTS * sizeof(W_) );
47
48         /* Allocate the heap */
49         heap_space = (P_) xmalloc((SM_word_heap_size + EXTRA_HEAP_WORDS) * sizeof(W_));
50     
51         dualmodeInfo.modeinfo[TWO_SPACE_BOT].heap_words =
52             dualmodeInfo.modeinfo[TWO_SPACE_TOP].heap_words = SM_word_heap_size;
53
54         dualmodeInfo.modeinfo[TWO_SPACE_BOT].base =
55             HEAP_FRAME_BASE(heap_space, semispaceSize);
56         dualmodeInfo.modeinfo[TWO_SPACE_BOT].lim =
57             HEAP_FRAME_LIMIT(heap_space, semispaceSize);
58         dualmodeInfo.modeinfo[TWO_SPACE_TOP].base =
59             HEAP_FRAME_BASE(heap_space + semispaceSize, semispaceSize);
60         dualmodeInfo.modeinfo[TWO_SPACE_TOP].lim =
61             HEAP_FRAME_LIMIT(heap_space + semispaceSize, semispaceSize);
62
63         dualmodeInfo.bit_words = (SM_word_heap_size + BITS_IN(BitWord) - 1) / BITS_IN(BitWord);
64         dualmodeInfo.bits      = (BitWord *)(heap_space + SM_word_heap_size) - dualmodeInfo.bit_words;
65
66         dualmodeInfo.modeinfo[COMPACTING].heap_words =
67             SM_word_heap_size - dualmodeInfo.bit_words;
68         dualmodeInfo.modeinfo[COMPACTING].base =
69             HEAP_FRAME_BASE(heap_space, SM_word_heap_size - dualmodeInfo.bit_words);
70         dualmodeInfo.modeinfo[COMPACTING].lim =
71             HEAP_FRAME_LIMIT(heap_space, SM_word_heap_size - dualmodeInfo.bit_words);
72
73         stat_init("DUALMODE", "Collection", "  Mode  ");
74     }
75
76     sm->hp = hp_start = dualmodeInfo.modeinfo[dualmodeInfo.mode].base - 1;
77
78     if (SM_alloc_size) {
79         sm->hplim = sm->hp + SM_alloc_size;
80         SM_alloc_min = 0; /* No min; alloc size specified */
81
82         if (sm->hplim > dualmodeInfo.modeinfo[dualmodeInfo.mode].lim) {
83             fprintf(stderr, "Not enough heap for requested alloc size\n");
84             return -1;
85         }
86     } else {
87         sm->hplim = dualmodeInfo.modeinfo[dualmodeInfo.mode].lim;
88     }
89
90     sm->CAFlist = NULL;
91
92 #ifndef PAR
93     initExtensions( sm );
94 #endif /* !PAR */
95
96     if (SM_trace) {
97         fprintf(stderr, "DUALMODE Heap: TS base, TS lim, TS base, TS lim, CM base, CM lim, CM bits, bit words\n                0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx\n",
98                 (W_) dualmodeInfo.modeinfo[TWO_SPACE_BOT].base,
99                 (W_) dualmodeInfo.modeinfo[TWO_SPACE_BOT].lim,
100                 (W_) dualmodeInfo.modeinfo[TWO_SPACE_TOP].base,
101                 (W_) dualmodeInfo.modeinfo[TWO_SPACE_TOP].lim,
102                 (W_) dualmodeInfo.modeinfo[COMPACTING].base,
103                 (W_) dualmodeInfo.modeinfo[COMPACTING].lim,
104                 (W_) dualmodeInfo.bits, dualmodeInfo.bit_words);
105         fprintf(stderr, "DUALMODE Initial: mode %ld, base 0x%lx, lim 0x%lx\n                         hp 0x%lx, hplim 0x%lx, free %lu\n",
106                 (W_) dualmodeInfo.mode,
107                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].base,
108                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].lim,
109                 (W_) sm->hp, (W_) sm->hplim, (W_) (sm->hplim - sm->hp) * sizeof(W_));
110     }
111
112     return 0;
113 }
114
115 I_
116 collectHeap(reqsize, sm, do_full_collection)
117     W_ reqsize;
118     smInfo *sm;
119     rtsBool do_full_collection;
120 {
121     I_  start_mode;
122
123     I_ free_space,      /* No of words of free space following GC */
124         alloc,          /* Number of words allocated since last GC */
125         resident,       /* Number of words remaining after GC */
126         bstk_roots;     /* Number of update frames on B stack */
127     StgFloat residency;    /* % Words remaining after GC */
128
129     fflush(stdout);     /* Flush stdout at start of GC */
130     SAVE_REGS(&ScavRegDump); /* Save registers */
131
132     if (SM_trace)
133         fprintf(stderr, "DUALMODE Start: mode %ld, base 0x%lx, lim 0x%lx\n                      hp 0x%lx, hplim 0x%lx, req %lu\n",
134                 dualmodeInfo.mode,
135                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].base,
136                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].lim,
137                 (W_) sm->hp, (W_) sm->hplim, (W_) (reqsize * sizeof(W_)));
138
139     alloc = sm->hp - hp_start;
140     stat_startGC(alloc);
141
142     start_mode = dualmodeInfo.mode;
143     if (start_mode == COMPACTING) { 
144
145         /* PERFORM COMPACTING COLLECTION */
146
147         /* bracket use of MARK_REG_MAP with RESTORE/SAVE of SCAV_REG_MAP */
148         RESTORE_REGS(&ScavRegDump);
149
150         markHeapRoots(sm, sm->CAFlist, 0,
151                       dualmodeInfo.modeinfo[COMPACTING].base,
152                       dualmodeInfo.modeinfo[COMPACTING].lim,
153                       dualmodeInfo.bits);
154
155         SAVE_REGS(&ScavRegDump);
156         /* end of bracket */
157
158 #ifndef PAR
159         sweepUpDeadMallocPtrs(sm->MallocPtrList, 
160                               dualmodeInfo.modeinfo[COMPACTING].base,
161                               dualmodeInfo.bits);
162 #endif
163         LinkCAFs(sm->CAFlist);
164
165         LinkRoots( sm->roots, sm->rootno );
166 #ifdef CONCURRENT
167         LinkSparks();
168 #endif
169 #ifdef PAR
170         LinkLiveGAs(dualmodeInfo.modeinfo[COMPACTING].base, dualmodeInfo.bits);
171 #else
172         DEBUG_STRING("Linking Stable Pointer Table:");
173         LINK_LOCATION_TO_CLOSURE(&sm->StablePointerTable);
174         LinkAStack( MAIN_SpA, stackInfo.botA );
175         LinkBStack( MAIN_SuB, stackInfo.botB );
176 #endif
177
178         /* Do Inplace Compaction */
179         /* Returns start of next closure, -1 gives last allocated word */
180         
181         sm->hp = Inplace_Compaction(dualmodeInfo.modeinfo[COMPACTING].base,
182                                     dualmodeInfo.modeinfo[COMPACTING].lim,
183                                     0, 0,
184                                     dualmodeInfo.bits,
185                                     dualmodeInfo.bit_words
186 #ifndef PAR
187                                     ,&(sm->MallocPtrList)
188 #endif
189                                     ) - 1;
190
191     } else {
192
193         /* COPYING COLLECTION */
194
195         dualmodeInfo.mode = NEXT_SEMI_SPACE(start_mode);
196         ToHp = dualmodeInfo.modeinfo[dualmodeInfo.mode].base - 1;
197         Scav = dualmodeInfo.modeinfo[dualmodeInfo.mode].base;
198                /* Point to (info field of) first closure */
199     
200         SetCAFInfoTables( sm->CAFlist );
201         EvacuateCAFs( sm->CAFlist );
202 #ifdef PAR
203         EvacuateLocalGAs(rtsTrue);
204 #else
205         evacSPTable( sm );
206 #endif /* PAR */
207         EvacuateRoots( sm->roots, sm->rootno );
208 #ifdef CONCURRENT
209         EvacuateSparks();
210 #endif
211 #ifndef PAR
212         EvacuateAStack( MAIN_SpA, stackInfo.botA );
213         EvacuateBStack( MAIN_SuB, stackInfo.botB, &bstk_roots );
214 #endif /* !PAR */
215
216         Scavenge();
217
218 #ifdef PAR
219         RebuildGAtables(rtsTrue);
220 #else
221         reportDeadMallocPtrs(sm->MallocPtrList, NULL, &(sm->MallocPtrList) );
222 #endif /* PAR */
223
224         sm->hp = hp_start = ToHp;  /* Last allocated word */
225     }
226
227     /* Use residency to determine if a change in mode is required */
228
229     resident = sm->hp - (dualmodeInfo.modeinfo[dualmodeInfo.mode].base - 1);
230     residency = resident / (StgFloat) SM_word_heap_size;
231     DO_MAX_RESIDENCY(resident); /* stats only */
232
233     if ((start_mode == TWO_SPACE_TOP) &&
234         (residency > dualmodeInfo.resid_to_compact)) {
235         DEBUG_STRING("Changed Mode: Two Space => Compacting");
236         dualmodeInfo.mode = COMPACTING;
237
238         /* Zero bit vector for marking phase at next collection */
239         { BitWord *ptr = dualmodeInfo.bits,
240                   *end = dualmodeInfo.bits + dualmodeInfo.bit_words;
241           while (ptr < end) { *(ptr++) = 0; };
242     }
243
244     } else if ((start_mode == COMPACTING) &&
245         (residency < dualmodeInfo.resid_from_compact)) {
246         DEBUG_STRING("Changed Mode: Compacting => Two Space");
247         dualmodeInfo.mode = TWO_SPACE_BOT;
248     }
249
250     if (SM_alloc_size) {
251         sm->hplim = sm->hp + SM_alloc_size;
252         if (sm->hplim > dualmodeInfo.modeinfo[dualmodeInfo.mode].lim) {
253             free_space = 0;
254         } else {
255             free_space = SM_alloc_size;
256         }
257     } else {
258         sm->hplim = dualmodeInfo.modeinfo[dualmodeInfo.mode].lim;
259         free_space = sm->hplim - sm->hp;
260     }
261
262     hp_start = sm->hp;
263
264     stat_endGC(alloc, dualmodeInfo.modeinfo[start_mode].heap_words,
265                resident, dualmodeInfo.modeinfo[start_mode].name);
266
267     if (SM_trace)
268         fprintf(stderr, "DUALMODE Done: mode %ld, base 0x%lx, lim 0x%lx\n                         hp 0x%lx, hplim 0x%lx, free %lu\n",
269                 dualmodeInfo.mode,
270                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].base,
271                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].lim,
272                 (W_) sm->hp, (W_) sm->hplim, (W_) ((sm->hplim - sm->hp) * sizeof(W_)));
273
274 #ifdef DEBUG
275     /* To help flush out bugs, we trash the part of the heap from
276        which we're about to start allocating. */
277     TrashMem(sm->hp+1, sm->hplim);
278 #endif /* DEBUG */
279
280     RESTORE_REGS(&ScavRegDump);     /* Restore Registers */
281
282     if ((SM_alloc_min > free_space) || (reqsize > free_space))
283         return GC_HARD_LIMIT_EXCEEDED;  /* Heap exhausted */
284     else 
285         return GC_SUCCESS;              /* Heap OK */
286 }
287
288 #endif /* GCdu */
289
290 \end{code}
291