]> gitweb.factorcode.org Git - factor.git/blob - vm/code_heap.cpp
Merge branch 'master' into new_gc
[factor.git] / vm / code_heap.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 code_heap::code_heap(cell size)
7 {
8         if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
9         seg = new segment(align_page(size),true);
10         if(!seg) fatal_error("Out of memory in heap allocator",size);
11         allocator = new free_list_allocator<heap_block>(size,seg->start);
12 }
13
14 code_heap::~code_heap()
15 {
16         delete allocator;
17         allocator = NULL;
18         delete seg;
19         seg = NULL;
20 }
21
22 void code_heap::write_barrier(code_block *compiled)
23 {
24         points_to_nursery.insert(compiled);
25         points_to_aging.insert(compiled);
26 }
27
28 void code_heap::clear_remembered_set()
29 {
30         points_to_nursery.clear();
31         points_to_aging.clear();
32 }
33
34 bool code_heap::needs_fixup_p(code_block *compiled)
35 {
36         return needs_fixup.count(compiled) > 0;
37 }
38
39 bool code_heap::marked_p(heap_block *compiled)
40 {
41         return allocator->state.marked_p(compiled);
42 }
43
44 void code_heap::set_marked_p(code_block *compiled)
45 {
46         allocator->state.set_marked_p(compiled);
47 }
48
49 void code_heap::clear_mark_bits()
50 {
51         allocator->state.clear_mark_bits();
52 }
53
54 void code_heap::code_heap_free(code_block *compiled)
55 {
56         points_to_nursery.erase(compiled);
57         points_to_aging.erase(compiled);
58         needs_fixup.erase(compiled);
59         allocator->free(compiled);
60 }
61
62 /* Allocate a code heap during startup */
63 void factor_vm::init_code_heap(cell size)
64 {
65         code = new code_heap(size);
66 }
67
68 bool factor_vm::in_code_heap_p(cell ptr)
69 {
70         return (ptr >= code->seg->start && ptr <= code->seg->end);
71 }
72
73 /* Compile a word definition with the non-optimizing compiler. Allocates memory */
74 void factor_vm::jit_compile_word(cell word_, cell def_, bool relocate)
75 {
76         gc_root<word> word(word_,this);
77         gc_root<quotation> def(def_,this);
78
79         jit_compile(def.value(),relocate);
80
81         word->code = def->code;
82
83         if(to_boolean(word->pic_def)) jit_compile(word->pic_def,relocate);
84         if(to_boolean(word->pic_tail_def)) jit_compile(word->pic_tail_def,relocate);
85 }
86
87 struct word_updater {
88         factor_vm *parent;
89
90         explicit word_updater(factor_vm *parent_) : parent(parent_) {}
91         void operator()(code_block *compiled, cell size)
92         {
93                 parent->update_word_references(compiled);
94         }
95 };
96
97 /* Update pointers to words referenced from all code blocks. Only after
98 defining a new word. */
99 void factor_vm::update_code_heap_words()
100 {
101         word_updater updater(this);
102         iterate_code_heap(updater);
103 }
104
105 /* After a full GC that did not grow the heap, we have to update references
106 to literals and other words. */
107 struct word_and_literal_code_heap_updater {
108         factor_vm *parent;
109
110         word_and_literal_code_heap_updater(factor_vm *parent_) : parent(parent_) {}
111
112         void operator()(heap_block *block, cell size)
113         {
114                 parent->update_code_block_words_and_literals((code_block *)block);
115         }
116 };
117
118 void factor_vm::update_code_heap_words_and_literals()
119 {
120         word_and_literal_code_heap_updater updater(this);
121         code->allocator->sweep(updater);
122 }
123
124 /* After growing the heap, we have to perform a full relocation to update
125 references to card and deck arrays. */
126 struct code_heap_relocator {
127         factor_vm *parent;
128
129         code_heap_relocator(factor_vm *parent_) : parent(parent_) {}
130
131         void operator()(code_block *block, cell size)
132         {
133                 parent->relocate_code_block(block);
134         }
135 };
136
137 void factor_vm::relocate_code_heap()
138 {
139         code_heap_relocator relocator(this);
140         code_heap_iterator<code_heap_relocator> iter(relocator);
141         code->allocator->sweep(iter);
142 }
143
144 void factor_vm::primitive_modify_code_heap()
145 {
146         gc_root<array> alist(dpop(),this);
147
148         cell count = array_capacity(alist.untagged());
149
150         if(count == 0)
151                 return;
152
153         cell i;
154         for(i = 0; i < count; i++)
155         {
156                 gc_root<array> pair(array_nth(alist.untagged(),i),this);
157
158                 gc_root<word> word(array_nth(pair.untagged(),0),this);
159                 gc_root<object> data(array_nth(pair.untagged(),1),this);
160
161                 switch(data.type())
162                 {
163                 case QUOTATION_TYPE:
164                         jit_compile_word(word.value(),data.value(),false);
165                         break;
166                 case ARRAY_TYPE:
167                         {
168                                 array *compiled_data = data.as<array>().untagged();
169                                 cell owner = array_nth(compiled_data,0);
170                                 cell literals = array_nth(compiled_data,1);
171                                 cell relocation = array_nth(compiled_data,2);
172                                 cell labels = array_nth(compiled_data,3);
173                                 cell code = array_nth(compiled_data,4);
174
175                                 code_block *compiled = add_code_block(
176                                         code_block_optimized,
177                                         code,
178                                         labels,
179                                         owner,
180                                         relocation,
181                                         literals);
182
183                                 word->code = compiled;
184                         }
185                         break;
186                 default:
187                         critical_error("Expected a quotation or an array",data.value());
188                         break;
189                 }
190
191                 update_word_xt(word.value());
192         }
193
194         update_code_heap_words();
195 }
196
197 /* Push the free space and total size of the code heap */
198 void factor_vm::primitive_code_room()
199 {
200         cell used, total_free, max_free;
201         code->allocator->usage(&used,&total_free,&max_free);
202         dpush(tag_fixnum(code->seg->size / 1024));
203         dpush(tag_fixnum(used / 1024));
204         dpush(tag_fixnum(total_free / 1024));
205         dpush(tag_fixnum(max_free / 1024));
206 }
207
208 code_block *code_heap::forward_code_block(code_block *compiled)
209 {
210         return (code_block *)allocator->state.forward_block(compiled);
211 }
212
213 struct callframe_forwarder {
214         factor_vm *parent;
215
216         explicit callframe_forwarder(factor_vm *parent_) : parent(parent_) {}
217
218         void operator()(stack_frame *frame)
219         {
220                 cell offset = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)frame->xt;
221
222                 code_block *forwarded = parent->code->forward_code_block(parent->frame_code(frame));
223                 frame->xt = forwarded->xt();
224
225                 FRAME_RETURN_ADDRESS(frame,parent) = (void *)((cell)frame->xt + offset);
226         }
227 };
228
229 void factor_vm::forward_object_xts()
230 {
231         begin_scan();
232
233         cell obj;
234
235         while(to_boolean(obj = next_object()))
236         {
237                 switch(tagged<object>(obj).type())
238                 {
239                 case WORD_TYPE:
240                         {
241                                 word *w = untag<word>(obj);
242
243                                 if(w->code)
244                                         w->code = code->forward_code_block(w->code);
245                                 if(w->profiling)
246                                         w->profiling = code->forward_code_block(w->profiling);
247
248                                 update_word_xt(obj);
249                         }
250                         break;
251                 case QUOTATION_TYPE:
252                         {
253                                 quotation *quot = untag<quotation>(obj);
254
255                                 if(quot->code)
256                                 {
257                                         quot->code = code->forward_code_block(quot->code);
258                                         set_quot_xt(quot,quot->code);
259                                 }
260                         }
261                         break;
262                 case CALLSTACK_TYPE:
263                         {
264                                 callstack *stack = untag<callstack>(obj);
265                                 callframe_forwarder forwarder(this);
266                                 iterate_callstack_object(stack,forwarder);
267                         }
268                         break;
269                 default:
270                         break;
271                 }
272         }
273
274         end_scan();
275 }
276
277 void factor_vm::forward_context_xts()
278 {
279         callframe_forwarder forwarder(this);
280         iterate_active_frames(forwarder);
281 }
282
283 struct callback_forwarder {
284         code_heap *code;
285         callback_heap *callbacks;
286
287         callback_forwarder(code_heap *code_, callback_heap *callbacks_) :
288                 code(code_), callbacks(callbacks_) {}
289
290         void operator()(callback *stub)
291         {
292                 stub->compiled = code->forward_code_block(stub->compiled);
293                 callbacks->update(stub);
294         }
295 };
296
297 void factor_vm::forward_callback_xts()
298 {
299         callback_forwarder forwarder(code,callbacks);
300         callbacks->iterate(forwarder);
301 }
302
303 /* Move all free space to the end of the code heap. Live blocks must be marked
304 on entry to this function. XTs in code blocks must be updated after this
305 function returns. */
306 void factor_vm::compact_code_heap(bool trace_contexts_p)
307 {
308         /* Figure out where blocks are going to go */
309         code->allocator->state.compute_forwarding();
310
311         /* Update references to the code heap from the data heap */
312         forward_object_xts();
313         if(trace_contexts_p)
314         {
315                 forward_context_xts();
316                 forward_callback_xts();
317         }
318
319         /* Move code blocks and update references amongst them (this requires
320         that the data heap is up to date since relocation looks up object XTs) */
321         code_heap_relocator relocator(this);
322         code_heap_iterator<code_heap_relocator> iter(relocator);
323         code->allocator->compact(iter);
324 }
325
326 struct stack_trace_stripper {
327         explicit stack_trace_stripper() {}
328
329         void operator()(code_block *compiled, cell size)
330         {
331                 compiled->owner = false_object;
332         }
333 };
334
335 void factor_vm::primitive_strip_stack_traces()
336 {
337         stack_trace_stripper stripper;
338         iterate_code_heap(stripper);
339 }
340
341 }