#include "state.h" #include //general purpouse includes #include "tools.h" //platform abstraction includes #include "allocate-pool.h" //gc internal includes #include "collector.h" #include "globals.h" #include "memory_pool.h" #include "object_header.h" #include "tools/worklist.h" void gc_state_swap(gc_state *const this); void gc_state_sweep_roots(gc_state *const this, worklist_t* worklist); void gc_state_clear(gc_state *const this); void gc_state_calc_usage(gc_state *const this); #if DEBUG bool gc_state_roots_match(gc_state *const this); bool gc_state_no_from_space_ref(gc_state *const this); #endif gc_state* gc_get_state() { static gc_state s; if(!s.is_initialized) ctor(&s); return &s; } void ctor(gc_state *const this) { this->from_code = 0; this->to_space = NULL; this->from_space = NULL; this->total_space = 0; this->used_space = 0; ctor(&this->pools_table); gc_allocate_pool(this); this->is_initialized = true; } void dtor(gc_state *const this) { dtor(&this->pools_table); this->is_initialized = false; } bool gc_is_in_heap(const gc_state* const this, const void* const address) { gc_memory_pool* target_pool = gc_pool_of(address); gc_memory_pool** first = cbegin(&this->pools_table); gc_memory_pool** last = cend(&this->pools_table); gc_memory_pool** result = find(first, &last, target_pool); return result != last && gc_pool_is_from_space(*result); } bool gc_is_in_to_space(const gc_state* const this, const void* const address) { gc_memory_pool* target_pool = gc_pool_of(address); gc_memory_pool** first = cbegin(&this->pools_table); gc_memory_pool** last = cend(&this->pools_table); gc_memory_pool** result = find(first, &last, target_pool); return result != last && !gc_pool_is_from_space(*result); } gc_object_header* gc_get_object_for_ref(gc_state* state, void* member) { intptr_t target = ((intptr_t)member); if(!gc_is_in_heap(state, member)) return NULL; gc_memory_pool* pool = gc_pool_of(member); gc_pool_object_iterator it = gc_pool_iterator_for(pool, member); gc_pool_object_iterator end = end(pool); while(it != end) { gc_object_header* object = *it; { intptr_t start = ((intptr_t)object); intptr_t end = ((intptr_t)start + object->size); if(start < target && end > target) { return object; } } ++it; } checkf(false, "is_in_heap() and iterator_for() return inconsistent data"); abort(); return NULL; } void* gc_try_allocate(gc_state* const this, size_t size) { gc_memory_pool* pool = this->from_space; while(pool != (gc_memory_pool*)0) { if(gc_pool_size_left(pool) > size) { return gc_pool_allocate(pool, size, true); } pool = pool->next; } return (void*)0; } void gc_allocate_pool(gc_state *const this) { gc_memory_pool* old_from_space = this->from_space; gc_memory_pool* old_to_space = this->to_space; this->from_space = (gc_memory_pool*)(pal_allocPool(POOL_SIZE_BYTES, 1)); this->to_space = (gc_memory_pool*)(pal_allocPool(POOL_SIZE_BYTES, 1)); ctor(this->from_space, POOL_SIZE_BYTES, old_from_space, this->to_space, this->from_code); ctor(this->to_space, POOL_SIZE_BYTES, old_to_space, this->from_space, (~this->from_code) & 0x01); this->total_space += gc_pool_size_used(this->from_space); push_back(&this->pools_table, this->from_space); push_back(&this->pools_table, this->to_space); } void gc_collect(gc_state* const this) { // DEBUG("collecting"); // DEBUG("previous usage " << this->used_space << " / " << this->total_space); worklist_t worklist; ctor(&worklist); gc_state_sweep_roots(this, &worklist); while(!empty(&worklist)) { intptr_t* ref = back(&worklist); pop_back(&worklist); gc_process_reference((void**)ref, &worklist); } check(gc_state_roots_match(this)); check(gc_state_no_from_space_ref(this)); gc_state_swap(this); gc_state_calc_usage(this); if(gc_needs_collect(this)) gc_allocate_pool(this); // DEBUG("done"); dtor(&worklist); } void gc_state_swap(gc_state* const this) { swap(&this->from_space, &this->to_space); gc_memory_pool* pool = this->to_space; while(pool) { gc_reset_pool(pool); pool = pool->next; } this->from_code = (~this->from_code) & 0x01; #if _DEBUG { gc_memory_pool* pool = this->from_space; while(pool) { check(gc_pool_is_from_space(pool)); pool = pool->next; } pool = this->to_space; while(pool) { check(!gc_pool_is_from_space(pool)); pool = pool->next; } } #endif } void gc_state_sweep_roots(gc_state* const this, worklist_t* worklist) { gc_memory_pool* pool = this->from_space; while(pool) { gc_pool_object_iterator it = begin(pool); gc_pool_object_iterator end = end(pool); for(;it != end; ++it) { gc_object_header* object = *it; if(!object->root_chain) continue; gc_copy_object(object); gc_scan_object(object->forward, worklist); } pool = pool->next; } } void gc_state_clear(gc_state* const this) { gc_memory_pool* pool = this->from_space; while(pool) { gc_reset_pool(pool); pool = pool->next; } pool = this->to_space; while(pool) { gc_reset_pool(pool); pool = pool->next; } } void gc_state_calc_usage(gc_state* const this) { this->total_space = 0; this->used_space = 0; gc_memory_pool* pool = this->from_space; while(pool) { size_t size = gc_pool_size_total(pool); size_t used = gc_pool_size_used(pool); check(used <= size); this->total_space += size; this->used_space += used; pool = pool->next; } } #if _DEBUG bool gc_state_roots_match(gc_state* const this) { gc_memory_pool* pool = this->to_space; while(pool) { size_t size = 0; gc_pool_object_iterator it = begin(pool); gc_pool_object_iterator end = end(pool); for(;it != end; ++it) { gc_object_header* object = *it; size += object->size; gcpointer_base* ptr = object->root_chain; while(ptr) { check(get_object_ptr(ptr->m_ptr) == object); ptr = ptr->m_next; } } check(size + gc_pool_size_used(pool) == gc_pool_size_total(pool)); pool = pool->next; } return true; } bool gc_state_no_from_space_ref(gc_state* const this) { gc_memory_pool* pool = this->to_space; while(pool) { void** potential_ref = (void**)pool->m_start; while(potential_ref < (void**)pool->m_free) { check(!gc_is_in_heap(this, *potential_ref)); potential_ref++; } pool = pool->next; } return true; } #endif