void fix_slots_to_compaction_live_objects(GC_Thread *gc_thread) { block_info *p_compaction_block = NULL; unsigned int num_slots_fixed = 0; while ((p_compaction_block = gc_thread->_p_gc->get_block_for_fix_slots_to_compaction_live_objects(gc_thread->get_id(), p_compaction_block))) { while (true) { Remembered_Set *some_slots = gc_thread->_p_gc->get_slots_into_compaction_block(p_compaction_block); if (some_slots == NULL) { // Done with fixing all slots break; } some_slots->rewind(); Slot one_slot(NULL); while (one_slot.set(some_slots->next().get_address())) { Partial_Reveal_Object *p_obj = one_slot.dereference(); // This slot points into this compaction block assert(GC_BLOCK_INFO(p_obj) == p_compaction_block); assert(p_obj->get_obj_info() & FORWARDING_BIT_MASK); Partial_Reveal_Object *p_new_obj = p_obj->get_forwarding_pointer(); gc_trace(p_obj, " fix_slots_to_compaction_live_objects(): a slot pointed to this object, but the slot is being repointed to " << p_new_obj); gc_trace(p_new_obj, " fix_slots_to_compaction_live_objects(): a slot repointed to this object, but the slot was pointing to " << p_obj); // update slot one_slot.update(p_new_obj); num_slots_fixed++; assert(GC_BLOCK_INFO(p_obj)->in_nursery_p == true); assert(GC_BLOCK_INFO(p_new_obj)->in_nursery_p == true); if (!cross_block_compaction) { // objects move within the same block assert(GC_BLOCK_INFO(p_new_obj) == GC_BLOCK_INFO(p_obj)); } else { // the block this moves into better have been flagged for compaction.. assert(GC_BLOCK_INFO(p_new_obj)->is_compaction_block); } } // while (one_slot) // Delete the remebered set since it is not needed anymore...all slot updates for this list are done delete some_slots; } // while (true) } // while INFOW(gc_thread, "fixed " << num_slots_fixed << " slots"); }
// // Input/Output next_obj_start_arg - a pointer to a pointer to where the // fused objects will eventually reside. Updated to the end of the fused // objects. // bool fuse_objects (GC_Thread *gc_thread, Partial_Reveal_Object *p_obj, void **next_obj_start_arg, unsigned int *problem_locks) { bool UNUSED debug_printf_trigger = false; unsigned int moved_count = 0; unsigned int unmoved_count = 0; // If we can fuse an object we do and return it. assert (p_obj->vt()->get_gcvt()->gc_fuse_info); gc_trace (p_obj, "This object is a candidate for fusing with next object."); Partial_Reveal_Object *scan_stack[MAX_FUSABLE_OBJECT_SCAN_STACK]; unsigned top = 0; Partial_Reveal_Object *fuse_queue[MAX_FUSED_OBJECT_COUNT]; unsigned last = 0; scan_stack[top++] = p_obj; unsigned int fused_size = get_object_size_bytes(p_obj); unsigned int base_obj_size = fused_size; void *to_obj = *next_obj_start_arg; void * UNUSED debug_orig_to_obj = to_obj; // Claim the Forwading bit if you can. If you loose the race you can't fuse since someone else is. Obj_Info_Type old_base_value = p_obj->get_obj_info(); Obj_Info_Type new_base_value = old_base_value; if ((old_base_value & FORWARDING_BIT_MASK) == FORWARDING_BIT_MASK) { return false; // Some other thread is going to move this object. } new_base_value = old_base_value | FORWARDING_BIT_MASK; if (p_obj->compare_exchange(new_base_value, old_base_value) != old_base_value) { // We did not get the forwarding pointer successfully, some other thread got it. // Since this is the base object we can just return false. return false; } // Build a queue of objects to colocate but do not grab the FORWARDING_BIT until the queue is built. while (top > 0) { Partial_Reveal_Object *p_cur_obj = scan_stack[--top]; int *offset_scanner = init_fused_object_scanner(p_cur_obj); Slot pp_next_object(NULL); Partial_Reveal_Object *p_last_object = p_obj; while (pp_next_object.set(p_get_ref(offset_scanner, p_cur_obj)) != NULL) { // Move the scanner to the next reference. offset_scanner = p_next_ref (offset_scanner); // This object is to be fused with the object located at the gc_fuse_info so calculate the required size. Partial_Reveal_Object *p_next_from_obj = pp_next_object.dereference(); gc_trace (p_next_from_obj, "This object is a candidate to be fused with previous object."); if (p_next_from_obj) { // Check NULL. block_info *fuse_block_info = GC_BLOCK_INFO(p_next_from_obj); void * next_natural_obj = (void *) (POINTER_SIZE_INT(p_last_object) + get_object_size_bytes(p_last_object)); Obj_Info_Type new_value = p_next_from_obj->get_obj_info(); bool is_colocation_natural = (next_natural_obj == (void *)p_next_from_obj); bool overflow = (((POINTER_SIZE_INT)to_obj + fused_size + get_object_size_bytes(p_next_from_obj)) > (POINTER_SIZE_INT)(GC_BLOCK_CEILING(to_obj))); bool already_forwarded = ((new_value & FORWARDING_BIT_MASK) == FORWARDING_BIT_MASK); bool in_compaction_block = gc_thread->_p_gc->is_compaction_block(fuse_block_info); bool can_fuse = ((!already_forwarded) && (!is_colocation_natural) && (!overflow) && in_compaction_block ); if (can_fuse){ if (p_next_from_obj->vt()->get_gcvt()->gc_fuse_info) { scan_stack[top++] = p_next_from_obj; } fuse_queue[last] = p_next_from_obj; fused_size += get_object_size_bytes(p_next_from_obj); last++; } else { p_obj->set_obj_info(old_base_value); // Release the forwarding bit and don't colocate this object. return false; } } } } unsigned i; // Grab the forwarding bits for the other object in the queue.. If you can't get a bit // remove the object from the queue. for (i = 0; i < last; i++) { Partial_Reveal_Object *p_fuse_obj = fuse_queue[i]; Obj_Info_Type new_value = p_fuse_obj->get_obj_info(); Obj_Info_Type old_value = new_value; bool already_forwarded = ((new_value & FORWARDING_BIT_MASK) == FORWARDING_BIT_MASK); new_value = old_value | FORWARDING_BIT_MASK; // Create the value with a the forwarding bit set. if (!already_forwarded) { // install the forwarding bit if it has not already been forwarded. already_forwarded = (p_fuse_obj->compare_exchange(new_value, old_value) != old_value); } if (already_forwarded) { debug_printf_trigger = true; TRACE("REMOVING FROM FUSE QUEUE."); // Remove this object from the queue since we can colocate it. unsigned int j; for (j = i; j < last - 1; j++) { fuse_queue[j] = fuse_queue[j+1]; } // We have one less object on the queue. fuse_queue[last] = NULL; last--; i--; // Redo since fuse_queue[i] now holds a new object. unmoved_count++; } gc_trace (p_fuse_obj, "No space so this object is not fused with parent."); } // We don't fuse more than a single block worth of objects. assert (fused_size <= GC_BLOCK_ALLOC_SIZE); // We own all the forwarding bits in all the objects in the fuse_queue. // If we only have the base object and no other object to colocate with it just return. if (last == 0) { p_obj->set_obj_info(old_base_value); // Release the forwarding bit and don't colocate this object. // No objects to relocate. TRACE("3"); return false; } // At this point all objects in the queue will be fused, we have the forwarding bits // so we now figure out where they will be colocated. gc_trace (p_obj, "Fusing this object with offspring."); assert ((POINTER_SIZE_INT)(GC_BLOCK_INFO (to_obj + get_object_size_bytes(p_obj) - 1)) <= (POINTER_SIZE_INT)(GC_BLOCK_CEILING(to_obj))); assert ((p_obj->get_obj_info() & FORWARDING_BIT_MASK) == FORWARDING_BIT_MASK); if (object_info_is_not_zero(p_obj)) { if ((p_obj->get_obj_info() & ~FORWARDING_BIT_MASK) != 0) { object_lock_save_info *obj_info = (object_lock_save_info *) STD_MALLOC(sizeof(object_lock_save_info)); assert(obj_info); // Save what needs to be restored. obj_info->obj_header = p_obj->get_obj_info(); obj_info->obj_header = obj_info->obj_header & ~FORWARDING_BIT_MASK; // Clear forwarding bit. // I need to keep track of the new after-slided address obj_info->p_obj = (Partial_Reveal_Object *) to_obj; gc_thread->insert_object_header_info_during_sliding_compaction(obj_info); *problem_locks = *problem_locks + 1;; // placement code does not deal with this so this is likely to be wrong. gc_trace (p_obj, "Object being fused needs obj_info preserved."); debug_printf_trigger = true; INFO("preserving base fused object header"); } } // Finally deal with this placement, moving the base object first. insert_object_location (gc_thread, to_obj, p_obj); gc_trace (to_obj, " In allocate_forwarding_pointers_for_compaction_live_objects forwarding *to* this location. (vtable not yet legal)"); gc_trace(p_obj, " was forwarded..."); if (verify_live_heap) { add_repointed_info_for_thread(p_obj, (Partial_Reveal_Object *) to_obj, gc_thread->get_id()); } assert (base_obj_size == get_object_size_bytes(p_obj)); to_obj = (void *) ((POINTER_SIZE_INT) to_obj + base_obj_size); // Now figure out where the referent objects belong and set up their forwarding pointers. for (i = 0; i < last; i++) { Partial_Reveal_Object *p_fuse_obj = fuse_queue[i]; unsigned int fused_obj_size = get_object_size_bytes(p_fuse_obj); gc_trace (p_fuse_obj, "Fusing this object with parent."); // Finally deal with this colocations. assert (p_fuse_obj != p_obj); // Nulls should have been filtered out up above. if (object_info_is_not_zero(p_fuse_obj)) { if ((p_fuse_obj->get_obj_info() & ~FORWARDING_BIT_MASK) != 0) { object_lock_save_info *obj_info = (object_lock_save_info *) STD_MALLOC(sizeof(object_lock_save_info)); assert(obj_info); // Save what needs to be restored. obj_info->obj_header = p_fuse_obj->get_obj_info(); obj_info->obj_header = obj_info->obj_header & ~FORWARDING_BIT_MASK; // Clear forwarding bit. // I need to keep track of the new after-slided address obj_info->p_obj = (Partial_Reveal_Object *) to_obj; gc_thread->insert_object_header_info_during_sliding_compaction(obj_info); *problem_locks = *problem_locks + 1;; // placement code does not deal with this so this is likely to be wrong. gc_trace (p_fuse_obj, "Object being fused needs obj_info preserved."); debug_printf_trigger = true; INFO("preserving fused object header"); } } // Counts are not thread safe but it is just an approximation.... moved_count++; // The object in the queue its forwarding bit set. { POINTER_SIZE_INT UNUSED next_available = (POINTER_SIZE_INT)to_obj + get_object_size_bytes(p_fuse_obj) -1; assert ((fuse_queue[i]->get_obj_info() & FORWARDING_BIT_MASK) == FORWARDING_BIT_MASK); assert (next_available <= ((POINTER_SIZE_INT)(GC_BLOCK_CEILING(to_obj)))); } insert_object_location(gc_thread, to_obj, p_fuse_obj); gc_trace (to_obj, " In allocate_forwarding_pointers_for_compaction_live_objects forwarding *to* this location. (vtable not yet legal)"); gc_trace(p_obj, " was forwarded..."); if (verify_live_heap) { add_repointed_info_for_thread(p_fuse_obj, (Partial_Reveal_Object *) to_obj, gc_thread->get_id()); } to_obj = (void *) ((POINTER_SIZE_INT) to_obj + fused_obj_size); } *next_obj_start_arg = to_obj; // Update and return. TRACE("next_obj_start_arg addr: " << next_obj_start_arg << ", old_val " << debug_orig_to_obj << ", new_val " << to_obj); return true; }