Ticket #1173: working-symbol-gc.patch
File working-symbol-gc.patch, 14.6 KB (added by , 8 years ago) |
---|
-
NEWS
diff --git a/NEWS b/NEWS index d64c818..0481245 100644
a b 23 23 which is faster because it is inlined (#1260, thanks to Kooda). 24 24 - The default error handler now truncates very long condition 25 25 messages (thanks to Lemonboy). 26 - Weak symbol GC (-:w) no longer drops random symbols (#1173). 26 27 27 28 - Syntax expander 28 29 - 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) 2652 2652 { 2653 2653 C_word *p = *ptr, *p0 = p; 2654 2654 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); 2656 2659 *(p++) = head; 2657 2660 *(p++) = tail; 2658 2661 *ptr = p; -
runtime.c
diff --git a/runtime.c b/runtime.c index cdaaa0e..558dfa4 100644
a b static C_TLS int timezone; 156 156 157 157 #define MAX_HASH_PREFIX 64 158 158 159 #define WEAK_TABLE_SIZE 997160 #define WEAK_HASH_ITERATIONS 4161 #define WEAK_HASH_DISPLACEMENT 7162 #define WEAK_COUNTER_MASK 3163 #define WEAK_COUNTER_MAX 2164 165 159 #define TEMPORARY_STACK_SIZE 4096 166 160 #define STRING_BUFFER_SIZE 4096 167 161 #define DEFAULT_MUTATION_STACK_SIZE 1024 … … typedef struct lf_list_struct 285 279 char *module_name; 286 280 } LF_LIST; 287 281 288 typedef struct weak_table_entry_struct289 {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 294 282 typedef struct finalizer_node_struct 295 283 { 296 284 struct finalizer_node_struct … … static C_TLS int 438 426 gc_count_1, 439 427 gc_count_1_total, 440 428 gc_count_2, 441 weak_table_randomization,442 429 stack_size_changed, 443 430 dlopen_flags, 444 431 heap_size_changed, … … static C_TLS int 474 461 allocated_finalizer_count, 475 462 pending_finalizer_count, 476 463 callback_returned_flag; 477 static C_TLS WEAK_TABLE_ENTRY *weak_item_table;478 464 static C_TLS C_GC_ROOT *gc_root_list = NULL; 479 465 static C_TLS FINALIZER_NODE 480 466 *finalizer_list, … … static void panic(C_char *msg) C_noret; 501 487 static void usual_panic(C_char *msg) C_noret; 502 488 static void horror(C_char *msg) C_noret; 503 489 static 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;505 490 static C_cpsproc(values_continuation) C_noret; 506 491 static C_word add_symbol(C_word **ptr, C_word key, C_word string, C_SYMBOL_TABLE *stable); 507 492 static C_regparm int C_fcall C_in_new_heapp(C_word x); … … static void C_fcall remark_system_globals(void) C_regparm; 515 500 static void C_fcall really_remark(C_word *x) C_regparm; 516 501 static C_word C_fcall intern0(C_char *name) C_regparm; 517 502 static void C_fcall update_locative_table(int mode) C_regparm; 503 static void C_fcall update_symbol_tables(int mode) C_regparm; 518 504 static LF_LIST *find_module_handle(C_char *name); 519 505 static void set_profile_timer(C_uword freq); 520 506 static void take_profile_sample(); … … int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel) 687 673 C_gc_mutation_hook = NULL; 688 674 C_gc_trace_hook = NULL; 689 675 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 698 676 /* Initialize finalizer lists: */ 699 677 finalizer_list = NULL; 700 678 finalizer_free_list = NULL; … … static void mark(C_word *x) { \ 2834 2812 C_cblockend 2835 2813 #endif 2836 2814 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) 2837 2822 2838 2823 C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 2839 2824 { 2840 int i, j, n, fcount , weakn = 0;2825 int i, j, n, fcount; 2841 2826 C_uword count, bytes; 2842 C_word *p, **msp, bucket, last , item, container;2827 C_word *p, **msp, bucket, last; 2843 2828 C_header h; 2844 2829 C_byte *tmp, *start; 2845 2830 LF_LIST *lfn; 2846 2831 C_SCHEME_BLOCK *bp; 2847 2832 C_GC_ROOT *gcrp; 2848 WEAK_TABLE_ENTRY *wep;2849 2833 double tgc = 0; 2850 2834 C_SYMBOL_TABLE *stp; 2851 2835 volatile int finalizers_checked; … … C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 2874 2858 gc_mode = GC_MINOR; 2875 2859 start = C_fromspace_top; 2876 2860 2877 if(C_enable_gcweak)2878 weak_table_randomization = rand();2879 2880 2861 /* Entry point for second-level GC (on explicit request or because of full fromspace): */ 2881 2862 #ifdef HAVE_SIGSETJMP 2882 2863 if(C_sigsetjmp(gc_restart, 0) || start >= C_fromspace_limit) { … … C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 2916 2897 for(i = 0; i < lfn->count; ++i) 2917 2898 mark(&lfn->lf[i]); 2918 2899 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 2924 2900 /* Mark collectibles: */ 2925 2901 for(msp = collectibles; msp < collectibles_top; ++msp) 2926 2902 if(*msp != NULL) mark(*msp); … … C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 2954 2930 mark(&tinfo->thread); 2955 2931 } 2956 2932 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 2957 2947 rescan: 2958 2948 /* Mark nested values in already moved (marked) blocks in breadth-first manner: */ 2959 2949 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) 3092 3082 3093 3083 i_like_spaghetti: 3094 3084 ++gc_count_2; 3095 3096 if(C_enable_gcweak) {3097 /* Check entries in weak item table and recover items ref'd only3098 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 }3134 3085 } 3135 3086 3087 update_symbol_tables(gc_mode); 3088 3136 3089 if(gc_mode == GC_MAJOR) { 3137 3090 tgc = C_cpu_milliseconds() - tgc; 3138 3091 gc_ms += tgc; … … C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) 3169 3122 (C_uword)tospace_start, (C_uword)tospace_top, 3170 3123 (C_uword)tospace_limit); 3171 3124 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 3175 3125 C_dbg("GC", C_text("%d locatives (from %d)\n"), locative_table_count, locative_table_size); 3176 3126 } 3177 3127 … … C_regparm void C_fcall mark_system_globals(void) 3200 3150 3201 3151 C_regparm void C_fcall really_mark(C_word *x) 3202 3152 { 3203 C_word val , item;3153 C_word val; 3204 3154 C_uword n, bytes; 3205 3155 C_header h; 3206 3156 C_SCHEME_BLOCK *p, *p2; 3207 WEAK_TABLE_ENTRY *wep;3208 3157 3209 3158 val = *x; 3210 3159 … … C_regparm void C_fcall really_mark(C_word *x) 3227 3176 return; 3228 3177 } 3229 3178 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; 3231 3181 3232 3182 p2 = (C_SCHEME_BLOCK *)C_align((C_uword)C_fromspace_top); 3233 3183 … … C_regparm void C_fcall really_mark(C_word *x) 3257 3207 C_memcpy(p2->data, p->data, bytes); 3258 3208 } 3259 3209 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 3267 3210 if(is_fptr(h)) { 3268 3211 val = fptr_to_ptr(h); 3269 3212 … … C_regparm void C_fcall really_mark(C_word *x) 3299 3242 } 3300 3243 #endif 3301 3244 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 3312 3245 n = C_header_size(p); 3313 3246 bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word); 3314 3247 … … static void remark(C_word *x) { \ 3348 3281 C_cblockend 3349 3282 #endif 3350 3283 3351 3352 3284 /* Do a major GC into a freshly allocated heap: */ 3353 3285 3354 3286 C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 3355 3287 { 3356 3288 int i, j; 3357 3289 C_uword count, n, bytes; 3358 C_word *p, **msp, item, last;3290 C_word *p, **msp, bucket, last; 3359 3291 C_header h; 3360 3292 C_byte *tmp, *start; 3361 3293 LF_LIST *lfn; 3362 3294 C_SCHEME_BLOCK *bp; 3363 WEAK_TABLE_ENTRY *wep;3364 3295 C_GC_ROOT *gcrp; 3365 3296 C_SYMBOL_TABLE *stp; 3366 3297 FINALIZER_NODE *flist; … … C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 3443 3374 remark(&lfn->lf[i]); 3444 3375 3445 3376 /* 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 } 3449 3389 3450 3390 /* Mark collectibles: */ 3451 3391 for(msp = collectibles; msp < collectibles_top; ++msp) … … C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 3473 3413 remark(&flist->finalizer); 3474 3414 } 3475 3415 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 3484 3416 /* Mark trace-buffer: */ 3485 3417 for(tinfo = trace_buffer; tinfo < trace_buffer_limit; ++tinfo) { 3486 3418 remark(&tinfo->cooked1); … … C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize) 3515 3447 heap_scan_top = (C_byte *)bp + C_align(bytes) + sizeof(C_word); 3516 3448 } 3517 3449 3450 update_symbol_tables(GC_REALLOC); 3451 3518 3452 heap_free (heapspace1, heapspace1_size); 3519 3453 heap_free (heapspace2, heapspace2_size); 3520 3454 … … C_regparm void C_fcall really_remark(C_word *x) 3560 3494 C_uword n, bytes; 3561 3495 C_header h; 3562 3496 C_SCHEME_BLOCK *p, *p2; 3563 WEAK_TABLE_ENTRY *wep;3564 3497 3565 3498 val = *x; 3566 3499 … … C_regparm void C_fcall update_locative_table(int mode) 3734 3667 if(mode != GC_REALLOC) locative_table_count = hi; 3735 3668 } 3736 3669 3737 3738 C_regparm WEAK_TABLE_ENTRY *C_fcall lookup_weak_table_entry(C_word item, C_word container) 3670 C_regparm void C_fcall update_symbol_tables(int mode) 3739 3671 { 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; 3749 3675 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 } 3756 3707 } 3757 3758 return NULL;3759 3708 } 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 3762 3725 } 3763 3764 return NULL;3765 3726 } 3766 3727 3767 3728