-/* -----------------------------------------------------------------------------
+/* -----------------------------------------------------------------------*-c-*-
*
- * (c) The GHC Team 1998-2006
+ * (c) The GHC Team 1998-2008
*
* Generational garbage collector: evacuation functions
*
// non-minor, parallel, GC. This file contains the code for both,
// controllled by the CPP symbol MINOR_GC.
-#ifdef MINOR_GC
-#define copy(a,b,c,d) copy0(a,b,c,d)
-#define copy_tag(a,b,c,d,e) copy_tag0(a,b,c,d,e)
-#define copyPart(a,b,c,d,e) copyPart0(a,b,c,d,e)
-#define evacuate(a) evacuate0(a)
+#ifndef PARALLEL_GC
+#define copy(a,b,c,d) copy1(a,b,c,d)
+#define copy_tag(a,b,c,d,e) copy_tag1(a,b,c,d,e)
+#define copyPart(a,b,c,d,e) copyPart1(a,b,c,d,e)
+#define evacuate(a) evacuate1(a)
#else
#undef copy
#undef copy_tag
nat i;
StgWord info;
-#if !defined(MINOR_GC) && defined(THREADED_RTS)
- do {
+#if defined(PARALLEL_GC) && defined(THREADED_RTS)
+spin:
info = xchg((StgPtr)&src->header.info, (W_)&stg_WHITEHOLE_info);
// so.. what is it?
- } while (info == (W_)&stg_WHITEHOLE_info);
- if (info == (W_)&stg_EVACUATED_info) {
+ if (info == (W_)&stg_WHITEHOLE_info) {
+#ifdef PROF_SPIN
+ whitehole_spin++;
+#endif
+ goto spin;
+ }
+ if (info == (W_)&stg_EVACUATED_info || info == (W_)&stg_IND_info) {
+ // NB. a closure might be updated with an IND by
+ // unchain_selector_thunks(), hence the test above.
src->header.info = (const StgInfoTable *)info;
return evacuate(p); // does the failed_to_evac stuff
}
// }
((StgEvacuated*)from)->evacuee = (StgClosure *)tagged_to;
-#if !defined(MINOR_GC) && defined(THREADED_RTS)
+#if defined(PARALLEL_GC) && defined(THREADED_RTS)
write_barrier();
((StgEvacuated*)from)->header.info = &stg_EVACUATED_info;
#endif
nat i;
StgWord info;
-#if !defined(MINOR_GC) && defined(THREADED_RTS)
- do {
+#if defined(PARALLEL_GC) && defined(THREADED_RTS)
+spin:
info = xchg((StgPtr)&src->header.info, (W_)&stg_WHITEHOLE_info);
- } while (info == (W_)&stg_WHITEHOLE_info);
+ if (info == (W_)&stg_WHITEHOLE_info) {
+#ifdef PROF_SPIN
+ whitehole_spin++;
+#endif
+ goto spin;
+ }
if (info == (W_)&stg_EVACUATED_info) {
src->header.info = (const StgInfoTable *)info;
- return evacuate(p); // does the failed_to_evac stuff
+ evacuate(p); // does the failed_to_evac stuff
+ return ;
}
#else
info = (W_)src->header.info;
}
((StgEvacuated*)from)->evacuee = (StgClosure *)to;
-#if !defined(MINOR_GC) && defined(THREADED_RTS)
+#if defined(PARALLEL_GC) && defined(THREADED_RTS)
write_barrier();
((StgEvacuated*)from)->header.info = &stg_EVACUATED_info;
#endif
if (!HEAP_ALLOCED(q)) {
-#ifdef MINOR_GC
- return;
-#endif
if (!major_gc) return;
info = get_itbl(q);
switch (info->type) {
case THUNK_STATIC:
- if (info->srt_bitmap != 0 &&
- *THUNK_STATIC_LINK((StgClosure *)q) == NULL) {
- ACQUIRE_SPIN_LOCK(&static_objects_sync);
+ if (info->srt_bitmap != 0) {
if (*THUNK_STATIC_LINK((StgClosure *)q) == NULL) {
- *THUNK_STATIC_LINK((StgClosure *)q) = static_objects;
- static_objects = (StgClosure *)q;
+#ifndef THREADED_RTS
+ *THUNK_STATIC_LINK((StgClosure *)q) = gct->static_objects;
+ gct->static_objects = (StgClosure *)q;
+#else
+ StgPtr link;
+ link = (StgPtr)cas((StgPtr)THUNK_STATIC_LINK((StgClosure *)q),
+ (StgWord)NULL,
+ (StgWord)gct->static_objects);
+ if (link == NULL) {
+ gct->static_objects = (StgClosure *)q;
+ }
+#endif
}
- RELEASE_SPIN_LOCK(&static_objects_sync);
}
return;
-
+
case FUN_STATIC:
if (info->srt_bitmap != 0 &&
*FUN_STATIC_LINK((StgClosure *)q) == NULL) {
- ACQUIRE_SPIN_LOCK(&static_objects_sync);
- if (*FUN_STATIC_LINK((StgClosure *)q) == NULL) {
- *FUN_STATIC_LINK((StgClosure *)q) = static_objects;
- static_objects = (StgClosure *)q;
- }
- RELEASE_SPIN_LOCK(&static_objects_sync);
+#ifndef THREADED_RTS
+ *FUN_STATIC_LINK((StgClosure *)q) = gct->static_objects;
+ gct->static_objects = (StgClosure *)q;
+#else
+ StgPtr link;
+ link = (StgPtr)cas((StgPtr)FUN_STATIC_LINK((StgClosure *)q),
+ (StgWord)NULL,
+ (StgWord)gct->static_objects);
+ if (link == NULL) {
+ gct->static_objects = (StgClosure *)q;
+ }
+#endif
}
return;
* scavenge it later).
*/
if (((StgIndStatic *)q)->saved_info == NULL) {
- ACQUIRE_SPIN_LOCK(&static_objects_sync);
if (*IND_STATIC_LINK((StgClosure *)q) == NULL) {
- *IND_STATIC_LINK((StgClosure *)q) = static_objects;
- static_objects = (StgClosure *)q;
+#ifndef THREADED_RTS
+ *IND_STATIC_LINK((StgClosure *)q) = gct->static_objects;
+ gct->static_objects = (StgClosure *)q;
+#else
+ StgPtr link;
+ link = (StgPtr)cas((StgPtr)IND_STATIC_LINK((StgClosure *)q),
+ (StgWord)NULL,
+ (StgWord)gct->static_objects);
+ if (link == NULL) {
+ gct->static_objects = (StgClosure *)q;
+ }
+#endif
}
- RELEASE_SPIN_LOCK(&static_objects_sync);
}
return;
case CONSTR_STATIC:
if (*STATIC_LINK(info,(StgClosure *)q) == NULL) {
- ACQUIRE_SPIN_LOCK(&static_objects_sync);
- // re-test, after acquiring lock
- if (*STATIC_LINK(info,(StgClosure *)q) == NULL) {
- *STATIC_LINK(info,(StgClosure *)q) = static_objects;
- static_objects = (StgClosure *)q;
- }
- RELEASE_SPIN_LOCK(&static_objects_sync);
- /* I am assuming that static_objects pointers are not
- * written to other objects, and thus, no need to retag. */
- }
+#ifndef THREADED_RTS
+ *STATIC_LINK(info,(StgClosure *)q) = gct->static_objects;
+ gct->static_objects = (StgClosure *)q;
+#else
+ StgPtr link;
+ link = (StgPtr)cas((StgPtr)STATIC_LINK(info,(StgClosure *)q),
+ (StgWord)NULL,
+ (StgWord)gct->static_objects);
+ if (link == NULL) {
+ gct->static_objects = (StgClosure *)q;
+ }
+#endif
+ }
+ /* I am assuming that static_objects pointers are not
+ * written to other objects, and thus, no need to retag. */
return;
case CONSTR_NOCAF_STATIC:
bd = Bdescr((P_)q);
- if (bd->gen_no > N) {
- /* Can't evacuate this object, because it's in a generation
- * older than the ones we're collecting. Let's hope that it's
- * in gct->evac_step or older, or we will have to arrange to track
- * this pointer using the mutable list.
- */
- if (bd->step < gct->evac_step) {
- // nope
- gct->failed_to_evac = rtsTrue;
- TICK_GC_FAILED_PROMOTION();
- }
- return;
- }
-
if ((bd->flags & (BF_LARGE | BF_COMPACTED | BF_EVACUATED)) != 0) {
- /* pointer into to-space: just return it. This normally
- * shouldn't happen, but alllowing it makes certain things
- * slightly easier (eg. the mutable list can contain the same
- * object twice, for example).
- */
+ // pointer into to-space: just return it. It might be a pointer
+ // into a generation that we aren't collecting (> N), or it
+ // might just be a pointer into to-space. The latter doesn't
+ // happen often, but allowing it makes certain things a bit
+ // easier; e.g. scavenging an object is idempotent, so it's OK to
+ // have an object on the mutable list multiple times.
if (bd->flags & BF_EVACUATED) {
+ // We aren't copying this object, so we have to check
+ // whether it is already in the target generation. (this is
+ // the write barrier).
if (bd->step < gct->evac_step) {
gct->failed_to_evac = rtsTrue;
TICK_GC_FAILED_PROMOTION();
info = get_itbl(q);
if (info->type == TSO &&
((StgTSO *)q)->what_next == ThreadRelocated) {
- q = (StgClosure *)((StgTSO *)q)->link;
+ q = (StgClosure *)((StgTSO *)q)->_link;
*p = q;
goto loop;
}
/* Deal with redirected TSOs (a TSO that's had its stack enlarged).
*/
if (tso->what_next == ThreadRelocated) {
- q = (StgClosure *)tso->link;
+ q = (StgClosure *)tso->_link;
*p = q;
goto loop;
}