/* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.97 2001/03/02 14:28:44 simonmar Exp $
+ * $Id: GC.c,v 1.98 2001/03/02 16:15:53 simonmar Exp $
*
* (c) The GHC Team 1998-1999
*
/* wasn't there something about update squeezing and ticky to be
* sorted out? oh yes: we aren't counting each enter properly
* in this case. See the log somewhere. KSW 1999-04-21
+ *
+ * Check two things: that the two update frames don't point to
+ * the same object, and that the updatee_bypass isn't already an
+ * indirection. Both of these cases only happen when we're in a
+ * block hole-style loop (and there are multiple update frames
+ * on the stack pointing to the same closure), but they can both
+ * screw us up if we don't check.
*/
- if (updatee_bypass != updatee_keep) {
+ if (updatee_bypass != updatee_keep && !closure_IND(updatee_bypass)) {
/* this wakes the threads up */
UPD_IND_NOLOCK(updatee_bypass, updatee_keep);
}
/* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.92 2001/03/02 14:25:04 simonmar Exp $
+ * $Id: Schedule.c,v 1.93 2001/03/02 16:15:53 simonmar Exp $
*
* (c) The GHC Team, 1998-2000
*
/* Replace the updatee with an indirection - happily
* this will also wake up any threads currently
* waiting on the result.
+ *
+ * Warning: if we're in a loop, more than one update frame on
+ * the stack may point to the same object. Be careful not to
+ * overwrite an IND_OLDGEN in this case, because we'll screw
+ * up the mutable lists. To be on the safe side, don't
+ * overwrite any kind of indirection at all. See also
+ * threadSqueezeStack in GC.c, where we have to make a similar
+ * check.
*/
- UPD_IND_NOLOCK(su->updatee,ap); /* revert the black hole */
+ if (!closure_IND(su->updatee)) {
+ UPD_IND_NOLOCK(su->updatee,ap); /* revert the black hole */
+ }
su = su->link;
sp += sizeofW(StgUpdateFrame) -1;
sp[0] = (W_)ap; /* push onto stack */
break;
}
-
+
case CATCH_FRAME:
{
StgCatchFrame *cf = (StgCatchFrame *)su;
/* -----------------------------------------------------------------------------
- * $Id: Storage.h,v 1.30 2001/03/02 14:36:16 simonmar Exp $
+ * $Id: Storage.h,v 1.31 2001/03/02 16:15:53 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
/* In the DEBUG case, we also zero out the slop of the old closure,
* so that the sanity checker can tell where the next closure is.
+ *
+ * Two important invariants: we should never try to update a closure
+ * to point to itself, and the closure being updated should not
+ * already have been updated (the mutable list will get messed up
+ * otherwise).
*/
#define updateWithIndirection(info, p1, p2) \
{ \
bdescr *bd; \
\
- ASSERT( p1 != p2 ); \
+ ASSERT( p1 != p2 && !closure_IND(p1) ); \
bd = Bdescr((P_)p1); \
if (bd->gen->no == 0) { \
((StgInd *)p1)->indirectee = p2; \
*/
#define updateWithStaticIndirection(info, p1, p2) \
{ \
- ASSERT( p1 != p2 ); \
+ ASSERT( p1 != p2 && !closure_IND(p1) ); \
ASSERT( ((StgMutClosure*)p1)->mut_link == NULL ); \
\
ACQUIRE_LOCK(&sm_mutex); \
{
bdescr *bd;
- ASSERT( p1 != p2 ); \
+ ASSERT( p1 != p2 && !closure_IND(p1) );
bd = Bdescr((P_)p1);
if (bd->gen->no == 0) {
((StgInd *)p1)->indirectee = p2;