pike.git / src / gc.c

version» Context lines:

pike.git/src/gc.c:87:    * GC_PASS_ZAP_WEAK    * Zap weak references to unmarked objects.    *    * GC_PASS_POSTTOUCH    * Debug.    *    * GC_PASS_FREE    * Free remaining unmarked objects.    *    * GC_PASS_KILL -  * Destruct remaining unmarked live (lfun::destroy()) objects. +  * Destruct remaining unmarked live (lfun::_destruct()) objects.    *    * GC_PASS_DESTRUCT    * Destruct objects to destruct.    *    * And the following simulated passes:    *    * GC_PASS_LOCATE    *    * GC_PASS_DISABLED    */
pike.git/src/gc.c:142:    * to save them by adding external references to them. However, it's    * not possible for live objects to save themselves or other live    * objects; all live objects that didn't have external references at    * the start of the gc pass will be destructed regardless of added    * references.    *    * Things that have only weak external references at the start of the    * gc pass will be freed. That's done before the live object destruct    * pass. Internal weak references are however still intact.    * -  * Note: Keep the doc for lfun::destroy up-to-date with the above. +  * Note: Keep the doc for lfun::_destruct up-to-date with the above.    */      /* #define GC_DEBUG */   /* #define GC_VERBOSE */   /* #define GC_CYCLE_DEBUG */   /* #define GC_STACK_DEBUG */   /* #define GC_INTERVAL_DEBUG */      #if defined(GC_VERBOSE) && !defined(PIKE_DEBUG)   #undef GC_VERBOSE
pike.git/src/gc.c:165:   #define GC_VERBOSE_DO(X) X   #else   #define GC_VERBOSE_DO(X)   #endif      int num_objects = 2; /* Account for *_empty_array. */   int got_unlinked_things;   ALLOC_COUNT_TYPE num_allocs =0;   ALLOC_COUNT_TYPE alloc_threshold = GC_MIN_ALLOC_THRESHOLD;   PMOD_EXPORT int Pike_in_gc = 0; - int gc_generation = 0; + unsigned INT16 gc_generation = 1;   time_t last_gc;   int gc_trace = 0, gc_debug = 0;   #ifdef DO_PIKE_CLEANUP   int gc_destruct_everything = 0;   #endif   size_t gc_ext_weak_refs;      ALLOC_COUNT_TYPE saved_alloc_threshold;   /* Used to backup alloc_threshold if the gc is disabled, so that it    * can be restored when it's enabled again. This is to not affect the
pike.git/src/gc.c:558:   /* These callbacks are run early in the check pass of the gc and when    * locate_references is called. They are typically used to mark    * external references (using gc_mark_external) for debug purposes. */   struct callback *debug_add_gc_callback(callback_func call,    void *arg,    callback_func free_func)   {    return add_to_callback(&gc_callbacks, call, arg, free_func);   }    - static void init_gc(void); +    static void gc_cycle_pop();    - #undef BLOCK_ALLOC_NEXT - #define BLOCK_ALLOC_NEXT next -  - #undef INIT_BLOCK - #ifdef PIKE_DEBUG - #define INIT_BLOCK(X) \ -  (X)->flags=(X)->refs=(X)->weak_refs=(X)->xrefs=0; \ -  (X)->saved_refs=-1; \ -  (X)->frame = 0; - #else - #define INIT_BLOCK(X) \ -  (X)->flags=(X)->refs=(X)->weak_refs=0; \ -  (X)->frame = 0; - #endif - #undef EXIT_BLOCK - #define EXIT_BLOCK(f) -  - #undef get_marker - #define get_marker debug_get_marker - #undef find_marker - #define find_marker debug_find_marker -  - PTR_HASH_ALLOC_FIXED_FILL_PAGES(marker,2) -  - #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))) -  - PMOD_EXPORT struct marker *pmod_get_marker (void *p) - { -  return debug_get_marker (p); - } -  - PMOD_EXPORT struct marker *pmod_find_marker (void *p) - { -  return debug_find_marker (p); - } -  +    #if defined (PIKE_DEBUG) || defined (GC_MARK_DEBUG)   PMOD_EXPORT void *gc_found_in = NULL;   PMOD_EXPORT int gc_found_in_type = PIKE_T_UNKNOWN;   PMOD_EXPORT const char *gc_found_place = NULL;   #endif      #ifdef DO_PIKE_CLEANUP   /* To keep the markers after the gc. Only used for the leak report at exit. */   int gc_keep_markers = 0;   PMOD_EXPORT int gc_external_refs_zapped = 0;
pike.git/src/gc.c:724: Inside #if defined(PIKE_DEBUG)
   for(mu=first_multiset;mu;mu=mu->next)    if(mu==(struct multiset *)something)    return T_MULTISET;    else if (mu->msd == (struct multiset_data *) something)    return T_MULTISET_DATA;       if(safe_debug_findstring((struct pike_string *)something))    return T_STRING;       if (pike_type_hash) -  for (i = 0; i < pike_type_hash_size; i++) +  for (i = 0; i <= pike_type_hash_size; i++)    for (t = pike_type_hash[i]; t; t = t->next)    if (t == (struct pike_type *) something)    return T_TYPE;       for (c = first_callable; c; c = c->next)    if (c == (struct callable *) something)    return T_STRUCT_CALLABLE;       return PIKE_T_UNKNOWN;   }
