pike.git / src / gc.c

version» Context lines:

pike.git/src/gc.c:1:   /*   || This file is part of Pike. For copyright information see COPYRIGHT.   || Pike is distributed under GPL, LGPL and MPL. See the file COPYING   || for more information. - || $Id: gc.c,v 1.268 2005/04/14 21:55:38 mast Exp $ + || $Id: gc.c,v 1.269 2005/04/14 22:50:12 mast Exp $   */      #include "global.h"      struct callback *gc_evaluator_callback=0;      #include "array.h"   #include "multiset.h"   #include "mapping.h"   #include "object.h"
pike.git/src/gc.c:125:   {    GC_STACK_COMMON_FIELDS;    INT16 weak; /* Weak flag to checkfn. */    gc_cycle_check_cb *checkfn;   };      struct gc_pop_frame   {    GC_STACK_COMMON_FIELDS;    unsigned INT16 cycle; /* Cycle id number. */ -  struct gc_pop_frame *prev; /* Previous frame in rec_list. */ -  struct gc_pop_frame *next; /* Next pointer in rec_list and kill_list. */ +  struct gc_pop_frame *prev; /* Previous frame in the frame list. */ +  struct gc_pop_frame *next; /* Next pointer in the frame list and in kill_list. */   };      struct gc_free_extra_frame /* Used on free_extra_list. See gc_delayed_free. */   {    void *data;    struct gc_free_extra_frame *fe_next; /* Next pointer. */    int type; /* The type of the thing. */   };      struct gc_frame
pike.git/src/gc.c:148:    union {    struct gc_link_frame link;    struct gc_pop_frame pop;    struct gc_free_extra_frame free_extra;    struct gc_frame *next; /* For block_alloc. */    } u;   };      /* frameflags bits. */   #define GC_POP_FRAME 0x01 - #define GC_WEAK_REF 0x02 - #define GC_STRONG_REF 0x04 - #define GC_OFF_STACK 0x08 - #define GC_ON_KILL_LIST 0x10 + #define GC_PREV_WEAK 0x02 /* Only applicable in pop frames. */ + #define GC_PREV_STRONG 0x04 /* Only applicable in pop frames. */ + #define GC_OFF_STACK 0x08 /* Only applicable in pop frames. */ + #define GC_ON_KILL_LIST 0x10 /* Only applicable in pop frames. */   #ifdef PIKE_DEBUG - #define GC_LINK_FREED 0x20 + #define GC_FRAME_FREED 0x20   #define GC_FOLLOWED_NONSTRONG 0x40   #endif      #undef BLOCK_ALLOC_NEXT   #define BLOCK_ALLOC_NEXT u.next      BLOCK_ALLOC(gc_frame,GC_LINK_CHUNK_SIZE)      static INLINE struct gc_pop_frame *alloc_pop_frame()   {
pike.git/src/gc.c:187:   {    return (struct gc_free_extra_frame *) alloc_gc_frame();   }      #ifdef PIKE_DEBUG      static unsigned num_gc_stack_frames = 0;      void debug_free_gc_stack_frame (struct gc_stack_frame *f)   { -  if (f->frameflags & GC_LINK_FREED) +  if (f->frameflags & GC_FRAME_FREED)    gc_fatal (f->data, 0, "Freeing freed gc_stack_frame.\n"); -  f->frameflags |= GC_LINK_FREED; +  f->frameflags |= GC_FRAME_FREED;    f->s_prev = (struct gc_stack_frame *) (ptrdiff_t) -1;    if (f->frameflags & GC_POP_FRAME) {    struct gc_pop_frame *p = (struct gc_pop_frame *) f;    p->prev = p->next = (struct gc_pop_frame *)(ptrdiff_t) -1;    }    really_free_gc_frame ((struct gc_frame *) f);   #ifdef GC_VERBOSE    num_gc_stack_frames--;   #endif   }
pike.git/src/gc.c:234:   #define STACK2POP(f) ((struct gc_pop_frame *) f)   #define STACK2LINK(f) ((struct gc_link_frame *) f)      #endif      #define gc_frame gc_foo_frame      #ifdef PIKE_DEBUG   #define CHECK_POP_FRAME(frame) do { \    struct gc_pop_frame *f_ = (frame); \ -  if (f_->frameflags & GC_LINK_FREED) \ +  if (f_->frameflags & GC_FRAME_FREED) \    gc_fatal (f_->data, 0, "Accessing freed gc_stack_frame.\n"); \    if (!(f_->frameflags & GC_POP_FRAME)) \    gc_fatal(f_->data, 0, #frame " is not a pop frame.\n"); \    if (f_->prev->next != f_) \    gc_fatal(f_->data, 0, "Pop frame pointers are inconsistent.\n"); \   } while (0)   #else   #define CHECK_POP_FRAME(frame) do {} while (0)   #endif    - static struct gc_pop_frame rec_list = {NULL, NULL, GC_POP_FRAME, 0, NULL, NULL}; - static struct gc_pop_frame *list_end = &rec_list; - static struct gc_stack_frame *stack_top = NULL; + static struct gc_pop_frame sentinel_frame = {NULL, NULL, GC_POP_FRAME, 0, NULL, NULL}; + static struct gc_pop_frame *list_end = &sentinel_frame; + static struct gc_stack_frame *stack_top = (struct gc_stack_frame *) &sentinel_frame; + static struct gc_pop_frame *stack_top_pop = &sentinel_frame;   static struct gc_pop_frame *kill_list = NULL;   static struct gc_free_extra_frame *free_extra_list = NULL; /* See note in gc_delayed_free. */      static unsigned last_cycle;   size_t gc_ext_weak_refs;      /* gc_frame objects are used as frames in a recursion stack during the    * cycle check pass. stack_top points to the current top of the    * stack. When a thing is recursed, a pop frame is first pushed on the    * stack and then the gc_cycle_check_* function fills in with link
pike.git/src/gc.c:277:    * A range of frames which always ends at the end of the list may be    * rotated a number of slots to break a cyclic reference at a chosen    * point. The stack of link frames are rotated simultaneously.    *    * Frames for live objects are linked into the beginning of kill_list    * when they're popped from rec_list.    *    * The cycle check functions might recurse another round through the    * frames that have been recursed already, to propagate the GC_LIVE    * flag to things that have been found to be referenced from live -  * objects. rec_list is not touched at all in this extra round. +  * objects. The frame list is not touched at all in this extra round.    */      static double objects_alloced = 0.0;   static double objects_freed = 0.0;   static double gc_time = 0.0, non_gc_time = 0.0;   static cpu_time_t last_gc_end_time = 0;   #if CPU_TIME_IS_THREAD_LOCAL == PIKE_NO   cpu_time_t auto_gc_time = 0;   #endif   
pike.git/src/gc.c:354: Inside #if defined(PIKE_DEBUG)
     #ifdef PIKE_DEBUG      #undef get_marker   #define get_marker(X) ((struct marker *) debug_malloc_pass(debug_get_marker(X)))   #undef find_marker   #define find_marker(X) ((struct marker *) debug_malloc_pass(debug_find_marker(X)))      int gc_in_cycle_check = 0;   static unsigned delayed_freed, weak_freed, checked, marked, cycle_checked, live_ref; - static unsigned max_gc_stack_frames, live_rec, frame_rot; + static unsigned max_gc_stack_frames, live_rec, frame_rot, link_search;   static unsigned gc_extra_refs = 0;      static unsigned max_tot_gc_stack_frames = 0;   static unsigned tot_cycle_checked = 0, tot_live_rec = 0, tot_frame_rot = 0;      static int gc_is_watching = 0;      int attempt_to_identify(void *something, void **inblock)   {    size_t i;
