2000-06-12
2000-06-12 21:41:41 by Martin Stjernholm <mast@lysator.liu.se>
-
46d4e7fe5e87d1857937c2bd2e0e7bc7f97e6eca
(76 lines)
(+42/-34)
[
Show
| Annotate
]
Branch: 7.9
Fixed another bug with GC_DONT_POP.
Rev: src/gc.c:1.95
Rev: src/gc.h:1.50
Rev: src/testsuite.in:1.302
29:
#include "block_alloc.h"
- RCSID("$Id: gc.c,v 1.94 2000/06/12 19:35:08 mast Exp $");
+ RCSID("$Id: gc.c,v 1.95 2000/06/12 21:41:41 mast Exp $");
/* Run garbage collect approximately every time
* 20 percent of all arrays, objects and programs is
114:
* cyclic reference at a chosen point. Some markers thus get a place
* earlier on the list even though their corresponding stack frames
* are later than some other markers they have references to. These
- * markers are given the GC_DONT_POP flag to make them stay on the
- * list when they're popped from the stack. They'll get popped
- * eventually since all markers in the gap between the top one and
- * it's previous gc_rec_last point are popped.
+ * markers are flagged to make them stay on the list when they're
+ * popped from the stack. They'll get popped eventually since all
+ * markers in the gap between the top one and it's previous
+ * gc_rec_last point are popped.
*
* Markers for live objects are linked into the beginning of kill_list
* when they're popped from rec_list.
408:
static void describe_marker(struct marker *m)
{
if (m)
- fprintf(stderr, "marker at %p: flags=0x%04x, refs=%d, weak=%d, "
+ fprintf(stderr, "marker at %p: flags=0x%06x, refs=%d, weak=%d, "
"xrefs=%d, cycle=%d, link=%p\n",
m, m->flags, m->refs, m->weak_refs,
m->xrefs, m->cycle, m->link);
747:
if (!(m->flags & GC_TOUCHED))
gc_fatal(a, 2, "An existing but untouched marker found "
"for object in linked lists.\n");
- else if (m->flags & (GC_RECURSING|GC_LIVE_RECURSE|GC_DONT_POP|
- GC_WEAK_REF|GC_STRONG_REF))
+ else if (m->flags & (GC_ON_STACK|GC_IN_REC_LIST|GC_DONT_POP|
+ GC_LIVE_RECURSE|GC_WEAK_REF|GC_STRONG_REF))
gc_fatal(a, 2, "Marker still got flag from recurse list.\n");
else if (m->flags & GC_REFERENCED)
return;
1057:
/* There's a cycle from beg to gc_rec_last which should be broken at
* pos. Do it by switching places of the markers before and after pos. */
struct marker *p, *q;
- CYCLE_DEBUG_MSG(pos, "break_cycle");
+
#ifdef PIKE_DEBUG
if (beg == pos)
gc_fatal(beg->data, 0, "Cycle already broken at requested position.\n");
1074:
else
for (p = &rec_list; p->link != beg; p = p->link) {}
+ CYCLE_DEBUG_MSG(beg, "break_cycle, break from");
+ CYCLE_DEBUG_MSG(pos, "break_cycle, break at");
+
p->link = pos;
for (p = beg; p->link != pos; p = p->link) {}
for (q = pos;; q = q->link) {
- q->flags |= GC_DONT_POP;
+ q->flags |= GC_MOVED_BACK|GC_DONT_POP;
CYCLE_DEBUG_MSG(q, "break_cycle, mark for don't pop");
if (q == gc_rec_last) break;
}
1178:
if (weak >= 0) gc_rec_last->flags |= GC_FOLLOWED_NONSTRONG;
#endif
- if (m->flags & GC_RECURSING) { /* A cyclic reference is found. */
+ if (m->flags & GC_IN_REC_LIST) { /* A cyclic reference is found. */
#ifdef PIKE_DEBUG
if (m == &rec_list || gc_rec_last == &rec_list)
gc_fatal(x, 0, "Cyclic ref involves dummy rec_list marker.\n");
1259:
if (p == gc_rec_last) break;
}}}} /* Mmm.. lisp ;) */
- else { /* A forward reference. */
- /* It might be a reference to a marker that has been swapped
+ else /* A forward reference. */
+ if (m->flags & GC_ON_STACK) {
+ /* It's a reference to a marker that has been swapped
* further down the list by break_cycle(). In that case we
- * must mark this path to stay on the list. */
- struct marker *q = 0;
+ * must mark gc_rec_last to stay on the list. */
+ CYCLE_DEBUG_MSG(m, "gc_cycle_push, mark for don't pop");
+ gc_rec_last->flags |= GC_DONT_POP;
+ }
+ else
CYCLE_DEBUG_MSG(m, "gc_cycle_push, forward ref");
- for (p = rec_list.link; p != gc_rec_last; p = p->link)
- if (p->flags & GC_DONT_POP) q = p;
- if (q)
- for (p = q->link;; p = p->link) {
- p->flags |= GC_DONT_POP;
- CYCLE_DEBUG_MSG(p, "gc_cycle_push, mark for don't pop");
- if (p == gc_rec_last) break;
+
}
}
- }
- }
+
else
if (!(m->flags & GC_CYCLE_CHECKED)) {
1287: Inside #if defined(PIKE_DEBUG)
}
#ifdef PIKE_DEBUG
cycle_checked++;
+ if (m->flags & GC_ON_STACK)
+ gc_fatal(x, 0, "Recursing twice into thing.\n");
if (m->flags & GC_LIVE_RECURSE)
gc_fatal(x, 0, "GC_LIVE_RECURSE set in normal recursion.\n");
#endif
1296:
for (; p->link && p->link->cycle == gc_rec_last->cycle; p = p->link) {}
m->link = p->link;
p->link = m;
- m->flags |= GC_CYCLE_CHECKED|GC_RECURSING;
+ m->flags |= GC_CYCLE_CHECKED|GC_ON_STACK|GC_IN_REC_LIST;
m->cycle = 0;
#ifdef GC_CYCLE_DEBUG
1376:
gc_cycle_indent -= 2;
#endif
- if (!(m->flags & GC_RECURSING) || m->flags & GC_LIVE_RECURSE) {
+ if (m->flags & GC_LIVE_RECURSE) {
m->flags &= ~GC_LIVE_RECURSE;
- CYCLE_DEBUG_MSG(m, "gc_cycle_pop, pop ignored");
+ CYCLE_DEBUG_MSG(m, "gc_cycle_pop, live pop");
return;
}
#ifdef PIKE_DEBUG
-
+ if (!(m->flags & GC_ON_STACK))
+ gc_fatal(a, 0, "Marker being popped isn't on stack.\n");
if (m->flags & GC_GOT_DEAD_REF)
gc_fatal(a, 0, "Didn't expect a dead extra ref.\n");
#endif
1393:
gc_fatal(a, 0, "Found GC_DONT_POP marker on top of stack.\n");
#endif
CYCLE_DEBUG_MSG(m, "gc_cycle_pop, keep on stack");
+ if (!(m->flags & GC_MOVED_BACK)) {
+ gc_rec_last->flags |= GC_DONT_POP;
+ CYCLE_DEBUG_MSG(gc_rec_last, "gc_cycle_pop, propagate don't pop");
+ }
return;
}
1406:
if (!p->cycle && !(p->flags & GC_LIVE_OBJ)) {
ADD_REF_IF_DEAD(p);
- p->flags &= ~(GC_RECURSING|GC_DONT_POP|GC_WEAK_REF|GC_STRONG_REF);
+ p->flags &= ~(GC_ON_STACK|GC_IN_REC_LIST|GC_DONT_POP|
+ GC_WEAK_REF|GC_STRONG_REF);
q->link = p->link;
DO_IF_DEBUG(p->link = (struct marker *) -1);
CYCLE_DEBUG_MSG(p, "gc_cycle_pop, pop off");
}
else {
- p->flags &= ~(GC_DONT_POP|GC_WEAK_REF|GC_STRONG_REF);
+ p->flags &= ~(GC_ON_STACK|GC_DONT_POP|
+ GC_WEAK_REF|GC_STRONG_REF);
q = p;
}
if (p == m) break;
1439: Inside #if defined(PIKE_DEBUG)
#ifdef PIKE_DEBUG
if (p->cycle && cycle && p->cycle != cycle)
gc_fatal(p->data, 0, "Popping more than one cycle from rec_list.\n");
- if (!(p->flags & GC_RECURSING))
- gc_fatal(p->data, 0, "Marker being cycle popped doesn't have GC_RECURSING.\n");
+ if (!(p->flags & GC_IN_REC_LIST))
+ gc_fatal(p->data, 0, "Marker being cycle popped doesn't have GC_IN_REC_LIST.\n");
if (p->flags & GC_GOT_DEAD_REF)
gc_fatal(p->data, 0, "Didn't expect a dead extra ref.\n");
#endif
- p->flags &= ~GC_RECURSING;
+ p->flags &= ~GC_IN_REC_LIST;
if (p->flags & GC_LIVE_OBJ) {
/* This extra ref is taken away in the kill pass. */