]> gitweb.factorcode.org Git - factor.git/blob - vm/inlineimpls.hpp
ca0b13be39b45551a151fb8b3587edafcc638650
[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 inline static cell align_page(cell a)
15 {
16         return vm->align_page(a);
17 }
18
19 // write_barrier.hpp
20
21 inline card *factorvm::addr_to_card(cell a)
22 {
23         return (card*)(((cell)(a) >> card_bits) + cards_offset);
24 }
25
26 inline card *addr_to_card(cell a)
27 {
28         return vm->addr_to_card(a);
29 }
30
31 inline cell factorvm::card_to_addr(card *c)
32 {
33         return ((cell)c - cards_offset) << card_bits;
34 }
35
36 inline cell card_to_addr(card *c)
37 {
38         return vm->card_to_addr(c);
39 }
40
41 inline cell factorvm::card_offset(card *c)
42 {
43         return *(c - (cell)data->cards + (cell)data->allot_markers);
44 }
45
46 inline cell card_offset(card *c)
47 {
48         return vm->card_offset(c);
49 }
50
51 inline card_deck *factorvm::addr_to_deck(cell a)
52 {
53         return (card_deck *)(((cell)a >> deck_bits) + decks_offset);
54 }
55
56 inline card_deck *addr_to_deck(cell a)
57 {
58         return vm->addr_to_deck(a);
59 }
60
61 inline cell factorvm::deck_to_addr(card_deck *c)
62 {
63         return ((cell)c - decks_offset) << deck_bits;
64 }
65
66 inline cell deck_to_addr(card_deck *c)
67 {
68         return vm->deck_to_addr(c);
69 }
70
71 inline card *factorvm::deck_to_card(card_deck *d)
72 {
73         return (card *)((((cell)d - decks_offset) << (deck_bits - card_bits)) + cards_offset);
74 }
75
76 inline card *deck_to_card(card_deck *d)
77 {
78         return vm->deck_to_card(d);
79 }
80
81 inline card *factorvm::addr_to_allot_marker(object *a)
82 {
83         return (card *)(((cell)a >> card_bits) + allot_markers_offset);
84 }
85
86 inline card *addr_to_allot_marker(object *a)
87 {
88         return vm->addr_to_allot_marker(a);
89 }
90
91 /* the write barrier must be called any time we are potentially storing a
92 pointer from an older generation to a younger one */
93 inline void factorvm::write_barrier(object *obj)
94 {
95         *addr_to_card((cell)obj) = card_mark_mask;
96         *addr_to_deck((cell)obj) = card_mark_mask;
97 }
98
99 inline void write_barrier(object *obj)
100 {
101         return vm->write_barrier(obj);
102 }
103
104 /* we need to remember the first object allocated in the card */
105 inline void factorvm::allot_barrier(object *address)
106 {
107         card *ptr = addr_to_allot_marker(address);
108         if(*ptr == invalid_allot_marker)
109                 *ptr = ((cell)address & addr_card_mask);
110 }
111
112 inline void allot_barrier(object *address)
113 {
114         return vm->allot_barrier(address);
115 }
116
117
118 //data_gc.hpp
119 inline bool factorvm::collecting_accumulation_gen_p()
120 {
121         return ((data->have_aging_p()
122                 && collecting_gen == data->aging()
123                 && !collecting_aging_again)
124                 || collecting_gen == data->tenured());
125 }
126
127 inline bool collecting_accumulation_gen_p()
128 {
129         return vm->collecting_accumulation_gen_p();
130 }
131
132 inline object *factorvm::allot_zone(zone *z, cell a)
133 {
134         cell h = z->here;
135         z->here = h + align8(a);
136         object *obj = (object *)h;
137         allot_barrier(obj);
138         return obj;
139 }
140
141 inline object *allot_zone(zone *z, cell a)
142 {
143         return vm->allot_zone(z,a);
144 }
145
146 /*
147  * It is up to the caller to fill in the object's fields in a meaningful
148  * fashion!
149  */
150 inline object *factorvm::allot_object(header header, cell size)
151 {
152 #ifdef GC_DEBUG
153         if(!gc_off)
154                 gc();
155 #endif
156
157         object *obj;
158
159         if(nursery.size - allot_buffer_zone > size)
160         {
161                 /* If there is insufficient room, collect the nursery */
162                 if(nursery.here + allot_buffer_zone + size > nursery.end)
163                         garbage_collection(data->nursery(),false,0);
164
165                 cell h = nursery.here;
166                 nursery.here = h + align8(size);
167                 obj = (object *)h;
168         }
169         /* If the object is bigger than the nursery, allocate it in
170         tenured space */
171         else
172         {
173                 zone *tenured = &data->generations[data->tenured()];
174
175                 /* If tenured space does not have enough room, collect */
176                 if(tenured->here + size > tenured->end)
177                 {
178                         gc();
179                         tenured = &data->generations[data->tenured()];
180                 }
181
182                 /* If it still won't fit, grow the heap */
183                 if(tenured->here + size > tenured->end)
184                 {
185                         garbage_collection(data->tenured(),true,size);
186                         tenured = &data->generations[data->tenured()];
187                 }
188
189                 obj = allot_zone(tenured,size);
190
191                 /* Allows initialization code to store old->new pointers
192                 without hitting the write barrier in the common case of
193                 a nursery allocation */
194                 write_barrier(obj);
195         }
196
197         obj->h = header;
198         return obj;
199 }
200
201 inline object *allot_object(header header, cell size)
202 {
203         return vm->allot_object(header,size);
204 }
205
206 template<typename TYPE> TYPE *factorvm::allot(cell size)
207 {
208         return (TYPE *)allot_object(header(TYPE::type_number),size);
209 }
210
211 template<typename TYPE> TYPE *allot(cell size)
212 {
213         return vm->allot<TYPE>(size);
214 }
215
216 inline void factorvm::check_data_pointer(object *pointer)
217 {
218 #ifdef FACTOR_DEBUG
219         if(!growing_data_heap)
220         {
221                 assert((cell)pointer >= data->seg->start
222                        && (cell)pointer < data->seg->end);
223         }
224 #endif
225 }
226
227 inline void check_data_pointer(object *pointer)
228 {
229         return vm->check_data_pointer(pointer);
230 }
231
232 inline void factorvm::check_tagged_pointer(cell tagged)
233 {
234 #ifdef FACTOR_DEBUG
235         if(!immediate_p(tagged))
236         {
237                 object *obj = untag<object>(tagged);
238                 check_data_pointer(obj);
239                 obj->h.hi_tag();
240         }
241 #endif
242 }
243
244 inline void check_tagged_pointer(cell tagged)
245 {
246         return vm->check_tagged_pointer(tagged);
247 }
248
249 //local_roots.hpp
250 template <typename TYPE>
251 struct gc_root : public tagged<TYPE>
252 {
253         factorvm *myvm;
254
255         void push() { check_tagged_pointer(tagged<TYPE>::value()); myvm->gc_locals.push_back((cell)this); }
256         
257         //explicit gc_root(cell value_, factorvm *vm) : myvm(vm),tagged<TYPE>(value_) { push(); }
258         explicit gc_root(cell value_,factorvm *vm) : tagged<TYPE>(value_),myvm(vm) { push(); }
259         explicit gc_root(TYPE *value_, factorvm *vm) : tagged<TYPE>(value_),myvm(vm) { push(); }
260
261         const gc_root<TYPE>& operator=(const TYPE *x) { tagged<TYPE>::operator=(x); return *this; }
262         const gc_root<TYPE>& operator=(const cell &x) { tagged<TYPE>::operator=(x); return *this; }
263
264         ~gc_root() {
265 #ifdef FACTOR_DEBUG
266                 assert(myvm->gc_locals.back() == (cell)this);
267 #endif
268                 myvm->gc_locals.pop_back();
269         }
270 };
271
272 /* A similar hack for the bignum implementation */
273 struct gc_bignum
274 {
275         bignum **addr;
276         factorvm *myvm;
277         gc_bignum(bignum **addr_, factorvm *vm) : addr(addr_), myvm(vm) {
278                 if(*addr_)
279                         check_data_pointer(*addr_);
280                 myvm->gc_bignums.push_back((cell)addr);
281         }
282
283         ~gc_bignum() {
284 #ifdef FACTOR_DEBUG
285                 assert(myvm->gc_bignums.back() == (cell)addr);
286 #endif
287                 myvm->gc_bignums.pop_back();
288         }
289 };
290
291 #define GC_BIGNUM(x,vm) gc_bignum x##__gc_root(&x,vm)
292
293 //generic_arrays.hpp
294 template <typename TYPE> TYPE *factorvm::allot_array_internal(cell capacity)
295 {
296         TYPE *array = allot<TYPE>(array_size<TYPE>(capacity));
297         array->capacity = tag_fixnum(capacity);
298         return array;
299 }
300
301 template <typename TYPE> TYPE *allot_array_internal(cell capacity)
302 {
303         return vm->allot_array_internal<TYPE>(capacity);
304 }
305
306 template <typename TYPE> bool factorvm::reallot_array_in_place_p(TYPE *array, cell capacity)
307 {
308         return in_zone(&nursery,array) && capacity <= array_capacity(array);
309 }
310
311 template <typename TYPE> bool reallot_array_in_place_p(TYPE *array, cell capacity)
312 {
313         return vm->reallot_array_in_place_p<TYPE>(array,capacity);
314 }
315
316 template <typename TYPE> TYPE *factorvm::reallot_array(TYPE *array_, cell capacity)
317 {
318         gc_root<TYPE> array(array_,this);
319
320         if(reallot_array_in_place_p(array.untagged(),capacity))
321         {
322                 array->capacity = tag_fixnum(capacity);
323                 return array.untagged();
324         }
325         else
326         {
327                 cell to_copy = array_capacity(array.untagged());
328                 if(capacity < to_copy)
329                         to_copy = capacity;
330
331                 TYPE *new_array = allot_array_internal<TYPE>(capacity);
332         
333                 memcpy(new_array + 1,array.untagged() + 1,to_copy * TYPE::element_size);
334                 memset((char *)(new_array + 1) + to_copy * TYPE::element_size,
335                         0,(capacity - to_copy) * TYPE::element_size);
336
337                 return new_array;
338         }
339 }
340
341 //arrays.hpp
342 inline void factorvm::set_array_nth(array *array, cell slot, cell value)
343 {
344 #ifdef FACTOR_DEBUG
345         assert(slot < array_capacity(array));
346         assert(array->h.hi_tag() == ARRAY_TYPE);
347         check_tagged_pointer(value);
348 #endif
349         array->data()[slot] = value;
350         write_barrier(array);
351 }
352
353 inline void set_array_nth(array *array, cell slot, cell value)
354 {
355         return vm->set_array_nth(array,slot,value);
356 }
357
358 struct growable_array {
359         cell count;
360         gc_root<array> elements;
361
362         growable_array(factorvm *myvm, cell capacity = 10) : count(0), elements(myvm->allot_array(capacity,F),myvm) {}
363
364         void add(cell elt);
365         void trim();
366 };
367
368 //byte_arrays.hpp
369 struct growable_byte_array {
370         cell count;
371         gc_root<byte_array> elements;
372
373         growable_byte_array(factorvm *myvm,cell capacity = 40) : count(0), elements(myvm->allot_byte_array(capacity),myvm) { }
374
375         void append_bytes(void *elts, cell len);
376         void append_byte_array(cell elts);
377
378         void trim();
379 };
380
381 //math.hpp
382 inline cell factorvm::allot_integer(fixnum x)
383 {
384         if(x < fixnum_min || x > fixnum_max)
385                 return tag<bignum>(fixnum_to_bignum(x));
386         else
387                 return tag_fixnum(x);
388 }
389
390 inline cell allot_integer(fixnum x)
391 {
392         return vm->allot_integer(x);
393 }
394
395 inline cell factorvm::allot_cell(cell x)
396 {
397         if(x > (cell)fixnum_max)
398                 return tag<bignum>(cell_to_bignum(x));
399         else
400                 return tag_fixnum(x);
401 }
402
403 inline cell allot_cell(cell x)
404 {
405         return vm->allot_cell(x);
406 }
407
408 inline cell factorvm::allot_float(double n)
409 {
410         boxed_float *flo = allot<boxed_float>(sizeof(boxed_float));
411         flo->n = n;
412         return tag(flo);
413 }
414
415 inline cell allot_float(double n)
416 {
417         return vm->allot_float(n);
418 }
419
420 inline bignum *factorvm::float_to_bignum(cell tagged)
421 {
422         return double_to_bignum(untag_float(tagged));
423 }
424
425 inline bignum *float_to_bignum(cell tagged)
426 {
427         return vm->float_to_bignum(tagged);
428 }
429
430 inline double factorvm::bignum_to_float(cell tagged)
431 {
432         return bignum_to_double(untag<bignum>(tagged));
433 }
434
435 inline double bignum_to_float(cell tagged)
436 {
437         return vm->bignum_to_float(tagged);
438 }
439
440 inline double factorvm::untag_float(cell tagged)
441 {
442         return untag<boxed_float>(tagged)->n;
443 }
444
445 inline double untag_float(cell tagged)
446 {
447         return vm->untag_float(tagged);
448 }
449
450 inline double factorvm::untag_float_check(cell tagged)
451 {
452         return untag_check<boxed_float>(tagged)->n;
453 }
454
455 inline double untag_float_check(cell tagged)
456 {
457         return vm->untag_float_check(tagged);
458 }
459
460 inline fixnum factorvm::float_to_fixnum(cell tagged)
461 {
462         return (fixnum)untag_float(tagged);
463 }
464
465 inline static fixnum float_to_fixnum(cell tagged)
466 {
467         return vm->float_to_fixnum(tagged);
468 }
469
470 inline double factorvm::fixnum_to_float(cell tagged)
471 {
472         return (double)untag_fixnum(tagged);
473 }
474
475 inline double fixnum_to_float(cell tagged)
476 {
477         return vm->fixnum_to_float(tagged);
478 }
479
480
481 //callstack.hpp
482 /* This is a little tricky. The iterator may allocate memory, so we
483 keep the callstack in a GC root and use relative offsets */
484 template<typename TYPE> void factorvm::iterate_callstack_object(callstack *stack_, TYPE &iterator)
485 {
486         gc_root<callstack> stack(stack_,vm);
487         fixnum frame_offset = untag_fixnum(stack->length) - sizeof(stack_frame);
488
489         while(frame_offset >= 0)
490         {
491                 stack_frame *frame = stack->frame_at(frame_offset);
492                 frame_offset -= frame->size;
493                 iterator(frame,this);
494         }
495 }
496
497 template<typename TYPE> void iterate_callstack_object(callstack *stack_, TYPE &iterator)
498 {
499         return vm->iterate_callstack_object(stack_,iterator);
500 }
501
502 //booleans.hpp
503 inline cell factorvm::tag_boolean(cell untagged)
504 {
505         return (untagged ? T : F);
506 }
507
508 inline cell tag_boolean(cell untagged)
509 {
510         return vm->tag_boolean(untagged);
511 }
512
513 // callstack.hpp
514 template<typename TYPE> void factorvm::iterate_callstack(cell top, cell bottom, TYPE &iterator)
515 {
516         stack_frame *frame = (stack_frame *)bottom - 1;
517
518         while((cell)frame >= top)
519         {
520                 iterator(frame,this);
521                 frame = frame_successor(frame);
522         }
523 }
524
525 template<typename TYPE> void iterate_callstack(cell top, cell bottom, TYPE &iterator)
526 {
527         return vm->iterate_callstack(top,bottom,iterator);
528 }
529
530
531 // data_heap.hpp
532 /* Every object has a regular representation in the runtime, which makes GC
533 much simpler. Every slot of the object until binary_payload_start is a pointer
534 to some other object. */
535 struct factorvm;
536 inline void factorvm::do_slots(cell obj, void (* iter)(cell *,factorvm*))
537 {
538         cell scan = obj;
539         cell payload_start = binary_payload_start((object *)obj);
540         cell end = obj + payload_start;
541
542         scan += sizeof(cell);
543
544         while(scan < end)
545         {
546                 iter((cell *)scan,this);
547                 scan += sizeof(cell);
548         }
549 }
550
551 inline void do_slots(cell obj, void (* iter)(cell *,factorvm*))
552 {
553         return vm->do_slots(obj,iter);
554 }
555
556 // code_heap.hpp
557
558 inline void factorvm::check_code_pointer(cell ptr)
559 {
560 #ifdef FACTOR_DEBUG
561         assert(in_code_heap_p(ptr));
562 #endif
563 }
564
565 }