pike.git/src/gc.c:934:    }    break;    }       case T_STORAGE:    fprintf(stderr, "%*s **In storage of object\n", indent, "");    break;       case T_MULTISET:    descblock = ((struct multiset *) memblock)->msd; -  /* FALL THROUGH */ +  /* FALLTHRU */       case T_MULTISET_DATA: {    struct multiset_data *msd = (struct multiset_data *) descblock;    union msnode *node = low_multiset_first (msd);    struct svalue ind;    for (; node; node = low_multiset_next (node)) {    if (&node->i.ind == (struct svalue *) location) {    fprintf (stderr, "%*s **In index ", indent, "");    safe_print_svalue (stderr, low_use_multiset_index (node, ind));    fputc ('\n', stderr);
pike.git/src/gc.c:970:    fprintf(stderr,"%*s **In a->prev\n",indent,"");       if( s-ITEM(a) > 0)    fprintf(stderr,"%*s **In index number %"PRINTPTRDIFFT"d\n",indent,"",    s-ITEM(a));    break;    }       case T_MAPPING:    descblock = ((struct mapping *) memblock)->data; -  /* FALL THROUGH */ +  /* FALLTHRU */    case T_MAPPING_DATA: {    INT32 e;    struct keypair *k;    NEW_MAPPING_LOOP((struct mapping_data *) descblock)    if (&k->ind == (struct svalue *) location) {    fprintf(stderr, "%*s **In index ", indent, "");    safe_print_svalue (stderr, &k->ind);    fputc('\n', stderr);    break;    }
pike.git/src/gc.c:1036: Inside #if defined(GC_STACK_DEBUG)
   fprintf (stderr, "data=%p prev=%p checkfn=%p weak=%d",    f->data, f->prev, f->checkfn, f->weak);   }   #endif      static void describe_marker(struct marker *m)   {    if (m) {    fprintf(stderr, "marker at %p: flags=0x%05lx refs=%d weak=%d "    "xrefs=%d saved=%d frame=%p", -  m, (long) m->flags, m->refs, m->weak_refs, +  m, (long) m->gc_flags, m->gc_refs, m->weak_refs,    m->xrefs, m->saved_refs, m->frame);    if (m->frame) {    fputs(" [", stderr);    describe_rec_frame (m->frame);    putc(']', stderr);    }    putc('\n', stderr);    }    else    fprintf(stderr, "no marker\n");
pike.git/src/gc.c:1168: Inside #if defined(PIKE_DEBUG)
   int indent,    int depth,    int flags,    void *inblock)   {    struct program *p=(struct program *)a;    struct marker *m;       if(depth<0) return;    -  if (marker_hash_table && (m = find_marker(a))) { +  if ((m = find_marker(a))) {    fprintf(stderr,"%*s**Got gc ",indent,"");    describe_marker(m);    }      again:    switch(t)    {    case T_STORAGE:    if (!inblock) attempt_to_identify (a, &a);    t = T_OBJECT;    goto again;       case T_FUNCTION:    if(attempt_to_identify(a, 0) != T_OBJECT)    {    fprintf(stderr,"%*s**Builtin function!\n",indent,"");    break;    } -  /* FALL THROUGH */ +  /* FALLTHRU */       case T_OBJECT:    p=((struct object *)a)->prog;    if(p && (p->flags & PROGRAM_USES_PARENT))    {    fprintf(stderr,"%*s**Parent identifier: %d\n",indent,"",PARENT_INFO( ((struct object *)a) )->parent_identifier);    }    fprintf(stderr,"%*s**Program id: %d\n",indent,"",((struct object *)a)->program_id);       if (((struct object *)a)->next == ((struct object *)a))
pike.git/src/gc.c:1751:    ID_FROM_INT(s->u.object->prog, SUBTYPEOF(*s))->name->str);    }    }    }    describe_something(s->u.refs, TYPEOF(*s), 0, 1, 0, 0);   }      PMOD_EXPORT void gc_watch(void *a)   {    struct marker *m; -  init_gc(); +     m = get_marker(a); -  if (!(m->flags & GC_WATCHED)) { -  m->flags |= GC_WATCHED; +  if (!(m->gc_flags & GC_WATCHED)) { +  m->gc_flags |= GC_WATCHED;    fprintf(stderr, "## Watching thing %p.\n", a);    gc_is_watching++;    }    else    fprintf(stderr, "## Already watching thing %p.\n", a);   }      static void gc_watched_found (struct marker *m, const char *found_in)   { -  fprintf(stderr, "## Watched thing %p with %d refs found in " -  "%s in pass %d.\n", m->data, *(INT32 *) m->data, found_in, Pike_in_gc); +  fprintf(stderr, "## Watched thing found in " +  "%s in pass %d.\n", found_in, Pike_in_gc);    describe_marker (m);   }      #endif /* PIKE_DEBUG */      #ifndef GC_MARK_DEBUG   struct pike_queue gc_mark_queue;   #define CHECK_MARK_QUEUE_EMPTY() assert (!gc_mark_queue.first)   #else /* GC_MARK_DEBUG */   
pike.git/src/gc.c:1842:   {    struct gc_queue_block *b;      #ifdef PIKE_DEBUG    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)    gc_fatal (data, 0, "gc_mark_enqueue() called in invalid gc pass.\n");    if (gc_found_in_type == PIKE_T_UNKNOWN || !gc_found_in)    gc_fatal (data, 0, "gc_mark_enqueue() called outside GC_ENTER.\n");    {    struct marker *m; -  if (gc_is_watching && (m = find_marker(data)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(data)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_mark_enqueue()");    }    }   #endif       b=gc_mark_last;    if(!b || b->used >= GC_QUEUE_ENTRIES)    {    b = (struct gc_queue_block *) malloc (sizeof (struct gc_queue_block));
pike.git/src/gc.c:1878:    b->used++;   }      #endif /* GC_MARK_DEBUG */      void debug_gc_touch(void *a)   {    struct marker *m;      #ifdef PIKE_DEBUG -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (!a) Pike_fatal("Got null pointer.\n"); +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_touch()");    }   #endif    -  if (!a) Pike_fatal("Got null pointer.\n"); -  +     switch (Pike_in_gc) {    case GC_PASS_PRETOUCH:    m = find_marker(a); -  + #ifdef PIKE_DEBUG    if (   #ifdef DO_PIKE_CLEANUP    !gc_keep_markers &&   #endif -  m && !(m->flags & (GC_PRETOUCHED - #ifdef PIKE_DEBUG -  |GC_WATCHED - #endif -  ))) +  m && !(m->gc_flags & (GC_PRETOUCHED|GC_WATCHED )))    gc_fatal(a, 1, "Thing got an existing but untouched marker.\n"); -  + #endif /* PIKE_DEBUG */    m = get_marker(a); -  m->flags |= GC_PRETOUCHED; +  m->gc_flags |= GC_PRETOUCHED;   #ifdef PIKE_DEBUG    m->saved_refs = *(INT32 *) a;   #endif    break;       case GC_PASS_POSTTOUCH: {   #ifdef PIKE_DEBUG    int extra_ref;   #endif    m = find_marker(a); -  + #ifdef PIKE_DEBUG    if (!m)    gc_fatal(a, 1, "Found a thing without marker.\n"); -  else if (!(m->flags & GC_PRETOUCHED)) +  else if (!(m->gc_flags & GC_PRETOUCHED))    gc_fatal(a, 1, "Thing got an existing but untouched marker.\n"); -  if (gc_destruct_everything && (m->flags & GC_MARKED)) +  if (gc_destruct_everything && (m->gc_flags & GC_MARKED))    gc_fatal (a, 1, "Thing got marked in gc_destruct_everything mode.\n"); - #ifdef PIKE_DEBUG -  extra_ref = (m->flags & GC_GOT_EXTRA_REF) == GC_GOT_EXTRA_REF; +  extra_ref = (m->gc_flags & GC_GOT_EXTRA_REF) == GC_GOT_EXTRA_REF;    if (m->saved_refs + extra_ref < *(INT32 *) a) -  if (m->flags & GC_WEAK_FREED) +  if (m->gc_flags & GC_WEAK_FREED)    gc_fatal(a, 1, "Something failed to remove weak reference(s) to thing, "    "or it has gotten more references since gc start.\n");    else    gc_fatal(a, 1, "Thing has gotten more references since gc start.\n");    else    if (m->weak_refs > m->saved_refs)    gc_fatal(a, 0, "A thing got more weak references than references.\n");   #endif -  m->flags |= GC_POSTTOUCHED; +  m->gc_flags |= GC_POSTTOUCHED;    break;    }       default:    Pike_fatal("debug_gc_touch() used in invalid gc pass.\n");    }   }      #ifdef PIKE_DEBUG   
pike.git/src/gc.c:1970: Inside #if defined(PIKE_DEBUG)
   if (Pike_in_gc != GC_PASS_CHECK)    Pike_fatal("gc check attempted in invalid pass.\n");       m = get_marker(a);       if (!*(INT32 *)a)    gc_fatal(a, 1, "GC check on thing without refs.\n");    if (m->saved_refs == -1) m->saved_refs = *(INT32 *)a;    else if (m->saved_refs != *(INT32 *)a)    gc_fatal(a, 1, "Refs changed in gc check pass.\n"); -  if (m->refs + m->xrefs >= *(INT32 *) a) -  /* m->refs will be incremented by the caller. */ +  if (m->gc_refs + m->xrefs >= *(INT32 *) a) +  /* m->gc_refs will be incremented by the caller. */    gc_fatal (a, 1, "Thing is getting more internal refs (%d + %d) "    "than refs (%d).\n"    "(Could be an extra free somewhere, or "    "a pointer might have been checked more than once.)\n", -  m->refs, m->xrefs, *(INT32 *) a); +  m->gc_refs, m->xrefs, *(INT32 *) a);    checked++;       return m;   }      #endif /* PIKE_DEBUG */      PMOD_EXPORT INT32 real_gc_check(void *a)   {    struct marker *m;    INT32 ret;      #ifdef PIKE_DEBUG    if (gc_found_in_type == PIKE_T_UNKNOWN || !gc_found_in)    gc_fatal (a, 0, "gc_check() called outside GC_ENTER.\n"); -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_check()");    }    if (!(m = gc_check_debug(a, 0))) return 0;   #else    m = get_marker(a);   #endif    -  ret=m->refs; -  add_ref(m); -  if (m->refs == *(INT32 *) a) -  m->flags |= GC_NOT_REFERENCED; +  ret=m->gc_refs++; +  if (m->gc_refs == *(INT32 *) a) +  m->gc_flags |= GC_NOT_REFERENCED;    return ret;   }      PMOD_EXPORT INT32 real_gc_check_weak(void *a)   {    struct marker *m;    INT32 ret;      #ifdef PIKE_DEBUG    if (gc_found_in_type == PIKE_T_UNKNOWN || !gc_found_in)    gc_fatal (a, 0, "gc_check_weak() called outside GC_ENTER.\n"); -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_check_weak()");    }    if (!(m = gc_check_debug(a, 1))) return 0;    if (m->weak_refs < 0)    gc_fatal(a, 1, "Thing has already reached threshold for weak free.\n");    if (m->weak_refs >= *(INT32 *) a)    gc_fatal(a, 1, "Thing has gotten more weak refs than refs.\n"); -  if (m->weak_refs > m->refs + 1) +  if (m->weak_refs > m->gc_refs + 1)    gc_fatal(a, 1, "Thing has gotten more weak refs than internal refs.\n");   #else    m = get_marker(a);   #endif       m->weak_refs++;    gc_ext_weak_refs++;    if (m->weak_refs == *(INT32 *) a)    m->weak_refs = -1;    -  ret=m->refs; -  add_ref(m); -  if (m->refs == *(INT32 *) a) -  m->flags |= GC_NOT_REFERENCED; +  ret=m->gc_refs++; +  if (m->gc_refs == *(INT32 *) a) +  m->gc_flags |= GC_NOT_REFERENCED;    return ret;   }      static void cleanup_markers (void)   { - #ifdef DO_PIKE_CLEANUP -  size_t e=0; -  -  if (gc_keep_markers) { -  /* Carry over any GC_CLEANUP_LEAKED flags but reinitialize them -  * otherwise. */ -  for(e=0;e<marker_hash_table_size;e++) { -  struct marker *m; -  for (m = marker_hash_table[e]; m; m = m->next) { - #ifdef PIKE_DEBUG -  m->flags &= GC_CLEANUP_LEAKED; -  m->xrefs = 0; -  m->saved_refs = -1; - #else -  m->flags = 0; - #endif -  m->refs = m->weak_refs = 0; -  m->frame = 0; +    } -  } -  return; -  } +     -  for(e=0;e<marker_hash_table_size;e++) -  while(marker_hash_table[e]) -  remove_marker(marker_hash_table[e]->data); - #endif -  exit_marker_hash(); - } -  - static void init_gc(void) - { - #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); - #ifdef PIKE_DEBUG -  } - #endif - } -  +    void exit_gc(void)   {    if (gc_evaluator_callback) {    remove_callback(gc_evaluator_callback);    gc_evaluator_callback = NULL;    }    if (!gc_keep_markers)    cleanup_markers();       ba_free_all(&gc_rec_frame_allocator);
