1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team, 1998-2004
5 * External Storage Manger Interface
7 * ---------------------------------------------------------------------------*/
13 #include "OSThreads.h"
15 /* -----------------------------------------------------------------------------
18 * We support an arbitrary number of generations, with an arbitrary number
19 * of steps per generation. Notes (in no particular order):
21 * - all generations except the oldest should have two steps. This gives
22 * objects a decent chance to age before being promoted, and in
23 * particular will ensure that we don't end up with too many
24 * thunks being updated in older generations.
26 * - the oldest generation has one step. There's no point in aging
27 * objects in the oldest generation.
29 * - generation 0, step 0 (G0S0) is the allocation area. It is given
30 * a fixed set of blocks during initialisation, and these blocks
33 * - during garbage collection, each step which is an evacuation
34 * destination (i.e. all steps except G0S0) is allocated a to-space.
35 * evacuated objects are allocated into the step's to-space until
36 * GC is finished, when the original step's contents may be freed
37 * and replaced by the to-space.
39 * - the mutable-list is per-generation (not per-step). G0 doesn't
40 * have one (since every garbage collection collects at least G0).
42 * - block descriptors contain pointers to both the step and the
43 * generation that the block belongs to, for convenience.
45 * - static objects are stored in per-generation lists. See GC.c for
46 * details of how we collect CAFs in the generational scheme.
48 * - large objects are per-step, and are promoted in the same way
49 * as small objects, except that we may allocate large objects into
50 * generation 1 initially.
52 * ------------------------------------------------------------------------- */
54 typedef struct step_ {
55 unsigned int no; /* step number */
56 bdescr * blocks; /* blocks in this step */
57 unsigned int n_blocks; /* number of blocks */
58 struct step_ * to; /* destination step for live objects */
59 struct generation_ * gen; /* generation this step belongs to */
60 unsigned int gen_no; /* generation number (cached) */
61 bdescr * large_objects; /* large objects (doubly linked) */
62 unsigned int n_large_blocks; /* no. of blocks used by large objs */
63 int is_compacted; /* compact this step? (old gen only) */
65 /* During GC, if we are collecting this step, blocks and n_blocks
66 * are copied into the following two fields. After GC, these blocks
68 bdescr * old_blocks; /* bdescr of first from-space block */
69 unsigned int n_old_blocks; /* number of blocks in from-space */
71 /* temporary use during GC: */
72 StgPtr hp; /* next free locn in to-space */
73 StgPtr hpLim; /* end of current to-space block */
74 bdescr * hp_bd; /* bdescr of current to-space block */
75 StgPtr scavd_hp; /* ... same as above, but already */
76 StgPtr scavd_hpLim; /* scavenged. */
77 bdescr * scan_bd; /* block currently being scanned */
78 StgPtr scan; /* scan pointer in current block */
79 bdescr * new_large_objects; /* large objects collected so far */
80 bdescr * scavenged_large_objects; /* live large objs after GC (d-link) */
81 unsigned int n_scavenged_large_blocks;/* size of above */
82 bdescr * bitmap; /* bitmap for compacting collection */
85 typedef struct generation_ {
86 unsigned int no; /* generation number */
87 step * steps; /* steps */
88 unsigned int n_steps; /* number of steps */
89 unsigned int max_blocks; /* max blocks in step 0 */
90 bdescr *mut_list; /* mut objects in this gen (not G0)*/
92 /* temporary use during GC: */
93 bdescr *saved_mut_list;
95 /* stats information */
96 unsigned int collections;
97 unsigned int failed_promotions;
100 extern generation * RTS_VAR(generations);
102 extern generation * RTS_VAR(g0);
103 extern step * RTS_VAR(g0s0);
104 extern generation * RTS_VAR(oldest_gen);
106 /* -----------------------------------------------------------------------------
107 Initialisation / De-initialisation
108 -------------------------------------------------------------------------- */
110 extern void initStorage(void);
111 extern void exitStorage(void);
112 extern void freeStorage(void);
114 /* -----------------------------------------------------------------------------
117 StgPtr allocate(nat n) Allocates a chunk of contiguous store
118 n words long, returning a pointer to
119 the first word. Always succeeds.
121 StgPtr allocateLocal(Capability *cap, nat n)
122 Allocates memory from the nursery in
123 the current Capability. This can be
124 done without taking a global lock,
127 StgPtr allocatePinned(nat n) Allocates a chunk of contiguous store
128 n words long, which is at a fixed
129 address (won't be moved by GC).
130 Returns a pointer to the first word.
133 NOTE: the GC can't in general handle
134 pinned objects, so allocatePinned()
135 can only be used for ByteArrays at the
138 Don't forget to TICK_ALLOC_XXX(...)
139 after calling allocate or
140 allocatePinned, for the
141 benefit of the ticky-ticky profiler.
143 rtsBool doYouWantToGC(void) Returns True if the storage manager is
144 ready to perform a GC, False otherwise.
146 lnat allocatedBytes(void) Returns the number of bytes allocated
147 via allocate() since the last GC.
148 Used in the reporting of statistics.
150 -------------------------------------------------------------------------- */
152 extern StgPtr allocate ( nat n );
153 extern StgPtr allocateLocal ( Capability *cap, nat n );
154 extern StgPtr allocatePinned ( nat n );
155 extern lnat allocatedBytes ( void );
157 extern bdescr * RTS_VAR(small_alloc_list);
158 extern bdescr * RTS_VAR(large_alloc_list);
159 extern bdescr * RTS_VAR(pinned_object_block);
161 extern StgPtr RTS_VAR(alloc_Hp);
162 extern StgPtr RTS_VAR(alloc_HpLim);
164 extern nat RTS_VAR(alloc_blocks);
165 extern nat RTS_VAR(alloc_blocks_lim);
167 INLINE_HEADER rtsBool
168 doYouWantToGC( void )
170 return (alloc_blocks >= alloc_blocks_lim);
173 /* memory allocator for executable memory */
174 extern void *allocateExec (nat bytes);
175 extern void freeExec (void *p);
177 /* -----------------------------------------------------------------------------
178 Performing Garbage Collection
180 GarbageCollect(get_roots) Performs a garbage collection.
181 'get_roots' is called to find all the
182 roots that the system knows about.
184 StgClosure Called by get_roots on each root.
185 MarkRoot(StgClosure *p) Returns the new location of the root.
186 -------------------------------------------------------------------------- */
188 extern void GarbageCollect(rtsBool force_major_gc);
190 /* -----------------------------------------------------------------------------
191 Generational garbage collection support
193 recordMutable(StgPtr p) Informs the garbage collector that a
194 previously immutable object has
195 become (permanently) mutable. Used
196 by thawArray and similar.
198 updateWithIndirection(p1,p2) Updates the object at p1 with an
199 indirection pointing to p2. This is
200 normally called for objects in an old
201 generation (>0) when they are updated.
203 updateWithPermIndirection(p1,p2) As above but uses a permanent indir.
205 -------------------------------------------------------------------------- */
208 * Storage manager mutex
210 #if defined(THREADED_RTS)
211 extern Mutex sm_mutex;
212 extern Mutex atomic_modify_mutvar_mutex;
215 #if defined(THREADED_RTS)
216 #define ACQUIRE_SM_LOCK ACQUIRE_LOCK(&sm_mutex);
217 #define RELEASE_SM_LOCK RELEASE_LOCK(&sm_mutex);
218 #define ASSERT_SM_LOCK() ASSERT_LOCK_HELD(&sm_mutex);
220 #define ACQUIRE_SM_LOCK
221 #define RELEASE_SM_LOCK
222 #define ASSERT_SM_LOCK()
226 recordMutableGen(StgClosure *p, generation *gen)
231 if (bd->free >= bd->start + BLOCK_SIZE_W) {
233 new_bd = allocBlock();
238 *bd->free++ = (StgWord)p;
243 recordMutableGenLock(StgClosure *p, generation *gen)
246 recordMutableGen(p,gen);
251 recordMutable(StgClosure *p)
254 ASSERT(closure_MUTABLE(p));
256 if (bd->gen_no > 0) recordMutableGen(p, &RTS_DEREF(generations)[bd->gen_no]);
260 recordMutableLock(StgClosure *p)
267 /* -----------------------------------------------------------------------------
268 The CAF table - used to let us revert CAFs in GHCi
269 -------------------------------------------------------------------------- */
271 /* set to disable CAF garbage collection in GHCi. */
272 /* (needed when dynamic libraries are used). */
273 extern rtsBool keepCAFs;
275 /* -----------------------------------------------------------------------------
276 This is the write barrier for MUT_VARs, a.k.a. IORefs. A
277 MUT_VAR_CLEAN object is not on the mutable list; a MUT_VAR_DIRTY
278 is. When written to, a MUT_VAR_CLEAN turns into a MUT_VAR_DIRTY
279 and is put on the mutable list.
280 -------------------------------------------------------------------------- */
282 void dirty_MUT_VAR(StgRegTable *reg, StgClosure *p);
284 /* -----------------------------------------------------------------------------
285 DEBUGGING predicates for pointers
287 LOOKS_LIKE_INFO_PTR(p) returns False if p is definitely not an info ptr
288 LOOKS_LIKE_CLOSURE_PTR(p) returns False if p is definitely not a closure ptr
290 These macros are complete but not sound. That is, they might
291 return false positives. Do not rely on them to distinguish info
292 pointers from closure pointers, for example.
294 We don't use address-space predicates these days, for portability
295 reasons, and the fact that code/data can be scattered about the
296 address space in a dynamically-linked environment. Our best option
297 is to look at the alleged info table and see whether it seems to
299 -------------------------------------------------------------------------- */
301 #define LOOKS_LIKE_INFO_PTR(p) \
302 (p && ((StgInfoTable *)(INFO_PTR_TO_STRUCT(p)))->type != INVALID_OBJECT && \
303 ((StgInfoTable *)(INFO_PTR_TO_STRUCT(p)))->type < N_CLOSURE_TYPES)
305 #define LOOKS_LIKE_CLOSURE_PTR(p) \
306 (LOOKS_LIKE_INFO_PTR((UNTAG_CLOSURE((StgClosure *)(p)))->header.info))
308 /* -----------------------------------------------------------------------------
309 Macros for calculating how big a closure will be (used during allocation)
310 -------------------------------------------------------------------------- */
312 INLINE_HEADER StgOffset PAP_sizeW ( nat n_args )
313 { return sizeofW(StgPAP) + n_args; }
315 INLINE_HEADER StgOffset AP_sizeW ( nat n_args )
316 { return sizeofW(StgAP) + n_args; }
318 INLINE_HEADER StgOffset AP_STACK_sizeW ( nat size )
319 { return sizeofW(StgAP_STACK) + size; }
321 INLINE_HEADER StgOffset CONSTR_sizeW( nat p, nat np )
322 { return sizeofW(StgHeader) + p + np; }
324 INLINE_HEADER StgOffset THUNK_SELECTOR_sizeW ( void )
325 { return sizeofW(StgSelector); }
327 INLINE_HEADER StgOffset BLACKHOLE_sizeW ( void )
328 { return sizeofW(StgHeader)+MIN_PAYLOAD_SIZE; }
330 /* --------------------------------------------------------------------------
332 ------------------------------------------------------------------------*/
334 INLINE_HEADER StgOffset sizeW_fromITBL( const StgInfoTable* itbl )
335 { return sizeofW(StgClosure)
336 + sizeofW(StgPtr) * itbl->layout.payload.ptrs
337 + sizeofW(StgWord) * itbl->layout.payload.nptrs; }
339 INLINE_HEADER StgOffset thunk_sizeW_fromITBL( const StgInfoTable* itbl )
340 { return sizeofW(StgThunk)
341 + sizeofW(StgPtr) * itbl->layout.payload.ptrs
342 + sizeofW(StgWord) * itbl->layout.payload.nptrs; }
344 INLINE_HEADER StgOffset ap_stack_sizeW( StgAP_STACK* x )
345 { return AP_STACK_sizeW(x->size); }
347 INLINE_HEADER StgOffset ap_sizeW( StgAP* x )
348 { return AP_sizeW(x->n_args); }
350 INLINE_HEADER StgOffset pap_sizeW( StgPAP* x )
351 { return PAP_sizeW(x->n_args); }
353 INLINE_HEADER StgOffset arr_words_sizeW( StgArrWords* x )
354 { return sizeofW(StgArrWords) + x->words; }
356 INLINE_HEADER StgOffset mut_arr_ptrs_sizeW( StgMutArrPtrs* x )
357 { return sizeofW(StgMutArrPtrs) + x->ptrs; }
359 INLINE_HEADER StgWord tso_sizeW ( StgTSO *tso )
360 { return TSO_STRUCT_SIZEW + tso->stack_size; }
362 INLINE_HEADER StgWord bco_sizeW ( StgBCO *bco )
363 { return bco->size; }
366 closure_sizeW_ (StgClosure *p, StgInfoTable *info)
368 switch (info->type) {
371 return sizeofW(StgThunk) + 1;
376 return sizeofW(StgHeader) + 1;
380 return sizeofW(StgThunk) + 2;
387 return sizeofW(StgHeader) + 2;
389 return thunk_sizeW_fromITBL(info);
391 return THUNK_SELECTOR_sizeW();
393 return ap_stack_sizeW((StgAP_STACK *)p);
395 return ap_sizeW((StgAP *)p);
397 return pap_sizeW((StgPAP *)p);
401 case IND_OLDGEN_PERM:
402 return sizeofW(StgInd);
404 return arr_words_sizeW((StgArrWords *)p);
405 case MUT_ARR_PTRS_CLEAN:
406 case MUT_ARR_PTRS_DIRTY:
407 case MUT_ARR_PTRS_FROZEN:
408 case MUT_ARR_PTRS_FROZEN0:
409 return mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
411 return tso_sizeW((StgTSO *)p);
413 return bco_sizeW((StgBCO *)p);
414 case TVAR_WATCH_QUEUE:
415 return sizeofW(StgTVarWatchQueue);
417 return sizeofW(StgTVar);
419 return sizeofW(StgTRecChunk);
421 return sizeofW(StgTRecHeader);
422 case ATOMIC_INVARIANT:
423 return sizeofW(StgAtomicInvariant);
424 case INVARIANT_CHECK_QUEUE:
425 return sizeofW(StgInvariantCheckQueue);
427 return sizeW_fromITBL(info);
431 // The definitive way to find the size, in words, of a heap-allocated closure
433 closure_sizeW (StgClosure *p)
435 return closure_sizeW_(p, get_itbl(p));
438 /* -----------------------------------------------------------------------------
439 Sizes of stack frames
440 -------------------------------------------------------------------------- */
442 INLINE_HEADER StgWord stack_frame_sizeW( StgClosure *frame )
444 StgRetInfoTable *info;
446 info = get_ret_itbl(frame);
447 switch (info->i.type) {
451 StgRetDyn *dyn = (StgRetDyn *)frame;
452 return sizeofW(StgRetDyn) + RET_DYN_BITMAP_SIZE +
453 RET_DYN_NONPTR_REGS_SIZE +
454 RET_DYN_PTRS(dyn->liveness) + RET_DYN_NONPTRS(dyn->liveness);
458 return sizeofW(StgRetFun) + ((StgRetFun *)frame)->size;
461 return 1 + GET_LARGE_BITMAP(&info->i)->size;
464 return 2 + BCO_BITMAP_SIZE((StgBCO *)((P_)frame)[1]);
467 return 1 + BITMAP_SIZE(info->i.layout.bitmap);
471 /* -----------------------------------------------------------------------------
473 -------------------------------------------------------------------------- */
475 extern void allocNurseries ( void );
476 extern void resetNurseries ( void );
477 extern void resizeNurseries ( nat blocks );
478 extern void resizeNurseriesFixed ( nat blocks );
479 extern void tidyAllocateLists ( void );
480 extern lnat countNurseryBlocks ( void );
482 /* -----------------------------------------------------------------------------
484 -------------------------------------------------------------------------- */
486 typedef void (*evac_fn)(StgClosure **);
488 extern void threadPaused ( Capability *cap, StgTSO * );
489 extern StgClosure * isAlive ( StgClosure *p );
490 extern void markCAFs ( evac_fn evac );
492 /* -----------------------------------------------------------------------------
493 Stats 'n' DEBUG stuff
494 -------------------------------------------------------------------------- */
496 extern ullong RTS_VAR(total_allocated);
498 extern lnat calcAllocated ( void );
499 extern lnat calcLive ( void );
500 extern lnat calcNeeded ( void );
503 extern void memInventory(void);
504 extern void checkSanity(void);
505 extern nat countBlocks(bdescr *);
506 extern void checkNurserySanity( step *stp );
510 void printMutOnceList(generation *gen);
511 void printMutableList(generation *gen);
514 /* ----------------------------------------------------------------------------
515 Storage manager internal APIs and globals
516 ------------------------------------------------------------------------- */
518 #define END_OF_STATIC_LIST stgCast(StgClosure*,1)
520 extern void newDynCAF(StgClosure *);
522 extern void move_TSO(StgTSO *src, StgTSO *dest);
523 extern StgTSO *relocate_stack(StgTSO *dest, ptrdiff_t diff);
525 extern StgClosure * RTS_VAR(scavenged_static_objects);
526 extern StgWeak * RTS_VAR(old_weak_ptr_list);
527 extern StgWeak * RTS_VAR(weak_ptr_list);
528 extern StgClosure * RTS_VAR(caf_list);
529 extern StgClosure * RTS_VAR(revertible_caf_list);
530 extern StgTSO * RTS_VAR(resurrected_threads);
532 #endif /* STORAGE_H */