]> gitweb.factorcode.org Git - factor.git/blob - vm/inlineimpls.hpp
a247afa4d703a1bec1a16372c47c4cd6019d1626
[factor.git] / vm / inlineimpls.hpp
1 namespace factor
2 {
3
4 // I've had to copy inline implementations here to make dependencies work. Am hoping to move this code back into include files
5 // once the rest of the reentrant changes are done. -PD
6
7 // segments.hpp
8
9 inline cell factorvm::align_page(cell a)
10 {
11         return align(a,getpagesize());
12 }
13
14 // write_barrier.hpp
15
16 inline card *factorvm::addr_to_card(cell a)
17 {
18         return (card*)(((cell)(a) >> card_bits) + cards_offset);
19 }
20
21
22 inline cell factorvm::card_to_addr(card *c)
23 {
24         return ((cell)c - cards_offset) << card_bits;
25 }
26
27
28 inline cell factorvm::card_offset(card *c)
29 {
30         return *(c - (cell)data->cards + (cell)data->allot_markers);
31 }
32
33 inline card_deck *factorvm::addr_to_deck(cell a)
34 {
35         return (card_deck *)(((cell)a >> deck_bits) + decks_offset);
36 }
37
38 inline cell factorvm::deck_to_addr(card_deck *c)
39 {
40         return ((cell)c - decks_offset) << deck_bits;
41 }
42
43 inline card *factorvm::deck_to_card(card_deck *d)
44 {
45         return (card *)((((cell)d - decks_offset) << (deck_bits - card_bits)) + cards_offset);
46 }
47
48 inline card *factorvm::addr_to_allot_marker(object *a)
49 {
50         return (card *)(((cell)a >> card_bits) + allot_markers_offset);
51 }
52
53 /* the write barrier must be called any time we are potentially storing a
54 pointer from an older generation to a younger one */
55 inline void factorvm::write_barrier(object *obj)
56 {
57         *addr_to_card((cell)obj) = card_mark_mask;
58         *addr_to_deck((cell)obj) = card_mark_mask;
59 }
60
61 /* we need to remember the first object allocated in the card */
62 inline void factorvm::allot_barrier(object *address)
63 {
64         card *ptr = addr_to_allot_marker(address);
65         if(*ptr == invalid_allot_marker)
66                 *ptr = ((cell)address & addr_card_mask);
67 }
68
69
70 //data_gc.hpp
71 inline bool factorvm::collecting_accumulation_gen_p()
72 {
73         return ((data->have_aging_p()
74                 && collecting_gen == data->aging()
75                 && !collecting_aging_again)
76                 || collecting_gen == data->tenured());
77 }
78
79 inline object *factorvm::allot_zone(zone *z, cell a)
80 {
81         cell h = z->here;
82         z->here = h + align8(a);
83         object *obj = (object *)h;
84         allot_barrier(obj);
85         return obj;
86 }
87
88 /*
89  * It is up to the caller to fill in the object's fields in a meaningful
90  * fashion!
91  */
92 inline object *factorvm::allot_object(header header, cell size)
93 {
94 #ifdef GC_DEBUG
95         if(!gc_off)
96                 gc();
97 #endif
98
99         object *obj;
100
101         if(nursery.size - allot_buffer_zone > size)
102         {
103                 /* If there is insufficient room, collect the nursery */
104                 if(nursery.here + allot_buffer_zone + size > nursery.end)
105                         garbage_collection(data->nursery(),false,0);
106
107                 cell h = nursery.here;
108                 nursery.here = h + align8(size);
109                 obj = (object *)h;
110         }
111         /* If the object is bigger than the nursery, allocate it in
112         tenured space */
113         else
114         {
115                 zone *tenured = &data->generations[data->tenured()];
116
117                 /* If tenured space does not have enough room, collect */
118                 if(tenured->here + size > tenured->end)
119                 {
120                         gc();
121                         tenured = &data->generations[data->tenured()];
122                 }
123
124                 /* If it still won't fit, grow the heap */
125                 if(tenured->here + size > tenured->end)
126                 {
127                         garbage_collection(data->tenured(),true,size);
128                         tenured = &data->generations[data->tenured()];
129                 }
130
131                 obj = allot_zone(tenured,size);
132
133                 /* Allows initialization code to store old->new pointers
134                 without hitting the write barrier in the common case of
135                 a nursery allocation */
136                 write_barrier(obj);
137         }
138
139         obj->h = header;
140         return obj;
141 }
142
143 template<typename TYPE> TYPE *factorvm::allot(cell size)
144 {
145         return (TYPE *)allot_object(header(TYPE::type_number),size);
146 }
147
148 inline void factorvm::check_data_pointer(object *pointer)
149 {
150 #ifdef FACTOR_DEBUG
151         if(!growing_data_heap)
152         {
153                 assert((cell)pointer >= data->seg->start
154                        && (cell)pointer < data->seg->end);
155         }
156 #endif
157 }
158
159 inline void factorvm::check_tagged_pointer(cell tagged)
160 {
161 #ifdef FACTOR_DEBUG
162         if(!immediate_p(tagged))
163         {
164                 object *obj = untag<object>(tagged);
165                 check_data_pointer(obj);
166                 obj->h.hi_tag();
167         }
168 #endif
169 }
170
171 //local_roots.hpp
172 template <typename TYPE>
173 struct gc_root : public tagged<TYPE>
174 {
175         factorvm *myvm;
176
177         void push() { myvm->check_tagged_pointer(tagged<TYPE>::value()); myvm->gc_locals.push_back((cell)this); }
178         
179         explicit gc_root(cell value_,factorvm *vm) : tagged<TYPE>(value_),myvm(vm) { push(); }
180         explicit gc_root(TYPE *value_, factorvm *vm) : tagged<TYPE>(value_),myvm(vm) { push(); }
181
182         const gc_root<TYPE>& operator=(const TYPE *x) { tagged<TYPE>::operator=(x); return *this; }
183         const gc_root<TYPE>& operator=(const cell &x) { tagged<TYPE>::operator=(x); return *this; }
184
185         ~gc_root() {
186 #ifdef FACTOR_DEBUG
187                 assert(myvm->gc_locals.back() == (cell)this);
188 #endif
189                 myvm->gc_locals.pop_back();
190         }
191 };
192
193 /* A similar hack for the bignum implementation */
194 struct gc_bignum
195 {
196         bignum **addr;
197         factorvm *myvm;
198         gc_bignum(bignum **addr_, factorvm *vm) : addr(addr_), myvm(vm) {
199                 if(*addr_)
200                         myvm->check_data_pointer(*addr_);
201                 myvm->gc_bignums.push_back((cell)addr);
202         }
203
204         ~gc_bignum() {
205 #ifdef FACTOR_DEBUG
206                 assert(myvm->gc_bignums.back() == (cell)addr);
207 #endif
208                 myvm->gc_bignums.pop_back();
209         }
210 };
211
212 #define GC_BIGNUM(x,vm) gc_bignum x##__gc_root(&x,vm)
213
214 //generic_arrays.hpp
215 template <typename TYPE> TYPE *factorvm::allot_array_internal(cell capacity)
216 {
217         TYPE *array = allot<TYPE>(array_size<TYPE>(capacity));
218         array->capacity = tag_fixnum(capacity);
219         return array;
220 }
221
222 template <typename TYPE> bool factorvm::reallot_array_in_place_p(TYPE *array, cell capacity)
223 {
224         return in_zone(&nursery,array) && capacity <= array_capacity(array);
225 }
226
227 template <typename TYPE> TYPE *factorvm::reallot_array(TYPE *array_, cell capacity)
228 {
229         gc_root<TYPE> array(array_,this);
230
231         if(reallot_array_in_place_p(array.untagged(),capacity))
232         {
233                 array->capacity = tag_fixnum(capacity);
234                 return array.untagged();
235         }
236         else
237         {
238                 cell to_copy = array_capacity(array.untagged());
239                 if(capacity < to_copy)
240                         to_copy = capacity;
241
242                 TYPE *new_array = allot_array_internal<TYPE>(capacity);
243         
244                 memcpy(new_array + 1,array.untagged() + 1,to_copy * TYPE::element_size);
245                 memset((char *)(new_array + 1) + to_copy * TYPE::element_size,
246                         0,(capacity - to_copy) * TYPE::element_size);
247
248                 return new_array;
249         }
250 }
251
252 //arrays.hpp
253 inline void factorvm::set_array_nth(array *array, cell slot, cell value)
254 {
255 #ifdef FACTOR_DEBUG
256         assert(slot < array_capacity(array));
257         assert(array->h.hi_tag() == ARRAY_TYPE);
258         check_tagged_pointer(value);
259 #endif
260         array->data()[slot] = value;
261         write_barrier(array);
262 }
263
264 struct growable_array {
265         cell count;
266         gc_root<array> elements;
267
268         growable_array(factorvm *myvm, cell capacity = 10) : count(0), elements(myvm->allot_array(capacity,F),myvm) {}
269
270         void add(cell elt);
271         void trim();
272 };
273
274 //byte_arrays.hpp
275 struct growable_byte_array {
276         cell count;
277         gc_root<byte_array> elements;
278
279         growable_byte_array(factorvm *myvm,cell capacity = 40) : count(0), elements(myvm->allot_byte_array(capacity),myvm) { }
280
281         void append_bytes(void *elts, cell len);
282         void append_byte_array(cell elts);
283
284         void trim();
285 };
286
287 //math.hpp
288 inline cell factorvm::allot_integer(fixnum x)
289 {
290         if(x < fixnum_min || x > fixnum_max)
291                 return tag<bignum>(fixnum_to_bignum(x));
292         else
293                 return tag_fixnum(x);
294 }
295
296 inline cell factorvm::allot_cell(cell x)
297 {
298         if(x > (cell)fixnum_max)
299                 return tag<bignum>(cell_to_bignum(x));
300         else
301                 return tag_fixnum(x);
302 }
303
304 inline cell factorvm::allot_float(double n)
305 {
306         boxed_float *flo = allot<boxed_float>(sizeof(boxed_float));
307         flo->n = n;
308         return tag(flo);
309 }
310
311 inline bignum *factorvm::float_to_bignum(cell tagged)
312 {
313         return double_to_bignum(untag_float(tagged));
314 }
315
316 inline double factorvm::bignum_to_float(cell tagged)
317 {
318         return bignum_to_double(untag<bignum>(tagged));
319 }
320
321 inline double factorvm::untag_float(cell tagged)
322 {
323         return untag<boxed_float>(tagged)->n;
324 }
325
326 inline double factorvm::untag_float_check(cell tagged)
327 {
328         return untag_check<boxed_float>(tagged)->n;
329 }
330
331 inline fixnum factorvm::float_to_fixnum(cell tagged)
332 {
333         return (fixnum)untag_float(tagged);
334 }
335
336 inline double factorvm::fixnum_to_float(cell tagged)
337 {
338         return (double)untag_fixnum(tagged);
339 }
340
341 //callstack.hpp
342 /* This is a little tricky. The iterator may allocate memory, so we
343 keep the callstack in a GC root and use relative offsets */
344 template<typename TYPE> void factorvm::iterate_callstack_object(callstack *stack_, TYPE &iterator)
345 {
346         gc_root<callstack> stack(stack_,this);
347         fixnum frame_offset = untag_fixnum(stack->length) - sizeof(stack_frame);
348
349         while(frame_offset >= 0)
350         {
351                 stack_frame *frame = stack->frame_at(frame_offset);
352                 frame_offset -= frame->size;
353                 iterator(frame,this);
354         }
355 }
356
357 //booleans.hpp
358 inline cell factorvm::tag_boolean(cell untagged)
359 {
360         return (untagged ? T : F);
361 }
362
363 // callstack.hpp
364 template<typename TYPE> void factorvm::iterate_callstack(cell top, cell bottom, TYPE &iterator)
365 {
366         stack_frame *frame = (stack_frame *)bottom - 1;
367
368         while((cell)frame >= top)
369         {
370                 iterator(frame,this);
371                 frame = frame_successor(frame);
372         }
373 }
374
375
376 // data_heap.hpp
377 /* Every object has a regular representation in the runtime, which makes GC
378 much simpler. Every slot of the object until binary_payload_start is a pointer
379 to some other object. */
380 struct factorvm;
381 inline void factorvm::do_slots(cell obj, void (* iter)(cell *,factorvm*))
382 {
383         cell scan = obj;
384         cell payload_start = binary_payload_start((object *)obj);
385         cell end = obj + payload_start;
386
387         scan += sizeof(cell);
388
389         while(scan < end)
390         {
391                 iter((cell *)scan,this);
392                 scan += sizeof(cell);
393         }
394 }
395
396 // code_heap.hpp
397
398 inline void factorvm::check_code_pointer(cell ptr)
399 {
400 #ifdef FACTOR_DEBUG
401         assert(in_code_heap_p(ptr));
402 #endif
403 }
404
405 }