mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-23 20:15:05 +02:00
Added notes for switching GC's
This commit is contained in:
parent
241a54324d
commit
e99301024a
1 changed files with 471 additions and 393 deletions
864
runtime.c
864
runtime.c
|
@ -1946,406 +1946,484 @@ void Cyc_apply_from_buf(int argc, object prim, object *buf) {
|
||||||
apply(cont, prim, (object)&args[0]);
|
apply(cont, prim, (object)&args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
///**
|
||||||
* Copy an object to the GC heap
|
// * Copy an object to the GC heap
|
||||||
*/
|
// */
|
||||||
char *transport(x, gcgen) char *x; int gcgen;
|
//char *transport(x, gcgen) char *x; int gcgen;
|
||||||
{
|
//{
|
||||||
if (nullp(x)) return x;
|
// if (nullp(x)) return x;
|
||||||
if (obj_is_char(x)) return x;
|
// if (obj_is_char(x)) return x;
|
||||||
#if DEBUG_GC
|
//#if DEBUG_GC
|
||||||
printf("entered transport ");
|
// printf("entered transport ");
|
||||||
printf("transport %ld\n", type_of(x));
|
// printf("transport %ld\n", type_of(x));
|
||||||
#endif
|
//#endif
|
||||||
switch (type_of(x))
|
// switch (type_of(x))
|
||||||
{case cons_tag:
|
// {case cons_tag:
|
||||||
{register list nx = (list) allocp;
|
// {register list nx = (list) allocp;
|
||||||
type_of(nx) = cons_tag; car(nx) = car(x); cdr(nx) = cdr(x);
|
// type_of(nx) = cons_tag; car(nx) = car(x); cdr(nx) = cdr(x);
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
allocp = ((char *) nx)+sizeof(cons_type);
|
// allocp = ((char *) nx)+sizeof(cons_type);
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case macro_tag:
|
// case macro_tag:
|
||||||
{register macro nx = (macro) allocp;
|
// {register macro nx = (macro) allocp;
|
||||||
type_of(nx) = macro_tag; nx->fn = ((macro) x)->fn;
|
// type_of(nx) = macro_tag; nx->fn = ((macro) x)->fn;
|
||||||
nx->num_args = ((macro) x)->num_args;
|
// nx->num_args = ((macro) x)->num_args;
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
allocp = ((char *) nx)+sizeof(macro_type);
|
// allocp = ((char *) nx)+sizeof(macro_type);
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case closure0_tag:
|
// case closure0_tag:
|
||||||
{register closure0 nx = (closure0) allocp;
|
// {register closure0 nx = (closure0) allocp;
|
||||||
type_of(nx) = closure0_tag; nx->fn = ((closure0) x)->fn;
|
// type_of(nx) = closure0_tag; nx->fn = ((closure0) x)->fn;
|
||||||
nx->num_args = ((closure0) x)->num_args;
|
// nx->num_args = ((closure0) x)->num_args;
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
allocp = ((char *) nx)+sizeof(closure0_type);
|
// allocp = ((char *) nx)+sizeof(closure0_type);
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case closure1_tag:
|
// case closure1_tag:
|
||||||
{register closure1 nx = (closure1) allocp;
|
// {register closure1 nx = (closure1) allocp;
|
||||||
type_of(nx) = closure1_tag; nx->fn = ((closure1) x)->fn;
|
// type_of(nx) = closure1_tag; nx->fn = ((closure1) x)->fn;
|
||||||
nx->num_args = ((closure1) x)->num_args;
|
// nx->num_args = ((closure1) x)->num_args;
|
||||||
nx->elt1 = ((closure1) x)->elt1;
|
// nx->elt1 = ((closure1) x)->elt1;
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(closure1_type);
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure1_type);
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case closure2_tag:
|
// case closure2_tag:
|
||||||
{register closure2 nx = (closure2) allocp;
|
// {register closure2 nx = (closure2) allocp;
|
||||||
type_of(nx) = closure2_tag; nx->fn = ((closure2) x)->fn;
|
// type_of(nx) = closure2_tag; nx->fn = ((closure2) x)->fn;
|
||||||
nx->num_args = ((closure2) x)->num_args;
|
// nx->num_args = ((closure2) x)->num_args;
|
||||||
nx->elt1 = ((closure2) x)->elt1;
|
// nx->elt1 = ((closure2) x)->elt1;
|
||||||
nx->elt2 = ((closure2) x)->elt2;
|
// nx->elt2 = ((closure2) x)->elt2;
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(closure2_type);
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure2_type);
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case closure3_tag:
|
// case closure3_tag:
|
||||||
{register closure3 nx = (closure3) allocp;
|
// {register closure3 nx = (closure3) allocp;
|
||||||
type_of(nx) = closure3_tag; nx->fn = ((closure3) x)->fn;
|
// type_of(nx) = closure3_tag; nx->fn = ((closure3) x)->fn;
|
||||||
nx->num_args = ((closure3) x)->num_args;
|
// nx->num_args = ((closure3) x)->num_args;
|
||||||
nx->elt1 = ((closure3) x)->elt1;
|
// nx->elt1 = ((closure3) x)->elt1;
|
||||||
nx->elt2 = ((closure3) x)->elt2;
|
// nx->elt2 = ((closure3) x)->elt2;
|
||||||
nx->elt3 = ((closure3) x)->elt3;
|
// nx->elt3 = ((closure3) x)->elt3;
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(closure3_type);
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure3_type);
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case closure4_tag:
|
// case closure4_tag:
|
||||||
{register closure4 nx = (closure4) allocp;
|
// {register closure4 nx = (closure4) allocp;
|
||||||
type_of(nx) = closure4_tag; nx->fn = ((closure4) x)->fn;
|
// type_of(nx) = closure4_tag; nx->fn = ((closure4) x)->fn;
|
||||||
nx->num_args = ((closure4) x)->num_args;
|
// nx->num_args = ((closure4) x)->num_args;
|
||||||
nx->elt1 = ((closure4) x)->elt1;
|
// nx->elt1 = ((closure4) x)->elt1;
|
||||||
nx->elt2 = ((closure4) x)->elt2;
|
// nx->elt2 = ((closure4) x)->elt2;
|
||||||
nx->elt3 = ((closure4) x)->elt3;
|
// nx->elt3 = ((closure4) x)->elt3;
|
||||||
nx->elt4 = ((closure4) x)->elt4;
|
// nx->elt4 = ((closure4) x)->elt4;
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(closure4_type);
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure4_type);
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case closureN_tag:
|
// case closureN_tag:
|
||||||
{register closureN nx = (closureN) allocp;
|
// {register closureN nx = (closureN) allocp;
|
||||||
int i;
|
// int i;
|
||||||
type_of(nx) = closureN_tag; nx->fn = ((closureN) x)->fn;
|
// type_of(nx) = closureN_tag; nx->fn = ((closureN) x)->fn;
|
||||||
nx->num_args = ((closureN) x)->num_args;
|
// nx->num_args = ((closureN) x)->num_args;
|
||||||
nx->num_elt = ((closureN) x)->num_elt;
|
// nx->num_elt = ((closureN) x)->num_elt;
|
||||||
nx->elts = (object *)(((char *)nx) + sizeof(closureN_type));
|
// nx->elts = (object *)(((char *)nx) + sizeof(closureN_type));
|
||||||
for (i = 0; i < nx->num_elt; i++) {
|
// for (i = 0; i < nx->num_elt; i++) {
|
||||||
nx->elts[i] = ((closureN) x)->elts[i];
|
// nx->elts[i] = ((closureN) x)->elts[i];
|
||||||
}
|
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(closureN_type) + sizeof(object) * nx->num_elt;
|
|
||||||
return (char *) nx;}
|
|
||||||
case vector_tag:
|
|
||||||
{register vector nx = (vector) allocp;
|
|
||||||
int i;
|
|
||||||
type_of(nx) = vector_tag;
|
|
||||||
nx->num_elt = ((vector) x)->num_elt;
|
|
||||||
nx->elts = (object *)(((char *)nx) + sizeof(vector_type));
|
|
||||||
for (i = 0; i < nx->num_elt; i++) {
|
|
||||||
nx->elts[i] = ((vector) x)->elts[i];
|
|
||||||
}
|
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(vector_type) + sizeof(object) * nx->num_elt;
|
|
||||||
return (char *) nx;}
|
|
||||||
case string_tag:
|
|
||||||
{register string_type *nx = (string_type *) allocp;
|
|
||||||
int str_size = gc_word_align(((string_type *)x)->len + 1);
|
|
||||||
type_of(nx) = string_tag;
|
|
||||||
nx->len = ((string_type *)x)->len;
|
|
||||||
nx->str = ((char *)nx) + sizeof(string_type);
|
|
||||||
memcpy(nx->str, ((string_type *)x)->str, nx->len + 1);
|
|
||||||
//TODO: below is changing, now we will need to always copy the cstring
|
|
||||||
//along with the string_type. need to be careful of any off-by-one errors
|
|
||||||
//here...
|
|
||||||
// if (gcgen == 0) {
|
|
||||||
// // Minor, data heap is not relocated
|
|
||||||
// nx->str = ((string_type *)x)->str;
|
|
||||||
// } else {
|
|
||||||
// // Major collection, data heap is moving
|
|
||||||
// nx->str = dhallocp;
|
|
||||||
// int len = strlen(((string_type *) x)->str);
|
|
||||||
// memcpy(dhallocp, ((string_type *) x)->str, len + 1);
|
|
||||||
// dhallocp += len + 1;
|
|
||||||
// }
|
// }
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(string_type)+str_size;
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(closureN_type) + sizeof(object) * nx->num_elt;
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case integer_tag:
|
// case vector_tag:
|
||||||
{register integer_type *nx = (integer_type *) allocp;
|
// {register vector nx = (vector) allocp;
|
||||||
type_of(nx) = integer_tag; nx->value = ((integer_type *) x)->value;
|
// int i;
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// type_of(nx) = vector_tag;
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(integer_type);
|
// nx->num_elt = ((vector) x)->num_elt;
|
||||||
return (char *) nx;}
|
// nx->elts = (object *)(((char *)nx) + sizeof(vector_type));
|
||||||
case double_tag:
|
// for (i = 0; i < nx->num_elt; i++) {
|
||||||
{register double_type *nx = (double_type *) allocp;
|
// nx->elts[i] = ((vector) x)->elts[i];
|
||||||
type_of(nx) = double_tag; nx->value = ((double_type *) x)->value;
|
// }
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(double_type);
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(vector_type) + sizeof(object) * nx->num_elt;
|
||||||
return (char *) nx;}
|
// return (char *) nx;}
|
||||||
case port_tag:
|
// case string_tag:
|
||||||
{register port_type *nx = (port_type *) allocp;
|
// {register string_type *nx = (string_type *) allocp;
|
||||||
type_of(nx) = port_tag; nx->fp = ((port_type *) x)->fp;
|
// int str_size = gc_word_align(((string_type *)x)->len + 1);
|
||||||
nx->mode = ((port_type *) x)->mode;
|
// type_of(nx) = string_tag;
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
// nx->len = ((string_type *)x)->len;
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(port_type);
|
// nx->str = ((char *)nx) + sizeof(string_type);
|
||||||
return (char *) nx;}
|
// memcpy(nx->str, ((string_type *)x)->str, nx->len + 1);
|
||||||
case cvar_tag:
|
////TODO: below is changing, now we will need to always copy the cstring
|
||||||
{register cvar_type *nx = (cvar_type *) allocp;
|
////along with the string_type. need to be careful of any off-by-one errors
|
||||||
type_of(nx) = cvar_tag; nx->pvar = ((cvar_type *) x)->pvar;
|
////here...
|
||||||
forward(x) = nx; type_of(x) = forward_tag;
|
//// if (gcgen == 0) {
|
||||||
x = (char *) nx; allocp = ((char *) nx)+sizeof(cvar_type);
|
//// // Minor, data heap is not relocated
|
||||||
return (char *) nx;}
|
//// nx->str = ((string_type *)x)->str;
|
||||||
case forward_tag:
|
//// } else {
|
||||||
return (char *) forward(x);
|
//// // Major collection, data heap is moving
|
||||||
case eof_tag: break;
|
//// nx->str = dhallocp;
|
||||||
case primitive_tag: break;
|
//// int len = strlen(((string_type *) x)->str);
|
||||||
case boolean_tag: break;
|
//// memcpy(dhallocp, ((string_type *) x)->str, len + 1);
|
||||||
case symbol_tag: break; // JAE TODO: raise an error here? Should not be possible in real code, though (IE, without GC DEBUG flag)
|
//// dhallocp += len + 1;
|
||||||
default:
|
//// }
|
||||||
printf("transport: bad tag x=%p x.tag=%ld\n",(void *)x,type_of(x)); exit(0);}
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
return x;}
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(string_type)+str_size;
|
||||||
|
// return (char *) nx;}
|
||||||
/* Use overflow macro which already knows which way the stack goes. */
|
// case integer_tag:
|
||||||
/* Major collection, transport objects on stack or old heap */
|
// {register integer_type *nx = (integer_type *) allocp;
|
||||||
#define transp(p) \
|
// type_of(nx) = integer_tag; nx->value = ((integer_type *) x)->value;
|
||||||
temp = (p); \
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
if ((check_overflow(low_limit,temp) && \
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(integer_type);
|
||||||
check_overflow(temp,high_limit)) || \
|
// return (char *) nx;}
|
||||||
(check_overflow(old_heap_low_limit - 1, temp) && \
|
// case double_tag:
|
||||||
check_overflow(temp,old_heap_high_limit + 1))) \
|
// {register double_type *nx = (double_type *) allocp;
|
||||||
(p) = (object) transport(temp,major);
|
// type_of(nx) = double_tag; nx->value = ((double_type *) x)->value;
|
||||||
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
void GC_loop(int major, closure cont, object *ans, int num_ans)
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(double_type);
|
||||||
{char foo;
|
// return (char *) nx;}
|
||||||
int i;
|
// case port_tag:
|
||||||
register object temp;
|
// {register port_type *nx = (port_type *) allocp;
|
||||||
register object low_limit = &foo; /* Move live data above us. */
|
// type_of(nx) = port_tag; nx->fp = ((port_type *) x)->fp;
|
||||||
register object high_limit = stack_begin;
|
// nx->mode = ((port_type *) x)->mode;
|
||||||
register char *scanp = allocp; /* Cheney scan pointer. */
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
register object old_heap_low_limit = low_limit; // Minor-GC default
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(port_type);
|
||||||
register object old_heap_high_limit = high_limit; // Minor-GC default
|
// return (char *) nx;}
|
||||||
|
// case cvar_tag:
|
||||||
char *tmp_bottom = bottom; /* Bottom of tospace. */
|
// {register cvar_type *nx = (cvar_type *) allocp;
|
||||||
char *tmp_allocp = allocp; /* Cheney allocate pointer. */
|
// type_of(nx) = cvar_tag; nx->pvar = ((cvar_type *) x)->pvar;
|
||||||
char *tmp_alloc_end = alloc_end;
|
// forward(x) = nx; type_of(x) = forward_tag;
|
||||||
char *tmp_dhbottom = dhbottom;
|
// x = (char *) nx; allocp = ((char *) nx)+sizeof(cvar_type);
|
||||||
char *tmp_dhallocp = dhallocp;
|
// return (char *) nx;}
|
||||||
char *tmp_dhallocp_end = dhalloc_end;
|
// case forward_tag:
|
||||||
|
// return (char *) forward(x);
|
||||||
if (dhallocp > dhalloc_limit) {
|
// case eof_tag: break;
|
||||||
// Upgrade to major GC
|
// case primitive_tag: break;
|
||||||
major = 1;
|
// case boolean_tag: break;
|
||||||
no_major_gcs++;
|
// case symbol_tag: break; // JAE TODO: raise an error here? Should not be possible in real code, though (IE, without GC DEBUG flag)
|
||||||
no_gcs--;
|
// default:
|
||||||
}
|
// printf("transport: bad tag x=%p x.tag=%ld\n",(void *)x,type_of(x)); exit(0);}
|
||||||
|
// return x;}
|
||||||
if (major) {
|
//
|
||||||
// Initialize new heap (TODO: make a function for this)
|
///* Use overflow macro which already knows which way the stack goes. */
|
||||||
bottom = calloc(1,global_heap_size);
|
///* Major collection, transport objects on stack or old heap */
|
||||||
allocp = (char *) ((((long) bottom)+7) & -8);
|
//#define transp(p) \
|
||||||
alloc_end = allocp + global_heap_size - 8;
|
//temp = (p); \
|
||||||
scanp = allocp;
|
//if ((check_overflow(low_limit,temp) && \
|
||||||
old_heap_low_limit = tmp_bottom;
|
// check_overflow(temp,high_limit)) || \
|
||||||
old_heap_high_limit = tmp_alloc_end;
|
// (check_overflow(old_heap_low_limit - 1, temp) && \
|
||||||
|
// check_overflow(temp,old_heap_high_limit + 1))) \
|
||||||
dhallocp = dhbottom = calloc(1, global_heap_size);
|
// (p) = (object) transport(temp,major);
|
||||||
dhalloc_limit = dhallocp + (long)((global_heap_size - 8) * 0.90);
|
//
|
||||||
dhalloc_end = dhallocp + global_heap_size - 8;
|
//void GC_loop(int major, closure cont, object *ans, int num_ans)
|
||||||
}
|
//{char foo;
|
||||||
|
// int i;
|
||||||
#if DEBUG_GC
|
// register object temp;
|
||||||
printf("\n=== started GC type = %d === \n", major);
|
// register object low_limit = &foo; /* Move live data above us. */
|
||||||
#endif
|
// register object high_limit = stack_begin;
|
||||||
/* Transport GC's continuation and its argument. */
|
// register char *scanp = allocp; /* Cheney scan pointer. */
|
||||||
transp(cont);
|
// register object old_heap_low_limit = low_limit; // Minor-GC default
|
||||||
gc_cont = cont;
|
// register object old_heap_high_limit = high_limit; // Minor-GC default
|
||||||
gc_num_ans = num_ans;
|
//
|
||||||
#if DEBUG_GC
|
// char *tmp_bottom = bottom; /* Bottom of tospace. */
|
||||||
printf("DEBUG done transporting cont\n");
|
// char *tmp_allocp = allocp; /* Cheney allocate pointer. */
|
||||||
#endif
|
// char *tmp_alloc_end = alloc_end;
|
||||||
|
// char *tmp_dhbottom = dhbottom;
|
||||||
/* Prevent overrunning buffer */
|
// char *tmp_dhallocp = dhallocp;
|
||||||
if (num_ans > NUM_GC_ANS) {
|
// char *tmp_dhallocp_end = dhalloc_end;
|
||||||
printf("Fatal error - too many arguments (%d) to GC\n", num_ans);
|
//
|
||||||
exit(1);
|
// if (dhallocp > dhalloc_limit) {
|
||||||
}
|
// // Upgrade to major GC
|
||||||
|
// major = 1;
|
||||||
for (i = 0; i < num_ans; i++){
|
// no_major_gcs++;
|
||||||
transp(ans[i]);
|
// no_gcs--;
|
||||||
gc_ans[i] = ans[i];
|
// }
|
||||||
}
|
//
|
||||||
#if DEBUG_GC
|
// if (major) {
|
||||||
printf("DEBUG done transporting gc_ans\n");
|
// // Initialize new heap (TODO: make a function for this)
|
||||||
#endif
|
// bottom = calloc(1,global_heap_size);
|
||||||
|
// allocp = (char *) ((((long) bottom)+7) & -8);
|
||||||
/* Transport mutations. */
|
// alloc_end = allocp + global_heap_size - 8;
|
||||||
{
|
// scanp = allocp;
|
||||||
list l;
|
// old_heap_low_limit = tmp_bottom;
|
||||||
for (l = mutation_table; !nullp(l); l = cdr(l)) {
|
// old_heap_high_limit = tmp_alloc_end;
|
||||||
object o = car(l);
|
//
|
||||||
if (type_of(o) == cons_tag) {
|
// dhallocp = dhbottom = calloc(1, global_heap_size);
|
||||||
// Transport, if necessary
|
// dhalloc_limit = dhallocp + (long)((global_heap_size - 8) * 0.90);
|
||||||
// TODO: need to test this with major GC, and
|
// dhalloc_end = dhallocp + global_heap_size - 8;
|
||||||
// GC's of list/car-cdr from same generation
|
// }
|
||||||
transp(car(o));
|
//
|
||||||
transp(cdr(o));
|
//#if DEBUG_GC
|
||||||
} else if (type_of(o) == vector_tag) {
|
// printf("\n=== started GC type = %d === \n", major);
|
||||||
int i;
|
//#endif
|
||||||
// TODO: probably too inefficient, try collecting single index
|
// /* Transport GC's continuation and its argument. */
|
||||||
for (i = 0; i < ((vector)o)->num_elt; i++) {
|
// transp(cont);
|
||||||
transp(((vector)o)->elts[i]);
|
// gc_cont = cont;
|
||||||
}
|
// gc_num_ans = num_ans;
|
||||||
} else if (type_of(o) == forward_tag) {
|
//#if DEBUG_GC
|
||||||
// Already transported, skip
|
// printf("DEBUG done transporting cont\n");
|
||||||
} else {
|
//#endif
|
||||||
printf("Unexpected type %ld transporting mutation\n", type_of(o));
|
//
|
||||||
exit(1);
|
// /* Prevent overrunning buffer */
|
||||||
}
|
// if (num_ans > NUM_GC_ANS) {
|
||||||
}
|
// printf("Fatal error - too many arguments (%d) to GC\n", num_ans);
|
||||||
}
|
// exit(1);
|
||||||
clear_mutations(); /* Reset for next time */
|
// }
|
||||||
|
//
|
||||||
/* Transport global variables. */
|
// for (i = 0; i < num_ans; i++){
|
||||||
transp(Cyc_global_variables); /* Internal global used by the runtime */
|
// transp(ans[i]);
|
||||||
{
|
// gc_ans[i] = ans[i];
|
||||||
list l = global_table;
|
// }
|
||||||
for(; !nullp(l); l = cdr(l)){
|
//#if DEBUG_GC
|
||||||
cvar_type *c = (cvar_type *)car(l);
|
// printf("DEBUG done transporting gc_ans\n");
|
||||||
transp(*(c->pvar)); // GC global, not the pvar
|
//#endif
|
||||||
}
|
//
|
||||||
}
|
// /* Transport mutations. */
|
||||||
while (scanp<allocp) /* Scan the newspace. */
|
// {
|
||||||
switch (type_of(scanp))
|
// list l;
|
||||||
{case cons_tag:
|
// for (l = mutation_table; !nullp(l); l = cdr(l)) {
|
||||||
#if DEBUG_GC
|
// object o = car(l);
|
||||||
printf("DEBUG transport cons_tag\n");
|
// if (type_of(o) == cons_tag) {
|
||||||
#endif
|
// // Transport, if necessary
|
||||||
transp(car(scanp)); transp(cdr(scanp));
|
// // TODO: need to test this with major GC, and
|
||||||
scanp += sizeof(cons_type); break;
|
// // GC's of list/car-cdr from same generation
|
||||||
case macro_tag:
|
// transp(car(o));
|
||||||
#if DEBUG_GC
|
// transp(cdr(o));
|
||||||
printf("DEBUG transport macro \n");
|
// } else if (type_of(o) == vector_tag) {
|
||||||
#endif
|
// int i;
|
||||||
scanp += sizeof(macro_type); break;
|
// // TODO: probably too inefficient, try collecting single index
|
||||||
case closure0_tag:
|
// for (i = 0; i < ((vector)o)->num_elt; i++) {
|
||||||
#if DEBUG_GC
|
// transp(((vector)o)->elts[i]);
|
||||||
printf("DEBUG transport closure0 \n");
|
// }
|
||||||
#endif
|
// } else if (type_of(o) == forward_tag) {
|
||||||
scanp += sizeof(closure0_type); break;
|
// // Already transported, skip
|
||||||
case closure1_tag:
|
// } else {
|
||||||
#if DEBUG_GC
|
// printf("Unexpected type %ld transporting mutation\n", type_of(o));
|
||||||
printf("DEBUG transport closure1 \n");
|
// exit(1);
|
||||||
#endif
|
// }
|
||||||
transp(((closure1) scanp)->elt1);
|
// }
|
||||||
scanp += sizeof(closure1_type); break;
|
// }
|
||||||
case closure2_tag:
|
// clear_mutations(); /* Reset for next time */
|
||||||
#if DEBUG_GC
|
//
|
||||||
printf("DEBUG transport closure2 \n");
|
// /* Transport global variables. */
|
||||||
#endif
|
// transp(Cyc_global_variables); /* Internal global used by the runtime */
|
||||||
transp(((closure2) scanp)->elt1); transp(((closure2) scanp)->elt2);
|
// {
|
||||||
scanp += sizeof(closure2_type); break;
|
// list l = global_table;
|
||||||
case closure3_tag:
|
// for(; !nullp(l); l = cdr(l)){
|
||||||
#if DEBUG_GC
|
// cvar_type *c = (cvar_type *)car(l);
|
||||||
printf("DEBUG transport closure3 \n");
|
// transp(*(c->pvar)); // GC global, not the pvar
|
||||||
#endif
|
// }
|
||||||
transp(((closure3) scanp)->elt1); transp(((closure3) scanp)->elt2);
|
// }
|
||||||
transp(((closure3) scanp)->elt3);
|
// while (scanp<allocp) /* Scan the newspace. */
|
||||||
scanp += sizeof(closure3_type); break;
|
// switch (type_of(scanp))
|
||||||
case closure4_tag:
|
// {case cons_tag:
|
||||||
#if DEBUG_GC
|
//#if DEBUG_GC
|
||||||
printf("DEBUG transport closure4 \n");
|
// printf("DEBUG transport cons_tag\n");
|
||||||
#endif
|
//#endif
|
||||||
transp(((closure4) scanp)->elt1); transp(((closure4) scanp)->elt2);
|
// transp(car(scanp)); transp(cdr(scanp));
|
||||||
transp(((closure4) scanp)->elt3); transp(((closure4) scanp)->elt4);
|
// scanp += sizeof(cons_type); break;
|
||||||
scanp += sizeof(closure4_type); break;
|
// case macro_tag:
|
||||||
case closureN_tag:
|
//#if DEBUG_GC
|
||||||
#if DEBUG_GC
|
// printf("DEBUG transport macro \n");
|
||||||
printf("DEBUG transport closureN \n");
|
//#endif
|
||||||
#endif
|
// scanp += sizeof(macro_type); break;
|
||||||
{int i; int n = ((closureN) scanp)->num_elt;
|
// case closure0_tag:
|
||||||
for (i = 0; i < n; i++) {
|
//#if DEBUG_GC
|
||||||
transp(((closureN) scanp)->elts[i]);
|
// printf("DEBUG transport closure0 \n");
|
||||||
}
|
//#endif
|
||||||
scanp += sizeof(closureN_type) + sizeof(object) * n;
|
// scanp += sizeof(closure0_type); break;
|
||||||
}
|
// case closure1_tag:
|
||||||
break;
|
//#if DEBUG_GC
|
||||||
case vector_tag:
|
// printf("DEBUG transport closure1 \n");
|
||||||
#if DEBUG_GC
|
//#endif
|
||||||
printf("DEBUG transport vector \n");
|
// transp(((closure1) scanp)->elt1);
|
||||||
#endif
|
// scanp += sizeof(closure1_type); break;
|
||||||
{int i; int n = ((vector) scanp)->num_elt;
|
// case closure2_tag:
|
||||||
for (i = 0; i < n; i++) {
|
//#if DEBUG_GC
|
||||||
transp(((vector) scanp)->elts[i]);
|
// printf("DEBUG transport closure2 \n");
|
||||||
}
|
//#endif
|
||||||
scanp += sizeof(vector_type) + sizeof(object) * n;
|
// transp(((closure2) scanp)->elt1); transp(((closure2) scanp)->elt2);
|
||||||
}
|
// scanp += sizeof(closure2_type); break;
|
||||||
break;
|
// case closure3_tag:
|
||||||
case string_tag: {
|
//#if DEBUG_GC
|
||||||
#if DEBUG_GC
|
// printf("DEBUG transport closure3 \n");
|
||||||
printf("DEBUG transport string \n");
|
//#endif
|
||||||
#endif
|
// transp(((closure3) scanp)->elt1); transp(((closure3) scanp)->elt2);
|
||||||
string_type *x = (string_type *)scanp;
|
// transp(((closure3) scanp)->elt3);
|
||||||
scanp += sizeof(string_type);
|
// scanp += sizeof(closure3_type); break;
|
||||||
scanp += gc_word_align(x->len + 1);
|
// case closure4_tag:
|
||||||
break;
|
//#if DEBUG_GC
|
||||||
}
|
// printf("DEBUG transport closure4 \n");
|
||||||
//TODO: cstring is now after string_type, so need to skip that, too.
|
//#endif
|
||||||
//stack allocations should be OK since we are only scanning the newspace here,
|
// transp(((closure4) scanp)->elt1); transp(((closure4) scanp)->elt2);
|
||||||
//but should double-check that... (though we are not able to even scan the
|
// transp(((closure4) scanp)->elt3); transp(((closure4) scanp)->elt4);
|
||||||
//stack so should be fine)
|
// scanp += sizeof(closure4_type); break;
|
||||||
case integer_tag:
|
// case closureN_tag:
|
||||||
#if DEBUG_GC
|
//#if DEBUG_GC
|
||||||
printf("DEBUG transport integer \n");
|
// printf("DEBUG transport closureN \n");
|
||||||
#endif
|
//#endif
|
||||||
scanp += sizeof(integer_type); break;
|
// {int i; int n = ((closureN) scanp)->num_elt;
|
||||||
case double_tag:
|
// for (i = 0; i < n; i++) {
|
||||||
#if DEBUG_GC
|
// transp(((closureN) scanp)->elts[i]);
|
||||||
printf("DEBUG transport double \n");
|
// }
|
||||||
#endif
|
// scanp += sizeof(closureN_type) + sizeof(object) * n;
|
||||||
scanp += sizeof(double_type); break;
|
// }
|
||||||
case port_tag:
|
// break;
|
||||||
#if DEBUG_GC
|
// case vector_tag:
|
||||||
printf("DEBUG transport port \n");
|
//#if DEBUG_GC
|
||||||
#endif
|
// printf("DEBUG transport vector \n");
|
||||||
scanp += sizeof(port_type); break;
|
//#endif
|
||||||
case cvar_tag:
|
// {int i; int n = ((vector) scanp)->num_elt;
|
||||||
#if DEBUG_GC
|
// for (i = 0; i < n; i++) {
|
||||||
printf("DEBUG transport cvar \n");
|
// transp(((vector) scanp)->elts[i]);
|
||||||
#endif
|
// }
|
||||||
scanp += sizeof(cvar_type); break;
|
// scanp += sizeof(vector_type) + sizeof(object) * n;
|
||||||
case eof_tag:
|
// }
|
||||||
case primitive_tag:
|
// break;
|
||||||
case symbol_tag:
|
// case string_tag: {
|
||||||
case boolean_tag:
|
//#if DEBUG_GC
|
||||||
default:
|
// printf("DEBUG transport string \n");
|
||||||
printf("GC: bad tag scanp=%p scanp.tag=%ld\n",(void *)scanp,type_of(scanp));
|
//#endif
|
||||||
exit(0);}
|
// string_type *x = (string_type *)scanp;
|
||||||
|
// scanp += sizeof(string_type);
|
||||||
if (major) {
|
// scanp += gc_word_align(x->len + 1);
|
||||||
free(tmp_bottom);
|
// break;
|
||||||
free(tmp_dhbottom);
|
// }
|
||||||
}
|
////TODO: cstring is now after string_type, so need to skip that, too.
|
||||||
}
|
////stack allocations should be OK since we are only scanning the newspace here,
|
||||||
|
////but should double-check that... (though we are not able to even scan the
|
||||||
|
////stack so should be fine)
|
||||||
|
// case integer_tag:
|
||||||
|
//#if DEBUG_GC
|
||||||
|
// printf("DEBUG transport integer \n");
|
||||||
|
//#endif
|
||||||
|
// scanp += sizeof(integer_type); break;
|
||||||
|
// case double_tag:
|
||||||
|
//#if DEBUG_GC
|
||||||
|
// printf("DEBUG transport double \n");
|
||||||
|
//#endif
|
||||||
|
// scanp += sizeof(double_type); break;
|
||||||
|
// case port_tag:
|
||||||
|
//#if DEBUG_GC
|
||||||
|
// printf("DEBUG transport port \n");
|
||||||
|
//#endif
|
||||||
|
// scanp += sizeof(port_type); break;
|
||||||
|
// case cvar_tag:
|
||||||
|
//#if DEBUG_GC
|
||||||
|
// printf("DEBUG transport cvar \n");
|
||||||
|
//#endif
|
||||||
|
// scanp += sizeof(cvar_type); break;
|
||||||
|
// case eof_tag:
|
||||||
|
// case primitive_tag:
|
||||||
|
// case symbol_tag:
|
||||||
|
// case boolean_tag:
|
||||||
|
// default:
|
||||||
|
// printf("GC: bad tag scanp=%p scanp.tag=%ld\n",(void *)scanp,type_of(scanp));
|
||||||
|
// exit(0);}
|
||||||
|
//
|
||||||
|
// if (major) {
|
||||||
|
// free(tmp_bottom);
|
||||||
|
// free(tmp_dhbottom);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans;
|
||||||
|
//{
|
||||||
|
// /* Only room for one more minor-GC, so do a major one.
|
||||||
|
// * Not sure this is the best strategy, it may be better to do major
|
||||||
|
// * ones sooner, perhaps after every x minor GC's.
|
||||||
|
// *
|
||||||
|
// * Also may need to consider dynamically increasing heap size, but
|
||||||
|
// * by how much (1.3x, 1.5x, etc) and when? I suppose when heap usage
|
||||||
|
// * after a collection is above a certain percentage, then it would be
|
||||||
|
// * necessary to increase heap size the next time.
|
||||||
|
// */
|
||||||
|
// if (allocp >= (bottom + (global_heap_size - global_stack_size))) {
|
||||||
|
// //printf("Possibly only room for one more minor GC. no_gcs = %ld\n", no_gcs);
|
||||||
|
// no_major_gcs++;
|
||||||
|
// GC_loop(1, cont, ans, num_ans);
|
||||||
|
// } else {
|
||||||
|
// no_gcs++; /* Count the number of minor GC's. */
|
||||||
|
// GC_loop(0, cont, ans, num_ans);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /* You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind... */
|
||||||
|
// longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */
|
||||||
|
//}
|
||||||
|
|
||||||
void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans;
|
void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans;
|
||||||
{
|
// TODO: take 'live' objects from the stack and allocate them on the heap
|
||||||
/* Only room for one more minor-GC, so do a major one.
|
/*
|
||||||
* Not sure this is the best strategy, it may be better to do major
|
note fwd pointers are only ever placed on the stack, never the heap
|
||||||
* ones sooner, perhaps after every x minor GC's.
|
|
||||||
*
|
|
||||||
* Also may need to consider dynamically increasing heap size, but
|
|
||||||
* by how much (1.3x, 1.5x, etc) and when? I suppose when heap usage
|
|
||||||
* after a collection is above a certain percentage, then it would be
|
|
||||||
* necessary to increase heap size the next time.
|
|
||||||
*/
|
|
||||||
if (allocp >= (bottom + (global_heap_size - global_stack_size))) {
|
|
||||||
//printf("Possibly only room for one more minor GC. no_gcs = %ld\n", no_gcs);
|
|
||||||
no_major_gcs++;
|
|
||||||
GC_loop(1, cont, ans, num_ans);
|
|
||||||
} else {
|
|
||||||
no_gcs++; /* Count the number of minor GC's. */
|
|
||||||
GC_loop(0, cont, ans, num_ans);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind... */
|
we now have 2 GC's:
|
||||||
|
- Stack GC, a minor collection where we move live stack objs to heap
|
||||||
|
- Heap GC, a major collection where we do mark&sweep
|
||||||
|
|
||||||
|
when replacing an object,
|
||||||
|
- only need to do this for objects on 'this' stack
|
||||||
|
- if object is a fwd pointer, return it's forwarding address
|
||||||
|
- otherwise,
|
||||||
|
* allocate them on the heap
|
||||||
|
* return the new address
|
||||||
|
* leave a forwarding pointer on the stack with the new address
|
||||||
|
- may be able to modify transp macro to do this part
|
||||||
|
|
||||||
|
can still use write buffer to ensure any heap->stack references are handled
|
||||||
|
|
||||||
|
need to transport:
|
||||||
|
- stack closure/args
|
||||||
|
- mutation write barrier
|
||||||
|
- globals
|
||||||
|
|
||||||
|
after transport is complete, we will not be scanning newspace but
|
||||||
|
do need to transport any stack objects referenced by the above
|
||||||
|
a couple of ideas:
|
||||||
|
- create a list of allocated objects, and pass over them in much
|
||||||
|
the same way the cheney algorithm does (2 "fingers"??). I think
|
||||||
|
this could actually just be a list of pointers since we want to
|
||||||
|
copy to the heap not the scan space. the goal is just to ensure
|
||||||
|
all live stack references are moved to the heap. trick here is to
|
||||||
|
ensure scan space is large enough, although if it runs out
|
||||||
|
we can just allocate a new space (of say double the size),
|
||||||
|
memcpy the old one, and update scanp/allocp accordingly.
|
||||||
|
* can use a bump pointer to build the list, so it should be
|
||||||
|
fairly efficient, especially if we don't have to resize too much
|
||||||
|
* will be writing all of this code from scratch, but can use
|
||||||
|
existing scan code as a guide
|
||||||
|
- or, during transport recursively transport objects that could
|
||||||
|
contain references (closures, lists, etc). This may be more
|
||||||
|
convenient to code, although it requires stack space to traverse
|
||||||
|
the structures. I think it might also get stuck processing circular
|
||||||
|
structures (!!!), so this approach is not an option
|
||||||
|
TBD how (or even if) this can scale to multiple threads...
|
||||||
|
is is possible to use write barrier(s) to detect if one thread is
|
||||||
|
working with another's data during GC? This will be an important
|
||||||
|
point to keep in mind as the code is being written
|
||||||
|
|
||||||
|
!!!
|
||||||
|
IMPORTANT - does the timing of GC matter? for example, if we GC before
|
||||||
|
scanning all the stack space, there might be an object referenced by
|
||||||
|
a live stack object that would get freed because we haven't gotten to
|
||||||
|
it yet!
|
||||||
|
|
||||||
|
so I think we have to scan all the stack space before doing a GC.
|
||||||
|
alternatively, can we use a write barrier to keep track of when a
|
||||||
|
stack object references one on the heap? that would effectively make
|
||||||
|
the heap object into a root until stack GC
|
||||||
|
|
||||||
|
Originally thought this, but now not so sure because it seems the above
|
||||||
|
has to be taken into account:
|
||||||
|
|
||||||
|
Do not have to explicitly GC until heap is full enough for one to
|
||||||
|
be initiated. do need to code gc_collect though, and ensure it is
|
||||||
|
called at the appropriate time.
|
||||||
|
|
||||||
|
I think everything else will work as written, but not quite sure how
|
||||||
|
to handle this detail yet. and it is very important to get right
|
||||||
|
!!!!
|
||||||
|
|
||||||
|
thoughts:
|
||||||
|
- worth having a write barrier for globals? that is, only GC those that
|
||||||
|
were modified. just an idea...
|
||||||
|
*/
|
||||||
longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */
|
longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive a list of arguments and apply them to the given function
|
* Receive a list of arguments and apply them to the given function
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Reference in a new issue