]> gitweb.factorcode.org Git - factor.git/blob - vm/data_heap.cpp
forwarding functions replaced with PRIMITIVE_FORWARD() macro
[factor.git] / vm / data_heap.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 cell factor_vm::init_zone(zone *z, cell size, cell start)
7 {
8         z->size = size;
9         z->start = z->here = start;
10         z->end = start + size;
11         return z->end;
12 }
13
14 void factor_vm::init_card_decks()
15 {
16         cell start = align(data->seg->start,deck_size);
17         allot_markers_offset = (cell)data->allot_markers - (start >> card_bits);
18         cards_offset = (cell)data->cards - (start >> card_bits);
19         decks_offset = (cell)data->decks - (start >> deck_bits);
20 }
21
22 data_heap *factor_vm::alloc_data_heap(cell gens, cell young_size,cell aging_size,cell tenured_size)
23 {
24         young_size = align(young_size,deck_size);
25         aging_size = align(aging_size,deck_size);
26         tenured_size = align(tenured_size,deck_size);
27
28         data_heap *data = (data_heap *)safe_malloc(sizeof(data_heap));
29         data->young_size = young_size;
30         data->aging_size = aging_size;
31         data->tenured_size = tenured_size;
32         data->gen_count = gens;
33
34         cell total_size;
35         if(data->gen_count == 2)
36                 total_size = young_size + 2 * tenured_size;
37         else if(data->gen_count == 3)
38                 total_size = young_size + 2 * aging_size + 2 * tenured_size;
39         else
40         {
41                 fatal_error("Invalid number of generations",data->gen_count);
42                 return NULL; /* can't happen */
43         }
44
45         total_size += deck_size;
46
47         data->seg = alloc_segment(total_size);
48
49         data->generations = (zone *)safe_malloc(sizeof(zone) * data->gen_count);
50         data->semispaces = (zone *)safe_malloc(sizeof(zone) * data->gen_count);
51
52         cell cards_size = total_size >> card_bits;
53         data->allot_markers = (cell *)safe_malloc(cards_size);
54         data->allot_markers_end = data->allot_markers + cards_size;
55
56         data->cards = (cell *)safe_malloc(cards_size);
57         data->cards_end = data->cards + cards_size;
58
59         cell decks_size = total_size >> deck_bits;
60         data->decks = (cell *)safe_malloc(decks_size);
61         data->decks_end = data->decks + decks_size;
62
63         cell alloter = align(data->seg->start,deck_size);
64
65         alloter = init_zone(&data->generations[data->tenured()],tenured_size,alloter);
66         alloter = init_zone(&data->semispaces[data->tenured()],tenured_size,alloter);
67
68         if(data->gen_count == 3)
69         {
70                 alloter = init_zone(&data->generations[data->aging()],aging_size,alloter);
71                 alloter = init_zone(&data->semispaces[data->aging()],aging_size,alloter);
72         }
73
74         if(data->gen_count >= 2)
75         {
76                 alloter = init_zone(&data->generations[data->nursery()],young_size,alloter);
77                 alloter = init_zone(&data->semispaces[data->nursery()],0,alloter);
78         }
79
80         if(data->seg->end - alloter > deck_size)
81                 critical_error("Bug in alloc_data_heap",alloter);
82
83         return data;
84 }
85
86 data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes)
87 {
88         cell new_tenured_size = (data->tenured_size * 2) + requested_bytes;
89
90         return alloc_data_heap(data->gen_count,
91                 data->young_size,
92                 data->aging_size,
93                 new_tenured_size);
94 }
95
96 void factor_vm::dealloc_data_heap(data_heap *data)
97 {
98         dealloc_segment(data->seg);
99         free(data->generations);
100         free(data->semispaces);
101         free(data->allot_markers);
102         free(data->cards);
103         free(data->decks);
104         free(data);
105 }
106
107 void factor_vm::clear_cards(cell from, cell to)
108 {
109         /* NOTE: reverse order due to heap layout. */
110         card *first_card = addr_to_card(data->generations[to].start);
111         card *last_card = addr_to_card(data->generations[from].end);
112         memset(first_card,0,last_card - first_card);
113 }
114
115 void factor_vm::clear_decks(cell from, cell to)
116 {
117         /* NOTE: reverse order due to heap layout. */
118         card_deck *first_deck = addr_to_deck(data->generations[to].start);
119         card_deck *last_deck = addr_to_deck(data->generations[from].end);
120         memset(first_deck,0,last_deck - first_deck);
121 }
122
123 void factor_vm::clear_allot_markers(cell from, cell to)
124 {
125         /* NOTE: reverse order due to heap layout. */
126         card *first_card = addr_to_allot_marker((object *)data->generations[to].start);
127         card *last_card = addr_to_allot_marker((object *)data->generations[from].end);
128         memset(first_card,invalid_allot_marker,last_card - first_card);
129 }
130
131 void factor_vm::reset_generation(cell i)
132 {
133         zone *z = (i == data->nursery() ? &nursery : &data->generations[i]);
134
135         z->here = z->start;
136         if(secure_gc)
137                 memset((void*)z->start,69,z->size);
138 }
139
140 /* After garbage collection, any generations which are now empty need to have
141 their allocation pointers and cards reset. */
142 void factor_vm::reset_generations(cell from, cell to)
143 {
144         cell i;
145         for(i = from; i <= to; i++)
146                 reset_generation(i);
147
148         clear_cards(from,to);
149         clear_decks(from,to);
150         clear_allot_markers(from,to);
151 }
152
153 void factor_vm::set_data_heap(data_heap *data_)
154 {
155         data = data_;
156         nursery = data->generations[data->nursery()];
157         init_card_decks();
158         clear_cards(data->nursery(),data->tenured());
159         clear_decks(data->nursery(),data->tenured());
160         clear_allot_markers(data->nursery(),data->tenured());
161 }
162
163 void factor_vm::init_data_heap(cell gens,cell young_size,cell aging_size,cell tenured_size,bool secure_gc_)
164 {
165         set_data_heap(alloc_data_heap(gens,young_size,aging_size,tenured_size));
166         secure_gc = secure_gc_;
167         init_data_gc();
168 }
169
170 /* Size of the object pointed to by a tagged pointer */
171 cell factor_vm::object_size(cell tagged)
172 {
173         if(immediate_p(tagged))
174                 return 0;
175         else
176                 return untagged_object_size(untag<object>(tagged));
177 }
178
179 /* Size of the object pointed to by an untagged pointer */
180 cell factor_vm::untagged_object_size(object *pointer)
181 {
182         return align8(unaligned_object_size(pointer));
183 }
184
185 /* Size of the data area of an object pointed to by an untagged pointer */
186 cell factor_vm::unaligned_object_size(object *pointer)
187 {
188         switch(pointer->h.hi_tag())
189         {
190         case ARRAY_TYPE:
191                 return array_size((array*)pointer);
192         case BIGNUM_TYPE:
193                 return array_size((bignum*)pointer);
194         case BYTE_ARRAY_TYPE:
195                 return array_size((byte_array*)pointer);
196         case STRING_TYPE:
197                 return string_size(string_capacity((string*)pointer));
198         case TUPLE_TYPE:
199                 return tuple_size(untag<tuple_layout>(((tuple *)pointer)->layout));
200         case QUOTATION_TYPE:
201                 return sizeof(quotation);
202         case WORD_TYPE:
203                 return sizeof(word);
204         case FLOAT_TYPE:
205                 return sizeof(boxed_float);
206         case DLL_TYPE:
207                 return sizeof(dll);
208         case ALIEN_TYPE:
209                 return sizeof(alien);
210         case WRAPPER_TYPE:
211                 return sizeof(wrapper);
212         case CALLSTACK_TYPE:
213                 return callstack_size(untag_fixnum(((callstack *)pointer)->length));
214         default:
215                 critical_error("Invalid header",(cell)pointer);
216                 return 0; /* can't happen */
217         }
218 }
219
220 inline void factor_vm::primitive_size()
221 {
222         box_unsigned_cell(object_size(dpop()));
223 }
224
225 PRIMITIVE_FORWARD(size)
226
227 /* The number of cells from the start of the object which should be scanned by
228 the GC. Some types have a binary payload at the end (string, word, DLL) which
229 we ignore. */
230 cell factor_vm::binary_payload_start(object *pointer)
231 {
232         switch(pointer->h.hi_tag())
233         {
234         /* these objects do not refer to other objects at all */
235         case FLOAT_TYPE:
236         case BYTE_ARRAY_TYPE:
237         case BIGNUM_TYPE:
238         case CALLSTACK_TYPE:
239                 return 0;
240         /* these objects have some binary data at the end */
241         case WORD_TYPE:
242                 return sizeof(word) - sizeof(cell) * 3;
243         case ALIEN_TYPE:
244                 return sizeof(cell) * 3;
245         case DLL_TYPE:
246                 return sizeof(cell) * 2;
247         case QUOTATION_TYPE:
248                 return sizeof(quotation) - sizeof(cell) * 2;
249         case STRING_TYPE:
250                 return sizeof(string);
251         /* everything else consists entirely of pointers */
252         case ARRAY_TYPE:
253                 return array_size<array>(array_capacity((array*)pointer));
254         case TUPLE_TYPE:
255                 return tuple_size(untag<tuple_layout>(((tuple *)pointer)->layout));
256         case WRAPPER_TYPE:
257                 return sizeof(wrapper);
258         default:
259                 critical_error("Invalid header",(cell)pointer);
260                 return 0; /* can't happen */
261         }
262 }
263
264 /* Push memory usage statistics in data heap */
265 inline void factor_vm::primitive_data_room()
266 {
267         dpush(tag_fixnum((data->cards_end - data->cards) >> 10));
268         dpush(tag_fixnum((data->decks_end - data->decks) >> 10));
269
270         growable_array a(this);
271
272         cell gen;
273         for(gen = 0; gen < data->gen_count; gen++)
274         {
275                 zone *z = (gen == data->nursery() ? &nursery : &data->generations[gen]);
276                 a.add(tag_fixnum((z->end - z->here) >> 10));
277                 a.add(tag_fixnum((z->size) >> 10));
278         }
279
280         a.trim();
281         dpush(a.elements.value());
282 }
283
284 PRIMITIVE_FORWARD(data_room)
285
286 /* Disables GC and activates next-object ( -- obj ) primitive */
287 void factor_vm::begin_scan()
288 {
289         heap_scan_ptr = data->generations[data->tenured()].start;
290         gc_off = true;
291 }
292
293 void factor_vm::end_scan()
294 {
295         gc_off = false;
296 }
297
298 inline void factor_vm::primitive_begin_scan()
299 {
300         begin_scan();
301 }
302
303 PRIMITIVE_FORWARD(begin_scan)
304
305 cell factor_vm::next_object()
306 {
307         if(!gc_off)
308                 general_error(ERROR_HEAP_SCAN,F,F,NULL);
309
310         if(heap_scan_ptr >= data->generations[data->tenured()].here)
311                 return F;
312
313         object *obj = (object *)heap_scan_ptr;
314         heap_scan_ptr += untagged_object_size(obj);
315         return tag_dynamic(obj);
316 }
317
318 /* Push object at heap scan cursor and advance; pushes f when done */
319 inline void factor_vm::primitive_next_object()
320 {
321         dpush(next_object());
322 }
323
324 PRIMITIVE_FORWARD(next_object)
325
326 /* Re-enables GC */
327 inline void factor_vm::primitive_end_scan()
328 {
329         gc_off = false;
330 }
331
332 PRIMITIVE_FORWARD(end_scan)
333
334 template<typename TYPE> void factor_vm::each_object(TYPE &functor)
335 {
336         begin_scan();
337         cell obj;
338         while((obj = next_object()) != F)
339                 functor(tagged<object>(obj));
340         end_scan();
341 }
342
343 namespace
344 {
345
346 struct word_counter {
347         cell count;
348         word_counter() : count(0) {}
349         void operator()(tagged<object> obj) { if(obj.type_p(WORD_TYPE)) count++; }
350 };
351
352 struct word_accumulator {
353         growable_array words;
354         word_accumulator(int count,factor_vm *vm) : words(vm,count) {}
355         void operator()(tagged<object> obj) { if(obj.type_p(WORD_TYPE)) words.add(obj.value()); }
356 };
357
358 }
359
360 cell factor_vm::find_all_words()
361 {
362         word_counter counter;
363         each_object(counter);
364         word_accumulator accum(counter.count,this);
365         each_object(accum);
366         accum.words.trim();
367         return accum.words.elements.value();
368 }
369
370 }