clib: move REG to the stack frames
[nit.git] / clib / gc.c
1 /* This file is part of NIT ( http://www.nitlanguage.org ).
2 *
3 * Copyright 2009 Julien Chevalier <chevjulien@gmail.com>
4 *
5 * This file is free software, which comes along with NIT. This software is
6 * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
7 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
8 * PARTICULAR PURPOSE. You can modify it is you want, provided this header
9 * is kept unaltered, and a notification of the changes is added.
10 * You are allowed to redistribute it and sell it, alone or is a part of
11 * another product.
12 */
13
14 #include "gc.h"
15 #ifdef DEBUG
16 # include <assert.h>
17 #else
18 # define assert(x) while(0)
19 #endif
20
21 void Nit_gc_init(void) {
22 heapActive = malloc(sizeof(heap));
23 heapInactive = malloc(sizeof(heap));
24
25 heapActive->heapPointer = malloc(HEAP_ACTIVE_SIZE_MIN);
26 heapInactive->heapPointer = malloc(HEAP_ACTIVE_SIZE_MIN);
27
28 if (heapActive->heapPointer==NULL) exit(1);
29 if (heapInactive->heapPointer==NULL) exit(1);
30
31 heapActive->size = HEAP_ACTIVE_SIZE_MIN;
32 heapInactive->size = HEAP_ACTIVE_SIZE_MIN;
33
34 allocationPointer = heapActive->heapPointer;
35
36 evacuationPointer = heapInactive->heapPointer;
37 scavengingPointer = evacuationPointer;
38
39 GC_List_Init(&staticObjects);
40 }
41
42 val_t GC_evacuation(obj_t object) {
43 bigint size;
44 bigint objectSize;
45 val_t newAdress;
46 Nit_NativeArray array;
47 BOX_struct box;
48
49 assert(ISOBJ(object) && !ISNULL(object));
50 if (GET_MARKBIT(object) != (bigint)0) {
51 newAdress = REMOVE_MARKBIT((bigint)((object)->vft));
52 } else {
53 newAdress = (val_t)evacuationPointer;
54 if (OBJ_IS_ARRAY(object)) {
55 array = (Nit_NativeArray)object;
56 size = sizeof(struct Nit_NativeArray) + ((array->size - 1) * sizeof(val_t));
57 memcpy(evacuationPointer, (array), size);
58 (array)->vft = (classtable_elt_t*)evacuationPointer;
59 } else if (IS_BOX(object)) {
60 box = (BOX_struct)object;
61 size = sizeof(struct TBOX_struct);
62 memcpy(evacuationPointer, object, size);
63 box->vft = (classtable_elt_t*)evacuationPointer;
64 } else {
65 objectSize = (bigint)((object)[0].vft[1].i);
66 size = (objectSize) * sizeof(val_t);
67 memcpy(evacuationPointer, object, size);
68 (object)[0].vft = (classtable_elt_t*)evacuationPointer;
69 }
70 SET_MARKBIT(object);
71 evacuationPointer += size;
72 }
73
74 return newAdress;
75 }
76
77 void GC_scavenging(void) {
78 obj_t object = (obj_t)scavengingPointer;
79 int size;
80 int i;
81 obj_t referencedObject;
82 bigint objectSize;
83 Nit_NativeArray *array;
84
85 if (IS_BOX(object)) {
86 size = sizeof(struct TBOX_struct);
87 } else {
88 array = (Nit_NativeArray*)&scavengingPointer;
89 if (OBJ_IS_ARRAY((obj_t)*array)) {
90 size = sizeof(struct Nit_NativeArray) + (((*array)->size - 1) * sizeof(val_t));
91 for (i = 0; i < (*array)->size; i++) {
92 referencedObject = (obj_t)((*array)->val[i]);
93 if (!ISNULL(referencedObject) && ISOBJ(referencedObject)) {
94 (*array)->val[i] = (bigint)GC_evacuation(referencedObject);
95 }
96 }
97 } else {
98 objectSize = (bigint)((object)->vft[1].i);
99 size = (objectSize) * sizeof(val_t);
100 for (i = 2; i < objectSize; i++) {
101 referencedObject = (obj_t)(object[i].objectSize);
102 if (!ISNULL(referencedObject) && ISOBJ(referencedObject)) {
103 ((object)[i].objectSize) = (bigint)GC_evacuation(referencedObject);
104 }
105 }
106 }
107 }
108 scavengingPointer += size;
109 }
110
111 void GC_collect(void) {
112 val_t *pointer;
113 int i;
114 int j;
115 struct stack_frame_t *frame = stack_frame_head;
116 GC_static_object *staticObject = staticObjects.top;
117 val_t object;
118 heap *tempPointer;
119
120 evacuationPointer = heapInactive->heapPointer;
121 scavengingPointer = heapInactive->heapPointer;
122 for (i = 0; i < staticObjects.size; i++) {
123 object = *(val_t*)(staticObject->pointer);
124 if (!ISNULL(object) && ISOBJ(object)) {
125 *(staticObject->pointer) = GC_evacuation((obj_t)object);
126 }
127 staticObject = staticObject->next;
128 }
129 while (frame != NULL) {
130 for (j = 0; j < frame->REG_size; j++) {
131 object = frame->REG[j];
132 if (!ISNULL(object) && ISOBJ(object)) {
133 frame->REG[j] = GC_evacuation((obj_t)object);
134 }
135 }
136 if (frame == frame->prev) break;
137 frame = frame->prev;
138 }
139 while (evacuationPointer != scavengingPointer) {
140 GC_scavenging();
141 }
142
143 /* pour tests seulement, pas necessaire */
144 memset(heapActive->heapPointer, 0, heapActive->size);
145 allocationPointer = evacuationPointer;
146
147 /* inverse le tas actif et le tas inactif */
148 tempPointer = heapActive;
149 heapActive = heapInactive;
150 heapInactive = tempPointer;
151
152 heapActiveUsedSize = allocationPointer - heapActive->heapPointer;
153 }
154
155 void GC_set_heap_size(size_t newHeapSize) {
156 free(heapInactive->heapPointer);
157 heapInactive->heapPointer = malloc(newHeapSize);
158 if (heapInactive->heapPointer == NULL) {
159 exit(1);
160 }
161 heapInactive->size = newHeapSize;
162 memset(heapInactive->heapPointer, 0, newHeapSize);
163 }
164
165 void GC_detect_memory_needs(size_t size) {
166 if (size > (heapActive->size - heapActiveUsedSize)) {
167 GC_collect();
168 if (heapActive->size - heapActiveUsedSize > heapActive->size / 2 && heapActive->size * 3 / 4 > HEAP_ACTIVE_SIZE_MIN) {
169 GC_set_heap_size(heapActive->size * 3 / 4);
170 GC_collect();
171 GC_set_heap_size(heapActive->size);
172 }
173 }
174 if (size > (heapActive->size - heapActiveUsedSize)) {
175 int try_size = heapInactive->size * 2;
176 while (size > (try_size - heapActiveUsedSize)) {
177 try_size *= 2;
178 }
179 GC_set_heap_size(try_size);
180 GC_collect();
181 GC_set_heap_size(heapActive->size);
182 }
183 }
184
185 void *Nit_gc_malloc(size_t size) {
186 char *result;
187
188 GC_detect_memory_needs(size);
189
190 result = allocationPointer;
191 heapActiveUsedSize += size;
192 allocationPointer += size;
193
194 return result;
195 }
196
197 void GC_add_static_object(val_t *pointer) {
198 GC_List_Push(&staticObjects, pointer);
199 }
200