[project @ 1998-11-26 09:17:22 by sof]
[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 rtsBool
38 initHeap(smInfo * sm)
39 {
40     if (heap_space == 0) { /* allocates if it doesn't already exist */
41
42         I_ semispaceSize = RTSflags.GcFlags.heapSize / 2;
43
44         /* Allocate the roots space */
45         sm->roots = (P_ *) stgMallocWords(SM_MAXROOTS, "initHeap (roots)");
46
47         /* Allocate the heap */
48         heap_space = (P_) stgMallocWords(RTSflags.GcFlags.heapSize + EXTRA_HEAP_WORDS,
49                                          "initHeap (heap)");
50     
51         dualmodeInfo.modeinfo[TWO_SPACE_BOT].heap_words =
52             dualmodeInfo.modeinfo[TWO_SPACE_TOP].heap_words = RTSflags.GcFlags.heapSize;
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 = (RTSflags.GcFlags.heapSize + BITS_IN(BitWord) - 1) / BITS_IN(BitWord);
64         dualmodeInfo.bits      = (BitWord *)(heap_space + RTSflags.GcFlags.heapSize) - dualmodeInfo.bit_words;
65
66         dualmodeInfo.modeinfo[COMPACTING].heap_words =
67             RTSflags.GcFlags.heapSize - dualmodeInfo.bit_words;
68         dualmodeInfo.modeinfo[COMPACTING].base =
69             HEAP_FRAME_BASE(heap_space, RTSflags.GcFlags.heapSize - dualmodeInfo.bit_words);
70         dualmodeInfo.modeinfo[COMPACTING].lim =
71             HEAP_FRAME_LIMIT(heap_space, RTSflags.GcFlags.heapSize - 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
81         RTSflags.GcFlags.minAllocAreaSize = 0; /* specified size takes precedence */
82
83         if (sm->hplim > dualmodeInfo.modeinfo[dualmodeInfo.mode].lim) {
84             fprintf(stderr, "Not enough heap for requested alloc size\n");
85             return rtsFalse;
86         }
87     } else {
88         sm->hplim = dualmodeInfo.modeinfo[dualmodeInfo.mode].lim;
89     }
90
91     sm->CAFlist = NULL;
92
93 #ifndef PAR
94     initExtensions( sm );
95 #endif /* !PAR */
96
97     if (RTSflags.GcFlags.trace) {
98         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",
99                 (W_) dualmodeInfo.modeinfo[TWO_SPACE_BOT].base,
100                 (W_) dualmodeInfo.modeinfo[TWO_SPACE_BOT].lim,
101                 (W_) dualmodeInfo.modeinfo[TWO_SPACE_TOP].base,
102                 (W_) dualmodeInfo.modeinfo[TWO_SPACE_TOP].lim,
103                 (W_) dualmodeInfo.modeinfo[COMPACTING].base,
104                 (W_) dualmodeInfo.modeinfo[COMPACTING].lim,
105                 (W_) dualmodeInfo.bits, dualmodeInfo.bit_words);
106         fprintf(stderr, "DUALMODE Initial: mode %ld, base 0x%lx, lim 0x%lx\n                         hp 0x%lx, hplim 0x%lx, free %lu\n",
107                 (W_) dualmodeInfo.mode,
108                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].base,
109                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].lim,
110                 (W_) sm->hp, (W_) sm->hplim, (W_) (sm->hplim - sm->hp) * sizeof(W_));
111     }
112
113     return rtsTrue; /* OK */
114 }
115
116 I_
117 collectHeap(reqsize, sm, do_full_collection)
118     W_ reqsize;
119     smInfo *sm;
120     rtsBool do_full_collection;
121 {
122     I_  start_mode;
123
124     I_ free_space,      /* No of words of free space following GC */
125         alloc,          /* Number of words allocated since last GC */
126         resident,       /* Number of words remaining after GC */
127         bstk_roots;     /* Number of update frames on B stack */
128     StgFloat residency;    /* % Words remaining after GC */
129
130     fflush(stdout);     /* Flush stdout at start of GC */
131     SAVE_REGS(&ScavRegDump); /* Save registers */
132
133     if (RTSflags.GcFlags.trace)
134         fprintf(stderr, "DUALMODE Start: mode %ld, base 0x%lx, lim 0x%lx\n                      hp 0x%lx, hplim 0x%lx, req %lu\n",
135                 dualmodeInfo.mode,
136                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].base,
137                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].lim,
138                 (W_) sm->hp, (W_) sm->hplim, (W_) (reqsize * sizeof(W_)));
139
140     alloc = sm->hp - hp_start;
141     stat_startGC(alloc);
142
143     start_mode = dualmodeInfo.mode;
144     if (start_mode == COMPACTING) { 
145
146         /* PERFORM COMPACTING COLLECTION */
147
148         /* bracket use of MARK_REG_MAP with RESTORE/SAVE of SCAV_REG_MAP */
149         RESTORE_REGS(&ScavRegDump);
150
151         markHeapRoots(sm, sm->CAFlist, 0,
152                       dualmodeInfo.modeinfo[COMPACTING].base,
153                       dualmodeInfo.modeinfo[COMPACTING].lim,
154                       dualmodeInfo.bits);
155
156         SAVE_REGS(&ScavRegDump);
157         /* end of bracket */
158
159 #ifndef PAR
160         sweepUpDeadForeignObjs(sm->ForeignObjList, 
161                                dualmodeInfo.modeinfo[COMPACTING].base,
162                                dualmodeInfo.bits);
163 #endif
164         LinkCAFs(sm->CAFlist);
165
166         LinkRoots( sm->roots, sm->rootno );
167 #ifdef CONCURRENT
168         LinkSparks();
169 #endif
170 #ifdef PAR
171         LinkLiveGAs(dualmodeInfo.modeinfo[COMPACTING].base, dualmodeInfo.bits);
172 #else
173 /* stable pointers are now accessed via sm->roots
174         DEBUG_STRING("Linking Stable Pointer Table:");
175         LINK_LOCATION_TO_CLOSURE(&sm->StablePointerTable);
176 */
177 #if 1 /* !defined(GRAN) */ /* HWL */
178         LinkAStack( MAIN_SpA, stackInfo.botA );
179         LinkBStack( MAIN_SuB, stackInfo.botB );
180 #endif
181 #endif
182
183         /* Do Inplace Compaction */
184         /* Returns start of next closure, -1 gives last allocated word */
185         
186         sm->hp = Inplace_Compaction(dualmodeInfo.modeinfo[COMPACTING].base,
187                                     dualmodeInfo.modeinfo[COMPACTING].lim,
188                                     0, 0,
189                                     dualmodeInfo.bits,
190                                     dualmodeInfo.bit_words
191 #ifndef PAR
192                                     ,&(sm->ForeignObjList)
193 #endif
194                                     ) - 1;
195
196     } else {
197
198         /* COPYING COLLECTION */
199
200         dualmodeInfo.mode = NEXT_SEMI_SPACE(start_mode);
201         ToHp = dualmodeInfo.modeinfo[dualmodeInfo.mode].base - 1;
202         Scav = dualmodeInfo.modeinfo[dualmodeInfo.mode].base;
203                /* Point to (info field of) first closure */
204     
205         SetCAFInfoTables( sm->CAFlist );
206         EvacuateCAFs( sm->CAFlist );
207 #ifdef PAR
208         EvacuateLocalGAs(rtsTrue);
209 #else
210         /* evacSPTable( sm ); stable pointers now reachable via sm->roots */
211 #endif /* PAR */
212         EvacuateRoots( sm->roots, sm->rootno );
213 #if defined(CONCURRENT) && !defined(GRAN)
214         EvacuateSparks();
215 #endif
216 #if !defined(PAR) /* && !defined(GRAN) */ /* HWL */
217         EvacuateAStack( MAIN_SpA, stackInfo.botA );
218         EvacuateBStack( MAIN_SuB, stackInfo.botB, &bstk_roots );
219 #endif /* !PAR */
220
221         Scavenge();
222
223 #ifdef PAR
224         RebuildGAtables(rtsTrue);
225 #else
226         reportDeadForeignObjs(sm->ForeignObjList, NULL, &(sm->ForeignObjList) );
227 #endif /* PAR */
228
229         sm->hp = hp_start = ToHp;  /* Last allocated word */
230     }
231
232     /* Use residency to determine if a change in mode is required */
233
234     resident = sm->hp - (dualmodeInfo.modeinfo[dualmodeInfo.mode].base - 1);
235     residency = resident / (StgFloat) RTSflags.GcFlags.heapSize;
236     DO_MAX_RESIDENCY(resident); /* stats only */
237
238     if ((start_mode == TWO_SPACE_TOP) &&
239         (residency > dualmodeInfo.resid_to_compact)) {
240         DEBUG_STRING("Changed Mode: Two Space => Compacting");
241         dualmodeInfo.mode = COMPACTING;
242
243         /* Zero bit vector for marking phase at next collection */
244         { BitWord *ptr = dualmodeInfo.bits,
245                   *end = dualmodeInfo.bits + dualmodeInfo.bit_words;
246           while (ptr < end) { *(ptr++) = 0; };
247     }
248
249     } else if ((start_mode == COMPACTING) &&
250         (residency < dualmodeInfo.resid_from_compact)) {
251         DEBUG_STRING("Changed Mode: Compacting => Two Space");
252         dualmodeInfo.mode = TWO_SPACE_BOT;
253     }
254
255     if (SM_alloc_size) {
256         sm->hplim = sm->hp + SM_alloc_size;
257         if (sm->hplim > dualmodeInfo.modeinfo[dualmodeInfo.mode].lim) {
258             free_space = 0;
259         } else {
260             free_space = SM_alloc_size;
261         }
262     } else {
263         sm->hplim = dualmodeInfo.modeinfo[dualmodeInfo.mode].lim;
264         free_space = sm->hplim - sm->hp;
265     }
266
267     hp_start = sm->hp;
268
269     stat_endGC(alloc, dualmodeInfo.modeinfo[start_mode].heap_words,
270                resident, dualmodeInfo.modeinfo[start_mode].name);
271
272     if (RTSflags.GcFlags.trace)
273         fprintf(stderr, "DUALMODE Done: mode %ld, base 0x%lx, lim 0x%lx\n                         hp 0x%lx, hplim 0x%lx, free %lu\n",
274                 dualmodeInfo.mode,
275                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].base,
276                 (W_) dualmodeInfo.modeinfo[dualmodeInfo.mode].lim,
277                 (W_) sm->hp, (W_) sm->hplim, (W_) ((sm->hplim - sm->hp) * sizeof(W_)));
278
279 #ifdef DEBUG
280     /* To help flush out bugs, we trash the part of the heap from
281        which we're about to start allocating. */
282     TrashMem(sm->hp+1, sm->hplim);
283 #endif /* DEBUG */
284
285     RESTORE_REGS(&ScavRegDump);     /* Restore Registers */
286
287     if (free_space < RTSflags.GcFlags.minAllocAreaSize || free_space < reqsize)
288         return GC_HARD_LIMIT_EXCEEDED;  /* Heap exhausted */
289     else 
290         return GC_SUCCESS;              /* Heap OK */
291 }
292
293 #endif /* GCdu */
294
295 \end{code}
296