6930181996-02-25Fredrik Hübinette (Hubbe) /*\
06983f1996-09-22Fredrik Hübinette (Hubbe) ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License)
6930181996-02-25Fredrik Hübinette (Hubbe) ||| See the files COPYING and DISCLAIMER for more information. \*/
3741091999-09-25Henrik Grubbström (Grubba) /**/
6930181996-02-25Fredrik Hübinette (Hubbe) #include "global.h"
a29e021996-10-15Fredrik Hübinette (Hubbe) struct callback *gc_evaluator_callback=0;
c94c371996-03-28Fredrik Hübinette (Hubbe) #include "array.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #include "multiset.h"
c94c371996-03-28Fredrik Hübinette (Hubbe) #include "mapping.h" #include "object.h" #include "program.h"
4a578f1997-01-27Fredrik Hübinette (Hubbe) #include "stralloc.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "stuff.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
9aa6fa1997-05-19Fredrik Hübinette (Hubbe) #include "pike_memory.h"
1a11681997-10-06Fredrik Hübinette (Hubbe) #include "pike_macros.h"
1ca3ba1997-10-13Fredrik Hübinette (Hubbe) #include "pike_types.h"
dc296b1997-10-21Fredrik Hübinette (Hubbe) #include "time_stuff.h"
2eeba91999-03-17Fredrik Hübinette (Hubbe) #include "constants.h"
1637c42000-02-01Fredrik Hübinette (Hubbe) #include "interpret.h"
132f0d2000-08-13Henrik Grubbström (Grubba) #include "bignum.h"
c94c371996-03-28Fredrik Hübinette (Hubbe) 
6930181996-02-25Fredrik Hübinette (Hubbe) #include "gc.h" #include "main.h"
dc296b1997-10-21Fredrik Hübinette (Hubbe) #include <math.h>
6930181996-02-25Fredrik Hübinette (Hubbe) 
3741091999-09-25Henrik Grubbström (Grubba) #include "block_alloc.h"
7c0df72001-02-06Henrik Grubbström (Grubba) RCSID("$Id: gc.c,v 1.145 2001/02/06 19:39:40 grubba Exp $");
24ddc71998-03-28Henrik Grubbström (Grubba) 
e2d9e62000-06-10Martin Stjernholm /* Run garbage collect approximately every time
6930181996-02-25Fredrik Hübinette (Hubbe)  * 20 percent of all arrays, objects and programs is * garbage. */ #define GC_CONST 20 #define MIN_ALLOC_THRESHOLD 1000
b95bef1996-03-29Fredrik Hübinette (Hubbe) #define MAX_ALLOC_THRESHOLD 10000000
6930181996-02-25Fredrik Hübinette (Hubbe) #define MULTIPLIER 0.9
c94c371996-03-28Fredrik Hübinette (Hubbe) #define MARKER_CHUNK_SIZE 1023
45d87e2000-07-18Martin Stjernholm #define GC_LINK_CHUNK_SIZE 31
e2d9e62000-06-10Martin Stjernholm  /* The gc will free all things with no external references that isn't * referenced by undestructed objects with destroy() lfuns (known as * "live" objects). Live objects without external references are then * destructed and garbage collected with normal refcount garbing * (which might leave dead garbage around for the next gc). These live * objects are destructed in an order that tries to be as well defined * as possible using several rules: * * o If an object A references B single way, then A is destructed * before B. * o If A and B are in a cycle, and there is a reference somewhere * from B to A that is weaker than any reference from A to B, then * A is destructed before B. * o Weak references are considered weaker than normal ones, and both * are considered weaker than strong references. * o Strong references are used in special cases like parent object * references. There can never be a cycle consisting only of strong * references. (This means the gc will never destruct a parent
22aa2f2000-09-04Martin Stjernholm  * object before all children have been destructed.)
e2d9e62000-06-10Martin Stjernholm  * * The gc tries to detect and warn about cases where there are live * objects with no well defined order between them. There are cases * that are missed by this detection, though. * * Things that aren't live objects but are referenced from them are * still intact during this destruct pass, so it's entirely possible
22aa2f2000-09-04Martin Stjernholm  * 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.
e2d9e62000-06-10Martin Stjernholm  *
10c4a42000-08-17Martin Stjernholm  * 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.
e2d9e62000-06-10Martin Stjernholm  */
d9dd812000-06-12Martin Stjernholm /* #define GC_VERBOSE */ /* #define GC_CYCLE_DEBUG */
e2d9e62000-06-10Martin Stjernholm 
45d87e2000-07-18Martin Stjernholm /* #define GC_STACK_DEBUG */
e2d9e62000-06-10Martin Stjernholm #if defined(GC_VERBOSE) && !defined(PIKE_DEBUG) #undef GC_VERBOSE #endif #ifdef GC_VERBOSE #define GC_VERBOSE_DO(X) X #else #define GC_VERBOSE_DO(X) #endif
6930181996-02-25Fredrik Hübinette (Hubbe) 
7bf6232000-04-23Martin Stjernholm INT32 num_objects = 1; /* Account for empty_array. */
dc296b1997-10-21Fredrik Hübinette (Hubbe) INT32 num_allocs =0;
f5757f2000-08-11Henrik Grubbström (Grubba) ptrdiff_t alloc_threshold = MIN_ALLOC_THRESHOLD;
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int Pike_in_gc = 0;
8ea2061998-04-29Fredrik Noring struct pike_queue gc_mark_queue;
4452c12000-02-02Fredrik Hübinette (Hubbe) time_t last_gc;
45d87e2000-07-18Martin Stjernholm struct gc_frame { struct gc_frame *back; /* Previous stack frame. */ void *data; union { struct { /* Pop frame. */ struct gc_frame *prev; /* Previous frame in rec_list. */ struct gc_frame *next; /* Next pointer in rec_list and kill_list. */ unsigned INT16 cycle; /* Cycle id number. */ } pop; struct { /* Link frame. */ gc_cycle_check_cb *checkfn; int weak; } link; } u; unsigned INT16 frameflags; }; #define GC_POP_FRAME 0x01 #define GC_WEAK_REF 0x02 #define GC_STRONG_REF 0x04 #define GC_OFF_STACK 0x08 #ifdef PIKE_DEBUG #define GC_LINK_FREED 0x10 #define GC_FOLLOWED_NONSTRONG 0x20 #endif #undef BLOCK_ALLOC_NEXT #define BLOCK_ALLOC_NEXT back BLOCK_ALLOC(gc_frame,GC_LINK_CHUNK_SIZE) #define PREV(frame) ((frame)->u.pop.prev) #define NEXT(frame) ((frame)->u.pop.next) #define CYCLE(frame) ((frame)->u.pop.cycle) #ifdef PIKE_DEBUG #define CHECK_POP_FRAME(frame) do { \ if ((frame)->frameflags & GC_LINK_FREED) \ gc_fatal((frame)->data, 0, "Accessing freed gc_frame.\n"); \ if (!((frame)->frameflags & GC_POP_FRAME)) \ gc_fatal((frame)->data, 0, #frame " is not a pop frame.\n"); \ if (NEXT(PREV(frame)) != (frame)) \ gc_fatal((frame)->data, 0, \ "Pop frame pointers are inconsistent.\n"); \ } while (0) #else #define CHECK_POP_FRAME(frame) do {} while (0) #endif static struct gc_frame rec_list = {0, 0, {{0, 0, 0}}, GC_POP_FRAME}; static struct gc_frame *gc_rec_last = &rec_list, *gc_rec_top = 0; static struct gc_frame *kill_list = 0;
e2d9e62000-06-10Martin Stjernholm static unsigned last_cycle;
6d30f52000-07-11Martin Stjernholm size_t gc_ext_weak_refs;
6930181996-02-25Fredrik Hübinette (Hubbe) 
45d87e2000-07-18Martin Stjernholm /* gc_frame objects are used as frames in a recursion stack during the * cycle check pass. gc_rec_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 * frames for every reference the thing contains.
996f872000-06-12Martin Stjernholm  *
45d87e2000-07-18Martin Stjernholm  * rec_list is a double linked list of the pop frames on the stack, * and that list represents the current prospective destruct order. * gc_rec_last points at the last frame in the list and new frames are * linked in after it. A cycle is always treated as one atomic unit, * e.g. it's either popped whole or not at all. That means that * rec_list may contain frames that are no longer on the stack.
996f872000-06-12Martin Stjernholm  *
45d87e2000-07-18Martin Stjernholm  * 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
996f872000-06-12Martin Stjernholm  * when they're popped from rec_list. * * The cycle check functions might recurse another round through the
45d87e2000-07-18Martin Stjernholm  * frames that have been recursed already, to propagate the GC_LIVE
996f872000-06-12Martin Stjernholm  * flag to things that have been found to be referenced from live * objects. rec_list is not touched at all in this extra round. */
dc296b1997-10-21Fredrik Hübinette (Hubbe) static double objects_alloced = 0.0; static double objects_freed = 0.0;
6930181996-02-25Fredrik Hübinette (Hubbe) 
4a578f1997-01-27Fredrik Hübinette (Hubbe) struct callback_list gc_callbacks;
424d9c1999-05-02Fredrik Hübinette (Hubbe) struct callback *debug_add_gc_callback(callback_func call,
4a578f1997-01-27Fredrik Hübinette (Hubbe)  void *arg, callback_func free_func) { return add_to_callback(&gc_callbacks, call, arg, free_func); }
45d87e2000-07-18Martin Stjernholm static void gc_cycle_pop(void *a); #undef BLOCK_ALLOC_NEXT #define BLOCK_ALLOC_NEXT next
c94c371996-03-28Fredrik Hübinette (Hubbe) 
424d9c1999-05-02Fredrik Hübinette (Hubbe) #undef INIT_BLOCK
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
e2d9e62000-06-10Martin Stjernholm #define INIT_BLOCK(X) \ (X)->flags=(X)->refs=(X)->weak_refs=(X)->xrefs=0; \
0816292000-07-03Martin Stjernholm  (X)->saved_refs=-1; \
45d87e2000-07-18Martin Stjernholm  (X)->frame = 0;
424d9c1999-05-02Fredrik Hübinette (Hubbe) #else
e2d9e62000-06-10Martin Stjernholm #define INIT_BLOCK(X) \
45d87e2000-07-18Martin Stjernholm  (X)->flags=(X)->refs=(X)->weak_refs=0; \ (X)->frame = 0;
05c7cd1997-07-19Fredrik Hübinette (Hubbe) #endif
c94c371996-03-28Fredrik Hübinette (Hubbe) 
22aa2f2000-09-04Martin Stjernholm #ifdef PIKE_DEBUG #undef get_marker #define get_marker debug_get_marker #undef find_marker #define find_marker debug_find_marker #endif
424d9c1999-05-02Fredrik Hübinette (Hubbe) PTR_HASH_ALLOC(marker,MARKER_CHUNK_SIZE)
c94c371996-03-28Fredrik Hübinette (Hubbe) 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
1ca3ba1997-10-13Fredrik Hübinette (Hubbe) 
22aa2f2000-09-04Martin Stjernholm #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)))
e2d9e62000-06-10Martin Stjernholm int gc_in_cycle_check = 0; static unsigned weak_freed, checked, marked, cycle_checked, live_ref;
45d87e2000-07-18Martin Stjernholm static unsigned max_gc_frames, num_gc_frames = 0;
e2d9e62000-06-10Martin Stjernholm static unsigned gc_extra_refs = 0;
dc296b1997-10-21Fredrik Hübinette (Hubbe) void dump_gc_info(void) { fprintf(stderr,"Current number of objects: %ld\n",(long)num_objects); fprintf(stderr,"Objects allocated total : %ld\n",(long)num_allocs); fprintf(stderr," threshold for next gc() : %ld\n",(long)alloc_threshold); fprintf(stderr,"Average allocs per gc() : %f\n",objects_alloced); fprintf(stderr,"Average frees per gc() : %f\n",objects_freed);
a17d762000-08-11Henrik Grubbström (Grubba)  fprintf(stderr,"Second since last gc() : %ld\n", DO_NOT_WARN((long)TIME(0) - (long)last_gc));
dc296b1997-10-21Fredrik Hübinette (Hubbe)  fprintf(stderr,"Projected garbage : %f\n", objects_freed * (double) num_allocs / (double) alloc_threshold);
6bc62b2000-04-14Martin Stjernholm  fprintf(stderr,"in_gc : %d\n", Pike_in_gc);
dc296b1997-10-21Fredrik Hübinette (Hubbe) }
1ca3ba1997-10-13Fredrik Hübinette (Hubbe) TYPE_T attempt_to_identify(void *something) { struct array *a; struct object *o; struct program *p;
62971d1998-01-19Fredrik Hübinette (Hubbe)  struct mapping *m; struct multiset *mu;
1ca3ba1997-10-13Fredrik Hübinette (Hubbe)  a=&empty_array; do { if(a==(struct array *)something) return T_ARRAY; a=a->next;
55530f2000-09-30Martin Stjernholm  }while(a!=&empty_array);
1ca3ba1997-10-13Fredrik Hübinette (Hubbe) 
55530f2000-09-30Martin Stjernholm  for(o=first_object;o;o=o->next)
1ca3ba1997-10-13Fredrik Hübinette (Hubbe)  if(o==(struct object *)something) return T_OBJECT;
55530f2000-09-30Martin Stjernholm  for(p=first_program;p;p=p->next)
1ca3ba1997-10-13Fredrik Hübinette (Hubbe)  if(p==(struct program *)something) return T_PROGRAM;
55530f2000-09-30Martin Stjernholm  for(m=first_mapping;m;m=m->next)
62971d1998-01-19Fredrik Hübinette (Hubbe)  if(m==(struct mapping *)something) return T_MAPPING;
22aa2f2000-09-04Martin Stjernholm  else if (m->data == (struct mapping_data *) something) return T_MAPPING_DATA;
62971d1998-01-19Fredrik Hübinette (Hubbe) 
55530f2000-09-30Martin Stjernholm  for(mu=first_multiset;mu;mu=mu->next)
62971d1998-01-19Fredrik Hübinette (Hubbe)  if(mu==(struct multiset *)something) return T_MULTISET; if(safe_debug_findstring((struct pike_string *)something)) return T_STRING;
04966d2000-10-03Fredrik Hübinette (Hubbe)  return PIKE_T_UNKNOWN;
1ca3ba1997-10-13Fredrik Hübinette (Hubbe) }
20513c2000-04-12Fredrik Hübinette (Hubbe) void *check_for =0;
1ca3ba1997-10-13Fredrik Hübinette (Hubbe) static char *found_where="";
f6d0171997-10-15Fredrik Hübinette (Hubbe) static void *found_in=0;
4694111997-11-07Fredrik Hübinette (Hubbe) static int found_in_type=0;
f6d0171997-10-15Fredrik Hübinette (Hubbe) void *gc_svalue_location=0;
06ae272000-04-19Martin Stjernholm char *fatal_after_gc=0;
e2d9e62000-06-10Martin Stjernholm int gc_debug = 0;
ad2bdb2000-04-12Fredrik Hübinette (Hubbe) 
a4033e2000-04-14Fredrik Hübinette (Hubbe) #define DESCRIBE_MEM 1 #define DESCRIBE_NO_REFS 2 #define DESCRIBE_SHORT 4 #define DESCRIBE_NO_DMALLOC 8
ad2bdb2000-04-12Fredrik Hübinette (Hubbe) 
a4033e2000-04-14Fredrik Hübinette (Hubbe) /* type == -1 means that memblock is a char* and should be * really be printed.. */ void describe_location(void *real_memblock, int real_type, void *location, int indent, int depth, int flags)
3568101997-10-16Fredrik Hübinette (Hubbe) {
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  struct program *p;
a4033e2000-04-14Fredrik Hübinette (Hubbe)  void *memblock=0; int type=real_type;
4694111997-11-07Fredrik Hübinette (Hubbe)  if(!location) return;
1e4e5f2000-04-07Fredrik Hübinette (Hubbe) /* fprintf(stderr,"**Location of (short) svalue: %p\n",location); */
62971d1998-01-19Fredrik Hübinette (Hubbe) 
87c7f92000-04-19Martin Stjernholm  if(real_type!=-1) memblock=real_memblock;
a4033e2000-04-14Fredrik Hübinette (Hubbe) 
20513c2000-04-12Fredrik Hübinette (Hubbe) #ifdef DEBUG_MALLOC if(memblock == 0 || type == -1) { extern void *dmalloc_find_memblock_base(void *); memblock=dmalloc_find_memblock_base(location); } #endif
04966d2000-10-03Fredrik Hübinette (Hubbe)  if(type==PIKE_T_UNKNOWN)
a4033e2000-04-14Fredrik Hübinette (Hubbe)  type=attempt_to_identify(memblock);
20513c2000-04-12Fredrik Hübinette (Hubbe)  if(memblock)
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s-> from %s %p offset %ld\n", indent,"",
20513c2000-04-12Fredrik Hübinette (Hubbe)  get_name_of_type(type), memblock,
a17d762000-08-11Henrik Grubbström (Grubba)  DO_NOT_WARN((long)((char *)location - (char *)memblock)));
20513c2000-04-12Fredrik Hübinette (Hubbe)  else
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s-> at location %p in unknown memblock (mmaped?)\n", indent,"",
20513c2000-04-12Fredrik Hübinette (Hubbe)  location);
a4033e2000-04-14Fredrik Hübinette (Hubbe)  if(memblock && depth>0) describe_something(memblock,type,indent+2,depth-1,flags | DESCRIBE_MEM);
20513c2000-04-12Fredrik Hübinette (Hubbe) 
a4033e2000-04-14Fredrik Hübinette (Hubbe)  again:
62971d1998-01-19Fredrik Hübinette (Hubbe)  switch(type)
3568101997-10-16Fredrik Hübinette (Hubbe)  {
04966d2000-10-03Fredrik Hübinette (Hubbe)  case PIKE_T_UNKNOWN:
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  for(p=first_program;p;p=p->next) { if(memblock == (void *)p->program) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **In memory block for program at %p\n", indent,"", p);
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  memblock=p; type=T_PROGRAM;
a4033e2000-04-14Fredrik Hübinette (Hubbe)  goto again;
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  } } break;
0b69441998-01-19Fredrik Hübinette (Hubbe)  case T_PROGRAM: {
9c815b2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t e;
0b69441998-01-19Fredrik Hübinette (Hubbe)  char *ptr=(char *)location;
a4033e2000-04-14Fredrik Hübinette (Hubbe)  p=(struct program *)memblock;
0b69441998-01-19Fredrik Hübinette (Hubbe) 
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  if(location == (void *)&p->prev)
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **In p->prev\n",indent,"");
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  if(location == (void *)&p->next)
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **In p->next\n",indent,"");
1e4e5f2000-04-07Fredrik Hübinette (Hubbe) 
a4033e2000-04-14Fredrik Hübinette (Hubbe)  if(p->inherits && ptr >= (char *)p->inherits &&
f00c362000-08-10Henrik Grubbström (Grubba)  ptr < (char*)(p->inherits+p->num_inherits))
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  {
f00c362000-08-10Henrik Grubbström (Grubba)  e=((char *)ptr - (char *)(p->inherits)) / sizeof(struct inherit);
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **In p->inherits[%ld] (%s)\n",indent,"",
a17d762000-08-11Henrik Grubbström (Grubba)  DO_NOT_WARN((long)e),
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  p->inherits[e].name ? p->inherits[e].name->str : "no name");
dfe8f32000-04-26Fredrik Hübinette (Hubbe)  break;
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  }
a4033e2000-04-14Fredrik Hübinette (Hubbe)  if(p->constants && ptr >= (char *)p->constants &&
f00c362000-08-10Henrik Grubbström (Grubba)  ptr < (char*)(p->constants+p->num_constants))
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  {
f00c362000-08-10Henrik Grubbström (Grubba)  e = ((char *)ptr - (char *)(p->constants)) /
9c815b2000-08-10Henrik Grubbström (Grubba)  sizeof(struct program_constant);
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **In p->constants[%ld] (%s)\n",indent,"",
a17d762000-08-11Henrik Grubbström (Grubba)  DO_NOT_WARN((long)e),
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  p->constants[e].name ? p->constants[e].name->str : "no name");
dfe8f32000-04-26Fredrik Hübinette (Hubbe)  break;
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  }
0b69441998-01-19Fredrik Hübinette (Hubbe) 
a4033e2000-04-14Fredrik Hübinette (Hubbe)  if(p->identifiers && ptr >= (char *)p->identifiers &&
f00c362000-08-10Henrik Grubbström (Grubba)  ptr < (char*)(p->identifiers+p->num_identifiers))
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  {
f00c362000-08-10Henrik Grubbström (Grubba)  e = ((char *)ptr - (char *)(p->identifiers)) /
9c815b2000-08-10Henrik Grubbström (Grubba)  sizeof(struct identifier);
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **In p->identifiers[%ld] (%s)\n",indent,"",
a17d762000-08-11Henrik Grubbström (Grubba)  DO_NOT_WARN((long)e),
a4033e2000-04-14Fredrik Hübinette (Hubbe)  p->identifiers[e].name ? p->identifiers[e].name->str : "no name");
dfe8f32000-04-26Fredrik Hübinette (Hubbe)  break;
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  } #define FOO(NTYP,TYP,NAME) \
a4033e2000-04-14Fredrik Hübinette (Hubbe)  if(location == (void *)&p->NAME) fprintf(stderr,"%*s **In p->" #NAME "\n",indent,""); \
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  if(ptr >= (char *)p->NAME && ptr<(char*)(p->NAME+p->PIKE_CONCAT(num_,NAME))) \
f5757f2000-08-11Henrik Grubbström (Grubba)  fprintf(stderr,"%*s **In p->" #NAME "[%ld]\n",indent,"", \
1a12e82000-09-30Martin Stjernholm  PTRDIFF_T_TO_LONG(((char *)ptr - (char *)(p->NAME)) / sizeof(TYP)));
1e4e5f2000-04-07Fredrik Hübinette (Hubbe) #include "program_areas.h"
0b69441998-01-19Fredrik Hübinette (Hubbe) 
dfe8f32000-04-26Fredrik Hübinette (Hubbe)  break;
0b69441998-01-19Fredrik Hübinette (Hubbe)  }
62971d1998-01-19Fredrik Hübinette (Hubbe)  case T_OBJECT:
3568101997-10-16Fredrik Hübinette (Hubbe)  {
62971d1998-01-19Fredrik Hübinette (Hubbe)  struct object *o=(struct object *)memblock;
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  struct program *p;
a4033e2000-04-14Fredrik Hübinette (Hubbe)  if(location == (void *)&o->parent) fprintf(stderr,"%*s **In o->parent\n",indent,""); if(location == (void *)&o->prog) fprintf(stderr,"%*s **In o->prog\n",indent,""); if(location == (void *)&o->next) fprintf(stderr,"%*s **In o->next\n",indent,""); if(location == (void *)&o->prev) fprintf(stderr,"%*s **In o->prev\n",indent,"");
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  p=o->prog; if(!o->prog) { p=id_to_program(o->program_id); if(p)
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **(We are lucky, found program for destructed object)\n",indent,"");
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  } if(p)
3568101997-10-16Fredrik Hübinette (Hubbe)  {
62971d1998-01-19Fredrik Hübinette (Hubbe)  INT32 e,d;
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  for(e=0;e<(INT32)p->num_inherits;e++)
3568101997-10-16Fredrik Hübinette (Hubbe)  {
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  struct inherit tmp=p->inherits[e];
62971d1998-01-19Fredrik Hübinette (Hubbe)  char *base=o->storage + tmp.storage_offset; for(d=0;d<(INT32)tmp.prog->num_identifiers;d++)
3568101997-10-16Fredrik Hübinette (Hubbe)  {
62971d1998-01-19Fredrik Hübinette (Hubbe)  struct identifier *id=tmp.prog->identifiers+d; if(!IDENTIFIER_IS_VARIABLE(id->identifier_flags)) continue; if(location == (void *)(base + id->func.offset)) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **In variable %s\n",indent,"",id->name->str);
62971d1998-01-19Fredrik Hübinette (Hubbe)  }
3568101997-10-16Fredrik Hübinette (Hubbe)  }
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  if((char *)location >= base && (char *)location <= base + ( tmp.prog->storage_needed - tmp.prog->inherits[0].storage_offset )) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s **In storage for inherit %d",indent,"",e);
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  if(tmp.name) fprintf(stderr," (%s)",tmp.name->str); fprintf(stderr,"\n"); }
3568101997-10-16Fredrik Hübinette (Hubbe)  } }
dfe8f32000-04-26Fredrik Hübinette (Hubbe)  break;
3568101997-10-16Fredrik Hübinette (Hubbe)  }
62971d1998-01-19Fredrik Hübinette (Hubbe)  case T_ARRAY: { struct array *a=(struct array *)memblock; struct svalue *s=(struct svalue *)location;
f5757f2000-08-11Henrik Grubbström (Grubba)  fprintf(stderr,"%*s **In index %ld\n",indent,"", DO_NOT_WARN((long)(s-ITEM(a))));
dfe8f32000-04-26Fredrik Hübinette (Hubbe)  break;
62971d1998-01-19Fredrik Hübinette (Hubbe)  }
3568101997-10-16Fredrik Hübinette (Hubbe)  }
dfe8f32000-04-26Fredrik Hübinette (Hubbe) 
57a4362000-04-27Fredrik Hübinette (Hubbe) #ifdef DEBUG_MALLOC
dc4d8c2000-08-11Henrik Grubbström (Grubba)  /* FIXME: Is the following call correct? * Shouldn't the second argument be an offset? */
dfe8f32000-04-26Fredrik Hübinette (Hubbe)  dmalloc_describe_location(memblock, location, indent);
57a4362000-04-27Fredrik Hübinette (Hubbe) #endif
3568101997-10-16Fredrik Hübinette (Hubbe) }
45d87e2000-07-18Martin Stjernholm static void describe_gc_frame(struct gc_frame *l) { if (l->frameflags & GC_POP_FRAME) fprintf(stderr, "back=%p, prev=%p, next=%p, data=%p, cycle=%u, flags=0x%02x", l->back, PREV(l), NEXT(l), l->data, CYCLE(l), l->frameflags); else fprintf(stderr, "LINK back=%p, data=%p, weak=%d, flags=0x%02x", l->back, l->data, l->u.link.weak, l->frameflags); }
e2d9e62000-06-10Martin Stjernholm static void describe_marker(struct marker *m) {
45d87e2000-07-18Martin Stjernholm  if (m) {
1a12e82000-09-30Martin Stjernholm  fprintf(stderr, "marker at %p: flags=0x%04x, refs=%d, weak=%d, "
45d87e2000-07-18Martin Stjernholm  "xrefs=%d, saved=%d, frame=%p",
e2d9e62000-06-10Martin Stjernholm  m, m->flags, m->refs, m->weak_refs,
45d87e2000-07-18Martin Stjernholm  m->xrefs, m->saved_refs, m->frame); #ifdef PIKE_DEBUG if (m->frame) { fputs(" [", stderr); describe_gc_frame(m->frame); putc(']', stderr); } #endif putc('\n', stderr); }
e2d9e62000-06-10Martin Stjernholm  else fprintf(stderr, "no marker\n"); } void debug_gc_fatal(void *a, int flags, const char *fmt, ...) { va_list args; va_start(args, fmt); fprintf(stderr, "**"); (void) VFPRINTF(stderr, fmt, args); describe(a); if (flags & 1) locate_references(a); if (flags & 2) fatal_after_gc = "Fatal in garbage collector.\n"; else debug_fatal("Fatal in garbage collector.\n"); }
0816292000-07-03Martin Stjernholm static void gdb_gc_stop_here(void *a, int weak)
b8a6e71996-09-25Fredrik Hübinette (Hubbe) {
1a12e82000-09-30Martin Stjernholm  fprintf(stderr,"***One %sref found%s. ",
0816292000-07-03Martin Stjernholm  weak ? "weak " : "", found_where?found_where:"");
1a12e82000-09-30Martin Stjernholm  describe_location(found_in , found_in_type, gc_svalue_location,0,1,0);
20513c2000-04-12Fredrik Hübinette (Hubbe)  fprintf(stderr,"----------end------------\n");
b8a6e71996-09-25Fredrik Hübinette (Hubbe) }
f6d0171997-10-15Fredrik Hübinette (Hubbe) 
1330e12000-08-10Henrik Grubbström (Grubba) void debug_gc_xmark_svalues(struct svalue *s, ptrdiff_t num, char *fromwhere)
4694111997-11-07Fredrik Hübinette (Hubbe) { found_in=(void *)fromwhere; found_in_type=-1; gc_xmark_svalues(s,num);
04966d2000-10-03Fredrik Hübinette (Hubbe)  found_in_type=PIKE_T_UNKNOWN;
4694111997-11-07Fredrik Hübinette (Hubbe)  found_in=0; }
1330e12000-08-10Henrik Grubbström (Grubba) void debug_gc_check_svalues(struct svalue *s, ptrdiff_t num, TYPE_T t, void *data)
f6d0171997-10-15Fredrik Hübinette (Hubbe) { found_in=data; found_in_type=t;
c4ccb82000-07-04Martin Stjernholm  gc_check_svalues(s,num);
04966d2000-10-03Fredrik Hübinette (Hubbe)  found_in_type=PIKE_T_UNKNOWN;
4694111997-11-07Fredrik Hübinette (Hubbe)  found_in=0;
f6d0171997-10-15Fredrik Hübinette (Hubbe) }
1330e12000-08-10Henrik Grubbström (Grubba) void debug_gc_check_weak_svalues(struct svalue *s, ptrdiff_t num, TYPE_T t, void *data)
e2d9e62000-06-10Martin Stjernholm { found_in=data; found_in_type=t;
c4ccb82000-07-04Martin Stjernholm  gc_check_weak_svalues(s,num);
04966d2000-10-03Fredrik Hübinette (Hubbe)  found_in_type=PIKE_T_UNKNOWN;
e2d9e62000-06-10Martin Stjernholm  found_in=0; }
f6d0171997-10-15Fredrik Hübinette (Hubbe) void debug_gc_check_short_svalue(union anything *u, TYPE_T type, TYPE_T t, void *data) { found_in=data; found_in_type=t; gc_check_short_svalue(u,type);
04966d2000-10-03Fredrik Hübinette (Hubbe)  found_in_type=PIKE_T_UNKNOWN;
4694111997-11-07Fredrik Hübinette (Hubbe)  found_in=0;
f6d0171997-10-15Fredrik Hübinette (Hubbe) }
e2d9e62000-06-10Martin Stjernholm void debug_gc_check_weak_short_svalue(union anything *u, TYPE_T type, TYPE_T t, void *data) { found_in=data; found_in_type=t; gc_check_weak_short_svalue(u,type);
04966d2000-10-03Fredrik Hübinette (Hubbe)  found_in_type=PIKE_T_UNKNOWN;
e2d9e62000-06-10Martin Stjernholm  found_in=0; }
0b69441998-01-19Fredrik Hübinette (Hubbe) 
22aa2f2000-09-04Martin Stjernholm int debug_low_gc_check(void *x, TYPE_T t, void *data)
0b69441998-01-19Fredrik Hübinette (Hubbe) { int ret; found_in=data; found_in_type=t; ret=gc_check(x);
04966d2000-10-03Fredrik Hübinette (Hubbe)  found_in_type=PIKE_T_UNKNOWN;
0b69441998-01-19Fredrik Hübinette (Hubbe)  found_in=0; return ret; }
393a592000-08-16Henrik Grubbström (Grubba) /* Avoid loss of precision warning. */ #ifdef __ECL
1a12e82000-09-30Martin Stjernholm static inline unsigned long SIZE_T_TO_ULONG(size_t x)
393a592000-08-16Henrik Grubbström (Grubba) {
1a12e82000-09-30Martin Stjernholm  return DO_NOT_WARN((unsigned long)x);
393a592000-08-16Henrik Grubbström (Grubba) } #else /* !__ECL */
1a12e82000-09-30Martin Stjernholm #define SIZE_T_TO_ULONG(x) ((unsigned long)(x))
393a592000-08-16Henrik Grubbström (Grubba) #endif /* __ECL */
a4033e2000-04-14Fredrik Hübinette (Hubbe) void low_describe_something(void *a, int t, int indent, int depth, int flags)
f6d0171997-10-15Fredrik Hübinette (Hubbe) { struct program *p=(struct program *)a;
0816292000-07-03Martin Stjernholm  struct marker *m;
f6d0171997-10-15Fredrik Hübinette (Hubbe) 
a4033e2000-04-14Fredrik Hübinette (Hubbe)  if(depth<0) return;
afa78b2000-08-27Martin Stjernholm  if (Pike_in_gc && (m = find_marker(a))) {
0816292000-07-03Martin Stjernholm  fprintf(stderr,"%*s**Got gc ",indent,""); describe_marker(m); }
f6d0171997-10-15Fredrik Hübinette (Hubbe)  switch(t) {
2eeba91999-03-17Fredrik Hübinette (Hubbe)  case T_FUNCTION: if(attempt_to_identify(a) != T_OBJECT) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Builtin function!\n",indent,"");
2eeba91999-03-17Fredrik Hübinette (Hubbe)  break; }
f6d0171997-10-15Fredrik Hübinette (Hubbe)  case T_OBJECT: p=((struct object *)a)->prog;
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Parent identifier: %d\n",indent,"",((struct object *)a)->parent_identifier); fprintf(stderr,"%*s**Program id: %ld\n",indent,"",((struct object *)a)->program_id);
1e4e5f2000-04-07Fredrik Hübinette (Hubbe) 
7bf6232000-04-23Martin Stjernholm  if (((struct object *)a)->next == ((struct object *)a)) fprintf(stderr, "%*s**The object is fake.\n",indent,"");
e2d9e62000-06-10Martin Stjernholm  { struct object *o; for (o = first_object; o && o != (struct object *) a; o = o->next) {} if (!o) fprintf(stderr,"%*s**The object is not on the object link list.\n",indent,""); for (o = objects_to_destruct; o && o != (struct object *) a; o = o->next) {} if (o) fprintf(stderr,"%*s**The object is on objects_to_destruct.\n",indent,""); }
7bf6232000-04-23Martin Stjernholm  if(!p) { fprintf(stderr,"%*s**The object is destructed.\n",indent,""); p=id_to_program(((struct object *)a)->program_id); } if (p) { fprintf(stderr,"%*s**Attempting to describe program object was instantiated from:\n",indent,"");
505e3e2000-09-30Martin Stjernholm #ifdef DEBUG_MALLOC if ((int) p == 0x55555555)
728b232000-09-30Martin Stjernholm  fprintf(stderr, "%*s**Zapped program pointer.\n", indent, "");
505e3e2000-09-30Martin Stjernholm  else #endif low_describe_something(p, T_PROGRAM, indent, depth, flags);
7bf6232000-04-23Martin Stjernholm  }
8fb1e11998-04-05Fredrik Hübinette (Hubbe)  if( ((struct object *)a)->parent) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Describing object's parent:\n",indent,""); describe_something( ((struct object *)a)->parent, t, indent+2,depth-1, (flags | DESCRIBE_SHORT | DESCRIBE_NO_REFS ) & ~ (DESCRIBE_MEM));
8fb1e11998-04-05Fredrik Hübinette (Hubbe)  }else{
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**There is no parent (any longer?)\n",indent,"");
8fb1e11998-04-05Fredrik Hübinette (Hubbe)  }
7bf6232000-04-23Martin Stjernholm  break;
22aa2f2000-09-04Martin Stjernholm 
f6d0171997-10-15Fredrik Hübinette (Hubbe)  case T_PROGRAM:
3568101997-10-16Fredrik Hübinette (Hubbe)  { char *tmp; INT32 line,pos;
2eeba91999-03-17Fredrik Hübinette (Hubbe)  int foo=0;
3568101997-10-16Fredrik Hübinette (Hubbe) 
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Program id: %ld\n",indent,"",(long)(p->id));
e2d9e62000-06-10Martin Stjernholm 
05590d1998-04-23Fredrik Hübinette (Hubbe)  if(p->flags & PROGRAM_HAS_C_METHODS)
f6d0171997-10-15Fredrik Hübinette (Hubbe)  {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**The program was written in C.\n",indent,"");
f6d0171997-10-15Fredrik Hübinette (Hubbe)  }
2eeba91999-03-17Fredrik Hübinette (Hubbe)  for(pos=0;pos<100;pos++)
f6d0171997-10-15Fredrik Hübinette (Hubbe)  {
3568101997-10-16Fredrik Hübinette (Hubbe)  tmp=get_line(p->program+pos, p, &line); if(tmp && line) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Location: %s:%ld\n",indent,"",tmp,(long)line);
2eeba91999-03-17Fredrik Hübinette (Hubbe)  foo=1;
3568101997-10-16Fredrik Hübinette (Hubbe)  break; }
393a592000-08-16Henrik Grubbström (Grubba)  if(pos+1>=(ptrdiff_t)p->num_program)
2eeba91999-03-17Fredrik Hübinette (Hubbe)  break; } #if 0 if(!foo && p->num_linenumbers>1 && EXTRACT_UCHAR(p->linenumbers)=='\177') {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**From file: %s\n",indent,"",p->linenumbers+1);
2eeba91999-03-17Fredrik Hübinette (Hubbe)  foo=1; } #endif if(!foo) { int e;
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**identifiers:\n",indent,"");
2eeba91999-03-17Fredrik Hübinette (Hubbe)  for(e=0;e<p->num_identifier_references;e++)
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**** %s\n",indent,"",ID_FROM_INT(p,e)->name->str);
2eeba91999-03-17Fredrik Hübinette (Hubbe) 
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**num inherits: %d\n",indent,"",p->num_inherits);
f6d0171997-10-15Fredrik Hübinette (Hubbe)  }
a4033e2000-04-14Fredrik Hübinette (Hubbe)  if(flags & DESCRIBE_MEM) {
1e4e5f2000-04-07Fredrik Hübinette (Hubbe) #define FOO(NUMTYPE,TYPE,NAME) \
1a12e82000-09-30Martin Stjernholm  fprintf(stderr, "%*s* " #NAME " %p[%lu]\n", \ indent, "", p->NAME, SIZE_T_TO_ULONG(p->PIKE_CONCAT(num_,NAME)));
1e4e5f2000-04-07Fredrik Hübinette (Hubbe) #include "program_areas.h"
a4033e2000-04-14Fredrik Hübinette (Hubbe)  }
2eeba91999-03-17Fredrik Hübinette (Hubbe) 
f6d0171997-10-15Fredrik Hübinette (Hubbe)  break;
3568101997-10-16Fredrik Hübinette (Hubbe)  }
e2d9e62000-06-10Martin Stjernholm  case T_MULTISET: fprintf(stderr,"%*s**Describing array of multiset:\n",indent,""); debug_dump_array(((struct multiset *)a)->ind); break;
f6d0171997-10-15Fredrik Hübinette (Hubbe)  case T_ARRAY:
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Describing array:\n",indent,"");
f6d0171997-10-15Fredrik Hübinette (Hubbe)  debug_dump_array((struct array *)a); break;
62971d1998-01-19Fredrik Hübinette (Hubbe) 
61e9a01998-01-25Fredrik Hübinette (Hubbe)  case T_MAPPING:
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Describing mapping:\n",indent,"");
1d152d2000-03-07Fredrik Hübinette (Hubbe)  debug_dump_mapping((struct mapping *)a);
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Describing mapping data block:\n",indent,""); describe_something( ((struct mapping *)a)->data, -2, indent+2,depth-1,flags);
61e9a01998-01-25Fredrik Hübinette (Hubbe)  break;
62971d1998-01-19Fredrik Hübinette (Hubbe)  case T_STRING: { struct pike_string *s=(struct pike_string *)a;
f5757f2000-08-11Henrik Grubbström (Grubba)  fprintf(stderr, "%*s**String length is %ld:\n", indent, "", DO_NOT_WARN((long)s->len));
62971d1998-01-19Fredrik Hübinette (Hubbe)  if(s->len>77) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s** \"%60s ...\"\n",indent,"",s->str);
62971d1998-01-19Fredrik Hübinette (Hubbe)  }else{
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s** \"%s\"\n",indent,"",s->str);
62971d1998-01-19Fredrik Hübinette (Hubbe)  } break; }
f6d0171997-10-15Fredrik Hübinette (Hubbe)  }
25479a2000-03-07Fredrik Hübinette (Hubbe) }
a4033e2000-04-14Fredrik Hübinette (Hubbe) void describe_something(void *a, int t, int indent, int depth, int flags)
25479a2000-03-07Fredrik Hübinette (Hubbe) {
111fdd2000-04-17Fredrik Hübinette (Hubbe)  int tmp;
25479a2000-03-07Fredrik Hübinette (Hubbe)  struct program *p=(struct program *)a; if(!a) return; if(t==-1) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Location description: %s\n",indent,"",(char *)a);
25479a2000-03-07Fredrik Hübinette (Hubbe)  return; }
111fdd2000-04-17Fredrik Hübinette (Hubbe)  /* Disable debug, this may help reduce recursion bugs */ tmp=d_flag; d_flag=0;
3845452000-03-08Henrik Grubbström (Grubba) #ifdef DEBUG_MALLOC if (((int)a) == 0x55555555) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s**Location: %p Type: %s Zapped pointer\n",indent,"",a,
3845452000-03-08Henrik Grubbström (Grubba)  get_name_of_type(t)); } else #endif /* DEBUG_MALLOC */
728b232000-09-30Martin Stjernholm  if (((ptrdiff_t)a) & 3) { fprintf(stderr,"%*s**Location: %p Type: %s Misaligned address\n",indent,"",a, get_name_of_type(t)); } else { fprintf(stderr,"%*s**Location: %p Type: %s Refs: %d\n",indent,"",a, get_name_of_type(t), *(INT32 *)a);
25479a2000-03-07Fredrik Hübinette (Hubbe)  #ifdef DEBUG_MALLOC
728b232000-09-30Martin Stjernholm  if(!(flags & DESCRIBE_NO_DMALLOC)) debug_malloc_dump_references(a,indent+2,depth-1,flags);
25479a2000-03-07Fredrik Hübinette (Hubbe) #endif
728b232000-09-30Martin Stjernholm  low_describe_something(a,t,indent,depth,flags); }
87c7f92000-04-19Martin Stjernholm 
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"%*s*******************\n",indent,"");
111fdd2000-04-17Fredrik Hübinette (Hubbe)  d_flag=tmp;
8fb1e11998-04-05Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void describe(void *x)
8fb1e11998-04-05Fredrik Hübinette (Hubbe) {
a4033e2000-04-14Fredrik Hübinette (Hubbe)  describe_something(x, attempt_to_identify(x), 0, 2, 0);
f6d0171997-10-15Fredrik Hübinette (Hubbe) }
c72a4e1998-12-15Fredrik Hübinette (Hubbe) void debug_describe_svalue(struct svalue *s) { fprintf(stderr,"Svalue at %p is:\n",s); switch(s->type) { case T_INT: fprintf(stderr," %ld\n",(long)s->u.integer); break; case T_FLOAT: fprintf(stderr," %f\n",s->u.float_number); break;
2eeba91999-03-17Fredrik Hübinette (Hubbe)  case T_FUNCTION: if(s->subtype == FUNCTION_BUILTIN) { fprintf(stderr," Builtin function: %s\n",s->u.efun->name->str); }else{ if(!s->u.object->prog) {
1e4e5f2000-04-07Fredrik Hübinette (Hubbe)  struct program *p=id_to_program(s->u.object->program_id); if(p) { fprintf(stderr," Function (destructed) name: %s\n",ID_FROM_INT(p,s->subtype)->name->str); }else{ fprintf(stderr," Function in destructed object.\n"); }
2eeba91999-03-17Fredrik Hübinette (Hubbe)  }else{ fprintf(stderr," Function name: %s\n",ID_FROM_INT(s->u.object->prog,s->subtype)->name->str); } }
c72a4e1998-12-15Fredrik Hübinette (Hubbe)  }
a4033e2000-04-14Fredrik Hübinette (Hubbe)  describe_something(s->u.refs,s->type,0,2,0);
c72a4e1998-12-15Fredrik Hübinette (Hubbe) }
7bf6232000-04-23Martin Stjernholm void debug_gc_touch(void *a) { struct marker *m;
e2d9e62000-06-10Martin Stjernholm  if (!a) fatal("Got null pointer.\n");
7bf6232000-04-23Martin Stjernholm  m = find_marker(a);
22aa2f2000-09-04Martin Stjernholm  switch (Pike_in_gc) { case GC_PASS_PRETOUCH: if (m && !(m->flags & GC_PRETOUCHED)) gc_fatal(a, 1, "Thing got an existing but untouched marker.\n"); get_marker(a)->flags |= GC_PRETOUCHED; break; case GC_PASS_MIDDLETOUCH: if (!m) gc_fatal(a, 1, "Found a thing without marker.\n"); else if (!(m->flags & GC_PRETOUCHED)) gc_fatal(a, 1, "Thing got an existing but untouched marker.\n"); m->flags |= GC_MIDDLETOUCHED; break; case GC_PASS_POSTTOUCH: 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))) gc_fatal(a, 2, "Thing still got flag from recurse list.\n"); else if (m->flags & GC_MARKED) 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)) gc_fatal(a, 2, "A thing was missed by " "both mark and cycle check pass.\n"); else if (!(m->flags & GC_IS_REFERENCED)) gc_fatal(a, 2, "An unreferenced thing " "got missed by gc_is_referenced().\n"); else if (!(m->flags & GC_DO_FREE)) gc_fatal(a, 2, "An unreferenced thing " "got missed by gc_do_free().\n"); else if (m->flags & GC_GOT_EXTRA_REF) gc_fatal(a, 2, "A thing still got an extra ref.\n");
1a12e82000-09-30Martin Stjernholm  else if (m->weak_refs > m->saved_refs) gc_fatal(a, 2, "A thing got more weak references than references.\n");
22aa2f2000-09-04Martin Stjernholm  else if (!(m->flags & GC_LIVE)) {
1a12e82000-09-30Martin Stjernholm  if (m->weak_refs < 0)
22aa2f2000-09-04Martin Stjernholm  gc_fatal(a, 3, "A thing which had only weak references is " "still around after gc.\n"); else gc_fatal(a, 3, "A thing to garb is still around.\n"); }
6d30f52000-07-11Martin Stjernholm  }
22aa2f2000-09-04Martin Stjernholm  break; default: fatal("debug_gc_touch() used in invalid gc pass.\n");
7bf6232000-04-23Martin Stjernholm  } }
0816292000-07-03Martin Stjernholm static INLINE struct marker *gc_check_debug(void *a, int weak)
c94c371996-03-28Fredrik Hübinette (Hubbe) {
7bf6232000-04-23Martin Stjernholm  struct marker *m;
87c7f92000-04-19Martin Stjernholm 
e2d9e62000-06-10Martin Stjernholm  if (!a) fatal("Got null pointer.\n");
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  if(check_for) { if(check_for == a) {
0816292000-07-03Martin Stjernholm  gdb_gc_stop_here(a, weak);
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  }
4a578f1997-01-27Fredrik Hübinette (Hubbe)  return 0;
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  }
e942a72000-04-15Fredrik Hübinette (Hubbe) 
7bf6232000-04-23Martin Stjernholm  if (Pike_in_gc != GC_PASS_CHECK) fatal("gc check attempted in invalid pass.\n"); m = get_marker(a);
87c7f92000-04-19Martin Stjernholm 
e2d9e62000-06-10Martin Stjernholm  if (!*(INT32 *)a) gc_fatal(a, 1, "GC check on thing without refs.\n");
0816292000-07-03Martin Stjernholm  if (m->saved_refs != -1 && m->saved_refs != *(INT32 *)a) gc_fatal(a, 1, "Refs changed in gc check pass.\n"); m->saved_refs = *(INT32 *)a;
ff322e2000-06-10Martin Stjernholm  if (m->refs + m->xrefs >= *(INT32 *) a) /* m->refs will be incremented by the caller. */ gc_fatal(a, 1, "Thing is getting more internal refs than refs.\n");
e2d9e62000-06-10Martin Stjernholm  checked++; return m; } #endif /* PIKE_DEBUG */
fa8c692000-11-30Fredrik Hübinette (Hubbe) PMOD_EXPORT INT32 real_gc_check(void *a)
e2d9e62000-06-10Martin Stjernholm { struct marker *m;
0816292000-07-03Martin Stjernholm  INT32 ret;
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG
0816292000-07-03Martin Stjernholm  if (!(m = gc_check_debug(a, 0))) return 0;
2200002000-04-23Martin Stjernholm #else m = get_marker(a);
b8a6e71996-09-25Fredrik Hübinette (Hubbe) #endif
0816292000-07-03Martin Stjernholm  ret = add_ref(m); if (m->refs >= *(INT32 *) a) m->flags |= GC_NOT_REFERENCED; return ret;
e2d9e62000-06-10Martin Stjernholm }
e942a72000-04-15Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm INT32 real_gc_check_weak(void *a) { struct marker *m;
0816292000-07-03Martin Stjernholm  INT32 ret;
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG
0816292000-07-03Martin Stjernholm  if (!(m = gc_check_debug(a, 1))) return 0;
10c4a42000-08-17Martin Stjernholm  if (m->weak_refs < 0)
9326332000-06-12Martin Stjernholm  gc_fatal(a, 1, "Thing has already reached threshold for weak free.\n");
0816292000-07-03Martin Stjernholm  if (m->weak_refs >= *(INT32 *) a) gc_fatal(a, 1, "Thing has gotten more weak refs than refs.\n");
9326332000-06-12Martin Stjernholm  if (m->weak_refs > m->refs + 1) gc_fatal(a, 1, "Thing has gotten more weak refs than internal refs.\n");
e2d9e62000-06-10Martin Stjernholm #else m = get_marker(a);
ff322e2000-06-10Martin Stjernholm #endif
0816292000-07-03Martin Stjernholm  m->weak_refs++;
6d30f52000-07-11Martin Stjernholm  gc_ext_weak_refs++;
0816292000-07-03Martin Stjernholm  if (m->weak_refs >= *(INT32 *) a) m->weak_refs = -1; ret = add_ref(m); if (m->refs >= *(INT32 *) a) m->flags |= GC_NOT_REFERENCED; return ret;
c94c371996-03-28Fredrik Hübinette (Hubbe) }
b51e6d1998-02-18Fredrik Hübinette (Hubbe) static void init_gc(void) {
424d9c1999-05-02Fredrik Hübinette (Hubbe)  init_marker_hash();
45d87e2000-07-18Martin Stjernholm  get_marker(rec_list.data); /* Used to simplify fencepost conditions. */
b51e6d1998-02-18Fredrik Hübinette (Hubbe) } static void exit_gc(void) {
424d9c1999-05-02Fredrik Hübinette (Hubbe) #ifdef DO_PIKE_CLEANUP int e=0; struct marker *h; 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();
45d87e2000-07-18Martin Stjernholm  free_all_gc_frame_blocks(); #ifdef GC_VERBOSE num_gc_frames = 0; #endif
b51e6d1998-02-18Fredrik Hübinette (Hubbe) }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
b51e6d1998-02-18Fredrik Hübinette (Hubbe) void locate_references(void *a) {
7bf6232000-04-23Martin Stjernholm  int tmp, orig_in_gc = Pike_in_gc;
7506fe2000-04-19Martin Stjernholm  void *orig_check_for=check_for;
6bc62b2000-04-14Martin Stjernholm  if(!Pike_in_gc)
b51e6d1998-02-18Fredrik Hübinette (Hubbe)  init_gc();
7bf6232000-04-23Martin Stjernholm  Pike_in_gc = GC_PASS_LOCATE; /* Disable debug, this may help reduce recursion bugs */ tmp=d_flag; d_flag=0;
06ae272000-04-19Martin Stjernholm 
b51e6d1998-02-18Fredrik Hübinette (Hubbe)  fprintf(stderr,"**Looking for references:\n"); check_for=a;
25d21c1998-02-24Per Hedbor 
b51e6d1998-02-18Fredrik Hübinette (Hubbe)  found_where=" in an array"; gc_check_all_arrays(); found_where=" in a multiset"; gc_check_all_multisets(); found_where=" in a mapping"; gc_check_all_mappings(); found_where=" in a program"; gc_check_all_programs(); found_where=" in an object"; gc_check_all_objects();
20513c2000-04-12Fredrik Hübinette (Hubbe)  #ifdef PIKE_DEBUG
94d2b22000-10-12Martin Stjernholm  if(master_object) { found_where = " as master_object"; gc_external_mark2(master_object,0," &master_object"); }
5f61da2000-04-13Fredrik Hübinette (Hubbe)  { extern struct mapping *builtin_constants;
94d2b22000-10-12Martin Stjernholm  if(builtin_constants) { found_where = " as builtin_constants";
5f61da2000-04-13Fredrik Hübinette (Hubbe)  gc_external_mark2(builtin_constants,0," &builtin_constants");
94d2b22000-10-12Martin Stjernholm  }
5f61da2000-04-13Fredrik Hübinette (Hubbe)  }
20513c2000-04-12Fredrik Hübinette (Hubbe) #endif
b51e6d1998-02-18Fredrik Hübinette (Hubbe)  found_where=" in a module"; call_callback(& gc_callbacks, (void *)0); found_where="";
7506fe2000-04-19Martin Stjernholm  check_for=orig_check_for;
20513c2000-04-12Fredrik Hübinette (Hubbe)  #ifdef DEBUG_MALLOC { extern void dmalloc_find_references_to(void *); #if 0 fprintf(stderr,"**DMALLOC Looking for references:\n"); dmalloc_find_references_to(a); #endif } #endif
7bf6232000-04-23Martin Stjernholm  Pike_in_gc = orig_in_gc;
6bc62b2000-04-14Martin Stjernholm  if(!Pike_in_gc)
b51e6d1998-02-18Fredrik Hübinette (Hubbe)  exit_gc();
7bf6232000-04-23Martin Stjernholm  d_flag=tmp;
b51e6d1998-02-18Fredrik Hübinette (Hubbe) }
25d21c1998-02-24Per Hedbor #endif
b51e6d1998-02-18Fredrik Hübinette (Hubbe) 
1637c42000-02-01Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
e2d9e62000-06-10Martin Stjernholm void gc_add_extra_ref(void *a)
c94c371996-03-28Fredrik Hübinette (Hubbe) {
e2d9e62000-06-10Martin Stjernholm  struct marker *m = get_marker(a); if (m->flags & GC_GOT_EXTRA_REF) gc_fatal(a, 0, "Thing already got an extra gc ref.\n"); m->flags |= GC_GOT_EXTRA_REF; gc_extra_refs++; ++*(INT32 *) a; }
1637c42000-02-01Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm void gc_free_extra_ref(void *a) { struct marker *m = get_marker(a); if (!(m->flags & GC_GOT_EXTRA_REF)) gc_fatal(a, 0, "Thing haven't got an extra gc ref.\n"); m->flags &= ~GC_GOT_EXTRA_REF; gc_extra_refs--; } int debug_gc_is_referenced(void *a) { struct marker *m; if (!a) fatal("Got null pointer.\n"); if (Pike_in_gc != GC_PASS_MARK) fatal("gc_is_referenced() called in invalid gc pass.\n");
1422411997-10-13Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm  if (gc_debug) { m = find_marker(a);
22aa2f2000-09-04Martin Stjernholm  if ((!m || !(m->flags & GC_PRETOUCHED)) &&
e2d9e62000-06-10Martin Stjernholm  !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);
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  }
7e697c2000-09-14Martin Stjernholm  else m = get_marker(a);
1637c42000-02-01Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm  if (m->flags & GC_IS_REFERENCED) gc_fatal(a, 0, "gc_is_referenced() called twice for thing.\n"); m->flags |= GC_IS_REFERENCED;
0816292000-07-03Martin Stjernholm  return !(m->flags & GC_NOT_REFERENCED);
c94c371996-03-28Fredrik Hübinette (Hubbe) }
20513c2000-04-12Fredrik Hübinette (Hubbe) int gc_external_mark3(void *a, void *in, char *where)
05c7cd1997-07-19Fredrik Hübinette (Hubbe) { struct marker *m;
e2d9e62000-06-10Martin Stjernholm  if (!a) fatal("Got null pointer.\n"); if (Pike_in_gc != GC_PASS_CHECK && Pike_in_gc != GC_PASS_LOCATE) fatal("gc_external_mark() called in invalid gc pass.\n");
7506fe2000-04-19Martin Stjernholm 
05c7cd1997-07-19Fredrik Hübinette (Hubbe)  if(check_for) { if(a==check_for) {
1ca3ba1997-10-13Fredrik Hübinette (Hubbe)  char *tmp=found_where;
20513c2000-04-12Fredrik Hübinette (Hubbe)  void *tmp2=found_in; if(where) found_where=where; if(in) found_in=in;
0816292000-07-03Martin Stjernholm  gdb_gc_stop_here(a, 0);
20513c2000-04-12Fredrik Hübinette (Hubbe) 
1ca3ba1997-10-13Fredrik Hübinette (Hubbe)  found_where=tmp;
20513c2000-04-12Fredrik Hübinette (Hubbe)  found_in=tmp2;
05c7cd1997-07-19Fredrik Hübinette (Hubbe)  return 1; } return 0; }
424d9c1999-05-02Fredrik Hübinette (Hubbe)  m=get_marker(a);
05c7cd1997-07-19Fredrik Hübinette (Hubbe)  m->xrefs++; m->flags|=GC_XREFERENCED;
0816292000-07-03Martin Stjernholm  if(Pike_in_gc == GC_PASS_CHECK && (m->refs + m->xrefs > *(INT32 *)a || (m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)))
ff322e2000-06-10Martin Stjernholm  gc_fatal(a, 1, "Ref counts are wrong.\n");
05c7cd1997-07-19Fredrik Hübinette (Hubbe)  return 0; }
e2d9e62000-06-10Martin Stjernholm 
63709a2000-07-18Martin Stjernholm void debug_really_free_gc_frame(struct gc_frame *l) { if (l->frameflags & GC_LINK_FREED) gc_fatal(l->data, 0, "Freeing freed gc_frame.\n"); l->frameflags |= GC_LINK_FREED;
a609812000-08-03Henrik Grubbström (Grubba)  l->back = PREV(l) = NEXT(l) = (struct gc_frame *)(ptrdiff_t) -1;
63709a2000-07-18Martin Stjernholm  really_free_gc_frame(l); #ifdef GC_VERBOSE num_gc_frames--; #endif } #else /* PIKE_DEBUG */ #define debug_really_free_gc_frame(l) really_free_gc_frame(l) #endif /* PIKE_DEBUG */
e2d9e62000-06-10Martin Stjernholm int gc_do_weak_free(void *a) { struct marker *m;
63709a2000-07-18Martin Stjernholm #ifdef PIKE_DEBUG
ff322e2000-06-10Martin Stjernholm  if (!a) fatal("Got null pointer.\n");
22aa2f2000-09-04Martin Stjernholm  if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)
e2d9e62000-06-10Martin Stjernholm  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"); }
ff322e2000-06-10Martin Stjernholm  else m = get_marker(a);
e2d9e62000-06-10Martin Stjernholm  debug_malloc_touch(a); if (m->weak_refs > m->refs) gc_fatal(a, 0, "More weak references than internal references.\n");
63709a2000-07-18Martin Stjernholm #else m = get_marker(a); #endif
e2d9e62000-06-10Martin Stjernholm 
45d87e2000-07-18Martin Stjernholm  if (Pike_in_gc != GC_PASS_ZAP_WEAK) {
2b8dde2000-09-15Martin Stjernholm  if (m->weak_refs < 0) goto should_free;
6d30f52000-07-11Martin Stjernholm  } else if (!(m->flags & GC_MARKED)) {
63709a2000-07-18Martin Stjernholm #ifdef PIKE_DEBUG
6d30f52000-07-11Martin Stjernholm  if (m->weak_refs <= 0) gc_fatal(a, 0, "Too many weak refs cleared to thing with external " "weak refs.\n");
63709a2000-07-18Martin Stjernholm #endif
6d30f52000-07-11Martin Stjernholm  m->weak_refs--;
2b8dde2000-09-15Martin Stjernholm  goto should_free;
6d30f52000-07-11Martin Stjernholm  } return 0;
2b8dde2000-09-15Martin Stjernholm  should_free: gc_ext_weak_refs--; #ifdef PIKE_DEBUG
1a12e82000-09-30Martin Stjernholm  m->saved_refs--;
2b8dde2000-09-15Martin Stjernholm  m->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; } return 1;
e2d9e62000-06-10Martin Stjernholm }
05c7cd1997-07-19Fredrik Hübinette (Hubbe) 
49bf8a2000-12-14Martin Stjernholm void gc_delayed_free(void *a) { struct marker *m; #ifdef PIKE_DEBUG if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE && Pike_in_gc != GC_PASS_ZAP_WEAK) 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) fatal("gc_delayed_free() called for thing that haven't got a single ref.\n"); if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED)) gc_fatal(a, 1, "gc_delayed_free() got a thing marked as referenced.\n"); debug_malloc_touch(a); #else m = get_marker(a); #endif gc_add_extra_ref(a); m->flags |= GC_GOT_DEAD_REF; }
c94c371996-03-28Fredrik Hübinette (Hubbe) int gc_mark(void *a) {
0816292000-07-03Martin Stjernholm  struct marker *m = get_marker(debug_malloc_pass(a));
c94c371996-03-28Fredrik Hübinette (Hubbe) 
87c7f92000-04-19Martin Stjernholm #ifdef PIKE_DEBUG
e2d9e62000-06-10Martin Stjernholm  if (!a) fatal("Got null pointer.\n");
45d87e2000-07-18Martin Stjernholm  if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)
7bf6232000-04-23Martin Stjernholm  fatal("gc mark attempted in invalid pass.\n");
0816292000-07-03Martin Stjernholm  if (!*(INT32 *) a) gc_fatal(a, 0, "Marked a thing without refs.\n");
10c4a42000-08-17Martin Stjernholm  if (m->weak_refs < 0)
6d30f52000-07-11Martin Stjernholm  gc_fatal(a, 0, "Marking thing scheduled for weak free.\n");
87c7f92000-04-19Martin Stjernholm #endif
1a12e82000-09-30Martin Stjernholm  if (Pike_in_gc == GC_PASS_ZAP_WEAK) {
45d87e2000-07-18Martin Stjernholm  /* 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 non-weak refs. */
1a12e82000-09-30Martin Stjernholm #ifdef PIKE_DEBUG if (!(m->flags & GC_MARKED)) gc_fatal(a, 0, "gc_mark() called for thing in zap weak pass " "that wasn't marked before.\n"); #endif
6d30f52000-07-11Martin Stjernholm  if (m->flags & GC_FREE_VISITED) return 0; else { m->flags |= GC_FREE_VISITED; return 1; }
1a12e82000-09-30Martin Stjernholm  }
6d30f52000-07-11Martin Stjernholm  else if (m->flags & GC_MARKED) { #ifdef PIKE_DEBUG if (m->weak_refs != 0) gc_fatal(a, 0, "weak_refs changed in marker already visited by gc_mark().\n"); #endif
c94c371996-03-28Fredrik Hübinette (Hubbe)  return 0;
6d30f52000-07-11Martin Stjernholm  } else { if (m->weak_refs) { gc_ext_weak_refs -= m->weak_refs; m->weak_refs = 0; }
0816292000-07-03Martin Stjernholm  m->flags = (m->flags & ~GC_NOT_REFERENCED) | GC_MARKED;
e2d9e62000-06-10Martin Stjernholm  DO_IF_DEBUG(marked++);
c94c371996-03-28Fredrik Hübinette (Hubbe)  return 1; } }
fa8c692000-11-30Fredrik Hübinette (Hubbe) PMOD_EXPORT void gc_cycle_enqueue(gc_cycle_check_cb *checkfn, void *data, int weak)
45d87e2000-07-18Martin Stjernholm { struct gc_frame *l = alloc_gc_frame();
1a12e82000-09-30Martin Stjernholm #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
45d87e2000-07-18Martin Stjernholm #ifdef GC_VERBOSE if (++num_gc_frames > max_gc_frames) max_gc_frames = num_gc_frames; #endif l->data = data; l->u.link.checkfn = checkfn; l->u.link.weak = weak; l->frameflags = 0; l->back = gc_rec_top; #ifdef GC_STACK_DEBUG fprintf(stderr, "enqueue %p [%p]: ", l, gc_rec_top); describe_gc_frame(l); fputc('\n', stderr); #endif gc_rec_top = l; } static struct gc_frame *gc_cycle_enqueue_pop(void *data) { struct gc_frame *l = alloc_gc_frame();
1a12e82000-09-30Martin Stjernholm #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
45d87e2000-07-18Martin Stjernholm #ifdef GC_VERBOSE if (++num_gc_frames > max_gc_frames) max_gc_frames = num_gc_frames; #endif l->data = data; PREV(l) = gc_rec_last; NEXT(l) = 0; CYCLE(l) = 0; l->frameflags = GC_POP_FRAME; l->back = gc_rec_top; #ifdef GC_STACK_DEBUG fprintf(stderr, "enqueue %p [%p]: ", l, gc_rec_top); describe_gc_frame(l); fputc('\n', stderr); #endif gc_rec_top = l; return l; } void gc_cycle_run_queue() {
1a12e82000-09-30Martin Stjernholm #ifdef PIKE_DEBUG if (Pike_in_gc != GC_PASS_CYCLE) fatal("Use of the gc frame stack outside the cycle check pass.\n"); #endif
45d87e2000-07-18Martin Stjernholm  while (gc_rec_top) { #ifdef GC_STACK_DEBUG fprintf(stderr, "dequeue %p [%p]: ", gc_rec_top, gc_rec_top->back); describe_gc_frame(gc_rec_top); fputc('\n', stderr); #endif if (gc_rec_top->frameflags & GC_POP_FRAME) { struct gc_frame *l = gc_rec_top->back; gc_cycle_pop(gc_rec_top->data); gc_rec_top = l; } else { struct gc_frame l = *gc_rec_top; #ifdef PIKE_DEBUG if (l.frameflags & GC_LINK_FREED) gc_fatal(l.data, 0, "Accessing freed gc_frame.\n"); #endif debug_really_free_gc_frame(gc_rec_top); gc_rec_top = l.back; l.u.link.checkfn(l.data, l.u.link.weak); } } }
e2d9e62000-06-10Martin Stjernholm #ifdef GC_CYCLE_DEBUG static int gc_cycle_indent = 0;
996f872000-06-12Martin Stjernholm #define CYCLE_DEBUG_MSG(M, TXT) do { \
45d87e2000-07-18Martin Stjernholm  fprintf(stderr, "%*s%-35s %p [%p] ", gc_cycle_indent, "", \
af72c52000-07-02Martin Stjernholm  (TXT), (M) ? (M)->data : 0, gc_rec_last->data); \
996f872000-06-12Martin Stjernholm  describe_marker(M); \ } while (0) #else #define CYCLE_DEBUG_MSG(M, TXT) do {} while (0)
e2d9e62000-06-10Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm static void rotate_rec_list (struct gc_frame *beg, struct gc_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. */
e2d9e62000-06-10Martin Stjernholm {
45d87e2000-07-18Martin Stjernholm  struct gc_frame *l;
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG
1a12e82000-09-30Martin Stjernholm  if (Pike_in_gc != GC_PASS_CYCLE) fatal("Use of the gc frame stack outside the cycle check pass.\n");
45d87e2000-07-18Martin Stjernholm  CHECK_POP_FRAME(beg); CHECK_POP_FRAME(pos);
e2d9e62000-06-10Martin Stjernholm  if (beg == pos) gc_fatal(beg->data, 0, "Cycle already broken at requested position.\n");
45d87e2000-07-18Martin Stjernholm  if (NEXT(gc_rec_last)) gc_fatal(gc_rec_last->data, 0, "gc_rec_last not at end.\n");
e2d9e62000-06-10Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm #ifdef GC_STACK_DEBUG fprintf(stderr,"Stack before:\n"); for (l = gc_rec_top; l; l = l->back) { fprintf(stderr, " %p ", l); describe_gc_frame(l); fputc('\n', stderr); } #endif if (CYCLE(beg)) { for (l = beg; CYCLE(PREV(l)) == CYCLE(beg); l = PREV(l)) CHECK_POP_FRAME(l); CHECK_POP_FRAME(l); if (CYCLE(l) == CYCLE(pos)) {
af72c52000-07-02Martin Stjernholm  /* Breaking something previously marked as a cycle. Clear it * since we're no longer sure it's an ambigious cycle. */
45d87e2000-07-18Martin Stjernholm  unsigned cycle = CYCLE(l); for (; l && CYCLE(l) == cycle; l = NEXT(l)) { CHECK_POP_FRAME(l); #ifdef GC_CYCLE_DEBUG if (CYCLE(l)) CYCLE_DEBUG_MSG(find_marker(l->data), "> rotate_rec_list, clear cycle"); #endif CYCLE(l) = 0; }
af72c52000-07-02Martin Stjernholm  }
45d87e2000-07-18Martin Stjernholm  else beg = l; /* Keep the cycle continuous. */
e2d9e62000-06-10Martin Stjernholm  }
45d87e2000-07-18Martin Stjernholm  CYCLE_DEBUG_MSG(find_marker(beg->data), "> rotate_rec_list, begin at");
46d4e72000-06-12Martin Stjernholm 
45d87e2000-07-18Martin Stjernholm  { struct gc_frame *b = beg, *p = pos, *old_rec_top; while (b->frameflags & GC_OFF_STACK) { if ((b = NEXT(b)) == pos) goto done; CHECK_POP_FRAME(b); } while (p->frameflags & GC_OFF_STACK) { if (!(p = NEXT(p))) goto done; CHECK_POP_FRAME(p); } old_rec_top = gc_rec_top; gc_rec_top = p->back; p->back = b->back; b->back = old_rec_top;
996f872000-06-12Martin Stjernholm  }
45d87e2000-07-18Martin Stjernholm done:
996f872000-06-12Martin Stjernholm  {
45d87e2000-07-18Martin Stjernholm  struct gc_frame *new_rec_last = PREV(pos); NEXT(PREV(beg)) = pos; PREV(pos) = PREV(beg); NEXT(gc_rec_last) = beg; PREV(beg) = gc_rec_last; gc_rec_last = new_rec_last; NEXT(gc_rec_last) = 0;
e2d9e62000-06-10Martin Stjernholm  }
af72c52000-07-02Martin Stjernholm 
45d87e2000-07-18Martin Stjernholm  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");
af72c52000-07-02Martin Stjernholm  }
45d87e2000-07-18Martin Stjernholm #ifdef GC_STACK_DEBUG fprintf(stderr,"Stack after:\n"); for (l = gc_rec_top; l; l = l->back) { fprintf(stderr, " %p ", l); describe_gc_frame(l); fputc('\n', stderr); } #endif
e2d9e62000-06-10Martin Stjernholm } int gc_cycle_push(void *x, struct marker *m, int weak)
c94c371996-03-28Fredrik Hübinette (Hubbe) {
45d87e2000-07-18Martin Stjernholm  struct marker *last = find_marker(gc_rec_last->data);
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG if (!x) fatal("Got null pointer.\n"); if (m->data != x) fatal("Got wrong marker.\n"); if (Pike_in_gc != GC_PASS_CYCLE) fatal("GC cycle push attempted in invalid pass.\n");
22aa2f2000-09-04Martin Stjernholm  if (gc_debug && !(m->flags & GC_PRETOUCHED))
e2d9e62000-06-10Martin Stjernholm  gc_fatal(x, 0, "gc_cycle_push() called for untouched thing.\n");
0816292000-07-03Martin Stjernholm  if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) && *(INT32 *) x)
e2d9e62000-06-10Martin Stjernholm  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 (gc_debug) { struct array *a; struct object *o; struct program *p; struct mapping *m; struct multiset *l; for(a = gc_internal_array; a != &empty_array; a = a->next) if(a == (struct array *) x) goto on_gc_internal_lists; for(o = gc_internal_object; o; o = o->next) if(o == (struct object *) x) goto on_gc_internal_lists; for(p = gc_internal_program; p; p = p->next) if(p == (struct program *) x) goto on_gc_internal_lists; 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:
1f3b782000-06-16Fredrik Hübinette (Hubbe)  ; /* We must have a least one expression after a label! - Hubbe */
e2d9e62000-06-10Martin Stjernholm  } #endif
11649a2000-04-14Henrik Grubbström (Grubba) 
45d87e2000-07-18Martin Stjernholm  if (last->flags & GC_LIVE_RECURSE) {
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG
45d87e2000-07-18Martin Stjernholm  if (!(last->flags & GC_LIVE))
e2d9e62000-06-10Martin Stjernholm  gc_fatal(x, 0, "Doing live recursion from a dead thing.\n"); #endif
1637c42000-02-01Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm  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; }
996f872000-06-12Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_push, no live recurse");
e2d9e62000-06-10Martin Stjernholm  } else { /* Nothing more to do. Unwind the live recursion. */ int flags;
996f872000-06-12Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_push, live rec done");
e2d9e62000-06-10Martin Stjernholm  do {
45d87e2000-07-18Martin Stjernholm  last->flags &= ~GC_LIVE_RECURSE;
e2d9e62000-06-10Martin Stjernholm #ifdef GC_CYCLE_DEBUG gc_cycle_indent -= 2;
45d87e2000-07-18Martin Stjernholm  CYCLE_DEBUG_MSG(find_marker(gc_rec_last->data), "> gc_cycle_push, unwinding live");
e2d9e62000-06-10Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm  while (1) { struct gc_frame *l = gc_rec_top;
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG
45d87e2000-07-18Martin Stjernholm  if (!gc_rec_top) fatal("Expected a gc_cycle_pop entry in gc_rec_top.\n");
e2d9e62000-06-10Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm  gc_rec_top = l->back; if (l->frameflags & GC_POP_FRAME) { gc_rec_last = PREV(l); debug_really_free_gc_frame(l); break; } debug_really_free_gc_frame(l); } last = find_marker(gc_rec_last->data); } while (last->flags & GC_LIVE_RECURSE);
e2d9e62000-06-10Martin Stjernholm  } return 0; }
a595b92000-06-11Martin Stjernholm #ifdef PIKE_DEBUG
45d87e2000-07-18Martin Stjernholm  if (weak < 0 && gc_rec_last->frameflags & GC_FOLLOWED_NONSTRONG) gc_fatal(x, 0, "Followed strong link too late.\n"); if (weak >= 0) gc_rec_last->frameflags |= GC_FOLLOWED_NONSTRONG;
a595b92000-06-11Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm  if (m->frame && !(m->frame->frameflags & GC_OFF_STACK)) { /* A cyclic reference is found. */
9326332000-06-12Martin Stjernholm #ifdef PIKE_DEBUG
45d87e2000-07-18Martin Stjernholm  if (gc_rec_last == &rec_list)
9326332000-06-12Martin Stjernholm  gc_fatal(x, 0, "Cyclic ref involves dummy rec_list marker.\n");
45d87e2000-07-18Martin Stjernholm  CHECK_POP_FRAME(gc_rec_last); CHECK_POP_FRAME(m->frame);
9326332000-06-12Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm  if (m != last) { struct gc_frame *p, *weak_ref = 0, *nonstrong_ref = 0;
e2d9e62000-06-10Martin Stjernholm  if (!weak) {
45d87e2000-07-18Martin Stjernholm  struct gc_frame *q;
af72c52000-07-02Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_push, search normal");
45d87e2000-07-18Martin Stjernholm  for (q = m->frame, p = NEXT(q);; q = p, p = NEXT(p)) { CHECK_POP_FRAME(p); if (p->frameflags & (GC_WEAK_REF|GC_STRONG_REF)) { if (p->frameflags & GC_WEAK_REF) weak_ref = p;
e2d9e62000-06-10Martin Stjernholm  else if (!nonstrong_ref) nonstrong_ref = q; } if (p == gc_rec_last) break; } } else if (weak < 0) {
af72c52000-07-02Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_push, search strong");
45d87e2000-07-18Martin Stjernholm  for (p = NEXT(m->frame);; p = NEXT(p)) { CHECK_POP_FRAME(p); if (p->frameflags & GC_WEAK_REF) weak_ref = p; if (!(p->frameflags & GC_STRONG_REF)) nonstrong_ref = p;
e2d9e62000-06-10Martin Stjernholm  if (p == gc_rec_last) break; } #ifdef PIKE_DEBUG
af72c52000-07-02Martin Stjernholm  if (p == gc_rec_last && !nonstrong_ref)
e2d9e62000-06-10Martin Stjernholm  gc_fatal(x, 0, "Only strong links in cycle.\n"); #endif } else {
45d87e2000-07-18Martin Stjernholm  struct gc_frame *q;
af72c52000-07-02Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_push, search weak");
45d87e2000-07-18Martin Stjernholm  for (q = m->frame, p = NEXT(q);; q = p, p = NEXT(p)) { CHECK_POP_FRAME(p); if (!(p->frameflags & GC_WEAK_REF) && !nonstrong_ref) nonstrong_ref = q;
e2d9e62000-06-10Martin Stjernholm  if (p == gc_rec_last) break; } }
45d87e2000-07-18Martin Stjernholm  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); }
e2d9e62000-06-10Martin Stjernholm 
45d87e2000-07-18Martin Stjernholm  else if (weak < 0) { /* The backward link is strong. Must break the cycle at the * last nonstrong link. */ if (m->frame->frameflags & GC_STRONG_REF) nonstrong_ref->frameflags = (nonstrong_ref->frameflags & ~GC_WEAK_REF) | GC_STRONG_REF; else m->frame->frameflags = (m->frame->frameflags & ~GC_WEAK_REF) | GC_STRONG_REF; CYCLE_DEBUG_MSG(find_marker(nonstrong_ref->data), "gc_cycle_push, nonstrong break"); rotate_rec_list(m->frame, nonstrong_ref); }
e2d9e62000-06-10Martin Stjernholm 
45d87e2000-07-18Martin Stjernholm  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);
46d4e72000-06-12Martin Stjernholm  }
af72c52000-07-02Martin Stjernholm  }
45d87e2000-07-18Martin Stjernholm  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 = CYCLE(m->frame) ? CYCLE(m->frame) : ++last_cycle; if (cycle == CYCLE(gc_rec_last)) CYCLE_DEBUG_MSG(m, "gc_cycle_push, old cycle"); else { CYCLE_DEBUG_MSG(m, "gc_cycle_push, cycle"); for (p = m->frame;; p = NEXT(p)) { CYCLE(p) = cycle; CYCLE_DEBUG_MSG(find_marker(p->data), "> gc_cycle_push, mark cycle"); if (p == gc_rec_last) break; }}}}} /* Mmm.. lisp ;) */
e2d9e62000-06-10Martin Stjernholm  else if (!(m->flags & GC_CYCLE_CHECKED)) {
45d87e2000-07-18Martin Stjernholm  struct gc_frame *l, *prev_rec_last = gc_rec_last;
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG cycle_checked++;
45d87e2000-07-18Martin Stjernholm  if (m->frame) gc_fatal(x, 0, "Marker already got a frame.\n"); if (NEXT(gc_rec_last)) gc_fatal(gc_rec_last->data, 0, "Not at end of list.\n");
e2d9e62000-06-10Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm  NEXT(gc_rec_last) = m->frame = l = gc_cycle_enqueue_pop(x); m->flags |= GC_CYCLE_CHECKED | (last->flags & GC_LIVE); if (weak) { if (weak > 0) l->frameflags |= GC_WEAK_REF; else l->frameflags |= GC_STRONG_REF; }
e2d9e62000-06-10Martin Stjernholm  #ifdef GC_CYCLE_DEBUG
996f872000-06-12Martin Stjernholm  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");
e2d9e62000-06-10Martin Stjernholm  gc_cycle_indent += 2; #endif
45d87e2000-07-18Martin Stjernholm  gc_rec_last = l;
e2d9e62000-06-10Martin Stjernholm  return 1; } /* Should normally not recurse now, but got to do that anyway if we * must mark live things. */
45d87e2000-07-18Martin Stjernholm  if (!(last->flags & GC_LIVE) || m->flags & GC_LIVE) {
996f872000-06-12Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_push, no recurse");
e2d9e62000-06-10Martin Stjernholm  return 0; } live_recurse: #ifdef PIKE_DEBUG if (m->flags & GC_LIVE) fatal("Shouldn't live recurse when there's nothing to do.\n"); #endif m->flags |= GC_LIVE|GC_LIVE_RECURSE; if (m->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(x); if (!--*(INT32 *) x) { #ifdef PIKE_DEBUG gc_fatal(x, 0, "Thing got zero refs after removing the dead gc ref.\n"); #endif } }
45d87e2000-07-18Martin Stjernholm  { /* Recurse without linking onto rec_list. */ struct gc_frame *l = gc_cycle_enqueue_pop(x);
e2d9e62000-06-10Martin Stjernholm #ifdef GC_CYCLE_DEBUG
45d87e2000-07-18Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_push, live recurse"); gc_cycle_indent += 2;
e2d9e62000-06-10Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm  gc_rec_last = l; }
e2d9e62000-06-10Martin Stjernholm  return 1; }
45d87e2000-07-18Martin Stjernholm static void gc_cycle_pop(void *a)
e2d9e62000-06-10Martin Stjernholm {
45d87e2000-07-18Martin Stjernholm  struct marker *m = find_marker(a); struct gc_frame *here, *base, *p;
e2d9e62000-06-10Martin Stjernholm  #ifdef PIKE_DEBUG
45d87e2000-07-18Martin Stjernholm  if (!a) fatal("Got null pointer.\n");
e2d9e62000-06-10Martin Stjernholm  if (Pike_in_gc != GC_PASS_CYCLE) fatal("GC cycle pop attempted in invalid pass.\n"); if (!(m->flags & GC_CYCLE_CHECKED)) gc_fatal(a, 0, "Marker being popped doesn't have GC_CYCLE_CHECKED.\n");
0816292000-07-03Martin Stjernholm  if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) && *(INT32 *) a)
e2d9e62000-06-10Martin Stjernholm  gc_fatal(a, 1, "Got a referenced marker to gc_cycle_pop.\n"); if (m->flags & GC_XREFERENCED) gc_fatal(a, 1, "Doing cycle check in externally referenced thing " "missed in mark pass.\n"); #endif #ifdef GC_CYCLE_DEBUG gc_cycle_indent -= 2; #endif
46d4e72000-06-12Martin Stjernholm  if (m->flags & GC_LIVE_RECURSE) {
e2d9e62000-06-10Martin Stjernholm  m->flags &= ~GC_LIVE_RECURSE;
45d87e2000-07-18Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_pop_live"); gc_rec_last = PREV(gc_rec_top); debug_really_free_gc_frame(gc_rec_top);
996f872000-06-12Martin Stjernholm  return;
e2d9e62000-06-10Martin Stjernholm  }
45d87e2000-07-18Martin Stjernholm  here = m->frame;
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG
45d87e2000-07-18Martin Stjernholm  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(gc_rec_last); if (here->frameflags & GC_OFF_STACK)
46d4e72000-06-12Martin Stjernholm  gc_fatal(a, 0, "Marker being popped isn't on stack.\n");
a609812000-08-03Henrik Grubbström (Grubba)  here->back = (struct gc_frame *)(ptrdiff_t) -1;
9326332000-06-12Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm  here->frameflags |= GC_OFF_STACK;
e2d9e62000-06-10Martin Stjernholm 
45d87e2000-07-18Martin Stjernholm  for (base = PREV(here), p = here;; base = p, p = NEXT(p)) { if (base == here) { /* Part of a cycle; wait until the cycle is complete before * unlinking it from rec_list. */
a609812000-08-03Henrik Grubbström (Grubba)  DO_IF_DEBUG(m->frame->back = (struct gc_frame *)(ptrdiff_t) -1);
af72c52000-07-02Martin Stjernholm  CYCLE_DEBUG_MSG(m, "gc_cycle_pop, keep cycle"); return; }
45d87e2000-07-18Martin Stjernholm  CHECK_POP_FRAME(p); if (!(CYCLE(p) && CYCLE(p) == CYCLE(base)))
af72c52000-07-02Martin Stjernholm  break; }
45d87e2000-07-18Martin Stjernholm  gc_rec_last = base; while ((p = NEXT(base))) { struct marker *pm = find_marker(p->data);
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG
45d87e2000-07-18Martin Stjernholm  if (pm->frame != p) gc_fatal(p->data, 0, "Bogus marker for thing being popped.\n");
e2d9e62000-06-10Martin Stjernholm #endif
45d87e2000-07-18Martin Stjernholm  p->frameflags &= ~(GC_WEAK_REF|GC_STRONG_REF); if (pm->flags & GC_LIVE_OBJ) {
2b8dde2000-09-15Martin Stjernholm  /* 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);
45d87e2000-07-18Martin Stjernholm  base = p;
a609812000-08-03Henrik Grubbström (Grubba)  DO_IF_DEBUG(PREV(p) = (struct gc_frame *)(ptrdiff_t) -1);
45d87e2000-07-18Martin Stjernholm  CYCLE_DEBUG_MSG(pm, "gc_cycle_pop, put on kill list");
e2d9e62000-06-10Martin Stjernholm  }
45d87e2000-07-18Martin Stjernholm  else { if (!(pm->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. */
2b8dde2000-09-15Martin Stjernholm  if (!(pm->flags & GC_GOT_DEAD_REF)) { gc_add_extra_ref(pm->data); pm->flags |= GC_GOT_DEAD_REF; } }
996f872000-06-12Martin Stjernholm #ifdef PIKE_DEBUG
2b8dde2000-09-15Martin Stjernholm  else
45d87e2000-07-18Martin Stjernholm  if (pm->flags & GC_GOT_DEAD_REF)
2b8dde2000-09-15Martin Stjernholm  gc_fatal(p->data, 0, "Didn't expect a dead extra ref.\n");
45d87e2000-07-18Martin Stjernholm #endif NEXT(base) = NEXT(p); CYCLE_DEBUG_MSG(pm, "gc_cycle_pop, pop off"); pm->frame = 0; debug_really_free_gc_frame(p);
996f872000-06-12Martin Stjernholm  }
8fb1e11998-04-05Fredrik Hübinette (Hubbe)  }
e2d9e62000-06-10Martin Stjernholm 
45d87e2000-07-18Martin Stjernholm  if (base != gc_rec_last) { NEXT(base) = kill_list; kill_list = NEXT(gc_rec_last); NEXT(gc_rec_last) = 0; }
e2d9e62000-06-10Martin Stjernholm } void do_gc_recurse_svalues(struct svalue *s, int num) { gc_recurse_svalues(s, num); }
1637c42000-02-01Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm void do_gc_recurse_short_svalue(union anything *u, TYPE_T type) { gc_recurse_short_svalue(u, type);
c94c371996-03-28Fredrik Hübinette (Hubbe) }
e2d9e62000-06-10Martin Stjernholm  int gc_do_free(void *a) { struct marker *m; #ifdef PIKE_DEBUG if (!a) fatal("Got null pointer.\n"); if (Pike_in_gc != GC_PASS_FREE) 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. */ #ifdef PIKE_DEBUG
0816292000-07-03Martin Stjernholm  if (*(INT32 *) a > !!(m->flags & GC_GOT_EXTRA_REF)) { if (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) gc_fatal(a, 0, "gc_do_free() called for referenced thing.\n"); if (gc_debug &&
22aa2f2000-09-04Martin Stjernholm  (m->flags & (GC_PRETOUCHED|GC_MARKED|GC_IS_REFERENCED)) == GC_PRETOUCHED)
0816292000-07-03Martin Stjernholm  gc_fatal(a, 0, "gc_do_free() called without prior call to " "gc_mark() or gc_is_referenced().\n"); }
be39f52000-07-03Martin Stjernholm  if((m->flags & (GC_MARKED|GC_XREFERENCED)) == GC_XREFERENCED) gc_fatal(a, 1, "Thing with external reference missed in gc mark pass.\n");
e2d9e62000-06-10Martin Stjernholm  if ((m->flags & (GC_DO_FREE|GC_LIVE)) == GC_LIVE) live_ref++; m->flags |= GC_DO_FREE;
1637c42000-02-01Fredrik Hübinette (Hubbe) #endif
c94c371996-03-28Fredrik Hübinette (Hubbe) 
0816292000-07-03Martin Stjernholm  return !(m->flags & GC_LIVE);
e2d9e62000-06-10Martin Stjernholm }
66ac542000-09-05Henrik Grubbström (Grubba) static void free_obj_arr(void *oa) { struct array *obj_arr = *((struct array **)oa); if (obj_arr) free_array(obj_arr); free(oa); }
e2d9e62000-06-10Martin Stjernholm static void warn_bad_cycles() {
66ac542000-09-05Henrik Grubbström (Grubba)  /* The reason for the extra level of indirection, is that it might * be clobbered by the longjump() in SET_ONERROR otherwise. * (On some architectures longjump() might restore obj_arr's original * value (eg if obj_arr is in a register)). */ struct array **obj_arr_ = (struct array **)xalloc(sizeof(struct array *)); ONERROR tmp; *obj_arr_ = NULL; SET_ONERROR(tmp, free_obj_arr, obj_arr_);
d70a3e2000-07-07Martin Stjernholm 
66ac542000-09-05Henrik Grubbström (Grubba)  {
45d87e2000-07-18Martin Stjernholm  struct gc_frame *p;
e2d9e62000-06-10Martin Stjernholm  unsigned cycle = 0;
66ac542000-09-05Henrik Grubbström (Grubba)  *obj_arr_ = allocate_array(0);
4be85a2000-07-07Martin Stjernholm 
e2d9e62000-06-10Martin Stjernholm  for (p = kill_list; p;) {
45d87e2000-07-18Martin Stjernholm  if ((cycle = CYCLE(p))) {
e2d9e62000-06-10Martin Stjernholm  push_object((struct object *) p->data);
66ac542000-09-05Henrik Grubbström (Grubba)  *obj_arr_ = append_array(*obj_arr_, --sp);
e2d9e62000-06-10Martin Stjernholm  }
45d87e2000-07-18Martin Stjernholm  p = NEXT(p);
7e8ea32000-08-13Henrik Grubbström (Grubba)  if (p ? ((unsigned)(CYCLE(p) != cycle)) : cycle) {
66ac542000-09-05Henrik Grubbström (Grubba)  if ((*obj_arr_)->size >= 2) {
e2d9e62000-06-10Martin Stjernholm  push_constant_text("gc"); push_constant_text("bad_cycle");
66ac542000-09-05Henrik Grubbström (Grubba)  push_array(*obj_arr_); *obj_arr_ = 0;
e2d9e62000-06-10Martin Stjernholm  SAFE_APPLY_MASTER("runtime_warning", 3); pop_stack();
66ac542000-09-05Henrik Grubbström (Grubba)  *obj_arr_ = allocate_array(0);
e2d9e62000-06-10Martin Stjernholm  }
66ac542000-09-05Henrik Grubbström (Grubba)  else *obj_arr_ = resize_array(*obj_arr_, 0);
e2d9e62000-06-10Martin Stjernholm  } if (!p) break; } }
d70a3e2000-07-07Martin Stjernholm 
66ac542000-09-05Henrik Grubbström (Grubba)  CALL_AND_UNSET_ONERROR(tmp);
e2d9e62000-06-10Martin Stjernholm } int do_gc(void)
6930181996-02-25Fredrik Hübinette (Hubbe) { double tmp;
e2d9e62000-06-10Martin Stjernholm  int objs, pre_kill_objs;
dc296b1997-10-21Fredrik Hübinette (Hubbe)  double multiplier;
e2d9e62000-06-10Martin Stjernholm  struct array *a; struct multiset *l; struct mapping *m; struct program *p; struct object *o;
db62dc2000-04-14Martin Stjernholm #ifdef PIKE_DEBUG
e2d9e62000-06-10Martin Stjernholm #ifdef HAVE_GETHRTIME
48f1c62000-07-04Henrik Grubbström (Grubba)  hrtime_t gcstarttime = 0;
b088ab2000-04-15Martin Stjernholm #endif
e2d9e62000-06-10Martin Stjernholm  unsigned destroy_count, obj_count;
db62dc2000-04-14Martin Stjernholm #endif
6930181996-02-25Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm  if(Pike_in_gc) return 0;
7bf6232000-04-23Martin Stjernholm  init_gc(); Pike_in_gc=GC_PASS_PREPARE; #ifdef PIKE_DEBUG gc_debug = d_flag; #endif
890e5b1996-11-21Fredrik Hübinette (Hubbe) 
7f9b4c2000-04-19Martin Stjernholm  destruct_objects_to_destruct();
e78abd1996-11-21Fredrik Hübinette (Hubbe)  if(gc_evaluator_callback) { remove_callback(gc_evaluator_callback); gc_evaluator_callback=0; }
890e5b1996-11-21Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm  objs=num_objects; last_cycle = 0;
6930181996-02-25Fredrik Hübinette (Hubbe) 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
e2d9e62000-06-10Martin Stjernholm  if(GC_VERBOSE_DO(1 ||) t_flag) {
6930181996-02-25Fredrik Hübinette (Hubbe)  fprintf(stderr,"Garbage collecting ... ");
e2d9e62000-06-10Martin Stjernholm  GC_VERBOSE_DO(fprintf(stderr, "\n"));
b088ab2000-04-15Martin Stjernholm #ifdef HAVE_GETHRTIME
6bc62b2000-04-14Martin Stjernholm  gcstarttime = gethrtime();
b088ab2000-04-15Martin Stjernholm #endif
6bc62b2000-04-14Martin Stjernholm  }
06983f1996-09-22Fredrik Hübinette (Hubbe)  if(num_objects < 0) fatal("Panic, less than zero objects!\n");
6930181996-02-25Fredrik Hübinette (Hubbe) #endif
4452c12000-02-02Fredrik Hübinette (Hubbe)  last_gc=TIME(0);
dc296b1997-10-21Fredrik Hübinette (Hubbe)  multiplier=pow(MULTIPLIER, (double) num_allocs / (double) alloc_threshold); objects_alloced*=multiplier;
6930181996-02-25Fredrik Hübinette (Hubbe)  objects_alloced += (double) num_allocs;
dc296b1997-10-21Fredrik Hübinette (Hubbe)  objects_freed*=multiplier;
c94c371996-03-28Fredrik Hübinette (Hubbe) 
1a12e82000-09-30Martin Stjernholm  /* Thread switches, object alloc/free and any reference changes are * disallowed now. */
08679c2000-04-26Martin Stjernholm 
7bf6232000-04-23Martin Stjernholm #ifdef PIKE_DEBUG
e2d9e62000-06-10Martin Stjernholm  weak_freed = checked = marked = cycle_checked = live_ref = 0;
7bf6232000-04-23Martin Stjernholm  if (gc_debug) {
e2d9e62000-06-10Martin Stjernholm  unsigned n;
7bf6232000-04-23Martin Stjernholm  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();
22aa2f2000-09-04Martin Stjernholm  gc_touch_all_strings();
e2d9e62000-06-10Martin Stjernholm  if (n != (unsigned) num_objects)
7bf6232000-04-23Martin Stjernholm  fatal("Object count wrong before gc; expected %d, got %d.\n", num_objects, n);
e2d9e62000-06-10Martin Stjernholm  GC_VERBOSE_DO(fprintf(stderr, "| pretouch: %u things\n", n));
7bf6232000-04-23Martin Stjernholm  } #endif
c94c371996-03-28Fredrik Hübinette (Hubbe) 
7bf6232000-04-23Martin Stjernholm  Pike_in_gc=GC_PASS_CHECK;
6d30f52000-07-11Martin Stjernholm  gc_ext_weak_refs = 0;
a991451997-07-08Fredrik Hübinette (Hubbe)  /* First we count internal references */
6930181996-02-25Fredrik Hübinette (Hubbe)  gc_check_all_arrays();
06983f1996-09-22Fredrik Hübinette (Hubbe)  gc_check_all_multisets();
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_check_all_mappings();
6930181996-02-25Fredrik Hübinette (Hubbe)  gc_check_all_programs(); gc_check_all_objects();
20513c2000-04-12Fredrik Hübinette (Hubbe)  #ifdef PIKE_DEBUG
48f1c62000-07-04Henrik Grubbström (Grubba)  if(master_object) gc_external_mark2(master_object,0," &master_object");
5f61da2000-04-13Fredrik Hübinette (Hubbe)  { extern struct mapping *builtin_constants; if(builtin_constants) gc_external_mark2(builtin_constants,0," &builtin_constants"); }
20513c2000-04-12Fredrik Hübinette (Hubbe) #endif
7bf6232000-04-23Martin Stjernholm  /* These callbacks are mainly for the check pass, but can also * do things that are normally associated with the mark pass
5fbe6e2000-04-14Fredrik Hübinette (Hubbe)  */
4a578f1997-01-27Fredrik Hübinette (Hubbe)  call_callback(& gc_callbacks, (void *)0);
c94c371996-03-28Fredrik Hübinette (Hubbe) 
1a12e82000-09-30Martin Stjernholm  GC_VERBOSE_DO(fprintf(stderr, "| check: %u references checked, counted %lu weak refs\n", checked, SIZE_T_TO_ULONG(gc_ext_weak_refs)));
e2d9e62000-06-10Martin Stjernholm 
7bf6232000-04-23Martin Stjernholm  Pike_in_gc=GC_PASS_MARK;
e2d9e62000-06-10Martin Stjernholm 
49bf8a2000-12-14Martin Stjernholm  /* Anything after and including gc_internal_* in the linked lists
e2d9e62000-06-10Martin Stjernholm  * are considered to lack external references. The mark pass move * externally referenced things in front of these pointers. */ gc_internal_array = empty_array.next; gc_internal_multiset = first_multiset; gc_internal_mapping = first_mapping; gc_internal_program = first_program; gc_internal_object = first_object;
1a12e82000-09-30Martin Stjernholm  /* Next we mark anything with external references. Note that we can * follow the same reference several times, e.g. with shared mapping * data blocks. */
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_mark_all_arrays();
991e5a1998-04-28Fredrik Hübinette (Hubbe)  run_queue(&gc_mark_queue);
06983f1996-09-22Fredrik Hübinette (Hubbe)  gc_mark_all_multisets();
991e5a1998-04-28Fredrik Hübinette (Hubbe)  run_queue(&gc_mark_queue);
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_mark_all_mappings();
991e5a1998-04-28Fredrik Hübinette (Hubbe)  run_queue(&gc_mark_queue);
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_mark_all_programs();
991e5a1998-04-28Fredrik Hübinette (Hubbe)  run_queue(&gc_mark_queue);
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_mark_all_objects();
991e5a1998-04-28Fredrik Hübinette (Hubbe)  run_queue(&gc_mark_queue);
03f0982000-09-04Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
22aa2f2000-09-04Martin Stjernholm  if(gc_debug) gc_mark_all_strings();
03f0982000-09-04Henrik Grubbström (Grubba) #endif /* PIKE_DEBUG */
e2d9e62000-06-10Martin Stjernholm  GC_VERBOSE_DO(fprintf(stderr,
1a12e82000-09-30Martin Stjernholm  "| mark: %u markers referenced, %u weak references freed,\n" "| %d things really freed, got %lu tricky weak refs\n", marked, weak_freed, objs - num_objects, SIZE_T_TO_ULONG(gc_ext_weak_refs)));
c94c371996-03-28Fredrik Hübinette (Hubbe) 
1a12e82000-09-30Martin Stjernholm  {
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG
1a12e82000-09-30Martin Stjernholm  size_t orig_ext_weak_refs = gc_ext_weak_refs; obj_count = num_objects; max_gc_frames = 0; #endif Pike_in_gc=GC_PASS_CYCLE; /* Now find all cycles in the internal structures. Note that we can * follow the same reference several times, just like in the mark * pass. */ /* 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();
08679c2000-04-26Martin Stjernholm 
20513c2000-04-12Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
1a12e82000-09-30Martin Stjernholm  if (gc_rec_top) fatal("gc_rec_top not empty at end of cycle check pass.\n"); if (NEXT(&rec_list) || gc_rec_last != &rec_list || gc_rec_top) fatal("Recurse list not empty or inconsistent after cycle check pass.\n"); if (gc_ext_weak_refs != orig_ext_weak_refs) fatal("gc_ext_weak_refs changed from %lu to %lu in cycle check pass.\n", SIZE_T_TO_ULONG(orig_ext_weak_refs), SIZE_T_TO_ULONG(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 things really freed,\n" "| space for %u gc frames used\n", cycle_checked, last_cycle, weak_freed, obj_count - num_objects, max_gc_frames)); }
e2d9e62000-06-10Martin Stjernholm 
22aa2f2000-09-04Martin Stjernholm #ifdef PIKE_DEBUG if (gc_debug) { unsigned n; size_t i; struct marker *m; Pike_in_gc=GC_PASS_MIDDLETOUCH; 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(); gc_touch_all_strings(); if (n != (unsigned) num_objects) fatal("Object count wrong in gc; expected %d, got %d.\n", num_objects, n); get_marker(rec_list.data)->flags |= GC_MIDDLETOUCHED; #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); fprintf(stderr, "Describing thing for marker:\n"); describe(m->data); fatal("Fatal in garbage collector.\n"); } #endif GC_VERBOSE_DO(fprintf(stderr, "| middletouch\n")); } #endif
45d87e2000-07-18Martin Stjernholm  if (gc_ext_weak_refs) { size_t to_free = gc_ext_weak_refs; #ifdef PIKE_DEBUG obj_count = num_objects; #endif Pike_in_gc = GC_PASS_ZAP_WEAK; /* Zap weak references from external to internal things. That * doesn't occur very often; only when something have both * external weak refs and nonweak cyclic refs from internal * things. */
a332d02000-09-04Martin Stjernholm  gc_zap_ext_weak_refs_in_mappings();
1a12e82000-09-30Martin Stjernholm  gc_zap_ext_weak_refs_in_arrays(); /* Multisets handled as arrays. */ gc_zap_ext_weak_refs_in_objects(); gc_zap_ext_weak_refs_in_programs();
45d87e2000-07-18Martin Stjernholm  GC_VERBOSE_DO( fprintf(stderr,
1a12e82000-09-30Martin Stjernholm  "| zap weak: freed %ld external weak refs, %lu internal still around,\n" "| %d things really freed\n", PTRDIFF_T_TO_LONG(to_free - gc_ext_weak_refs), SIZE_T_TO_ULONG(gc_ext_weak_refs), obj_count - num_objects));
45d87e2000-07-18Martin Stjernholm  }
e2d9e62000-06-10Martin Stjernholm 
49bf8a2000-12-14Martin Stjernholm  /* Add an extra reference to the stuff gc_internal_* point to, so we * know they're still around when gc_free_all_unreferenced_* is * about to be called. */ if (gc_internal_array != &empty_array) add_ref(gc_internal_array); if (gc_internal_multiset) add_ref(gc_internal_multiset); if (gc_internal_mapping) add_ref(gc_internal_mapping); if (gc_internal_program) add_ref(gc_internal_program); if (gc_internal_object) add_ref(gc_internal_object);
e2d9e62000-06-10Martin Stjernholm  /* Thread switches, object alloc/free and reference changes are * allowed again now. */
7bf6232000-04-23Martin Stjernholm  Pike_in_gc=GC_PASS_FREE;
e2d9e62000-06-10Martin Stjernholm #ifdef PIKE_DEBUG weak_freed = 0; obj_count = num_objects; #endif
49bf8a2000-12-14Martin Stjernholm  /* Now we free the unused stuff. The extra refs to gc_internal_* * added above are removed just before the calls so we'll get the * correct relative positions in them. */ if (gc_internal_array != &empty_array) { FREE_AND_GET_REFERENCED(gc_internal_array, struct array, free_array); gc_free_all_unreferenced_arrays(); } if (gc_internal_multiset) { FREE_AND_GET_REFERENCED(gc_internal_multiset, struct multiset, free_multiset); gc_free_all_unreferenced_multisets(); } if (gc_internal_mapping) { FREE_AND_GET_REFERENCED(gc_internal_mapping, struct mapping, free_mapping); gc_free_all_unreferenced_mappings(); } if (gc_internal_program) { FREE_AND_GET_REFERENCED(gc_internal_program, struct program, free_program); gc_free_all_unreferenced_programs(); } if (gc_internal_object) { FREE_AND_GET_REFERENCED(gc_internal_object, struct object, free_object); gc_free_all_unreferenced_objects(); }
e2d9e62000-06-10Martin Stjernholm  GC_VERBOSE_DO(fprintf(stderr, "| free: %d really freed, %u left with live references\n", obj_count - num_objects, live_ref));
20513c2000-04-12Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
49bf8a2000-12-14Martin Stjernholm  gc_internal_array = (struct array *) (ptrdiff_t) -1; gc_internal_multiset = (struct multiset *) (ptrdiff_t) -1; gc_internal_mapping = (struct mapping *) (ptrdiff_t) -1; gc_internal_program = (struct program *) (ptrdiff_t) -1; gc_internal_object = (struct object *) (ptrdiff_t) -1;
57d4d32000-08-23Henrik Grubbström (Grubba)  if(fatal_after_gc) fatal("%s", fatal_after_gc);
20513c2000-04-12Fredrik Hübinette (Hubbe) #endif
10c4a42000-08-17Martin Stjernholm  /* Pike code may run again now. */
e2d9e62000-06-10Martin Stjernholm  Pike_in_gc=GC_PASS_KILL; /* Destruct the live objects in cycles, but first warn about any bad * cycles. */ pre_kill_objs = num_objects; if (last_cycle) { objs -= num_objects; warn_bad_cycles(); objs += num_objects; } #ifdef PIKE_DEBUG destroy_count = 0; #endif
fb5e412000-07-18Martin Stjernholm  while (kill_list) { struct gc_frame *next = NEXT(kill_list);
e2d9e62000-06-10Martin Stjernholm  struct object *o = (struct object *) kill_list->data; #ifdef PIKE_DEBUG
45d87e2000-07-18Martin Stjernholm  if ((get_marker(kill_list->data)->flags & (GC_LIVE|GC_LIVE_OBJ)) != (GC_LIVE|GC_LIVE_OBJ))
e2d9e62000-06-10Martin Stjernholm  gc_fatal(o, 0, "Invalid thing in kill list.\n");
45d87e2000-07-18Martin Stjernholm  if (o->parent && !o->parent->prog && get_marker(o->parent)->flags & GC_LIVE_OBJ) gc_fatal(o, 0, "GC destructed parent prematurely.\n");
e2d9e62000-06-10Martin Stjernholm #endif GC_VERBOSE_DO(fprintf(stderr, "| Killing %p with %d refs\n", o, o->refs)); destruct(o); free_object(o); gc_free_extra_ref(o); #ifdef PIKE_DEBUG destroy_count++; #endif
63709a2000-07-18Martin Stjernholm  debug_really_free_gc_frame(kill_list);
fb5e412000-07-18Martin Stjernholm  kill_list = next;
e2d9e62000-06-10Martin Stjernholm  } GC_VERBOSE_DO(fprintf(stderr, "| kill: %u objects killed, %d things really freed\n", destroy_count, pre_kill_objs - num_objects));
7bf6232000-04-23Martin Stjernholm  Pike_in_gc=GC_PASS_DESTRUCT;
e2d9e62000-06-10Martin Stjernholm  /* Destruct objects on the destruct queue. */ GC_VERBOSE_DO(obj_count = num_objects);
7bf6232000-04-23Martin Stjernholm  destruct_objects_to_destruct();
e2d9e62000-06-10Martin Stjernholm  GC_VERBOSE_DO(fprintf(stderr, "| destruct: %d things really freed\n", obj_count - num_objects));
08679c2000-04-26Martin Stjernholm 
7bf6232000-04-23Martin Stjernholm #ifdef PIKE_DEBUG if (gc_debug) {
e2d9e62000-06-10Martin Stjernholm  unsigned n;
7bf6232000-04-23Martin Stjernholm  Pike_in_gc=GC_PASS_POSTTOUCH; 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();
0838862000-09-15Henrik Grubbström (Grubba)  /* gc_touch_all_strings(); */
e2d9e62000-06-10Martin Stjernholm  if (n != (unsigned) num_objects)
7bf6232000-04-23Martin Stjernholm  fatal("Object count wrong after gc; expected %d, got %d.\n", num_objects, n);
e2d9e62000-06-10Martin Stjernholm  GC_VERBOSE_DO(fprintf(stderr, "| posttouch: %u things\n", n));
7bf6232000-04-23Martin Stjernholm  }
e2d9e62000-06-10Martin Stjernholm  if (gc_extra_refs) fatal("Lost track of %d extra refs to things in gc.\n", gc_extra_refs);
1a12e82000-09-30Martin Stjernholm  if(fatal_after_gc) fatal("%s", fatal_after_gc);
7bf6232000-04-23Martin Stjernholm #endif Pike_in_gc=0;
b51e6d1998-02-18Fredrik Hübinette (Hubbe)  exit_gc();
06983f1996-09-22Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm  /* It's possible that more things got allocated in the kill pass * than were freed. The count before that is a better measurement * then. */ if (pre_kill_objs < num_objects) objs -= pre_kill_objs; else objs -= num_objects; objects_freed += (double) objs;
6930181996-02-25Fredrik Hübinette (Hubbe)  tmp=(double)num_objects; tmp=tmp * GC_CONST/100.0 * (objects_alloced+1.0) / (objects_freed+1.0);
6acd502000-05-01Fredrik Noring  if(alloc_threshold + num_allocs <= tmp) tmp = (double)(alloc_threshold + num_allocs); if(tmp < MIN_ALLOC_THRESHOLD) tmp = (double)MIN_ALLOC_THRESHOLD; if(tmp > MAX_ALLOC_THRESHOLD) tmp = (double)MAX_ALLOC_THRESHOLD;
f5757f2000-08-11Henrik Grubbström (Grubba)  alloc_threshold = (ptrdiff_t)tmp;
6acd502000-05-01Fredrik Noring 
6930181996-02-25Fredrik Hübinette (Hubbe)  num_allocs=0;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
e2d9e62000-06-10Martin Stjernholm  if(GC_VERBOSE_DO(1 ||) t_flag)
a4033e2000-04-14Fredrik Hübinette (Hubbe)  { #ifdef HAVE_GETHRTIME
6bc62b2000-04-14Martin Stjernholm  fprintf(stderr,"done (freed %ld of %ld objects), %ld ms.\n",
e2d9e62000-06-10Martin Stjernholm  (long)objs,(long)objs + num_objects,
a4033e2000-04-14Fredrik Hübinette (Hubbe)  (long)((gethrtime() - gcstarttime)/1000000));
b088ab2000-04-15Martin Stjernholm #else
a4033e2000-04-14Fredrik Hübinette (Hubbe)  fprintf(stderr,"done (freed %ld of %ld objects)\n",
e2d9e62000-06-10Martin Stjernholm  (long)objs,(long)objs + num_objects);
b088ab2000-04-15Martin Stjernholm #endif
a4033e2000-04-14Fredrik Hübinette (Hubbe)  }
6930181996-02-25Fredrik Hübinette (Hubbe) #endif
a29e021996-10-15Fredrik Hübinette (Hubbe) 
bf45771996-12-05Fredrik Hübinette (Hubbe) #ifdef ALWAYS_GC
890e5b1996-11-21Fredrik Hübinette (Hubbe)  ADD_GC_CALLBACK(); #else
bf45771996-12-05Fredrik Hübinette (Hubbe)  if(d_flag > 3) ADD_GC_CALLBACK();
a29e021996-10-15Fredrik Hübinette (Hubbe) #endif
e2d9e62000-06-10Martin Stjernholm  return objs;
6930181996-02-25Fredrik Hübinette (Hubbe) }
7c0df72001-02-06Henrik Grubbström (Grubba) /*! @decl mapping(string:int|float) _gc_status() *! *! Get statistics from the garbage collector. *! *! @returns *! A mapping with the following content will be returned: *! @mapping *! @member int "num_objects" *! Number of objects. *! @member int "num_allocs" *! Number of memory allocations. *! @member int "alloc_threshold" *! Threshold where the garbage-collector starts. *! @member int "objects_alloced" *! Number of allocated objects. *! @member int "objects_freed" *! Number of freed objects. *! @member int "last_gc" *! Time when the garbage-collector last ran. *! @member float "projected_garbage" *! Heuristic for the amount of garbage in the system. *! @endmapping *! *! @seealso *! @[gc()] */
1637c42000-02-01Fredrik Hübinette (Hubbe) void f__gc_status(INT32 args) { pop_n_elems(args); push_constant_text("num_objects"); push_int(num_objects); push_constant_text("num_allocs"); push_int(num_allocs); push_constant_text("alloc_threshold");
905e0c2000-08-11Henrik Grubbström (Grubba)  push_int64(alloc_threshold);
1637c42000-02-01Fredrik Hübinette (Hubbe)  push_constant_text("objects_alloced");
905e0c2000-08-11Henrik Grubbström (Grubba)  push_int64(objects_alloced);
1637c42000-02-01Fredrik Hübinette (Hubbe)  push_constant_text("objects_freed");
905e0c2000-08-11Henrik Grubbström (Grubba)  push_int64(objects_freed);
1637c42000-02-01Fredrik Hübinette (Hubbe)  push_constant_text("last_gc");
905e0c2000-08-11Henrik Grubbström (Grubba)  push_int64(last_gc);
1637c42000-02-01Fredrik Hübinette (Hubbe)  push_constant_text("projected_garbage"); push_float(objects_freed * (double) num_allocs / (double) alloc_threshold); f_aggregate_mapping(14); }
5da0872000-08-22Henrik Grubbström (Grubba)  void cleanup_gc(void) { #ifdef PIKE_DEBUG if (gc_evaluator_callback) { remove_callback(gc_evaluator_callback); gc_evaluator_callback = NULL; } #endif /* PIKE_DEBUG */ }