diff --git a/gc.c b/gc.c index a15b0f51..8be59a00 100644 --- a/gc.c +++ b/gc.c @@ -821,13 +821,12 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) gc_mark_gray(thd, old_obj); // Check if value is on the heap. If so, mark gray right now, // otherwise set it to be marked after moved to heap by next GC -// if (gc_is_stack_obj(thd, value)) { -// grayed(value) = 1; -// } else { -// gc_mark_gray(thd, value); -// } + if (gc_is_stack_obj(thd, value)) { + grayed(value) = 1; + } else { + gc_mark_gray(thd, value); + } pthread_mutex_unlock(&(thd->lock)); -gc_stack_mark_gray(thd, value); // TODO: this line will be replace with above block } else if (stage == STAGE_TRACING) { //fprintf(stderr, "DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stderr); @@ -877,12 +876,20 @@ gc_stack_mark_gray(thd, value); // TODO: this line will be replace with above bl void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { int i, status = ATOMIC_GET(&gc_status_col); + + // Handle any pending marks from write barrier + pthread_mutex_lock(&(thd->lock)); + thd->last_write += thd->pending_writes; + thd->pending_writes = 0; + pthread_mutex_unlock(&(thd->lock)); + if (thd->gc_status != status) { if (thd->gc_status == STATUS_ASYNC) { // Async is done, so clean up old mark data from the last collection pthread_mutex_lock(&(thd->lock)); thd->last_write = 0; thd->last_read = 0; + thd->pending_writes = 0; pthread_mutex_unlock(&(thd->lock)); } else if (thd->gc_status == STATUS_SYNC2) { @@ -941,6 +948,17 @@ void gc_mark_gray(gc_thread_data *thd, object obj) } } +void gc_mark_gray2(gc_thread_data *thd, object obj) +{ + if (is_object_type(obj) && mark(obj) == gc_color_clear) { + thd->mark_buffer = vpbuffer_add(thd->mark_buffer, + &(thd->mark_buffer_len), + (thd->last_write + thd->pending_writes), + obj); + thd->pending_writes++; + } +} + // TODO: before doing this, may want to debug a bit and see what is // being passed to gc_mut_update. see if those objects tend to have // any heap refs. may need to add debug code to do that... @@ -1003,7 +1021,10 @@ void gc_collector_trace() if (clean) { pthread_mutex_lock(&(m->lock)); if (m->last_read < m->last_write) { - printf("JAE DEBUG - might have exited trace early\n"); + fprintf(stderr, "JAE DEBUG - might have exited trace early\n"); + clean = 0; + } + else if (m->pending_writes) { clean = 0; } pthread_mutex_unlock(&(m->lock)); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 423aae83..ab73bed9 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -56,6 +56,7 @@ struct gc_thread_data_t { int gc_status; int last_write; int last_read; + int pending_writes; void **mark_buffer; int mark_buffer_len; pthread_mutex_t lock; @@ -164,6 +165,7 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len); void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth); void gc_stack_mark_gray(gc_thread_data *thd, object obj); void gc_mark_gray(gc_thread_data *thd, object obj); +void gc_mark_gray2(gc_thread_data *thd, object obj); void gc_collector_trace(); void gc_mark_black(object obj); void gc_collector_mark_gray(object parent, object obj); diff --git a/runtime.c b/runtime.c index 93cff642..616eb527 100644 --- a/runtime.c +++ b/runtime.c @@ -2452,35 +2452,24 @@ void gc_mark_globals() } } -char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, int *num_grayed, char *obj, object hp) +char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, char *obj, object hp) { + if (grayed(obj)) { + pthread_mutex_lock(&(thd->lock)); + gc_mark_gray2(thd, hp); + pthread_mutex_unlock(&(thd->lock)); + } + // hp ==> new heap object, point to it from old stack object forward(obj) = hp; type_of(obj) = forward_tag; // keep track of each allocation so we can scan/move // the whole live object 'tree' gc_thr_add_to_move_buffer(thd, alloci, hp); - -// TODO: if grayed(obj) then - do a deferred gc_mark_gray on hp -// you know, one possibility would be to add it to the thread mark buffer -// but now increment the read (write?) variable. instead increment another -// one and wait until the end of minor GC to set read (write?) to the -// appropriate value. just need to make sure we have the lock before -// updating it. -// that should avoid race conditions and the need for an additional buffer - - if (TODO){ - lock - gc_mark_gray - but WITHOUT incrementing write (read?) - unlock - (*num_grayed)++; -} - - return (char *)hp; } -char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown, int *num_grayed) { +char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; switch(type_of(obj)){ case cons_tag: { @@ -2562,7 +2551,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown, int temp = obj; \ if (check_overflow(low_limit, temp) && \ check_overflow(temp, high_limit)){ \ - (obj) = (object) gc_move(temp, (gc_thread_data *)data, &alloci, &heap_grown, &num_grayed); \ + (obj) = (object) gc_move(temp, (gc_thread_data *)data, &alloci, &heap_grown); \ } \ } @@ -2575,7 +2564,6 @@ void GC(void *data, closure cont, object *args, int num_args) int i; int scani = 0, alloci = 0; int heap_grown = 0; - int num_grayed = 0; //fprintf(stdout, "DEBUG, started minor GC\n"); // JAE DEBUG // Prevent overrunning buffer