Ticket #1173: okay-working-symbol-gc.patch

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

Faster working symbol GC

  • 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..e988e54 100644
    a b C_fctexport C_word C_fcall C_i_o_fixnum_and(C_word x, C_word y) C_regparm; 
    19511951C_fctexport C_word C_fcall C_i_o_fixnum_ior(C_word x, C_word y) C_regparm;
    19521952C_fctexport C_word C_fcall C_i_o_fixnum_xor(C_word x, C_word y) C_regparm;
    19531953C_fctexport C_word C_fcall C_a_i_flonum_round_proper(C_word **a, int c, C_word n) C_regparm;
     1954C_fctexport C_word C_fcall C_i_persist_symbol(C_word sym) C_regparm;
    19541955C_fctexport C_word C_fcall C_i_getprop(C_word sym, C_word prop, C_word def) C_regparm;
    19551956C_fctexport C_word C_fcall C_putprop(C_word **a, C_word sym, C_word prop, C_word val) C_regparm;
    19561957C_fctexport C_word C_fcall C_i_get_keyword(C_word key, C_word args, C_word def) C_regparm;
    C_inline C_word C_fcall C_a_bucket(C_word **ptr, C_word head, C_word tail) 
    26522653{
    26532654  C_word *p = *ptr, *p0 = p;
    26542655
    2655   *(p++) = C_BUCKET_TYPE | (C_SIZEOF_BUCKET - 1);
     2656  if (C_enable_gcweak)
     2657    *(p++) = C_BUCKET_TYPE | C_SPECIALBLOCK_BIT | (C_SIZEOF_BUCKET - 1);
     2658  else
     2659    *(p++) = C_BUCKET_TYPE | (C_SIZEOF_BUCKET - 1);
    26562660  *(p++) = head;
    26572661  *(p++) = tail;
    26582662  *ptr = p;
  • eval.scm

    diff --git a/eval.scm b/eval.scm
    index 6242f62..cc304c3 100644
    a b  
    381381                                             (lambda (v)
    382382                                               (##sys#error 'eval "environment is not mutable" evalenv var)) ;XXX var?
    383383                                             (lambda (v)
     384                                               (##sys#persist-symbol var)
    384385                                               (##sys#setslot var 0 (##core#app val v))) ) ) ]
    385386                                      [(zero? i) (lambda (v) (##sys#setslot (##sys#slot v 0) j (##core#app val v)))]
    386387                                      [else
  • library.scm

    diff --git a/library.scm b/library.scm
    index e95542f..71bfbf1 100644
    a b EOF 
    204204(define ##sys#gc (##core#primitive "C_gc"))
    205205(define (##sys#setslot x i y) (##core#inline "C_i_setslot" x i y))
    206206(define (##sys#setislot x i y) (##core#inline "C_i_set_i_slot" x i y))
     207(define (##sys#persist-symbol s) (##core#inline "C_i_persist_symbol" s))
    207208(define ##sys#allocate-vector (##core#primitive "C_allocate_vector"))
    208209(define (argc+argv) (##sys#values main_argc main_argv))
    209210(define ##sys#make-structure (##core#primitive "C_make_structure"))
    EOF 
    49714972
    49724973(define get (getter-with-setter ##sys#get put! "(get sym prop . default)"))
    49734974
     4975;; TODO: "Unpersist" symbol if this drops the last property
    49744976(define (remprop! sym prop)
    49754977  (##sys#check-symbol sym 'remprop!)
    49764978  (let loop ((plist (##sys#slot sym 2)) (ptl #f))
  • runtime.c

    diff --git a/runtime.c b/runtime.c
    index cdaaa0e..f7983ba 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);
    508493static C_word C_fcall hash_string(int len, C_char *str, C_word m, C_word r, int ci) C_regparm;
    509494static C_word C_fcall lookup(C_word key, int len, C_char *str, C_SYMBOL_TABLE *stable) C_regparm;
     495static void C_fcall persist(C_word sym, C_SYMBOL_TABLE *stable) C_regparm;
    510496static double compute_symbol_table_load(double *avg_bucket_len, int *total);
    511497static C_word C_fcall convert_string_to_number(C_char *str, int radix, C_word *fix, double *flo) C_regparm;
    512498static C_word C_fcall maybe_inexact_to_exact(C_word n) C_regparm;
    static void C_fcall remark_system_globals(void) C_regparm; 
    515501static void C_fcall really_remark(C_word *x) C_regparm;
    516502static C_word C_fcall intern0(C_char *name) C_regparm;
    517503static void C_fcall update_locative_table(int mode) C_regparm;
     504static void C_fcall update_symbol_tables(int mode) C_regparm;
    518505static LF_LIST *find_module_handle(C_char *name);
    519506static void set_profile_timer(C_uword freq);
    520507static void take_profile_sample();
    int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel) 
    687674  C_gc_mutation_hook = NULL;
    688675  C_gc_trace_hook = NULL;
    689676
    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 
    698677  /* Initialize finalizer lists: */
    699678  finalizer_list = NULL;
    700679  finalizer_free_list = NULL;
    C_regparm C_word C_fcall lookup(C_word key, int len, C_char *str, C_SYMBOL_TABLE 
    22572236  return C_SCHEME_FALSE;
    22582237}
    22592238
     2239C_regparm C_word C_fcall C_i_persist_symbol(C_word sym)
     2240{
     2241  C_i_check_symbol(sym);
     2242  persist(sym, NULL);
     2243  return C_SCHEME_UNDEFINED;
     2244}
     2245
     2246/* Mark a symbol as "persistent", to prevent it from being GC'ed */
     2247C_regparm void C_fcall persist(C_word sym, C_SYMBOL_TABLE *stable)
     2248{
     2249  C_word bucket, str = C_block_item(sym, 1);
     2250  int key, len = C_header_size(str);
     2251
     2252  if (stable == NULL) stable = symbol_table;
     2253
     2254  key = hash_string(len, C_c_string(str), stable->size, stable->rand, 0);
     2255
     2256  for(bucket = stable->table[ key ]; bucket != C_SCHEME_END_OF_LIST;
     2257      bucket = C_block_item(bucket,1)) {
     2258    if (C_block_item(bucket,0) == sym) {
     2259      /* Change weak to strong ref to ensure overall survival */
     2260      C_block_header(bucket) = C_block_header(bucket) & ~C_SPECIALBLOCK_BIT;
     2261      /* Ensure survival on next minor GC */
     2262      if (C_in_stackp(sym)) C_mutate_slot(&C_block_item(bucket, 0), sym);
     2263      return;
     2264    }
     2265  }
     2266}
     2267
    22602268
    22612269double compute_symbol_table_load(double *avg_bucket_len, int *total_n)
    22622270{
    static void mark(C_word *x) { \ 
    28342842  C_cblockend
    28352843#endif
    28362844
    2837 
    28382845C_regparm void C_fcall C_reclaim(void *trampoline, C_word c)
    28392846{
    2840   int i, j, n, fcount, weakn = 0;
     2847  int i, j, n, fcount;
    28412848  C_uword count, bytes;
    2842   C_word *p, **msp, bucket, last, item, container;
     2849  C_word *p, **msp, bucket, last;
    28432850  C_header h;
    28442851  C_byte *tmp, *start;
    28452852  LF_LIST *lfn;
    28462853  C_SCHEME_BLOCK *bp;
    28472854  C_GC_ROOT *gcrp;
    2848   WEAK_TABLE_ENTRY *wep;
    28492855  double tgc = 0;
    28502856  C_SYMBOL_TABLE *stp;
    28512857  volatile int finalizers_checked;
    C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 
    28742880  gc_mode = GC_MINOR;
    28752881  start = C_fromspace_top;
    28762882
    2877   if(C_enable_gcweak)
    2878     weak_table_randomization = rand();
    2879 
    28802883  /* Entry point for second-level GC (on explicit request or because of full fromspace): */
    28812884#ifdef HAVE_SIGSETJMP
    28822885  if(C_sigsetjmp(gc_restart, 0) || start >= C_fromspace_limit) {
    C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 
    30923095
    30933096  i_like_spaghetti:
    30943097    ++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     }
    31343098  }
    31353099
     3100  update_symbol_tables(gc_mode);
     3101
    31363102  if(gc_mode == GC_MAJOR) {
    31373103    tgc = C_cpu_milliseconds() - tgc;
    31383104    gc_ms += tgc;
    C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 
    31693135          (C_uword)tospace_start, (C_uword)tospace_top,
    31703136          (C_uword)tospace_limit);
    31713137
    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    
    31753138    C_dbg("GC", C_text("%d locatives (from %d)\n"), locative_table_count, locative_table_size);
    31763139  }
    31773140
    C_regparm void C_fcall mark_system_globals(void) 
    32003163
    32013164C_regparm void C_fcall really_mark(C_word *x)
    32023165{
    3203   C_word val, item;
     3166  C_word val;
    32043167  C_uword n, bytes;
    32053168  C_header h;
    32063169  C_SCHEME_BLOCK *p, *p2;
    3207   WEAK_TABLE_ENTRY *wep;
    32083170
    32093171  val = *x;
    32103172
    C_regparm void C_fcall really_mark(C_word *x) 
    32273189      return;
    32283190    }
    32293191
    3230     if((C_uword)val >= (C_uword)fromspace_start && (C_uword)val < (C_uword)C_fromspace_top) return;
     3192    if((C_uword)val >= (C_uword)fromspace_start && (C_uword)val < (C_uword)C_fromspace_top)
     3193      return;
    32313194
    32323195    p2 = (C_SCHEME_BLOCK *)C_align((C_uword)C_fromspace_top);
    32333196
    C_regparm void C_fcall really_mark(C_word *x) 
    32573220    C_memcpy(p2->data, p->data, bytes);
    32583221  }
    32593222  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 
    32673223    if(is_fptr(h)) {
    32683224      val = fptr_to_ptr(h);
    32693225
    C_regparm void C_fcall really_mark(C_word *x) 
    32993255    }
    33003256#endif
    33013257
    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 
    33123258    n = C_header_size(p);
    33133259    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
    33143260
    static void remark(C_word *x) { \ 
    33483294  C_cblockend
    33493295#endif
    33503296
    3351 
    33523297/* Do a major GC into a freshly allocated heap: */
    33533298
    33543299C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize)
    33553300{
    33563301  int i, j;
    33573302  C_uword count, n, bytes;
    3358   C_word *p, **msp, item, last;
     3303  C_word *p, **msp, bucket, last;
    33593304  C_header h;
    33603305  C_byte *tmp, *start;
    33613306  LF_LIST *lfn;
    33623307  C_SCHEME_BLOCK *bp;
    3363   WEAK_TABLE_ENTRY *wep;
    33643308  C_GC_ROOT *gcrp;
    33653309  C_SYMBOL_TABLE *stp;
    33663310  FINALIZER_NODE *flist;
    C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 
    34453389  /* Mark symbol table: */
    34463390  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
    34473391    for(i = 0; i < stp->size; ++i)
    3448       remark(&stp->table[i]);
     3392      remark(&stp->table[i]); /* Ensure buckets survive */
    34493393
    34503394  /* Mark collectibles: */
    34513395  for(msp = collectibles; msp < collectibles_top; ++msp)
    C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 
    34733417    remark(&flist->finalizer);
    34743418  }
    34753419
    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 
    34843420  /* Mark trace-buffer: */
    34853421  for(tinfo = trace_buffer; tinfo < trace_buffer_limit; ++tinfo) {
    34863422    remark(&tinfo->cooked1);
    C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 
    35153451    heap_scan_top = (C_byte *)bp + C_align(bytes) + sizeof(C_word);
    35163452  }
    35173453
     3454  update_symbol_tables(GC_REALLOC);
     3455
    35183456  heap_free (heapspace1, heapspace1_size);
    35193457  heap_free (heapspace2, heapspace2_size);
    35203458 
    C_regparm void C_fcall really_remark(C_word *x) 
    35603498  C_uword n, bytes;
    35613499  C_header h;
    35623500  C_SCHEME_BLOCK *p, *p2;
    3563   WEAK_TABLE_ENTRY *wep;
    35643501
    35653502  val = *x;
    35663503
    C_regparm void C_fcall update_locative_table(int mode) 
    37343671  if(mode != GC_REALLOC) locative_table_count = hi;
    37353672}
    37363673
    3737 
    3738 C_regparm WEAK_TABLE_ENTRY *C_fcall lookup_weak_table_entry(C_word item, C_word container)
     3674C_regparm void C_fcall update_symbol_tables(int mode)
    37393675{
    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 ];
     3676  int weakn = 0, i;
     3677  C_word bucket, last, sym, h;
     3678  C_SYMBOL_TABLE *stp;
    37493679
    3750     if(wep->item == 0) {
    3751       if(container != 0) {
    3752         /* Add fresh entry: */
    3753         wep->item = item;
    3754         wep->container = container;
    3755         return wep;
     3680  if(C_enable_gcweak) {
     3681    /* Fixup symbol table */
     3682    for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
     3683      for(i = 0; i < stp->size; ++i) {
     3684        last = 0;
     3685
     3686        for(bucket = stp->table[ i ]; bucket != C_SCHEME_END_OF_LIST; bucket = C_block_item(bucket,1)) {
     3687
     3688          sym = C_block_item(bucket, 0);
     3689          h = C_block_header(sym);
     3690
     3691          /* Resolve any forwarding pointers */
     3692          while(is_fptr(h)) {
     3693            sym = fptr_to_ptr(h);
     3694            h = C_block_header(sym);
     3695          }
     3696
     3697          assert((h & C_HEADER_TYPE_BITS) == C_SYMBOL_TYPE);
     3698
     3699          /* If the symbol is unreferenced, drop it: */
     3700          if(!C_truep(C_permanentp(sym)) && (mode == GC_REALLOC ?
     3701                                             !C_in_new_heapp(sym) :
     3702                                             !C_in_fromspacep(sym))) {
     3703
     3704            if(last) C_set_block_item(last, 1, C_block_item(bucket,1));
     3705            else stp->table[ i ] = C_block_item(bucket,1);
     3706
     3707            assert(C_block_item(sym, 0) == C_SCHEME_UNBOUND ||
     3708                   C_block_item(sym, 0) == sym); /* kw */
     3709            assert(C_block_item(sym, 2) == C_SCHEME_END_OF_LIST);
     3710            ++weakn;
     3711          } else {
     3712            C_set_block_item(bucket,0,sym); /* Might have moved */
     3713            last = bucket;
     3714          }
     3715        }
    37563716      }
    3757 
    3758       return NULL;
    37593717    }
    3760     else if(wep->item == item) return wep;
    3761     else disp += WEAK_HASH_DISPLACEMENT;
     3718    if(gc_report_flag && weakn)
     3719      C_dbg("GC", C_text("%d recoverable weakly held items found\n"), weakn);
     3720  } else {
     3721#ifdef DEBUGBUILD
     3722    /* Sanity check: all symbols should've been marked */
     3723    for(stp = symbol_table_list; stp != NULL; stp = stp->next)
     3724      for(i = 0; i < stp->size; ++i)
     3725        for(bucket = stp->table[ i ]; bucket != C_SCHEME_END_OF_LIST; bucket = C_block_item(bucket,1)) {
     3726          sym = C_block_item(bucket, 0);
     3727          assert(!is_fptr(C_block_header(sym)) &&
     3728                 (C_truep(C_permanentp(sym)) ||
     3729                  (mode == GC_REALLOC ?
     3730                   C_in_new_heapp(sym) :
     3731                   C_in_fromspacep(sym))));
     3732        }
     3733#endif
    37623734  }
    3763 
    3764   return NULL;
    37653735}
    37663736
    37673737
    C_putprop(C_word **ptr, C_word sym, C_word prop, C_word val) 
    94049374{
    94059375  C_word pl = C_block_item(sym, 2);
    94069376
     9377  /* Newly added plist?  Ensure the symbol stays! */
     9378  if (C_enable_gcweak && pl == C_SCHEME_END_OF_LIST) persist(sym, NULL);
     9379
    94079380  while(pl != C_SCHEME_END_OF_LIST) {
    94089381    if(C_block_item(pl, 0) == prop) {
    94099382      C_mutate2(&C_u_i_car(C_u_i_cdr(pl)), val);