]> gitweb.factorcode.org Git - factor.git/commitdiff
more generational GC work
authorSlava Pestov <slava@factorcode.org>
Wed, 11 May 2005 04:43:52 +0000 (04:43 +0000)
committerSlava Pestov <slava@factorcode.org>
Wed, 11 May 2005 04:43:52 +0000 (04:43 +0000)
Makefile
library/bootstrap/primitives.factor
library/tools/memory.factor
native/gc.c
native/gc.h
native/image.c
native/memory.c
native/memory.h
native/relocate.c
native/relocate.h
native/unix/signal.c

index ece0aa04ee258fdca5eac65b3e48c204009e06a5..dc86f06c7e43c215a4c7f8ddb84c567a34df4a50 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,10 @@
 CC = gcc
-#DEFAULT_CFLAGS = -Wall -O3 -fomit-frame-pointer $(SITE_CFLAGS)
-DEFAULT_CFLAGS = -g
+DEFAULT_CFLAGS = -Wall -O3 -fomit-frame-pointer $(SITE_CFLAGS)
+#DEFAULT_CFLAGS = -g
 DEFAULT_LIBS = -lm
 
-#STRIP = strip
-STRIP = touch
+STRIP = strip
+#STRIP = touch
 
 UNIX_OBJS = native/unix/file.o \
        native/unix/signal.o \
index d5aba647c674192747f3cbb67cd698994bb11ee5..77acf3aece7aa6fdda3466bdc4950e92cf414fb7 100644 (file)
@@ -134,7 +134,7 @@ vocabularies get [
     [ "set-datastack" "kernel"                " ds -- "          ]
     [ "set-callstack" "kernel"                " cs -- "          ]
     [ "exit" "kernel"                         [ [ integer ] [ ] ] ]
-    [ "room" "memory"                         [ [ ] [ integer integer integer integer ] ] ]
+    [ "room" "memory"                         [ [ ] [ integer integer general-list ] ] ]
     [ "os-env" "kernel"                       [ [ string ] [ object ] ] ]
     [ "millis" "kernel"                       [ [ ] [ integer ] ] ]
     [ "(random-int)" "math"                   [ [ ] [ integer ] ] ]
index 664796ed62d06f0175508cbfb5e603731c472497..a1f8436e8ca616edbdd7886614156efe180b3caf 100644 (file)
@@ -8,7 +8,7 @@ words ;
 : save
     #! Save the current image.
     "image" get save-image ;
-    
+
 ! Printing an overview of heap usage.
 
 : kb. 1024 /i unparse write " KB" write ;
@@ -21,7 +21,10 @@ words ;
 
 : room. ( -- )
     room
-    "Data space: " write (room.)
+    0 swap [
+        "Generation " write over unparse write ": " write
+        uncons (room.) 1 +
+    ] each drop
     "Code space: " write (room.) ;
 
 ! Some words for iterating through the heap.
index a6284f799dc99722e630e004fd66bc682b465c5e..73630e36c584863e608fb042067f493a6c61991b 100644 (file)
@@ -30,32 +30,6 @@ void collect_roots(void)
                copy_handle(&userenv[i]);
 }
 
