From 8bf20a05b5da1a61cae95b8a2ee944737044d8c0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 19 Nov 2015 23:00:53 -0500 Subject: [PATCH] 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. --- gc.c | 163 +++++++++++++++++++++++++++++++++++++++- include/cyclone/types.h | 5 +- runtime.c | 113 ++++++---------------------- 3 files changed, 183 insertions(+), 98 deletions(-) diff --git a/gc.c b/gc.c index 5b7bb0d1..480d7b51 100644 --- a/gc.c +++ b/gc.c @@ -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??? diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 685a9a45..1e2f2703 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -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); diff --git a/runtime.c b/runtime.c index 5ec6623f..f938944e 100644 --- a/runtime.c +++ b/runtime.c @@ -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;