1 ***************************************************************************
5 ***************************************************************************
11 #include "SMinternal.h"
12 #include "SMcopying.h"
17 I_ semispace = 0; /* 0 or 1 */
18 semispaceData semispaceInfo[2]
21 P_ heap_space = 0; /* Address of first word of slab
22 of memory allocated for heap */
24 P_ hp_start; /* Value of Hp when reduction was resumed */
30 if (heap_space == 0) { /* allocates if it doesn't already exist */
32 I_ semispaceSize = SM_word_heap_size / 2;
34 /* Allocate the roots space */
35 sm->roots = (P_ *) xmalloc( SM_MAXROOTS * sizeof(W_) );
37 /* Allocate the heap */
38 heap_space = (P_) xmalloc((SM_word_heap_size + EXTRA_HEAP_WORDS) * sizeof(W_));
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);
47 " No of Roots Caf Caf Astk Bstk",
48 "Astk Bstk Reg No bytes bytes bytes");
51 /* Initialise heap pointer and limit */
52 sm->hp = hp_start = semispaceInfo[semispace].base - 1;
53 sm->hardHpOverflowSize = 0;
56 sm->hplim = sm->hp + SM_alloc_size;
57 SM_alloc_min = 0; /* No min; alloc size specified */
59 if (sm->hplim > semispaceInfo[semispace].lim) {
60 fprintf(stderr, "Not enough heap for requested alloc size\n");
64 sm->hplim = semispaceInfo[semispace].lim;
69 if (sm->hplim > sm->hp + GCInterval) {
70 sm->hplim = sm->hp + GCInterval;
73 force_GC = 0; /* forcing GC has no effect, as semi-space is smaller than GCInterval */
78 #if defined(LIFE_PROFILE)
79 sm->hplim = sm->hp + ((sm->hplim - sm->hp) / 2); /* space for HpLim incr */
81 sm->hplim = sm->hp + LifeInterval;
83 #endif /* LIFE_PROFILE */
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",
97 (W_) semispaceInfo[semispace].base,
98 (W_) semispaceInfo[semispace].lim,
99 (W_) sm->hp, (W_) sm->hplim, (W_) (sm->hplim - sm->hp) * sizeof(W_));
106 collectHeap(reqsize, sm, do_full_collection)
109 rtsBool do_full_collection; /* ignored */
111 #if defined(LIFE_PROFILE)
112 I_ next_interval; /* if doing profile */
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 */
122 fflush(stdout); /* Flush stdout at start of GC */
123 SAVE_REGS(&ScavRegDump); /* Save registers */
125 #if defined(LIFE_PROFILE)
126 if (do_life_prof) { life_profile_setup(); }
127 #endif /* LIFE_PROFILE */
129 #if defined(USE_COST_CENTRES)
130 if (interval_expired) { heap_profile_setup(); }
131 #endif /* USE_COST_CENTRES */
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_));
139 alloc = sm->hp - hp_start;
142 /* Set Up For Collecting:
144 - Set ToHp to point one below bottom of to-space (last allocated)
145 - Set CAFs to Evac & Upd
148 semispace = NEXT_SEMI_SPACE(semispace);
149 ToHp = semispaceInfo[semispace].base - 1;
150 Scav = semispaceInfo[semispace].base;
152 SetCAFInfoTables( sm->CAFlist );
154 EvacuateLocalGAs(rtsTrue);
158 EvacuateRoots( sm->roots, sm->rootno );
163 EvacuateAStack( MAIN_SpA, stackInfo.botA );
164 EvacuateBStack( MAIN_SuB, stackInfo.botB, &bstk_roots );
169 EvacAndScavengeCAFs( sm->CAFlist, &extra_caf_words, &caf_roots );
172 RebuildGAtables(rtsTrue);
174 reportDeadMallocPtrs(sm->MallocPtrList, NULL, &(sm->MallocPtrList) );
177 /* TIDY UP AND RETURN */
179 sm->hp = hp_start = ToHp; /* Last allocated word */
181 resident = sm->hp - (semispaceInfo[semispace].base - 1);
182 DO_MAX_RESIDENCY(resident); /* stats only */
185 sm->hplim = sm->hp + SM_alloc_size;
186 if (sm->hplim > semispaceInfo[semispace].lim) {
189 free_space = SM_alloc_size;
192 sm->hplim = semispaceInfo[semispace].lim;
193 free_space = sm->hplim - sm->hp;
196 if (SM_stats_verbose) {
197 char comment_str[BIG_STRING_LEN];
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_));
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);
211 #if defined(LIFE_PROFILE)
213 strcat(comment_str, " life");
216 #if defined(USE_COST_CENTRES)
217 if (interval_expired) {
218 strcat(comment_str, " prof");
222 stat_endGC(alloc, SM_word_heap_size, resident, comment_str);
224 stat_endGC(alloc, SM_word_heap_size, resident, "");
227 #if defined(LIFE_PROFILE)
228 free_space = free_space / 2; /* space for HpLim incr */
230 next_interval = life_profile_done(alloc, reqsize);
231 free_space -= next_interval; /* ensure interval available */
233 #endif /* LIFE_PROFILE */
235 #if defined(USE_COST_CENTRES) || defined(GUM)
236 if (interval_expired) {
237 #if defined(USE_COST_CENTRES)
240 report_cc_profiling(0 /*partial*/);
242 #endif /* USE_COST_CENTRES */
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_)));
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);
258 RESTORE_REGS(&ScavRegDump); /* Restore Registers */
260 if ( (SM_alloc_min > free_space) || (reqsize > free_space) ) {
261 return( GC_HARD_LIMIT_EXCEEDED ); /* Heap absolutely exhausted */
264 #if defined(FORCE_GC)
266 if (sm->hplim > sm->hp + GCInterval) {
267 sm->hplim = sm->hp + GCInterval;
270 #endif /* FORCE_GC */
272 #if defined(LIFE_PROFILE)
273 /* space for HpLim incr */
274 sm->hplim = sm->hp + ((sm->hplim - sm->hp) / 2);
276 /* set hplim for next life profile */
277 sm->hplim = sm->hp + next_interval;
279 #endif /* LIFE_PROFILE */
281 if (reqsize + sm->hardHpOverflowSize > free_space) {
282 return( GC_SOFT_LIMIT_EXCEEDED ); /* Heap nearly exhausted */
284 return( GC_SUCCESS ); /* Heap OK */