/*<--------all (live and dead) objects scanner begin-------->*/ static FORCE_INLINE void verifier_scan_object_slots(Partial_Reveal_Object *p_obj, Heap_Verifier* heap_verifier) { verifier_allocation_update_info(p_obj, heap_verifier); verify_object_header(p_obj, heap_verifier); if (!object_has_ref_field(p_obj)) return; REF* p_ref; if (object_is_array(p_obj)){ Partial_Reveal_Array* array = (Partial_Reveal_Array*)p_obj; unsigned int array_length = array->array_len; p_ref = (REF*)((POINTER_SIZE_INT)array + (int)array_first_element_offset(array)); for (unsigned int i = 0; i < array_length; i++) { verify_write_barrier(p_ref+i, heap_verifier); if( read_slot(p_ref+i) != NULL) verify_all_object_slot(p_ref+i, heap_verifier); // if(!is_unreachable_obj(p_obj)){ // verify_write_barrier(p_ref+i, heap_verifier); // if( read_slot(p_ref+i) != NULL) verify_live_object_slot(p_ref+i, heap_verifier); // }else{ // if( read_slot(p_ref+i) != NULL) verify_all_object_slot(p_ref+i, heap_verifier); // } } }else{ unsigned int num_refs = object_ref_field_num(p_obj); int* ref_iterator = object_ref_iterator_init(p_obj); for(unsigned int i=0; i<num_refs; i++){ p_ref = object_ref_iterator_get(ref_iterator+i, p_obj); verify_write_barrier(p_ref, heap_verifier); if( read_slot(p_ref) != NULL) verify_all_object_slot(p_ref, heap_verifier); //if(!is_unreachable_obj(p_obj)){ // verify_write_barrier(p_ref, heap_verifier); // if( read_slot(p_ref) != NULL) verify_live_object_slot(p_ref, heap_verifier); //}else{ // if( read_slot(p_ref) != NULL) verify_all_object_slot(p_ref, heap_verifier); //} } #ifndef BUILD_IN_REFERENT WeakReferenceType type = special_reference_type(p_obj); if(type == NOT_REFERENCE) return; //if(type != SOFT_REFERENCE && verifier_collect_is_minor(heap_verifier->gc_verifier)){ { p_ref = obj_get_referent_field(p_obj); verify_write_barrier(p_ref, heap_verifier); if( read_slot(p_ref) != NULL) verify_all_object_slot(p_ref, heap_verifier); //if(!is_unreachable_obj(p_obj)){ // verify_write_barrier(p_ref, heap_verifier); // if( read_slot(p_ref) != NULL) verify_live_object_slot(p_ref, heap_verifier); //}else{ // if( read_slot(p_ref) != NULL) verify_all_object_slot(p_ref, heap_verifier); //} } #endif } return; }
/*This function is for concurrent mark.*/ static void write_barrier_rem_obj_snapshot(Managed_Object_Handle p_obj_holding_ref) { Mutator *mutator = (Mutator *)gc_get_tls(); REF* p_obj_slot; if(obj_need_take_snapshot((Partial_Reveal_Object*)p_obj_holding_ref)){ if (object_is_array((Partial_Reveal_Object*)p_obj_holding_ref)) { Partial_Reveal_Object* array = (Partial_Reveal_Object*)p_obj_holding_ref; assert(!obj_is_primitive_array(array)); Partial_Reveal_Object* obj_to_snapshot; I_32 array_length = vector_get_length((Vector_Handle) array); for (int i = 0; i < array_length; i++) { p_obj_slot = (REF*)vector_get_element_address_ref((Vector_Handle) array, i); obj_to_snapshot = (Partial_Reveal_Object*)read_slot(p_obj_slot); if (obj_to_snapshot != NULL) mutator_dirtyset_add_entry(mutator, obj_to_snapshot); } }else{ /* scan non-array object */ Partial_Reveal_Object* p_obj = (Partial_Reveal_Object*)p_obj_holding_ref; unsigned int num_refs = object_ref_field_num(p_obj); int *ref_iterator = object_ref_iterator_init(p_obj); Partial_Reveal_Object* obj_to_snapshot; for(unsigned int i=0; i<num_refs; i++){ p_obj_slot = object_ref_iterator_get(ref_iterator+i, p_obj); obj_to_snapshot = (Partial_Reveal_Object*)read_slot(p_obj_slot); if (obj_to_snapshot != NULL) mutator_dirtyset_add_entry(mutator, obj_to_snapshot); } if(is_reference_obj(p_obj)){ REF* p_referent_field = obj_get_referent_field(p_obj); obj_to_snapshot = (Partial_Reveal_Object*)read_slot(p_referent_field); if (obj_to_snapshot != NULL) mutator_dirtyset_add_entry(mutator, obj_to_snapshot); } } obj_mark_gray_in_table((Partial_Reveal_Object *) p_obj_holding_ref); // now, the black-only obj (no gray bit been set) will also be scaned by marker, here mark it to gray to prevent this, just a workaround obj_mark_black_in_table((Partial_Reveal_Object *) p_obj_holding_ref, mutator); obj_dirty_in_table((Partial_Reveal_Object *) p_obj_holding_ref); } }
static void update_referent_field_ignore_finref(GC *gc, Pool *pool) { Vector_Block *block = pool_get_entry(pool); while(block){ POINTER_SIZE_INT *iter = vector_block_iterator_init(block); for(; !vector_block_iterator_end(block, iter); iter = vector_block_iterator_advance(block, iter)){ REF *p_ref = (REF*)iter; Partial_Reveal_Object *p_obj = read_slot(p_ref); assert(p_obj); REF *p_referent_field = obj_get_referent_field(p_obj); if(collect_is_fallback()) fallback_update_fw_ref(p_referent_field); Partial_Reveal_Object *p_referent = read_slot(p_referent_field); if(!p_referent){ // referent field has been cleared *p_ref = (REF)NULL; continue; } if(!gc_obj_is_dead(gc, p_referent)){ // referent is alive if(obj_need_move(gc, p_referent)) if(collect_is_minor()){ assert(obj_is_fw_in_oi(p_referent)); Partial_Reveal_Object* p_new_referent = obj_get_fw_in_oi(p_referent); write_slot(p_referent_field, p_new_referent); if(gc_is_gen_mode()) if(addr_belongs_to_nos(p_new_referent) && !addr_belongs_to_nos(p_obj)) collector_remset_add_entry(gc->collectors[0], ( Partial_Reveal_Object**)p_referent_field); } else { finref_repset_add_entry(gc, p_referent_field); } *p_ref = (REF)NULL; continue; } *p_referent_field = (REF)NULL; /* referent is weakly reachable: clear the referent field */ } block = pool_get_entry(pool); } }
/* * The reason why we don't use identify_dead_refs() to implement this function is * that we will differentiate phanref from weakref in the future. */ static void identify_dead_phanrefs(Collector *collector) { GC *gc = collector->gc; Finref_Metadata *metadata = gc->finref_metadata; Pool *phanref_pool = metadata->phanref_pool; if(collect_need_update_repset()) finref_reset_repset(gc); // collector_reset_repset(collector); pool_iterator_init(phanref_pool); Vector_Block *block = pool_iterator_next(phanref_pool); while(block){ POINTER_SIZE_INT *iter = vector_block_iterator_init(block); for(; !vector_block_iterator_end(block, iter); iter = vector_block_iterator_advance(block, iter)){ Partial_Reveal_Object **p_ref = (Partial_Reveal_Object **)iter; Partial_Reveal_Object *p_obj = read_slot((REF*)p_ref); assert(p_obj); REF *p_referent_field = obj_get_referent_field(p_obj); if(collect_is_fallback()) fallback_update_fw_ref(p_referent_field); Partial_Reveal_Object *p_referent = read_slot(p_referent_field); if(!p_referent){ // referent field has been cleared *p_ref = NULL; continue; } if(!gc_obj_is_dead(gc, p_referent)){ // referent is alive if(obj_need_move(gc, p_referent)){ if(collect_is_minor()){ assert(obj_is_fw_in_oi(p_referent)); Partial_Reveal_Object* p_new_referent = obj_get_fw_in_oi(p_referent); write_slot(p_referent_field, p_new_referent); if(gc_is_gen_mode()) if(addr_belongs_to_nos(p_new_referent) && !addr_belongs_to_nos(p_obj)) collector_remset_add_entry(gc->collectors[0], ( Partial_Reveal_Object**)p_referent_field); } else{ // if(collect_move_object()){ this check is redundant because obj_need_move checks finref_repset_add_entry(gc, p_referent_field); } } *p_ref = (REF)NULL; continue; } *p_referent_field = (REF)NULL; #ifdef ORDER_DEBUG if(ref_file == NULL){ if(order_record){ ref_file = fopen64("RECORD_REF_LOG.log", "w+"); } else{ ref_file = fopen64("REPLAY_REF_LOG.log", "w+"); } } assert(ref_file); fprintf(ref_file, "GC[%d]: ref (%d, %d) is DEAD!\n", gc->num_collections, p_referent->alloc_tid, p_referent->alloc_count); fflush(ref_file); #endif /* Phantom status: for future use * if((unsigned int)p_referent & PHANTOM_REF_ENQUEUE_STATUS_MASK){ * // enqueued but not explicitly cleared OR pending for enqueueing * *iter = NULL; * } * resurrect_obj_tree(collector, p_referent_field); */ } block = pool_iterator_next(phanref_pool); } // collector_put_repset(collector); if(collect_need_update_repset()){ finref_put_repset(gc); finref_add_repset_from_pool(gc, phanref_pool); } }
static void identify_dead_refs(GC *gc, Pool *pool) { if(collect_need_update_repset()) finref_reset_repset(gc); pool_iterator_init(pool); Vector_Block *block = pool_iterator_next(pool); while(block){ POINTER_SIZE_INT *iter = vector_block_iterator_init(block); for(; !vector_block_iterator_end(block, iter); iter = vector_block_iterator_advance(block, iter)){ REF *p_ref = (REF*)iter; Partial_Reveal_Object *p_obj = read_slot(p_ref); assert(p_obj); REF *p_referent_field = obj_get_referent_field(p_obj); if(collect_is_fallback()) fallback_update_fw_ref(p_referent_field); Partial_Reveal_Object *p_referent = read_slot(p_referent_field); if(!p_referent){ /* referent field has been cleared. I forgot why we set p_ref with NULL here. I guess it's because this ref_obj was processed in abother p_ref already, so there is no need to keep same ref_obj in this p_ref. */ *p_ref = (REF)NULL; continue; } if(!gc_obj_is_dead(gc, p_referent)){ // referent is alive if(obj_need_move(gc, p_referent)){ if(collect_is_minor()){ assert(obj_is_fw_in_oi(p_referent)); Partial_Reveal_Object* p_new_referent = obj_get_fw_in_oi(p_referent); write_slot(p_referent_field, p_new_referent); /* if it's gen mode, and referent stays in NOS, we need keep p_referent_field in collector remset. This leads to the ref obj live even it is actually only weakly-reachable in next gen-mode collection. This simplifies the design. Otherwise, we need remember the refobj in MOS seperately and process them seperately. */ if(gc_is_gen_mode()) if(addr_belongs_to_nos(p_new_referent) && !addr_belongs_to_nos(p_obj)) collector_remset_add_entry(gc->collectors[0], ( Partial_Reveal_Object**)p_referent_field); } else{ // if(collect_move_object()){ the condition is redundant because obj_need_move already checks finref_repset_add_entry(gc, p_referent_field); } } *p_ref = (REF)NULL; }else{ /* else, the referent is dead (weakly reachable), clear the referent field */ *p_referent_field = (REF)NULL; #ifdef ORDER_DEBUG if(ref_file == NULL){ if(order_record){ ref_file = fopen64("RECORD_REF_LOG.log", "w+"); } else{ ref_file = fopen64("REPLAY_REF_LOG.log", "w+"); } } assert(ref_file); fprintf(ref_file, "GC[%d]: ref (%d, %d) is DEAD!\n", gc->num_collections, p_referent->alloc_tid, p_referent->alloc_count); fflush(ref_file); #endif /* for dead referent, p_ref is not set NULL. p_ref keeps the ref object, which will be moved to VM for enqueueing. */ } }/* for each ref object */ block = pool_iterator_next(pool); } if(collect_need_update_repset()){ finref_put_repset(gc); finref_add_repset_from_pool(gc, pool); } }
static FORCE_INLINE void scan_object(Heap_Verifier* heap_verifier, Partial_Reveal_Object *p_obj) { GC_Verifier* gc_verifier = heap_verifier->gc_verifier; #if !defined(USE_UNIQUE_MARK_SWEEP_GC) && !defined(USE_UNIQUE_MOVE_COMPACT_GC) if(gc_verifier->is_before_fallback_collection) { if(obj_belongs_to_nos(p_obj) && obj_is_fw_in_oi(p_obj)){ assert(obj_get_vt(p_obj) == obj_get_vt(obj_get_fw_in_oi(p_obj))); p_obj = obj_get_fw_in_oi(p_obj); assert(p_obj); } } #endif if(!obj_mark_in_vt(p_obj)) return; if( !major_is_marksweep() && p_obj >= los_boundary ){ Block_Header* block = GC_BLOCK_HEADER(p_obj); if( heap_verifier->is_before_gc) block->num_live_objs++; /* we can't set block->num_live_objs = 0 if !is_before_gc, because the some blocks may be freed hence not visited after GC. So we should reset it in GC space reset functions. */ } verify_object_header(p_obj, heap_verifier); verifier_update_verify_info(p_obj, heap_verifier); /*FIXME: */ if (!object_has_ref_field(p_obj)) return; REF* p_ref; if (object_is_array(p_obj)) { Partial_Reveal_Array* array = (Partial_Reveal_Array*)p_obj; unsigned int array_length = array->array_len; p_ref = (REF*)((POINTER_SIZE_INT)array + (int)array_first_element_offset(array)); for (unsigned int i = 0; i < array_length; i++) { scan_slot(heap_verifier, p_ref+i); } }else{ unsigned int num_refs = object_ref_field_num(p_obj); int* ref_iterator = object_ref_iterator_init(p_obj); for(unsigned int i=0; i<num_refs; i++){ p_ref = object_ref_iterator_get(ref_iterator+i, p_obj); scan_slot(heap_verifier, p_ref); } #ifndef BUILD_IN_REFERENT WeakReferenceType type = special_reference_type(p_obj); if(type == SOFT_REFERENCE && verifier_collect_is_minor(gc_verifier)){ p_ref = obj_get_referent_field(p_obj); scan_slot(heap_verifier, p_ref); } #endif } return; }