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
9 inline cell factorvm::align_page(cell a)
11 return align(a,getpagesize());
14 inline static cell align_page(cell a)
16 return vm->align_page(a);
21 inline card *factorvm::addr_to_card(cell a)
23 return (card*)(((cell)(a) >> card_bits) + cards_offset);
26 inline card *addr_to_card(cell a)
28 return vm->addr_to_card(a);
31 inline cell factorvm::card_to_addr(card *c)
33 return ((cell)c - cards_offset) << card_bits;
36 inline cell card_to_addr(card *c)
38 return vm->card_to_addr(c);
41 inline cell factorvm::card_offset(card *c)
43 return *(c - (cell)data->cards + (cell)data->allot_markers);
46 inline cell card_offset(card *c)
48 return vm->card_offset(c);
51 inline card_deck *factorvm::addr_to_deck(cell a)
53 return (card_deck *)(((cell)a >> deck_bits) + decks_offset);
56 inline card_deck *addr_to_deck(cell a)
58 return vm->addr_to_deck(a);
61 inline cell factorvm::deck_to_addr(card_deck *c)
63 return ((cell)c - decks_offset) << deck_bits;
66 inline cell deck_to_addr(card_deck *c)
68 return vm->deck_to_addr(c);
71 inline card *factorvm::deck_to_card(card_deck *d)
73 return (card *)((((cell)d - decks_offset) << (deck_bits - card_bits)) + cards_offset);
76 inline card *deck_to_card(card_deck *d)
78 return vm->deck_to_card(d);
81 inline card *factorvm::addr_to_allot_marker(object *a)
83 return (card *)(((cell)a >> card_bits) + allot_markers_offset);
86 inline card *addr_to_allot_marker(object *a)
88 return vm->addr_to_allot_marker(a);
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)
95 *addr_to_card((cell)obj) = card_mark_mask;
96 *addr_to_deck((cell)obj) = card_mark_mask;
99 inline void write_barrier(object *obj)
101 return vm->write_barrier(obj);
104 /* we need to remember the first object allocated in the card */
105 inline void factorvm::allot_barrier(object *address)
107 card *ptr = addr_to_allot_marker(address);
108 if(*ptr == invalid_allot_marker)
109 *ptr = ((cell)address & addr_card_mask);
112 inline void allot_barrier(object *address)
114 return vm->allot_barrier(address);
119 inline bool factorvm::collecting_accumulation_gen_p()
121 return ((data->have_aging_p()
122 && collecting_gen == data->aging()
123 && !collecting_aging_again)
124 || collecting_gen == data->tenured());
127 inline bool collecting_accumulation_gen_p()
129 return vm->collecting_accumulation_gen_p();
132 inline object *factorvm::allot_zone(zone *z, cell a)
135 z->here = h + align8(a);
136 object *obj = (object *)h;
141 inline object *allot_zone(zone *z, cell a)
143 return vm->allot_zone(z,a);
147 * It is up to the caller to fill in the object's fields in a meaningful
150 inline object *factorvm::allot_object(header header, cell size)
159 if(nursery.size - allot_buffer_zone > size)
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);
165 cell h = nursery.here;
166 nursery.here = h + align8(size);
169 /* If the object is bigger than the nursery, allocate it in
173 zone *tenured = &data->generations[data->tenured()];
175 /* If tenured space does not have enough room, collect */
176 if(tenured->here + size > tenured->end)
179 tenured = &data->generations[data->tenured()];
182 /* If it still won't fit, grow the heap */
183 if(tenured->here + size > tenured->end)
185 garbage_collection(data->tenured(),true,size);
186 tenured = &data->generations[data->tenured()];
189 obj = allot_zone(tenured,size);
191 /* Allows initialization code to store old->new pointers
192 without hitting the write barrier in the common case of
193 a nursery allocation */
201 inline object *allot_object(header header, cell size)
203 return vm->allot_object(header,size);
206 template<typename TYPE> TYPE *factorvm::allot(cell size)
208 return (TYPE *)allot_object(header(TYPE::type_number),size);
211 template<typename TYPE> TYPE *allot(cell size)
213 return vm->allot<TYPE>(size);
216 inline void factorvm::check_data_pointer(object *pointer)
219 if(!growing_data_heap)
221 assert((cell)pointer >= data->seg->start
222 && (cell)pointer < data->seg->end);
227 inline void check_data_pointer(object *pointer)
229 return vm->check_data_pointer(pointer);
232 inline void factorvm::check_tagged_pointer(cell tagged)
235 if(!immediate_p(tagged))
237 object *obj = untag<object>(tagged);
238 check_data_pointer(obj);
244 inline void check_tagged_pointer(cell tagged)
246 return vm->check_tagged_pointer(tagged);
250 template <typename TYPE>
251 struct gc_root : public tagged<TYPE>
255 void push() { check_tagged_pointer(tagged<TYPE>::value()); myvm->gc_locals.push_back((cell)this); }
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(); }
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; }
266 assert(myvm->gc_locals.back() == (cell)this);
268 myvm->gc_locals.pop_back();
272 /* A similar hack for the bignum implementation */
277 gc_bignum(bignum **addr_, factorvm *vm) : addr(addr_), myvm(vm) {
279 check_data_pointer(*addr_);
280 myvm->gc_bignums.push_back((cell)addr);
285 assert(myvm->gc_bignums.back() == (cell)addr);
287 myvm->gc_bignums.pop_back();
291 #define GC_BIGNUM(x,vm) gc_bignum x##__gc_root(&x,vm)
294 template <typename TYPE> TYPE *factorvm::allot_array_internal(cell capacity)
296 TYPE *array = allot<TYPE>(array_size<TYPE>(capacity));
297 array->capacity = tag_fixnum(capacity);
301 template <typename TYPE> TYPE *allot_array_internal(cell capacity)
303 return vm->allot_array_internal<TYPE>(capacity);
306 template <typename TYPE> bool factorvm::reallot_array_in_place_p(TYPE *array, cell capacity)
308 return in_zone(&nursery,array) && capacity <= array_capacity(array);
311 template <typename TYPE> bool reallot_array_in_place_p(TYPE *array, cell capacity)
313 return vm->reallot_array_in_place_p<TYPE>(array,capacity);
316 template <typename TYPE> TYPE *factorvm::reallot_array(TYPE *array_, cell capacity)
318 gc_root<TYPE> array(array_,this);
320 if(reallot_array_in_place_p(array.untagged(),capacity))
322 array->capacity = tag_fixnum(capacity);
323 return array.untagged();
327 cell to_copy = array_capacity(array.untagged());
328 if(capacity < to_copy)
331 TYPE *new_array = allot_array_internal<TYPE>(capacity);
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);
342 inline void factorvm::set_array_nth(array *array, cell slot, cell value)
345 assert(slot < array_capacity(array));
346 assert(array->h.hi_tag() == ARRAY_TYPE);
347 check_tagged_pointer(value);
349 array->data()[slot] = value;
350 write_barrier(array);
353 inline void set_array_nth(array *array, cell slot, cell value)
355 return vm->set_array_nth(array,slot,value);
358 struct growable_array {
360 gc_root<array> elements;
362 growable_array(factorvm *myvm, cell capacity = 10) : count(0), elements(myvm->allot_array(capacity,F),myvm) {}
369 struct growable_byte_array {
371 gc_root<byte_array> elements;
373 growable_byte_array(factorvm *myvm,cell capacity = 40) : count(0), elements(myvm->allot_byte_array(capacity),myvm) { }
375 void append_bytes(void *elts, cell len);
376 void append_byte_array(cell elts);
382 inline cell factorvm::allot_integer(fixnum x)
384 if(x < fixnum_min || x > fixnum_max)
385 return tag<bignum>(fixnum_to_bignum(x));
387 return tag_fixnum(x);
390 inline cell allot_integer(fixnum x)
392 return vm->allot_integer(x);
395 inline cell factorvm::allot_cell(cell x)
397 if(x > (cell)fixnum_max)
398 return tag<bignum>(cell_to_bignum(x));
400 return tag_fixnum(x);
403 inline cell allot_cell(cell x)
405 return vm->allot_cell(x);
408 inline cell factorvm::allot_float(double n)
410 boxed_float *flo = allot<boxed_float>(sizeof(boxed_float));
415 inline cell allot_float(double n)
417 return vm->allot_float(n);
420 inline bignum *factorvm::float_to_bignum(cell tagged)
422 return double_to_bignum(untag_float(tagged));
425 inline bignum *float_to_bignum(cell tagged)
427 return vm->float_to_bignum(tagged);
430 inline double factorvm::bignum_to_float(cell tagged)
432 return bignum_to_double(untag<bignum>(tagged));
435 inline double bignum_to_float(cell tagged)
437 return vm->bignum_to_float(tagged);
440 inline double factorvm::untag_float(cell tagged)
442 return untag<boxed_float>(tagged)->n;
445 inline double untag_float(cell tagged)
447 return vm->untag_float(tagged);
450 inline double factorvm::untag_float_check(cell tagged)
452 return untag_check<boxed_float>(tagged)->n;
455 inline double untag_float_check(cell tagged)
457 return vm->untag_float_check(tagged);
460 inline fixnum factorvm::float_to_fixnum(cell tagged)
462 return (fixnum)untag_float(tagged);
465 inline static fixnum float_to_fixnum(cell tagged)
467 return vm->float_to_fixnum(tagged);
470 inline double factorvm::fixnum_to_float(cell tagged)
472 return (double)untag_fixnum(tagged);
475 inline double fixnum_to_float(cell tagged)
477 return vm->fixnum_to_float(tagged);
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)
486 gc_root<callstack> stack(stack_,vm);
487 fixnum frame_offset = untag_fixnum(stack->length) - sizeof(stack_frame);
489 while(frame_offset >= 0)
491 stack_frame *frame = stack->frame_at(frame_offset);
492 frame_offset -= frame->size;
493 iterator(frame,this);
497 template<typename TYPE> void iterate_callstack_object(callstack *stack_, TYPE &iterator)
499 return vm->iterate_callstack_object(stack_,iterator);
503 inline cell factorvm::tag_boolean(cell untagged)
505 return (untagged ? T : F);
508 inline cell tag_boolean(cell untagged)
510 return vm->tag_boolean(untagged);
514 template<typename TYPE> void factorvm::iterate_callstack(cell top, cell bottom, TYPE &iterator)
516 stack_frame *frame = (stack_frame *)bottom - 1;
518 while((cell)frame >= top)
520 iterator(frame,this);
521 frame = frame_successor(frame);
525 template<typename TYPE> void iterate_callstack(cell top, cell bottom, TYPE &iterator)
527 return vm->iterate_callstack(top,bottom,iterator);
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. */
536 inline void factorvm::do_slots(cell obj, void (* iter)(cell *,factorvm*))
539 cell payload_start = binary_payload_start((object *)obj);
540 cell end = obj + payload_start;
542 scan += sizeof(cell);
546 iter((cell *)scan,this);
547 scan += sizeof(cell);
551 inline void do_slots(cell obj, void (* iter)(cell *,factorvm*))
553 return vm->do_slots(obj,iter);
558 inline void factorvm::check_code_pointer(cell ptr)
561 assert(in_code_heap_p(ptr));