pike.git/src/gc.c:1483:       case GC_PASS_POSTTOUCH:    m = find_marker(a);    if (!*(INT32 *) a)    gc_fatal(a, 1, "Found a thing without refs.\n");    if (m) {    if (!(m->flags & (GC_PRETOUCHED|GC_MIDDLETOUCHED)))    gc_fatal(a, 2, "An existing but untouched marker found "    "for object in linked lists.\n");    else if (m->flags & GC_LIVE_RECURSE || -  (m->frame && m->frame->frameflags & (GC_WEAK_REF|GC_STRONG_REF))) +  (m->frame && m->frame->frameflags & (GC_PREV_WEAK|GC_PREV_STRONG)))    gc_fatal(a, 2, "Thing still got flag from recurse list.\n");   #ifdef PIKE_DEBUG    else if (m->flags & GC_MARKED)    return;    else if (gc_destruct_everything)    return;    else if (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_XREFERENCED)    gc_fatal(a, 3, "A thing with external references "    "got missed by mark pass.\n");    else if (!(m->flags & GC_CYCLE_CHECKED))
pike.git/src/gc.c:1668: Inside #if defined(PIKE_DEBUG)
  #ifdef PIKE_DEBUG    if (!gc_is_watching) {   #endif   #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP)    /* The marker hash table is left around after a previous gc if    * gc_keep_markers is set. */    if (marker_hash_table) cleanup_markers();    if (!marker_hash_table)   #endif    low_init_marker_hash(num_objects); -  get_marker(rec_list.data); /* Used to simplify fencepost conditions. */ +  get_marker(sentinel_frame.data); /* Used to simplify fencepost conditions. */   #ifdef PIKE_DEBUG    }   #endif   }      void exit_gc(void)   {    if (gc_evaluator_callback) {    remove_callback(gc_evaluator_callback);    gc_evaluator_callback = NULL;
