factor/native/gc.c

230 lines
4.5 KiB
C
Raw Normal View History

2004-07-16 02:26:21 -04:00
#include "factor.h"
2005-05-10 22:30:58 -04:00
/* Generational copying garbage collector */
2004-07-16 02:26:21 -04:00
void collect_roots(void)
{
int i;
CELL ptr;
2005-05-10 22:30:58 -04:00
gc_debug("root: t",T);
2005-02-19 23:25:21 -05:00
COPY_OBJECT(T);
2005-05-10 22:30:58 -04:00
gc_debug("root: bignum_zero",bignum_zero);
COPY_OBJECT(bignum_zero);
gc_debug("root: bignum_pos_one",bignum_pos_one);
COPY_OBJECT(bignum_pos_one);
gc_debug("root: bignum_neg_one",bignum_neg_one);
COPY_OBJECT(bignum_neg_one);
gc_debug("root: callframe",callframe);
2005-02-19 23:25:21 -05:00
COPY_OBJECT(callframe);
2005-05-10 22:30:58 -04:00
gc_debug("root: executing",executing);
2005-02-19 23:25:21 -05:00
COPY_OBJECT(executing);
for(ptr = ds_bot; ptr <= ds; ptr += CELLS)
2005-02-19 23:25:21 -05:00
copy_handle((CELL*)ptr);
for(ptr = cs_bot; ptr <= cs; ptr += CELLS)
2005-02-19 23:25:21 -05:00
copy_handle((CELL*)ptr);
for(i = 0; i < USER_ENV; i++)
2005-02-19 23:25:21 -05:00
copy_handle(&userenv[i]);
}
2004-07-16 02:26:21 -04:00
/*
Given a pointer to a tagged pointer to oldspace, copy it to newspace.
If the object has already been copied, return the forwarding
pointer address without copying anything; otherwise, install
a new forwarding pointer.
*/
CELL copy_object_impl(CELL pointer)
2004-07-16 02:26:21 -04:00
{
CELL newpointer;
gc_debug("copy_object",pointer);
newpointer = (CELL)copy_untagged_object((void*)UNTAG(pointer),
object_size(pointer));
put(UNTAG(pointer),RETAG(newpointer,OBJECT_TYPE));
return newpointer;
2004-07-16 02:26:21 -04:00
}
INLINE void collect_object(CELL scan)
2004-07-16 02:26:21 -04:00
{
switch(untag_header(get(scan)))
{
2004-07-27 23:29:37 -04:00
case WORD_TYPE:
collect_word((F_WORD*)scan);
2004-07-27 23:29:37 -04:00
break;
2004-07-16 02:26:21 -04:00
case ARRAY_TYPE:
case TUPLE_TYPE:
collect_array((F_ARRAY*)scan);
2004-07-16 02:26:21 -04:00
break;
2005-01-27 20:06:10 -05:00
case HASHTABLE_TYPE:
collect_hashtable((F_HASHTABLE*)scan);
break;
2004-07-16 02:26:21 -04:00
case VECTOR_TYPE:
collect_vector((F_VECTOR*)scan);
2004-07-16 02:26:21 -04:00
break;
case SBUF_TYPE:
collect_sbuf((F_SBUF*)scan);
2004-07-16 02:26:21 -04:00
break;
2004-12-25 18:08:20 -05:00
case DLL_TYPE:
collect_dll((DLL*)scan);
2004-12-25 18:08:20 -05:00
break;
2005-04-09 18:30:46 -04:00
case DISPLACED_ALIEN_TYPE:
collect_displaced_alien((DISPLACED_ALIEN*)scan);
break;
2004-07-16 02:26:21 -04:00
}
}
INLINE CELL collect_next(CELL scan)
2004-07-16 02:26:21 -04:00
{
CELL size;
2004-07-16 02:26:21 -04:00
gc_debug("collect_next",scan);
gc_debug("collect_next header",get(scan));
if(headerp(get(scan)))
2004-07-16 02:26:21 -04:00
{
size = untagged_object_size(scan);
collect_object(scan);
}
else
{
size = CELLS;
2005-02-19 23:25:21 -05:00
copy_handle((CELL*)scan);
2004-07-16 02:26:21 -04:00
}
return scan + size;
2004-07-16 02:26:21 -04:00
}
2005-05-11 00:43:52 -04:00
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)
2004-07-16 02:26:21 -04:00
{
2005-03-21 20:59:30 -05:00
s64 start = current_millis();
CELL scan;
2004-11-22 19:15:14 -05:00
2005-02-17 21:19:27 -05:00
if(heap_scan)
{
fprintf(stderr,"GC disabled\n");
fflush(stderr);
return;
}
2004-08-29 03:20:19 -04:00
gc_in_progress = true;
2005-05-11 00:43:52 -04:00
begin_gc(gen);
/* initialize chase pointer */
scan = allot_zone->here;
2005-05-10 22:30:58 -04:00
2004-08-13 02:19:22 -04:00
collect_roots();
2005-05-10 22:30:58 -04:00
collect_cards();
/* collect literal objects referenced from compiled code */
collect_literals();
2005-05-11 00:43:52 -04:00
while(scan < allot_zone->here)
2004-07-16 02:26:21 -04:00
{
gc_debug("scan loop",scan);
scan = collect_next(scan);
2004-07-16 02:26:21 -04:00
}
2005-05-11 00:43:52 -04:00
end_gc(gen);
2004-07-16 02:26:21 -04:00
gc_debug("gc done",0);
2004-08-29 03:20:19 -04:00
gc_in_progress = false;
2004-11-22 19:15:14 -05:00
gc_time += (current_millis() - start);
2004-07-16 02:26:21 -04:00
}
2005-05-11 00:43:52 -04:00
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)
{
2005-05-11 00:43:52 -04:00
if(nursery.here > nursery.alarm)
primitive_gc();
}
2004-11-22 19:15:14 -05:00
void primitive_gc_time(void)
{
maybe_garbage_collection();
dpush(tag_bignum(s48_long_long_to_bignum(gc_time)));
2004-11-22 19:15:14 -05:00
}