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