| 1 | #include "collector.h"
|
|---|
| 2 |
|
|---|
| 3 | #ifdef __cforall
|
|---|
| 4 | extern "C" {
|
|---|
| 5 | #endif
|
|---|
| 6 | #include <string.h>
|
|---|
| 7 | #ifdef __cforall
|
|---|
| 8 | }
|
|---|
| 9 | #endif
|
|---|
| 10 |
|
|---|
| 11 | #include "state.h"
|
|---|
| 12 | #include "gcpointers.h"
|
|---|
| 13 | #include "memory_pool.h"
|
|---|
| 14 |
|
|---|
| 15 | void* gc_finish_alloc_block(void* block, size_t actual_size, size_t target_size);
|
|---|
| 16 | void gc_assign_reference(void** ref, gc_object_header* ptr);
|
|---|
| 17 |
|
|---|
| 18 | gcpointer_t** gc_find_previous_ref(gcpointer_t* target)
|
|---|
| 19 | {
|
|---|
| 20 | if(!(target)) return NULL;
|
|---|
| 21 |
|
|---|
| 22 | bool managed = gc_is_managed(target);
|
|---|
| 23 | gc_object_header* obj = gc_get_object_ptr((void*)target->ptr);
|
|---|
| 24 |
|
|---|
| 25 | check(gc_is_valide(obj));
|
|---|
| 26 |
|
|---|
| 27 | gcpointer_t** prev_next_ptr = managed ? &obj->type_chain : &obj->root_chain;
|
|---|
| 28 | while((*prev_next_ptr) && (*prev_next_ptr) != target)
|
|---|
| 29 | {
|
|---|
| 30 | prev_next_ptr = &(*prev_next_ptr)->next;
|
|---|
| 31 | }
|
|---|
| 32 |
|
|---|
| 33 | return prev_next_ptr;
|
|---|
| 34 | }
|
|---|
| 35 |
|
|---|
| 36 | void* gc_allocate(size_t target_size)
|
|---|
| 37 | {
|
|---|
| 38 | size_t size = gc_compute_size(target_size + sizeof(gc_object_header));
|
|---|
| 39 |
|
|---|
| 40 | check(size < POOL_SIZE_BYTES);
|
|---|
| 41 |
|
|---|
| 42 | void* block = NULL;
|
|---|
| 43 | gc_state* gc = gc_get_state();
|
|---|
| 44 |
|
|---|
| 45 | if((intptr_t)(block = gc_try_allocate(gc, size))) return gc_finish_alloc_block(block, size, target_size);
|
|---|
| 46 |
|
|---|
| 47 | gc_collect(gc);
|
|---|
| 48 |
|
|---|
| 49 | if((intptr_t)(block = gc_try_allocate(gc, size))) return gc_finish_alloc_block(block, size, target_size);
|
|---|
| 50 |
|
|---|
| 51 | gc_allocate_pool(gc);
|
|---|
| 52 |
|
|---|
| 53 | if((intptr_t)(block = gc_try_allocate(gc, size))) return gc_finish_alloc_block(block, size, target_size);
|
|---|
| 54 |
|
|---|
| 55 | checkf(false, "ERROR: allocation in new pool failed");
|
|---|
| 56 |
|
|---|
| 57 | return NULL;
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | void* gc_finish_alloc_block(void* block, size_t actual_size, size_t target_size)
|
|---|
| 61 | {
|
|---|
| 62 | void* data = (void*)(((intptr_t)block) + sizeof(gc_object_header));
|
|---|
| 63 | void* header = block;
|
|---|
| 64 |
|
|---|
| 65 | check(((intptr_t)data) > ((intptr_t)block));
|
|---|
| 66 | check(((intptr_t)data) >= ((intptr_t)header));
|
|---|
| 67 | check(is_aligned(data));
|
|---|
| 68 | check(((intptr_t)data) + target_size <= ((intptr_t)block) + actual_size);
|
|---|
| 69 |
|
|---|
| 70 | gc_object_header* obj = placement_ctor(header, actual_size);
|
|---|
| 71 |
|
|---|
| 72 | (void)obj; //remove unsused warning since this is for debug
|
|---|
| 73 | check(obj == get_object_ptr(data));
|
|---|
| 74 |
|
|---|
| 75 | gc_register_allocation(gc_get_state(), actual_size);
|
|---|
| 76 |
|
|---|
| 77 | return data;
|
|---|
| 78 | }
|
|---|
| 79 |
|
|---|
| 80 | void gc_process_reference(void** ref, worklist_t* worklist)
|
|---|
| 81 | {
|
|---|
| 82 | check(!gc_is_in_heap(gc_get_state(), ref));
|
|---|
| 83 |
|
|---|
| 84 | gc_object_header* ptr = gc_get_object_ptr(*ref);
|
|---|
| 85 | if(ptr)
|
|---|
| 86 | {
|
|---|
| 87 | if(!ptr->is_forwarded)
|
|---|
| 88 | {
|
|---|
| 89 | gc_copy_object(ptr);
|
|---|
| 90 |
|
|---|
| 91 | gc_scan_object(ptr->forward, worklist);
|
|---|
| 92 |
|
|---|
| 93 | gc_assign_reference(ref, ptr->forward);
|
|---|
| 94 | }
|
|---|
| 95 | else
|
|---|
| 96 | {
|
|---|
| 97 | //duplication to help debug
|
|---|
| 98 | gc_assign_reference(ref, ptr->forward);
|
|---|
| 99 | }
|
|---|
| 100 | }
|
|---|
| 101 | }
|
|---|
| 102 |
|
|---|
| 103 | void gc_assign_reference(void** ref, gc_object_header* ptr)
|
|---|
| 104 | {
|
|---|
| 105 | void* address = (void*)(((intptr_t)ptr) + sizeof(gc_object_header));
|
|---|
| 106 |
|
|---|
| 107 | gc_write_aligned_ptr(ref, address);
|
|---|
| 108 | }
|
|---|
| 109 |
|
|---|
| 110 | gc_object_header* gc_copy_object(gc_object_header* ptr)
|
|---|
| 111 | {
|
|---|
| 112 | check(!ptr->forward);
|
|---|
| 113 | check(!ptr->is_forwarded);
|
|---|
| 114 | check(gc_is_from_space(gc_pool_of(ptr)));
|
|---|
| 115 |
|
|---|
| 116 | gc_memory_pool* pool = gc_pool_of(ptr)->mirror;
|
|---|
| 117 |
|
|---|
| 118 | void* new_block = gc_pool_allocate(pool, ptr->size, true);
|
|---|
| 119 |
|
|---|
| 120 | memcpy(new_block, ptr, ptr->size);
|
|---|
| 121 |
|
|---|
| 122 | gc_object_header* fwd_ptr = placement_copy_ctor(new_block, ptr);
|
|---|
| 123 |
|
|---|
| 124 | ptr->forward = fwd_ptr;
|
|---|
| 125 | ptr->is_forwarded = true;
|
|---|
| 126 |
|
|---|
| 127 | return fwd_ptr;
|
|---|
| 128 | }
|
|---|
| 129 |
|
|---|
| 130 | void gc_scan_object(gc_object_header* object, worklist_t* worklist)
|
|---|
| 131 | {
|
|---|
| 132 | gcpointer_t* field = object->type_chain;
|
|---|
| 133 | while(field)
|
|---|
| 134 | {
|
|---|
| 135 | check(((intptr_t)field) > ((intptr_t)object));
|
|---|
| 136 | check(((intptr_t)field) < ((intptr_t)((intptr_t)object) + object->size));
|
|---|
| 137 |
|
|---|
| 138 | check(gc_is_in_to_space(gc_get_state(), &type->ptr));
|
|---|
| 139 |
|
|---|
| 140 | intptr_t* ref = &field->ptr;
|
|---|
| 141 | push_back(worklist, ref);
|
|---|
| 142 |
|
|---|
| 143 | field = field->next;
|
|---|
| 144 | }
|
|---|
| 145 | }
|
|---|