-void clear_cards(void)
-{
-       BYTE *ptr;
-       for(ptr = cards; ptr < cards_end; ptr++)
-               clear_card(ptr);
-}
-
-void collect_cards(void)
-{
-       BYTE *ptr;
-       for(ptr = cards; ptr < cards_end; ptr++)
-       {
-               CARD c = *ptr;
-               if(card_marked(*ptr))
-               {
-                       CELL offset = (c & CARD_BASE_MASK);
-                       if(offset == 0x7f)
-                               critical_error("bad card",c);
-                       CELL ea = (CELL)CARD_TO_ADDR(c) + offset;
-                       printf("write barrier hit %d\n",offset);
-                       printf("object header: %x\n",get(ea));
-                       clear_card(ptr);
-               }
-       }
-}
-
 /*
 Given a pointer to a tagged pointer to oldspace, copy it to newspace.
 If the object has already been copied, return the forwarding
@@ -122,7 +96,81 @@ INLINE CELL collect_next(CELL scan)
        return scan + size;
 }
 
-void primitive_gc(void)
+void clear_cards(void)
+{
+       BYTE *ptr;
+       for(ptr = cards; ptr < cards_end; ptr++)
+               clear_card(ptr);
+}
+
+/* scan all the objects in the card */
+void collect_card(CARD *ptr)
+{
+       CARD c = *ptr;
+       CELL offset = (c & CARD_BASE_MASK);
+       CELL card_scan = (CELL)CARD_TO_ADDR(ptr) + offset;
+       CELL card_end = (CELL)CARD_TO_ADDR(ptr + 1);
+
+       if(offset == 0x7f)
+               critical_error("bad card",c);
+
+       printf("! write barrier hit %d\n",offset);
+       while(card_scan < card_end)
+               card_scan = collect_next(card_scan);
+
+       clear_card(ptr);
+}
+
+void collect_gen_cards(CELL gen)
+{
+       CARD *ptr = ADDR_TO_CARD(generations[gen].base);
+       CARD *last_card = ADDR_TO_CARD(generations[gen].here);
+       for(ptr = cards; ptr <= last_card; ptr++)
+       {
+               if(card_marked(*ptr))
+                       collect_card(ptr);
+       }
+}
+
+/* scan cards in all generations older than the one being collected */
+void collect_cards(void)
+{
+       CELL gen;
+       for(gen = collecting_generation; gen < GC_GENERATIONS; gen++)
+               collect_gen_cards(gen);
+}
+
+void begin_gc(CELL gen)
+{
+       collecting_generation = generations[gen].base;
+
+       if(gen == TENURED)
+       {
+               /* when collecting the oldest generation, rotate it
+               with the semispace */
+               ZONE z = generations[gen];
+               generations[gen] = prior;
+               prior = z;
+               generations[gen].here = generations[gen].base;
+               allot_zone = &generations[gen];
+       }
+       else
+       {
+               /* when collecting a younger generation, we copy
+               reachable objects to the next oldest generation,
+               so we set the allot_zone so the next generation. */
+               allot_zone = &generations[gen + 1];
+       }
+}
+
+void end_gc(CELL gen)
+{
+       /* continue allocating from the nursery. */
+       allot_zone = &nursery;
+}
+
+/* collect gen and all younger generations */
+void garbage_collection(CELL gen)
 {
        s64 start = current_millis();
        CELL scan;
@@ -136,8 +184,10 @@ void primitive_gc(void)
 
        gc_in_progress = true;
 
-       flip_zones();
-       scan = active.base;
+       begin_gc(gen);
+
+       /* initialize chase pointer */
+       scan = allot_zone->here;
 
        collect_roots();
        collect_cards();
@@ -145,23 +195,30 @@ void primitive_gc(void)
        /* collect literal objects referenced from compiled code */
        collect_literals();
        
-       while(scan < active.here)
+       while(scan < allot_zone->here)
        {
                gc_debug("scan loop",scan);
                scan = collect_next(scan);
        }
+
+       end_gc(gen);
+
        gc_debug("gc done",0);
 
        gc_in_progress = false;
-
        gc_time += (current_millis() - start);
 }
 
+void primitive_gc(void)
+{
+       garbage_collection(TENURED);
+}
+
 /* WARNING: only call this from a context where all local variables
 are also reachable via the GC roots. */
 void maybe_garbage_collection(void)
 {
-       if(active.here > active.alarm)
+       if(nursery.here > nursery.alarm)
                primitive_gc();
 }
 
index 6ed8665a4afc77fad3e65cb171e633bcd880b449..6f96650d976845b09f236ce619b637c457f7d683 100644 (file)
@@ -5,6 +5,15 @@ bool heap_scan;
 
 s64 gc_time;
 
+/* only meaningful during a GC */
+CELL collecting_generation;
+
+/* test if the pointer is in generation being collected, or a younger one.
+init_arena() arranges things so that the older generations are first,
+so we have to check that the pointer occurs after the beginning of
+the requested generation. */
+#define COLLECTING_GEN(ptr) (collecting_generation <= ptr)
+
 /* Given a pointer to oldspace, copy it to newspace. */
 INLINE void* copy_untagged_object(void* pointer, CELL size)
 {
@@ -32,6 +41,9 @@ INLINE CELL copy_object(CELL pointer)
 
        gc_debug("copy object",pointer);
 
+       if(!COLLECTING_GEN(pointer))
+               return pointer;
+
        if(pointer == F)
                return F;
 
@@ -42,7 +54,7 @@ INLINE CELL copy_object(CELL pointer)
 
        header = get(UNTAG(pointer));
        untagged = UNTAG(header);
-       if(TAG(header) != FIXNUM_TYPE && in_zone(&active,untagged))
+       if(TAG(header) != FIXNUM_TYPE && in_zone(&tenured,untagged))
        {
                gc_debug("forwarding",untagged);
                return RETAG(untagged,tag);
@@ -59,6 +71,8 @@ INLINE void copy_handle(CELL* handle)
 }
 
 void collect_roots(void);
+void collect_card(CARD *ptr);
+void collect_gen_cards(CELL gen);
 void collect_cards(void);
 void clear_cards(void);
 void primitive_gc(void);
index 857f89d8e93bc82b38721e256243bf143e3757a7..f0c117a6624fe94ac8a99b08b9de8b7f1f3c91d7 100644 (file)
@@ -54,10 +54,10 @@ void load_image(char* filename, int literal_table)
                CELL size = h.size / CELLS;
                allot(h.size);
 
-               if(size != fread((void*)active.base,sizeof(CELL),size,file))
+               if(size != fread((void*)tenured.base,sizeof(CELL),size,file))
                        fatal_error("Wrong data heap length",h.size);
 
-               active.here = active.base + h.size;
+               tenured.here = tenured.base + h.size;
                data_relocation_base = h.relocation_base;
        }
 
