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