Copy objects into heap while we have the heap lock

Attempting to prevent issues with unitialized memory. Unfortunately this is not the primary cause of the errors.
This commit is contained in:
Justin Ethier 2015-11-19 23:00:53 -05:00
parent 173e1ca407
commit 8bf20a05b5
3 changed files with 183 additions and 98 deletions

163
gc.c
View file

@ -109,6 +109,159 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size)
return h;
}
// Copy given object into given heap object
char *gc_copy_obj(object dest, char *obj, gc_thread_data *thd)
{
// NOTE: no additional type checking because this is called from gc_move
// which already does that
switch(type_of(obj)){
case cons_tag: {
list hp = dest;
hp->hdr.mark = thd->gc_alloc_color;
type_of(hp) = cons_tag;
car(hp) = car(obj);
cdr(hp) = cdr(obj);
return (char *)hp;
}
case macro_tag: {
macro_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = macro_tag;
hp->fn = ((macro) obj)->fn;
hp->num_args = ((macro) obj)->num_args;
return (char *)hp;
}
case closure0_tag: {
closure0_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure0_tag;
hp->fn = ((closure0) obj)->fn;
hp->num_args = ((closure0) obj)->num_args;
return (char *)hp;
}
case closure1_tag: {
closure1_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure1_tag;
hp->fn = ((closure1) obj)->fn;
hp->num_args = ((closure1) obj)->num_args;
hp->elt1 = ((closure1) obj)->elt1;
return (char *)hp;
}
case closure2_tag: {
closure2_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure2_tag;
hp->fn = ((closure2) obj)->fn;
hp->num_args = ((closure2) obj)->num_args;
hp->elt1 = ((closure2) obj)->elt1;
hp->elt2 = ((closure2) obj)->elt2;
return (char *)hp;
}
case closure3_tag: {
closure3_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure3_tag;
hp->fn = ((closure3) obj)->fn;
hp->num_args = ((closure3) obj)->num_args;
hp->elt1 = ((closure3) obj)->elt1;
hp->elt2 = ((closure3) obj)->elt2;
hp->elt3 = ((closure3) obj)->elt3;
return (char *)hp;
}
case closure4_tag: {
closure4_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure4_tag;
hp->fn = ((closure4) obj)->fn;
hp->num_args = ((closure4) obj)->num_args;
hp->elt1 = ((closure4) obj)->elt1;
hp->elt2 = ((closure4) obj)->elt2;
hp->elt3 = ((closure4) obj)->elt3;
hp->elt4 = ((closure4) obj)->elt4;
return (char *)hp;
}
case closureN_tag: {
int i;
closureN_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closureN_tag;
hp->fn = ((closureN) obj)->fn;
hp->num_args = ((closureN) obj)->num_args;
hp->num_elt = ((closureN) obj)-> num_elt;
hp->elts = (object *)(((char *)hp) + sizeof(closureN_type));
for (i = 0; i < hp->num_elt; i++) {
hp->elts[i] = ((closureN) obj)->elts[i];
}
return (char *)hp;
}
case vector_tag: {
int i;
vector_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = vector_tag;
hp->num_elt = ((vector) obj)-> num_elt;
hp->elts = (object *)(((char *)hp) + sizeof(vector_type));
for (i = 0; i < hp->num_elt; i++) {
hp->elts[i] = ((vector) obj)->elts[i];
}
return (char *)hp;
}
case string_tag: {
char *s;
string_type *hp = dest;
s = ((char *)hp) + sizeof(string_type);
memcpy(s, string_str(obj), string_len(obj) + 1);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = string_tag;
string_len(hp) = string_len(obj);
string_str(hp) = s;
return (char *)hp;
}
case integer_tag: {
integer_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = integer_tag;
hp->value = ((integer_type *) obj)->value;
return (char *)hp;
}
case double_tag: {
double_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = double_tag;
hp->value = ((double_type *) obj)->value;
return (char *)hp;
}
case port_tag: {
port_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = port_tag;
hp->fp = ((port_type *) obj)->fp;
hp->mode = ((port_type *) obj)->mode;
return (char *)hp;
}
case cvar_tag: {
cvar_type *hp = dest;
mark(hp) = thd->gc_alloc_color;
type_of(hp) = cvar_tag;
hp->pvar = ((cvar_type *) obj)->pvar;
return (char *)hp;
}
case forward_tag:
return (char *)forward(obj);
case eof_tag:
case primitive_tag:
case boolean_tag:
case symbol_tag:
break;
default:
fprintf(stderr, "gc_copy_obj: bad tag obj=%p obj.tag=%ld\n",(object) obj, type_of(obj));
exit(1);
}
return (char *)obj;
}
int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size)
{
size_t cur_size, new_size;
@ -125,7 +278,7 @@ printf("DEBUG - grew heap\n");
return (h_new != NULL);
}
void *gc_try_alloc(gc_heap *h, size_t size)
void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd)
{
gc_free_list *f1, *f2, *f3;
pthread_mutex_lock(&heap_lock);
@ -143,6 +296,8 @@ void *gc_try_alloc(gc_heap *h, size_t size)
} else { /* Take the whole chunk */
f1->next = f2->next;
}
// Copy object into heap now to avoid any uninitialized memory issues
gc_copy_obj(f2, obj, thd);
pthread_mutex_unlock(&heap_lock);
return f2;
}
@ -157,7 +312,7 @@ void *gc_try_alloc(gc_heap *h, size_t size)
// maybe only lock during each individual operation, not for a whole
// sweep or alloc
void *gc_alloc(gc_heap *h, size_t size, int *heap_grown)
void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *heap_grown)
{
void *result = NULL;
size_t max_freed = 0, sum_freed = 0, total_size;
@ -166,7 +321,7 @@ void *gc_alloc(gc_heap *h, size_t size, int *heap_grown)
// the allowed ratio, try growing heap.
// then try realloc. if cannot alloc now, then throw out of memory error
size = gc_heap_align(size);
result = gc_try_alloc(h, size);
result = gc_try_alloc(h, size, obj, thd);
if (!result) {
// TODO: may want to consider not doing this now, and implementing gc_collect as
// part of the runtime, since we would have all of the roots, stack args,
@ -181,7 +336,7 @@ void *gc_alloc(gc_heap *h, size_t size, int *heap_grown)
gc_grow_heap(h, size, 0);
*heap_grown = 1;
// }
result = gc_try_alloc(h, size);
result = gc_try_alloc(h, size, obj, thd);
if (!result) {
fprintf(stderr, "out of memory error allocating %d bytes\n", size);
exit(1); // TODO: throw error???

View file

@ -129,8 +129,9 @@ void gc_initialize();
void gc_add_mutator(gc_thread_data *thd);
gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size);
int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size);
void *gc_try_alloc(gc_heap *h, size_t size);
void *gc_alloc(gc_heap *h, size_t size, int *heap_grown);
char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd);
void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd);
void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *heap_grown);
size_t gc_allocated_bytes(object obj);
gc_heap *gc_heap_last(gc_heap *h);
size_t gc_heap_total_size(gc_heap *h);