pike.git/src/gc.c:2101: Inside #if defined(PIKE_DEBUG)
   struct gc_pop_frame *p = alloc_pop_frame();   #ifdef PIKE_DEBUG    if (Pike_in_gc != GC_PASS_CYCLE)    gc_fatal(data, 0, "Use of the gc frame stack outside the cycle check pass.\n");   #endif   #ifdef GC_VERBOSE    if (++num_gc_stack_frames > max_gc_stack_frames)    max_gc_stack_frames = num_gc_stack_frames;   #endif    p->data = data; -  p->prev = list_end; -  p->next = 0; + #ifdef PIKE_DEBUG +  p->prev = p->next = (struct gc_pop_frame *) (ptrdiff_t) -1; + #endif    p->cycle = 0;    p->s_prev = stack_top;   #ifdef GC_STACK_DEBUG    fprintf(stderr, "enqueue %p [%p]: ", p, stack_top);    describe_gc_stack_frame (POP2STACK (p));    fputc('\n', stderr);   #endif    stack_top = POP2STACK (p); -  +  stack_top_pop = p;    return p;   }      void gc_cycle_run_queue()   {   #ifdef PIKE_DEBUG    if (Pike_in_gc != GC_PASS_CYCLE)    Pike_fatal("Use of the gc frame stack outside the cycle check pass.\n");   #endif -  while (stack_top) { +  +  while (stack_top != POP2STACK (&sentinel_frame)) {   #ifdef GC_STACK_DEBUG    fprintf(stderr, "dequeue %p [%p]: ", stack_top, stack_top->s_prev);    describe_gc_stack_frame(stack_top);    fputc('\n', stderr);   #endif -  +     if (stack_top->frameflags & GC_POP_FRAME) {    struct gc_stack_frame *f = stack_top->s_prev;    gc_cycle_pop (stack_top->data);    stack_top = f; -  } else { +  +  /* Use separate pointer chain instead? */ +  for (; !(f->frameflags & GC_POP_FRAME); f = f->s_prev) {} +  stack_top_pop = STACK2POP (f); +  } +  +  else {    struct gc_link_frame l = *STACK2LINK (stack_top);   #ifdef PIKE_DEBUG -  if (l.frameflags & GC_LINK_FREED) +  if (l.frameflags & GC_FRAME_FREED)    gc_fatal(l.data, 0, "Accessing freed gc_frame.\n");   #endif    FREE_LINK_FRAME (STACK2LINK (stack_top));    stack_top = l.s_prev;    l.checkfn (l.data, l.weak);    }    }   }      #ifdef GC_CYCLE_DEBUG   static int gc_cycle_indent = 0;   #define CYCLE_DEBUG_MSG(M, TXT) do { \ -  fprintf(stderr, "%*s%-35s %p [%p] ", gc_cycle_indent, "", \ -  (TXT), (M) ? (M)->data : 0, list_end->data); \ +  fprintf(stderr, "%*s%-35s %p [stack:%p, list:%p] ", gc_cycle_indent, "", \ +  (TXT), (M) ? (M)->data : 0, stack_top->data, list_end->data); \    describe_marker(M); \   } while (0)   #else   #define CYCLE_DEBUG_MSG(M, TXT) do {} while (0)   #endif    - static void rotate_rec_list (struct gc_pop_frame *beg, struct gc_pop_frame *pos) + static void rotate_frame_list (struct gc_pop_frame *beg, struct gc_pop_frame *pos)   /* Rotates the marker list and the cycle stack so the bit from pos    * down to the end gets before the bit from beg down to pos. The beg    * pos might be moved further down the stack to avoid mixing cycles or    * breaking strong link sequences. */   {   #ifdef GC_STACK_DEBUG    struct gc_stack_frame *l;   #endif -  CYCLE_DEBUG_MSG(find_marker(beg->data), "> rotate_rec_list, asked to begin at"); +  CYCLE_DEBUG_MSG(find_marker(beg->data), "> rotate_frame_list, asked to begin at");      #ifdef PIKE_DEBUG    if (Pike_in_gc != GC_PASS_CYCLE)    Pike_fatal("Use of the gc frame stack outside the cycle check pass.\n");    CHECK_POP_FRAME(beg);    CHECK_POP_FRAME(pos);    if (beg == pos)    gc_fatal(beg->data, 0, "Cycle already broken at requested position.\n");    if (list_end->next)    gc_fatal(list_end->data, 0, "list_end not at end.\n");   #endif      #ifdef GC_STACK_DEBUG    fprintf(stderr,"Stack before:\n"); -  for (l = stack_top; l; l = l->s_prev) { +  for (l = stack_top; l != &sentinel_frame; l = l->s_prev) {    fprintf(stderr, " %p ", l);    describe_gc_stack_frame(l);    fputc('\n', stderr);    }   #endif    - #if 0 -  if (beg->cycle) { -  for (l = beg; l->prev->cycle == beg->cycle; l = l->prev) -  CHECK_POP_FRAME(l); -  if (l->cycle == pos->cycle) { -  /* Breaking something previously marked as a cycle. Clear it -  * since we're no longer sure it's an unambiguous cycle. */ -  unsigned cycle = l->cycle; -  for (; l && l->cycle == cycle; l = l->next) { -  CHECK_POP_FRAME(l); - #ifdef GC_CYCLE_DEBUG -  if (l->cycle) -  CYCLE_DEBUG_MSG(find_marker(l->data), "> rotate_rec_list, clear cycle"); - #endif -  l->cycle = 0; -  } -  } -  else beg = l; /* Keep the cycle continuous. */ -  } - #endif -  +     /* Always keep chains of strong refs continuous, or else we risk    * breaking the order in a later rotation. */ -  for (; beg->frameflags & GC_STRONG_REF; beg = beg->prev) {} +  for (; beg->frameflags & GC_PREV_STRONG; beg = beg->prev) {}    -  CYCLE_DEBUG_MSG(find_marker(beg->data), "> rotate_rec_list, begin at"); +  CYCLE_DEBUG_MSG(find_marker(beg->data), "> rotate_frame_list, begin at");       {    struct gc_pop_frame *b = beg, *p = pos;    struct gc_stack_frame *old_stack_top;    while (b->frameflags & GC_OFF_STACK) {    if ((b = b->next) == pos) goto done;    CHECK_POP_FRAME(b);    DO_IF_DEBUG(frame_rot++);    }    while (p->frameflags & GC_OFF_STACK) {
