Ejemplo n.º 1
0
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");
}
Ejemplo n.º 2
0
//
// 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;
}