113
runtime.c
View file

@ -2456,16 +2456,17 @@ void gc_mark_globals()
char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) {
if (!is_object_type(obj)) return obj;
//gcMoveCountsDEBUG[type_of(obj)]++;
// !!!
// TODO: clean up code below and consolidate with gc_copy_obj in gc.c:
// !!!
//gcMoveCountsDEBUG[type_of(obj)]++;
//printf("DEBUG gc_move type = %ld\n", type_of(obj)); // JAE DEBUG
switch(type_of(obj)){
case cons_tag: {
list hp = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); // hp ==> new heap object
hp->hdr.mark = thd->gc_alloc_color;
type_of(hp) = cons_tag;
car(hp) = car(obj);
cdr(hp) = cdr(obj);
list hp = gc_alloc(Cyc_heap, sizeof(cons_type), obj, thd, heap_grown); // hp ==> new heap object
forward(obj) = hp;
type_of(obj) = forward_tag;
// keep track of each allocation so we can scan/move
@ -2474,169 +2475,97 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) {
return (char *)hp;
}
case macro_tag: {
macro_type *hp = gc_alloc(Cyc_heap, sizeof(macro_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = macro_tag;
hp->fn = ((macro) obj)->fn;
hp->num_args = ((macro) obj)->num_args;
macro_type *hp = gc_alloc(Cyc_heap, sizeof(macro_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case closure0_tag: {
closure0_type *hp = gc_alloc(Cyc_heap, sizeof(closure0_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure0_tag;
hp->fn = ((closure0) obj)->fn;
hp->num_args = ((closure0) obj)->num_args;
closure0_type *hp = gc_alloc(Cyc_heap, sizeof(closure0_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case closure1_tag: {
closure1_type *hp = gc_alloc(Cyc_heap, sizeof(closure1_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure1_tag;
hp->fn = ((closure1) obj)->fn;
hp->num_args = ((closure1) obj)->num_args;
hp->elt1 = ((closure1) obj)->elt1;
closure1_type *hp = gc_alloc(Cyc_heap, sizeof(closure1_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case closure2_tag: {
closure2_type *hp = gc_alloc(Cyc_heap, sizeof(closure2_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure2_tag;
hp->fn = ((closure2) obj)->fn;
hp->num_args = ((closure2) obj)->num_args;
hp->elt1 = ((closure2) obj)->elt1;
hp->elt2 = ((closure2) obj)->elt2;
closure2_type *hp = gc_alloc(Cyc_heap, sizeof(closure2_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case closure3_tag: {
closure3_type *hp = gc_alloc(Cyc_heap, sizeof(closure3_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure3_tag;
hp->fn = ((closure3) obj)->fn;
hp->num_args = ((closure3) obj)->num_args;
hp->elt1 = ((closure3) obj)->elt1;
hp->elt2 = ((closure3) obj)->elt2;
hp->elt3 = ((closure3) obj)->elt3;
closure3_type *hp = gc_alloc(Cyc_heap, sizeof(closure3_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case closure4_tag: {
closure4_type *hp = gc_alloc(Cyc_heap, sizeof(closure4_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closure4_tag;
hp->fn = ((closure4) obj)->fn;
hp->num_args = ((closure4) obj)->num_args;
hp->elt1 = ((closure4) obj)->elt1;
hp->elt2 = ((closure4) obj)->elt2;
hp->elt3 = ((closure4) obj)->elt3;
hp->elt4 = ((closure4) obj)->elt4;
closure4_type *hp = gc_alloc(Cyc_heap, sizeof(closure4_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case closureN_tag: {
int i;
closureN_type *hp = gc_alloc(Cyc_heap,
sizeof(closureN_type) + sizeof(object) * (((closureN) obj)->num_elt),
heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = closureN_tag;
hp->fn = ((closureN) obj)->fn;
hp->num_args = ((closureN) obj)->num_args;
hp->num_elt = ((closureN) obj)-> num_elt;
hp->elts = (object *)(((char *)hp) + sizeof(closureN_type));
for (i = 0; i < hp->num_elt; i++) {
hp->elts[i] = ((closureN) obj)->elts[i];
}
obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case vector_tag: {
int i;
vector_type *hp = gc_alloc(Cyc_heap,
sizeof(vector_type) + sizeof(object) * (((vector) obj)->num_elt),
heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = vector_tag;
hp->num_elt = ((vector) obj)-> num_elt;
hp->elts = (object *)(((char *)hp) + sizeof(vector_type));
for (i = 0; i < hp->num_elt; i++) {
hp->elts[i] = ((vector) obj)->elts[i];
}
obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case string_tag: {
char *s;
string_type *hp = gc_alloc(Cyc_heap,
sizeof(string_type) + ((string_len(obj) + 1)),
heap_grown);
s = ((char *)hp) + sizeof(string_type);
memcpy(s, string_str(obj), string_len(obj) + 1);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = string_tag;
string_len(hp) = string_len(obj);
string_str(hp) = s;
obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case integer_tag: {
integer_type *hp = gc_alloc(Cyc_heap, sizeof(integer_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = integer_tag;
hp->value = ((integer_type *) obj)->value;
integer_type *hp = gc_alloc(Cyc_heap, sizeof(integer_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case double_tag: {
double_type *hp = gc_alloc(Cyc_heap, sizeof(double_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = double_tag;
hp->value = ((double_type *) obj)->value;
double_type *hp = gc_alloc(Cyc_heap, sizeof(double_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case port_tag: {
port_type *hp = gc_alloc(Cyc_heap, sizeof(port_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = port_tag;
hp->fp = ((port_type *) obj)->fp;
hp->mode = ((port_type *) obj)->mode;
port_type *hp = gc_alloc(Cyc_heap, sizeof(port_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
return (char *)hp;
}
case cvar_tag: {
cvar_type *hp = gc_alloc(Cyc_heap, sizeof(cvar_type), heap_grown);
mark(hp) = thd->gc_alloc_color;
type_of(hp) = cvar_tag;
hp->pvar = ((cvar_type *) obj)->pvar;
cvar_type *hp = gc_alloc(Cyc_heap, sizeof(cvar_type), obj, thd, heap_grown);
forward(obj) = hp;
type_of(obj) = forward_tag;
gc_thr_add_to_move_buffer(thd, alloci, hp);
@ -2649,7 +2578,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) {
case boolean_tag: break;
case symbol_tag: break; // JAE TODO: raise an error here? Should not be possible in real code, though (IE, without GC DEBUG flag)
default:
fprintf(stderr, "gc_move: bad tag x=%p x.tag=%ld\n",(object) obj, type_of(obj));
fprintf(stderr, "gc_move: bad tag obj=%p obj.tag=%ld\n",(object) obj, type_of(obj));
exit(1);
}
return (char *)obj;