0.6.12.4:
[sbcl.git] / src / runtime / gencgc.c
index a476686..acc956c 100644 (file)
  */
 
 /*
- * $Header$
- */
-
-/*
  * For a review of garbage collection techniques (e.g. generational
  * GC) and terminology (e.g. "scavenging") see Paul R. Wilson,
  * "Uniprocessor Garbage Collection Techniques". As of 20000618, this
 #include "runtime.h"
 #include "sbcl.h"
 #include "os.h"
+#include "interr.h"
 #include "globals.h"
 #include "interrupt.h"
 #include "validate.h"
 #include "lispregs.h"
+#include "arch.h"
 #include "gc.h"
 #include "gencgc.h"
 
@@ -66,10 +64,13 @@ boolean enable_page_protection = 1;
 
 /* Should we unmap a page and re-mmap it to have it zero filled? */
 #if defined(__FreeBSD__) || defined(__OpenBSD__)
-/* Note: this can waste a lot of swap on FreeBSD so don't unmap there.
+/* comment from cmucl-2.4.8: This can waste a lot of swap on FreeBSD
+ * so don't unmap there.
  *
- * Presumably this behavior exists on OpenBSD too, so don't unmap
- * there either. -- WHN 20000727 */
+ * The CMU CL comment didn't specify a version, but was probably an
+ * old version of FreeBSD (pre-4.0), so this might no longer be true.
+ * OTOH, if it is true, this behavior might exist on OpenBSD too, so
+ * for now we don't unmap there either. -- WHN 2001-04-07 */
 boolean gencgc_unmap_zero = 0;
 #else
 boolean gencgc_unmap_zero = 1;
@@ -365,27 +366,30 @@ print_generation_stats(int verbose) /* FIXME: should take FILE argument */
 
        for (j = 0; j < last_free_page; j++)
            if (page_table[j].gen == i) {
+
                /* Count the number of boxed pages within the given
-                * generation */
-               if (page_table[j].allocated == BOXED_PAGE)
+                * generation. */
+               if (page_table[j].allocated == BOXED_PAGE) {
                    if (page_table[j].large_object)
                        large_boxed_cnt++;
                    else
                        boxed_cnt++;
-       
+               }
+
                /* Count the number of unboxed pages within the given
-                * generation */
-               if (page_table[j].allocated == UNBOXED_PAGE)
+                * generation. */
+               if (page_table[j].allocated == UNBOXED_PAGE) {
                    if (page_table[j].large_object)
                        large_unboxed_cnt++;
                    else
                        unboxed_cnt++;
+               }
            }
 
        gc_assert(generations[i].bytes_allocated
                  == generation_bytes_allocated(i));
        fprintf(stderr,
-               "   %8d: %5d %5d %5d %5d %8d %5d %8d %4d %3d %7.4lf\n",
+               "   %8d: %5d %5d %5d %5d %8d %5d %8d %4d %3d %7.4f\n",
                i,
                boxed_cnt, unboxed_cnt, large_boxed_cnt, large_unboxed_cnt,
                generations[i].bytes_allocated,
@@ -396,7 +400,7 @@ print_generation_stats(int verbose) /* FIXME: should take FILE argument */
                generations[i].num_gc,
                gen_av_mem_age(i));
     }
-    fprintf(stderr,"   Total bytes allocated=%d\n", bytes_allocated);
+    fprintf(stderr,"   Total bytes allocated=%ld\n", bytes_allocated);
 
     fpu_restore(fpu_state);
 }
@@ -690,7 +694,7 @@ struct new_area {
     int  size;
 };
 static struct new_area (*new_areas)[];
-static new_areas_index;
+static int new_areas_index;
 int max_new_areas;
 
 /* Add a new area to new_areas. */
@@ -1195,6 +1199,7 @@ static void
 
     /* shouldn't happen */
     gc_assert(0);
+    return((void *) NIL); /* dummy value: return something ... */
 }
 
 /* Allocate space from the boxed_region. If there is not enough free
@@ -1313,6 +1318,7 @@ static void
 
     /* shouldn't happen? */
     gc_assert(0);
+    return((void *) NIL); /* dummy value: return something ... */
 }
 
 static inline void
@@ -1741,12 +1747,18 @@ copy_large_unboxed_object(lispobj object, int nwords)
 
 #define DIRECT_SCAV 0
 