pike.git/src/gc.c:2118: Inside #if defined(PIKE_DEBUG)
   gc_is_watching = 0;    }   #endif   }      #ifdef PIKE_DEBUG      PMOD_EXPORT void gc_check_zapped (void *a, TYPE_T type, const char *file, INT_TYPE line)   {    struct marker *m = find_marker (a); -  if (m && (m->flags & GC_CLEANUP_LEAKED)) +  if (m && (m->gc_flags & GC_CLEANUP_LEAKED))    fprintf (stderr, "Free of leaked %s %p from %s:%ld, %d refs remaining\n",    get_name_of_type (type), a, file, (long)line, *(INT32 *)a - 1);   }      /* This function marks some known externals. The rest are handled by    * callbacks added with add_gc_callback. */   static void mark_externals (void)   {    struct mapping *constants;    if (master_object)    gc_mark_external (master_object, " as master_object");    if ((constants = get_builtin_constants()))    gc_mark_external (constants, " as global constants mapping");   }      PMOD_EXPORT void locate_references(void *a)   {    int tmp, orig_in_gc = Pike_in_gc;    const char *orig_gc_found_place = gc_found_place; -  int i=0; -  if(!marker_hash_table) -  { -  i=1; -  init_gc(); -  } +     Pike_in_gc = GC_PASS_LOCATE;    gc_found_place = NULL;       /* Disable debug, this may help reduce recursion bugs */    tmp=d_flag;    d_flag=0;       fprintf(stderr,"**Looking for references to %p:\n", a);       check_for=a;
pike.git/src/gc.c:2183: Inside #if defined(PIKE_DEBUG) and #if defined(DEBUG_MALLOC)
   dmalloc_find_references_to(a);   #endif    }   #endif       fprintf(stderr,"**Done looking for references to %p, "    "found %"PRINTSIZET"u refs.\n", a, found_ref_count);       Pike_in_gc = orig_in_gc;    gc_found_place = orig_gc_found_place; -  if(i) exit_gc(); +     d_flag=tmp;   }      void debug_gc_add_extra_ref(void *a)   {    struct marker *m;    -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_add_extra_ref()");    }       if (gc_debug) {    m = find_marker(a); -  if ((!m || !(m->flags & GC_PRETOUCHED)) && +  if ((!m || !(m->gc_flags & GC_PRETOUCHED)) &&    !safe_debug_findstring((struct pike_string *) a))    gc_fatal(a, 0, "Doing gc_add_extra_ref() on invalid object.\n");    if (!m) m = get_marker(a);    }    else m = get_marker(a);    -  if (m->flags & GC_GOT_EXTRA_REF) +  if (m->gc_flags & GC_GOT_EXTRA_REF)    gc_fatal(a, 0, "Thing already got an extra gc ref.\n"); -  m->flags |= GC_GOT_EXTRA_REF; +  m->gc_flags |= GC_GOT_EXTRA_REF;    gc_extra_refs++;    add_ref( (struct ref_dummy *)a);   }      void debug_gc_free_extra_ref(void *a)   {    struct marker *m;    -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_free_extra_ref()");    }       if (gc_debug) {    m = find_marker(a); -  if ((!m || !(m->flags & GC_PRETOUCHED)) && +  if ((!m || !(m->gc_flags & GC_PRETOUCHED)) &&    !safe_debug_findstring((struct pike_string *) a))    gc_fatal(a, 0, "Doing gc_add_extra_ref() on invalid object.\n");    if (!m) m = get_marker(a);    }    else m = get_marker(a);    -  if (!(m->flags & GC_GOT_EXTRA_REF)) +  if (!(m->gc_flags & GC_GOT_EXTRA_REF))    gc_fatal(a, 0, "Thing haven't got an extra gc ref.\n"); -  m->flags &= ~GC_GOT_EXTRA_REF; +  m->gc_flags &= ~GC_GOT_EXTRA_REF;    gc_extra_refs--;   }         int debug_gc_is_referenced(void *a)   {    struct marker *m;    -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_is_referenced()");    }       if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_MARK)    Pike_fatal("gc_is_referenced() called in invalid gc pass.\n");       if (gc_debug) {    m = find_marker(a); -  if ((!m || !(m->flags & GC_PRETOUCHED)) && +  if ((!m || !(m->gc_flags & GC_PRETOUCHED)) &&    !safe_debug_findstring((struct pike_string *) a))    gc_fatal(a, 0, "Doing gc_is_referenced() on invalid object.\n");    if (!m) m = get_marker(a);    }    else m = get_marker(a);    -  if (m->flags & GC_IS_REFERENCED) +  if (m->gc_flags & GC_IS_REFERENCED)    gc_fatal(a, 0, "gc_is_referenced() called twice for thing.\n"); -  m->flags |= GC_IS_REFERENCED; +  m->gc_flags |= GC_IS_REFERENCED;    -  return !(m->flags & GC_NOT_REFERENCED); +  return !(m->gc_flags & GC_NOT_REFERENCED);   }      int gc_mark_external (void *a, const char *place)   {    struct marker *m;    -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_mark_external()");    }       if (!a) Pike_fatal("Got null pointer.\n");       if(Pike_in_gc == GC_PASS_LOCATE)    {    if(a==check_for) {    const char *orig_gc_found_place = gc_found_place;
