2004-07-16 02:26:21 -04:00
|
|
|
#include "factor.h"
|
|
|
|
|
|
|
|
/* Stop-and-copy garbage collection using Cheney's algorithm. */
|
|
|
|
|
2004-08-28 22:25:59 -04:00
|
|
|
/* #define GC_DEBUG */
|
2004-07-16 02:26:21 -04:00
|
|
|
|
|
|
|
INLINE void gc_debug(char* msg, CELL x) {
|
|
|
|
#ifdef GC_DEBUG
|
|
|
|
printf("%s %d\n",msg,x);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
void copy_object(CELL* handle)
|
|
|
|
{
|
|
|
|
CELL pointer = *handle;
|
|
|
|
CELL tag = TAG(pointer);
|
|
|
|
CELL header, newpointer;
|
|
|
|
|
2004-09-08 02:31:03 -04:00
|
|
|
if(tag == FIXNUM_TYPE || pointer == F)
|
2004-07-16 02:26:21 -04:00
|
|
|
return;
|
2004-11-27 22:26:05 -05:00
|
|
|
|
2004-08-31 20:31:16 -04:00
|
|
|
if(in_zone(&active,pointer))
|
2004-07-31 14:58:16 -04:00
|
|
|
critical_error("copy_object given newspace ptr",pointer);
|
|
|
|
|
2004-07-16 02:26:21 -04:00
|
|
|
header = get(UNTAG(pointer));
|
|
|
|
|
|
|
|
if(TAG(header) == GC_COLLECTED)
|
|
|
|
{
|
|
|
|
newpointer = UNTAG(header);
|
|
|
|
gc_debug("FORWARDING",newpointer);
|
|
|
|
}
|
2004-08-10 00:58:52 -04:00
|
|
|
else if(TAG(pointer) == GC_COLLECTED)
|
|
|
|
{
|
|
|
|
critical_error("asked to copy forwarding pointer",pointer);
|
|
|
|
newpointer = 0; /* to shut up gcc */
|
|
|
|
}
|
2004-07-16 02:26:21 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
gc_debug("copy_object",pointer);
|
2004-08-04 22:43:58 -04:00
|
|
|
newpointer = (CELL)copy_untagged_object((void*)UNTAG(pointer),
|
2004-07-16 02:26:21 -04:00
|
|
|
object_size(pointer));
|
|
|
|
put(UNTAG(pointer),RETAG(newpointer,GC_COLLECTED));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tag == GC_COLLECTED)
|
2004-07-20 02:59:32 -04:00
|
|
|
critical_error("installing forwarding pointer in newspace",newpointer);
|
2004-07-16 02:26:21 -04:00
|
|
|
|
|
|
|
*handle = RETAG(newpointer,tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
void collect_object(void)
|
|
|
|
{
|
|
|
|
CELL size = untagged_object_size(scan);
|
|
|
|
gc_debug("collect_object",scan);
|
|
|
|
gc_debug("collect_object size=",size);
|
|
|
|
|
|
|
|
switch(untag_header(get(scan)))
|
|
|
|
{
|
2004-07-27 23:29:37 -04:00
|
|
|
case WORD_TYPE:
|
2004-12-10 21:46:42 -05:00
|
|
|
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:
|
2004-12-10 21:46:42 -05:00
|
|
|
collect_array((F_ARRAY*)scan);
|
2004-07-16 02:26:21 -04:00
|
|
|
break;
|
|
|
|
case VECTOR_TYPE:
|
2004-12-10 21:46:42 -05:00
|
|
|
collect_vector((F_VECTOR*)scan);
|
2004-07-16 02:26:21 -04:00
|
|
|
break;
|
|
|
|
case SBUF_TYPE:
|
2004-12-10 21:46:42 -05:00
|
|
|
collect_sbuf((F_SBUF*)scan);
|
2004-07-16 02:26:21 -04:00
|
|
|
break;
|
2004-08-12 17:36:36 -04:00
|
|
|
case PORT_TYPE:
|
2004-12-10 21:46:42 -05:00
|
|
|
collect_port((F_PORT*)scan);
|
2004-07-31 14:58:16 -04:00
|
|
|
break;
|
2004-07-16 02:26:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
scan += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void collect_next(void)
|
|
|
|
{
|
|
|
|
gc_debug("collect_next",scan);
|
|
|
|
gc_debug("collect_next header",get(scan));
|
|
|
|
switch(TAG(get(scan)))
|
|
|
|
{
|
|
|
|
case HEADER_TYPE:
|
|
|
|
collect_object();
|
|
|
|
break;
|
|
|
|
default:
|
2004-08-04 22:43:58 -04:00
|
|
|
copy_object((CELL*)scan);
|
2004-07-16 02:26:21 -04:00
|
|
|
scan += CELLS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-13 02:19:22 -04:00
|
|
|
void collect_roots(void)
|
2004-07-16 02:26:21 -04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2004-08-12 02:13:43 -04:00
|
|
|
CELL ptr;
|
|
|
|
|
2004-07-16 02:26:21 -04:00
|
|
|
gc_debug("collect_roots",scan);
|
2004-09-08 02:31:03 -04:00
|
|
|
/*T must be the first in the heap */
|
2004-07-16 02:26:21 -04:00
|
|
|
copy_object(&T);
|
2004-08-29 01:04:42 -04:00
|
|
|
/* the bignum 0 1 -1 constants must be the next three */
|
2004-08-25 02:00:52 -04:00
|
|
|
copy_bignum_constants();
|
2004-08-29 01:04:42 -04:00
|
|
|
copy_object(&callframe);
|
2004-08-12 02:13:43 -04:00
|
|
|
|
2004-11-06 21:03:35 -05:00
|
|
|
for(ptr = ds_bot; ptr <= ds; ptr += CELLS)
|
2004-08-12 02:13:43 -04:00
|
|
|
copy_object((void*)ptr);
|
|
|
|
|
2004-11-06 21:03:35 -05:00
|
|
|
for(ptr = cs_bot; ptr <= cs; ptr += CELLS)
|
2004-08-12 02:13:43 -04:00
|
|
|
copy_object((void*)ptr);
|
|
|
|
|
2004-07-16 02:26:21 -04:00
|
|
|
for(i = 0; i < USER_ENV; i++)
|
2004-08-20 18:48:08 -04:00
|
|
|
copy_object(&userenv[i]);
|
2004-07-16 02:26:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void primitive_gc(void)
|
|
|
|
{
|
2004-12-10 21:39:45 -05:00
|
|
|
int64_t start = current_millis();
|
2004-11-22 19:15:14 -05:00
|
|
|
|
2004-08-29 03:20:19 -04:00
|
|
|
gc_in_progress = true;
|
|
|
|
|
2004-07-16 02:26:21 -04:00
|
|
|
flip_zones();
|
2004-08-31 20:31:16 -04:00
|
|
|
scan = active.here = active.base;
|
2004-08-13 02:19:22 -04:00
|
|
|
collect_roots();
|
|
|
|
collect_io_tasks();
|
2004-09-06 22:39:12 -04:00
|
|
|
/* collect literal objects referenced from compiled code */
|
|
|
|
collect_literals();
|
2004-08-31 20:31:16 -04:00
|
|
|
while(scan < active.here)
|
2004-07-16 02:26:21 -04:00
|
|
|
{
|
|
|
|
gc_debug("scan loop",scan);
|
|
|
|
collect_next();
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|
2004-10-12 23:49:43 -04:00
|
|
|
|
|
|
|
/* 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)
|
2004-10-17 19:01:16 -04:00
|
|
|
primitive_gc();
|
2004-10-12 23:49:43 -04:00
|
|
|
}
|
2004-11-22 19:15:14 -05:00
|
|
|
|
|
|
|
void primitive_gc_time(void)
|
|
|
|
{
|
|
|
|
maybe_garbage_collection();
|
|
|
|
dpush(tag_object(s48_long_long_to_bignum(gc_time)));
|
|
|
|
}
|