X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fgencgc.c;h=1d143c862ac30846a95d763ceb611f32a11623f3;hb=5a942de4c3645c0c63a262eb7b825a9843e96372;hp=18687975ce20bc096c1f60ce14c38d372a3f76ff;hpb=ba12c5c0420f28250ef4931b47af92c6d7963195;p=sbcl.git diff --git a/src/runtime/gencgc.c b/src/runtime/gencgc.c index 1868797..1d143c8 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); @@ -82,13 +79,16 @@ 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; +os_vm_size_t 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; +os_vm_size_t large_object_size = 4 * GENCGC_CARD_BYTES; #else -long large_object_size = 4 * PAGE_BYTES; +os_vm_size_t large_object_size = 4 * PAGE_BYTES; #endif +/* Largest allocation seen since last GC. */ +os_vm_size_t large_allocation = 0; + /* * debugging @@ -152,8 +152,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. */ @@ -248,17 +248,17 @@ find_page_index(void *addr) 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)*GENCGC_CARD_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 * X in bytes. */ -static inline -size_t void_diff(void *x, void *y) +static inline os_vm_size_t +void_diff(void *x, void *y) { gc_assert(x >= y); return (pointer_sized_uint_t)x - (pointer_sized_uint_t)y; @@ -288,13 +288,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; @@ -308,20 +308,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 @@ -361,11 +353,11 @@ static pthread_mutex_t free_pages_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t allocation_lock = PTHREAD_MUTEX_INITIALIZER; #endif -extern unsigned long gencgc_release_granularity; -unsigned long gencgc_release_granularity = GENCGC_RELEASE_GRANULARITY; +extern os_vm_size_t gencgc_release_granularity; +os_vm_size_t gencgc_release_granularity = GENCGC_RELEASE_GRANULARITY; -extern unsigned long gencgc_alloc_granularity; -unsigned long gencgc_alloc_granularity = GENCGC_ALLOC_GRANULARITY; +extern os_vm_size_t gencgc_alloc_granularity; +os_vm_size_t gencgc_alloc_granularity = GENCGC_ALLOC_GRANULARITY; /* @@ -374,11 +366,10 @@ unsigned long gencgc_alloc_granularity = GENCGC_ALLOC_GRANULARITY; /* 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) @@ -389,11 +380,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) @@ -403,11 +394,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)) { @@ -420,11 +411,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)) @@ -468,11 +459,11 @@ write_generation_stats(FILE *file) 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) { @@ -499,27 +490,31 @@ write_generation_stats(FILE *file) gc_assert(generations[i].bytes_allocated == count_generation_bytes_allocated(i)); fprintf(file, - " %1d: %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %8ld %5ld %8ld %4ld %3d %7.4f\n", + " %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(file," Total bytes allocated = %lu\n", bytes_allocated); - fprintf(file," Dynamic-space-size bytes = %lu\n", (unsigned long)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); } @@ -598,9 +593,9 @@ 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; @@ -797,7 +792,7 @@ gc_alloc_new_region(long nbytes, int page_type_flag, struct alloc_region *alloc_ { page_index_t first_page; page_index_t last_page; - unsigned long bytes_found; + os_vm_size_t bytes_found; page_index_t i; int ret; @@ -880,15 +875,11 @@ gc_alloc_new_region(long nbytes, int page_type_flag, struct alloc_region *alloc_ /* we can do this after releasing free_pages_lock */ if (gencgc_zero_check) { - long *p; - for (p = (long *)alloc_region->start_addr; - p < (long *)alloc_region->end_addr; p++) { + word_t *p; + for (p = (word_t *)alloc_region->start_addr; + p < (word_t *)alloc_region->end_addr; p++) { if (*p != 0) { - /* KLUDGE: It would be nice to use %lx and explicit casts - * (long) in code like this, so that it is less likely to - * break randomly when running on a machine with different - * word sizes. -- WHN 19991129 */ - lose("The new region at %x is not zero (start=%p, end=%p).\n", + lose("The new region is not zero at %p (start=%p, end=%p).\n", p, alloc_region->start_addr, alloc_region->end_addr); } } @@ -919,15 +910,14 @@ struct new_area { size_t size; }; static struct new_area (*new_areas)[]; -static long new_areas_index; -long max_new_areas; +static size_t new_areas_index; +size_t max_new_areas; /* Add a new area to new_areas. */ static void add_new_area(page_index_t first_page, size_t offset, size_t size) { - unsigned long new_area_start,c; - long i; + size_t new_area_start, c, i; /* Ignore if full. */ if (new_areas_index >= NUM_NEW_AREAS) @@ -951,7 +941,7 @@ add_new_area(page_index_t first_page, size_t offset, size_t size) /* Search backwards for a prior area that this follows from. If found this will save adding a new area. */ for (i = new_areas_index-1, c = 0; (i >= 0) && (c < 8); i--, c++) { - unsigned long area_end = + size_t area_end = npage_bytes((*new_areas)[i].page) + (*new_areas)[i].offset + (*new_areas)[i].size; @@ -996,13 +986,13 @@ add_new_area(page_index_t first_page, size_t offset, size_t size) void gc_alloc_update_page_tables(int page_type_flag, struct alloc_region *alloc_region) { - int more; + boolean more; page_index_t first_page; page_index_t next_page; - unsigned long bytes_used; - unsigned long orig_first_page_bytes_used; - unsigned long region_size; - unsigned long byte_cnt; + os_vm_size_t bytes_used; + os_vm_size_t region_size; + os_vm_size_t byte_cnt; + page_bytes_t orig_first_page_bytes_used; int ret; @@ -1128,13 +1118,11 @@ static inline void *gc_quick_alloc(long nbytes); void * gc_alloc_large(long nbytes, int page_type_flag, struct alloc_region *alloc_region) { - page_index_t first_page; - page_index_t last_page; - int orig_first_page_bytes_used; - long byte_cnt; - int more; - unsigned long bytes_used; - page_index_t next_page; + boolean more; + page_index_t first_page, next_page, last_page; + page_bytes_t orig_first_page_bytes_used; + os_vm_size_t byte_cnt; + os_vm_size_t bytes_used; int ret; ret = thread_mutex_lock(&free_pages_lock); @@ -1276,27 +1264,29 @@ 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 nbytes_goal = nbytes; - long bytes_found = 0; - long most_bytes_found = 0; - page_index_t most_bytes_found_from, most_bytes_found_to; - int small_object = nbytes < GENCGC_CARD_BYTES; + 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; + 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); + /* 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 @@ -1360,6 +1350,7 @@ gc_find_freeish_pages(page_index_t *restart_page_ptr, long nbytes, gc_heap_exhausted_error_or_lose(most_bytes_found, nbytes); } + gc_assert(most_bytes_found_to); *restart_page_ptr = most_bytes_found_from; return most_bytes_found_to-1; } @@ -1419,12 +1410,6 @@ gc_quick_alloc(long nbytes) } static inline void * -gc_quick_alloc_large(long nbytes) -{ - return gc_general_alloc(nbytes, BOXED_PAGE_FLAG ,ALLOC_QUICK); -} - -static inline void * gc_alloc_unboxed(long nbytes) { return gc_general_alloc(nbytes, UNBOXED_PAGE_FLAG, 0); @@ -1435,166 +1420,15 @@ gc_quick_alloc_unboxed(long nbytes) { return gc_general_alloc(nbytes, UNBOXED_PAGE_FLAG, ALLOC_QUICK); } - -static inline void * -gc_quick_alloc_large_unboxed(long nbytes) -{ - return gc_general_alloc(nbytes, UNBOXED_PAGE_FLAG, ALLOC_QUICK); -} - -/* Copy a large boxed object. If the object is in a large object - * region then it is simply promoted, else it is copied. If it's large - * enough then it's copied to a large object region. - * - * Vectors may have shrunk. If the object is not copied the space - * needs to be reclaimed, and the page_tables corrected. */ -lispobj -copy_large_object(lispobj object, long nwords) -{ - int tag; - lispobj *new; - page_index_t first_page; - - gc_assert(is_lisp_pointer(object)); - gc_assert(from_space_p(object)); - gc_assert((nwords & 0x01) == 0); - - - /* Check whether it's in a large object region. */ - first_page = find_page_index((void *)object); - gc_assert(first_page >= 0); - - if (page_table[first_page].large_object) { - - /* Promote the object. */ - - unsigned long remaining_bytes; - page_index_t next_page; - unsigned long bytes_freed; - unsigned long old_bytes_used; - - /* Note: Any page write-protection must be removed, else a - * later scavenge_newspace may incorrectly not scavenge these - * pages. This would not be necessary if they are added to the - * new areas, but let's do it for them all (they'll probably - * be written anyway?). */ - - gc_assert(page_table[first_page].region_start_offset == 0); - - next_page = first_page; - remaining_bytes = nwords*N_WORD_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 == 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 -= GENCGC_CARD_BYTES; - next_page++; - } - - /* Now only one page remains, but the object may have shrunk - * so there may be more unused pages which will be freed. */ - - /* The object may have shrunk but shouldn't have grown. */ - gc_assert(page_table[next_page].bytes_used >= remaining_bytes); - - page_table[next_page].gen = new_space; - gc_assert(page_boxed_p(next_page)); - - /* Adjust the bytes_used. */ - old_bytes_used = page_table[next_page].bytes_used; - page_table[next_page].bytes_used = remaining_bytes; - - bytes_freed = old_bytes_used - remaining_bytes; - - /* Free any remaining pages; needs care. */ - next_page++; - 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 && - (page_table[next_page].region_start_offset == - npage_bytes(next_page - first_page))) { - /* Checks out OK, free the page. Don't need to bother zeroing - * pages as this should have been done before shrinking the - * object. These pages shouldn't be write-protected as they - * should be zero filled. */ - gc_assert(page_table[next_page].write_protected == 0); - - old_bytes_used = page_table[next_page].bytes_used; - page_table[next_page].allocated = FREE_PAGE_FLAG; - page_table[next_page].bytes_used = 0; - bytes_freed += old_bytes_used; - next_page++; - } - - generations[from_space].bytes_allocated -= N_WORD_BYTES*nwords - + bytes_freed; - generations[new_space].bytes_allocated += N_WORD_BYTES*nwords; - bytes_allocated -= bytes_freed; - - /* Add the region to the new_areas if requested. */ - add_new_area(first_page,0,nwords*N_WORD_BYTES); - - return(object); - } else { - /* Get tag of object. */ - tag = lowtag_of(object); - - /* Allocate space. */ - new = gc_quick_alloc_large(nwords*N_WORD_BYTES); - - memcpy(new,native_pointer(object),nwords*N_WORD_BYTES); - - /* Return Lisp pointer of new object. */ - return ((lispobj) new) | tag; - } -} - -/* to copy unboxed objects */ -lispobj -copy_unboxed_object(lispobj object, long nwords) -{ - long tag; - lispobj *new; - - gc_assert(is_lisp_pointer(object)); - gc_assert(from_space_p(object)); - gc_assert((nwords & 0x01) == 0); - - /* Get tag of object. */ - tag = lowtag_of(object); - - /* Allocate space. */ - new = gc_quick_alloc_unboxed(nwords*N_WORD_BYTES); - - memcpy(new,native_pointer(object),nwords*N_WORD_BYTES); - - /* Return Lisp pointer of new object. */ - return ((lispobj) new) | tag; -} - -/* to copy large unboxed objects - * - * If the object is in a large object region then it is simply - * promoted, else it is copied. If it's large enough then it's copied - * to a large object region. +/* Copy a large object. If the object is in a large object region then + * it is simply promoted, else it is copied. If it's large enough then + * it's copied to a large object region. * * Bignums and vectors may have shrunk. If the object is not copied - * the space needs to be reclaimed, and the page_tables corrected. - * - * KLUDGE: There's a lot of cut-and-paste duplication between this - * function and copy_large_object(..). -- WHN 20000619 */ -lispobj -copy_large_unboxed_object(lispobj object, long nwords) + * the space needs to be reclaimed, and the page_tables corrected. */ +static lispobj +general_copy_large_object(lispobj object, long nwords, boolean boxedp) { int tag; lispobj *new; @@ -1605,7 +1439,7 @@ copy_large_unboxed_object(lispobj object, long nwords) gc_assert((nwords & 0x01) == 0); if ((nwords > 1024*1024) && gencgc_verbose) { - FSHOW((stderr, "/copy_large_unboxed_object: %d bytes\n", + FSHOW((stderr, "/general_copy_large_object: %d bytes\n", nwords*N_WORD_BYTES)); } @@ -1617,25 +1451,42 @@ copy_large_unboxed_object(lispobj object, long nwords) /* Promote the object. Note: Unboxed objects may have been * allocated to a BOXED region so it may be necessary to * change the region to UNBOXED. */ - unsigned long remaining_bytes; + os_vm_size_t remaining_bytes; + os_vm_size_t bytes_freed; page_index_t next_page; - unsigned long bytes_freed; - unsigned long old_bytes_used; + page_bytes_t old_bytes_used; - gc_assert(page_table[first_page].region_start_offset == 0); + /* FIXME: This comment is somewhat stale. + * + * Note: Any page write-protection must be removed, else a + * later scavenge_newspace may incorrectly not scavenge these + * pages. This would not be necessary if they are added to the + * new areas, but let's do it for them all (they'll probably + * be written anyway?). */ + gc_assert(page_table[first_page].region_start_offset == 0); next_page = first_page; remaining_bytes = nwords*N_WORD_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 == GENCGC_CARD_BYTES); - + /* Should have been unprotected by unprotect_oldspace() + * for boxed objects, and after promotion unboxed ones + * should not be on protected pages at all. */ + gc_assert(!page_table[next_page].write_protected); + + if (boxedp) + gc_assert(page_boxed_p(next_page)); + else { + gc_assert(page_allocated_no_region_p(next_page)); + page_table[next_page].allocated = UNBOXED_PAGE_FLAG; + } page_table[next_page].gen = new_space; - page_table[next_page].allocated = UNBOXED_PAGE_FLAG; + remaining_bytes -= GENCGC_CARD_BYTES; next_page++; } @@ -1647,7 +1498,11 @@ copy_large_unboxed_object(lispobj object, long nwords) gc_assert(page_table[next_page].bytes_used >= remaining_bytes); page_table[next_page].gen = new_space; - page_table[next_page].allocated = UNBOXED_PAGE_FLAG; + + if (boxedp) + gc_assert(page_boxed_p(next_page)); + else + page_table[next_page].allocated = UNBOXED_PAGE_FLAG; /* Adjust the bytes_used. */ old_bytes_used = page_table[next_page].bytes_used; @@ -1659,7 +1514,14 @@ copy_large_unboxed_object(lispobj object, long nwords) next_page++; while ((old_bytes_used == GENCGC_CARD_BYTES) && (page_table[next_page].gen == from_space) && - page_allocated_no_region_p(next_page) && + /* FIXME: It is not obvious to me why this is necessary + * as a loop condition: it seems to me that the + * region_start_offset test should be sufficient, but + * experimentally that is not the case. --NS + * 2011-11-28 */ + (boxedp ? + page_boxed_p(next_page) : + page_allocated_no_region_p(next_page)) && page_table[next_page].large_object && (page_table[next_page].region_start_offset == npage_bytes(next_page - first_page))) { @@ -1678,23 +1540,29 @@ copy_large_unboxed_object(lispobj object, long nwords) if ((bytes_freed > 0) && gencgc_verbose) { FSHOW((stderr, - "/copy_large_unboxed bytes_freed=%d\n", + "/general_copy_large_object bytes_freed=%"OS_VM_SIZE_FMT"\n", bytes_freed)); } - generations[from_space].bytes_allocated -= - nwords*N_WORD_BYTES + bytes_freed; + generations[from_space].bytes_allocated -= nwords*N_WORD_BYTES + + bytes_freed; generations[new_space].bytes_allocated += nwords*N_WORD_BYTES; bytes_allocated -= bytes_freed; + /* Add the region to the new_areas if requested. */ + if (boxedp) + add_new_area(first_page,0,nwords*N_WORD_BYTES); + return(object); - } - else { + + } else { /* Get tag of object. */ tag = lowtag_of(object); /* Allocate space. */ - new = gc_quick_alloc_large_unboxed(nwords*N_WORD_BYTES); + new = gc_general_alloc(nwords*N_WORD_BYTES, + (boxedp ? BOXED_PAGE_FLAG : UNBOXED_PAGE_FLAG), + ALLOC_QUICK); /* Copy the object. */ memcpy(new,native_pointer(object),nwords*N_WORD_BYTES); @@ -1704,8 +1572,24 @@ copy_large_unboxed_object(lispobj object, long nwords) } } +lispobj +copy_large_object(lispobj object, long nwords) +{ + return general_copy_large_object(object, nwords, 1); +} +lispobj +copy_large_unboxed_object(lispobj object, long nwords) +{ + return general_copy_large_object(object, nwords, 0); +} +/* to copy unboxed objects */ +lispobj +copy_unboxed_object(lispobj object, long nwords) +{ + return gc_general_copy_object(object, nwords, UNBOXED_PAGE_FLAG); +} /* @@ -1726,13 +1610,13 @@ static lispobj trans_boxed(lispobj object); * Currently only absolute fixups to the constant vector, or to the * code area are checked. */ void -sniff_code_object(struct code *code, unsigned long displacement) +sniff_code_object(struct code *code, os_vm_size_t displacement) { #ifdef LISP_FEATURE_X86 long nheader_words, ncode_words, nwords; - void *p; - void *constants_start_addr = NULL, *constants_end_addr; - void *code_start_addr, *code_end_addr; + os_vm_address_t constants_start_addr = NULL, constants_end_addr, p; + os_vm_address_t code_start_addr, code_end_addr; + os_vm_address_t code_addr = (os_vm_address_t)code; int fixup_found = 0; if (!check_code_fixups) @@ -1744,10 +1628,10 @@ sniff_code_object(struct code *code, unsigned long displacement) nheader_words = HeaderValue(*(lispobj *)code); nwords = ncode_words + nheader_words; - constants_start_addr = (void *)code + 5*N_WORD_BYTES; - constants_end_addr = (void *)code + nheader_words*N_WORD_BYTES; - code_start_addr = (void *)code + nheader_words*N_WORD_BYTES; - code_end_addr = (void *)code + nwords*N_WORD_BYTES; + constants_start_addr = code_addr + 5*N_WORD_BYTES; + constants_end_addr = code_addr + nheader_words*N_WORD_BYTES; + code_start_addr = code_addr + nheader_words*N_WORD_BYTES; + code_end_addr = code_addr + nwords*N_WORD_BYTES; /* Work through the unboxed code. */ for (p = code_start_addr; p < code_end_addr; p++) { @@ -1764,8 +1648,8 @@ sniff_code_object(struct code *code, unsigned long displacement) /* Check for code references. */ /* Check for a 32 bit word that looks like an absolute reference to within the code adea of the code object. */ - if ((data >= (code_start_addr-displacement)) - && (data < (code_end_addr-displacement))) { + if ((data >= (void*)(code_start_addr-displacement)) + && (data < (void*)(code_end_addr-displacement))) { /* function header */ if ((d4 == 0x5e) && (((unsigned)p - 4 - 4*HeaderValue(*((unsigned *)p-1))) == @@ -1807,8 +1691,8 @@ sniff_code_object(struct code *code, unsigned long displacement) /* Check for a 32 bit word that looks like an absolute reference to within the constant vector. Constant references will be aligned. */ - if ((data >= (constants_start_addr-displacement)) - && (data < (constants_end_addr-displacement)) + if ((data >= (void*)(constants_start_addr-displacement)) + && (data < (void*)(constants_end_addr-displacement)) && (((unsigned)data & 0x3) == 0)) { /* Mov eax,m32 */ if (d1 == 0xa1) { @@ -1906,11 +1790,12 @@ gencgc_apply_code_fixups(struct code *old_code, struct code *new_code) /* x86-64 uses pc-relative addressing instead of this kludge */ #ifndef LISP_FEATURE_X86_64 long nheader_words, ncode_words, nwords; - void *constants_start_addr, *constants_end_addr; - void *code_start_addr, *code_end_addr; + os_vm_address_t constants_start_addr, constants_end_addr; + os_vm_address_t code_start_addr, code_end_addr; + os_vm_address_t code_addr = (os_vm_address_t)new_code; + os_vm_address_t old_addr = (os_vm_address_t)old_code; + os_vm_size_t displacement = code_addr - old_addr; lispobj fixups = NIL; - unsigned long displacement = - (unsigned long)new_code - (unsigned long)old_code; struct vector *fixups_vector; ncode_words = fixnum_value(new_code->code_size); @@ -1919,10 +1804,10 @@ gencgc_apply_code_fixups(struct code *old_code, struct code *new_code) /* FSHOW((stderr, "/compiled code object at %x: header words = %d, code words = %d\n", new_code, nheader_words, ncode_words)); */ - constants_start_addr = (void *)new_code + 5*N_WORD_BYTES; - constants_end_addr = (void *)new_code + nheader_words*N_WORD_BYTES; - code_start_addr = (void *)new_code + nheader_words*N_WORD_BYTES; - code_end_addr = (void *)new_code + nwords*N_WORD_BYTES; + constants_start_addr = code_addr + 5*N_WORD_BYTES; + constants_end_addr = code_addr + nheader_words*N_WORD_BYTES; + code_start_addr = code_addr + nheader_words*N_WORD_BYTES; + code_end_addr = code_addr + nwords*N_WORD_BYTES; /* FSHOW((stderr, "/const start = %x, end = %x\n", @@ -1970,24 +1855,22 @@ gencgc_apply_code_fixups(struct code *old_code, struct code *new_code) long length = fixnum_value(fixups_vector->length); long i; for (i = 0; i < length; i++) { - unsigned long offset = fixups_vector->data[i]; + long offset = fixups_vector->data[i]; /* Now check the current value of offset. */ - unsigned long old_value = - *(unsigned long *)((unsigned long)code_start_addr + offset); + os_vm_address_t old_value = *(os_vm_address_t *)(code_start_addr + offset); /* If it's within the old_code object then it must be an * absolute fixup (relative ones are not saved) */ - if ((old_value >= (unsigned long)old_code) - && (old_value < ((unsigned long)old_code - + nwords*N_WORD_BYTES))) + if ((old_value >= old_addr) + && (old_value < (old_addr + nwords*N_WORD_BYTES))) /* So add the dispacement. */ - *(unsigned long *)((unsigned long)code_start_addr + offset) = + *(os_vm_address_t *)(code_start_addr + offset) = old_value + displacement; else /* It is outside the old code object so it must be a * relative fixup (absolute fixups are not saved). So * subtract the displacement. */ - *(unsigned long *)((unsigned long)code_start_addr + offset) = + *(os_vm_address_t *)(code_start_addr + offset) = old_value - displacement; } } else { @@ -2037,181 +1920,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 @@ -2293,310 +2001,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 @@ -2656,14 +2060,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 @@ -2676,15 +2077,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 @@ -3032,7 +2430,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 @@ -3207,15 +2605,15 @@ scavenge_newspace_generation_one_scan(generation_index_t generation) static void scavenge_newspace_generation(generation_index_t generation) { - long i; + size_t i; /* the new_areas array currently being written to by gc_alloc() */ struct new_area (*current_new_areas)[] = &new_areas_1; - long current_new_areas_index; + size_t current_new_areas_index; /* the new_areas created by the previous scavenge cycle */ struct new_area (*previous_new_areas)[] = NULL; - long previous_new_areas_index; + size_t previous_new_areas_index; /* Flush the current regions updating the tables. */ gc_alloc_update_all_page_tables(); @@ -3322,16 +2720,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 @@ -3446,8 +2847,8 @@ print_ptr(lispobj *addr) page_index_t pi1 = find_page_index((void*)addr); if (pi1 != -1) - fprintf(stderr," %x: page %d alloc %d gen %d bytes_used %d offset %lu dont_move %d\n", - (unsigned long) addr, + fprintf(stderr," %p: page %d alloc %d gen %d bytes_used %d offset %lu dont_move %d\n", + addr, pi1, page_table[pi1].allocated, page_table[pi1].gen, @@ -3677,14 +3078,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 @@ -3697,15 +3095,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 @@ -3725,9 +3120,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 @@ -3909,19 +3301,6 @@ write_protect_generation_pages(generation_index_t generation) } } -#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64) -static void -scavenge_control_stack(struct thread *th) -{ - lispobj *control_stack = - (lispobj *)(th->control_stack_start); - unsigned long control_stack_size = - access_control_stack_pointer(th) - control_stack; - - scavenge(control_stack, control_stack_size); -} -#endif - #if defined(LISP_FEATURE_SB_THREAD) && (defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)) static void preserve_context_registers (os_context_t *c) @@ -3986,10 +3365,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 @@ -4138,7 +3513,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 @@ -4195,8 +3570,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); @@ -4259,11 +3634,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). */ @@ -4350,7 +3720,7 @@ void collect_garbage(generation_index_t last_gen) { generation_index_t gen = 0, i; - int raise; + int raise, more = 0; int gen_to_wp; /* The largest value of last_free_page seen since the time * remap_free_pages was called. */ @@ -4383,13 +3753,23 @@ collect_garbage(generation_index_t last_gen) do { /* Collect the generation. */ - if (gen >= gencgc_oldest_gen_to_gc) { - /* Never raise the oldest generation. */ + if (more || (gen >= gencgc_oldest_gen_to_gc)) { + /* Never raise the oldest generation. Never raise the extra generation + * collected due to more-flag. */ raise = 0; + more = 0; } else { raise = (gen < last_gen) || (generations[gen].num_gc >= generations[gen].number_of_gcs_before_promotion); + /* If we would not normally raise this one, but we're + * running low on space in comparison to the object-sizes + * we've been seeing, raise it and collect the next one + * too. */ + if (!raise && gen == last_gen) { + more = (2*large_allocation) >= (dynamic_space_size - bytes_allocated); + raise = more; + } } if (gencgc_verbose > 1) { @@ -4422,8 +3802,8 @@ collect_garbage(generation_index_t last_gen) gen++; } while ((gen <= gencgc_oldest_gen_to_gc) && ((gen < last_gen) - || ((gen <= gencgc_oldest_gen_to_gc) - && raise + || more + || (raise && (generations[gen].bytes_allocated > generations[gen].gc_trigger) && (generation_average_age(gen) @@ -4465,9 +3845,15 @@ collect_garbage(generation_index_t last_gen) update_dynamic_space_free_pointer(); - auto_gc_trigger = bytes_allocated + bytes_consed_between_gcs; + /* Update auto_gc_trigger. Make sure we trigger the next GC before + * running out of heap! */ + if (bytes_consed_between_gcs >= dynamic_space_size - bytes_allocated) + auto_gc_trigger = bytes_allocated + bytes_consed_between_gcs; + else + auto_gc_trigger = bytes_allocated + (dynamic_space_size - bytes_allocated)/2; + if(gencgc_verbose) - fprintf(stderr,"Next gc when %ld bytes have been consed\n", + fprintf(stderr,"Next gc when %"OS_VM_SIZE_FMT" bytes have been consed\n", auto_gc_trigger); /* If we did a big GC (arbitrarily defined as gen > 1), release memory @@ -4481,6 +3867,7 @@ collect_garbage(generation_index_t last_gen) } gc_active_p = 0; + large_allocation = 0; log_generation_stats(gc_logfile, "=== GC End ==="); SHOW("returning from collect_garbage"); @@ -4503,7 +3890,7 @@ 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; + void *page_start; for (last_page = page; (last_page < page_table_pages) && page_allocated_p(last_page); last_page++) { @@ -4551,7 +3938,6 @@ gc_free_heap(void) generations[page].gc_trigger = 2000000; generations[page].num_gc = 0; generations[page].cum_sum_bytes_allocated = 0; - generations[page].lutexes = NULL; } if (gencgc_verbose > 1) @@ -4583,6 +3969,12 @@ gc_init(void) 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 @@ -4594,12 +3986,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 @@ -4651,10 +4037,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. */ @@ -4703,13 +4088,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); @@ -4757,6 +4135,9 @@ general_alloc_internal(long nbytes, int page_type_flag, struct alloc_region *reg /* Must be inside a PA section. */ gc_assert(get_pseudo_atomic_atomic(thread)); + if (nbytes > large_allocation) + large_allocation = nbytes; + /* maybe we can do this quickly ... */ new_free_pointer = region->free_pointer + nbytes; if (new_free_pointer <= region->end_addr) { @@ -4768,7 +4149,7 @@ general_alloc_internal(long nbytes, int page_type_flag, struct alloc_region *reg /* we have to go the long way around, it seems. Check whether we * should GC in the near future */ - if (auto_gc_trigger && bytes_allocated > auto_gc_trigger) { + if (auto_gc_trigger && bytes_allocated+nbytes > auto_gc_trigger) { /* Don't flood the system with interrupts if the need to gc is * already noted. This can happen for example when SUB-GC * allocates or after a gc triggered in a WITHOUT-GCING. */ @@ -4858,7 +4239,17 @@ void unhandled_sigmemoryfault(void* addr); * * Return true if this signal is a normal generational GC thing that * we were able to handle, or false if it was abnormal and control - * should fall through to the general SIGSEGV/SIGBUS/whatever logic. */ + * should fall through to the general SIGSEGV/SIGBUS/whatever logic. + * + * We have two control flags for this: one causes us to ignore faults + * on unprotected pages completely, and the second complains to stderr + * but allows us to continue without losing. + */ +extern boolean ignore_memoryfaults_on_unprotected_pages; +boolean ignore_memoryfaults_on_unprotected_pages = 0; + +extern boolean continue_after_memoryfault_on_unprotected_pages; +boolean continue_after_memoryfault_on_unprotected_pages = 0; int gencgc_handle_wp_violation(void* fault_addr) @@ -4889,17 +4280,39 @@ gencgc_handle_wp_violation(void* fault_addr) 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 { + } else if (!ignore_memoryfaults_on_unprotected_pages) { /* The only acceptable reason for this signal on a heap * access is that GENCGC write-protected the page. * However, if two CPUs hit a wp page near-simultaneously, * we had better not have the second one lose here if it * does this test after the first one has already set wp=0 */ - if(page_table[page_index].write_protected_cleared != 1) - lose("fault in heap page %d not marked as write-protected\nboxed_region.first_page: %d, boxed_region.last_page %d\n", - page_index, boxed_region.first_page, - boxed_region.last_page); + if(page_table[page_index].write_protected_cleared != 1) { + void lisp_backtrace(int frames); + lisp_backtrace(10); + fprintf(stderr, + "Fault @ %p, page %"PAGE_INDEX_FMT" not marked as write-protected:\n" + " boxed_region.first_page: %"PAGE_INDEX_FMT"," + " boxed_region.last_page %"PAGE_INDEX_FMT"\n" + " page.region_start_offset: %"OS_VM_SIZE_FMT"\n" + " page.bytes_used: %"PAGE_BYTES_FMT"\n" + " page.allocated: %d\n" + " page.write_protected: %d\n" + " page.write_protected_cleared: %d\n" + " page.generation: %d\n", + fault_addr, + page_index, + boxed_region.first_page, + boxed_region.last_page, + page_table[page_index].region_start_offset, + page_table[page_index].bytes_used, + page_table[page_index].allocated, + page_table[page_index].write_protected, + page_table[page_index].write_protected_cleared, + page_table[page_index].gen); + if (!continue_after_memoryfault_on_unprotected_pages) + lose("Feh.\n"); + } } ret = thread_mutex_unlock(&free_pages_lock); gc_assert(ret == 0); @@ -4982,7 +4395,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; @@ -5017,7 +4431,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