Added notes for switching GC's

This commit is contained in:
Justin Ethier 2015-10-14 22:56:25 -04:00
parent 241a54324d
commit e99301024a

864
runtime.c
View file

@ -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
*/ */