source: tests/zombies/gc_no_raii/src/internal/state.c @ 154672d

Last change on this file since 154672d was 87b9332, checked in by Andrew Beach <ajbeach@…>, 4 years ago

Moved 'examples/' to 'tests/zombies/'.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1#include "state.h"
2
3#include <stdlib.hfa>
4
5//general purpouse includes
6#include "tools.h"
7
8//platform abstraction includes
9#include "allocate-pool.h"
10
11//gc internal includes
12#include "collector.h"
13#include "globals.h"
14#include "memory_pool.h"
15#include "object_header.h"
16#include "tools/worklist.h"
17
18void gc_state_swap(gc_state *const this);
19void gc_state_sweep_roots(gc_state *const this, worklist_t* worklist);
20void gc_state_clear(gc_state *const this);
21void gc_state_calc_usage(gc_state *const this);
22
23#ifndef NDEBUG
24        bool gc_state_roots_match(gc_state *const this);
25        bool gc_state_no_from_space_ref(gc_state *const this);
26#endif
27
28static gc_state s;
29
30gc_state* gc_get_state()
31{
32        if(!s.is_initialized) ctor(&s);
33        return &s;
34}
35
36void ctor(gc_state *const this)
37{
38        this->from_code = 0;
39        this->to_space = NULL;
40        this->from_space = NULL;
41        this->total_space = 0;
42        this->used_space = 0;
43        ctor(&this->pools_table);
44
45        gc_allocate_pool(this);
46
47        this->is_initialized = true;
48}
49
50void dtor(gc_state *const this)
51{
52        dtor(&this->pools_table);
53        this->is_initialized = false;
54}
55
56bool gc_is_in_heap(const gc_state* const this, const void* const address)
57{
58        gc_memory_pool* target_pool = gc_pool_of(address);
59
60        gc_memory_pool** first = cbegin(&this->pools_table);
61        gc_memory_pool** last = cend(&this->pools_table);
62        gc_memory_pool** result = find(first, &last, target_pool);
63        return result != last && gc_pool_is_from_space(*result);
64}
65
66bool gc_is_in_to_space(const gc_state* const this, const void* const address)
67{
68        gc_memory_pool* target_pool = gc_pool_of(address);
69
70        gc_memory_pool** first = cbegin(&this->pools_table);
71        gc_memory_pool** last = cend(&this->pools_table);
72        gc_memory_pool** result = find(first, &last, target_pool);
73        return result != last && !gc_pool_is_from_space(*result);
74}
75
76gc_object_header* gc_get_object_for_ref(gc_state* state, void* member)
77{
78        volatile int stage = 0;
79        intptr_t target = ((intptr_t)member);
80        if(!gc_is_in_heap(state, member)) return NULL;
81        stage++;
82
83        gc_memory_pool* pool = gc_pool_of(member);
84        stage++;
85        gc_pool_object_iterator it = gc_pool_iterator_for(pool, member);
86        stage++;
87        gc_pool_object_iterator end = end(pool);
88        stage++;
89
90        while(it != end)
91        {
92                gc_object_header* object = *it;
93                check(object);
94                check( is_valid(object) );
95                {
96                        intptr_t start = ((intptr_t)object);
97                        intptr_t end = ((intptr_t)start + object->size);
98                        if(start < target && end > target)
99                        {
100                                return object;
101                        }
102                }
103                stage++;
104                ++it;
105        }
106
107        checkf( (int) 0, "is_in_heap() and iterator_for() return inconsistent data");
108        abort();
109        return NULL;
110}
111
112void* gc_try_allocate(gc_state* const this, size_t size)
113{
114        gc_memory_pool* pool = this->from_space;
115        while(pool != (gc_memory_pool*)0)
116        {
117                if(gc_pool_size_left(pool) > size)
118                {
119                        return gc_pool_allocate(pool, size, true);
120                }
121                pool = pool->next;
122        }
123
124        return (void*)0;
125}
126
127void gc_allocate_pool(gc_state *const this)
128{
129        gc_memory_pool* old_from_space = this->from_space;
130      gc_memory_pool* old_to_space = this->to_space;
131
132      this->from_space = (gc_memory_pool*)(pal_allocPool(POOL_SIZE_BYTES, 1));
133      this->to_space   = (gc_memory_pool*)(pal_allocPool(POOL_SIZE_BYTES, 1));
134
135      this->from_space{ POOL_SIZE_BYTES, old_from_space, this->to_space,   this->from_code };
136      this->to_space  { POOL_SIZE_BYTES, old_to_space,   this->from_space, (~this->from_code) & 0x01 };
137
138        this->total_space += gc_pool_size_used(this->from_space);
139
140        push_back(&this->pools_table, this->from_space);
141        push_back(&this->pools_table, this->to_space);
142}
143
144void gc_collect(gc_state* const this)
145{
146        // DEBUG("collecting");
147        // DEBUG("previous usage " << this->used_space << " / " << this->total_space);
148
149        worklist_t worklist;
150        ctor(&worklist);
151        gc_state_sweep_roots(this, &worklist);
152
153        while(!empty(&worklist))
154        {
155                intptr_t* ref = back(&worklist);
156                pop_back(&worklist);
157                gc_process_reference((void**)ref, &worklist);
158        }
159
160        check(gc_state_roots_match(this));
161        check(gc_state_no_from_space_ref(this));
162
163        gc_state_swap(this);
164
165        gc_state_calc_usage(this);
166
167        if(gc_needs_collect(this)) gc_allocate_pool(this);
168
169        // DEBUG("done");
170        dtor(&worklist);
171}
172
173void gc_state_swap(gc_state* const this)
174{
175        swap(&this->from_space, &this->to_space);
176
177        gc_memory_pool* pool = this->to_space;
178        while(pool)
179        {
180                gc_reset_pool(pool);
181                pool = pool->next;
182        }
183
184        this->from_code = (~this->from_code) & 0x01;
185
186        #ifndef NDEBUG
187                {
188                        gc_memory_pool* pool = this->from_space;
189                        while(pool)
190                        {
191                                check(gc_pool_is_from_space(pool));
192                                pool = pool->next;
193                        }
194
195                        pool = this->to_space;
196                        while(pool)
197                        {
198                                check(!gc_pool_is_from_space(pool));
199                                pool = pool->next;
200                        }
201                }
202        #endif
203}
204
205void gc_state_sweep_roots(gc_state* const this, worklist_t* worklist)
206{
207        gc_memory_pool* pool = this->from_space;
208        while(pool)
209        {
210                gc_pool_object_iterator it = begin(pool);
211                gc_pool_object_iterator end = end(pool);
212                for(;it != end; ++it)
213                {
214                        gc_object_header* object = *it;
215                        if(!object->root_chain) continue;
216
217                        gc_copy_object(object);
218
219                        gc_scan_object(object->forward, worklist);
220                }
221
222                pool = pool->next;
223        }
224}
225
226void gc_state_clear(gc_state* const this)
227{
228        gc_memory_pool* pool = this->from_space;
229        while(pool)
230        {
231                gc_reset_pool(pool);
232                pool = pool->next;
233        }
234
235        pool = this->to_space;
236        while(pool)
237        {
238                gc_reset_pool(pool);
239                pool = pool->next;
240        }
241}
242
243void gc_state_calc_usage(gc_state* const this)
244{
245        this->total_space = 0;
246        this->used_space = 0;
247
248        gc_memory_pool* pool = this->from_space;
249        while(pool)
250        {
251                size_t size = gc_pool_size_total(pool);
252                size_t used = gc_pool_size_used(pool);
253                check(used <= size);
254                this->total_space += size;
255                this->used_space += used;
256
257                pool = pool->next;
258        }
259}
260
261#ifndef NDEBUG
262        bool gc_state_roots_match(gc_state* const this)
263        {
264                gc_memory_pool* pool = this->to_space;
265                while(pool)
266                {
267                        size_t size = 0;
268                        gc_pool_object_iterator it = begin(pool);
269                        gc_pool_object_iterator end = end(pool);
270                        for(;it != end; ++it)
271                        {
272                                gc_object_header* object = *it;
273                                size += object->size;
274
275                                gcpointer_t* ptr = object->root_chain;
276                                while(ptr)
277                                {
278                                        check(gc_get_object_ptr( (void*)ptr->ptr ) == object);
279                                        ptr = ptr->next;
280                                }
281                        }
282
283                        checkf(size + gc_pool_size_left(pool) == gc_pool_size_total(pool),
284                                (const char*)"expected %lu + %lu == %lu\n",
285                                (size_t)size,
286                                (size_t)gc_pool_size_left(pool),
287                                (size_t)gc_pool_size_total(pool));
288
289                        pool = pool->next;
290                }
291
292                return true;
293        }
294
295        bool gc_state_no_from_space_ref(gc_state* const this)
296        {
297                gc_memory_pool* pool = this->to_space;
298                while(pool)
299                {
300                        void** potential_ref = (void**)pool->start_p;
301                        while(potential_ref < (void**)pool->free_p)
302                        {
303                                check(!gc_is_in_heap(this, *potential_ref));
304                                potential_ref++;
305                        }
306
307                        pool = pool->next;
308                }
309
310                return true;
311        }
312#endif
Note: See TracBrowser for help on using the repository browser.