[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / runtime / storage / SM2s.lc
1 ***************************************************************************
2
3                            TWO SPACE COLLECTION
4
5 ***************************************************************************
6
7 \begin{code}
8 #if defined(GC2s)
9
10 #define SCAV_REG_MAP
11 #include "SMinternal.h"
12 #include "SMcopying.h"
13 #include "SMextn.h"
14
15 REGDUMP(ScavRegDump);
16
17 I_ semispace = 0;              /* 0 or 1 */
18 semispaceData semispaceInfo[2]
19     = {{0,0}, {0,0}};
20
21 P_ heap_space = 0;              /* Address of first word of slab 
22                                    of memory allocated for heap */
23
24 P_ hp_start;            /* Value of Hp when reduction was resumed */
25
26
27 I_ initHeap( sm )
28     smInfo *sm;    
29 {
30     if (heap_space == 0) { /* allocates if it doesn't already exist */
31
32         I_ semispaceSize = SM_word_heap_size / 2;
33
34         /* Allocate the roots space */
35         sm->roots = (P_ *) xmalloc( SM_MAXROOTS * sizeof(W_) );
36
37         /* Allocate the heap */
38         heap_space = (P_) xmalloc((SM_word_heap_size + EXTRA_HEAP_WORDS) * sizeof(W_));
39     
40         /* Define the semi-spaces */
41         semispaceInfo[0].base = HEAP_FRAME_BASE(heap_space, semispaceSize);
42         semispaceInfo[1].base = HEAP_FRAME_BASE(heap_space + semispaceSize, semispaceSize);
43         semispaceInfo[0].lim = HEAP_FRAME_LIMIT(heap_space, semispaceSize);
44         semispaceInfo[1].lim = HEAP_FRAME_LIMIT(heap_space + semispaceSize, semispaceSize);
45
46         stat_init("TWOSPACE",
47                   " No of Roots  Caf   Caf    Astk   Bstk",
48                   "Astk Bstk Reg  No  bytes  bytes  bytes");
49     }
50
51     /* Initialise heap pointer and limit */
52     sm->hp = hp_start = semispaceInfo[semispace].base - 1;
53     sm->hardHpOverflowSize = 0;
54
55     if (SM_alloc_size) {
56         sm->hplim = sm->hp + SM_alloc_size;
57         SM_alloc_min = 0; /* No min; alloc size specified */
58
59         if (sm->hplim > semispaceInfo[semispace].lim) {
60             fprintf(stderr, "Not enough heap for requested alloc size\n");
61             return -1;
62         }
63     } else {
64         sm->hplim = semispaceInfo[semispace].lim;
65     }
66
67 #if defined(FORCE_GC)
68     if (force_GC) {
69        if (sm->hplim > sm->hp + GCInterval) {
70           sm->hplim = sm->hp + GCInterval; 
71        }
72        else {
73           force_GC = 0; /* forcing GC has no effect, as semi-space is smaller than GCInterval */ 
74        }
75     }
76 #endif /* FORCE_GC */
77
78 #if defined(LIFE_PROFILE)
79     sm->hplim = sm->hp + ((sm->hplim - sm->hp) / 2); /* space for HpLim incr */
80     if (do_life_prof) {
81         sm->hplim = sm->hp + LifeInterval;
82     }
83 #endif /* LIFE_PROFILE */
84
85     sm->CAFlist = NULL;
86
87 #ifndef PAR
88     initExtensions( sm );
89 #endif /* !PAR */
90
91     if (SM_trace) {
92         fprintf(stderr, "TWO SPACE Heap: 0base, 0lim, 1base, 1lim\n                0x%lx, 0x%lx, 0x%lx, 0x%lx\n",
93                 (W_) semispaceInfo[0].base, (W_) semispaceInfo[0].lim,
94                 (W_) semispaceInfo[1].base, (W_) semispaceInfo[1].lim);
95         fprintf(stderr, "TWO SPACE Initial: space %ld, base 0x%lx, lim 0x%lx\n                         hp 0x%lx, hplim 0x%lx, free %lu\n",
96                 semispace,
97                 (W_) semispaceInfo[semispace].base,
98                 (W_) semispaceInfo[semispace].lim,
99                 (W_) sm->hp, (W_) sm->hplim, (W_) (sm->hplim - sm->hp) * sizeof(W_));
100     }
101
102     return 0;
103 }
104
105 I_
106 collectHeap(reqsize, sm, do_full_collection)
107     W_ reqsize;
108     smInfo *sm;
109     rtsBool do_full_collection; /* ignored */
110 {
111 #if defined(LIFE_PROFILE)
112     I_ next_interval;  /* if doing profile */
113 #endif
114
115     I_ free_space,      /* No of words of free space following GC */
116         alloc,          /* Number of words allocated since last GC */
117         resident,       /* Number of words remaining after GC */
118         extra_caf_words,/* Extra words referenced from CAFs */
119         caf_roots,      /* Number of CAFs */
120         bstk_roots;     /* Number of update frames on B stack */
121
122     fflush(stdout);     /* Flush stdout at start of GC */
123     SAVE_REGS(&ScavRegDump); /* Save registers */
124
125 #if defined(LIFE_PROFILE)
126     if (do_life_prof) { life_profile_setup(); }
127 #endif /* LIFE_PROFILE */
128
129 #if defined(USE_COST_CENTRES)
130     if (interval_expired) { heap_profile_setup(); }
131 #endif  /* USE_COST_CENTRES */
132   
133     if (SM_trace)
134         fprintf(stderr, "TWO SPACE Start: space %ld, base 0x%lx, lim 0x%lx\n                         hp 0x%lx, hplim 0x%lx, req %lu\n",
135                 semispace, (W_) semispaceInfo[semispace].base,
136                 (W_) semispaceInfo[semispace].lim,
137                 (W_) sm->hp, (W_) sm->hplim, reqsize * sizeof(W_));
138
139     alloc = sm->hp - hp_start;
140     stat_startGC(alloc);
141
142     /* Set Up For Collecting:
143          - Flip Spaces
144          - Set ToHp to point one below bottom of to-space (last allocated)
145          - Set CAFs to Evac & Upd
146      */
147
148     semispace = NEXT_SEMI_SPACE(semispace);
149     ToHp = semispaceInfo[semispace].base - 1;
150     Scav = semispaceInfo[semispace].base;
151     
152     SetCAFInfoTables( sm->CAFlist );
153 #ifdef PAR
154     EvacuateLocalGAs(rtsTrue);
155 #else
156     evacSPTable( sm );
157 #endif /* PAR */
158     EvacuateRoots( sm->roots, sm->rootno );
159 #ifdef CONCURRENT
160     EvacuateSparks();
161 #endif
162 #ifndef PAR
163     EvacuateAStack( MAIN_SpA, stackInfo.botA );
164     EvacuateBStack( MAIN_SuB, stackInfo.botB, &bstk_roots );
165 #endif /* !PAR */
166
167     Scavenge();
168
169     EvacAndScavengeCAFs( sm->CAFlist, &extra_caf_words, &caf_roots );
170
171 #ifdef PAR
172     RebuildGAtables(rtsTrue);
173 #else
174     reportDeadMallocPtrs(sm->MallocPtrList, NULL, &(sm->MallocPtrList) );
175 #endif /* PAR */
176
177     /* TIDY UP AND RETURN */
178
179     sm->hp = hp_start = ToHp;  /* Last allocated word */
180
181     resident = sm->hp - (semispaceInfo[semispace].base - 1);
182     DO_MAX_RESIDENCY(resident); /* stats only */
183
184     if (SM_alloc_size) {
185         sm->hplim = sm->hp + SM_alloc_size;
186         if (sm->hplim > semispaceInfo[semispace].lim) {
187             free_space = 0;
188         } else {
189             free_space = SM_alloc_size;
190         }
191     } else {
192         sm->hplim = semispaceInfo[semispace].lim;
193         free_space = sm->hplim - sm->hp;
194     }
195
196     if (SM_stats_verbose) {
197         char comment_str[BIG_STRING_LEN];
198 #ifndef PAR
199         sprintf(comment_str, "%4u %4ld %3ld %3ld %6lu %6lu %6lu",
200                 (SUBTRACT_A_STK(MAIN_SpA, stackInfo.botA) + 1),
201                 bstk_roots, sm->rootno,
202                 caf_roots, extra_caf_words*sizeof(W_),
203                 (SUBTRACT_A_STK(MAIN_SpA, stackInfo.botA) + 1)*sizeof(W_),
204                 (SUBTRACT_B_STK(MAIN_SpB, stackInfo.botB) + 1)*sizeof(W_));
205 #else
206         /* ToDo: come up with some interesting statistics for the parallel world */
207         sprintf(comment_str, "%4u %4ld %3ld %3ld %6lu %6lu %6lu",
208                 0, 0, sm->rootno, caf_roots, extra_caf_words*sizeof(W_), 0, 0);
209 #endif
210
211 #if defined(LIFE_PROFILE)
212         if (do_life_prof) {
213             strcat(comment_str, " life");
214         }
215 #endif
216 #if defined(USE_COST_CENTRES)
217         if (interval_expired) {
218             strcat(comment_str, " prof");
219         }
220 #endif
221
222         stat_endGC(alloc, SM_word_heap_size, resident, comment_str);
223     } else {
224         stat_endGC(alloc, SM_word_heap_size, resident, "");
225     }
226
227 #if defined(LIFE_PROFILE)
228       free_space = free_space / 2; /* space for HpLim incr */
229       if (do_life_prof) {
230           next_interval = life_profile_done(alloc, reqsize);
231           free_space -= next_interval;  /* ensure interval available */
232       }
233 #endif /* LIFE_PROFILE */
234
235 #if defined(USE_COST_CENTRES) || defined(GUM)
236       if (interval_expired) {
237 #if defined(USE_COST_CENTRES)
238           heap_profile_done();
239 #endif
240           report_cc_profiling(0 /*partial*/);
241       }
242 #endif /* USE_COST_CENTRES */
243
244     if (SM_trace)
245         fprintf(stderr, "TWO SPACE Done: space %ld, base 0x%lx, lim 0x%lx\n                         hp 0x%lx, hplim 0x%lx, free %lu\n",
246                 semispace, (W_) semispaceInfo[semispace].base,
247                 (W_) semispaceInfo[semispace].lim,
248                 (W_) sm->hp, (W_) sm->hplim, (W_) (free_space * sizeof(W_)));
249
250 #ifdef DEBUG
251     /* To help flush out bugs, we trash the part of the heap from
252        which we're about to start allocating and all of the other semispace. */
253     TrashMem(sm->hp+1, sm->hplim);
254     TrashMem(semispaceInfo[NEXT_SEMI_SPACE(semispace)].base, 
255              semispaceInfo[NEXT_SEMI_SPACE(semispace)].lim);
256 #endif /* DEBUG */
257
258     RESTORE_REGS(&ScavRegDump);     /* Restore Registers */
259
260     if ( (SM_alloc_min > free_space) || (reqsize > free_space) ) {
261       return( GC_HARD_LIMIT_EXCEEDED ); /* Heap absolutely exhausted */
262     } else {
263
264 #if defined(FORCE_GC)
265     if (force_GC) {
266        if (sm->hplim > sm->hp + GCInterval) {
267           sm->hplim = sm->hp + GCInterval;
268        }
269     }
270 #endif /* FORCE_GC */
271 +         
272 #if defined(LIFE_PROFILE)
273       /* space for HpLim incr */
274       sm->hplim = sm->hp + ((sm->hplim - sm->hp) / 2);
275       if (do_life_prof) {
276           /* set hplim for next life profile */
277           sm->hplim = sm->hp + next_interval;
278       }
279 #endif /* LIFE_PROFILE */
280           
281       if (reqsize + sm->hardHpOverflowSize > free_space) {
282         return( GC_SOFT_LIMIT_EXCEEDED );   /* Heap nearly exhausted */
283       } else {
284         return( GC_SUCCESS );               /* Heap OK */
285       }
286     }
287 }
288
289 #endif /* GC2s */
290
291 \end{code}