@@ -106,9 +106,9 @@ bool save_image(char* filename)
 
        h.magic = IMAGE_MAGIC;
        h.version = IMAGE_VERSION;
-       h.relocation_base = active.base;
+       h.relocation_base = tenured.base;
        h.boot = userenv[BOOT_ENV];
-       h.size = active.here - active.base;
+       h.size = tenured.here - tenured.base;
        h.global = userenv[GLOBAL_ENV];
        h.t = T;
        h.bignum_zero = bignum_zero;
@@ -122,7 +122,7 @@ bool save_image(char* filename)
        ext_h.relocation_base = compiling.base;
        fwrite(&ext_h,sizeof(HEADER_2),1,file);
 
-       fwrite((void*)active.base,h.size,1,file);
+       fwrite((void*)tenured.base,h.size,1,file);
        fwrite((void*)compiling.base,ext_h.size,1,file);
 
        fclose(file);
@@ -133,7 +133,8 @@ bool save_image(char* filename)
 void primitive_save_image(void)
 {
        F_STRING* filename;
-       primitive_gc();
+       /* do a full GC to push everything into tenured space */
+       garbage_collection(TENURED);
        filename = untag_string(dpop());
        save_image(to_c_string(filename));
 }
index 87cdf0d2a8cfa64820720e3a5963d8f6310d56da..e839ff9c683e70ae3616a98692a940cb1acac5e5 100644 (file)
@@ -45,12 +45,14 @@ void init_arena(CELL young_size, CELL aging_size)
        if(heap_start == 0)
                fatal_error("Cannot allocate data heap",total_size);
 
-       alloter = init_zone(&generations[TENURED],aging_size,alloter);
+       alloter = init_zone(&tenured,aging_size,alloter);
        alloter = init_zone(&prior,aging_size,alloter);
 
        for(i = 0; i < GC_GENERATIONS - 1; i++)
                alloter = init_zone(&generations[i],young_size,alloter);
 
+       allot_zone = &nursery;
+
        if(alloter != heap_start + total_size)
                fatal_error("Oops",alloter);
 
@@ -83,20 +85,21 @@ void allot_profile_step(CELL a)
        untag_word_fast(executing)->allot_count += a;
 }
 
-void flip_zones()
-{
-       ZONE z = active;
-       active = prior;
-       prior = z;
-       active.here = active.base;
-}
-
 void primitive_room(void)
 {
+       CELL list = F;
+       int gen;
        box_signed_cell(compiling.limit - compiling.here);
        box_signed_cell(compiling.limit - compiling.base);
-       box_signed_cell(active.limit - active.here);
-       box_signed_cell(active.limit - active.base);
+       for(gen = GC_GENERATIONS - 1; gen >= 0; gen--)
+       {
+               ZONE *z = &generations[gen];
+               list = cons(cons(
+                       tag_fixnum(z->limit - z->here),
+                       tag_fixnum(z->limit - z->base)),
+                       list);
+       }
+       dpush(list);
 }
 
 void primitive_allot_profiling(void)
@@ -124,8 +127,8 @@ void primitive_size(void)
 void primitive_begin_scan(void)
 {
        primitive_gc();
-       heap_scan_ptr = active.base;
-       heap_scan_end = active.here;
+       heap_scan_ptr = tenured.base;
+       heap_scan_end = tenured.here;
        heap_scan = true;
 }
 
index c9e981d33715d5f188175ac54498e91e7a30fcf8..c411b414aff37f11dca8ba479d9afc9b790ad466 100644 (file)
@@ -55,12 +55,14 @@ INLINE bool in_zone(ZONE* z, CELL pointer)
 #define TENURED (GC_GENERATIONS-1)
 
 ZONE generations[GC_GENERATIONS];
