static void collector_trace_rootsets(Collector* collector) { GC* gc = collector->gc; GC_Metadata* metadata = gc->metadata; #ifdef GC_GEN_STATS GC_Gen_Collector_Stats* stats = (GC_Gen_Collector_Stats*)collector->stats; #endif unsigned int num_active_collectors = gc->num_active_collectors; atomic_cas32( &num_finished_collectors, 0, num_active_collectors); Space* space = collector->collect_space; collector->trace_stack = free_task_pool_get_entry(metadata); /* find root slots saved by 1. active mutators, 2. exited mutators, 3. last cycle collectors */ Vector_Block* root_set = pool_iterator_next(metadata->gc_rootset_pool); /* first step: copy all root objects to trace tasks. */ TRACE2("gc.process", "GC: collector["<<((POINTER_SIZE_INT)collector->thread_handle)<<"]: copy root objects to trace stack ..."); while(root_set){ POINTER_SIZE_INT* iter = vector_block_iterator_init(root_set); while(!vector_block_iterator_end(root_set,iter)){ REF *p_ref = (REF *)*iter; iter = vector_block_iterator_advance(root_set, iter); assert(*p_ref); /* root ref cann't be NULL, but remset can be */ collector_tracestack_push(collector, p_ref); #ifdef GC_GEN_STATS gc_gen_collector_update_rootset_ref_num(stats); #endif } root_set = pool_iterator_next(metadata->gc_rootset_pool); } /* put back the last trace_stack task */ pool_put_entry(metadata->mark_task_pool, collector->trace_stack); /* second step: iterate over the trace tasks and forward objects */ collector->trace_stack = free_task_pool_get_entry(metadata); TRACE2("gc.process", "GC: collector["<<((POINTER_SIZE_INT)collector->thread_handle)<<"]: finish copying root objects to trace stack."); TRACE2("gc.process", "GC: collector["<<((POINTER_SIZE_INT)collector->thread_handle)<<"]: trace and forward objects ..."); retry: Vector_Block* trace_task = pool_get_entry(metadata->mark_task_pool); while(trace_task){ POINTER_SIZE_INT* iter = vector_block_iterator_init(trace_task); while(!vector_block_iterator_end(trace_task,iter)){ REF *p_ref = (REF *)*iter; iter = vector_block_iterator_advance(trace_task, iter); #ifdef PREFETCH_SUPPORTED /* DO PREFETCH */ if( mark_prefetch ) { if(!vector_block_iterator_end(trace_task, iter)) { REF *pref= (REF*) *iter; PREFETCH( read_slot(pref)); } } #endif trace_object(collector, p_ref); if(collector->result == FALSE) break; /* force return */ } vector_stack_clear(trace_task); pool_put_entry(metadata->free_task_pool, trace_task); if(collector->result == FALSE){ gc_task_pool_clear(metadata->mark_task_pool); break; /* force return */ } trace_task = pool_get_entry(metadata->mark_task_pool); } /* A collector comes here when seeing an empty mark_task_pool. The last collector will ensure all the tasks are finished.*/ atomic_inc32(&num_finished_collectors); while(num_finished_collectors != num_active_collectors){ if( pool_is_empty(metadata->mark_task_pool)) continue; /* we can't grab the task here, because of a race condition. If we grab the task, and the pool is empty, other threads may fall to this barrier and then pass. */ atomic_dec32(&num_finished_collectors); goto retry; } TRACE2("gc.process", "GC: collector["<<((POINTER_SIZE_INT)collector->thread_handle)<<"]: finish tracing and forwarding objects."); /* now we are done, but each collector has a private stack that is empty */ trace_task = (Vector_Block*)collector->trace_stack; vector_stack_clear(trace_task); pool_put_entry(metadata->free_task_pool, trace_task); collector->trace_stack = NULL; return; }
// Resurrect the obj tree whose root is the obj which p_ref points to static inline void resurrect_obj_tree(Collector *collector, REF *p_ref) { GC *gc = collector->gc; GC_Metadata *metadata = gc->metadata; Partial_Reveal_Object *p_obj = read_slot(p_ref); assert(p_obj && gc_obj_is_dead(gc, p_obj)); void *p_ref_or_obj = p_ref; Trace_Object_Func trace_object; /* set trace_object() function */ if(collect_is_minor()){ if(gc_is_gen_mode()){ if(minor_is_forward()) trace_object = trace_obj_in_gen_fw; else if(minor_is_semispace()) trace_object = trace_obj_in_gen_ss; else assert(0); }else{ if(minor_is_forward()) trace_object = trace_obj_in_nongen_fw; else if(minor_is_semispace()) trace_object = trace_obj_in_nongen_ss; else assert(0); } } else if(collect_is_major_normal() || !gc_has_nos()){ p_ref_or_obj = p_obj; if(gc_has_space_tuner(gc) && (gc->tuner->kind != TRANS_NOTHING)){ trace_object = trace_obj_in_space_tune_marking; unsigned int obj_size = vm_object_size(p_obj); #ifdef USE_32BITS_HASHCODE obj_size += hashcode_is_set(p_obj) ? GC_OBJECT_ALIGNMENT : 0; #endif if(!obj_belongs_to_space(p_obj, gc_get_los((GC_Gen*)gc))){ collector->non_los_live_obj_size += obj_size; collector->segment_live_size[SIZE_TO_SEGMENT_INDEX(obj_size)] += obj_size; } else { collector->los_live_obj_size += round_up_to_size(obj_size, KB); } } else if(!gc_has_nos()){ trace_object = trace_obj_in_ms_marking; } else { trace_object = trace_obj_in_normal_marking; } } else if(collect_is_fallback()){ if(major_is_marksweep()) trace_object = trace_obj_in_ms_fallback_marking; else trace_object = trace_obj_in_fallback_marking; } else { assert(major_is_marksweep()); p_ref_or_obj = p_obj; if( gc->gc_concurrent_status == GC_CON_NIL ) trace_object = trace_obj_in_ms_marking; else trace_object = trace_obj_in_ms_concurrent_mark; } collector->trace_stack = free_task_pool_get_entry(metadata); collector_tracestack_push(collector, p_ref_or_obj); pool_put_entry(metadata->mark_task_pool, collector->trace_stack); collector->trace_stack = free_task_pool_get_entry(metadata); Vector_Block *task_block = pool_get_entry(metadata->mark_task_pool); while(task_block){ POINTER_SIZE_INT *iter = vector_block_iterator_init(task_block); while(!vector_block_iterator_end(task_block, iter)){ void *p_ref_or_obj = (void*)*iter; assert(((collect_is_minor()||collect_is_fallback()) && *(Partial_Reveal_Object **)p_ref_or_obj) || ((collect_is_major_normal()||major_is_marksweep()||!gc_has_nos()) && p_ref_or_obj)); trace_object(collector, p_ref_or_obj); if(collector->result == FALSE) break; /* Resurrection fallback happens; force return */ iter = vector_block_iterator_advance(task_block, iter); } vector_stack_clear(task_block); pool_put_entry(metadata->free_task_pool, task_block); if(collector->result == FALSE){ gc_task_pool_clear(metadata->mark_task_pool); break; /* force return */ } task_block = pool_get_entry(metadata->mark_task_pool); } task_block = (Vector_Block*)collector->trace_stack; vector_stack_clear(task_block); pool_put_entry(metadata->free_task_pool, task_block); collector->trace_stack = NULL; }
static void collector_trace_rootsets(Collector* collector) { GC* gc = collector->gc; GC_Metadata* metadata = gc->metadata; #ifdef GC_GEN_STATS GC_Gen_Collector_Stats* stats = (GC_Gen_Collector_Stats*)collector->stats; #endif unsigned int num_active_collectors = gc->num_active_collectors; atomic_cas32( &num_finished_collectors, 0, num_active_collectors); Space* space = collector->collect_space; collector->trace_stack = free_task_pool_get_entry(metadata); /* find root slots saved by 1. active mutators, 2. exited mutators, 3. last cycle collectors */ Vector_Block* root_set = pool_iterator_next(metadata->gc_rootset_pool); /* first step: copy all root objects to trace tasks. */ TRACE2("gc.process", "GC: collector["<<((POINTER_SIZE_INT)collector->thread_handle)<<"]: copy root objects to trace stack ......"); while(root_set){ POINTER_SIZE_INT* iter = vector_block_iterator_init(root_set); while(!vector_block_iterator_end(root_set,iter)){ REF *p_ref = (REF *)*iter; iter = vector_block_iterator_advance(root_set,iter); if(!*p_ref) continue; /* root ref cann't be NULL, but remset can be */ Partial_Reveal_Object *p_obj = read_slot(p_ref); #ifdef GC_GEN_STATS gc_gen_collector_update_rootset_ref_num(stats); #endif if(obj_belongs_to_nos(p_obj)){ collector_tracestack_push(collector, p_ref); } } root_set = pool_iterator_next(metadata->gc_rootset_pool); } /* put back the last trace_stack task */ pool_put_entry(metadata->mark_task_pool, collector->trace_stack); /* second step: iterate over the trace tasks and forward objects */ collector->trace_stack = free_task_pool_get_entry(metadata); TRACE2("gc.process", "GC: collector["<<((POINTER_SIZE_INT)collector->thread_handle)<<"]: finish copying root objects to trace stack."); TRACE2("gc.process", "GC: collector["<<((POINTER_SIZE_INT)collector->thread_handle)<<"]: trace and forward objects ......"); retry: Vector_Block* trace_task = pool_get_entry(metadata->mark_task_pool); while(trace_task){ POINTER_SIZE_INT* iter = vector_block_iterator_init(trace_task); while(!vector_block_iterator_end(trace_task,iter)){ REF *p_ref = (REF *)*iter; iter = vector_block_iterator_advance(trace_task,iter); assert(*p_ref); /* a task can't be NULL, it was checked before put into the task stack */ #ifdef PREFETCH_SUPPORTED /* DO PREFETCH */ if( mark_prefetch ) { if(!vector_block_iterator_end(trace_task, iter)) { REF *pref= (REF*) *iter; PREFETCH( read_slot(pref)); } } #endif /* in sequential version, we only trace same object once, but we were using a local hashset for that, which couldn't catch the repetition between multiple collectors. This is subject to more study. */ /* FIXME:: we should not let root_set empty during working, other may want to steal it. degenerate my stack into root_set, and grab another stack */ /* a task has to belong to collected space, it was checked before put into the stack */ trace_object(collector, p_ref); if(collector->result == FALSE) break; /* force return */ } vector_stack_clear(trace_task); pool_put_entry(metadata->free_task_pool, trace_task); if(collector->result == FALSE){ gc_task_pool_clear(metadata->mark_task_pool); break; /* force return */ } trace_task = pool_get_entry(metadata->mark_task_pool); } atomic_inc32(&num_finished_collectors); while(num_finished_collectors != num_active_collectors){ if( pool_is_empty(metadata->mark_task_pool)) continue; /* we can't grab the task here, because of a race condition. If we grab the task, and the pool is empty, other threads may fall to this barrier and then pass. */ atomic_dec32(&num_finished_collectors); goto retry; } TRACE2("gc.process", "GC: collector["<<((POINTER_SIZE_INT)collector->thread_handle)<<"]: finish tracing and forwarding objects."); /* now we are done, but each collector has a private stack that is empty */ trace_task = (Vector_Block*)collector->trace_stack; vector_stack_clear(trace_task); pool_put_entry(metadata->free_task_pool, trace_task); collector->trace_stack = NULL; return; }