+/* FIXME: Most calls end up going to a little trouble to compute an
+ * 'nwords' value. The system might be a little simpler if this
+ * function used an 'end' parameter instead. */
 static void
 scavenge(lispobj *start, long nwords)
 {
     while (nwords > 0) {
        lispobj object;
-       int type, words_scavenged;
+#if DIRECT_SCAV
+       int type;
+#endif
+       int words_scavenged;
 
        object = *start;
        
@@ -1767,7 +1779,7 @@ scavenge(lispobj *start, long nwords)
                lispobj first_word = *ptr;
        
                if (first_word == 0x01) {
-                   /* Yep, there be a forwarding pointer. */
+                   /* Yes, there's a forwarding pointer. */
                    *start = ptr[1];
                    words_scavenged = 1;
                }
@@ -1780,7 +1792,7 @@ scavenge(lispobj *start, long nwords)
            }
        } else {
            if ((object & 3) == 0) {
-               /* It's a fixnum. Real easy.. */
+               /* It's a fixnum: really easy.. */
                words_scavenged = 1;
            } else {
                /* It's some sort of header object or another. */
@@ -1912,8 +1924,6 @@ void
 sniff_code_object(struct code *code, unsigned displacement)
 {
     int nheader_words, ncode_words, nwords;
-    lispobj fheaderl;
-    struct function *fheaderp;
     void *p;
     void *constants_start_addr, *constants_end_addr;
     void *code_start_addr, *code_end_addr;
@@ -2093,7 +2103,6 @@ apply_code_fixups(struct code *old_code, struct code *new_code)
     int nheader_words, ncode_words, nwords;
     void *constants_start_addr, *constants_end_addr;
     void *code_start_addr, *code_end_addr;
-    lispobj p;
     lispobj fixups = NIL;
     unsigned displacement = (unsigned)new_code - (unsigned)old_code;
     struct vector *fixups_vector;
@@ -2533,7 +2542,6 @@ trans_list(lispobj object)
 {
     lispobj new_list_pointer;
     struct cons *cons, *new_cons;
-    int n = 0;
     lispobj cdr;
 
     gc_assert(from_space_p(object));
@@ -2879,12 +2887,14 @@ scav_vector(lispobj *where, lispobj object)
 {
     unsigned int kv_length;
     lispobj *kv_vector;
-    unsigned int  length;
+    unsigned int length = 0; /* (0 = dummy to stop GCC warning) */
     lispobj *hash_table;
     lispobj empty_symbol;
-    unsigned int  *index_vector, *next_vector, *hash_vector;
+    unsigned int *index_vector = NULL; /* (NULL = dummy to stop GCC warning) */
+    unsigned int *next_vector = NULL; /* (NULL = dummy to stop GCC warning) */
+    unsigned int *hash_vector = NULL; /* (NULL = dummy to stop GCC warning) */
     lispobj weak_p_obj;
-    unsigned next_vector_length;
+    unsigned next_vector_length = 0;
 
     /* FIXME: A comment explaining this would be nice. It looks as
      * though SB-VM:VECTOR-VALID-HASHING-SUBTYPE is set for EQ-based
@@ -2918,12 +2928,12 @@ scav_vector(lispobj *where, lispobj object)
      * the hash table code reserves for marking empty slots. */
     scavenge(where+3, 1);
     if (!Pointerp(where[3])) {
-       lose("not #:%EMPTY-HT-SLOT% symbol pointer: %x", where[3]);
+       lose("not empty-hash-table-slot symbol pointer: %x", where[3]);
     }
     empty_symbol = where[3];
     /* fprintf(stderr,"* empty_symbol = %x\n", empty_symbol);*/
     if (TypeOf(*(lispobj *)PTR(empty_symbol)) != type_SymbolHeader) {
-       lose("not a symbol where #:%EMPTY-HT-SLOT% expected: %x",
+       lose("not a symbol where empty-hash-table-slot symbol expected: %x",
             *(lispobj *)PTR(empty_symbol));
     }
 
@@ -3649,7 +3659,7 @@ static lispobj
 trans_weak_pointer(lispobj object)
 {
     lispobj copy;
-    struct weak_pointer *wp;
+    /* struct weak_pointer *wp; */
 
     gc_assert(Pointerp(object));
 
@@ -3682,7 +3692,7 @@ void scan_weak_pointers(void)
     struct weak_pointer *wp;
     for (wp = weak_pointers; wp != NULL; wp = wp->next) {
        lispobj value = wp->value;
-       lispobj first, *first_pointer;
+       lispobj *first_pointer;
 
        first_pointer = (lispobj *)PTR(value);
 
@@ -4050,7 +4060,7 @@ search_read_only_space(lispobj *pointer)
 static lispobj *
 search_static_space(lispobj *pointer)
 {
-    lispobj* start = (lispobj*)static_space;
+    lispobj* start = (lispobj*)STATIC_SPACE_START;
     lispobj* end = (lispobj*)SymbolValue(STATIC_SPACE_FREE_POINTER);
     if ((pointer < start) || (pointer >= end))
        return NULL;
@@ -4114,7 +4124,8 @@ valid_dynamic_space_pointer(lispobj *pointer)
        case type_FuncallableInstanceHeader:
        case type_ByteCodeFunction:
        case type_ByteCodeClosure:
-           if ((int)pointer != ((int)start_addr+type_FunctionPointer)) {
+           if ((unsigned)pointer !=
+               ((unsigned)start_addr+type_FunctionPointer)) {
                if (gencgc_verbose)
                    FSHOW((stderr,
                           "/Wf2: %x %x %x\n",
@@ -4131,7 +4142,8 @@ valid_dynamic_space_pointer(lispobj *pointer)
        }
        break;
     case type_ListPointer:
-       if ((int)pointer != ((int)start_addr+type_ListPointer)) {
+       if ((unsigned)pointer !=
+           ((unsigned)start_addr+type_ListPointer)) {
            if (gencgc_verbose)
                FSHOW((stderr,
                       "/Wl1: %x %x %x\n",
@@ -4156,7 +4168,8 @@ valid_dynamic_space_pointer(lispobj *pointer)
            return 0;
        }
     case type_InstancePointer:
-       if ((int)pointer != ((int)start_addr+type_InstancePointer)) {
+       if ((unsigned)pointer !=
+           ((unsigned)start_addr+type_InstancePointer)) {
            if (gencgc_verbose)
                FSHOW((stderr,
                       "/Wi1: %x %x %x\n",
@@ -4172,7 +4185,8 @@ valid_dynamic_space_pointer(lispobj *pointer)
        }
        break;
     case type_OtherPointer:
-       if ((int)pointer != ((int)start_addr+type_OtherPointer)) {
+       if ((unsigned)pointer !=
+           ((int)start_addr+type_OtherPointer)) {
            if (gencgc_verbose)
                FSHOW((stderr,
                       "/Wo1: %x %x %x\n",
@@ -4308,9 +4322,6 @@ valid_dynamic_space_pointer(lispobj *pointer)
 static void
 maybe_adjust_large_object(lispobj *where)
 {
-    int tag;
-    lispobj *new;
-    lispobj *source, *dest;
     int first_page;
     int nwords;
 
@@ -4481,8 +4492,12 @@ preserve_pointer(void *addr)
 
     region_allocation = page_table[addr_page_index].allocated;
 
-    /* Check the offset within the page */
-    if (((int)addr & 0xfff) > page_table[addr_page_index].bytes_used)
+    /* Check the offset within the page.
+     *
+     * FIXME: The mask should have a symbolic name, and ideally should
+     * be derived from page size instead of hardwired to 0xfff.
+     * (Also fix other uses of 0xfff, elsewhere.) */
+    if (((unsigned)addr & 0xfff) > page_table[addr_page_index].bytes_used)
        return;
 
     if (enable_pointer_filter && !valid_dynamic_space_pointer(addr))
@@ -4510,7 +4525,7 @@ preserve_pointer(void *addr)
        if ((page_table[addr_page_index].allocated == FREE_PAGE)
            || (page_table[addr_page_index].bytes_used == 0)
            /* Check the offset within the page. */
-           || (((int)addr & 0xfff)
+           || (((unsigned)addr & 0xfff)
                > page_table[addr_page_index].bytes_used)) {
            FSHOW((stderr,
                   "weird? ignore ptr 0x%x to freed area of large object\n",
@@ -4588,14 +4603,20 @@ scavenge_thread_stacks(void)
                           vector_length));
                if (vector_length > 0) {
                    lispobj *stack_pointer = (lispobj*)stack->data[0];
-                   if ((stack_pointer < control_stack) ||
-                       (stack_pointer > control_stack_end))
+                   if ((stack_pointer < (lispobj *)CONTROL_STACK_START) ||
+                       (stack_pointer > (lispobj *)CONTROL_STACK_END))
                        lose("invalid stack pointer %x",
                             (unsigned)stack_pointer);
-                   if ((stack_pointer > control_stack) &&
-                       (stack_pointer < control_stack_end)) {
-                       unsigned int length = ((int)control_stack_end -
-                                              (int)stack_pointer) / 4;
+                   if ((stack_pointer > (lispobj *)CONTROL_STACK_START) &&
+                       (stack_pointer < (lispobj *)CONTROL_STACK_END)) {
+                       /* FIXME: Ick!
+                        *   (1) hardwired word length = 4; and as usual,
+                        *       when fixing this, check for other places
+                        *       with the same problem
+                        *   (2) calling it 'length' suggests bytes;
+                        *       perhaps 'size' instead? */
+                       unsigned int length = ((unsigned)CONTROL_STACK_END -
+                                              (unsigned)stack_pointer) / 4;
                        int j;
                        if (length >= vector_length) {
                            lose("invalid stack size %d >= vector length %d",
@@ -4961,12 +4982,10 @@ scavenge_newspace_generation(int generation)
     /* the new_areas array currently being written to by gc_alloc */
     struct new_area  (*current_new_areas)[] = &new_areas_1;
     int current_new_areas_index;
-    int current_new_areas_allocated;
 
     /* the new_areas created but the previous scavenge cycle */
     struct new_area  (*previous_new_areas)[] = NULL;
     int previous_new_areas_index;
-    int previous_new_areas_allocated;
 
 #define SC_NS_GEN_CK 0
 #if SC_NS_GEN_CK
@@ -5099,14 +5118,13 @@ scavenge_newspace_generation(int generation)
 static void
 unprotect_oldspace(void)
 {
-    int bytes_freed = 0;
     int i;
 
     for (i = 0; i < last_free_page; i++) {
        if ((page_table[i].allocated != FREE_PAGE)
            && (page_table[i].bytes_used != 0)
            && (page_table[i].gen == from_space)) {
-           void *page_start, *addr;
+           void *page_start;
 
            page_start = (void *)page_address(i);
 
@@ -5221,7 +5239,7 @@ print_ptr(lispobj *addr)
 
     if (pi1 != -1)
        fprintf(stderr,"  %x: page %d  alloc %d  gen %d  bytes_used %d  offset %d  dont_move %d\n",
-               addr,
+               (unsigned int) addr,
                pi1,
                page_table[pi1].allocated,
                page_table[pi1].gen,
@@ -5243,12 +5261,12 @@ print_ptr(lispobj *addr)
 extern int undefined_tramp;
 
 static void
-verify_space(lispobj*start, size_t words)
+verify_space(lispobj *start, size_t words)
 {
-    int dynamic_space = (find_page_index((void*)start) != -1);
-    int readonly_space =
-       (READ_ONLY_SPACE_START <= (int)start &&
-        (int)start < SymbolValue(READ_ONLY_SPACE_FREE_POINTER));
+    int is_in_dynamic_space = (find_page_index((void*)start) != -1);
+    int is_in_readonly_space =
+       (READ_ONLY_SPACE_START <= (unsigned)start &&
+        (unsigned)start < SymbolValue(READ_ONLY_SPACE_FREE_POINTER));
 
     while (words > 0) {
        size_t count = 1;
@@ -5260,7 +5278,7 @@ verify_space(lispobj*start, size_t words)
                (READ_ONLY_SPACE_START <= thing &&
                 thing < SymbolValue(READ_ONLY_SPACE_FREE_POINTER));
            int to_static_space =
-               ((int)static_space <= thing &&
+               (STATIC_SPACE_START <= thing &&
                 thing < SymbolValue(STATIC_SPACE_FREE_POINTER));
 
            /* Does it point to the dynamic space? */
@@ -5276,7 +5294,7 @@ verify_space(lispobj*start, size_t words)
                }
                /* Check that its not in the RO space as it would then be a
                 * pointer from the RO to the dynamic space. */
-               if (readonly_space) {
+               if (is_in_readonly_space) {
                    lose("ptr to dynamic space %x from RO space %x",
                         thing, start);
                }
@@ -5289,7 +5307,7 @@ verify_space(lispobj*start, size_t words)
            } else {
                /* Verify that it points to another valid space. */
                if (!to_readonly_space && !to_static_space
-                   && (thing != (int)&undefined_tramp)) {
+                   && (thing != (unsigned)&undefined_tramp)) {
                    lose("Ptr %x @ %x sees junk.", thing, start);
                }
            }
@@ -5334,7 +5352,7 @@ verify_space(lispobj*start, size_t words)
                        /* Check that it's not in the dynamic space.
                         * FIXME: Isn't is supposed to be OK for code
                         * objects to be in the dynamic space these days? */
-                       if (dynamic_space
+                       if (is_in_dynamic_space
                            /* It's ok if it's byte compiled code. The trace
                             * table offset will be a fixnum if it's x86
                             * compiled code - check. */
@@ -5435,19 +5453,25 @@ verify_space(lispobj*start, size_t words)
 static void
 verify_gc(void)
 {
+    /* FIXME: It would be nice to make names consistent so that
+     * foo_size meant size *in* *bytes* instead of size in some
+     * arbitrary units. (Yes, this caused a bug, how did you guess?:-)
+     * Some counts of lispobjs are called foo_count; it might be good
+     * to grep for all foo_size and rename the appropriate ones to
+     * foo_count. */
     int read_only_space_size =
        (lispobj*)SymbolValue(READ_ONLY_SPACE_FREE_POINTER)
        - (lispobj*)READ_ONLY_SPACE_START;
     int static_space_size =
        (lispobj*)SymbolValue(STATIC_SPACE_FREE_POINTER)
-       - (lispobj*)static_space;
+       - (lispobj*)STATIC_SPACE_START;
     int binding_stack_size =
        (lispobj*)SymbolValue(BINDING_STACK_POINTER)
        - (lispobj*)BINDING_STACK_START;
 
     verify_space((lispobj*)READ_ONLY_SPACE_START, read_only_space_size);
-    verify_space((lispobj*)static_space, static_space_size);
-    verify_space((lispobj*)BINDING_STACK_START, binding_stack_size);
+    verify_space((lispobj*)STATIC_SPACE_START   , static_space_size);
+    verify_space((lispobj*)BINDING_STACK_START  , binding_stack_size);
 }
 
 static void
@@ -5508,7 +5532,7 @@ verify_zero_fill(void)
        } else {
            int free_bytes = 4096 - page_table[page].bytes_used;
            if (free_bytes > 0) {
-               int *start_addr = (int *)((int)page_address(page)
+               int *start_addr = (int *)((unsigned)page_address(page)
                                          + page_table[page].bytes_used);
                int size = free_bytes / 4;
                int i;
@@ -5586,7 +5610,6 @@ write_protect_generation_pages(int generation)
 static void
 garbage_collect_generation(int generation, int raise)
 {
-    unsigned long allocated = bytes_allocated;
     unsigned long bytes_freed;
     unsigned long i;
     unsigned long read_only_space_size, static_space_size;
@@ -5635,9 +5658,11 @@ garbage_collect_generation(int generation, int raise)
     /* Scavenge the stack's conservative roots. */
     {
        lispobj **ptr;
-       for (ptr = (lispobj **)CONTROL_STACK_END-1;
-            ptr > (lispobj **)&raise; ptr--)
+       for (ptr = (lispobj **)CONTROL_STACK_END - 1;
+            ptr > (lispobj **)&raise;
+            ptr--) {
            preserve_pointer(*ptr);
+       }
     }
 #ifdef CONTROL_STACKS
     scavenge_thread_stacks();
@@ -5666,26 +5691,28 @@ garbage_collect_generation(int generation, int raise)
     }
 
     /* Scavenge the binding stack. */
-    scavenge(binding_stack,
-            (lispobj *)SymbolValue(BINDING_STACK_POINTER) - binding_stack);
+    scavenge( (lispobj *) BINDING_STACK_START,
+            (lispobj *)SymbolValue(BINDING_STACK_POINTER) -
+            (lispobj *)BINDING_STACK_START);
 
     if (SymbolValue(SCAVENGE_READ_ONLY_SPACE) != NIL) {
        read_only_space_size =
-           (lispobj *)SymbolValue(READ_ONLY_SPACE_FREE_POINTER)
-           - read_only_space;
+           (lispobj*)SymbolValue(READ_ONLY_SPACE_FREE_POINTER) -
+           (lispobj*)READ_ONLY_SPACE_START;
        FSHOW((stderr,
               "/scavenge read only space: %d bytes\n",
               read_only_space_size * sizeof(lispobj)));
-       scavenge(read_only_space, read_only_space_size);
+       scavenge( (lispobj *) READ_ONLY_SPACE_START, read_only_space_size);
     }
 
-    static_space_size = (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER)
-       - static_space;
+    static_space_size =
+       (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER) -
+       (lispobj *)STATIC_SPACE_START;
     if (gencgc_verbose > 1)
        FSHOW((stderr,
               "/scavenge static space: %d bytes\n",
               static_space_size * sizeof(lispobj)));
-    scavenge(static_space, static_space_size);
+    scavenge( (lispobj *) STATIC_SPACE_START, static_space_size);
 
     /* All generations but the generation being GCed need to be
      * scavenged. The new_space generation needs special handling as
@@ -5784,6 +5811,7 @@ update_x86_dynamic_space_free_pointer(void)
 
     SetSymbolValue(ALLOCATION_POINTER,
                   (lispobj)(((char *)heap_base) + last_free_page*4096));
+    return 0; /* dummy value: return something ... */
 }
 
 /* GC all generations below last_gen, raising their objects to the
@@ -5958,14 +5986,11 @@ gc_free_heap(void)
                     addr);
            }
        } else if (gencgc_zero_check_during_free_heap) {
-           int *page_start, i;
-
            /* Double-check that the page is zero filled. */
+           int *page_start, i;
            gc_assert(page_table[page].allocated == FREE_PAGE);
            gc_assert(page_table[page].bytes_used == 0);
-
-           page_start = (int *)page_address(i);
-
+           page_start = (int *)page_address(page);
            for (i=0; i<1024; i++) {
                if (page_start[i] != 0) {
                    lose("free region not zero at %x", page_start + i);
@@ -6030,7 +6055,7 @@ gc_init(void)
 
     gc_init_tables();
 
-    heap_base = (void*)DYNAMIC_0_SPACE_START;
+    heap_base = (void*)DYNAMIC_SPACE_START;
 
     /* Initialize each page structure. */
     for (i = 0; i < NUM_PAGES; i++) {
@@ -6089,7 +6114,7 @@ void
 gencgc_pickup_dynamic(void)
 {
     int page = 0;
-    int addr = DYNAMIC_0_SPACE_START;
+    int addr = DYNAMIC_SPACE_START;
     int alloc_ptr = SymbolValue(ALLOCATION_POINTER);
 
     /* Initialize the first region. */
@@ -6099,7 +6124,7 @@ gencgc_pickup_dynamic(void)
        page_table[page].bytes_used = 4096;
        page_table[page].large_object = 0;
        page_table[page].first_object_offset =
-           (void *)DYNAMIC_0_SPACE_START - page_address(page);
+           (void *)DYNAMIC_SPACE_START - page_address(page);
        addr += 4096;
        page++;
     } while (addr < alloc_ptr);
@@ -6287,15 +6312,17 @@ clear_auto_gc_trigger(void)
     auto_gc_trigger = 0;
 }
 \f
-/* Find the code object for the given pc, or return NULL on failure. */
-lispobj*
+/* Find the code object for the given pc, or return NULL on failure.
+ *
+ * FIXME: PC shouldn't be lispobj*, should it? Maybe void*? */
+lispobj *
 component_ptr_from_pc(lispobj *pc)
 {
     lispobj *object = NULL;
 
-    if (object = search_read_only_space(pc))
+    if ( (object = search_read_only_space(pc)) )
        ;
-    else if (object = search_static_space(pc))
+    else if ( (object = search_static_space(pc)) )
        ;
     else
        object = search_dynamic_space(pc);