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);
113 /* -----------------------------------------------------------------------------
116 StgPtr allocate(nat n) Allocates a chunk of contiguous store
117 n words long, returning a pointer to
118 the first word. Always succeeds.
120 StgPtr allocatePinned(nat n) Allocates a chunk of contiguous store
121 n words long, which is at a fixed
122 address (won't be moved by GC).
123 Returns a pointer to the first word.
126 NOTE: the GC can't in general handle
127 pinned objects, so allocatePinned()
128 can only be used for ByteArrays at the
131 Don't forget to TICK_ALLOC_XXX(...)
132 after calling allocate or
133 allocatePinned, for the
134 benefit of the ticky-ticky profiler.
136 rtsBool doYouWantToGC(void) Returns True if the storage manager is
137 ready to perform a GC, False otherwise.
139 lnat allocated_bytes(void) Returns the number of bytes allocated
140 via allocate() since the last GC.
141 Used in the reporting of statistics.
143 SMP: allocate and doYouWantToGC can be used from STG code, they are
144 surrounded by a mutex.
145 -------------------------------------------------------------------------- */
147 extern StgPtr allocate ( nat n );
148 extern StgPtr allocateLocal ( Capability *cap, nat n );
149 extern StgPtr allocatePinned ( nat n );
150 extern lnat allocated_bytes ( void );
152 extern bdescr * RTS_VAR(small_alloc_list);
153 extern bdescr * RTS_VAR(large_alloc_list);
154 extern bdescr * RTS_VAR(pinned_object_block);
156 extern StgPtr RTS_VAR(alloc_Hp);
157 extern StgPtr RTS_VAR(alloc_HpLim);
159 extern nat RTS_VAR(alloc_blocks);
160 extern nat RTS_VAR(alloc_blocks_lim);
162 INLINE_HEADER rtsBool
163 doYouWantToGC( void )
165 return (alloc_blocks >= alloc_blocks_lim);
168 /* -----------------------------------------------------------------------------
169 Performing Garbage Collection
171 GarbageCollect(get_roots) Performs a garbage collection.
172 'get_roots' is called to find all the
173 roots that the system knows about.
175 StgClosure Called by get_roots on each root.
176 MarkRoot(StgClosure *p) Returns the new location of the root.
177 -------------------------------------------------------------------------- */
179 extern void GarbageCollect(void (*get_roots)(evac_fn),rtsBool force_major_gc);
181 /* -----------------------------------------------------------------------------
182 Generational garbage collection support
184 recordMutable(StgPtr p) Informs the garbage collector that a
185 previously immutable object has
186 become (permanently) mutable. Used
187 by thawArray and similar.
189 updateWithIndirection(p1,p2) Updates the object at p1 with an
190 indirection pointing to p2. This is
191 normally called for objects in an old
192 generation (>0) when they are updated.
194 updateWithPermIndirection(p1,p2) As above but uses a permanent indir.
196 -------------------------------------------------------------------------- */
199 * Storage manager mutex
202 extern Mutex sm_mutex;
206 #define ACQUIRE_SM_LOCK ACQUIRE_LOCK(&sm_mutex);
207 #define RELEASE_SM_LOCK RELEASE_LOCK(&sm_mutex);
208 #define ASSERT_SM_LOCK() ASSERT_LOCK_HELD(&sm_mutex);
210 #define ACQUIRE_SM_LOCK
211 #define RELEASE_SM_LOCK
212 #define ASSERT_SM_LOCK()
216 recordMutableGen(StgClosure *p, generation *gen)
221 if (bd->free >= bd->start + BLOCK_SIZE_W) {
223 new_bd = allocBlock();
228 *bd->free++ = (StgWord)p;
233 recordMutableGenLock(StgClosure *p, generation *gen)
236 recordMutableGen(p,gen);
241 recordMutable(StgClosure *p)
244 ASSERT(closure_MUTABLE(p));
246 if (bd->gen_no > 0) recordMutableGen(p, &RTS_DEREF(generations)[bd->gen_no]);
250 recordMutableLock(StgClosure *p)
257 /* -----------------------------------------------------------------------------
258 The CAF table - used to let us revert CAFs in GHCi
259 -------------------------------------------------------------------------- */
261 /* set to disable CAF garbage collection in GHCi. */
262 /* (needed when dynamic libraries are used). */
263 extern rtsBool keepCAFs;
265 /* -----------------------------------------------------------------------------
266 DEBUGGING predicates for pointers
268 LOOKS_LIKE_INFO_PTR(p) returns False if p is definitely not an info ptr
269 LOOKS_LIKE_CLOSURE_PTR(p) returns False if p is definitely not a closure ptr
271 These macros are complete but not sound. That is, they might
272 return false positives. Do not rely on them to distinguish info
273 pointers from closure pointers, for example.
275 We don't use address-space predicates these days, for portability
276 reasons, and the fact that code/data can be scattered about the
277 address space in a dynamically-linked environment. Our best option
278 is to look at the alleged info table and see whether it seems to
280 -------------------------------------------------------------------------- */
282 #define LOOKS_LIKE_INFO_PTR(p) \
283 (p && ((StgInfoTable *)(INFO_PTR_TO_STRUCT(p)))->type != INVALID_OBJECT && \
284 ((StgInfoTable *)(INFO_PTR_TO_STRUCT(p)))->type < N_CLOSURE_TYPES)
286 #define LOOKS_LIKE_CLOSURE_PTR(p) \
287 (LOOKS_LIKE_INFO_PTR(((StgClosure *)(p))->header.info))
289 /* -----------------------------------------------------------------------------
290 Macros for calculating how big a closure will be (used during allocation)
291 -------------------------------------------------------------------------- */
293 INLINE_HEADER StgOffset PAP_sizeW ( nat n_args )
294 { return sizeofW(StgPAP) + n_args; }
296 INLINE_HEADER StgOffset AP_sizeW ( nat n_args )
297 { return sizeofW(StgAP) + n_args; }
299 INLINE_HEADER StgOffset AP_STACK_sizeW ( nat size )
300 { return sizeofW(StgAP_STACK) + size; }
302 INLINE_HEADER StgOffset CONSTR_sizeW( nat p, nat np )
303 { return sizeofW(StgHeader) + p + np; }
305 INLINE_HEADER StgOffset THUNK_SELECTOR_sizeW ( void )
306 { return stg_max(sizeofW(StgHeader)+MIN_UPD_SIZE, sizeofW(StgSelector)); }
308 INLINE_HEADER StgOffset BLACKHOLE_sizeW ( void )
309 { return sizeofW(StgHeader)+MIN_UPD_SIZE; }
311 /* --------------------------------------------------------------------------
313 ------------------------------------------------------------------------*/
315 INLINE_HEADER StgOffset sizeW_fromITBL( const StgInfoTable* itbl )
316 { return sizeofW(StgClosure)
317 + sizeofW(StgPtr) * itbl->layout.payload.ptrs
318 + sizeofW(StgWord) * itbl->layout.payload.nptrs; }
320 INLINE_HEADER StgOffset thunk_sizeW_fromITBL( const StgInfoTable* itbl )
321 { return sizeofW(StgThunk)
322 + sizeofW(StgPtr) * itbl->layout.payload.ptrs
323 + sizeofW(StgWord) * itbl->layout.payload.nptrs; }
325 INLINE_HEADER StgOffset ap_stack_sizeW( StgAP_STACK* x )
326 { return AP_STACK_sizeW(x->size); }
328 INLINE_HEADER StgOffset ap_sizeW( StgAP* x )
329 { return AP_sizeW(x->n_args); }
331 INLINE_HEADER StgOffset pap_sizeW( StgPAP* x )
332 { return PAP_sizeW(x->n_args); }
334 INLINE_HEADER StgOffset arr_words_sizeW( StgArrWords* x )
335 { return sizeofW(StgArrWords) + x->words; }
337 INLINE_HEADER StgOffset mut_arr_ptrs_sizeW( StgMutArrPtrs* x )
338 { return sizeofW(StgMutArrPtrs) + x->ptrs; }
340 INLINE_HEADER StgWord tso_sizeW ( StgTSO *tso )
341 { return TSO_STRUCT_SIZEW + tso->stack_size; }
343 INLINE_HEADER StgWord bco_sizeW ( StgBCO *bco )
344 { return bco->size; }
346 /* -----------------------------------------------------------------------------
347 Sizes of stack frames
348 -------------------------------------------------------------------------- */
350 INLINE_HEADER StgWord stack_frame_sizeW( StgClosure *frame )
352 StgRetInfoTable *info;
354 info = get_ret_itbl(frame);
355 switch (info->i.type) {
359 StgRetDyn *dyn = (StgRetDyn *)frame;
360 return sizeofW(StgRetDyn) + RET_DYN_BITMAP_SIZE +
361 RET_DYN_NONPTR_REGS_SIZE +
362 RET_DYN_PTRS(dyn->liveness) + RET_DYN_NONPTRS(dyn->liveness);
366 return sizeofW(StgRetFun) + ((StgRetFun *)frame)->size;
370 return 1 + GET_LARGE_BITMAP(&info->i)->size;
373 return 2 + BCO_BITMAP_SIZE((StgBCO *)((P_)frame)[1]);
376 return 1 + BITMAP_SIZE(info->i.layout.bitmap);
380 /* -----------------------------------------------------------------------------
382 -------------------------------------------------------------------------- */
384 extern void allocNurseries ( void );
385 extern void resetNurseries ( void );
386 extern void resizeNurseries ( nat blocks );
387 extern void resizeNurseriesFixed ( nat blocks );
388 extern void tidyAllocateLists ( void );
389 extern lnat countNurseryBlocks ( void );
391 /* -----------------------------------------------------------------------------
393 -------------------------------------------------------------------------- */
395 extern void threadPaused ( StgTSO * );
396 extern StgClosure * isAlive ( StgClosure *p );
397 extern void markCAFs ( evac_fn evac );
399 /* -----------------------------------------------------------------------------
400 Stats 'n' DEBUG stuff
401 -------------------------------------------------------------------------- */
403 extern ullong RTS_VAR(total_allocated);
405 extern lnat calcAllocated ( void );
406 extern lnat calcLive ( void );
407 extern lnat calcNeeded ( void );
410 extern void memInventory(void);
411 extern void checkSanity(void);
412 extern nat countBlocks(bdescr *);
413 extern void checkNurserySanity( step *stp );
417 void printMutOnceList(generation *gen);
418 void printMutableList(generation *gen);
421 /* ----------------------------------------------------------------------------
422 Storage manager internal APIs and globals
423 ------------------------------------------------------------------------- */
425 #define END_OF_STATIC_LIST stgCast(StgClosure*,1)
427 extern void newDynCAF(StgClosure *);
429 extern void move_TSO(StgTSO *src, StgTSO *dest);
430 extern StgTSO *relocate_stack(StgTSO *dest, ptrdiff_t diff);
432 extern StgClosure * RTS_VAR(scavenged_static_objects);
433 extern StgWeak * RTS_VAR(old_weak_ptr_list);
434 extern StgWeak * RTS_VAR(weak_ptr_list);
435 extern StgClosure * RTS_VAR(caf_list);
436 extern StgClosure * RTS_VAR(revertible_caf_list);
437 extern StgTSO * RTS_VAR(resurrected_threads);
439 #endif /* STORAGE_H */