pike.git/src/gc.c:2243:    {    struct gc_pop_frame *new_list_end = pos->prev;    beg->prev->next = pos;    pos->prev = beg->prev;    list_end->next = beg;    beg->prev = list_end;    list_end = new_list_end;    list_end->next = 0;    }    -  if (beg->frameflags & GC_WEAK_REF) { -  beg->frameflags &= ~GC_WEAK_REF; -  pos->frameflags |= GC_WEAK_REF; -  CYCLE_DEBUG_MSG(get_marker(pos->data), "> rotate_rec_list, moved weak flag"); -  } -  +    #ifdef GC_STACK_DEBUG    fprintf(stderr,"Stack after:\n"); -  for (l = stack_top; l; l = l->s_prev) { +  for (l = stack_top; l != sentinel_frame; l = l->s_prev) {    fprintf(stderr, " %p ", l);    describe_gc_stack_frame(l);    fputc('\n', stderr);    }   #endif   }      int gc_cycle_push(void *x, struct marker *m, int weak)   { -  struct marker *last = find_marker(list_end->data); +  struct marker *top = find_marker (stack_top_pop->data);    -  +  /* FIXME: Should use top instead? */ +  struct marker *last = find_marker (list_end->data); +    #ifdef PIKE_DEBUG    if (gc_is_watching && m && m->flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_cycle_push()");    }       debug_malloc_touch(x);       if (!x) Pike_fatal("Got null pointer.\n");    if (m->data != x) Pike_fatal("Got wrong marker.\n");
pike.git/src/gc.c:2285: Inside #if defined(PIKE_DEBUG)
   if (gc_debug && !(m->flags & GC_PRETOUCHED))    gc_fatal(x, 0, "gc_cycle_push() called for untouched thing.\n");    if (!gc_destruct_everything) {    if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) &&    *(INT32 *) x)    gc_fatal(x, 1, "Got a referenced marker to gc_cycle_push.\n");    if (m->flags & GC_XREFERENCED)    gc_fatal(x, 1, "Doing cycle check in externally referenced thing "    "missed in mark pass.\n");    } -  if (weak && list_end == &rec_list) +  if (weak && list_end == &sentinel_frame)    gc_fatal(x, 1, "weak is %d when on top of stack.\n", weak);    if (gc_debug > 1) {    struct array *a;    struct object *o;    struct program *p;    struct mapping *m;    struct multiset *l;    for(a = gc_internal_array; a; a = a->next)    if(a == (struct array *) x) goto on_gc_internal_lists;    for(o = gc_internal_object; o; o = o->next)
pike.git/src/gc.c:2309: Inside #if defined(PIKE_DEBUG)
   for(m = gc_internal_mapping; m; m = m->next)    if(m == (struct mapping *) x) goto on_gc_internal_lists;    for(l = gc_internal_multiset; l; l = l->next)    if(l == (struct multiset *) x) goto on_gc_internal_lists;    gc_fatal(x, 0, "gc_cycle_check() called for thing not on gc_internal lists.\n");    on_gc_internal_lists:    ; /* We must have a least one expression after a label! - Hubbe */    }   #endif    -  if (last->flags & GC_LIVE_RECURSE) { +  if (top->flags & GC_LIVE_RECURSE) {   #ifdef PIKE_DEBUG -  if (!(last->flags & GC_LIVE)) +  if (!(top->flags & GC_LIVE))    gc_fatal(x, 0, "Doing live recursion from a dead thing.\n");   #endif       if (m->flags & GC_CYCLE_CHECKED) {    if (!(m->flags & GC_LIVE)) {    /* Only recurse through things already handled; we'll get to the    * other later in the normal recursion. */   #ifdef PIKE_DEBUG    if (m->flags & GC_LIVE_RECURSE)    gc_fatal(x, 0, "Mark live recursion attempted twice into thing.\n");   #endif    goto live_recurse;    }    CYCLE_DEBUG_MSG(m, "gc_cycle_push, no live recurse");    }       else {    /* We'll get here eventually in the normal recursion. Pop off    * the remaining live recurse frames for the last thing. */    CYCLE_DEBUG_MSG(m, "gc_cycle_push, no live recurse"); -  last->flags &= ~GC_LIVE_RECURSE; +  top->flags &= ~GC_LIVE_RECURSE;    while (1) { -  struct gc_stack_frame *l = stack_top; +  struct gc_stack_frame *l = stack_top, *f;   #ifdef PIKE_DEBUG -  if (!stack_top) -  Pike_fatal("Expected a gc_cycle_pop entry in stack_top.\n"); +  if (stack_top == POP2STACK (&sentinel_frame)) +  Pike_fatal ("Stack shouldn't be empty here.\n");   #endif    stack_top = l->s_prev; -  +  +  /* Use separate pointer chain instead? */ +  for (f = stack_top; !(f->frameflags & GC_POP_FRAME); f = f->s_prev) {} +  stack_top_pop = STACK2POP (f); +     if (l->frameflags & GC_POP_FRAME) { -  list_end = STACK2POP (l)->prev; +     FREE_POP_FRAME (STACK2POP (l));    break;    }    FREE_LINK_FRAME (STACK2LINK (l));    }   #ifdef GC_CYCLE_DEBUG    gc_cycle_indent -= 2;    CYCLE_DEBUG_MSG(m, "> gc_cycle_push, unwound live rec");   #endif    }       return 0;    }      #ifdef PIKE_DEBUG -  if (weak < 0 && list_end->frameflags & GC_FOLLOWED_NONSTRONG) +  if (weak < 0 && stack_top->frameflags & GC_FOLLOWED_NONSTRONG)    gc_fatal(x, 0, "Followed strong link too late.\n"); -  if (weak >= 0) list_end->frameflags |= GC_FOLLOWED_NONSTRONG; +  if (weak >= 0) stack_top->frameflags |= GC_FOLLOWED_NONSTRONG;   #endif       if (m->frame && !(m->frame->frameflags & GC_ON_KILL_LIST)) {    /* A cyclic reference is found. */   #ifdef PIKE_DEBUG -  if (list_end == &rec_list) -  gc_fatal(x, 0, "Cyclic ref involves dummy rec_list marker.\n"); +  if (list_end == &sentinel_frame) +  gc_fatal(x, 0, "Cyclic ref involves dummy sentinel_frame marker.\n");    CHECK_POP_FRAME(list_end);    CHECK_POP_FRAME(m->frame);   #endif       if (m != last) {    struct gc_pop_frame *p, *weak_ref = 0, *nonstrong_ref = 0;    if (!weak) {    struct gc_pop_frame *q;    CYCLE_DEBUG_MSG(m, "gc_cycle_push, search normal");    /* Find the last weakly linked thing and the one before the    * first strongly linked thing. */    for (q = m->frame, p = q->next;; q = p, p = p->next) { -  +  CYCLE_DEBUG_MSG (find_marker (p->data), "> gc_cycle_push, search");    CHECK_POP_FRAME(p); -  if (p->frameflags & (GC_WEAK_REF|GC_STRONG_REF)) { -  if (p->frameflags & GC_WEAK_REF) weak_ref = p; +  DO_IF_DEBUG (link_search++); +  if (p->frameflags & (GC_PREV_WEAK|GC_PREV_STRONG)) { +  if (p->frameflags & GC_PREV_WEAK) weak_ref = p;    else if (!nonstrong_ref) nonstrong_ref = q;    }    if (p == list_end) break;    }    }       else if (weak < 0) {    CYCLE_DEBUG_MSG(m, "gc_cycle_push, search strong");    /* Find the last weakly linked thing and the last one which    * isn't strongly linked. */    for (p = m->frame->next;; p = p->next) { -  +  CYCLE_DEBUG_MSG (find_marker (p->data), "> gc_cycle_push, search");    CHECK_POP_FRAME(p); -  if (p->frameflags & GC_WEAK_REF) weak_ref = p; -  if (!(p->frameflags & GC_STRONG_REF)) nonstrong_ref = p; +  DO_IF_DEBUG (link_search++); +  if (p->frameflags & GC_PREV_WEAK) weak_ref = p; +  if (!(p->frameflags & GC_PREV_STRONG)) nonstrong_ref = p;    if (p == list_end) break;    }   #ifdef PIKE_DEBUG    if (p == list_end && !nonstrong_ref) {    fprintf(stderr, "Only strong links in cycle:\n");    for (p = m->frame;; p = p->next) {    describe(p->data);    locate_references(p->data);    if (p == list_end) break;    fprintf(stderr, "========= next =========\n");
