X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fgencgc.c;h=652733fad1f5134cd5dd486c2059cf1bcca06f8b;hb=df9e151e5c81ac2716011c246c0e62848527b9b3;hp=288e968c7ccce568cfaa7318987215dc8df7a896;hpb=d97e3589f6ba0ff7ec3d0b6c25b680c4691ac886;p=sbcl.git diff --git a/src/runtime/gencgc.c b/src/runtime/gencgc.c index 288e968..652733f 100644 --- a/src/runtime/gencgc.c +++ b/src/runtime/gencgc.c @@ -52,15 +52,12 @@ #include "genesis/instance.h" #include "genesis/layout.h" #include "gencgc.h" -#if defined(LUTEX_WIDETAG) -#include "pthread-lutex.h" -#endif #if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64) #include "genesis/cons.h" #endif /* forward declarations */ -page_index_t gc_find_freeish_pages(long *restart_page_ptr, long nbytes, +page_index_t gc_find_freeish_pages(page_index_t *restart_page_ptr, long nbytes, int page_type_flag); @@ -81,7 +78,13 @@ enum { boolean enable_page_protection = 1; /* the minimum size (in bytes) for a large object*/ +#if (GENCGC_ALLOC_GRANULARITY >= PAGE_BYTES) && (GENCGC_ALLOC_GRANULARITY >= GENCGC_CARD_BYTES) +long large_object_size = 4 * GENCGC_ALLOC_GRANULARITY; +#elif (GENCGC_CARD_BYTES >= PAGE_BYTES) && (GENCGC_CARD_BYTES >= GENCGC_ALLOC_GRANULARITY) +long large_object_size = 4 * GENCGC_CARD_BYTES; +#else long large_object_size = 4 * PAGE_BYTES; +#endif /* @@ -146,8 +149,8 @@ boolean gencgc_partial_pickup = 0; */ /* the total bytes allocated. These are seen by Lisp DYNAMIC-USAGE. */ -unsigned long bytes_allocated = 0; -unsigned long auto_gc_trigger = 0; +os_vm_size_t bytes_allocated = 0; +os_vm_size_t auto_gc_trigger = 0; /* the source and destination generations. These are set before a GC starts * scavenging. */ @@ -217,7 +220,7 @@ static void *heap_base = NULL; inline void * page_address(page_index_t page_num) { - return (heap_base + (page_num * PAGE_BYTES)); + return (heap_base + (page_num * GENCGC_CARD_BYTES)); } /* Calculate the address where the allocation region associated with @@ -235,18 +238,18 @@ find_page_index(void *addr) { if (addr >= heap_base) { page_index_t index = ((pointer_sized_uint_t)addr - - (pointer_sized_uint_t)heap_base) / PAGE_BYTES; + (pointer_sized_uint_t)heap_base) / GENCGC_CARD_BYTES; if (index < page_table_pages) return (index); } return (-1); } -static size_t -npage_bytes(long npages) +static os_vm_size_t +npage_bytes(page_index_t npages) { gc_assert(npages>=0); - return ((unsigned long)npages)*PAGE_BYTES; + return ((os_vm_size_t)npages)*GENCGC_CARD_BYTES; } /* Check that X is a higher address than Y and return offset from Y to @@ -282,13 +285,13 @@ struct generation { page_index_t alloc_large_unboxed_start_page; /* the bytes allocated to this generation */ - unsigned long bytes_allocated; + os_vm_size_t bytes_allocated; /* the number of bytes at which to trigger a GC */ - unsigned long gc_trigger; + os_vm_size_t gc_trigger; /* to calculate a new level for gc_trigger */ - unsigned long bytes_consed_between_gc; + os_vm_size_t bytes_consed_between_gc; /* the number of GCs since the last raise */ int num_gc; @@ -302,20 +305,12 @@ struct generation { * objects are added from a GC of a younger generation. Dividing by * the bytes_allocated will give the average age of the memory in * this generation since its last GC. */ - unsigned long cum_sum_bytes_allocated; + os_vm_size_t cum_sum_bytes_allocated; /* a minimum average memory age before a GC will occur helps * prevent a GC when a large number of new live objects have been * added, in which case a GC could be a waste of time */ double minimum_age_before_gc; - - /* A linked list of lutex structures in this generation, used for - * implementing lutex finalization. */ -#ifdef LUTEX_WIDETAG - struct lutex *lutexes; -#else - void *lutexes; -#endif }; /* an array of generation structures. There needs to be one more @@ -355,6 +350,12 @@ static pthread_mutex_t free_pages_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t allocation_lock = PTHREAD_MUTEX_INITIALIZER; #endif +extern os_vm_size_t gencgc_release_granularity; +os_vm_size_t gencgc_release_granularity = GENCGC_RELEASE_GRANULARITY; + +extern os_vm_size_t gencgc_alloc_granularity; +os_vm_size_t gencgc_alloc_granularity = GENCGC_ALLOC_GRANULARITY; + /* * miscellaneous heap functions @@ -362,11 +363,10 @@ static pthread_mutex_t allocation_lock = PTHREAD_MUTEX_INITIALIZER; /* Count the number of pages which are write-protected within the * given generation. */ -static long +static page_index_t count_write_protect_generation_pages(generation_index_t generation) { - page_index_t i; - unsigned long count = 0; + page_index_t i, count = 0; for (i = 0; i < last_free_page; i++) if (page_allocated_p(i) @@ -377,11 +377,11 @@ count_write_protect_generation_pages(generation_index_t generation) } /* Count the number of pages within the given generation. */ -static long +static page_index_t count_generation_pages(generation_index_t generation) { page_index_t i; - long count = 0; + page_index_t count = 0; for (i = 0; i < last_free_page; i++) if (page_allocated_p(i) @@ -391,11 +391,11 @@ count_generation_pages(generation_index_t generation) } #if QSHOW -static long +static page_index_t count_dont_move_pages(void) { page_index_t i; - long count = 0; + page_index_t count = 0; for (i = 0; i < last_free_page; i++) { if (page_allocated_p(i) && (page_table[i].dont_move != 0)) { @@ -408,11 +408,11 @@ count_dont_move_pages(void) /* Work through the pages and add up the number of bytes used for the * given generation. */ -static unsigned long +static os_vm_size_t count_generation_bytes_allocated (generation_index_t gen) { page_index_t i; - unsigned long result = 0; + os_vm_size_t result = 0; for (i = 0; i < last_free_page; i++) { if (page_allocated_p(i) && (page_table[i].gen == gen)) @@ -433,10 +433,8 @@ generation_average_age(generation_index_t gen) / ((double)generations[gen].bytes_allocated); } -/* The verbose argument controls how much to print: 0 for normal - * level of detail; 1 for debugging. */ extern void -print_generation_stats() /* FIXME: should take FILE argument, or construct a string */ +write_generation_stats(FILE *file) { generation_index_t i; @@ -453,16 +451,16 @@ print_generation_stats() /* FIXME: should take FILE argument, or construct a str fpu_save(fpu_state); /* Print the heap stats. */ - fprintf(stderr, + fprintf(file, " Gen StaPg UbSta LaSta LUbSt Boxed Unboxed LB LUB !move Alloc Waste Trig WP GCs Mem-age\n"); for (i = 0; i < SCRATCH_GENERATION; i++) { page_index_t j; - long boxed_cnt = 0; - long unboxed_cnt = 0; - long large_boxed_cnt = 0; - long large_unboxed_cnt = 0; - long pinned_cnt=0; + page_index_t boxed_cnt = 0; + page_index_t unboxed_cnt = 0; + page_index_t large_boxed_cnt = 0; + page_index_t large_unboxed_cnt = 0; + page_index_t pinned_cnt=0; for (j = 0; j < last_free_page; j++) if (page_table[j].gen == i) { @@ -488,31 +486,99 @@ print_generation_stats() /* FIXME: should take FILE argument, or construct a str gc_assert(generations[i].bytes_allocated == count_generation_bytes_allocated(i)); - fprintf(stderr, - " %1d: %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %8ld %5ld %8ld %4ld %3d %7.4f\n", + fprintf(file, + " %1d: %5ld %5ld %5ld %5ld", i, generations[i].alloc_start_page, generations[i].alloc_unboxed_start_page, generations[i].alloc_large_start_page, - generations[i].alloc_large_unboxed_start_page, - boxed_cnt, - unboxed_cnt, - large_boxed_cnt, - large_unboxed_cnt, - pinned_cnt, + generations[i].alloc_large_unboxed_start_page); + fprintf(file, + " %5"PAGE_INDEX_FMT" %5"PAGE_INDEX_FMT" %5"PAGE_INDEX_FMT + " %5"PAGE_INDEX_FMT" %5"PAGE_INDEX_FMT, + boxed_cnt, unboxed_cnt, large_boxed_cnt, + large_unboxed_cnt, pinned_cnt); + fprintf(file, + " %8"OS_VM_SIZE_FMT + " %5"OS_VM_SIZE_FMT + " %8"OS_VM_SIZE_FMT + " %4"PAGE_INDEX_FMT" %3d %7.4f\n", generations[i].bytes_allocated, - (npage_bytes(count_generation_pages(i)) - - generations[i].bytes_allocated), + (npage_bytes(count_generation_pages(i)) - generations[i].bytes_allocated), generations[i].gc_trigger, count_write_protect_generation_pages(i), generations[i].num_gc, generation_average_age(i)); } - fprintf(stderr," Total bytes allocated = %lu\n", bytes_allocated); - fprintf(stderr," Dynamic-space-size bytes = %u\n", dynamic_space_size); + fprintf(file," Total bytes allocated = %"OS_VM_SIZE_FMT"\n", bytes_allocated); + fprintf(file," Dynamic-space-size bytes = %"OS_VM_SIZE_FMT"\n", dynamic_space_size); fpu_restore(fpu_state); } + +extern void +write_heap_exhaustion_report(FILE *file, long available, long requested, + struct thread *thread) +{ + fprintf(file, + "Heap exhausted during %s: %ld bytes available, %ld requested.\n", + gc_active_p ? "garbage collection" : "allocation", + available, + requested); + write_generation_stats(file); + fprintf(file, "GC control variables:\n"); + fprintf(file, " *GC-INHIBIT* = %s\n *GC-PENDING* = %s\n", + SymbolValue(GC_INHIBIT,thread)==NIL ? "false" : "true", + (SymbolValue(GC_PENDING, thread) == T) ? + "true" : ((SymbolValue(GC_PENDING, thread) == NIL) ? + "false" : "in progress")); +#ifdef LISP_FEATURE_SB_THREAD + fprintf(file, " *STOP-FOR-GC-PENDING* = %s\n", + SymbolValue(STOP_FOR_GC_PENDING,thread)==NIL ? "false" : "true"); +#endif +} + +extern void +print_generation_stats(void) +{ + write_generation_stats(stderr); +} + +extern char* gc_logfile; +char * gc_logfile = NULL; + +extern void +log_generation_stats(char *logfile, char *header) +{ + if (logfile) { + FILE * log = fopen(logfile, "a"); + if (log) { + fprintf(log, "%s\n", header); + write_generation_stats(log); + fclose(log); + } else { + fprintf(stderr, "Could not open gc logfile: %s\n", logfile); + fflush(stderr); + } + } +} + +extern void +report_heap_exhaustion(long available, long requested, struct thread *th) +{ + if (gc_logfile) { + FILE * log = fopen(gc_logfile, "a"); + if (log) { + write_heap_exhaustion_report(log, available, requested, th); + fclose(log); + } else { + fprintf(stderr, "Could not open gc logfile: %s\n", gc_logfile); + fflush(stderr); + } + } + /* Always to stderr as well. */ + write_heap_exhaustion_report(stderr, available, requested, th); +} #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) @@ -524,13 +590,16 @@ void fast_bzero(void*, size_t); /* in -assem.S */ * OS. Generally done after a large GC. */ void zero_pages_with_mmap(page_index_t start, page_index_t end) { - int i; + page_index_t i; void *addr = page_address(start), *new_addr; - size_t length = npage_bytes(1+end-start); + os_vm_size_t length = npage_bytes(1+end-start); if (start > end) return; + gc_assert(length >= gencgc_release_granularity); + gc_assert((length % gencgc_release_granularity) == 0); + os_invalidate(addr, length); new_addr = os_validate(addr, length); if (new_addr == NULL || new_addr != addr) { @@ -559,19 +628,28 @@ zero_pages(page_index_t start, page_index_t end) { } +static void +zero_and_mark_pages(page_index_t start, page_index_t end) { + page_index_t i; + + zero_pages(start, end); + for (i = start; i <= end; i++) + page_table[i].need_to_zero = 0; +} + /* Zero the pages from START to END (inclusive), except for those * pages that are known to already zeroed. Mark all pages in the * ranges as non-zeroed. */ static void zero_dirty_pages(page_index_t start, page_index_t end) { - page_index_t i; + page_index_t i, j; for (i = start; i <= end; i++) { - if (page_table[i].need_to_zero == 1) { - zero_pages(start, end); - break; - } + if (!page_table[i].need_to_zero) continue; + for (j = i+1; (j <= end) && (page_table[j].need_to_zero); j++); + zero_pages(i, j-1); + i = j; } for (i = start; i <= end; i++) { @@ -729,7 +807,7 @@ gc_alloc_new_region(long nbytes, int page_type_flag, struct alloc_region *alloc_ gc_assert(ret == 0); first_page = generation_alloc_start_page(gc_alloc_generation, page_type_flag, 0); last_page=gc_find_freeish_pages(&first_page, nbytes, page_type_flag); - bytes_found=(PAGE_BYTES - page_table[first_page].bytes_used) + bytes_found=(GENCGC_CARD_BYTES - page_table[first_page].bytes_used) + npage_bytes(last_page-first_page); /* Set up the alloc_region. */ @@ -959,8 +1037,8 @@ gc_alloc_update_page_tables(int page_type_flag, struct alloc_region *alloc_regio more = 0; if ((bytes_used = void_diff(alloc_region->free_pointer, page_address(first_page))) - >PAGE_BYTES) { - bytes_used = PAGE_BYTES; + >GENCGC_CARD_BYTES) { + bytes_used = GENCGC_CARD_BYTES; more = 1; } page_table[first_page].bytes_used = bytes_used; @@ -984,8 +1062,8 @@ gc_alloc_update_page_tables(int page_type_flag, struct alloc_region *alloc_regio /* Calculate the number of bytes used in this page. */ more = 0; if ((bytes_used = void_diff(alloc_region->free_pointer, - page_address(next_page)))>PAGE_BYTES) { - bytes_used = PAGE_BYTES; + page_address(next_page)))>GENCGC_CARD_BYTES) { + bytes_used = GENCGC_CARD_BYTES; more = 1; } page_table[next_page].bytes_used = bytes_used; @@ -1086,8 +1164,8 @@ gc_alloc_large(long nbytes, int page_type_flag, struct alloc_region *alloc_regio /* Calc. the number of bytes used in this page. This is not * always the number of new bytes, unless it was free. */ more = 0; - if ((bytes_used = nbytes+orig_first_page_bytes_used) > PAGE_BYTES) { - bytes_used = PAGE_BYTES; + if ((bytes_used = nbytes+orig_first_page_bytes_used) > GENCGC_CARD_BYTES) { + bytes_used = GENCGC_CARD_BYTES; more = 1; } page_table[first_page].bytes_used = bytes_used; @@ -1111,8 +1189,8 @@ gc_alloc_large(long nbytes, int page_type_flag, struct alloc_region *alloc_regio /* Calculate the number of bytes used in this page. */ more = 0; bytes_used=(nbytes+orig_first_page_bytes_used)-byte_cnt; - if (bytes_used > PAGE_BYTES) { - bytes_used = PAGE_BYTES; + if (bytes_used > GENCGC_CARD_BYTES) { + bytes_used = GENCGC_CARD_BYTES; more = 1; } page_table[next_page].bytes_used = bytes_used; @@ -1161,20 +1239,7 @@ gc_heap_exhausted_error_or_lose (long available, long requested) * the danger that we bounce back here before the error has been * handled, or indeed even printed. */ - fprintf(stderr, "Heap exhausted during %s: %ld bytes available, %ld requested.\n", - gc_active_p ? "garbage collection" : "allocation", - available, requested); - print_generation_stats(); - fprintf(stderr, "GC control variables:\n"); - fprintf(stderr, " *GC-INHIBIT* = %s\n *GC-PENDING* = %s\n", - SymbolValue(GC_INHIBIT,thread)==NIL ? "false" : "true", - (SymbolValue(GC_PENDING, thread) == T) ? - "true" : ((SymbolValue(GC_PENDING, thread) == NIL) ? - "false" : "in progress")); -#ifdef LISP_FEATURE_SB_THREAD - fprintf(stderr, " *STOP-FOR-GC-PENDING* = %s\n", - SymbolValue(STOP_FOR_GC_PENDING,thread)==NIL ? "false" : "true"); -#endif + report_heap_exhaustion(available, requested, thread); if (gc_active_p || (available == 0)) { /* If we are in GC, or totally out of memory there is no way * to sanely transfer control to the lisp-side of things. @@ -1203,89 +1268,95 @@ gc_heap_exhausted_error_or_lose (long available, long requested) } page_index_t -gc_find_freeish_pages(page_index_t *restart_page_ptr, long nbytes, +gc_find_freeish_pages(page_index_t *restart_page_ptr, long bytes, int page_type_flag) { - page_index_t first_page, last_page; - page_index_t restart_page = *restart_page_ptr; - long bytes_found = 0; - long most_bytes_found = 0; + page_index_t most_bytes_found_from = 0, most_bytes_found_to = 0; + page_index_t first_page, last_page, restart_page = *restart_page_ptr; + os_vm_size_t nbytes = bytes; + os_vm_size_t nbytes_goal = nbytes; + os_vm_size_t bytes_found = 0; + os_vm_size_t most_bytes_found = 0; + boolean small_object = nbytes < GENCGC_CARD_BYTES; /* FIXME: assert(free_pages_lock is held); */ + if (nbytes_goal < gencgc_alloc_granularity) + nbytes_goal = gencgc_alloc_granularity; + /* Toggled by gc_and_save for heap compaction, normally -1. */ if (gencgc_alloc_start_page != -1) { restart_page = gencgc_alloc_start_page; } - gc_assert(nbytes>=0); - if (((unsigned long)nbytes)>=PAGE_BYTES) { - /* Search for a contiguous free space of at least nbytes, - * aligned on a page boundary. The page-alignment is strictly - * speaking needed only for objects at least large_object_size - * bytes in size. */ - do { - first_page = restart_page; - while ((first_page < page_table_pages) && - page_allocated_p(first_page)) + /* FIXME: This is on bytes instead of nbytes pending cleanup of + * long from the interface. */ + gc_assert(bytes>=0); + /* Search for a page with at least nbytes of space. We prefer + * not to split small objects on multiple pages, to reduce the + * number of contiguous allocation regions spaning multiple + * pages: this helps avoid excessive conservativism. + * + * For other objects, we guarantee that they start on their own + * page boundary. + */ + first_page = restart_page; + while (first_page < page_table_pages) { + bytes_found = 0; + if (page_free_p(first_page)) { + gc_assert(0 == page_table[first_page].bytes_used); + bytes_found = GENCGC_CARD_BYTES; + } else if (small_object && + (page_table[first_page].allocated == page_type_flag) && + (page_table[first_page].large_object == 0) && + (page_table[first_page].gen == gc_alloc_generation) && + (page_table[first_page].write_protected == 0) && + (page_table[first_page].dont_move == 0)) { + bytes_found = GENCGC_CARD_BYTES - page_table[first_page].bytes_used; + if (bytes_found < nbytes) { + if (bytes_found > most_bytes_found) + most_bytes_found = bytes_found; first_page++; - - last_page = first_page; - bytes_found = PAGE_BYTES; - while ((bytes_found < nbytes) && - (last_page < (page_table_pages-1)) && - page_free_p(last_page+1)) { - last_page++; - bytes_found += PAGE_BYTES; - gc_assert(0 == page_table[last_page].bytes_used); - gc_assert(0 == page_table[last_page].write_protected); + continue; } - if (bytes_found > most_bytes_found) - most_bytes_found = bytes_found; - restart_page = last_page + 1; - } while ((restart_page < page_table_pages) && (bytes_found < nbytes)); - - } else { - /* Search for a page with at least nbytes of space. We prefer - * not to split small objects on multiple pages, to reduce the - * number of contiguous allocation regions spaning multiple - * pages: this helps avoid excessive conservativism. */ - first_page = restart_page; - while (first_page < page_table_pages) { - if (page_free_p(first_page)) - { - gc_assert(0 == page_table[first_page].bytes_used); - bytes_found = PAGE_BYTES; - break; - } - else if ((page_table[first_page].allocated == page_type_flag) && - (page_table[first_page].large_object == 0) && - (page_table[first_page].gen == gc_alloc_generation) && - (page_table[first_page].write_protected == 0) && - (page_table[first_page].dont_move == 0)) - { - bytes_found = PAGE_BYTES - - page_table[first_page].bytes_used; - if (bytes_found > most_bytes_found) - most_bytes_found = bytes_found; - if (bytes_found >= nbytes) - break; - } + } else { first_page++; + continue; } - last_page = first_page; - restart_page = first_page + 1; + + gc_assert(page_table[first_page].write_protected == 0); + for (last_page = first_page+1; + ((last_page < page_table_pages) && + page_free_p(last_page) && + (bytes_found < nbytes_goal)); + last_page++) { + bytes_found += GENCGC_CARD_BYTES; + gc_assert(0 == page_table[last_page].bytes_used); + gc_assert(0 == page_table[last_page].write_protected); + } + + if (bytes_found > most_bytes_found) { + most_bytes_found = bytes_found; + most_bytes_found_from = first_page; + most_bytes_found_to = last_page; + } + if (bytes_found >= nbytes_goal) + break; + + first_page = last_page; } + bytes_found = most_bytes_found; + restart_page = first_page + 1; + /* Check for a failure */ if (bytes_found < nbytes) { gc_assert(restart_page >= page_table_pages); gc_heap_exhausted_error_or_lose(most_bytes_found, nbytes); } - gc_assert(page_table[first_page].write_protected == 0); - - *restart_page_ptr = first_page; - return last_page; + gc_assert(most_bytes_found_to); + *restart_page_ptr = most_bytes_found_from; + return most_bytes_found_to-1; } /* Allocate bytes. All the rest of the special-purpose allocation @@ -1408,19 +1479,19 @@ copy_large_object(lispobj object, long nwords) next_page = first_page; remaining_bytes = nwords*N_WORD_BYTES; - while (remaining_bytes > PAGE_BYTES) { + while (remaining_bytes > GENCGC_CARD_BYTES) { gc_assert(page_table[next_page].gen == from_space); gc_assert(page_boxed_p(next_page)); gc_assert(page_table[next_page].large_object); gc_assert(page_table[next_page].region_start_offset == npage_bytes(next_page-first_page)); - gc_assert(page_table[next_page].bytes_used == PAGE_BYTES); + gc_assert(page_table[next_page].bytes_used == GENCGC_CARD_BYTES); /* Should have been unprotected by unprotect_oldspace(). */ gc_assert(page_table[next_page].write_protected == 0); page_table[next_page].gen = new_space; - remaining_bytes -= PAGE_BYTES; + remaining_bytes -= GENCGC_CARD_BYTES; next_page++; } @@ -1441,7 +1512,7 @@ copy_large_object(lispobj object, long nwords) /* Free any remaining pages; needs care. */ next_page++; - while ((old_bytes_used == PAGE_BYTES) && + while ((old_bytes_used == GENCGC_CARD_BYTES) && (page_table[next_page].gen == from_space) && page_boxed_p(next_page) && page_table[next_page].large_object && @@ -1550,17 +1621,17 @@ copy_large_unboxed_object(lispobj object, long nwords) next_page = first_page; remaining_bytes = nwords*N_WORD_BYTES; - while (remaining_bytes > PAGE_BYTES) { + while (remaining_bytes > GENCGC_CARD_BYTES) { gc_assert(page_table[next_page].gen == from_space); gc_assert(page_allocated_no_region_p(next_page)); gc_assert(page_table[next_page].large_object); gc_assert(page_table[next_page].region_start_offset == npage_bytes(next_page-first_page)); - gc_assert(page_table[next_page].bytes_used == PAGE_BYTES); + gc_assert(page_table[next_page].bytes_used == GENCGC_CARD_BYTES); page_table[next_page].gen = new_space; page_table[next_page].allocated = UNBOXED_PAGE_FLAG; - remaining_bytes -= PAGE_BYTES; + remaining_bytes -= GENCGC_CARD_BYTES; next_page++; } @@ -1581,7 +1652,7 @@ copy_large_unboxed_object(lispobj object, long nwords) /* Free any remaining pages; needs care. */ next_page++; - while ((old_bytes_used == PAGE_BYTES) && + while ((old_bytes_used == GENCGC_CARD_BYTES) && (page_table[next_page].gen == from_space) && page_allocated_no_region_p(next_page) && page_table[next_page].large_object && @@ -1961,181 +2032,6 @@ trans_unboxed_large(lispobj object) return copy_large_unboxed_object(object, length); } #endif - - -/* - * Lutexes. Using the normal finalization machinery for finalizing - * lutexes is tricky, since the finalization depends on working lutexes. - * So we track the lutexes in the GC and finalize them manually. - */ - -#if defined(LUTEX_WIDETAG) - -/* - * Start tracking LUTEX in the GC, by adding it to the linked list of - * lutexes in the nursery generation. The caller is responsible for - * locking, and GCs must be inhibited until the registration is - * complete. - */ -void -gencgc_register_lutex (struct lutex *lutex) { - int index = find_page_index(lutex); - generation_index_t gen; - struct lutex *head; - - /* This lutex is in static space, so we don't need to worry about - * finalizing it. - */ - if (index == -1) - return; - - gen = page_table[index].gen; - - gc_assert(gen >= 0); - gc_assert(gen < NUM_GENERATIONS); - - head = generations[gen].lutexes; - - lutex->gen = gen; - lutex->next = head; - lutex->prev = NULL; - if (head) - head->prev = lutex; - generations[gen].lutexes = lutex; -} - -/* - * Stop tracking LUTEX in the GC by removing it from the appropriate - * linked lists. This will only be called during GC, so no locking is - * needed. - */ -void -gencgc_unregister_lutex (struct lutex *lutex) { - if (lutex->prev) { - lutex->prev->next = lutex->next; - } else { - generations[lutex->gen].lutexes = lutex->next; - } - - if (lutex->next) { - lutex->next->prev = lutex->prev; - } - - lutex->next = NULL; - lutex->prev = NULL; - lutex->gen = -1; -} - -/* - * Mark all lutexes in generation GEN as not live. - */ -static void -unmark_lutexes (generation_index_t gen) { - struct lutex *lutex = generations[gen].lutexes; - - while (lutex) { - lutex->live = 0; - lutex = lutex->next; - } -} - -/* - * Finalize all lutexes in generation GEN that have not been marked live. - */ -static void -reap_lutexes (generation_index_t gen) { - struct lutex *lutex = generations[gen].lutexes; - - while (lutex) { - struct lutex *next = lutex->next; - if (!lutex->live) { - lutex_destroy((tagged_lutex_t) lutex); - gencgc_unregister_lutex(lutex); - } - lutex = next; - } -} - -/* - * Mark LUTEX as live. - */ -static void -mark_lutex (lispobj tagged_lutex) { - struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex); - - lutex->live = 1; -} - -/* - * Move all lutexes in generation FROM to generation TO. - */ -static void -move_lutexes (generation_index_t from, generation_index_t to) { - struct lutex *tail = generations[from].lutexes; - - /* Nothing to move */ - if (!tail) - return; - - /* Change the generation of the lutexes in FROM. */ - while (tail->next) { - tail->gen = to; - tail = tail->next; - } - tail->gen = to; - - /* Link the last lutex in the FROM list to the start of the TO list */ - tail->next = generations[to].lutexes; - - /* And vice versa */ - if (generations[to].lutexes) { - generations[to].lutexes->prev = tail; - } - - /* And update the generations structures to match this */ - generations[to].lutexes = generations[from].lutexes; - generations[from].lutexes = NULL; -} - -static long -scav_lutex(lispobj *where, lispobj object) -{ - mark_lutex((lispobj) where); - - return CEILING(sizeof(struct lutex)/sizeof(lispobj), 2); -} - -static lispobj -trans_lutex(lispobj object) -{ - struct lutex *lutex = (struct lutex *) native_pointer(object); - lispobj copied; - size_t words = CEILING(sizeof(struct lutex)/sizeof(lispobj), 2); - gc_assert(is_lisp_pointer(object)); - copied = copy_object(object, words); - - /* Update the links, since the lutex moved in memory. */ - if (lutex->next) { - lutex->next->prev = (struct lutex *) native_pointer(copied); - } - - if (lutex->prev) { - lutex->prev->next = (struct lutex *) native_pointer(copied); - } else { - generations[lutex->gen].lutexes = - (struct lutex *) native_pointer(copied); - } - - return copied; -} - -static long -size_lutex(lispobj *where) -{ - return CEILING(sizeof(struct lutex)/sizeof(lispobj), 2); -} -#endif /* LUTEX_WIDETAG */ - /* * weak pointers @@ -2217,310 +2113,6 @@ search_dynamic_space(void *pointer) (lispobj *)pointer)); } -/* Helper for valid_lisp_pointer_p and - * possibly_valid_dynamic_space_pointer. - * - * pointer is the pointer to validate, and start_addr is the address - * of the enclosing object. - */ -static int -looks_like_valid_lisp_pointer_p(lispobj *pointer, lispobj *start_addr) -{ - if (!is_lisp_pointer((lispobj)pointer)) { - return 0; - } - - /* Check that the object pointed to is consistent with the pointer - * low tag. */ - switch (lowtag_of((lispobj)pointer)) { - case FUN_POINTER_LOWTAG: - /* Start_addr should be the enclosing code object, or a closure - * header. */ - switch (widetag_of(*start_addr)) { - case CODE_HEADER_WIDETAG: - /* Make sure we actually point to a function in the code object, - * as opposed to a random point there. */ - if (SIMPLE_FUN_HEADER_WIDETAG==widetag_of(*(pointer-FUN_POINTER_LOWTAG))) - return 1; - else - return 0; - case CLOSURE_HEADER_WIDETAG: - case FUNCALLABLE_INSTANCE_HEADER_WIDETAG: - if ((unsigned long)pointer != - ((unsigned long)start_addr+FUN_POINTER_LOWTAG)) { - if (gencgc_verbose) { - FSHOW((stderr, - "/Wf2: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - break; - default: - if (gencgc_verbose) { - FSHOW((stderr, - "/Wf3: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - break; - case LIST_POINTER_LOWTAG: - if ((unsigned long)pointer != - ((unsigned long)start_addr+LIST_POINTER_LOWTAG)) { - if (gencgc_verbose) { - FSHOW((stderr, - "/Wl1: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - /* Is it plausible cons? */ - if ((is_lisp_pointer(start_addr[0]) || - is_lisp_immediate(start_addr[0])) && - (is_lisp_pointer(start_addr[1]) || - is_lisp_immediate(start_addr[1]))) - break; - else { - if (gencgc_verbose) { - FSHOW((stderr, - "/Wl2: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - case INSTANCE_POINTER_LOWTAG: - if ((unsigned long)pointer != - ((unsigned long)start_addr+INSTANCE_POINTER_LOWTAG)) { - if (gencgc_verbose) { - FSHOW((stderr, - "/Wi1: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - if (widetag_of(start_addr[0]) != INSTANCE_HEADER_WIDETAG) { - if (gencgc_verbose) { - FSHOW((stderr, - "/Wi2: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - break; - case OTHER_POINTER_LOWTAG: - -#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64) - /* The all-architecture test below is good as far as it goes, - * but an LRA object is similar to a FUN-POINTER: It is - * embedded within a CODE-OBJECT pointed to by start_addr, and - * cannot be found by simply walking the heap, therefore we - * need to check for it. -- AB, 2010-Jun-04 */ - if ((widetag_of(start_addr[0]) == CODE_HEADER_WIDETAG)) { - lispobj *potential_lra = - (lispobj *)(((unsigned long)pointer) - OTHER_POINTER_LOWTAG); - if ((widetag_of(potential_lra[0]) == RETURN_PC_HEADER_WIDETAG) && - ((potential_lra - HeaderValue(potential_lra[0])) == start_addr)) { - return 1; /* It's as good as we can verify. */ - } - } -#endif - - if ((unsigned long)pointer != - ((unsigned long)start_addr+OTHER_POINTER_LOWTAG)) { - if (gencgc_verbose) { - FSHOW((stderr, - "/Wo1: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - /* Is it plausible? Not a cons. XXX should check the headers. */ - if (is_lisp_pointer(start_addr[0]) || ((start_addr[0] & 3) == 0)) { - if (gencgc_verbose) { - FSHOW((stderr, - "/Wo2: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - switch (widetag_of(start_addr[0])) { - case UNBOUND_MARKER_WIDETAG: - case NO_TLS_VALUE_MARKER_WIDETAG: - case CHARACTER_WIDETAG: -#if N_WORD_BITS == 64 - case SINGLE_FLOAT_WIDETAG: -#endif - if (gencgc_verbose) { - FSHOW((stderr, - "*Wo3: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - - /* only pointed to by function pointers? */ - case CLOSURE_HEADER_WIDETAG: - case FUNCALLABLE_INSTANCE_HEADER_WIDETAG: - if (gencgc_verbose) { - FSHOW((stderr, - "*Wo4: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - - case INSTANCE_HEADER_WIDETAG: - if (gencgc_verbose) { - FSHOW((stderr, - "*Wo5: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - - /* the valid other immediate pointer objects */ - case SIMPLE_VECTOR_WIDETAG: - case RATIO_WIDETAG: - case COMPLEX_WIDETAG: -#ifdef COMPLEX_SINGLE_FLOAT_WIDETAG - case COMPLEX_SINGLE_FLOAT_WIDETAG: -#endif -#ifdef COMPLEX_DOUBLE_FLOAT_WIDETAG - case COMPLEX_DOUBLE_FLOAT_WIDETAG: -#endif -#ifdef COMPLEX_LONG_FLOAT_WIDETAG - case COMPLEX_LONG_FLOAT_WIDETAG: -#endif - case SIMPLE_ARRAY_WIDETAG: - case COMPLEX_BASE_STRING_WIDETAG: -#ifdef COMPLEX_CHARACTER_STRING_WIDETAG - case COMPLEX_CHARACTER_STRING_WIDETAG: -#endif - case COMPLEX_VECTOR_NIL_WIDETAG: - case COMPLEX_BIT_VECTOR_WIDETAG: - case COMPLEX_VECTOR_WIDETAG: - case COMPLEX_ARRAY_WIDETAG: - case VALUE_CELL_HEADER_WIDETAG: - case SYMBOL_HEADER_WIDETAG: - case FDEFN_WIDETAG: - case CODE_HEADER_WIDETAG: - case BIGNUM_WIDETAG: -#if N_WORD_BITS != 64 - case SINGLE_FLOAT_WIDETAG: -#endif - case DOUBLE_FLOAT_WIDETAG: -#ifdef LONG_FLOAT_WIDETAG - case LONG_FLOAT_WIDETAG: -#endif - case SIMPLE_BASE_STRING_WIDETAG: -#ifdef SIMPLE_CHARACTER_STRING_WIDETAG - case SIMPLE_CHARACTER_STRING_WIDETAG: -#endif - case SIMPLE_BIT_VECTOR_WIDETAG: - case SIMPLE_ARRAY_NIL_WIDETAG: - case SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG: - case SIMPLE_ARRAY_UNSIGNED_BYTE_4_WIDETAG: - case SIMPLE_ARRAY_UNSIGNED_BYTE_7_WIDETAG: - case SIMPLE_ARRAY_UNSIGNED_BYTE_8_WIDETAG: - case SIMPLE_ARRAY_UNSIGNED_BYTE_15_WIDETAG: - case SIMPLE_ARRAY_UNSIGNED_BYTE_16_WIDETAG: -#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_29_WIDETAG - case SIMPLE_ARRAY_UNSIGNED_BYTE_29_WIDETAG: -#endif - case SIMPLE_ARRAY_UNSIGNED_BYTE_31_WIDETAG: - case SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG: -#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG - case SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG - case SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_64_WIDETAG - case SIMPLE_ARRAY_UNSIGNED_BYTE_64_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_8_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_8_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_30_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_30_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG: -#endif - case SIMPLE_ARRAY_SINGLE_FLOAT_WIDETAG: - case SIMPLE_ARRAY_DOUBLE_FLOAT_WIDETAG: -#ifdef SIMPLE_ARRAY_LONG_FLOAT_WIDETAG - case SIMPLE_ARRAY_LONG_FLOAT_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_COMPLEX_SINGLE_FLOAT_WIDETAG - case SIMPLE_ARRAY_COMPLEX_SINGLE_FLOAT_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_COMPLEX_DOUBLE_FLOAT_WIDETAG - case SIMPLE_ARRAY_COMPLEX_DOUBLE_FLOAT_WIDETAG: -#endif -#ifdef SIMPLE_ARRAY_COMPLEX_LONG_FLOAT_WIDETAG - case SIMPLE_ARRAY_COMPLEX_LONG_FLOAT_WIDETAG: -#endif - case SAP_WIDETAG: - case WEAK_POINTER_WIDETAG: -#ifdef LUTEX_WIDETAG - case LUTEX_WIDETAG: -#endif - break; - - default: - if (gencgc_verbose) { - FSHOW((stderr, - "/Wo6: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - break; - default: - if (gencgc_verbose) { - FSHOW((stderr, - "*W?: %x %x %x\n", - pointer, start_addr, *start_addr)); - } - return 0; - } - - /* looks good */ - return 1; -} - -/* Used by the debugger to validate possibly bogus pointers before - * calling MAKE-LISP-OBJ on them. - * - * FIXME: We would like to make this perfect, because if the debugger - * constructs a reference to a bugs lisp object, and it ends up in a - * location scavenged by the GC all hell breaks loose. - * - * Whereas possibly_valid_dynamic_space_pointer has to be conservative - * and return true for all valid pointers, this could actually be eager - * and lie about a few pointers without bad results... but that should - * be reflected in the name. - */ -int -valid_lisp_pointer_p(lispobj *pointer) -{ - lispobj *start; - if (((start=search_dynamic_space(pointer))!=NULL) || - ((start=search_static_space(pointer))!=NULL) || - ((start=search_read_only_space(pointer))!=NULL)) - return looks_like_valid_lisp_pointer_p(pointer, start); - else - return 0; -} - #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) /* Is there any possibility that pointer is a valid Lisp object @@ -2580,14 +2172,11 @@ maybe_adjust_large_object(lispobj *where) case SIMPLE_ARRAY_UNSIGNED_BYTE_8_WIDETAG: case SIMPLE_ARRAY_UNSIGNED_BYTE_15_WIDETAG: case SIMPLE_ARRAY_UNSIGNED_BYTE_16_WIDETAG: -#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_29_WIDETAG - case SIMPLE_ARRAY_UNSIGNED_BYTE_29_WIDETAG: -#endif + + case SIMPLE_ARRAY_UNSIGNED_FIXNUM_WIDETAG: + case SIMPLE_ARRAY_UNSIGNED_BYTE_31_WIDETAG: case SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG: -#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG - case SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG: -#endif #ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG case SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG: #endif @@ -2600,15 +2189,12 @@ maybe_adjust_large_object(lispobj *where) #ifdef SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG case SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG: #endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_30_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_30_WIDETAG: -#endif + + case SIMPLE_ARRAY_FIXNUM_WIDETAG: + #ifdef SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG case SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG: #endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG: -#endif #ifdef SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG case SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG: #endif @@ -2648,20 +2234,20 @@ maybe_adjust_large_object(lispobj *where) next_page = first_page; remaining_bytes = nwords*N_WORD_BYTES; - while (remaining_bytes > PAGE_BYTES) { + while (remaining_bytes > GENCGC_CARD_BYTES) { gc_assert(page_table[next_page].gen == from_space); gc_assert(page_allocated_no_region_p(next_page)); gc_assert(page_table[next_page].large_object); gc_assert(page_table[next_page].region_start_offset == npage_bytes(next_page-first_page)); - gc_assert(page_table[next_page].bytes_used == PAGE_BYTES); + gc_assert(page_table[next_page].bytes_used == GENCGC_CARD_BYTES); page_table[next_page].allocated = boxed; /* Shouldn't be write-protected at this stage. Essential that the * pages aren't. */ gc_assert(!page_table[next_page].write_protected); - remaining_bytes -= PAGE_BYTES; + remaining_bytes -= GENCGC_CARD_BYTES; next_page++; } @@ -2683,7 +2269,7 @@ maybe_adjust_large_object(lispobj *where) /* Free any remaining pages; needs care. */ next_page++; - while ((old_bytes_used == PAGE_BYTES) && + while ((old_bytes_used == GENCGC_CARD_BYTES) && (page_table[next_page].gen == from_space) && page_allocated_no_region_p(next_page) && page_table[next_page].large_object && @@ -2751,7 +2337,7 @@ preserve_pointer(void *addr) /* quick check 2: Check the offset within the page. * */ - if (((unsigned long)addr & (PAGE_BYTES - 1)) > + if (((unsigned long)addr & (GENCGC_CARD_BYTES - 1)) > page_table[addr_page_index].bytes_used) return; @@ -2786,7 +2372,7 @@ preserve_pointer(void *addr) while (page_table[first_page].region_start_offset != 0) { --first_page; /* Do some checks. */ - gc_assert(page_table[first_page].bytes_used == PAGE_BYTES); + gc_assert(page_table[first_page].bytes_used == GENCGC_CARD_BYTES); gc_assert(page_table[first_page].gen == from_space); gc_assert(page_table[first_page].allocated == region_allocation); } @@ -2803,7 +2389,7 @@ preserve_pointer(void *addr) if (page_free_p(addr_page_index) || (page_table[addr_page_index].bytes_used == 0) /* Check the offset within the page. */ - || (((unsigned long)addr & (PAGE_BYTES - 1)) + || (((unsigned long)addr & (GENCGC_CARD_BYTES - 1)) > page_table[addr_page_index].bytes_used)) { FSHOW((stderr, "weird? ignore ptr 0x%x to freed area of large object\n", @@ -2837,8 +2423,8 @@ preserve_pointer(void *addr) gc_assert(!page_table[i].write_protected); /* Check whether this is the last page in this contiguous block.. */ - if ((page_table[i].bytes_used < PAGE_BYTES) - /* ..or it is PAGE_BYTES and is the last in the block */ + if ((page_table[i].bytes_used < GENCGC_CARD_BYTES) + /* ..or it is CARD_BYTES and is the last in the block */ || page_free_p(i+1) || (page_table[i+1].bytes_used == 0) /* next page free */ || (page_table[i+1].gen != from_space) /* diff. gen */ @@ -2913,7 +2499,7 @@ update_page_write_prot(page_index_t page) /*FSHOW((stderr, "/write-protecting page %d gen %d\n", page, gen));*/ os_protect((void *)page_addr, - PAGE_BYTES, + GENCGC_CARD_BYTES, OS_VM_PROT_READ|OS_VM_PROT_EXECUTE); /* Note the page as protected in the page tables. */ @@ -2956,7 +2542,7 @@ static void scavenge_generations(generation_index_t from, generation_index_t to) { page_index_t i; - int num_wp = 0; + page_index_t num_wp = 0; #define SC_GEN_CK 0 #if SC_GEN_CK @@ -2982,8 +2568,8 @@ scavenge_generations(generation_index_t from, generation_index_t to) for (last_page = i; ; last_page++) { write_protected = write_protected && page_table[last_page].write_protected; - if ((page_table[last_page].bytes_used < PAGE_BYTES) - /* Or it is PAGE_BYTES and is the last in the block */ + if ((page_table[last_page].bytes_used < GENCGC_CARD_BYTES) + /* Or it is CARD_BYTES and is the last in the block */ || (!page_boxed_p(last_page+1)) || (page_table[last_page+1].bytes_used == 0) || (page_table[last_page+1].gen != generation) @@ -3098,8 +2684,8 @@ scavenge_newspace_generation_one_scan(generation_index_t generation) /* Check whether this is the last page in this * contiguous block */ - if ((page_table[last_page].bytes_used < PAGE_BYTES) - /* Or it is PAGE_BYTES and is the last in the block */ + if ((page_table[last_page].bytes_used < GENCGC_CARD_BYTES) + /* Or it is CARD_BYTES and is the last in the block */ || (!page_boxed_p(last_page+1)) || (page_table[last_page+1].bytes_used == 0) || (page_table[last_page+1].gen != generation) @@ -3246,16 +2832,19 @@ scavenge_newspace_generation(generation_index_t generation) record_new_objects = 0; #if SC_NS_GEN_CK - /* Check that none of the write_protected pages in this generation - * have been written to. */ - for (i = 0; i < page_table_pages; i++) { - if (page_allocated_p(i) - && (page_table[i].bytes_used != 0) - && (page_table[i].gen == generation) - && (page_table[i].write_protected_cleared != 0) - && (page_table[i].dont_move == 0)) { - lose("write protected page %d written to in scavenge_newspace_generation\ngeneration=%d dont_move=%d\n", - i, generation, page_table[i].dont_move); + { + page_index_t i; + /* Check that none of the write_protected pages in this generation + * have been written to. */ + for (i = 0; i < page_table_pages; i++) { + if (page_allocated_p(i) + && (page_table[i].bytes_used != 0) + && (page_table[i].gen == generation) + && (page_table[i].write_protected_cleared != 0) + && (page_table[i].dont_move == 0)) { + lose("write protected page %d written to in scavenge_newspace_generation\ngeneration=%d dont_move=%d\n", + i, generation, page_table[i].dont_move); + } } } #endif @@ -3287,16 +2876,16 @@ unprotect_oldspace(void) if (!region_addr) { /* First region. */ region_addr = page_addr; - region_bytes = PAGE_BYTES; + region_bytes = GENCGC_CARD_BYTES; } else if (region_addr + region_bytes == page_addr) { /* Region continue. */ - region_bytes += PAGE_BYTES; + region_bytes += GENCGC_CARD_BYTES; } else { /* Unprotect previous region. */ os_protect(region_addr, region_bytes, OS_VM_PROT_ALL); /* First page in new region. */ region_addr = page_addr; - region_bytes = PAGE_BYTES; + region_bytes = GENCGC_CARD_BYTES; } } } @@ -3601,14 +3190,11 @@ verify_space(lispobj *start, size_t words) case SIMPLE_ARRAY_UNSIGNED_BYTE_8_WIDETAG: case SIMPLE_ARRAY_UNSIGNED_BYTE_15_WIDETAG: case SIMPLE_ARRAY_UNSIGNED_BYTE_16_WIDETAG: -#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_29_WIDETAG - case SIMPLE_ARRAY_UNSIGNED_BYTE_29_WIDETAG: -#endif + + case SIMPLE_ARRAY_UNSIGNED_FIXNUM_WIDETAG: + case SIMPLE_ARRAY_UNSIGNED_BYTE_31_WIDETAG: case SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG: -#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG - case SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG: -#endif #ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG case SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG: #endif @@ -3621,15 +3207,12 @@ verify_space(lispobj *start, size_t words) #ifdef SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG case SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG: #endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_30_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_30_WIDETAG: -#endif + + case SIMPLE_ARRAY_FIXNUM_WIDETAG: + #ifdef SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG case SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG: #endif -#ifdef SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG - case SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG: -#endif #ifdef SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG case SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG: #endif @@ -3649,9 +3232,6 @@ verify_space(lispobj *start, size_t words) #endif case SAP_WIDETAG: case WEAK_POINTER_WIDETAG: -#ifdef LUTEX_WIDETAG - case LUTEX_WIDETAG: -#endif #ifdef NO_TLS_VALUE_MARKER_WIDETAG case NO_TLS_VALUE_MARKER_WIDETAG: #endif @@ -3718,8 +3298,8 @@ verify_generation(generation_index_t generation) for (last_page = i; ;last_page++) /* Check whether this is the last page in this contiguous * block. */ - if ((page_table[last_page].bytes_used < PAGE_BYTES) - /* Or it is PAGE_BYTES and is the last in the block */ + if ((page_table[last_page].bytes_used < GENCGC_CARD_BYTES) + /* Or it is CARD_BYTES and is the last in the block */ || (page_table[last_page+1].allocated != region_allocation) || (page_table[last_page+1].bytes_used == 0) || (page_table[last_page+1].gen != generation) @@ -3754,7 +3334,7 @@ verify_zero_fill(void) } } } else { - long free_bytes = PAGE_BYTES - page_table[page].bytes_used; + long free_bytes = GENCGC_CARD_BYTES - page_table[page].bytes_used; if (free_bytes > 0) { long *start_addr = (long *)((unsigned long)page_address(page) + page_table[page].bytes_used); @@ -3910,10 +3490,6 @@ garbage_collect_generation(generation_index_t generation, int raise) /* Initialize the weak pointer list. */ weak_pointers = NULL; -#ifdef LUTEX_WIDETAG - unmark_lutexes(generation); -#endif - /* When a generation is not being raised it is transported to a * temporary generation (NUM_GENERATIONS), and lowered when * done. Set up this new generation. There should be no pages @@ -4062,7 +3638,7 @@ garbage_collect_generation(generation_index_t generation, int raise) scavenge((lispobj *) th->binding_stack_start,len); #ifdef LISP_FEATURE_SB_THREAD /* do the tls as well */ - len=fixnum_value(SymbolValue(FREE_TLS_INDEX,0)) - + len=(SymbolValue(FREE_TLS_INDEX,0) >> WORD_SHIFT) - (sizeof (struct thread))/(sizeof (lispobj)); scavenge((lispobj *) (th+1),len); #endif @@ -4119,8 +3695,8 @@ garbage_collect_generation(generation_index_t generation, int raise) /* As a check re-scavenge the newspace once; no new objects should * be found. */ { - long old_bytes_allocated = bytes_allocated; - long bytes_allocated; + os_vm_size_t old_bytes_allocated = bytes_allocated; + os_vm_size_t bytes_allocated; /* Start with a full scavenge. */ scavenge_newspace_generation_one_scan(new_space); @@ -4183,11 +3759,6 @@ garbage_collect_generation(generation_index_t generation, int raise) else ++generations[generation].num_gc; -#ifdef LUTEX_WIDETAG - reap_lutexes(generation); - if (raise) - move_lutexes(generation, generation+1); -#endif } /* Update last_free_page, then SymbolValue(ALLOCATION_POINTER). */ @@ -4207,32 +3778,54 @@ update_dynamic_space_free_pointer(void) } static void -remap_free_pages (page_index_t from, page_index_t to) +remap_page_range (page_index_t from, page_index_t to) +{ + /* There's a mysterious Solaris/x86 problem with using mmap + * tricks for memory zeroing. See sbcl-devel thread + * "Re: patch: standalone executable redux". + */ +#if defined(LISP_FEATURE_SUNOS) + zero_and_mark_pages(from, to); +#else + const page_index_t + release_granularity = gencgc_release_granularity/GENCGC_CARD_BYTES, + release_mask = release_granularity-1, + end = to+1, + aligned_from = (from+release_mask)&~release_mask, + aligned_end = (end&~release_mask); + + if (aligned_from < aligned_end) { + zero_pages_with_mmap(aligned_from, aligned_end-1); + if (aligned_from != from) + zero_and_mark_pages(from, aligned_from-1); + if (aligned_end != end) + zero_and_mark_pages(aligned_end, end-1); + } else { + zero_and_mark_pages(from, to); + } +#endif +} + +static void +remap_free_pages (page_index_t from, page_index_t to, int forcibly) { page_index_t first_page, last_page; + if (forcibly) + return remap_page_range(from, to); + for (first_page = from; first_page <= to; first_page++) { if (page_allocated_p(first_page) || - (page_table[first_page].need_to_zero == 0)) { + (page_table[first_page].need_to_zero == 0)) continue; - } last_page = first_page + 1; while (page_free_p(last_page) && - (last_page < to) && - (page_table[last_page].need_to_zero == 1)) { + (last_page <= to) && + (page_table[last_page].need_to_zero == 1)) last_page++; - } - /* There's a mysterious Solaris/x86 problem with using mmap - * tricks for memory zeroing. See sbcl-devel thread - * "Re: patch: standalone executable redux". - */ -#if defined(LISP_FEATURE_SUNOS) - zero_pages(first_page, last_page-1); -#else - zero_pages_with_mmap(first_page, last_page-1); -#endif + remap_page_range(first_page, last_page-1); first_page = last_page; } @@ -4259,6 +3852,7 @@ collect_garbage(generation_index_t last_gen) static page_index_t high_water_mark = 0; FSHOW((stderr, "/entering collect_garbage(%d)\n", last_gen)); + log_generation_stats(gc_logfile, "=== GC Start ==="); gc_active_p = 1; @@ -4377,12 +3971,13 @@ collect_garbage(generation_index_t last_gen) if (gen > small_generation_limit) { if (last_free_page > high_water_mark) high_water_mark = last_free_page; - remap_free_pages(0, high_water_mark); + remap_free_pages(0, high_water_mark, 0); high_water_mark = 0; } gc_active_p = 0; + log_generation_stats(gc_logfile, "=== GC End ==="); SHOW("returning from collect_garbage"); } @@ -4394,7 +3989,7 @@ collect_garbage(generation_index_t last_gen) void gc_free_heap(void) { - page_index_t page; + page_index_t page, last_page; if (gencgc_verbose > 1) { SHOW("entering gc_free_heap"); @@ -4403,34 +3998,26 @@ gc_free_heap(void) for (page = 0; page < page_table_pages; page++) { /* Skip free pages which should already be zero filled. */ if (page_allocated_p(page)) { - void *page_start, *addr; - - /* Mark the page free. The other slots are assumed invalid - * when it is a FREE_PAGE_FLAG and bytes_used is 0 and it - * should not be write-protected -- except that the - * generation is used for the current region but it sets - * that up. */ - page_table[page].allocated = FREE_PAGE_FLAG; - page_table[page].bytes_used = 0; + void *page_start; + for (last_page = page; + (last_page < page_table_pages) && page_allocated_p(last_page); + last_page++) { + /* Mark the page free. The other slots are assumed invalid + * when it is a FREE_PAGE_FLAG and bytes_used is 0 and it + * should not be write-protected -- except that the + * generation is used for the current region but it sets + * that up. */ + page_table[page].allocated = FREE_PAGE_FLAG; + page_table[page].bytes_used = 0; + page_table[page].write_protected = 0; + } #ifndef LISP_FEATURE_WIN32 /* Pages already zeroed on win32? Not sure * about this change. */ - /* Zero the page. */ page_start = (void *)page_address(page); - - /* First, remove any write-protection. */ - os_protect(page_start, PAGE_BYTES, OS_VM_PROT_ALL); - page_table[page].write_protected = 0; - - os_invalidate(page_start,PAGE_BYTES); - addr = os_validate(page_start,PAGE_BYTES); - if (addr == NULL || addr != page_start) { - lose("gc_free_heap: page moved, 0x%08x ==> 0x%08x\n", - page_start, - addr); - } -#else - page_table[page].write_protected = 0; + os_protect(page_start, npage_bytes(last_page-page), OS_VM_PROT_ALL); + remap_free_pages(page, last_page-1, 1); + page = last_page-1; #endif } else if (gencgc_zero_check_during_free_heap) { /* Double-check that the page is zero filled. */ @@ -4439,7 +4026,7 @@ gc_free_heap(void) gc_assert(page_free_p(page)); gc_assert(page_table[page].bytes_used == 0); page_start = (long *)page_address(page); - for (i=0; i<1024; i++) { + for (i=0; i 1) @@ -4488,9 +4074,15 @@ gc_init(void) /* Compute the number of pages needed for the dynamic space. * Dynamic space size should be aligned on page size. */ - page_table_pages = dynamic_space_size/PAGE_BYTES; + page_table_pages = dynamic_space_size/GENCGC_CARD_BYTES; gc_assert(dynamic_space_size == npage_bytes(page_table_pages)); + /* Default nursery size to 5% of the total dynamic space size, + * min 1Mb. */ + bytes_consed_between_gcs = dynamic_space_size/(os_vm_size_t)20; + if (bytes_consed_between_gcs < (1024*1024)) + bytes_consed_between_gcs = 1024*1024; + /* The page_table must be allocated using "calloc" to initialize * the page structures correctly. There used to be a separate * initialization loop (now commented out; see below) but that was @@ -4502,12 +4094,6 @@ gc_init(void) scavtab[WEAK_POINTER_WIDETAG] = scav_weak_pointer; transother[SIMPLE_ARRAY_WIDETAG] = trans_boxed_large; -#ifdef LUTEX_WIDETAG - scavtab[LUTEX_WIDETAG] = scav_lutex; - transother[LUTEX_WIDETAG] = trans_lutex; - sizetab[LUTEX_WIDETAG] = size_lutex; -#endif - heap_base = (void*)DYNAMIC_SPACE_START; /* The page structures are initialized implicitly when page_table @@ -4559,10 +4145,9 @@ gc_init(void) generations[i].num_gc = 0; generations[i].cum_sum_bytes_allocated = 0; /* the tune-able parameters */ - generations[i].bytes_consed_between_gc = 2000000; + generations[i].bytes_consed_between_gc = bytes_consed_between_gcs; generations[i].number_of_gcs_before_promotion = 1; generations[i].minimum_age_before_gc = 0.75; - generations[i].lutexes = NULL; } /* Initialize gc_alloc. */ @@ -4592,7 +4177,7 @@ gencgc_pickup_dynamic(void) /* It is possible, though rare, for the saved page table * to contain free pages below alloc_ptr. */ page_table[page].gen = gen; - page_table[page].bytes_used = PAGE_BYTES; + page_table[page].bytes_used = GENCGC_CARD_BYTES; page_table[page].large_object = 0; page_table[page].write_protected = 0; page_table[page].write_protected_cleared = 0; @@ -4611,13 +4196,6 @@ gencgc_pickup_dynamic(void) page++; } while (page_address(page) < alloc_ptr); -#ifdef LUTEX_WIDETAG - /* Lutexes have been registered in generation 0 by coreparse, and - * need to be moved to the right one manually. - */ - move_lutexes(0, PSEUDO_STATIC_GENERATION); -#endif - last_free_page = page; generations[gen].bytes_allocated = npage_bytes(page); @@ -4794,7 +4372,7 @@ gencgc_handle_wp_violation(void* fault_addr) gc_assert(ret == 0); if (page_table[page_index].write_protected) { /* Unprotect the page. */ - os_protect(page_address(page_index), PAGE_BYTES, OS_VM_PROT_ALL); + os_protect(page_address(page_index), GENCGC_CARD_BYTES, OS_VM_PROT_ALL); page_table[page_index].write_protected_cleared = 1; page_table[page_index].write_protected = 0; } else { @@ -4852,7 +4430,7 @@ zero_all_free_pages() if (page_free_p(i)) { #ifdef READ_PROTECT_FREE_PAGES os_protect(page_address(i), - PAGE_BYTES, + GENCGC_CARD_BYTES, OS_VM_PROT_ALL); #endif zero_pages(i, i); @@ -4890,7 +4468,8 @@ prepare_for_final_gc () * SB!VM:RESTART-LISP-FUNCTION */ void gc_and_save(char *filename, boolean prepend_runtime, - boolean save_runtime_options) + boolean save_runtime_options, + boolean compressed, int compression_level) { FILE *file; void *runtime_bytes = NULL; @@ -4925,7 +4504,8 @@ gc_and_save(char *filename, boolean prepend_runtime, /* The dumper doesn't know that pages need to be zeroed before use. */ zero_all_free_pages(); save_to_filehandle(file, filename, SymbolValue(RESTART_LISP_FUNCTION,0), - prepend_runtime, save_runtime_options); + prepend_runtime, save_runtime_options, + compressed ? compression_level : COMPRESSION_LEVEL_NONE); /* Oops. Save still managed to fail. Since we've mangled the stack * beyond hope, there's not much we can do. * (beyond FUNCALLing RESTART_LISP_FUNCTION, but I suspect that's