From 1cfc4ee568b84b2dfa7db391b8a7c269f1bff1be Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 8 Sep 2004 16:05:14 +0000 Subject: [PATCH] 0.8.14.2: Lots of GC cleanups: * use N_WORD_BYTES where appropriate, even in gencgc.c * use inline functions instead of macros (there are a few cases yet to replace, though) * use `fixnump' where possible instead of `& 0x3' (which will break with 64-bit ports) * tweak NWORDS to function correctly for n_bits greater than the word size (important for 64-bit ports) * changes to use to new, improved NWORDS function when appropriate (e.g. for determining the length of float arrays) purify.c needs some of the same tweaks; I have a version which seems to work on alpha64 but fails at the end of warm-init. Passes all tests. --- src/runtime/cheneygc.c | 18 ++++-------- src/runtime/gc-common.c | 46 +++++++++++++++-------------- src/runtime/gc-internal.h | 15 ++++++++-- src/runtime/gencgc.c | 72 +++++++++++++++++++-------------------------- src/runtime/runtime.h | 53 ++++++++++++++++++++++++++------- version.lisp-expr | 2 +- 6 files changed, 115 insertions(+), 91 deletions(-) diff --git a/src/runtime/cheneygc.c b/src/runtime/cheneygc.c index 07e9d15..63383f5 100644 --- a/src/runtime/cheneygc.c +++ b/src/runtime/cheneygc.c @@ -72,7 +72,7 @@ tv_diff(struct timeval *x, struct timeval *y) static void zero_stack(void) { - u32 *ptr = (u32 *)current_control_stack_pointer; + lispobj *ptr = current_control_stack_pointer; search: do { if (*ptr) @@ -92,7 +92,7 @@ zero_stack(void) void * gc_general_alloc(int bytes, int unboxed_p, int quick_p) { lispobj *new=new_space_free_pointer; - new_space_free_pointer+=(bytes/4); + new_space_free_pointer+=(bytes/N_WORD_BYTES); return new; } @@ -273,15 +273,8 @@ collect_garbage(unsigned ignore) user_time = tv_diff(&stop_rusage.ru_utime, &start_rusage.ru_utime); system_time = tv_diff(&stop_rusage.ru_stime, &start_rusage.ru_stime); -#if 0 - printf("Statistics:\n"); - printf("%10.2f sec of real time\n", real_time); - printf("%10.2f sec of user time,\n", user_time); - printf("%10.2f sec of system time.\n", system_time); -#else printf("Statistics: %10.2fs real, %10.2fs user, %10.2fs system.\n", real_time, user_time, system_time); -#endif gc_rate = ((float) size_retained / (float) (1<<20)) / real_time; @@ -339,8 +332,9 @@ scavenge_interrupt_context(os_context_t *context) /* before we scavenge the context. */ #ifdef reg_LIP lip = *os_context_register_addr(context, reg_LIP); - /* 0x7FFFFFFF or 0x7FFFFFFFFFFFFFFF ? */ - lip_offset = 0x7FFFFFFF; + /* 0x7FFFFFFF on 32-bit platforms; + 0x7FFFFFFFFFFFFFFF on 64-bit platforms */ + lip_offset = (((unsigned long)1) << (N_WORD_BITS - 1)) - 1; lip_register_pair = -1; for (i = 0; i < (sizeof(boxed_registers) / sizeof(int)); i++) { unsigned long reg; @@ -529,7 +523,7 @@ scav_fdefn(lispobj *where, lispobj object) == (char *)((unsigned long)(fdefn->raw_addr))) { scavenge(where + 1, sizeof(struct fdefn)/sizeof(lispobj) - 1); fdefn->raw_addr = - (u32) ((char *) LOW_WORD(fdefn->fun)) + FUN_RAW_ADDR_OFFSET; + (u32) ((char *) LOW_WORD(fdefn->fun)) + FUN_RAW_ADDR_OFFSET; return sizeof(struct fdefn) / sizeof(lispobj); } else diff --git a/src/runtime/gc-common.c b/src/runtime/gc-common.c index 0e94dd4..2dfe4c9 100644 --- a/src/runtime/gc-common.c +++ b/src/runtime/gc-common.c @@ -107,10 +107,10 @@ copy_object(lispobj object, int nwords) tag = lowtag_of(object); /* Allocate space. */ - new = gc_general_alloc(nwords*4,ALLOC_BOXED,ALLOC_QUICK); + new = gc_general_alloc(nwords*N_WORD_BYTES,ALLOC_BOXED,ALLOC_QUICK); /* Copy the object. */ - memcpy(new,native_pointer(object),nwords*4); + memcpy(new,native_pointer(object),nwords*N_WORD_BYTES); return make_lispobj(new,tag); } @@ -175,7 +175,7 @@ scavenge(lispobj *start, long n_words) } } #endif - else if ((object & 3) == 0) { + else if (fixnump(object)) { /* It's a fixnum: really easy.. */ n_words_scavenged = 1; } else { @@ -399,7 +399,8 @@ trans_return_pc_header(lispobj object) struct code *code, *ncode; return_pc = (struct simple_fun *) native_pointer(object); - offset = HeaderValue(return_pc->header) * 4 ; + /* FIXME: was times 4, should it really be N_WORD_BYTES? */ + offset = HeaderValue(return_pc->header) * N_WORD_BYTES; /* Transport the whole code object */ code = (struct code *) ((unsigned long) return_pc - offset); @@ -453,7 +454,8 @@ trans_fun_header(lispobj object) struct code *code, *ncode; fheader = (struct simple_fun *) native_pointer(object); - offset = HeaderValue(fheader->header) * 4; + /* FIXME: was times 4, should it really be N_WORD_BYTES? */ + offset = HeaderValue(fheader->header) * N_WORD_BYTES; /* Transport the whole code object */ code = (struct code *) ((unsigned long) fheader - offset); @@ -690,8 +692,7 @@ scav_fdefn(lispobj *where, lispobj object) fdefn->raw_addr = (char *)(fdefn->fun + FUN_RAW_ADDR_OFFSET); /* gc.c has more casts here, which may be relevant or alternatively may be compiler warning defeaters. try - fdefn->raw_addr = - (u32) ((char *) LOW_WORD(fdefn->fun)) + FUN_RAW_ADDR_OFFSET; + fdefn->raw_addr = ((char *) LOW_WORD(fdefn->fun)) + FUN_RAW_ADDR_OFFSET; */ return sizeof(struct fdefn) / sizeof(lispobj); } else { @@ -1144,7 +1145,7 @@ scav_vector_single_float(lispobj *where, lispobj object) vector = (struct vector *) where; length = fixnum_value(vector->length); - nwords = CEILING(length + 2, 2); + nwords = CEILING(NWORDS(length, 32) + 2, 2); return nwords; } @@ -1159,7 +1160,7 @@ trans_vector_single_float(lispobj object) vector = (struct vector *) native_pointer(object); length = fixnum_value(vector->length); - nwords = CEILING(length + 2, 2); + nwords = CEILING(NWORDS(length, 32) + 2, 2); return copy_large_unboxed_object(object, nwords); } @@ -1172,7 +1173,7 @@ size_vector_single_float(lispobj *where) vector = (struct vector *) where; length = fixnum_value(vector->length); - nwords = CEILING(length + 2, 2); + nwords = CEILING(NWORDS(length, 32) + 2, 2); return nwords; } @@ -1185,7 +1186,7 @@ scav_vector_double_float(lispobj *where, lispobj object) vector = (struct vector *) where; length = fixnum_value(vector->length); - nwords = CEILING(length * 2 + 2, 2); + nwords = CEILING(NWORDS(length, 64) + 2, 2); return nwords; } @@ -1200,7 +1201,7 @@ trans_vector_double_float(lispobj object) vector = (struct vector *) native_pointer(object); length = fixnum_value(vector->length); - nwords = CEILING(length * 2 + 2, 2); + nwords = CEILING(NWORDS(length, 64) + 2, 2); return copy_large_unboxed_object(object, nwords); } @@ -1213,7 +1214,7 @@ size_vector_double_float(lispobj *where) vector = (struct vector *) where; length = fixnum_value(vector->length); - nwords = CEILING(length * 2 + 2, 2); + nwords = CEILING(NWORDS(length, 64) + 2, 2); return nwords; } @@ -1272,7 +1273,7 @@ scav_vector_complex_single_float(lispobj *where, lispobj object) vector = (struct vector *) where; length = fixnum_value(vector->length); - nwords = CEILING(length * 2 + 2, 2); + nwords = CEILING(NWORDS(length, 64) + 2, 2); return nwords; } @@ -1287,7 +1288,7 @@ trans_vector_complex_single_float(lispobj object) vector = (struct vector *) native_pointer(object); length = fixnum_value(vector->length); - nwords = CEILING(length * 2 + 2, 2); + nwords = CEILING(NWORDS(length, 64) + 2, 2); return copy_large_unboxed_object(object, nwords); } @@ -1300,7 +1301,7 @@ size_vector_complex_single_float(lispobj *where) vector = (struct vector *) where; length = fixnum_value(vector->length); - nwords = CEILING(length * 2 + 2, 2); + nwords = CEILING(NWORDS(length, 64) + 2, 2); return nwords; } @@ -1315,7 +1316,7 @@ scav_vector_complex_double_float(lispobj *where, lispobj object) vector = (struct vector *) where; length = fixnum_value(vector->length); - nwords = CEILING(length * 4 + 2, 2); + nwords = CEILING(NWORDS(length, 128) + 2, 2); return nwords; } @@ -1330,7 +1331,7 @@ trans_vector_complex_double_float(lispobj object) vector = (struct vector *) native_pointer(object); length = fixnum_value(vector->length); - nwords = CEILING(length * 4 + 2, 2); + nwords = CEILING(NWORDS(length, 128) + 2, 2); return copy_large_unboxed_object(object, nwords); } @@ -1343,7 +1344,7 @@ size_vector_complex_double_float(lispobj *where) vector = (struct vector *) where; length = fixnum_value(vector->length); - nwords = CEILING(length * 4 + 2, 2); + nwords = CEILING(NWORDS(length, 128) + 2, 2); return nwords; } @@ -1470,8 +1471,9 @@ static int scav_lose(lispobj *where, lispobj object) { lose("no scavenge function for object 0x%08x (widetag 0x%x)", - (unsigned long)object, - widetag_of(*(lispobj*)native_pointer(object))); + (unsigned long)object, + widetag_of(*(lispobj*)native_pointer(object))); + return 0; /* bogus return value to satisfy static type checking */ } @@ -1697,7 +1699,7 @@ gc_init_tables(void) trans_vector_unsigned_byte_32; #ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG transother[SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG] = - trans_vector_unsigned_byte_32; + trans_vector_unsigned_byte_64; #endif #ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG transother[SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG] = diff --git a/src/runtime/gc-internal.h b/src/runtime/gc-internal.h index 8928f2b..0b4bd4d 100644 --- a/src/runtime/gc-internal.h +++ b/src/runtime/gc-internal.h @@ -33,9 +33,18 @@ static inline unsigned int NWORDS(unsigned int x, unsigned int n_bits) { - unsigned int elements_per_word = N_WORD_BITS/n_bits; + /* A good compiler should be able to constant-fold this whole thing, + even with the conditional. */ + if(n_bits <= N_WORD_BITS) { + unsigned int elements_per_word = N_WORD_BITS/n_bits; - return CEILING(x, elements_per_word)/elements_per_word; + return CEILING(x, elements_per_word)/elements_per_word; + } + else { + /* FIXME: should have some sort of assertion that N_WORD_BITS + evenly divides n_bits */ + return x * (n_bits/N_WORD_BITS); + } } /* FIXME: Shouldn't this be defined in sbcl.h? */ @@ -82,7 +91,7 @@ search_space(lispobj *start, size_t words, lispobj *pointer) /* If thing is an immediate then this is a cons. */ if (is_lisp_pointer(thing) - || ((thing & 3) == 0) /* fixnum */ + || (fixnump(thing)) || (widetag_of(thing) == BASE_CHAR_WIDETAG) || (widetag_of(thing) == UNBOUND_MARKER_WIDETAG)) count = 2; diff --git a/src/runtime/gencgc.c b/src/runtime/gencgc.c index e3acbe3..b50b8d8 100644 --- a/src/runtime/gencgc.c +++ b/src/runtime/gencgc.c @@ -1150,7 +1150,7 @@ copy_large_object(lispobj object, int nwords) gc_assert(page_table[first_page].first_object_offset == 0); next_page = first_page; - remaining_bytes = nwords*4; + remaining_bytes = nwords*N_WORD_BYTES; while (remaining_bytes > PAGE_BYTES) { gc_assert(page_table[next_page].gen == from_space); gc_assert(page_table[next_page].allocated == BOXED_PAGE_FLAG); @@ -1212,7 +1212,7 @@ copy_large_object(lispobj object, int nwords) bytes_allocated -= bytes_freed; /* Add the region to the new_areas if requested. */ - add_new_area(first_page,0,nwords*4); + add_new_area(first_page,0,nwords*N_WORD_BYTES); return(object); } else { @@ -1220,9 +1220,9 @@ copy_large_object(lispobj object, int nwords) tag = lowtag_of(object); /* Allocate space. */ - new = gc_quick_alloc_large(nwords*4); + new = gc_quick_alloc_large(nwords*N_WORD_BYTES); - memcpy(new,native_pointer(object),nwords*4); + memcpy(new,native_pointer(object),nwords*N_WORD_BYTES); /* Return Lisp pointer of new object. */ return ((lispobj) new) | tag; @@ -1244,9 +1244,9 @@ copy_unboxed_object(lispobj object, int nwords) tag = lowtag_of(object); /* Allocate space. */ - new = gc_quick_alloc_unboxed(nwords*4); + new = gc_quick_alloc_unboxed(nwords*N_WORD_BYTES); - memcpy(new,native_pointer(object),nwords*4); + memcpy(new,native_pointer(object),nwords*N_WORD_BYTES); /* Return Lisp pointer of new object. */ return ((lispobj) new) | tag; @@ -1268,7 +1268,6 @@ copy_large_unboxed_object(lispobj object, int nwords) { int tag; lispobj *new; - lispobj *source, *dest; int first_page; gc_assert(is_lisp_pointer(object)); @@ -1276,7 +1275,7 @@ copy_large_unboxed_object(lispobj object, int nwords) gc_assert((nwords & 0x01) == 0); if ((nwords > 1024*1024) && gencgc_verbose) - FSHOW((stderr, "/copy_large_unboxed_object: %d bytes\n", nwords*4)); + FSHOW((stderr, "/copy_large_unboxed_object: %d bytes\n", nwords*N_WORD_BYTES)); /* Check whether it's a large object. */ first_page = find_page_index((void *)object); @@ -1294,7 +1293,7 @@ copy_large_unboxed_object(lispobj object, int nwords) gc_assert(page_table[first_page].first_object_offset == 0); next_page = first_page; - remaining_bytes = nwords*4; + remaining_bytes = nwords*N_WORD_BYTES; while (remaining_bytes > PAGE_BYTES) { gc_assert(page_table[next_page].gen == from_space); gc_assert((page_table[next_page].allocated == UNBOXED_PAGE_FLAG) @@ -1352,8 +1351,8 @@ copy_large_unboxed_object(lispobj object, int nwords) "/copy_large_unboxed bytes_freed=%d\n", bytes_freed)); - generations[from_space].bytes_allocated -= 4*nwords + bytes_freed; - generations[new_space].bytes_allocated += 4*nwords; + generations[from_space].bytes_allocated -= nwords*N_WORD_BYTES + bytes_freed; + generations[new_space].bytes_allocated += nwords*N_WORD_BYTES; bytes_allocated -= bytes_freed; return(object); @@ -1363,19 +1362,10 @@ copy_large_unboxed_object(lispobj object, int nwords) tag = lowtag_of(object); /* Allocate space. */ - new = gc_quick_alloc_large_unboxed(nwords*4); - - dest = new; - source = (lispobj *) native_pointer(object); - - /* Copy the object. */ - while (nwords > 0) { - dest[0] = source[0]; - dest[1] = source[1]; - dest += 2; - source += 2; - nwords -= 2; - } + new = gc_quick_alloc_large_unboxed(nwords*N_WORD_BYTES); + + /* Copy the object. */ + memcpy(new,native_pointer(object),nwords*N_WORD_BYTES); /* Return Lisp pointer of new object. */ return ((lispobj) new) | tag; @@ -1419,10 +1409,10 @@ sniff_code_object(struct code *code, unsigned displacement) nheader_words = HeaderValue(*(lispobj *)code); nwords = ncode_words + nheader_words; - constants_start_addr = (void *)code + 5*4; - constants_end_addr = (void *)code + nheader_words*4; - code_start_addr = (void *)code + nheader_words*4; - code_end_addr = (void *)code + nwords*4; + 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; /* Work through the unboxed code. */ for (p = code_start_addr; p < code_end_addr; p++) { @@ -1589,10 +1579,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*4; - constants_end_addr = (void *)new_code + nheader_words*4; - code_start_addr = (void *)new_code + nheader_words*4; - code_end_addr = (void *)new_code + nwords*4; + 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; /* FSHOW((stderr, "/const start = %x, end = %x\n", @@ -1648,7 +1638,7 @@ gencgc_apply_code_fixups(struct code *old_code, struct code *new_code) /* If it's within the old_code object then it must be an * absolute fixup (relative ones are not saved) */ if ((old_value >= (unsigned)old_code) - && (old_value < ((unsigned)old_code + nwords*4))) + && (old_value < ((unsigned)old_code + nwords*N_WORD_BYTES))) /* So add the dispacement. */ *(unsigned *)((unsigned)code_start_addr + offset) = old_value + displacement; @@ -2065,11 +2055,11 @@ possibly_valid_dynamic_space_pointer(lispobj *pointer) } /* Is it plausible cons? */ if ((is_lisp_pointer(start_addr[0]) - || ((start_addr[0] & 3) == 0) /* fixnum */ + || (fixnump(start_addr[0])) || (widetag_of(start_addr[0]) == BASE_CHAR_WIDETAG) || (widetag_of(start_addr[0]) == UNBOUND_MARKER_WIDETAG)) && (is_lisp_pointer(start_addr[1]) - || ((start_addr[1] & 3) == 0) /* fixnum */ + || (fixnump(start_addr[1])) || (widetag_of(start_addr[1]) == BASE_CHAR_WIDETAG) || (widetag_of(start_addr[1]) == UNBOUND_MARKER_WIDETAG))) break; @@ -2315,7 +2305,7 @@ maybe_adjust_large_object(lispobj *where) gc_assert(page_table[first_page].first_object_offset == 0); next_page = first_page; - remaining_bytes = nwords*4; + remaining_bytes = nwords*N_WORD_BYTES; while (remaining_bytes > PAGE_BYTES) { gc_assert(page_table[next_page].gen == from_space); gc_assert((page_table[next_page].allocated == BOXED_PAGE_FLAG) @@ -2532,7 +2522,7 @@ update_page_write_prot(int page) int j; int wp_it = 1; void **page_addr = (void **)page_address(page); - int num_words = page_table[page].bytes_used / 4; + int num_words = page_table[page].bytes_used / N_WORD_BYTES; /* Shouldn't be a free page. */ gc_assert(page_table[page].allocated != FREE_PAGE_FLAG); @@ -2871,12 +2861,10 @@ scavenge_newspace_generation(int generation) /* Work through previous_new_areas. */ for (i = 0; i < previous_new_areas_index; i++) { - /* FIXME: All these bare *4 and /4 should be something - * like BYTES_PER_WORD or WBYTES. */ int page = (*previous_new_areas)[i].page; int offset = (*previous_new_areas)[i].offset; - int size = (*previous_new_areas)[i].size / 4; - gc_assert((*previous_new_areas)[i].size % 4 == 0); + int size = (*previous_new_areas)[i].size / N_WORD_BYTES; + gc_assert((*previous_new_areas)[i].size % N_WORD_BYTES == 0); scavenge(page_address(page)+offset, size); } @@ -3346,7 +3334,7 @@ verify_zero_fill(void) if (free_bytes > 0) { int *start_addr = (int *)((unsigned)page_address(page) + page_table[page].bytes_used); - int size = free_bytes / 4; + int size = free_bytes / N_WORD_BYTES; int i; for (i = 0; i < size; i++) { if (start_addr[i] != 0) { diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 88d6ca9..c6e8a6e 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -37,28 +37,35 @@ * problem.. */ #define QSHOW_SIGNALS 0 -/* FIXME: Make HeaderValue, CONS, SYMBOL, and FDEFN into inline - * functions instead of macros. */ - -#define HeaderValue(obj) ((unsigned long) ((obj) >> N_WIDETAG_BITS)) - -#define CONS(obj) ((struct cons *)((obj)-LIST_POINTER_LOWTAG)) -#define SYMBOL(obj) ((struct symbol *)((obj)-OTHER_POINTER_LOWTAG)) -#define FDEFN(obj) ((struct fdefn *)((obj)-OTHER_POINTER_LOWTAG)) - /* KLUDGE: These are in theory machine-dependent and OS-dependent, but * in practice the "foo int" definitions work for all the machines * that SBCL runs on as of 0.6.7. If we port to the Alpha or some * other non-32-bit machine we'll probably need real machine-dependent * and OS-dependent definitions again. */ /* even on alpha, int happens to be 4 bytes. long is longer. */ +/* FIXME: these names really shouldn't reflect their length and this + is not quite right for some of the FFI stuff */ +#if 64 == N_WORD_BITS +typedef unsigned long u32; +typedef signed long s32; +#else typedef unsigned int u32; typedef signed int s32; -#define LOW_WORD(c) ((long)(c) & 0xFFFFFFFFL) +#endif + /* this is an integral type the same length as a machine pointer */ typedef unsigned long pointer_sized_uint_t ; -typedef u32 lispobj; +/* FIXME: we do things this way because of the alpha32 port. once + alpha64 has arrived, all this nastiness can go away */ +#if 64 == N_WORD_BITS +#define LOW_WORD(c) ((pointer_sized_uint_t)c) +typedef unsigned long lispobj; +#else +#define LOW_WORD(c) ((long)(c) & 0xFFFFFFFFL) +/* fake it on alpha32 */ +typedef unsigned int lispobj; +#endif static inline int lowtag_of(lispobj obj) { @@ -70,6 +77,30 @@ widetag_of(lispobj obj) { return obj & WIDETAG_MASK; } +static inline unsigned long +HeaderValue(lispobj obj) +{ + return obj >> N_WIDETAG_BITS; +} + +static inline struct cons * +CONS(lispobj obj) +{ + return (struct cons *)(obj - LIST_POINTER_LOWTAG); +} + +static inline struct symbol * +SYMBOL(lispobj obj) +{ + return (struct symbol *)(obj - OTHER_POINTER_LOWTAG); +} + +static inline struct fdefn * +FDEFN(lispobj obj) +{ + return (struct fdefn *)(obj - OTHER_POINTER_LOWTAG); +} + /* Is the Lisp object obj something with pointer nature (as opposed to * e.g. a fixnum or character or unbound marker)? */ static inline int diff --git a/version.lisp-expr b/version.lisp-expr index c0b95e7..2137863 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -17,4 +17,4 @@ ;;; checkins which aren't released. (And occasionally for internal ;;; versions, especially for internal versions off the main CVS ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".) -"0.8.14.1" +"0.8.14.2" -- 1.7.10.4