pike.git/src/gc.c:2417: Inside #if defined(PIKE_DEBUG)
   gc_fatal(0, 0, "Only strong links in cycle.\n");    }   #endif    }       else {    struct gc_pop_frame *q;    CYCLE_DEBUG_MSG(m, "gc_cycle_push, search weak");    /* Find the thing before the first strongly linked one. */    for (q = m->frame, p = q->next;; q = p, p = p->next) { +  CYCLE_DEBUG_MSG (find_marker (p->data), "> gc_cycle_push, search");    CHECK_POP_FRAME(p); -  if (!(p->frameflags & GC_WEAK_REF) && !nonstrong_ref) +  DO_IF_DEBUG (link_search++); +  if (!(p->frameflags & GC_PREV_WEAK) && !nonstrong_ref)    nonstrong_ref = q;    if (p == list_end) break;    }    }       if (weak_ref) {    /* The backward link is normal or strong and there are one    * or more weak links in the cycle. Let's break it at the    * last one (to ensure that a sequence of several weak links    * are broken at the last one). */    CYCLE_DEBUG_MSG(find_marker(weak_ref->data),    "gc_cycle_push, weak break"); -  rotate_rec_list(m->frame, weak_ref); +  rotate_frame_list (m->frame, weak_ref);    }       else if (weak < 0) {    /* The backward link is strong. Must break the cycle at the    * last nonstrong link. */    CYCLE_DEBUG_MSG(find_marker(nonstrong_ref->data),    "gc_cycle_push, nonstrong break"); -  rotate_rec_list(m->frame, nonstrong_ref); +  rotate_frame_list (m->frame, nonstrong_ref);    nonstrong_ref->next->frameflags = -  (nonstrong_ref->next->frameflags & ~GC_WEAK_REF) | GC_STRONG_REF; +  (nonstrong_ref->next->frameflags & ~GC_PREV_WEAK) | GC_PREV_STRONG;    }       else if (nonstrong_ref) {    /* Either a nonweak cycle with a strong link in it or a weak    * cycle with a nonweak link in it. Break before the first    * link that's stronger than the others. */    if (nonstrong_ref != m->frame) {    CYCLE_DEBUG_MSG(find_marker(nonstrong_ref->data),    "gc_cycle_push, weaker break"); -  rotate_rec_list(m->frame, nonstrong_ref); +  rotate_frame_list (m->frame, nonstrong_ref);    }    }       else if (!weak) {    /* A normal cycle which will be destructed in arbitrary    * order. For reasons having to do with strong links we    * can't mark weak cycles this way. */    unsigned cycle = m->frame->cycle ? m->frame->cycle : ++last_cycle;    if (cycle == list_end->cycle)    CYCLE_DEBUG_MSG(m, "gc_cycle_push, old cycle");
