Add a write barrier to the TSO link field (#1589)
[ghc-hetmet.git] / rts / sm / Storage.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2008
4  *
5  * Storage manager front end
6  *
7  * Documentation on the architecture of the Storage Manager can be
8  * found in the online commentary:
9  * 
10  *   http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage
11  *
12  * ---------------------------------------------------------------------------*/
13
14 #include "PosixSource.h"
15 #include "Rts.h"
16 #include "RtsUtils.h"
17 #include "RtsFlags.h"
18 #include "Stats.h"
19 #include "Hooks.h"
20 #include "BlockAlloc.h"
21 #include "MBlock.h"
22 #include "Weak.h"
23 #include "Sanity.h"
24 #include "Arena.h"
25 #include "OSThreads.h"
26 #include "Capability.h"
27 #include "Storage.h"
28 #include "Schedule.h"
29 #include "RetainerProfile.h"    // for counting memory blocks (memInventory)
30 #include "OSMem.h"
31 #include "Trace.h"
32 #include "GC.h"
33 #include "Evac.h"
34
35 #include <stdlib.h>
36 #include <string.h>
37
38 /* 
39  * All these globals require sm_mutex to access in THREADED_RTS mode.
40  */
41 StgClosure    *caf_list         = NULL;
42 StgClosure    *revertible_caf_list = NULL;
43 rtsBool       keepCAFs;
44
45 bdescr *pinned_object_block;    /* allocate pinned objects into this block */
46 nat alloc_blocks;               /* number of allocate()d blocks since GC */
47 nat alloc_blocks_lim;           /* approximate limit on alloc_blocks */
48
49 generation *generations = NULL; /* all the generations */
50 generation *g0          = NULL; /* generation 0, for convenience */
51 generation *oldest_gen  = NULL; /* oldest generation, for convenience */
52 step *g0s0              = NULL; /* generation 0, step 0, for convenience */
53
54 nat total_steps         = 0;
55 step *all_steps         = NULL; /* single array of steps */
56
57 ullong total_allocated = 0;     /* total memory allocated during run */
58
59 nat n_nurseries         = 0;    /* == RtsFlags.ParFlags.nNodes, convenience */
60 step *nurseries         = NULL; /* array of nurseries, >1 only if THREADED_RTS */
61
62 #ifdef THREADED_RTS
63 /*
64  * Storage manager mutex:  protects all the above state from
65  * simultaneous access by two STG threads.
66  */
67 Mutex sm_mutex;
68 /*
69  * This mutex is used by atomicModifyMutVar# only
70  */
71 Mutex atomic_modify_mutvar_mutex;
72 #endif
73
74
75 /*
76  * Forward references
77  */
78 static void *stgAllocForGMP   (size_t size_in_bytes);
79 static void *stgReallocForGMP (void *ptr, size_t old_size, size_t new_size);
80 static void  stgDeallocForGMP (void *ptr, size_t size);
81
82 static void
83 initStep (step *stp, int g, int s)
84 {
85     stp->no = s;
86     stp->abs_no = RtsFlags.GcFlags.steps * g + s;
87     stp->blocks = NULL;
88     stp->n_blocks = 0;
89     stp->n_words = 0;
90     stp->old_blocks = NULL;
91     stp->n_old_blocks = 0;
92     stp->gen = &generations[g];
93     stp->gen_no = g;
94     stp->large_objects = NULL;
95     stp->n_large_blocks = 0;
96     stp->scavenged_large_objects = NULL;
97     stp->n_scavenged_large_blocks = 0;
98     stp->is_compacted = 0;
99     stp->bitmap = NULL;
100 #ifdef THREADED_RTS
101     initSpinLock(&stp->sync_todo);
102     initSpinLock(&stp->sync_large_objects);
103 #endif
104 }
105
106 void
107 initStorage( void )
108 {
109   nat g, s;
110   generation *gen;
111
112   if (generations != NULL) {
113       // multi-init protection
114       return;
115   }
116
117   initMBlocks();
118
119   /* Sanity check to make sure the LOOKS_LIKE_ macros appear to be
120    * doing something reasonable.
121    */
122   /* We use the NOT_NULL variant or gcc warns that the test is always true */
123   ASSERT(LOOKS_LIKE_INFO_PTR_NOT_NULL(&stg_BLACKHOLE_info));
124   ASSERT(LOOKS_LIKE_CLOSURE_PTR(&stg_dummy_ret_closure));
125   ASSERT(!HEAP_ALLOCED(&stg_dummy_ret_closure));
126   
127   if (RtsFlags.GcFlags.maxHeapSize != 0 &&
128       RtsFlags.GcFlags.heapSizeSuggestion > 
129       RtsFlags.GcFlags.maxHeapSize) {
130     RtsFlags.GcFlags.maxHeapSize = RtsFlags.GcFlags.heapSizeSuggestion;
131   }
132
133   if (RtsFlags.GcFlags.maxHeapSize != 0 &&
134       RtsFlags.GcFlags.minAllocAreaSize > 
135       RtsFlags.GcFlags.maxHeapSize) {
136       errorBelch("maximum heap size (-M) is smaller than minimum alloc area size (-A)");
137       RtsFlags.GcFlags.minAllocAreaSize = RtsFlags.GcFlags.maxHeapSize;
138   }
139
140   initBlockAllocator();
141   
142 #if defined(THREADED_RTS)
143   initMutex(&sm_mutex);
144   initMutex(&atomic_modify_mutvar_mutex);
145 #endif
146
147   ACQUIRE_SM_LOCK;
148
149   /* allocate generation info array */
150   generations = (generation *)stgMallocBytes(RtsFlags.GcFlags.generations 
151                                              * sizeof(struct generation_),
152                                              "initStorage: gens");
153
154   /* allocate all the steps into an array.  It is important that we do
155      it this way, because we need the invariant that two step pointers
156      can be directly compared to see which is the oldest.
157      Remember that the last generation has only one step. */
158   total_steps = 1 + (RtsFlags.GcFlags.generations - 1) * RtsFlags.GcFlags.steps;
159   all_steps   = stgMallocBytes(total_steps * sizeof(struct step_),
160                                "initStorage: steps");
161
162   /* Initialise all generations */
163   for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
164     gen = &generations[g];
165     gen->no = g;
166     gen->mut_list = allocBlock();
167     gen->collections = 0;
168     gen->par_collections = 0;
169     gen->failed_promotions = 0;
170     gen->max_blocks = 0;
171   }
172
173   /* A couple of convenience pointers */
174   g0 = &generations[0];
175   oldest_gen = &generations[RtsFlags.GcFlags.generations-1];
176
177   /* Allocate step structures in each generation */
178   if (RtsFlags.GcFlags.generations > 1) {
179     /* Only for multiple-generations */
180
181     /* Oldest generation: one step */
182     oldest_gen->n_steps = 1;
183     oldest_gen->steps   = all_steps + (RtsFlags.GcFlags.generations - 1)
184                                       * RtsFlags.GcFlags.steps;
185
186     /* set up all except the oldest generation with 2 steps */
187     for(g = 0; g < RtsFlags.GcFlags.generations-1; g++) {
188       generations[g].n_steps = RtsFlags.GcFlags.steps;
189       generations[g].steps   = all_steps + g * RtsFlags.GcFlags.steps;
190     }
191     
192   } else {
193     /* single generation, i.e. a two-space collector */
194     g0->n_steps = 1;
195     g0->steps   = all_steps;
196   }
197
198 #ifdef THREADED_RTS
199   n_nurseries = n_capabilities;
200 #else
201   n_nurseries = 1;
202 #endif
203   nurseries = stgMallocBytes (n_nurseries * sizeof(struct step_),
204                               "initStorage: nurseries");
205
206   /* Initialise all steps */
207   for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
208     for (s = 0; s < generations[g].n_steps; s++) {
209         initStep(&generations[g].steps[s], g, s);
210     }
211   }
212   
213   for (s = 0; s < n_nurseries; s++) {
214       initStep(&nurseries[s], 0, s);
215   }
216   
217   /* Set up the destination pointers in each younger gen. step */
218   for (g = 0; g < RtsFlags.GcFlags.generations-1; g++) {
219     for (s = 0; s < generations[g].n_steps-1; s++) {
220       generations[g].steps[s].to = &generations[g].steps[s+1];
221     }
222     generations[g].steps[s].to = &generations[g+1].steps[0];
223   }
224   oldest_gen->steps[0].to = &oldest_gen->steps[0];
225   
226   for (s = 0; s < n_nurseries; s++) {
227       nurseries[s].to = generations[0].steps[0].to;
228   }
229   
230   /* The oldest generation has one step. */
231   if (RtsFlags.GcFlags.compact) {
232       if (RtsFlags.GcFlags.generations == 1) {
233           errorBelch("WARNING: compaction is incompatible with -G1; disabled");
234       } else {
235           oldest_gen->steps[0].is_compacted = 1;
236       }
237   }
238
239   generations[0].max_blocks = 0;
240   g0s0 = &generations[0].steps[0];
241
242   /* The allocation area.  Policy: keep the allocation area
243    * small to begin with, even if we have a large suggested heap
244    * size.  Reason: we're going to do a major collection first, and we
245    * don't want it to be a big one.  This vague idea is borne out by 
246    * rigorous experimental evidence.
247    */
248   allocNurseries();
249
250   weak_ptr_list = NULL;
251   caf_list = NULL;
252   revertible_caf_list = NULL;
253    
254   /* initialise the allocate() interface */
255   alloc_blocks = 0;
256   alloc_blocks_lim = RtsFlags.GcFlags.minAllocAreaSize;
257
258   /* Tell GNU multi-precision pkg about our custom alloc functions */
259   mp_set_memory_functions(stgAllocForGMP, stgReallocForGMP, stgDeallocForGMP);
260
261 #ifdef THREADED_RTS
262   initSpinLock(&gc_alloc_block_sync);
263   initSpinLock(&recordMutableGen_sync);
264   whitehole_spin = 0;
265 #endif
266
267   IF_DEBUG(gc, statDescribeGens());
268
269   RELEASE_SM_LOCK;
270 }
271
272 void
273 exitStorage (void)
274 {
275     stat_exit(calcAllocated());
276 }
277
278 void
279 freeStorage (void)
280 {
281     stgFree(g0s0); // frees all the steps
282     stgFree(generations);
283     freeAllMBlocks();
284 #if defined(THREADED_RTS)
285     closeMutex(&sm_mutex);
286     closeMutex(&atomic_modify_mutvar_mutex);
287 #endif
288     stgFree(nurseries);
289 }
290
291 /* -----------------------------------------------------------------------------
292    CAF management.
293
294    The entry code for every CAF does the following:
295      
296       - builds a CAF_BLACKHOLE in the heap
297       - pushes an update frame pointing to the CAF_BLACKHOLE
298       - invokes UPD_CAF(), which:
299           - calls newCaf, below
300           - updates the CAF with a static indirection to the CAF_BLACKHOLE
301       
302    Why do we build a BLACKHOLE in the heap rather than just updating
303    the thunk directly?  It's so that we only need one kind of update
304    frame - otherwise we'd need a static version of the update frame too.
305
306    newCaf() does the following:
307        
308       - it puts the CAF on the oldest generation's mut-once list.
309         This is so that we can treat the CAF as a root when collecting
310         younger generations.
311
312    For GHCI, we have additional requirements when dealing with CAFs:
313
314       - we must *retain* all dynamically-loaded CAFs ever entered,
315         just in case we need them again.
316       - we must be able to *revert* CAFs that have been evaluated, to
317         their pre-evaluated form.
318
319       To do this, we use an additional CAF list.  When newCaf() is
320       called on a dynamically-loaded CAF, we add it to the CAF list
321       instead of the old-generation mutable list, and save away its
322       old info pointer (in caf->saved_info) for later reversion.
323
324       To revert all the CAFs, we traverse the CAF list and reset the
325       info pointer to caf->saved_info, then throw away the CAF list.
326       (see GC.c:revertCAFs()).
327
328       -- SDM 29/1/01
329
330    -------------------------------------------------------------------------- */
331
332 void
333 newCAF(StgClosure* caf)
334 {
335   ACQUIRE_SM_LOCK;
336
337   if(keepCAFs)
338   {
339     // HACK:
340     // If we are in GHCi _and_ we are using dynamic libraries,
341     // then we can't redirect newCAF calls to newDynCAF (see below),
342     // so we make newCAF behave almost like newDynCAF.
343     // The dynamic libraries might be used by both the interpreted
344     // program and GHCi itself, so they must not be reverted.
345     // This also means that in GHCi with dynamic libraries, CAFs are not
346     // garbage collected. If this turns out to be a problem, we could
347     // do another hack here and do an address range test on caf to figure
348     // out whether it is from a dynamic library.
349     ((StgIndStatic *)caf)->saved_info  = (StgInfoTable *)caf->header.info;
350     ((StgIndStatic *)caf)->static_link = caf_list;
351     caf_list = caf;
352   }
353   else
354   {
355     /* Put this CAF on the mutable list for the old generation.
356     * This is a HACK - the IND_STATIC closure doesn't really have
357     * a mut_link field, but we pretend it has - in fact we re-use
358     * the STATIC_LINK field for the time being, because when we
359     * come to do a major GC we won't need the mut_link field
360     * any more and can use it as a STATIC_LINK.
361     */
362     ((StgIndStatic *)caf)->saved_info = NULL;
363     recordMutableGen(caf, oldest_gen);
364   }
365   
366   RELEASE_SM_LOCK;
367 }
368
369 // An alternate version of newCaf which is used for dynamically loaded
370 // object code in GHCi.  In this case we want to retain *all* CAFs in
371 // the object code, because they might be demanded at any time from an
372 // expression evaluated on the command line.
373 // Also, GHCi might want to revert CAFs, so we add these to the
374 // revertible_caf_list.
375 //
376 // The linker hackily arranges that references to newCaf from dynamic
377 // code end up pointing to newDynCAF.
378 void
379 newDynCAF(StgClosure *caf)
380 {
381     ACQUIRE_SM_LOCK;
382
383     ((StgIndStatic *)caf)->saved_info  = (StgInfoTable *)caf->header.info;
384     ((StgIndStatic *)caf)->static_link = revertible_caf_list;
385     revertible_caf_list = caf;
386
387     RELEASE_SM_LOCK;
388 }
389
390 /* -----------------------------------------------------------------------------
391    Nursery management.
392    -------------------------------------------------------------------------- */
393
394 static bdescr *
395 allocNursery (step *stp, bdescr *tail, nat blocks)
396 {
397     bdescr *bd;
398     nat i;
399
400     // Allocate a nursery: we allocate fresh blocks one at a time and
401     // cons them on to the front of the list, not forgetting to update
402     // the back pointer on the tail of the list to point to the new block.
403     for (i=0; i < blocks; i++) {
404         // @LDV profiling
405         /*
406           processNursery() in LdvProfile.c assumes that every block group in
407           the nursery contains only a single block. So, if a block group is
408           given multiple blocks, change processNursery() accordingly.
409         */
410         bd = allocBlock();
411         bd->link = tail;
412         // double-link the nursery: we might need to insert blocks
413         if (tail != NULL) {
414             tail->u.back = bd;
415         }
416         bd->step = stp;
417         bd->gen_no = 0;
418         bd->flags = 0;
419         bd->free = bd->start;
420         tail = bd;
421     }
422     tail->u.back = NULL;
423     return tail;
424 }
425
426 static void
427 assignNurseriesToCapabilities (void)
428 {
429 #ifdef THREADED_RTS
430     nat i;
431
432     for (i = 0; i < n_nurseries; i++) {
433         capabilities[i].r.rNursery        = &nurseries[i];
434         capabilities[i].r.rCurrentNursery = nurseries[i].blocks;
435         capabilities[i].r.rCurrentAlloc   = NULL;
436     }
437 #else /* THREADED_RTS */
438     MainCapability.r.rNursery        = &nurseries[0];
439     MainCapability.r.rCurrentNursery = nurseries[0].blocks;
440     MainCapability.r.rCurrentAlloc   = NULL;
441 #endif
442 }
443
444 void
445 allocNurseries( void )
446
447     nat i;
448
449     for (i = 0; i < n_nurseries; i++) {
450         nurseries[i].blocks = 
451             allocNursery(&nurseries[i], NULL, 
452                          RtsFlags.GcFlags.minAllocAreaSize);
453         nurseries[i].n_blocks    = RtsFlags.GcFlags.minAllocAreaSize;
454         nurseries[i].old_blocks   = NULL;
455         nurseries[i].n_old_blocks = 0;
456     }
457     assignNurseriesToCapabilities();
458 }
459       
460 void
461 resetNurseries( void )
462 {
463     nat i;
464     bdescr *bd;
465     step *stp;
466
467     for (i = 0; i < n_nurseries; i++) {
468         stp = &nurseries[i];
469         for (bd = stp->blocks; bd; bd = bd->link) {
470             bd->free = bd->start;
471             ASSERT(bd->gen_no == 0);
472             ASSERT(bd->step == stp);
473             IF_DEBUG(sanity,memset(bd->start, 0xaa, BLOCK_SIZE));
474         }
475     }
476     assignNurseriesToCapabilities();
477 }
478
479 lnat
480 countNurseryBlocks (void)
481 {
482     nat i;
483     lnat blocks = 0;
484
485     for (i = 0; i < n_nurseries; i++) {
486         blocks += nurseries[i].n_blocks;
487     }
488     return blocks;
489 }
490
491 static void
492 resizeNursery ( step *stp, nat blocks )
493 {
494   bdescr *bd;
495   nat nursery_blocks;
496
497   nursery_blocks = stp->n_blocks;
498   if (nursery_blocks == blocks) return;
499
500   if (nursery_blocks < blocks) {
501       debugTrace(DEBUG_gc, "increasing size of nursery to %d blocks", 
502                  blocks);
503     stp->blocks = allocNursery(stp, stp->blocks, blocks-nursery_blocks);
504   } 
505   else {
506     bdescr *next_bd;
507     
508     debugTrace(DEBUG_gc, "decreasing size of nursery to %d blocks", 
509                blocks);
510
511     bd = stp->blocks;
512     while (nursery_blocks > blocks) {
513         next_bd = bd->link;
514         next_bd->u.back = NULL;
515         nursery_blocks -= bd->blocks; // might be a large block
516         freeGroup(bd);
517         bd = next_bd;
518     }
519     stp->blocks = bd;
520     // might have gone just under, by freeing a large block, so make
521     // up the difference.
522     if (nursery_blocks < blocks) {
523         stp->blocks = allocNursery(stp, stp->blocks, blocks-nursery_blocks);
524     }
525   }
526   
527   stp->n_blocks = blocks;
528   ASSERT(countBlocks(stp->blocks) == stp->n_blocks);
529 }
530
531 // 
532 // Resize each of the nurseries to the specified size.
533 //
534 void
535 resizeNurseriesFixed (nat blocks)
536 {
537     nat i;
538     for (i = 0; i < n_nurseries; i++) {
539         resizeNursery(&nurseries[i], blocks);
540     }
541 }
542
543 // 
544 // Resize the nurseries to the total specified size.
545 //
546 void
547 resizeNurseries (nat blocks)
548 {
549     // If there are multiple nurseries, then we just divide the number
550     // of available blocks between them.
551     resizeNurseriesFixed(blocks / n_nurseries);
552 }
553
554 /* -----------------------------------------------------------------------------
555    The allocate() interface
556
557    allocateInGen() function allocates memory directly into a specific
558    generation.  It always succeeds, and returns a chunk of memory n
559    words long.  n can be larger than the size of a block if necessary,
560    in which case a contiguous block group will be allocated.
561
562    allocate(n) is equivalent to allocateInGen(g0).
563    -------------------------------------------------------------------------- */
564
565 StgPtr
566 allocateInGen (generation *g, nat n)
567 {
568     step *stp;
569     bdescr *bd;
570     StgPtr ret;
571
572     ACQUIRE_SM_LOCK;
573     
574     TICK_ALLOC_HEAP_NOCTR(n);
575     CCS_ALLOC(CCCS,n);
576
577     stp = &g->steps[0];
578
579     if (n >= LARGE_OBJECT_THRESHOLD/sizeof(W_))
580     {
581         nat req_blocks =  (lnat)BLOCK_ROUND_UP(n*sizeof(W_)) / BLOCK_SIZE;
582
583         // Attempting to allocate an object larger than maxHeapSize
584         // should definitely be disallowed.  (bug #1791)
585         if (RtsFlags.GcFlags.maxHeapSize > 0 && 
586             req_blocks >= RtsFlags.GcFlags.maxHeapSize) {
587             heapOverflow();
588         }
589
590         bd = allocGroup(req_blocks);
591         dbl_link_onto(bd, &stp->large_objects);
592         stp->n_large_blocks += bd->blocks; // might be larger than req_blocks
593         bd->gen_no  = g->no;
594         bd->step = stp;
595         bd->flags = BF_LARGE;
596         bd->free = bd->start + n;
597         ret = bd->start;
598     }
599     else
600     {
601         // small allocation (<LARGE_OBJECT_THRESHOLD) */
602         bd = stp->blocks;
603         if (bd == NULL || bd->free + n > bd->start + BLOCK_SIZE_W) {
604             bd = allocBlock();
605             bd->gen_no = g->no;
606             bd->step = stp;
607             bd->flags = 0;
608             bd->link = stp->blocks;
609             stp->blocks = bd;
610             stp->n_blocks++;
611             alloc_blocks++;
612         }
613         ret = bd->free;
614         bd->free += n;
615     }
616
617     RELEASE_SM_LOCK;
618
619     return ret;
620 }
621
622 StgPtr
623 allocate (nat n)
624 {
625     return allocateInGen(g0,n);
626 }
627
628 lnat
629 allocatedBytes( void )
630 {
631     lnat allocated;
632
633     allocated = alloc_blocks * BLOCK_SIZE_W;
634     if (pinned_object_block != NULL) {
635         allocated -= (pinned_object_block->start + BLOCK_SIZE_W) - 
636             pinned_object_block->free;
637     }
638         
639     return allocated;
640 }
641
642 // split N blocks off the start of the given bdescr, returning the 
643 // remainder as a new block group.  We treat the remainder as if it
644 // had been freshly allocated in generation 0.
645 bdescr *
646 splitLargeBlock (bdescr *bd, nat blocks)
647 {
648     bdescr *new_bd;
649
650     // subtract the original number of blocks from the counter first
651     bd->step->n_large_blocks -= bd->blocks;
652
653     new_bd = splitBlockGroup (bd, blocks);
654
655     dbl_link_onto(new_bd, &g0s0->large_objects);
656     g0s0->n_large_blocks += new_bd->blocks;
657     new_bd->gen_no  = g0s0->no;
658     new_bd->step    = g0s0;
659     new_bd->flags   = BF_LARGE;
660     new_bd->free    = bd->free;
661
662     // add the new number of blocks to the counter.  Due to the gaps
663     // for block descriptor, new_bd->blocks + bd->blocks might not be
664     // equal to the original bd->blocks, which is why we do it this way.
665     bd->step->n_large_blocks += bd->blocks;
666
667     return new_bd;
668 }    
669
670 /* -----------------------------------------------------------------------------
671    allocateLocal()
672
673    This allocates memory in the current thread - it is intended for
674    use primarily from STG-land where we have a Capability.  It is
675    better than allocate() because it doesn't require taking the
676    sm_mutex lock in the common case.
677
678    Memory is allocated directly from the nursery if possible (but not
679    from the current nursery block, so as not to interfere with
680    Hp/HpLim).
681    -------------------------------------------------------------------------- */
682
683 StgPtr
684 allocateLocal (Capability *cap, nat n)
685 {
686     bdescr *bd;
687     StgPtr p;
688
689     if (n >= LARGE_OBJECT_THRESHOLD/sizeof(W_)) {
690         return allocateInGen(g0,n);
691     }
692
693     /* small allocation (<LARGE_OBJECT_THRESHOLD) */
694
695     TICK_ALLOC_HEAP_NOCTR(n);
696     CCS_ALLOC(CCCS,n);
697     
698     bd = cap->r.rCurrentAlloc;
699     if (bd == NULL || bd->free + n > bd->start + BLOCK_SIZE_W) {
700         
701         // The CurrentAlloc block is full, we need to find another
702         // one.  First, we try taking the next block from the
703         // nursery:
704         bd = cap->r.rCurrentNursery->link;
705         
706         if (bd == NULL || bd->free + n > bd->start + BLOCK_SIZE_W) {
707             // The nursery is empty, or the next block is already
708             // full: allocate a fresh block (we can't fail here).
709             ACQUIRE_SM_LOCK;
710             bd = allocBlock();
711             cap->r.rNursery->n_blocks++;
712             RELEASE_SM_LOCK;
713             bd->gen_no = 0;
714             bd->step = cap->r.rNursery;
715             bd->flags = 0;
716             // NO: alloc_blocks++;
717             // calcAllocated() uses the size of the nursery, and we've
718             // already bumpted nursery->n_blocks above.
719         } else {
720             // we have a block in the nursery: take it and put
721             // it at the *front* of the nursery list, and use it
722             // to allocate() from.
723             cap->r.rCurrentNursery->link = bd->link;
724             if (bd->link != NULL) {
725                 bd->link->u.back = cap->r.rCurrentNursery;
726             }
727         }
728         dbl_link_onto(bd, &cap->r.rNursery->blocks);
729         cap->r.rCurrentAlloc = bd;
730         IF_DEBUG(sanity, checkNurserySanity(cap->r.rNursery));
731     }
732     p = bd->free;
733     bd->free += n;
734     return p;
735 }
736
737 /* ---------------------------------------------------------------------------
738    Allocate a fixed/pinned object.
739
740    We allocate small pinned objects into a single block, allocating a
741    new block when the current one overflows.  The block is chained
742    onto the large_object_list of generation 0 step 0.
743
744    NOTE: The GC can't in general handle pinned objects.  This
745    interface is only safe to use for ByteArrays, which have no
746    pointers and don't require scavenging.  It works because the
747    block's descriptor has the BF_LARGE flag set, so the block is
748    treated as a large object and chained onto various lists, rather
749    than the individual objects being copied.  However, when it comes
750    to scavenge the block, the GC will only scavenge the first object.
751    The reason is that the GC can't linearly scan a block of pinned
752    objects at the moment (doing so would require using the
753    mostly-copying techniques).  But since we're restricting ourselves
754    to pinned ByteArrays, not scavenging is ok.
755
756    This function is called by newPinnedByteArray# which immediately
757    fills the allocated memory with a MutableByteArray#.
758    ------------------------------------------------------------------------- */
759
760 StgPtr
761 allocatePinned( nat n )
762 {
763     StgPtr p;
764     bdescr *bd = pinned_object_block;
765
766     // If the request is for a large object, then allocate()
767     // will give us a pinned object anyway.
768     if (n >= LARGE_OBJECT_THRESHOLD/sizeof(W_)) {
769         return allocate(n);
770     }
771
772     ACQUIRE_SM_LOCK;
773     
774     TICK_ALLOC_HEAP_NOCTR(n);
775     CCS_ALLOC(CCCS,n);
776
777     // we always return 8-byte aligned memory.  bd->free must be
778     // 8-byte aligned to begin with, so we just round up n to
779     // the nearest multiple of 8 bytes.
780     if (sizeof(StgWord) == 4) {
781         n = (n+1) & ~1;
782     }
783
784     // If we don't have a block of pinned objects yet, or the current
785     // one isn't large enough to hold the new object, allocate a new one.
786     if (bd == NULL || (bd->free + n) > (bd->start + BLOCK_SIZE_W)) {
787         pinned_object_block = bd = allocBlock();
788         dbl_link_onto(bd, &g0s0->large_objects);
789         g0s0->n_large_blocks++;
790         bd->gen_no = 0;
791         bd->step   = g0s0;
792         bd->flags  = BF_PINNED | BF_LARGE;
793         bd->free   = bd->start;
794         alloc_blocks++;
795     }
796
797     p = bd->free;
798     bd->free += n;
799     RELEASE_SM_LOCK;
800     return p;
801 }
802
803 /* -----------------------------------------------------------------------------
804    Write Barriers
805    -------------------------------------------------------------------------- */
806
807 /*
808    This is the write barrier for MUT_VARs, a.k.a. IORefs.  A
809    MUT_VAR_CLEAN object is not on the mutable list; a MUT_VAR_DIRTY
810    is.  When written to, a MUT_VAR_CLEAN turns into a MUT_VAR_DIRTY
811    and is put on the mutable list.
812 */
813 void
814 dirty_MUT_VAR(StgRegTable *reg, StgClosure *p)
815 {
816     Capability *cap = regTableToCapability(reg);
817     bdescr *bd;
818     if (p->header.info == &stg_MUT_VAR_CLEAN_info) {
819         p->header.info = &stg_MUT_VAR_DIRTY_info;
820         bd = Bdescr((StgPtr)p);
821         if (bd->gen_no > 0) recordMutableCap(p,cap,bd->gen_no);
822     }
823 }
824
825 // Setting a TSO's link field with a write barrier.
826 // It is *not* necessary to call this function when
827 //    * setting the link field to END_TSO_QUEUE
828 //    * putting a TSO on the blackhole_queue
829 //    * setting the link field of the currently running TSO, as it
830 //      will already be dirty.
831 void
832 setTSOLink (Capability *cap, StgTSO *tso, StgTSO *target)
833 {
834     bdescr *bd;
835     if ((tso->flags & (TSO_DIRTY|TSO_LINK_DIRTY)) == 0) {
836         tso->flags |= TSO_LINK_DIRTY;
837         bd = Bdescr((StgPtr)tso);
838         if (bd->gen_no > 0) recordMutableCap((StgClosure*)tso,cap,bd->gen_no);
839     }
840     tso->_link = target;
841 }
842
843 void
844 dirty_TSO (Capability *cap, StgTSO *tso)
845 {
846     bdescr *bd;
847     if ((tso->flags & TSO_DIRTY) == 0) {
848         tso->flags |= TSO_DIRTY;
849         bd = Bdescr((StgPtr)tso);
850         if (bd->gen_no > 0) recordMutableCap((StgClosure*)tso,cap,bd->gen_no);
851     }
852 }
853
854 /*
855    This is the write barrier for MVARs.  An MVAR_CLEAN objects is not
856    on the mutable list; a MVAR_DIRTY is.  When written to, a
857    MVAR_CLEAN turns into a MVAR_DIRTY and is put on the mutable list.
858    The check for MVAR_CLEAN is inlined at the call site for speed,
859    this really does make a difference on concurrency-heavy benchmarks
860    such as Chaneneos and cheap-concurrency.
861 */
862 void
863 dirty_MVAR(StgRegTable *reg, StgClosure *p)
864 {
865     Capability *cap = regTableToCapability(reg);
866     bdescr *bd;
867     bd = Bdescr((StgPtr)p);
868     if (bd->gen_no > 0) recordMutableCap(p,cap,bd->gen_no);
869 }
870
871 /* -----------------------------------------------------------------------------
872    Allocation functions for GMP.
873
874    These all use the allocate() interface - we can't have any garbage
875    collection going on during a gmp operation, so we use allocate()
876    which always succeeds.  The gmp operations which might need to
877    allocate will ask the storage manager (via doYouWantToGC()) whether
878    a garbage collection is required, in case we get into a loop doing
879    only allocate() style allocation.
880    -------------------------------------------------------------------------- */
881
882 static void *
883 stgAllocForGMP (size_t size_in_bytes)
884 {
885   StgArrWords* arr;
886   nat data_size_in_words, total_size_in_words;
887   
888   /* round up to a whole number of words */
889   data_size_in_words  = (size_in_bytes + sizeof(W_) + 1) / sizeof(W_);
890   total_size_in_words = sizeofW(StgArrWords) + data_size_in_words;
891   
892   /* allocate and fill it in. */
893 #if defined(THREADED_RTS)
894   arr = (StgArrWords *)allocateLocal(myTask()->cap, total_size_in_words);
895 #else
896   arr = (StgArrWords *)allocateLocal(&MainCapability, total_size_in_words);
897 #endif
898   SET_ARR_HDR(arr, &stg_ARR_WORDS_info, CCCS, data_size_in_words);
899   
900   /* and return a ptr to the goods inside the array */
901   return arr->payload;
902 }
903
904 static void *
905 stgReallocForGMP (void *ptr, size_t old_size, size_t new_size)
906 {
907     void *new_stuff_ptr = stgAllocForGMP(new_size);
908     nat i = 0;
909     char *p = (char *) ptr;
910     char *q = (char *) new_stuff_ptr;
911
912     for (; i < old_size; i++, p++, q++) {
913         *q = *p;
914     }
915
916     return(new_stuff_ptr);
917 }
918
919 static void
920 stgDeallocForGMP (void *ptr STG_UNUSED, 
921                   size_t size STG_UNUSED)
922 {
923     /* easy for us: the garbage collector does the dealloc'n */
924 }
925
926 /* -----------------------------------------------------------------------------
927  * Stats and stuff
928  * -------------------------------------------------------------------------- */
929
930 /* -----------------------------------------------------------------------------
931  * calcAllocated()
932  *
933  * Approximate how much we've allocated: number of blocks in the
934  * nursery + blocks allocated via allocate() - unused nusery blocks.
935  * This leaves a little slop at the end of each block, and doesn't
936  * take into account large objects (ToDo).
937  * -------------------------------------------------------------------------- */
938
939 lnat
940 calcAllocated( void )
941 {
942   nat allocated;
943   bdescr *bd;
944
945   allocated = allocatedBytes();
946   allocated += countNurseryBlocks() * BLOCK_SIZE_W;
947   
948   {
949 #ifdef THREADED_RTS
950   nat i;
951   for (i = 0; i < n_nurseries; i++) {
952       Capability *cap;
953       for ( bd = capabilities[i].r.rCurrentNursery->link; 
954             bd != NULL; bd = bd->link ) {
955           allocated -= BLOCK_SIZE_W;
956       }
957       cap = &capabilities[i];
958       if (cap->r.rCurrentNursery->free < 
959           cap->r.rCurrentNursery->start + BLOCK_SIZE_W) {
960           allocated -= (cap->r.rCurrentNursery->start + BLOCK_SIZE_W)
961               - cap->r.rCurrentNursery->free;
962       }
963   }
964 #else
965   bdescr *current_nursery = MainCapability.r.rCurrentNursery;
966
967   for ( bd = current_nursery->link; bd != NULL; bd = bd->link ) {
968       allocated -= BLOCK_SIZE_W;
969   }
970   if (current_nursery->free < current_nursery->start + BLOCK_SIZE_W) {
971       allocated -= (current_nursery->start + BLOCK_SIZE_W)
972           - current_nursery->free;
973   }
974 #endif
975   }
976
977   total_allocated += allocated;
978   return allocated;
979 }  
980
981 /* Approximate the amount of live data in the heap.  To be called just
982  * after garbage collection (see GarbageCollect()).
983  */
984 lnat 
985 calcLiveBlocks(void)
986 {
987   nat g, s;
988   lnat live = 0;
989   step *stp;
990
991   if (RtsFlags.GcFlags.generations == 1) {
992       return g0s0->n_large_blocks + g0s0->n_blocks;
993   }
994
995   for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
996     for (s = 0; s < generations[g].n_steps; s++) {
997       /* approximate amount of live data (doesn't take into account slop
998        * at end of each block).
999        */
1000       if (g == 0 && s == 0) { 
1001           continue; 
1002       }
1003       stp = &generations[g].steps[s];
1004       live += stp->n_large_blocks + stp->n_blocks;
1005     }
1006   }
1007   return live;
1008 }
1009
1010 lnat
1011 countOccupied(bdescr *bd)
1012 {
1013     lnat words;
1014
1015     words = 0;
1016     for (; bd != NULL; bd = bd->link) {
1017         words += bd->free - bd->start;
1018     }
1019     return words;
1020 }
1021
1022 // Return an accurate count of the live data in the heap, excluding
1023 // generation 0.
1024 lnat
1025 calcLiveWords(void)
1026 {
1027     nat g, s;
1028     lnat live;
1029     step *stp;
1030     
1031     if (RtsFlags.GcFlags.generations == 1) {
1032         return g0s0->n_words + countOccupied(g0s0->large_objects);
1033     }
1034     
1035     live = 0;
1036     for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
1037         for (s = 0; s < generations[g].n_steps; s++) {
1038             if (g == 0 && s == 0) continue; 
1039             stp = &generations[g].steps[s];
1040             live += stp->n_words + countOccupied(stp->large_objects);
1041         } 
1042     }
1043     return live;
1044 }
1045
1046 /* Approximate the number of blocks that will be needed at the next
1047  * garbage collection.
1048  *
1049  * Assume: all data currently live will remain live.  Steps that will
1050  * be collected next time will therefore need twice as many blocks
1051  * since all the data will be copied.
1052  */
1053 extern lnat 
1054 calcNeeded(void)
1055 {
1056     lnat needed = 0;
1057     nat g, s;
1058     step *stp;
1059     
1060     for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
1061         for (s = 0; s < generations[g].n_steps; s++) {
1062             if (g == 0 && s == 0) { continue; }
1063             stp = &generations[g].steps[s];
1064             if (g == 0 || // always collect gen 0
1065                 (generations[g].steps[0].n_blocks +
1066                  generations[g].steps[0].n_large_blocks 
1067                  > generations[g].max_blocks
1068                  && stp->is_compacted == 0)) {
1069                 needed += 2 * stp->n_blocks + stp->n_large_blocks;
1070             } else {
1071                 needed += stp->n_blocks + stp->n_large_blocks;
1072             }
1073         }
1074     }
1075     return needed;
1076 }
1077
1078 /* ----------------------------------------------------------------------------
1079    Executable memory
1080
1081    Executable memory must be managed separately from non-executable
1082    memory.  Most OSs these days require you to jump through hoops to
1083    dynamically allocate executable memory, due to various security
1084    measures.
1085
1086    Here we provide a small memory allocator for executable memory.
1087    Memory is managed with a page granularity; we allocate linearly
1088    in the page, and when the page is emptied (all objects on the page
1089    are free) we free the page again, not forgetting to make it
1090    non-executable.
1091
1092    TODO: The inability to handle objects bigger than BLOCK_SIZE_W means that
1093          the linker cannot use allocateExec for loading object code files
1094          on Windows. Once allocateExec can handle larger objects, the linker
1095          should be modified to use allocateExec instead of VirtualAlloc.
1096    ------------------------------------------------------------------------- */
1097
1098 static bdescr *exec_block;
1099
1100 void *allocateExec (nat bytes)
1101 {
1102     void *ret;
1103     nat n;
1104
1105     ACQUIRE_SM_LOCK;
1106
1107     // round up to words.
1108     n  = (bytes + sizeof(W_) + 1) / sizeof(W_);
1109
1110     if (n+1 > BLOCK_SIZE_W) {
1111         barf("allocateExec: can't handle large objects");
1112     }
1113
1114     if (exec_block == NULL || 
1115         exec_block->free + n + 1 > exec_block->start + BLOCK_SIZE_W) {
1116         bdescr *bd;
1117         lnat pagesize = getPageSize();
1118         bd = allocGroup(stg_max(1, pagesize / BLOCK_SIZE));
1119         debugTrace(DEBUG_gc, "allocate exec block %p", bd->start);
1120         bd->gen_no = 0;
1121         bd->flags = BF_EXEC;
1122         bd->link = exec_block;
1123         if (exec_block != NULL) {
1124             exec_block->u.back = bd;
1125         }
1126         bd->u.back = NULL;
1127         setExecutable(bd->start, bd->blocks * BLOCK_SIZE, rtsTrue);
1128         exec_block = bd;
1129     }
1130     *(exec_block->free) = n;  // store the size of this chunk
1131     exec_block->gen_no += n;  // gen_no stores the number of words allocated
1132     ret = exec_block->free + 1;
1133     exec_block->free += n + 1;
1134
1135     RELEASE_SM_LOCK
1136     return ret;
1137 }
1138
1139 void freeExec (void *addr)
1140 {
1141     StgPtr p = (StgPtr)addr - 1;
1142     bdescr *bd = Bdescr((StgPtr)p);
1143
1144     if ((bd->flags & BF_EXEC) == 0) {
1145         barf("freeExec: not executable");
1146     }
1147
1148     if (*(StgPtr)p == 0) {
1149         barf("freeExec: already free?");
1150     }
1151
1152     ACQUIRE_SM_LOCK;
1153
1154     bd->gen_no -= *(StgPtr)p;
1155     *(StgPtr)p = 0;
1156
1157     if (bd->gen_no == 0) {
1158         // Free the block if it is empty, but not if it is the block at
1159         // the head of the queue.
1160         if (bd != exec_block) {
1161             debugTrace(DEBUG_gc, "free exec block %p", bd->start);
1162             dbl_link_remove(bd, &exec_block);
1163             setExecutable(bd->start, bd->blocks * BLOCK_SIZE, rtsFalse);
1164             freeGroup(bd);
1165         } else {
1166             bd->free = bd->start;
1167         }
1168     }
1169
1170     RELEASE_SM_LOCK
1171 }    
1172
1173 /* -----------------------------------------------------------------------------
1174    Debugging
1175
1176    memInventory() checks for memory leaks by counting up all the
1177    blocks we know about and comparing that to the number of blocks
1178    allegedly floating around in the system.
1179    -------------------------------------------------------------------------- */
1180
1181 #ifdef DEBUG
1182
1183 // Useful for finding partially full blocks in gdb
1184 void findSlop(bdescr *bd);
1185 void findSlop(bdescr *bd)
1186 {
1187     lnat slop;
1188
1189     for (; bd != NULL; bd = bd->link) {
1190         slop = (bd->blocks * BLOCK_SIZE_W) - (bd->free - bd->start);
1191         if (slop > (1024/sizeof(W_))) {
1192             debugBelch("block at %p (bdescr %p) has %ldKB slop\n",
1193                        bd->start, bd, slop / (1024/sizeof(W_)));
1194         }
1195     }
1196 }
1197
1198 nat
1199 countBlocks(bdescr *bd)
1200 {
1201     nat n;
1202     for (n=0; bd != NULL; bd=bd->link) {
1203         n += bd->blocks;
1204     }
1205     return n;
1206 }
1207
1208 // (*1) Just like countBlocks, except that we adjust the count for a
1209 // megablock group so that it doesn't include the extra few blocks
1210 // that would be taken up by block descriptors in the second and
1211 // subsequent megablock.  This is so we can tally the count with the
1212 // number of blocks allocated in the system, for memInventory().
1213 static nat
1214 countAllocdBlocks(bdescr *bd)
1215 {
1216     nat n;
1217     for (n=0; bd != NULL; bd=bd->link) {
1218         n += bd->blocks;
1219         // hack for megablock groups: see (*1) above
1220         if (bd->blocks > BLOCKS_PER_MBLOCK) {
1221             n -= (MBLOCK_SIZE / BLOCK_SIZE - BLOCKS_PER_MBLOCK)
1222                 * (bd->blocks/(MBLOCK_SIZE/BLOCK_SIZE));
1223         }
1224     }
1225     return n;
1226 }
1227
1228 static lnat
1229 stepBlocks (step *stp)
1230 {
1231     ASSERT(countBlocks(stp->blocks) == stp->n_blocks);
1232     ASSERT(countBlocks(stp->large_objects) == stp->n_large_blocks);
1233     return stp->n_blocks + stp->n_old_blocks + 
1234             countAllocdBlocks(stp->large_objects);
1235 }
1236
1237 void
1238 memInventory (rtsBool show)
1239 {
1240   nat g, s, i;
1241   step *stp;
1242   lnat gen_blocks[RtsFlags.GcFlags.generations];
1243   lnat nursery_blocks, retainer_blocks,
1244        arena_blocks, exec_blocks;
1245   lnat live_blocks = 0, free_blocks = 0;
1246   rtsBool leak;
1247
1248   // count the blocks we current have
1249
1250   for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
1251       gen_blocks[g] = 0;
1252       for (i = 0; i < n_capabilities; i++) {
1253           gen_blocks[g] += countBlocks(capabilities[i].mut_lists[g]);
1254       }   
1255       gen_blocks[g] += countAllocdBlocks(generations[g].mut_list);
1256       for (s = 0; s < generations[g].n_steps; s++) {
1257           stp = &generations[g].steps[s];
1258           gen_blocks[g] += stepBlocks(stp);
1259       }
1260   }
1261
1262   nursery_blocks = 0;
1263   for (i = 0; i < n_nurseries; i++) {
1264       nursery_blocks += stepBlocks(&nurseries[i]);
1265   }
1266
1267   retainer_blocks = 0;
1268 #ifdef PROFILING
1269   if (RtsFlags.ProfFlags.doHeapProfile == HEAP_BY_RETAINER) {
1270       retainer_blocks = retainerStackBlocks();
1271   }
1272 #endif
1273
1274   // count the blocks allocated by the arena allocator
1275   arena_blocks = arenaBlocks();
1276
1277   // count the blocks containing executable memory
1278   exec_blocks = countAllocdBlocks(exec_block);
1279
1280   /* count the blocks on the free list */
1281   free_blocks = countFreeList();
1282
1283   live_blocks = 0;
1284   for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
1285       live_blocks += gen_blocks[g];
1286   }
1287   live_blocks += nursery_blocks + 
1288                + retainer_blocks + arena_blocks + exec_blocks;
1289
1290 #define MB(n) (((n) * BLOCK_SIZE_W) / ((1024*1024)/sizeof(W_)))
1291
1292   leak = live_blocks + free_blocks != mblocks_allocated * BLOCKS_PER_MBLOCK;
1293   if (show || leak)
1294   {
1295       if (leak) { 
1296           debugBelch("Memory leak detected:\n");
1297       } else {
1298           debugBelch("Memory inventory:\n");
1299       }
1300       for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
1301           debugBelch("  gen %d blocks : %5lu blocks (%lu MB)\n", g, 
1302                      gen_blocks[g], MB(gen_blocks[g]));
1303       }
1304       debugBelch("  nursery      : %5lu blocks (%lu MB)\n", 
1305                  nursery_blocks, MB(nursery_blocks));
1306       debugBelch("  retainer     : %5lu blocks (%lu MB)\n", 
1307                  retainer_blocks, MB(retainer_blocks));
1308       debugBelch("  arena blocks : %5lu blocks (%lu MB)\n", 
1309                  arena_blocks, MB(arena_blocks));
1310       debugBelch("  exec         : %5lu blocks (%lu MB)\n", 
1311                  exec_blocks, MB(exec_blocks));
1312       debugBelch("  free         : %5lu blocks (%lu MB)\n", 
1313                  free_blocks, MB(free_blocks));
1314       debugBelch("  total        : %5lu blocks (%lu MB)\n",
1315                  live_blocks + free_blocks, MB(live_blocks+free_blocks));
1316       if (leak) {
1317           debugBelch("\n  in system    : %5lu blocks (%lu MB)\n", 
1318                      mblocks_allocated * BLOCKS_PER_MBLOCK, mblocks_allocated);
1319       }
1320   }
1321 }
1322
1323
1324 /* Full heap sanity check. */
1325 void
1326 checkSanity( void )
1327 {
1328     nat g, s;
1329
1330     if (RtsFlags.GcFlags.generations == 1) {
1331         checkHeap(g0s0->blocks);
1332         checkChain(g0s0->large_objects);
1333     } else {
1334         
1335         for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
1336             for (s = 0; s < generations[g].n_steps; s++) {
1337                 if (g == 0 && s == 0) { continue; }
1338                 ASSERT(countBlocks(generations[g].steps[s].blocks)
1339                        == generations[g].steps[s].n_blocks);
1340                 ASSERT(countBlocks(generations[g].steps[s].large_objects)
1341                        == generations[g].steps[s].n_large_blocks);
1342                 checkHeap(generations[g].steps[s].blocks);
1343                 checkChain(generations[g].steps[s].large_objects);
1344                 if (g > 0) {
1345                     checkMutableList(generations[g].mut_list, g);
1346                 }
1347             }
1348         }
1349
1350         for (s = 0; s < n_nurseries; s++) {
1351             ASSERT(countBlocks(nurseries[s].blocks)
1352                    == nurseries[s].n_blocks);
1353             ASSERT(countBlocks(nurseries[s].large_objects)
1354                    == nurseries[s].n_large_blocks);
1355         }
1356             
1357         checkFreeListSanity();
1358     }
1359 }
1360
1361 /* Nursery sanity check */
1362 void
1363 checkNurserySanity( step *stp )
1364 {
1365     bdescr *bd, *prev;
1366     nat blocks = 0;
1367
1368     prev = NULL;
1369     for (bd = stp->blocks; bd != NULL; bd = bd->link) {
1370         ASSERT(bd->u.back == prev);
1371         prev = bd;
1372         blocks += bd->blocks;
1373     }
1374     ASSERT(blocks == stp->n_blocks);
1375 }
1376
1377 // handy function for use in gdb, because Bdescr() is inlined.
1378 extern bdescr *_bdescr( StgPtr p );
1379
1380 bdescr *
1381 _bdescr( StgPtr p )
1382 {
1383     return Bdescr(p);
1384 }
1385
1386 #endif