pike.git/src/gc.c:2302: Inside #if defined(PIKE_DEBUG) and #if defined(DEBUG_MALLOC)
   if (gc_external_refs_zapped) {    fprintf (stderr, "One external ref to %p found%s.\n",    a, place ? place : "");    if (gc_found_in) describe (gc_found_in);    return 0;    }   #endif       m=get_marker(a);    m->xrefs++; -  m->flags|=GC_XREFERENCED; +  m->gc_flags|=GC_XREFERENCED;    if(Pike_in_gc == GC_PASS_CHECK && -  (m->refs + m->xrefs > *(INT32 *)a || +  (m->gc_refs + m->xrefs > *(INT32 *)a ||    (m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)))    gc_fatal(a, 1, "Ref counts are wrong.\n");    return 0;   }      #define LOW_CHECK_REC_FRAME(f, file, line) do { \    if (f->rf_flags & GC_FRAME_FREED) \    dloc_gc_fatal (file, line, f->data, 0, \    "Accessing freed gc_stack_frame %p.\n", f); \    if (f->cycle_id->rf_flags & GC_FRAME_FREED) { \
pike.git/src/gc.c:2476:   #define CHECK_CYCLE_PIECE_FRAME(f) do {} while (0)   #define CHECK_KILL_LIST_FRAME(f) do {} while (0)   #define CHECK_REC_STACK(p1, p1n, p2, p2n) do {} while (0)   #endif /* !PIKE_DEBUG */      int gc_do_weak_free(void *a)   {    struct marker *m;      #ifdef PIKE_DEBUG -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_do_weak_free()");    }    if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)    Pike_fatal("gc_do_weak_free() called in invalid gc pass.\n");    if (gc_debug) {    if (!(m = find_marker(a)))    gc_fatal(a, 0, "gc_do_weak_free() got unknown object.\n");    }    else m = get_marker(a);    debug_malloc_touch(a);    -  if (m->weak_refs > m->refs) +  if (m->weak_refs > m->gc_refs)    gc_fatal(a, 0, "More weak references than internal references.\n");   #else    m = get_marker(a);   #endif       if (Pike_in_gc != GC_PASS_ZAP_WEAK) {    if (m->weak_refs < 0)    goto should_free;    }    else -  if (!(m->flags & GC_MARKED)) { +  if (!(m->gc_flags & GC_MARKED)) {   #ifdef PIKE_DEBUG    if (m->weak_refs <= 0)    gc_fatal(a, 0, "Too many weak refs cleared to thing with external "    "weak refs.\n");   #endif    m->weak_refs--;    goto should_free;    }    return 0;      should_free:    gc_ext_weak_refs--;   #ifdef PIKE_DEBUG    m->saved_refs--; -  m->flags |= GC_WEAK_FREED; +  m->gc_flags |= GC_WEAK_FREED;   #endif       if (*(INT32 *) a == 1) {    /* Make sure the thing doesn't run out of refs, since we can't    * handle cascading frees now. We'll do it in the free pass    * instead. */    gc_add_extra_ref(a); -  m->flags |= GC_GOT_DEAD_REF; +  m->gc_flags |= GC_GOT_DEAD_REF;   #ifdef PIKE_DEBUG    delayed_freed++;   #endif    }       return 1;   }      void gc_delayed_free(void *a, int type)   {    struct marker *m;      #ifdef PIKE_DEBUG -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_delayed_free()");    }    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE &&    Pike_in_gc != GC_PASS_ZAP_WEAK)    Pike_fatal("gc_delayed_free() called in invalid gc pass.\n");    if (gc_debug) {    if (!(m = find_marker(a)))    gc_fatal(a, 0, "gc_delayed_free() got unknown object (missed by pretouch pass).\n");    }    else m = get_marker(a);    if (*(INT32 *) a != 1)    Pike_fatal("gc_delayed_free() called for thing that haven't got a single ref.\n");    debug_malloc_touch(a);    delayed_freed++;   #else    m = get_marker(a);   #endif    -  if (m->flags & GC_MARKED) { +  if (m->gc_flags & GC_MARKED) {    /* Note that we can get marked things here, e.g. if the index in a    * mapping with weak indices is removed in the zap weak pass, the    * value will be zapped too, but it will still have a mark from    * the mark pass. This means that the stuff referenced by the    * value will only be refcount garbed, which can leave cyclic    * garbage for the next gc round.    *    * Since the value has been marked we won't find it in the free    * pass, so we have to keep special track of it. :P */    struct free_extra_frame *l = alloc_free_extra_frame();    l->data = a;    l->type = type;    l->next = free_extra_list;    free_extra_list = l;    }       gc_add_extra_ref(a); -  m->flags |= GC_GOT_DEAD_REF; +  m->gc_flags |= GC_GOT_DEAD_REF;   }      int real_gc_mark(void *a DO_IF_DEBUG (COMMA int type))   {    struct marker *m;      #ifdef PIKE_DEBUG    if (Pike_in_gc == GC_PASS_ZAP_WEAK && !find_marker (a))    gc_fatal_2 (a, type, 0, "gc_mark() called for for thing without marker "    "in zap weak pass.\n");   #endif       m = get_marker (a);    -  /* Note: m->refs and m->xrefs are useless already here due to how +  /* Note: m->gc_refs and m->xrefs are useless already here due to how    * gc_free_(short_)svalue works. */      #ifdef PIKE_DEBUG -  if (gc_is_watching && m && m->flags & GC_WATCHED) { +  if (gc_is_watching && m && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_mark()");    }    if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)    Pike_fatal("GC mark attempted in invalid pass.\n");    if (!*(INT32 *) a)    gc_fatal_2 (a, type, 1, "Marked a thing without refs.\n");    if (m->weak_refs < 0)    gc_fatal_2 (a, type, 1, "Marked a thing scheduled for weak free.\n");   #endif       if (Pike_in_gc == GC_PASS_ZAP_WEAK) {    /* Things are visited in the zap weak pass through the mark    * functions to free refs to internal things that only got weak    * external references. That happens only when a thing also have    * internal cyclic nonweak refs. */   #ifdef PIKE_DEBUG -  if (!(m->flags & GC_MARKED)) +  if (!(m->gc_flags & GC_MARKED))    gc_fatal_2 (a, type, 0, "gc_mark() called for thing in zap weak pass "    "that wasn't marked before.\n");   #endif -  if (m->flags & GC_FREE_VISITED) { +  if (m->gc_flags & GC_FREE_VISITED) {    debug_malloc_touch (a);    return 0;    }    else {    debug_malloc_touch (a); -  m->flags |= GC_FREE_VISITED; +  m->gc_flags |= GC_FREE_VISITED;    return 1;    }    }    -  else if (m->flags & GC_MARKED) { +  else if (m->gc_flags & GC_MARKED) {    debug_malloc_touch (a);   #ifdef PIKE_DEBUG    if (m->weak_refs != 0)    gc_fatal_2 (a, type, 0, "weak_refs changed in marker "    "already visited by gc_mark().\n");   #endif    return 0;    }       else {    debug_malloc_touch (a);    if (m->weak_refs) {    gc_ext_weak_refs -= m->weak_refs;    m->weak_refs = 0;    } -  m->flags = (m->flags & ~GC_NOT_REFERENCED) | GC_MARKED; +  m->gc_flags = (m->gc_flags & ~GC_NOT_REFERENCED) | GC_MARKED;    DO_IF_DEBUG(marked++);    return 1;    }   }      void gc_move_marker (void *old, void *new)   {    struct marker *m = find_marker (old);      #ifdef PIKE_DEBUG
pike.git/src/gc.c:2674:       move_marker (m, debug_malloc_pass (new));   }      PMOD_EXPORT void gc_cycle_enqueue(gc_cycle_check_cb *checkfn, void *data, int weak)   {    struct link_frame *l = alloc_link_frame();   #ifdef PIKE_DEBUG    {    struct marker *m; -  if (gc_is_watching && (m = find_marker(data)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(data)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_cycle_enqueue()");    }    }    if (Pike_in_gc != GC_PASS_CYCLE)    gc_fatal(data, 0, "Use of the gc frame stack outside the cycle check pass.\n");    if (stack_top == &sentinel_frame)    gc_fatal (data, 0, "No thing on rec stack to follow links from.\n");   #endif    l->data = data;
pike.git/src/gc.c:2858:   #endif       return beg;   }      int gc_cycle_push(void *data, struct marker *m, int weak)   {    struct marker *pm;      #ifdef PIKE_DEBUG -  if (gc_is_watching && m && m->flags & GC_WATCHED) { +  if (gc_is_watching && m && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_cycle_push()");    }       debug_malloc_touch (data);       if (!data) Pike_fatal ("Got null pointer.\n"); -  if (m->data != data) Pike_fatal ("Got wrong marker.\n"); +     if (Pike_in_gc != GC_PASS_CYCLE)    Pike_fatal("GC cycle push attempted in invalid pass.\n"); -  if (gc_debug && !(m->flags & GC_PRETOUCHED)) +  if (gc_debug && !(m->gc_flags & GC_PRETOUCHED))    gc_fatal (data, 0, "gc_cycle_push() called for untouched thing.\n");    if (!gc_destruct_everything) { -  if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) && +  if ((!(m->gc_flags & GC_NOT_REFERENCED) || m->gc_flags & GC_MARKED) &&    *(INT32 *) data)    gc_fatal (data, 1, "Got a referenced marker to gc_cycle_push.\n"); -  if (m->flags & GC_XREFERENCED) +  if (m->gc_flags & GC_XREFERENCED)    gc_fatal (data, 1, "Doing cycle check in externally referenced thing "    "missed in mark pass.\n");    }    if (weak && stack_top == &sentinel_frame)    gc_fatal (data, 1, "weak is %d when stack is empty.\n", weak);    if (gc_debug > 1) {    struct array *a;    struct object *o;    struct program *p;    struct mapping *m;
pike.git/src/gc.c:2906: Inside #if defined(PIKE_DEBUG)
   if(l == (struct multiset *) data) goto on_gc_internal_lists;    gc_fatal (data, 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 (stack_top->rf_flags & GC_MARK_LIVE) {    /* Only recurse through things already handled; we'll get to the    * other later in the normal recursion. */ -  if (m->flags & GC_CYCLE_CHECKED && !(m->flags & GC_LIVE)) { +  if (m->gc_flags & GC_CYCLE_CHECKED && !(m->gc_flags & GC_LIVE)) {    CYCLE_DEBUG_MSG (m->frame, "gc_cycle_push, mark live");    goto mark_live;    }    CYCLE_DEBUG_MSG (m->frame, "gc_cycle_push, no mark live");    return 0;    }       if (stack_top == &sentinel_frame)    pm = NULL;    else {
pike.git/src/gc.c:3100:    CYCLE_DEBUG_MSG (r, "> gc_cycle_push, mark cycle 1");    if (r == bottom) break;    }    }    CHECK_REC_STACK (cycle_frame, "cycle_frame", break_pos, "break_pos");    }    }    }       else -  if (!(m->flags & GC_CYCLE_CHECKED)) { +  if (!(m->gc_flags & GC_CYCLE_CHECKED)) {    struct gc_rec_frame *r;   #ifdef PIKE_DEBUG    cycle_checked++;    if (m->frame)    gc_fatal (data, 0, "Marker already got a frame.\n");   #endif    -  m->flags |= GC_CYCLE_CHECKED | (pm ? pm->flags & GC_LIVE : 0); +  m->gc_flags |= GC_CYCLE_CHECKED | (pm ? pm->gc_flags & GC_LIVE : 0);    m->frame = r = gc_cycle_enqueue_rec (data);    debug_malloc_touch (data);    if (weak) {    if (weak > 0) r->rf_flags = GC_PREV_WEAK;    else r->rf_flags = GC_PREV_STRONG;    }    else    r->rf_flags = 0;      #ifdef GC_CYCLE_DEBUG
pike.git/src/gc.c:3130: Inside #if defined(GC_CYCLE_DEBUG)
   else if (weak < 0) CYCLE_DEBUG_MSG (r, "gc_cycle_push, recurse strong");    else CYCLE_DEBUG_MSG (r, "gc_cycle_push, recurse");    gc_cycle_indent += 2;   #endif    CHECK_REC_STACK (NULL, NULL, NULL, NULL);    return 1;    }       /* Should normally not recurse now, but got to do that anyway if we    * must propagate GC_LIVE flags. */ -  if (!pm || !(pm->flags & GC_LIVE) || m->flags & GC_LIVE) { +  if (!pm || !(pm->gc_flags & GC_LIVE) || m->gc_flags & GC_LIVE) {    CYCLE_DEBUG_MSG (m->frame ? m->frame : NULL, "gc_cycle_push, no recurse");    return 0;    }       /* Initialize mark live recursion. */    gc_cycle_enqueue_rec (NULL)->rf_flags = GC_MARK_LIVE;   #ifdef GC_CYCLE_DEBUG    CYCLE_DEBUG_MSG (m->frame ? m->frame : NULL, "gc_cycle_push, mark live begins");    gc_cycle_indent += 2;   #endif      mark_live:   #ifdef PIKE_DEBUG -  if (m->flags & GC_LIVE) +  if (m->gc_flags & GC_LIVE)    Pike_fatal("Shouldn't mark live recurse when there's nothing to do.\n");   #endif -  m->flags |= GC_LIVE; +  m->gc_flags |= GC_LIVE;    debug_malloc_touch (data);    -  if (m->flags & GC_GOT_DEAD_REF) { +  if (m->gc_flags & GC_GOT_DEAD_REF) {    /* A thing previously popped as dead is now being marked live.    * Have to remove the extra ref added by gc_cycle_pop(). */    gc_free_extra_ref (data);    if (!sub_ref ((struct ref_dummy *) data)) {   #ifdef PIKE_DEBUG    gc_fatal (data, 0, "Thing got zero refs after removing the dead gc ref.\n");   #endif    }    }   
pike.git/src/gc.c:3194:    stack_top = r;    }       else {    struct gc_rec_frame *popped = stack_top;      #ifdef PIKE_DEBUG    {    void *data = popped->data;    struct marker *m = find_marker (data); -  if (gc_is_watching && m && m->flags & GC_WATCHED) { +  if (gc_is_watching && m && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_cycle_pop()");    } -  if (!(m->flags & GC_CYCLE_CHECKED)) +  if (!(m->gc_flags & GC_CYCLE_CHECKED))    gc_fatal (data, 0, "Marker being popped doesn't have GC_CYCLE_CHECKED.\n");    if (!gc_destruct_everything) { -  if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) && +  if ((!(m->gc_flags & GC_NOT_REFERENCED) || m->gc_flags & GC_MARKED) &&    *(INT32 *) data)    gc_fatal (data, 1, "Got a referenced marker to gc_cycle_pop.\n"); -  if (m->flags & GC_XREFERENCED) +  if (m->gc_flags & GC_XREFERENCED)    gc_fatal (data, 1, "Doing cycle check in externally referenced thing "    "missed in mark pass.\n");    }    if (popped->next != (struct gc_rec_frame *) (ptrdiff_t) -1)    gc_fatal (data, 0, "Popped rec frame got stuff in the next pointer.\n");    }   #endif       stack_top = popped->prev;   #ifdef PIKE_DEBUG
pike.git/src/gc.c:3282: Inside #if defined(PIKE_DEBUG)
   CHECK_CYCLE_PIECE_FRAME (r);    }   #endif       CYCLE_DEBUG_MSG (popped, "gc_cycle_pop, popping cycle");       do {    struct marker *m = find_marker (popped->data);    struct gc_rec_frame *next = popped->cycle_piece;    -  if (m->flags & GC_LIVE_OBJ) { +  if (m->gc_flags & GC_LIVE_OBJ) {    /* Move to the kill list. */   #ifdef PIKE_DEBUG    popped->rf_flags &= ~GC_ON_CYCLE_PIECE_LIST;    popped->cycle_piece = popped->u.last_cycle_piece =    (struct gc_rec_frame *) (ptrdiff_t) -1;   #endif    popped->next = *kill_list_ptr;    *kill_list_ptr = popped;    kill_list_ptr = &popped->next;    popped->rf_flags |= GC_ON_KILL_LIST;       /* Ensure that the frames on the kill list have a valid    * cycle id frame and that every frame is linked directly to    * it. This is only for the sake of warn_bad_cycles. */    if (!cycle_id) cycle_id = popped;    popped->cycle_id = cycle_id;       /* 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 (!(m->flags & GC_GOT_DEAD_REF)) +  if (!(m->gc_flags & GC_GOT_DEAD_REF))    gc_add_extra_ref (popped->data);       CHECK_KILL_LIST_FRAME (popped);    CYCLE_DEBUG_MSG (popped, "> gc_cycle_pop, move to kill list");    }       else { -  if (!(m->flags & GC_LIVE)) { +  if (!(m->gc_flags & GC_LIVE)) {    /* Add an extra ref which is taken away in the free pass. This    * is done to not refcount garb the cycles themselves    * recursively, which in bad cases can consume a lot of C    * stack. */ -  if (!(m->flags & GC_GOT_DEAD_REF)) { +  if (!(m->gc_flags & GC_GOT_DEAD_REF)) {    gc_add_extra_ref (popped->data); -  m->flags |= GC_GOT_DEAD_REF; +  m->gc_flags |= GC_GOT_DEAD_REF;    }    }   #ifdef PIKE_DEBUG    else -  if (m->flags & GC_GOT_DEAD_REF) +  if (m->gc_flags & GC_GOT_DEAD_REF)    gc_fatal (popped->data, 0, "Didn't expect a dead extra ref.\n");   #endif       CYCLE_DEBUG_MSG (popped, "> gc_cycle_pop, free");    m->frame = NULL;    really_free_gc_rec_frame (popped);    }       popped = next;    } while (popped);
pike.git/src/gc.c:3355:      void do_gc_recurse_short_svalue(union anything *u, int type)   {    gc_recurse_short_svalue(u, type);   }      int gc_do_free(void *a)   {    struct marker *m;   #ifdef PIKE_DEBUG -  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  if (gc_is_watching && (m = find_marker(a)) && m->gc_flags & GC_WATCHED) {    /* This is useful to set breakpoints on. */    gc_watched_found (m, "gc_do_free()");    }    if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_FREE)    Pike_fatal("gc free attempted in invalid pass.\n");   #endif       m=find_marker(debug_malloc_pass(a));    if (!m) return 0; /* Object created after cycle pass. */       if (gc_destruct_everything) {    /* We don't actually free much in this mode, just destruct    * objects. So when we normally would return nonzero we just    * remove the extra ref again. */ -  if (!(m->flags & GC_LIVE)) { +  if (!(m->gc_flags & GC_LIVE)) {    if (*(INT32 *) a == 1)    return 1;    else {    gc_free_extra_ref (a);    sub_ref ((struct ref_dummy *) a);    }    }    return 0;    }      #ifdef PIKE_DEBUG -  if (*(INT32 *) a > !!(m->flags & GC_GOT_EXTRA_REF)) { +  if (*(INT32 *) a > !!(m->gc_flags & GC_GOT_EXTRA_REF)) {    if (!gc_destruct_everything && -  (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED)) +  (!(m->gc_flags & GC_NOT_REFERENCED) || m->gc_flags & GC_MARKED))    gc_fatal(a, 0, "gc_do_free() called for referenced thing.\n");    if (gc_debug && -  (m->flags & (GC_PRETOUCHED|GC_MARKED|GC_IS_REFERENCED)) == GC_PRETOUCHED) +  (m->gc_flags & (GC_PRETOUCHED|GC_MARKED|GC_IS_REFERENCED)) == GC_PRETOUCHED)    gc_fatal(a, 0, "gc_do_free() called without prior call to "    "gc_mark() or gc_is_referenced().\n");    }    if(!gc_destruct_everything && -  (m->flags & (GC_MARKED|GC_XREFERENCED)) == GC_XREFERENCED) +  (m->gc_flags & (GC_MARKED|GC_XREFERENCED)) == GC_XREFERENCED)    gc_fatal(a, 1, "Thing with external reference missed in gc mark pass.\n"); -  if ((m->flags & (GC_DO_FREE|GC_LIVE)) == GC_LIVE) live_ref++; -  m->flags |= GC_DO_FREE; +  if ((m->gc_flags & (GC_DO_FREE|GC_LIVE)) == GC_LIVE) live_ref++; +  m->gc_flags |= GC_DO_FREE;   #endif    -  return !(m->flags & GC_LIVE); +  return !(m->gc_flags & GC_LIVE);   }      #if 0   static void free_obj_arr(void *oa)   {    struct array *obj_arr = *((struct array **)oa);       if (obj_arr) free_array(obj_arr);    free(oa);   }
pike.git/src/gc.c:3500:   #endif   }      size_t do_gc(void *UNUSED(ignored), int explicit_call)   {    ALLOC_COUNT_TYPE start_allocs;    size_t start_num_objs, unreferenced;    cpu_time_t gc_start_time, gc_start_real_time;    ptrdiff_t objs, pre_kill_objs;   #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) -  unsigned destroy_count; +  unsigned destruct_count;   #endif   #ifdef PIKE_DEBUG    unsigned obj_count;    ONERROR uwp;   #endif       if(Pike_in_gc) return 0;       if (gc_enabled <= 0 && (gc_enabled < 0 || !explicit_call)) {    /* If this happens then the gc has been disabled for a very long
pike.git/src/gc.c:3533:    remove_callback (gc_evaluator_callback);    gc_evaluator_callback = NULL;    }    return 0;    }      #ifdef DEBUG_MALLOC    if(debug_options & GC_RESET_DMALLOC)    reset_debug_malloc();   #endif -  init_gc(); +     gc_generation++;    Pike_in_gc=GC_PASS_PREPARE;       if (!SAFE_IS_ZERO(&gc_pre_cb)) {    safe_apply_svalue(&gc_pre_cb, 0, 1);    pop_stack();    }       gc_start_time = get_cpu_time();    gc_start_real_time = get_real_time();
pike.git/src/gc.c:3767: Inside #if defined(PIKE_DEBUG)
   n += gc_touch_all_objects();   #ifdef PIKE_DEBUG    gc_touch_all_strings();   #endif    if (n != (unsigned) num_objects && !got_unlinked_things)    Pike_fatal("Object count wrong in gc; expected %d, got %d.\n", num_objects, n);   #if 0 /* Temporarily disabled - Hubbe */   #ifdef PIKE_DEBUG   #ifdef DEBUG_MALLOC    PTR_HASH_LOOP(marker, i, m) -  if (!(m->flags & (GC_POSTTOUCHED|GC_WEAK_FREED)) && +  if (!(m->gc_flags & (GC_POSTTOUCHED|GC_WEAK_FREED)) &&    dmalloc_is_invalid_memory_block(m->data)) {    fprintf(stderr, "Found a stray marker after posttouch pass: ");    describe_marker(m);    fprintf(stderr, "Describing marker location(s):\n");    debug_malloc_dump_references(m, 2, 1, 0);    fprintf(stderr, "Describing thing for marker:\n");    Pike_in_gc = 0;    describe(m->data);    Pike_in_gc = GC_PASS_POSTTOUCH;    Pike_fatal("Fatal in garbage collector.\n");