pike.git/src/gc.c:2481:    if (!(m->flags & GC_CYCLE_CHECKED)) {    struct gc_pop_frame *l;   #ifdef PIKE_DEBUG    cycle_checked++;    if (m->frame)    gc_fatal(x, 0, "Marker already got a frame.\n");    if (list_end->next)    gc_fatal(list_end->data, 0, "Not at end of list.\n");   #endif    -  list_end->next = m->frame = l = gc_cycle_enqueue_pop(x); +  m->frame = l = gc_cycle_enqueue_pop(x); +  l->next = NULL; +  l->prev = list_end; +  list_end->next = l;    m->flags |= GC_CYCLE_CHECKED | (last->flags & GC_LIVE);    debug_malloc_touch(x);    if (weak) { -  if (weak > 0) l->frameflags |= GC_WEAK_REF; -  else l->frameflags |= GC_STRONG_REF; +  if (weak > 0) l->frameflags |= GC_PREV_WEAK; +  else l->frameflags |= GC_PREV_STRONG;    }      #ifdef GC_CYCLE_DEBUG    if (weak > 0) CYCLE_DEBUG_MSG(m, "gc_cycle_push, recurse weak");    else if (weak < 0) CYCLE_DEBUG_MSG(m, "gc_cycle_push, recurse strong");    else CYCLE_DEBUG_MSG(m, "gc_cycle_push, recurse");    gc_cycle_indent += 2;   #endif    list_end = l;    return 1;
pike.git/src/gc.c:2526:    * Have to remove the extra ref added by gc_cycle_pop(). */    gc_free_extra_ref(x);    if (!sub_ref ((struct ref_dummy *) x)) {   #ifdef PIKE_DEBUG    gc_fatal(x, 0, "Thing got zero refs after removing the dead gc ref.\n");   #endif    }    }       { -  /* Recurse without linking onto rec_list. */ +  /* Recurse without linking onto the frame list. */    struct gc_pop_frame *l = gc_cycle_enqueue_pop(x);   #ifdef GC_CYCLE_DEBUG    CYCLE_DEBUG_MSG(m, "gc_cycle_push, live recurse");    gc_cycle_indent += 2;   #endif -  list_end = l; +     }      #ifdef PIKE_DEBUG    live_rec++;   #endif    return 1;   }      static void gc_cycle_pop(void *a)   {
pike.git/src/gc.c:2572: Inside #if defined(PIKE_DEBUG)
   "missed in mark pass.\n");    }   #endif   #ifdef GC_CYCLE_DEBUG    gc_cycle_indent -= 2;   #endif       if (m->flags & GC_LIVE_RECURSE) {    m->flags &= ~GC_LIVE_RECURSE;    CYCLE_DEBUG_MSG(m, "gc_cycle_pop_live"); -  list_end = STACK2POP (stack_top)->prev; +     FREE_POP_FRAME (STACK2POP (stack_top)); -  +  /* stack_top and stack_top_pop updated by caller. */    return;    }       here = m->frame;   #ifdef PIKE_DEBUG    if (!here || here->data != a)    gc_fatal(a, 0, "Marker being popped has no or invalid frame.\n");    CHECK_POP_FRAME(here);    CHECK_POP_FRAME(list_end);    if (here->frameflags & GC_OFF_STACK)    gc_fatal(a, 0, "Marker being popped isn't on stack.\n");    here->s_prev = (struct gc_stack_frame *)(ptrdiff_t) -1;   #endif    here->frameflags |= GC_OFF_STACK;       for (base = here->prev, p = here;; base = p, p = p->next) {    if (base == here) {    /* Part of a cycle; wait until the cycle is complete before -  * unlinking it from rec_list. */ +  * unlinking it from the frame list. */    DO_IF_DEBUG(m->frame->s_prev = (struct gc_stack_frame *)(ptrdiff_t) -1);    CYCLE_DEBUG_MSG(m, "gc_cycle_pop, keep cycle");    return;    }    CHECK_POP_FRAME(p);    if (!(p->cycle && p->cycle == base->cycle))    break;    }       list_end = base;    while ((p = base->next)) {    struct marker *pm = find_marker(p->data);   #ifdef PIKE_DEBUG    if (pm->frame != p)    gc_fatal(p->data, 0, "Bogus marker for thing being popped.\n");   #endif -  p->frameflags &= ~(GC_WEAK_REF|GC_STRONG_REF); +  p->frameflags &= ~(GC_PREV_WEAK|GC_PREV_STRONG);    if (pm->flags & GC_LIVE_OBJ) {    /* This extra ref is taken away in the kill pass. Don't add one    * if it got an extra ref already due to weak free. */    if (!(pm->flags & GC_GOT_DEAD_REF))    gc_add_extra_ref(p->data);    base = p;    p->frameflags |= GC_ON_KILL_LIST;    DO_IF_DEBUG(p->prev = (struct gc_pop_frame *)(ptrdiff_t) -1);    CYCLE_DEBUG_MSG(pm, "gc_cycle_pop, put on kill list");    }
