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