pike.git/src/gc.c:3856:       /* Destruct the live objects in cycles, but first warn about any bad    * cycles. */    pre_kill_objs = num_objects;    if (Pike_interpreter.evaluator_stack && !gc_destruct_everything) {    objs -= num_objects;    warn_bad_cycles();    objs += num_objects;    }   #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) -  destroy_count = 0; +  destruct_count = 0;   #endif       if (!SAFE_IS_ZERO(&gc_post_cb)) {    safe_apply_svalue(&gc_post_cb, 0, 1);    pop_stack();    }       {    enum object_destruct_reason reason =   #ifdef DO_PIKE_CLEANUP
pike.git/src/gc.c:3900: Inside #if defined(PIKE_DEBUG)
   }    }    }   #endif       while (kill_list != &sentinel_frame) {    struct gc_rec_frame *next = kill_list->next;    struct object *o = (struct object *) kill_list->data;      #ifdef PIKE_DEBUG -  if ((get_marker(kill_list->data)->flags & (GC_LIVE|GC_LIVE_OBJ)) != +  if ((get_marker(kill_list->data)->gc_flags & (GC_LIVE|GC_LIVE_OBJ)) !=    (GC_LIVE|GC_LIVE_OBJ))    gc_fatal(o, 0, "Invalid object on kill list.\n");    if (o->prog && (o->prog->flags & PROGRAM_USES_PARENT) &&    PARENT_INFO(o)->parent &&    !PARENT_INFO(o)->parent->prog && -  get_marker(PARENT_INFO(o)->parent)->flags & GC_LIVE_OBJ) +  get_marker(PARENT_INFO(o)->parent)->gc_flags & GC_LIVE_OBJ)    gc_fatal(o, 0, "GC destructed parent prematurely.\n");   #endif       GC_VERBOSE_DO(    fprintf(stderr, "| Killing %p with %d refs", o, o->refs);    if (o->prog) {    INT_TYPE line;    struct pike_string *file = get_program_line (o->prog, &line);    fprintf(stderr, ", prog %s:%d\n", file->str, line);    free_string(file);