pike.git/src/gc.c:2648:    pm->frame = 0;    FREE_POP_FRAME (p);    }    }       if (base != list_end) {    base->next = kill_list;    kill_list = list_end->next;    list_end->next = 0;    } +  +  /* stack_top and stack_top_pop updated by caller. */   }      void do_gc_recurse_svalues(struct svalue *s, int num)   {    gc_recurse_svalues(s, num);   }      void do_gc_recurse_short_svalue(union anything *u, int type)   {    gc_recurse_short_svalue(u, type);
pike.git/src/gc.c:2871:       last_gc=TIME(0);    start_num_objs = num_objects;    start_allocs = num_allocs;    num_allocs = 0;       /* Object alloc/free and any reference changes are disallowed now. */      #ifdef PIKE_DEBUG    delayed_freed = weak_freed = checked = marked = cycle_checked = live_ref = 0; -  live_rec = frame_rot = 0; +  live_rec = frame_rot = link_search = 0;   #endif    if (gc_debug) {    unsigned n;    Pike_in_gc = GC_PASS_PRETOUCH;    n = gc_touch_all_arrays();    n += gc_touch_all_multisets();    n += gc_touch_all_mappings();    n += gc_touch_all_programs();    n += gc_touch_all_objects();   #ifdef PIKE_DEBUG
pike.git/src/gc.c:2973:    /* Note: The order between types here is normally not significant,    * but the permuting destruct order tests in the testsuite won't be    * really effective unless objects are handled first. :P */    gc_cycle_check_all_objects();    gc_cycle_check_all_arrays();    gc_cycle_check_all_multisets();    gc_cycle_check_all_mappings();    gc_cycle_check_all_programs();      #ifdef PIKE_DEBUG -  if (stack_top) -  Pike_fatal("stack_top not empty at end of cycle check pass.\n"); -  if (rec_list.next || list_end != &rec_list || stack_top) -  Pike_fatal("Recurse list not empty or inconsistent after cycle check pass.\n"); +  if (stack_top != POP2STACK (&sentinel_frame)) +  Pike_fatal("Frame stack not empty at end of cycle check pass.\n"); +  if (sentinel_frame.next || list_end != &sentinel_frame) +  Pike_fatal("Frame list not empty or inconsistent after cycle check pass.\n");    if (gc_ext_weak_refs != orig_ext_weak_refs)    Pike_fatal("gc_ext_weak_refs changed from %"PRINTSIZET"u "    "to %"PRINTSIZET"u in cycle check pass.\n",    orig_ext_weak_refs, gc_ext_weak_refs);   #endif       GC_VERBOSE_DO(fprintf(stderr,    "| cycle: %u internal things visited, %u cycle ids used,\n"    "| %u weak references freed, %d more things to free,\n"    "| %u live recursed frames, %u frame rotations,\n" -  "| space for %u gc frames used\n", +  "| %u links searched, space for %u gc frames used\n",    cycle_checked, last_cycle, weak_freed,    delayed_freed - obj_count, -  live_rec, frame_rot, max_gc_stack_frames)); +  live_rec, frame_rot, link_search, max_gc_stack_frames));    }       if (gc_ext_weak_refs) {    size_t to_free = gc_ext_weak_refs;   #ifdef PIKE_DEBUG    obj_count = delayed_freed;   #endif    Pike_in_gc = GC_PASS_ZAP_WEAK;    /* Zap weak references from external to internal things. That    * occurs when something has both external weak refs and nonweak
pike.git/src/gc.c:3033:    n = gc_touch_all_arrays();    n += gc_touch_all_multisets();    n += gc_touch_all_mappings();    n += gc_touch_all_programs();    n += gc_touch_all_objects();   #ifdef PIKE_DEBUG    gc_touch_all_strings();   #endif    if (n != (unsigned) num_objects)    Pike_fatal("Object count wrong in gc; expected %d, got %d.\n", num_objects, n); -  get_marker(rec_list.data)->flags |= GC_MIDDLETOUCHED; +  get_marker(sentinel_frame.data)->flags |= GC_MIDDLETOUCHED;   #if 0 /* Temporarily disabled - Hubbe */   #ifdef PIKE_DEBUG   #ifdef DEBUG_MALLOC    PTR_HASH_LOOP(marker, i, m)    if (!(m->flags & (GC_MIDDLETOUCHED|GC_WEAK_FREED)) &&    dmalloc_is_invalid_memory_block(m->data)) {    fprintf(stderr, "Found a stray marker after middletouch pass: ");    describe_marker(m);    fprintf(stderr, "Describing marker location(s):\n");    debug_malloc_dump_references(m, 2, 1, 0);