Ticket #1173: working-symbol-gc.patch

File working-symbol-gc.patch, 14.6 KB (added by sjamaan, 8 years ago)

A working, but slow fix

  • NEWS

    diff --git a/NEWS b/NEWS
    index d64c818..0481245 100644
    a b  
    2323    which is faster because it is inlined (#1260, thanks to Kooda).
    2424  - The default error handler now truncates very long condition
    2525    messages (thanks to Lemonboy).
     26  - Weak symbol GC (-:w) no longer drops random symbols (#1173).
    2627
    2728- Syntax expander
    2829  - DSSSL lambda lists have improved hygiene, so they don't need
  • chicken.h

    diff --git a/chicken.h b/chicken.h
    index d451835..5f25905 100644
    a b C_inline C_word C_fcall C_a_bucket(C_word **ptr, C_word head, C_word tail) 
    26522652{
    26532653  C_word *p = *ptr, *p0 = p;
    26542654
    2655   *(p++) = C_BUCKET_TYPE | (C_SIZEOF_BUCKET - 1);
     2655  if (C_enable_gcweak)
     2656    *(p++) = C_BUCKET_TYPE | C_SPECIALBLOCK_BIT | (C_SIZEOF_BUCKET - 1);
     2657  else
     2658    *(p++) = C_BUCKET_TYPE | (C_SIZEOF_BUCKET - 1);
    26562659  *(p++) = head;
    26572660  *(p++) = tail;
    26582661  *ptr = p;
  • runtime.c

    diff --git a/runtime.c b/runtime.c
    index cdaaa0e..558dfa4 100644
    a b static C_TLS int timezone; 
    156156
    157157#define MAX_HASH_PREFIX                64
    158158
    159 #define WEAK_TABLE_SIZE                997
    160 #define WEAK_HASH_ITERATIONS           4
    161 #define WEAK_HASH_DISPLACEMENT         7
    162 #define WEAK_COUNTER_MASK              3
    163 #define WEAK_COUNTER_MAX               2
    164 
    165159#define TEMPORARY_STACK_SIZE           4096
    166160#define STRING_BUFFER_SIZE             4096
    167161#define DEFAULT_MUTATION_STACK_SIZE    1024
    typedef struct lf_list_struct 
    285279  char *module_name;
    286280} LF_LIST;
    287281
    288 typedef struct weak_table_entry_struct
    289 {
    290   C_word item,                  /* item weakly held (symbol) */
    291          container;             /* object holding reference to symbol, lowest 3 bits are */
    292 } WEAK_TABLE_ENTRY;             /*   also used as a counter, saturated at 2 or more */
    293 
    294282typedef struct finalizer_node_struct
    295283{
    296284  struct finalizer_node_struct
    static C_TLS int 
    438426  gc_count_1,
    439427  gc_count_1_total,
    440428  gc_count_2,
    441   weak_table_randomization,
    442429  stack_size_changed,
    443430  dlopen_flags,
    444431  heap_size_changed,
    static C_TLS int 
    474461  allocated_finalizer_count,
    475462  pending_finalizer_count,
    476463  callback_returned_flag;
    477 static C_TLS WEAK_TABLE_ENTRY *weak_item_table;
    478464static C_TLS C_GC_ROOT *gc_root_list = NULL;
    479465static C_TLS FINALIZER_NODE
    480466  *finalizer_list,
    static void panic(C_char *msg) C_noret; 
    501487static void usual_panic(C_char *msg) C_noret;
    502488static void horror(C_char *msg) C_noret;
    503489static void C_fcall really_mark(C_word *x) C_regparm;
    504 static WEAK_TABLE_ENTRY *C_fcall lookup_weak_table_entry(C_word item, C_word container) C_regparm;
    505490static C_cpsproc(values_continuation) C_noret;
    506491static C_word add_symbol(C_word **ptr, C_word key, C_word string, C_SYMBOL_TABLE *stable);
    507492static C_regparm int C_fcall C_in_new_heapp(C_word x);
    static void C_fcall remark_system_globals(void) C_regparm; 
    515500static void C_fcall really_remark(C_word *x) C_regparm;
    516501static C_word C_fcall intern0(C_char *name) C_regparm;
    517502static void C_fcall update_locative_table(int mode) C_regparm;
     503static void C_fcall update_symbol_tables(int mode) C_regparm;
    518504static LF_LIST *find_module_handle(C_char *name);
    519505static void set_profile_timer(C_uword freq);
    520506static void take_profile_sample();
    int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel) 
    687673  C_gc_mutation_hook = NULL;
    688674  C_gc_trace_hook = NULL;
    689675
    690   /* Allocate weak item table: */
    691   if(C_enable_gcweak) {
    692     weak_item_table = (WEAK_TABLE_ENTRY *)C_calloc(WEAK_TABLE_SIZE, sizeof(WEAK_TABLE_ENTRY));
    693 
    694     if(weak_item_table == NULL)
    695       return 0;
    696   }
    697 
    698676  /* Initialize finalizer lists: */
    699677  finalizer_list = NULL;
    700678  finalizer_free_list = NULL;
    static void mark(C_word *x) { \ 
    28342812  C_cblockend
    28352813#endif
    28362814
     2815/* Keep all symbols that are globally bound (i.e., top-level
     2816 * identifiers) or have non-empty property lists.
     2817 * Keywords will always be discarded.
     2818 */
     2819#define keep_symbol(s) ((C_block_item((s), 0) != C_SCHEME_UNBOUND &&    \
     2820                         C_block_item((s), 0) != (s) /* kw */) ||       \
     2821                        C_block_item((s), 2) != C_SCHEME_END_OF_LIST)
    28372822
    28382823C_regparm void C_fcall C_reclaim(void *trampoline, C_word c)
    28392824{
    2840   int i, j, n, fcount, weakn = 0;
     2825  int i, j, n, fcount;
    28412826  C_uword count, bytes;
    2842   C_word *p, **msp, bucket, last, item, container;
     2827  C_word *p, **msp, bucket, last;
    28432828  C_header h;
    28442829  C_byte *tmp, *start;
    28452830  LF_LIST *lfn;
    28462831  C_SCHEME_BLOCK *bp;
    28472832  C_GC_ROOT *gcrp;
    2848   WEAK_TABLE_ENTRY *wep;
    28492833  double tgc = 0;
    28502834  C_SYMBOL_TABLE *stp;
    28512835  volatile int finalizers_checked;
    C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 
    28742858  gc_mode = GC_MINOR;
    28752859  start = C_fromspace_top;
    28762860
    2877   if(C_enable_gcweak)
    2878     weak_table_randomization = rand();
    2879 
    28802861  /* Entry point for second-level GC (on explicit request or because of full fromspace): */
    28812862#ifdef HAVE_SIGSETJMP
    28822863  if(C_sigsetjmp(gc_restart, 0) || start >= C_fromspace_limit) {
    C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 
    29162897      for(i = 0; i < lfn->count; ++i)
    29172898        mark(&lfn->lf[i]);
    29182899
    2919     /* Mark symbol tables: */
    2920     for(stp = symbol_table_list; stp != NULL; stp = stp->next)
    2921       for(i = 0; i < stp->size; ++i)
    2922         mark(&stp->table[i]);
    2923 
    29242900    /* Mark collectibles: */
    29252901    for(msp = collectibles; msp < collectibles_top; ++msp)
    29262902      if(*msp != NULL) mark(*msp);
    C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 
    29542930    mark(&tinfo->thread);
    29552931  }
    29562932
     2933  /* Mark symbol tables: */
     2934  for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
     2935    for(i = 0; i < stp->size; ++i) {
     2936      mark(&stp->table[i]); /* Ensure buckets survive */
     2937
     2938      if (C_enable_gcweak) {
     2939        for(bucket = stp->table[ i ]; bucket != C_SCHEME_END_OF_LIST; bucket = C_block_item(bucket,1)) {
     2940          if (keep_symbol(C_block_item(bucket, 0)))
     2941            mark(&C_block_item(bucket, 0));
     2942        }
     2943      }
     2944    }
     2945  }
     2946
    29572947 rescan:
    29582948  /* Mark nested values in already moved (marked) blocks in breadth-first manner: */
    29592949  while(heap_scan_top < (gc_mode == GC_MINOR ? C_fromspace_top : tospace_top)) {
    C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 
    30923082
    30933083  i_like_spaghetti:
    30943084    ++gc_count_2;
    3095 
    3096     if(C_enable_gcweak) {
    3097       /* Check entries in weak item table and recover items ref'd only
    3098          once, which are unbound symbols and have empty property-lists: */
    3099       weakn = 0;
    3100       wep = weak_item_table;
    3101 
    3102       for(i = 0; i < WEAK_TABLE_SIZE; ++i, ++wep)
    3103         if(wep->item != 0) {
    3104           if((wep->container & WEAK_COUNTER_MAX) == 0 && /* counter saturated? (more than 1) */
    3105              is_fptr((item = C_block_header(wep->item)))) { /* and forwarded/collected */
    3106             item = fptr_to_ptr(item);                       /* recover obj from forwarding ptr */
    3107             container = wep->container & ~WEAK_COUNTER_MASK;
    3108 
    3109             if(C_header_bits(item) == C_SYMBOL_TYPE &&
    3110                C_block_item(item, 0) == C_SCHEME_UNBOUND &&
    3111                C_block_item(item, 2) == C_SCHEME_END_OF_LIST) {
    3112               ++weakn;
    3113               C_set_block_item(container, 0, C_SCHEME_UNDEFINED); /* clear reference to item */
    3114             }
    3115           }
    3116 
    3117           wep->item = wep->container = 0;
    3118         }
    3119 
    3120       /* Remove empty buckets in symbol table: */
    3121       for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
    3122         for(i = 0; i < stp->size; ++i) {
    3123           last = 0;
    3124          
    3125           for(bucket = stp->table[ i ]; bucket != C_SCHEME_END_OF_LIST; bucket = C_block_item(bucket,1))
    3126             if(C_block_item(bucket,0) == C_SCHEME_UNDEFINED) {
    3127               if(last) C_set_block_item(last, 1, C_block_item(bucket,1));
    3128               else stp->table[ i ] = C_block_item(bucket,1);
    3129             }
    3130             else last = bucket;
    3131         }
    3132       }
    3133     }
    31343085  }
    31353086
     3087  update_symbol_tables(gc_mode);
     3088
    31363089  if(gc_mode == GC_MAJOR) {
    31373090    tgc = C_cpu_milliseconds() - tgc;
    31383091    gc_ms += tgc;
    C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 
    31693122          (C_uword)tospace_start, (C_uword)tospace_top,
    31703123          (C_uword)tospace_limit);
    31713124
    3172     if(gc_mode == GC_MAJOR && C_enable_gcweak && weakn)
    3173       C_dbg("GC", C_text("%d recoverable weakly held items found\n"), weakn);
    3174    
    31753125    C_dbg("GC", C_text("%d locatives (from %d)\n"), locative_table_count, locative_table_size);
    31763126  }
    31773127
    C_regparm void C_fcall mark_system_globals(void) 
    32003150
    32013151C_regparm void C_fcall really_mark(C_word *x)
    32023152{
    3203   C_word val, item;
     3153  C_word val;
    32043154  C_uword n, bytes;
    32053155  C_header h;
    32063156  C_SCHEME_BLOCK *p, *p2;
    3207   WEAK_TABLE_ENTRY *wep;
    32083157
    32093158  val = *x;
    32103159
    C_regparm void C_fcall really_mark(C_word *x) 
    32273176      return;
    32283177    }
    32293178
    3230     if((C_uword)val >= (C_uword)fromspace_start && (C_uword)val < (C_uword)C_fromspace_top) return;
     3179    if((C_uword)val >= (C_uword)fromspace_start && (C_uword)val < (C_uword)C_fromspace_top)
     3180      return;
    32313181
    32323182    p2 = (C_SCHEME_BLOCK *)C_align((C_uword)C_fromspace_top);
    32333183
    C_regparm void C_fcall really_mark(C_word *x) 
    32573207    C_memcpy(p2->data, p->data, bytes);
    32583208  }
    32593209  else { /* (major GC) */
    3260     /* Increase counter (saturated at 2) if weakly held item (someone pointed to this object): */
    3261     if(C_enable_gcweak &&
    3262        (h & C_HEADER_TYPE_BITS) == C_SYMBOL_TYPE &&
    3263        (wep = lookup_weak_table_entry(val, 0)) != NULL) {
    3264       if((wep->container & WEAK_COUNTER_MAX) == 0) ++wep->container;
    3265     }
    3266 
    32673210    if(is_fptr(h)) {
    32683211      val = fptr_to_ptr(h);
    32693212
    C_regparm void C_fcall really_mark(C_word *x) 
    32993242    }
    33003243#endif
    33013244
    3302     if(C_enable_gcweak && (h & C_HEADER_TYPE_BITS) == C_BUCKET_TYPE) {
    3303       item = C_block_item(val,0);
    3304 
    3305       /* Lookup item in weak item table or add entry: */
    3306       if((wep = lookup_weak_table_entry(item, (C_word)p2)) != NULL) {
    3307         /* If item is already forwarded, then set count to 2: */
    3308         if(is_fptr(C_block_header(item))) wep->container |= 2;
    3309       }
    3310     }
    3311 
    33123245    n = C_header_size(p);
    33133246    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
    33143247
    static void remark(C_word *x) { \ 
    33483281  C_cblockend
    33493282#endif
    33503283
    3351 
    33523284/* Do a major GC into a freshly allocated heap: */
    33533285
    33543286C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize)
    33553287{
    33563288  int i, j;
    33573289  C_uword count, n, bytes;
    3358   C_word *p, **msp, item, last;
     3290  C_word *p, **msp, bucket, last;
    33593291  C_header h;
    33603292  C_byte *tmp, *start;
    33613293  LF_LIST *lfn;
    33623294  C_SCHEME_BLOCK *bp;
    3363   WEAK_TABLE_ENTRY *wep;
    33643295  C_GC_ROOT *gcrp;
    33653296  C_SYMBOL_TABLE *stp;
    33663297  FINALIZER_NODE *flist;
    C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 
    34433374      remark(&lfn->lf[i]);
    34443375
    34453376  /* Mark symbol table: */
    3446   for(stp = symbol_table_list; stp != NULL; stp = stp->next)
    3447     for(i = 0; i < stp->size; ++i)
    3448       remark(&stp->table[i]);
     3377  for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
     3378    for(i = 0; i < stp->size; ++i) {
     3379      remark(&stp->table[i]); /* Ensure buckets survive */
     3380
     3381      if (C_enable_gcweak) {
     3382        for(bucket = stp->table[ i ]; bucket != C_SCHEME_END_OF_LIST; bucket = C_block_item(bucket,1)) {
     3383          if(keep_symbol(C_block_item(bucket, 0)))
     3384            remark(&C_block_item(bucket, 0));
     3385        }
     3386      }
     3387    }
     3388  }
    34493389
    34503390  /* Mark collectibles: */
    34513391  for(msp = collectibles; msp < collectibles_top; ++msp)
    C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 
    34733413    remark(&flist->finalizer);
    34743414  }
    34753415
    3476   /* Clear weakly held items: */
    3477   if(C_enable_gcweak) {
    3478     wep = weak_item_table;
    3479 
    3480     for(i = 0; i < WEAK_TABLE_SIZE; ++i, ++wep)
    3481       wep->item = wep->container = 0;
    3482   }
    3483 
    34843416  /* Mark trace-buffer: */
    34853417  for(tinfo = trace_buffer; tinfo < trace_buffer_limit; ++tinfo) {
    34863418    remark(&tinfo->cooked1);
    C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 
    35153447    heap_scan_top = (C_byte *)bp + C_align(bytes) + sizeof(C_word);
    35163448  }
    35173449
     3450  update_symbol_tables(GC_REALLOC);
     3451
    35183452  heap_free (heapspace1, heapspace1_size);
    35193453  heap_free (heapspace2, heapspace2_size);
    35203454 
    C_regparm void C_fcall really_remark(C_word *x) 
    35603494  C_uword n, bytes;
    35613495  C_header h;
    35623496  C_SCHEME_BLOCK *p, *p2;
    3563   WEAK_TABLE_ENTRY *wep;
    35643497
    35653498  val = *x;
    35663499
    C_regparm void C_fcall update_locative_table(int mode) 
    37343667  if(mode != GC_REALLOC) locative_table_count = hi;
    37353668}
    37363669
    3737 
    3738 C_regparm WEAK_TABLE_ENTRY *C_fcall lookup_weak_table_entry(C_word item, C_word container)
     3670C_regparm void C_fcall update_symbol_tables(int mode)
    37393671{
    3740   C_uword
    3741     key = (C_uword)item >> 2,
    3742     disp = 0,
    3743     n;
    3744   WEAK_TABLE_ENTRY *wep;
    3745 
    3746   for(n = 0; n < WEAK_HASH_ITERATIONS; ++n) {
    3747     key = (key + disp + weak_table_randomization) % WEAK_TABLE_SIZE;
    3748     wep = &weak_item_table[ key ];
     3672  int weakn = 0, i;
     3673  C_word bucket, last, sym, h;
     3674  C_SYMBOL_TABLE *stp;
    37493675
    3750     if(wep->item == 0) {
    3751       if(container != 0) {
    3752         /* Add fresh entry: */
    3753         wep->item = item;
    3754         wep->container = container;
    3755         return wep;
     3676  if(C_enable_gcweak) {
     3677    /* Fixup symbol table */
     3678    for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
     3679      for(i = 0; i < stp->size; ++i) {
     3680        last = 0;
     3681
     3682        for(bucket = stp->table[ i ]; bucket != C_SCHEME_END_OF_LIST; bucket = C_block_item(bucket,1)) {
     3683
     3684          sym = C_block_item(bucket, 0);
     3685          h = C_block_header(sym);
     3686          /* Resolve any forwarding pointers */
     3687          while(is_fptr(h)) {
     3688            sym = fptr_to_ptr(h);
     3689            h = C_block_header(sym);
     3690          }
     3691
     3692          /* If the symbol is unreferenced, drop it: */
     3693          if(!C_truep(C_permanentp(sym)) &&
     3694             (mode == GC_REALLOC ?
     3695              !C_in_new_heapp(sym) :
     3696              !C_in_fromspacep(sym))) {
     3697            if(last) C_set_block_item(last, 1, C_block_item(bucket,1));
     3698            else stp->table[ i ] = C_block_item(bucket,1);
     3699            ++weakn;
     3700            assert(!keep_symbol(sym));
     3701          } else {
     3702            assert((h & C_HEADER_TYPE_BITS) == C_SYMBOL_TYPE);
     3703            C_set_block_item(bucket,0,sym); /* Might have moved */
     3704            last = bucket;
     3705          }
     3706        }
    37563707      }
    3757 
    3758       return NULL;
    37593708    }
    3760     else if(wep->item == item) return wep;
    3761     else disp += WEAK_HASH_DISPLACEMENT;
     3709    if(gc_report_flag && weakn)
     3710      C_dbg("GC", C_text("%d recoverable weakly held items found\n"), weakn);
     3711  } else {
     3712#ifdef DEBUGBUILD
     3713    /* Sanity check: all symbols should've been marked */
     3714    for(stp = symbol_table_list; stp != NULL; stp = stp->next)
     3715      for(i = 0; i < stp->size; ++i)
     3716        for(bucket = stp->table[ i ]; bucket != C_SCHEME_END_OF_LIST; bucket = C_block_item(bucket,1)) {
     3717          sym = C_block_item(bucket, 0);
     3718          assert(!is_fptr(C_block_header(sym)) &&
     3719                 (C_truep(C_permanentp(sym)) ||
     3720                  (mode == GC_REALLOC ?
     3721                   C_in_new_heapp(sym) :
     3722                   C_in_fromspacep(sym))));
     3723        }
     3724#endif
    37623725  }
    3763 
    3764   return NULL;
    37653726}
    37663727
    37673728