pike.git/src/gc.c:3932:    push_int(reason);    push_int(o->refs - 1);    safe_apply_svalue(&gc_destruct_cb, 3, 1);    pop_stack();    }       destruct_object (o, reason);    free_object(o);    gc_free_extra_ref(o);   #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) -  destroy_count++; +  destruct_count++;   #endif    really_free_gc_rec_frame (kill_list);    kill_list = next;    }    }      #ifdef PIKE_DEBUG    if (rec_frames)    Pike_fatal ("Leaked %u rec frames.\n", rec_frames);   #endif       GC_VERBOSE_DO(fprintf(stderr, "| kill: %u objects killed, "    "%"PRINTSIZET"u things really freed\n", -  destroy_count, pre_kill_objs - num_objects)); +  destruct_count, pre_kill_objs - num_objects));       Pike_in_gc=GC_PASS_DESTRUCT;    /* Destruct objects on the destruct queue. */    GC_VERBOSE_DO(obj_count = num_objects);    destruct_objects_to_destruct();    GC_VERBOSE_DO(fprintf(stderr, "| destruct: %d things really freed\n",    obj_count - num_objects));      #ifdef PIKE_DEBUG    if (gc_extra_refs) {    size_t e;    fprintf (stderr, "Lost track of %d extra refs to things in gc.\n"    "Searching for marker(s) with extra refs:\n", gc_extra_refs); -  for (e = 0; e < marker_hash_table_size; e++) { -  struct marker *s = marker_hash_table[e], *m; -  for (m = s; m;) { -  if (m->flags & GC_GOT_EXTRA_REF) { +     fprintf (stderr, "========================================\n" -  "Found marker with extra ref: "); -  describe_marker (m); -  fprintf (stderr, "Describing the thing pointed to:\n"); -  describe (m->data); -  } -  m = m->next; -  /* The marker might be moved to the head of the chain via -  * describe() above, so do this to avoid infinite recursion. -  * Some entries in the chain might be missed, but I don't want -  * to bother. */ -  if (m == s) break; -  } -  } -  fprintf (stderr, "========================================\n" +     "Done searching for marker(s) with extra refs.\n");    Pike_fatal("Lost track of %d extra refs to things in gc.\n", gc_extra_refs);    }    if(fatal_after_gc) Pike_fatal("%s", fatal_after_gc);   #endif       /* Calculate the next alloc_threshold. */    {    double multiplier, new_threshold;    cpu_time_t last_non_gc_time, last_gc_time;
pike.git/src/gc.c:4052:    {    cpu_time_t gc_end_time = get_cpu_time();    if (gc_end_time > gc_start_time)    last_gc_time = gc_end_time - gc_start_time;    else    last_gc_time = (cpu_time_t) -1;    }       /* At this point, unreferenced contains the number of things that    * were without external references during the check and mark -  * passes. In the process of freeing them, destroy functions might +  * passes. In the process of freeing them, _destruct functions might    * have been called which means anything might have happened.    * Therefore we use that figure instead of the difference between    * the number of allocated things to measure the amount of    * garbage. */    last_garbage_ratio = (double) unreferenced / start_num_objs;       objects_alloced = objects_alloced * multiplier +    start_allocs * (1.0 - multiplier);    objects_freed = objects_freed * multiplier +    unreferenced * (1.0 - multiplier);
pike.git/src/gc.c:4171:    {    char timestr[40];    if (last_gc_time != (cpu_time_t) -1)    sprintf (timestr, ", %ld ms",    (long) (last_gc_time / (CPU_TIME_TICKS / 1000)));    else    timestr[0] = 0;   #ifdef DO_PIKE_CLEANUP    if (gc_destruct_everything)    fprintf(stderr, "done (%u %s destructed)%s\n", -  destroy_count, destroy_count == 1 ? "was" : "were", timestr); +  destruct_count, destruct_count == 1 ? "was" : "were", timestr);    else   #endif    fprintf(stderr, "done (%"PRINTSIZET"u of %"PRINTSIZET"u "    "%s unreferenced)%s\n",    unreferenced, start_num_objs,    unreferenced == 1 ? "was" : "were",    timestr);    }    }   
pike.git/src/gc.c:4203:    exit_gc();      #ifdef ALWAYS_GC    ADD_GC_CALLBACK();   #else    if(d_flag > 3) ADD_GC_CALLBACK();   #endif      #ifdef DO_PIKE_CLEANUP    if (gc_destruct_everything) -  return destroy_count; +  return destruct_count;   #endif       if (!SAFE_IS_ZERO(&gc_done_cb)) {    push_int(unreferenced);    safe_apply_svalue(&gc_done_cb, 1, 1);    pop_stack();    }       return unreferenced;   }
pike.git/src/gc.c:4620:    * If there's anything left in the complete list then it's internal    * cyclic stuff. In that case we put those things into the work list,    * move the indirectly incomplete list back to complete and repeat    * MC_PASS_LOOKAHEAD. Otherwise we're done.    */      /* #define MEMORY_COUNT_DEBUG */      #define MC_WQ_START_SIZE 1024    + #ifdef PIKE_THREADS   static IMUTEX_T mc_mutex; -  + #endif      PMOD_EXPORT int mc_pass;   PMOD_EXPORT size_t mc_counted_bytes;      static int mc_lookahead, mc_block_pike_cycle_depth;   static TYPE_FIELD mc_block_lookahead;   static TYPE_FIELD mc_block_lookahead_default = BIT_PROGRAM|BIT_STRING|BIT_TYPE;   /* Strings are blocked because they don't contain refs. Types are    * blocked because they are acyclic and don't contain refs to anything    * but strings and other types. */
pike.git/src/gc.c:5711:       {    int i;    for (i = -args + 1; i < 0; i++) {    struct svalue *s = Pike_sp + i;       if (TYPEOF(*s) == T_INT)    continue;       else if (!REFCOUNTED_TYPE(TYPEOF(*s))) { -  free (mc_work_queue + 1); +  mc_work_queue++; /* Compensate for 1-based indexing. */ +  free(mc_work_queue);    mc_work_queue = NULL;    stop_mc();    SIMPLE_ARG_TYPE_ERROR (    "count_memory", i + args + 1,    "array|multiset|mapping|object|program|string|type|int");    }       else {    if (TYPEOF(*s) == T_FUNCTION) {    struct svalue s2;    if (!(s2.u.program = program_from_function (s))) { -  free (mc_work_queue + 1); +  mc_work_queue++; /* Compensate for 1-based indexing. */ +  free(mc_work_queue);    mc_work_queue = NULL;    stop_mc();    SIMPLE_ARG_TYPE_ERROR (    "count_memory", i + args + 1,    "array|multiset|mapping|object|program|string|type|int");    }    add_ref (s2.u.program);    SET_SVAL_TYPE(s2, T_PROGRAM);    free_svalue (s);    move_svalue (s, &s2);
pike.git/src/gc.c:5747:    /* The user passed the same thing several times. Ignore it. */    }       else {    struct mc_marker *m =    my_make_mc_marker (s->u.ptr, visit_fn_from_type[TYPEOF(*s)], NULL);    m->flags |= MC_FLAG_INTERNAL;    if (!mc_block_pike_cycle_depth && TYPEOF(*s) == T_OBJECT) {    int cycle_depth = mc_cycle_depth_from_obj (s->u.object);    if (TYPEOF(throw_value) != PIKE_T_FREE) { -  free (mc_work_queue + 1); +  mc_work_queue++; /* Compensate for 1-based indexing. */ +  free(mc_work_queue);    mc_work_queue = NULL;    stop_mc();    throw_severity = THROW_ERROR;    pike_throw();    }    m->la_count = cycle_depth >= 0 ? cycle_depth : mc_lookahead;    }    else    m->la_count = mc_lookahead;    mc_wq_enqueue (m);
pike.git/src/gc.c:5876:    MC_DEBUG_MSG (NULL, "leave - added to incomplete list");    }    else {    DL_ADD_LAST (mc_complete, mc_ref_from);    MC_DEBUG_MSG (NULL, "leave - added to complete list");    }    }    }       if (TYPEOF(throw_value) != PIKE_T_FREE) { -  free (mc_work_queue + 1); +  mc_work_queue++; /* Compensate for 1-based indexing. */ +  free(mc_work_queue);    mc_work_queue = NULL;    stop_mc();    throw_severity = THROW_ERROR;    pike_throw();    }    }   #if defined (PIKE_DEBUG) || defined (MEMORY_COUNT_DEBUG)    mc_ref_from = (void *) (ptrdiff_t) -1;   #endif   
pike.git/src/gc.c:6116:    }       mc_pass = 0;    visit_enter = NULL;    visit_ref = NULL;    visit_leave = NULL;       DL_MAKE_EMPTY (mc_incomplete);    DL_MAKE_EMPTY (mc_indirect);   #ifdef DO_PIKE_CLEANUP -  { -  size_t e; -  for (e = 0; e < mc_marker_hash_table_size; e++) -  while (mc_marker_hash_table[e]) -  remove_mc_marker (mc_marker_hash_table[e]->thing); -  } +    #endif       assert (mc_wq_used == 1); -  free (mc_work_queue + 1); +  mc_work_queue++; /* Compensate for 1-based indexing. */ +  free(mc_work_queue);    mc_work_queue = NULL;    stop_mc();       pop_n_elems (args);    push_ulongest (return_count ? count_internal : mc_counted_bytes);   }      static struct mapping *identify_loop_reverse = NULL;      void identify_loop_visit_enter(void *thing, int type, void *UNUSED(extra))
pike.git/src/gc.c:6159:    int type = type_from_visit_fn(visit_dst);    struct mc_marker *ref_to = find_mc_marker(dst);    if (ref_to) {    /* Already visited or queued for visiting. */    return;    }       ref_to = my_make_mc_marker(dst, visit_dst, extra);       if (type != PIKE_T_UNKNOWN) { +  /* NB: low_mapping_insert() for object indices may throw errors +  * if eg lfun::`==() throws an error. We therefore instead +  * use the raw pointers as indices instead. +  */    struct svalue s; -  SET_SVAL(s, type, 0, refs, dst); -  low_mapping_insert(identify_loop_reverse, &s, Pike_sp-1, 0); -  +  SET_SVAL(s, PIKE_T_INT, NUMBER_NUMBER, integer, (INT_TYPE)(ptrdiff_t)dst);    mc_wq_enqueue(ref_to); -  +  low_mapping_insert(identify_loop_reverse, &s, Pike_sp-1, 0);    } else {    /* Not a valid svalue type.    *    * Probably T_MAPPING_DATA or T_MULTISET_DATA or similar.    *    * Recurse directly while we have the containing thing on the stack.    */    ref_to->flags |= MC_FLAG_INT_VISITED;    visit_dst(dst, VISIT_COMPLEX_ONLY, extra);    }
pike.git/src/gc.c:6280:    if (mc_ref_from->flags & MC_FLAG_INT_VISITED) continue;       mc_ref_from->flags |= MC_FLAG_INT_VISITED;    mc_ref_from->visit_fn(mc_ref_from->thing, VISIT_COMPLEX_ONLY, NULL);    }      #if defined (PIKE_DEBUG) || defined (MEMORY_COUNT_DEBUG)    mc_ref_from = (void *) (ptrdiff_t) -1;   #endif    -  /* NB: 1-based indexing in mc_work_queue. */ -  mc_work_queue++; +  mc_work_queue++; /* Compensate for 1-based indexing. */    free(mc_work_queue);    mc_work_queue = NULL;       visit_enter = NULL;    visit_ref = NULL;    visit_leave = NULL;      #ifdef PIKE_DEBUG    if (s != Pike_sp-1) {    Pike_fatal("Stack error in identify_loops.\n");    }   #endif    -  +  /* NB: low_mapping_lookup() for object indices may throw errors +  * if eg lfun::`==() throws an error. We therefore instead +  * use the raw pointers as indices instead. +  */ +  push_int((INT_TYPE)(ptrdiff_t)s->u.refs);    while ((k = low_mapping_lookup(identify_loop_reverse, Pike_sp-1))) {    /* NB: Since we entered this loop, we know that there's a    * reference loop involving s, as s otherwise wouldn't    * have been in the mapping.    */ -  +  pop_stack();    push_svalue(k); -  +  push_int((INT_TYPE)(ptrdiff_t)k->u.refs);    if (k->u.refs == s->u.refs) {    /* Found! */ -  +  pop_stack();    break;    }    }       free_mapping(identify_loop_reverse);       stop_mc();       if (!k) {    push_undefined();