generation *g0 = NULL; /* generation 0, for convenience */
generation *oldest_gen = NULL; /* oldest generation, for convenience */
-ullong total_allocated = 0; /* total memory allocated during run */
-
nursery *nurseries = NULL; /* array of nurseries, size == n_capabilities */
#ifdef THREADED_RTS
gen->n_old_blocks = 0;
gen->large_objects = NULL;
gen->n_large_blocks = 0;
+ gen->n_new_large_blocks = 0;
gen->mut_list = allocBlock();
gen->scavenged_large_objects = NULL;
gen->n_scavenged_large_blocks = 0;
void
initStorage( void )
{
- nat g;
+ nat g, n;
if (generations != NULL) {
// multi-init protection
* doing something reasonable.
*/
/* We use the NOT_NULL variant or gcc warns that the test is always true */
- ASSERT(LOOKS_LIKE_INFO_PTR_NOT_NULL((StgWord)&stg_BLACKHOLE_info));
+ ASSERT(LOOKS_LIKE_INFO_PTR_NOT_NULL((StgWord)&stg_BLOCKING_QUEUE_CLEAN_info));
ASSERT(LOOKS_LIKE_CLOSURE_PTR(&stg_dummy_ret_closure));
ASSERT(!HEAP_ALLOCED(&stg_dummy_ret_closure));
allocNurseries();
weak_ptr_list = NULL;
- caf_list = NULL;
- revertible_caf_list = NULL;
+ caf_list = END_OF_STATIC_LIST;
+ revertible_caf_list = END_OF_STATIC_LIST;
/* initialise the allocate() interface */
alloc_blocks_lim = RtsFlags.GcFlags.minAllocAreaSize;
N = 0;
+ // allocate a block for each mut list
+ for (n = 0; n < n_capabilities; n++) {
+ for (g = 1; g < RtsFlags.GcFlags.generations; g++) {
+ capabilities[n].mut_lists[g] = allocBlock();
+ }
+ }
+
initGcThreads();
IF_DEBUG(gc, statDescribeGens());
The entry code for every CAF does the following:
- - builds a CAF_BLACKHOLE in the heap
- - pushes an update frame pointing to the CAF_BLACKHOLE
- - invokes UPD_CAF(), which:
- - calls newCaf, below
- - updates the CAF with a static indirection to the CAF_BLACKHOLE
+ - builds a BLACKHOLE in the heap
+ - pushes an update frame pointing to the BLACKHOLE
+ - calls newCaf, below
+ - updates the CAF with a static indirection to the BLACKHOLE
- Why do we build a BLACKHOLE in the heap rather than just updating
+ Why do we build an BLACKHOLE in the heap rather than just updating
the thunk directly? It's so that we only need one kind of update
frame - otherwise we'd need a static version of the update frame too.
newCaf() does the following:
- - it puts the CAF on the oldest generation's mut-once list.
- This is so that we can treat the CAF as a root when collecting
+ - it puts the CAF on the oldest generation's mutable list.
+ This is so that we treat the CAF as a root when collecting
younger generations.
For GHCI, we have additional requirements when dealing with CAFs:
-------------------------------------------------------------------------- */
void
-newCAF(StgClosure* caf)
+newCAF(StgRegTable *reg, StgClosure* caf)
{
- ACQUIRE_SM_LOCK;
-
-#ifdef DYNAMIC
if(keepCAFs)
{
// HACK:
// do another hack here and do an address range test on caf to figure
// out whether it is from a dynamic library.
((StgIndStatic *)caf)->saved_info = (StgInfoTable *)caf->header.info;
+
+ ACQUIRE_SM_LOCK; // caf_list is global, locked by sm_mutex
((StgIndStatic *)caf)->static_link = caf_list;
caf_list = caf;
+ RELEASE_SM_LOCK;
}
else
-#endif
{
- /* Put this CAF on the mutable list for the old generation.
- * This is a HACK - the IND_STATIC closure doesn't really have
- * a mut_link field, but we pretend it has - in fact we re-use
- * the STATIC_LINK field for the time being, because when we
- * come to do a major GC we won't need the mut_link field
- * any more and can use it as a STATIC_LINK.
- */
+ // Put this CAF on the mutable list for the old generation.
((StgIndStatic *)caf)->saved_info = NULL;
- recordMutableGen(caf, oldest_gen->no);
+ if (oldest_gen->no != 0) {
+ recordMutableCap(caf, regTableToCapability(reg), oldest_gen->no);
+ }
}
-
- RELEASE_SM_LOCK;
+}
+
+// External API for setting the keepCAFs flag. see #3900.
+void
+setKeepCAFs (void)
+{
+ keepCAFs = 1;
}
// An alternate version of newCaf which is used for dynamically loaded
// The linker hackily arranges that references to newCaf from dynamic
// code end up pointing to newDynCAF.
void
-newDynCAF(StgClosure *caf)
+newDynCAF (StgRegTable *reg STG_UNUSED, StgClosure *caf)
{
ACQUIRE_SM_LOCK;
bd = allocGroup(req_blocks);
dbl_link_onto(bd, &g0->large_objects);
g0->n_large_blocks += bd->blocks; // might be larger than req_blocks
+ g0->n_new_large_blocks += bd->blocks;
RELEASE_SM_LOCK;
initBdescr(bd, g0, g0);
bd->flags = BF_LARGE;
}
p = bd->free;
bd->free += n;
+
+ IF_DEBUG(sanity, ASSERT(*((StgWord8*)p) == 0xaa));
return p;
}
cap->pinned_object_block = bd = allocBlock();
dbl_link_onto(bd, &g0->large_objects);
g0->n_large_blocks++;
+ g0->n_new_large_blocks++;
RELEASE_SM_LOCK;
initBdescr(bd, g0, g0);
bd->flags = BF_PINNED | BF_LARGE;
dirty_MUT_VAR(StgRegTable *reg, StgClosure *p)
{
Capability *cap = regTableToCapability(reg);
- bdescr *bd;
if (p->header.info == &stg_MUT_VAR_CLEAN_info) {
p->header.info = &stg_MUT_VAR_DIRTY_info;
- bd = Bdescr((StgPtr)p);
- if (bd->gen_no > 0) recordMutableCap(p,cap,bd->gen_no);
+ recordClosureMutated(cap,p);
}
}
void
setTSOLink (Capability *cap, StgTSO *tso, StgTSO *target)
{
- bdescr *bd;
if (tso->dirty == 0 && (tso->flags & TSO_LINK_DIRTY) == 0) {
tso->flags |= TSO_LINK_DIRTY;
- bd = Bdescr((StgPtr)tso);
- if (bd->gen_no > 0) recordMutableCap((StgClosure*)tso,cap,bd->gen_no);
+ recordClosureMutated(cap,(StgClosure*)tso);
}
tso->_link = target;
}
void
+setTSOPrev (Capability *cap, StgTSO *tso, StgTSO *target)
+{
+ if (tso->dirty == 0 && (tso->flags & TSO_LINK_DIRTY) == 0) {
+ tso->flags |= TSO_LINK_DIRTY;
+ recordClosureMutated(cap,(StgClosure*)tso);
+ }
+ tso->block_info.prev = target;
+}
+
+void
dirty_TSO (Capability *cap, StgTSO *tso)
{
- bdescr *bd;
if (tso->dirty == 0 && (tso->flags & TSO_LINK_DIRTY) == 0) {
- bd = Bdescr((StgPtr)tso);
- if (bd->gen_no > 0) recordMutableCap((StgClosure*)tso,cap,bd->gen_no);
+ recordClosureMutated(cap,(StgClosure*)tso);
}
tso->dirty = 1;
}
void
dirty_MVAR(StgRegTable *reg, StgClosure *p)
{
- Capability *cap = regTableToCapability(reg);
- bdescr *bd;
- bd = Bdescr((StgPtr)p);
- if (bd->gen_no > 0) recordMutableCap(p,cap,bd->gen_no);
+ recordClosureMutated(regTableToCapability(reg),p);
}
/* -----------------------------------------------------------------------------
}
}
- total_allocated += allocated;
+ allocated += g0->n_new_large_blocks * BLOCK_SIZE_W;
+
return allocated;
}