New write barrier implementation

This commit is contained in:
Justin Ethier 2015-12-07 22:34:29 -05:00
parent c8878e749a
commit 33447ebc57
3 changed files with 39 additions and 28 deletions

35
gc.c
View file

@ -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));

View file

@ -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);

View file

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