d57057b93af4f60ab905af7702ba09d3997a2649
[ghc-hetmet.git] / ghc / rts / Storage.h
1 /* -----------------------------------------------------------------------------
2  * $Id: Storage.h,v 1.38 2002/01/25 16:35:29 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * External Storage Manger Interface
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #ifndef STORAGE_H
11 #define STORAGE_H
12
13 #include "Block.h"
14 #include "BlockAlloc.h"
15 #include "StoragePriv.h"
16 #ifdef PROFILING
17 #include "LdvProfile.h"
18 #endif
19
20 /* -----------------------------------------------------------------------------
21    Initialisation / De-initialisation
22    -------------------------------------------------------------------------- */
23
24 extern void initStorage(void);
25 extern void exitStorage(void);
26
27 /* -----------------------------------------------------------------------------
28    Generic allocation
29
30    StgPtr allocate(nat n)       Allocates a chunk of contiguous store
31                                 n words long, returning a pointer to
32                                 the first word.  Always succeeds.
33                                 
34    StgPtr allocatePinned(nat n) Allocates a chunk of contiguous store
35                                 n words long, which is at a fixed
36                                 address (won't be moved by GC).  
37                                 Returns a pointer to the first word.
38                                 Always succeeds.
39                                 
40                                 NOTE: the GC can't in general handle
41                                 pinned objects, so allocatePinned()
42                                 can only be used for ByteArrays at the
43                                 moment.
44
45                                 Don't forget to TICK_ALLOC_XXX(...)
46                                 after calling allocate or
47                                 allocatePinned, for the
48                                 benefit of the ticky-ticky profiler.
49
50    rtsBool doYouWantToGC(void)  Returns True if the storage manager is
51                                 ready to perform a GC, False otherwise.
52
53    lnat  allocated_bytes(void)  Returns the number of bytes allocated
54                                 via allocate() since the last GC.
55                                 Used in the reoprting of statistics.
56
57    SMP: allocate and doYouWantToGC can be used from STG code, they are
58    surrounded by a mutex.
59    -------------------------------------------------------------------------- */
60
61 extern StgPtr  allocate        ( nat n );
62 extern StgPtr  allocatePinned  ( nat n );
63 extern lnat    allocated_bytes ( void );
64
65 static inline rtsBool
66 doYouWantToGC( void )
67 {
68   return (alloc_blocks >= alloc_blocks_lim);
69 }
70
71 /* -----------------------------------------------------------------------------
72    ExtendNursery(hp,hplim)      When hplim is reached, try to grab
73                                 some more allocation space.  Returns
74                                 False if the allocation space is
75                                 exhausted, and the application should
76                                 call GarbageCollect().
77   -------------------------------------------------------------------------- */
78
79 #define ExtendNursery(hp,hplim)                 \
80   (CurrentNursery->free = (P_)(hp)+1,           \
81    CurrentNursery->link == NULL ? rtsFalse :    \
82    (CurrentNursery = CurrentNursery->link,      \
83     OpenNursery(hp,hplim),                      \
84     rtsTrue))
85
86 extern void PleaseStopAllocating(void);
87
88 /* -----------------------------------------------------------------------------
89    Performing Garbage Collection
90
91    GarbageCollect(get_roots)    Performs a garbage collection.  
92                                 'get_roots' is called to find all the 
93                                 roots that the system knows about.
94
95    StgClosure                   Called by get_roots on each root.       
96    MarkRoot(StgClosure *p)      Returns the new location of the root.
97    -------------------------------------------------------------------------- */
98
99 extern void GarbageCollect(void (*get_roots)(evac_fn),rtsBool force_major_gc);
100
101 /* -----------------------------------------------------------------------------
102    Generational garbage collection support
103
104    recordMutable(StgPtr p)       Informs the garbage collector that a
105                                  previously immutable object has
106                                  become (permanently) mutable.  Used
107                                  by thawArray and similar.
108
109    updateWithIndirection(p1,p2)  Updates the object at p1 with an
110                                  indirection pointing to p2.  This is
111                                  normally called for objects in an old
112                                  generation (>0) when they are updated.
113
114    updateWithPermIndirection(p1,p2)  As above but uses a permanent indir.
115
116    -------------------------------------------------------------------------- */
117
118 /*
119  * Storage manager mutex
120  */
121 #ifdef SMP
122 extern pthread_mutex_t sm_mutex;
123 #endif
124
125 /* ToDo: shouldn't recordMutable and recordOldToNewPtrs acquire some
126  * kind of lock in the SMP case?
127  */
128 static inline void
129 recordMutable(StgMutClosure *p)
130 {
131   bdescr *bd;
132
133 #ifdef SMP
134   ASSERT(p->header.info == &stg_WHITEHOLE_info || closure_MUTABLE(p));
135 #else
136   ASSERT(closure_MUTABLE(p));
137 #endif
138
139   bd = Bdescr((P_)p);
140   if (bd->gen_no > 0) {
141     p->mut_link = generations[bd->gen_no].mut_list;
142     generations[bd->gen_no].mut_list = p;
143   }
144 }
145
146 static inline void
147 recordOldToNewPtrs(StgMutClosure *p)
148 {
149   bdescr *bd;
150   
151   bd = Bdescr((P_)p);
152   if (bd->gen_no > 0) {
153     p->mut_link = generations[bd->gen_no].mut_once_list;
154     generations[bd->gen_no].mut_once_list = p;
155   }
156 }
157
158 // @LDV profiling
159 // We zero out the slop when PROFILING is on.
160 // #ifndef DEBUG
161 #if !defined(DEBUG) && !defined(PROFILING)
162 #define updateWithIndirection(info, p1, p2)                             \
163   {                                                                     \
164     bdescr *bd;                                                         \
165                                                                         \
166     bd = Bdescr((P_)p1);                                                \
167     if (bd->gen_no == 0) {                                              \
168       ((StgInd *)p1)->indirectee = p2;                                  \
169       SET_INFO(p1,&stg_IND_info);                                       \
170       TICK_UPD_NEW_IND();                                               \
171     } else {                                                            \
172       ((StgIndOldGen *)p1)->indirectee = p2;                            \
173       if (info != &stg_BLACKHOLE_BQ_info) {                             \
174         ACQUIRE_LOCK(&sm_mutex);                                        \
175         ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list; \
176         generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;                    \
177         RELEASE_LOCK(&sm_mutex);                                        \
178       }                                                                 \
179       SET_INFO(p1,&stg_IND_OLDGEN_info);                                \
180       TICK_UPD_OLD_IND();                                               \
181     }                                                                   \
182   }
183 #elif defined(PROFILING)
184 // @LDV profiling
185 // We call LDV_recordDead_FILL_SLOP_DYNAMIC(p1) regardless of the generation in 
186 // which p1 resides.
187 //
188 // Note: 
189 //   After all, we do *NOT* need to call LDV_recordCreate() for both IND and 
190 //   IND_OLDGEN closures because they are inherently used. But, it corrupts
191 //   the invariants that every closure keeps its creation time in the profiling
192 //   field. So, we call LDV_recordCreate().
193
194 #define updateWithIndirection(info, p1, p2)                             \
195   {                                                                     \
196     bdescr *bd;                                                         \
197                                                                         \
198     LDV_recordDead_FILL_SLOP_DYNAMIC((p1));                             \
199     bd = Bdescr((P_)p1);                                                \
200     if (bd->gen_no == 0) {                                              \
201       ((StgInd *)p1)->indirectee = p2;                                  \
202       SET_INFO(p1,&stg_IND_info);                                       \
203       LDV_recordCreate((p1));                                           \
204       TICK_UPD_NEW_IND();                                               \
205     } else {                                                            \
206       ((StgIndOldGen *)p1)->indirectee = p2;                            \
207       if (info != &stg_BLACKHOLE_BQ_info) {                             \
208         ACQUIRE_LOCK(&sm_mutex);                                        \
209         ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list; \
210         generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;    \
211         RELEASE_LOCK(&sm_mutex);                                        \
212       }                                                                 \
213       SET_INFO(p1,&stg_IND_OLDGEN_info);                                \
214       LDV_recordCreate((p1));                                           \
215     }                                                                   \
216   }
217
218 #else
219
220 /* In the DEBUG case, we also zero out the slop of the old closure,
221  * so that the sanity checker can tell where the next closure is.
222  *
223  * Two important invariants: we should never try to update a closure
224  * to point to itself, and the closure being updated should not
225  * already have been updated (the mutable list will get messed up
226  * otherwise).
227  */
228 #define updateWithIndirection(info, p1, p2)                             \
229   {                                                                     \
230     bdescr *bd;                                                         \
231                                                                         \
232     ASSERT( p1 != p2 && !closure_IND(p1) );                             \
233     bd = Bdescr((P_)p1);                                                \
234     if (bd->gen_no == 0) {                                              \
235       ((StgInd *)p1)->indirectee = p2;                                  \
236       SET_INFO(p1,&stg_IND_info);                                       \
237       TICK_UPD_NEW_IND();                                               \
238     } else {                                                            \
239       if (info != &stg_BLACKHOLE_BQ_info) {                             \
240         {                                                               \
241           StgInfoTable *inf = get_itbl(p1);                             \
242           nat np = inf->layout.payload.ptrs,                            \
243               nw = inf->layout.payload.nptrs, i;                        \
244           if (inf->type != THUNK_SELECTOR) {                            \
245              for (i = np; i < np + nw; i++) {                           \
246                 ((StgClosure *)p1)->payload[i] = 0;                     \
247              }                                                          \
248           }                                                             \
249         }                                                               \
250         ACQUIRE_LOCK(&sm_mutex);                                        \
251         ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list; \
252         generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;                    \
253         RELEASE_LOCK(&sm_mutex);                                        \
254       }                                                                 \
255       ((StgIndOldGen *)p1)->indirectee = p2;                            \
256       SET_INFO(p1,&stg_IND_OLDGEN_info);                                \
257       TICK_UPD_OLD_IND();                                               \
258     }                                                                   \
259   }
260 #endif
261
262 /* Static objects all live in the oldest generation
263  */
264 #define updateWithStaticIndirection(info, p1, p2)                       \
265   {                                                                     \
266     ASSERT( p1 != p2 && !closure_IND(p1) );                             \
267     ASSERT( ((StgMutClosure*)p1)->mut_link == NULL );                   \
268                                                                         \
269     ACQUIRE_LOCK(&sm_mutex);                                            \
270     ((StgMutClosure *)p1)->mut_link = oldest_gen->mut_once_list;        \
271     oldest_gen->mut_once_list = (StgMutClosure *)p1;                    \
272     RELEASE_LOCK(&sm_mutex);                                            \
273                                                                         \
274     ((StgInd *)p1)->indirectee = p2;                                    \
275     SET_INFO((StgInd *)p1, &stg_IND_STATIC_info);                       \
276     TICK_UPD_STATIC_IND();                                              \
277   }
278
279 #if defined(TICKY_TICKY) || defined(PROFILING)
280 static inline void
281 updateWithPermIndirection(const StgInfoTable *info, StgClosure *p1, StgClosure *p2) 
282 {
283   bdescr *bd;
284
285   ASSERT( p1 != p2 && !closure_IND(p1) );
286
287 #ifdef PROFILING
288   // @LDV profiling
289   // Destroy the old closure.
290   // Nb: LDV_* stuff cannot mix with ticky-ticky
291   LDV_recordDead_FILL_SLOP_DYNAMIC(p1);
292 #endif
293   bd = Bdescr((P_)p1);
294   if (bd->gen_no == 0) {
295     ((StgInd *)p1)->indirectee = p2;
296     SET_INFO(p1,&stg_IND_PERM_info);
297 #ifdef PROFILING
298     // @LDV profiling
299     // We have just created a new closure.
300     LDV_recordCreate(p1);
301 #endif
302     TICK_UPD_NEW_PERM_IND(p1);
303   } else {
304     ((StgIndOldGen *)p1)->indirectee = p2;
305     if (info != &stg_BLACKHOLE_BQ_info) {
306       ACQUIRE_LOCK(&sm_mutex);
307       ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list;
308       generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;
309       RELEASE_LOCK(&sm_mutex);
310     }
311     SET_INFO(p1,&stg_IND_OLDGEN_PERM_info);
312 #ifdef PROFILING
313     // @LDV profiling
314     // We have just created a new closure.
315     LDV_recordCreate(p1);
316 #endif
317     TICK_UPD_OLD_PERM_IND();
318   }
319 }
320 #endif
321
322 /* -----------------------------------------------------------------------------
323    The CAF table - used to let us revert CAFs
324    -------------------------------------------------------------------------- */
325
326 void revertCAFs( void );
327
328 #if defined(DEBUG)
329 void printMutOnceList(generation *gen);
330 void printMutableList(generation *gen);
331 #endif /* DEBUG */
332
333 /* --------------------------------------------------------------------------
334                       Address space layout macros
335    --------------------------------------------------------------------------
336
337    Here are the assumptions GHC makes about address space layout.
338    Broadly, it thinks there are three sections:
339
340      CODE    Read-only.  Contains code and read-only data (such as
341                 info tables)
342              Also called "text"
343
344      DATA    Read-write data.  Contains static closures (and on some
345                 architectures, info tables too)
346
347      HEAP    Dynamically-allocated closures
348
349      USER    None of the above.  The only way USER things arise right 
350              now is when GHCi allocates a constructor info table, which
351              it does by mallocing them.
352
353    Three macros identify these three areas:
354      IS_CODE(p), IS_DATA(p), HEAP_ALLOCED(p)
355
356    HEAP_ALLOCED is called FOR EVERY SINGLE CLOSURE during GC.
357    It needs to be FAST.
358
359    Implementation of HEAP_ALLOCED
360    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
361    Concerning HEAP, most of the time (certainly under [Static] and [GHCi],
362    we ensure that the heap is allocated above some fixed address HEAP_BASE
363    (defined in MBlock.h).  In this case we set TEXT_BEFORE_HEAP, and we
364    get a nice fast test.
365
366    Sometimes we can't be quite sure.  For example in Windows, we can't 
367    fix where our heap address space comes from.  In this case we un-set 
368    TEXT_BEFORE_HEAP. That makes it more expensive to test whether a pointer
369    comes from the HEAP section, because we need to look at the allocator's
370    address maps (see HEAP_ALLOCED macro)
371
372    Implementation of CODE and DATA
373    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
374    Concerning CODE and DATA, there are three main regimes:
375
376      [Static] Totally      The segments are contiguous, and laid out 
377      statically linked     exactly as above
378
379      [GHCi] Static,        GHCi may load new modules, but it knows the
380      except for GHCi       address map, so for any given address it can
381                            still tell which section it belongs to
382
383      [DLL] OS-supported    Chunks of CODE and DATA may be mixed in 
384      dynamic loading       the address space, and we can't tell how
385
386
387    For the [Static] case, we assume memory is laid out like this
388    (in order of increasing addresses)
389
390        Start of memory
391            CODE section
392        TEXT_SECTION_END_MARKER   (usually _etext)
393            DATA section
394        DATA_SECTION_END_MARKER   (usually _end)
395            USER section
396        HEAP_BASE
397            HEAP section
398
399    For the [GHCi] case, we have to consult GHCi's dynamic linker's
400    address maps, which is done by macros
401          is_dynamically_loaded_code_or_rodata_ptr
402          is_dynamically_loaded_code_or_rwdata_ptr
403
404    For the [DLL] case, IS_CODE and IS_DATA are really not usable at all.
405  */
406
407
408 #undef TEXT_BEFORE_HEAP
409 #ifndef mingw32_TARGET_OS
410 #define TEXT_BEFORE_HEAP 1
411 #endif
412
413 extern void* TEXT_SECTION_END_MARKER_DECL;
414 extern void* DATA_SECTION_END_MARKER_DECL;
415
416 /* Take into account code sections in dynamically loaded object files. */
417 #define IS_CODE_PTR(p) (  ((P_)(p) < (P_)&TEXT_SECTION_END_MARKER) \
418                        || is_dynamically_loaded_code_or_rodata_ptr((char *)p) )
419 #define IS_DATA_PTR(p) ( ((P_)(p) >= (P_)&TEXT_SECTION_END_MARKER && \
420                           (P_)(p) < (P_)&DATA_SECTION_END_MARKER) \
421                        || is_dynamically_loaded_rwdata_ptr((char *)p) )
422 #define IS_USER_PTR(p) ( ((P_)(p) >= (P_)&DATA_SECTION_END_MARKER) \
423                        && is_not_dynamically_loaded_ptr((char *)p) )
424
425 /* The HEAP_ALLOCED test below is called FOR EVERY SINGLE CLOSURE
426  * during GC.  It needs to be FAST.
427  *
428  * BEWARE: when we're dynamically loading code (for GHCi), make sure
429  * that we don't load any code above HEAP_BASE, or this test won't work.
430  */
431 #ifdef TEXT_BEFORE_HEAP
432 # define HEAP_ALLOCED(x)  ((StgPtr)(x) >= (StgPtr)(HEAP_BASE))
433 #else
434 extern int is_heap_alloced(const void* x);
435 # define HEAP_ALLOCED(x)  (is_heap_alloced(x))
436 #endif
437
438
439 /* --------------------------------------------------------------------------
440    Macros for distinguishing data pointers from code pointers
441    --------------------------------------------------------------------------
442
443   Specification
444   ~~~~~~~~~~~~~
445   The garbage collector needs to make some critical distinctions between pointers.
446   In particular we need
447  
448      LOOKS_LIKE_GHC_INFO(p)          p points to an info table
449
450   For both of these macros, p is
451       *either* a pointer to a closure (static or heap allocated)
452       *or* a return address on the (Haskell) stack
453
454   (Return addresses are in fact info-pointers, so that the Haskell stack
455   looks very like a chunk of heap.)
456
457   The garbage collector uses LOOKS_LIKE_GHC_INFO when walking the stack, as it
458   walks over the "pending arguments" on its way to the next return address.
459   It is called moderately often, but not as often as HEAP_ALLOCED
460
461   ToDo: LOOKS_LIKE_GHC_INFO(p) does not return True when p points to a
462   constructor info table allocated by GHCi.  We should really rename 
463   LOOKS_LIKE_GHC_INFO to LOOKS_LIKE_GHC_RETURN_INFO.
464
465   Implementation
466   ~~~~~~~~~~~~~~
467   LOOKS_LIKE_GHC_INFO is more complicated because of the need to distinguish 
468   between static closures and info tables.  It's a known portability problem.
469   We have three approaches:
470
471   Plan A: Address-space partitioning.  
472     Keep info tables in the (single, contiguous) text segment:    IS_CODE_PTR(p)
473     and static closures in the (single, contiguous) data segment: IS_DATA_PTR(p)
474
475   Plan A can fail for two reasons:
476     * In many environments (eg. dynamic loading),
477       text and data aren't in a single contiguous range.  
478     * When we compile through vanilla C (no mangling) we sometimes
479       can't guaranteee to put info tables in the text section.  This
480       happens eg. on MacOS where the C compiler refuses to put const
481       data in the text section if it has any code pointers in it
482       (which info tables do *only* when we're compiling without
483       TABLES_NEXT_TO_CODE).
484     
485   Hence, Plan B: (compile-via-C-with-mangling, or native code generation)
486     Put a zero word before each static closure.
487     When compiling to native code, or via C-with-mangling, info tables
488     are laid out "backwards" from the address specified in the info pointer
489     (the entry code goes forward from the info pointer).  Hence, the word
490     before the one referenced the info pointer is part of the info table,
491     and is guaranteed non-zero.
492
493     For reasons nobody seems to fully understand, the statically-allocated tables
494     of INTLIKE and CHARLIKE closures can't have this zero word, so we
495     have to test separately for them.
496
497     Plan B fails altogether for the compile-through-vanilla-C route, because
498     info tables aren't laid out backwards.
499
500
501   Hence, Plan C: (unregisterised, compile-through-vanilla-C route only)
502     If we didn't manage to get info tables into the text section, then
503     we can distinguish between a static closure pointer and an info
504     pointer as follows:  the first word of an info table is a code pointer,
505     and therefore in text space, whereas the first word of a closure pointer
506     is an info pointer, and therefore not.  Shazam!
507 */
508
509
510 /* When working with Win32 DLLs, static closures are identified by
511    being prefixed with a zero word. This is needed so that we can
512    distinguish between pointers to static closures and (reversed!)
513    info tables.
514
515    This 'scheme' breaks down for closure tables such as CHARLIKE,
516    so we catch these separately.
517   
518    LOOKS_LIKE_STATIC_CLOSURE() 
519        - discriminates between static closures and info tbls
520          (needed by LOOKS_LIKE_GHC_INFO() below - [Win32 DLLs only.])
521    LOOKS_LIKE_STATIC() 
522        - distinguishes between static and heap allocated data.
523  */
524 #if defined(ENABLE_WIN32_DLL_SUPPORT)
525             /* definitely do not enable for mingw DietHEP */
526 #define LOOKS_LIKE_STATIC(r) (!(HEAP_ALLOCED(r)))
527
528 /* Tiresome predicates needed to check for pointers into the closure tables */
529 #define IS_CHARLIKE_CLOSURE(p) \
530     ( (P_)(p) >= (P_)stg_CHARLIKE_closure && \
531       (char*)(p) <= ((char*)stg_CHARLIKE_closure + \
532                      (MAX_CHARLIKE-MIN_CHARLIKE) * sizeof(StgIntCharlikeClosure)) )
533 #define IS_INTLIKE_CLOSURE(p) \
534     ( (P_)(p) >= (P_)stg_INTLIKE_closure && \
535       (char*)(p) <= ((char*)stg_INTLIKE_closure + \
536                      (MAX_INTLIKE-MIN_INTLIKE) * sizeof(StgIntCharlikeClosure)) )
537
538 #define LOOKS_LIKE_STATIC_CLOSURE(r) (((*(((unsigned long *)(r))-1)) == 0) || IS_CHARLIKE_CLOSURE(r) || IS_INTLIKE_CLOSURE(r))
539 #else
540 #define LOOKS_LIKE_STATIC(r) IS_DATA_PTR(r)
541 #define LOOKS_LIKE_STATIC_CLOSURE(r) IS_DATA_PTR(r)
542 #endif
543
544
545 /* -----------------------------------------------------------------------------
546    Macros for distinguishing infotables from closures.
547    
548    You'd think it'd be easy to tell an info pointer from a closure pointer:
549    closures live on the heap and infotables are in read only memory.  Right?
550    Wrong!  Static closures live in read only memory and Hugs allocates
551    infotables for constructors on the (writable) C heap.
552    -------------------------------------------------------------------------- */
553
554 /* not accurate by any means, but stops the assertions failing... */
555 /* TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO */
556 #define IS_HUGS_CONSTR_INFO(info)  IS_USER_PTR(info)
557
558 /* LOOKS_LIKE_GHC_INFO is called moderately often during GC, but
559  * Certainly not as often as HEAP_ALLOCED.
560  */
561 #ifdef TEXT_BEFORE_HEAP /* needed for mingw DietHEP */
562 # define LOOKS_LIKE_GHC_INFO(info) IS_CODE_PTR(info)
563 #else
564 # define LOOKS_LIKE_GHC_INFO(info) (!HEAP_ALLOCED(info) \
565                                     && !LOOKS_LIKE_STATIC_CLOSURE(info))
566 #endif
567
568
569 /* -----------------------------------------------------------------------------
570    Macros for calculating how big a closure will be (used during allocation)
571    -------------------------------------------------------------------------- */
572
573 static __inline__ StgOffset AP_sizeW    ( nat n_args )              
574 { return sizeofW(StgAP_UPD) + n_args; }
575
576 static __inline__ StgOffset PAP_sizeW   ( nat n_args )              
577 { return sizeofW(StgPAP)    + n_args; }
578
579 static __inline__ StgOffset CONSTR_sizeW( nat p, nat np )  
580 { return sizeofW(StgHeader) + p + np; }
581
582 static __inline__ StgOffset THUNK_SELECTOR_sizeW ( void )                    
583 { return sizeofW(StgHeader) + MIN_UPD_SIZE; }
584
585 static __inline__ StgOffset BLACKHOLE_sizeW ( void )                    
586 { return sizeofW(StgHeader) + MIN_UPD_SIZE; }
587
588 /* --------------------------------------------------------------------------
589  * Sizes of closures
590  * ------------------------------------------------------------------------*/
591
592 static __inline__ StgOffset sizeW_fromITBL( const StgInfoTable* itbl ) 
593 { return sizeofW(StgClosure) 
594        + sizeofW(StgPtr)  * itbl->layout.payload.ptrs 
595        + sizeofW(StgWord) * itbl->layout.payload.nptrs; }
596
597 static __inline__ StgOffset pap_sizeW( StgPAP* x )
598 { return PAP_sizeW(x->n_args); }
599
600 static __inline__ StgOffset arr_words_sizeW( StgArrWords* x )
601 { return sizeofW(StgArrWords) + x->words; }
602
603 static __inline__ StgOffset mut_arr_ptrs_sizeW( StgMutArrPtrs* x )
604 { return sizeofW(StgMutArrPtrs) + x->ptrs; }
605
606 static __inline__ StgWord tso_sizeW ( StgTSO *tso )
607 { return TSO_STRUCT_SIZEW + tso->stack_size; }
608
609 #endif /* STORAGE_H */
610