+ZONE *allot_zone;
 
-CELL heap_start;
+#define tenured generations[TENURED]
+#define nursery generations[TENURED] /* XXX */
 
-#define active generations[TENURED]
+CELL heap_start;
 
-/* spare semi-space; rotates with generations[TENURED]. */
+/* spare semi-space; rotates with tenured. */
 ZONE prior;
 
 /* card marking write barrier. a card is a byte storing a mark flag,
@@ -82,7 +84,7 @@ it is important that 7 bits is sufficient to represent every
 offset within the card */
 #define CARD_SIZE 16
 #define CARD_BITS 4
-#define CARD_MASK CARD_SIZE-1
+#define CARD_MASK (CARD_SIZE-1)
 
 INLINE CARD card_marked(CARD c)
 {
@@ -104,8 +106,8 @@ INLINE void rebase_card(CARD *c, u8 base)
        *c = base;
 }
 
-#define ADDR_TO_CARD(a) (CARD*)(((a-heap_start)>>CARD_BITS)+(CELL)cards)
-#define CARD_TO_ADDR(c) (CELL*)(((c-(CELL)cards)<<CARD_BITS)+heap_start)
+#define ADDR_TO_CARD(a) (CARD*)((((CELL)a-heap_start)>>CARD_BITS)+(CELL)cards)
+#define CARD_TO_ADDR(c) (CELL*)((((CELL)c-(CELL)cards)<<CARD_BITS)+heap_start)
 
 /* this is an inefficient write barrier. compiled definitions use a more
 efficient one hand-coded in assembly. the write barrier must be called
@@ -123,7 +125,7 @@ INLINE void allot_barrier(CELL address)
        CARD *c = ADDR_TO_CARD(address);
        /* we need to remember the first object allocated in the
        card */
-       rebase_card(c,MIN(card_base(*c),address & CARD_MASK));
+       rebase_card(c,MIN(card_base(*c),(address & CARD_MASK)));
 }
 
 bool allot_profiling;
@@ -146,9 +148,9 @@ INLINE CELL align8(CELL a)
 
 INLINE void* allot(CELL a)
 {
-       CELL h = active.here;
+       CELL h = allot_zone->here;
        allot_barrier(h);
-       active.here += align8(a);
+       allot_zone->here = h + align8(a);
        if(allot_profiling)
                allot_profile_step(align8(a));
        return (void*)h;
index 7e88b25091bdb5acaa5adbb6e354573d1e9a5936..e6b673624651699412b6506c473f3986deb6888e 100644 (file)
@@ -55,7 +55,7 @@ INLINE CELL relocate_data_next(CELL relocating)
 
 void relocate_data()
 {
-       CELL relocating = active.base;
+       CELL relocating = tenured.base;
 
        data_fixup(&userenv[BOOT_ENV]);
        data_fixup(&userenv[GLOBAL_ENV]);
@@ -70,7 +70,7 @@ void relocate_data()
 
        for(;;)
        {
-               if(relocating >= active.here)
+               if(relocating >= tenured.here)
                        break;
 
                relocating = relocate_data_next(relocating);
index 2f0998afcf190c3282ad85aca94aa18a4e1e92ab..5a2ad0e0d5d5cd1934d085a666a9f7c5c95c6595 100644 (file)
@@ -4,7 +4,7 @@ CELL data_relocation_base;
 INLINE void data_fixup(CELL* cell)
 {
        if(TAG(*cell) != FIXNUM_TYPE && *cell != F)
-               *cell += (active.base - data_relocation_base);
+               *cell += (tenured.base - data_relocation_base);
 }
 
 typedef enum {
index f05aff7676382697574c2d269988f2f447623f01..6a72d6133f1affa6010d9bc482e37b3fd6e34d09 100644 (file)
@@ -2,15 +2,11 @@
 
 void signal_handler(int signal, siginfo_t* siginfo, void* uap)
 {
-       if(active.here > active.limit)
+       if(allot_zone->here > allot_zone->limit)
        {
-               fprintf(stderr,"Out of memory\n");
-               fprintf(stderr,"active.base  = %ld\n",active.base);
-               fprintf(stderr,"active.here  = %ld\n",active.here);
-               fprintf(stderr,"active.limit = %ld\n",active.limit);
+               fprintf(stderr,"Out of memory!\n");
+               dump_generations();
                fflush(stderr);
-               flip_zones();
-               dump_stacks();
                exit(1);
        }
        else