Merge branch 'master' of git://factorcode.org/git/factor
[factor/jcg.git] / vm / data_gc.c
blob2122f930f0569e4f4be826812d3f1dd498f09f84
1 #include "master.h"
3 CELL init_zone(F_ZONE *z, CELL size, CELL start)
5 z->size = size;
6 z->start = z->here = start;
7 z->end = start + size;
8 return z->end;
11 void init_card_decks(void)
13 CELL start = align(data_heap->segment->start,DECK_SIZE);
14 allot_markers_offset = (CELL)data_heap->allot_markers - (start >> CARD_BITS);
15 cards_offset = (CELL)data_heap->cards - (start >> CARD_BITS);
16 decks_offset = (CELL)data_heap->decks - (start >> DECK_BITS);
19 F_DATA_HEAP *alloc_data_heap(CELL gens,
20 CELL young_size,
21 CELL aging_size,
22 CELL tenured_size)
24 young_size = align(young_size,DECK_SIZE);
25 aging_size = align(aging_size,DECK_SIZE);
26 tenured_size = align(tenured_size,DECK_SIZE);
28 F_DATA_HEAP *data_heap = safe_malloc(sizeof(F_DATA_HEAP));
29 data_heap->young_size = young_size;
30 data_heap->aging_size = aging_size;
31 data_heap->tenured_size = tenured_size;
32 data_heap->gen_count = gens;
34 CELL total_size;
35 if(data_heap->gen_count == 2)
36 total_size = young_size + 2 * tenured_size;
37 else if(data_heap->gen_count == 3)
38 total_size = young_size + 2 * aging_size + 2 * tenured_size;
39 else
41 fatal_error("Invalid number of generations",data_heap->gen_count);
42 return NULL; /* can't happen */
45 total_size += DECK_SIZE;
47 data_heap->segment = alloc_segment(total_size);
49 data_heap->generations = safe_malloc(sizeof(F_ZONE) * data_heap->gen_count);
50 data_heap->semispaces = safe_malloc(sizeof(F_ZONE) * data_heap->gen_count);
52 CELL cards_size = total_size >> CARD_BITS;
53 data_heap->allot_markers = safe_malloc(cards_size);
54 data_heap->allot_markers_end = data_heap->allot_markers + cards_size;
56 data_heap->cards = safe_malloc(cards_size);
57 data_heap->cards_end = data_heap->cards + cards_size;
59 CELL decks_size = total_size >> DECK_BITS;
60 data_heap->decks = safe_malloc(decks_size);
61 data_heap->decks_end = data_heap->decks + decks_size;
63 CELL alloter = align(data_heap->segment->start,DECK_SIZE);
65 alloter = init_zone(&data_heap->generations[TENURED],tenured_size,alloter);
66 alloter = init_zone(&data_heap->semispaces[TENURED],tenured_size,alloter);
68 if(data_heap->gen_count == 3)
70 alloter = init_zone(&data_heap->generations[AGING],aging_size,alloter);
71 alloter = init_zone(&data_heap->semispaces[AGING],aging_size,alloter);
74 if(data_heap->gen_count >= 2)
76 alloter = init_zone(&data_heap->generations[NURSERY],young_size,alloter);
77 alloter = init_zone(&data_heap->semispaces[NURSERY],0,alloter);
80 if(data_heap->segment->end - alloter > DECK_SIZE)
81 critical_error("Bug in alloc_data_heap",alloter);
83 return data_heap;
86 F_DATA_HEAP *grow_data_heap(F_DATA_HEAP *data_heap, CELL requested_bytes)
88 CELL new_tenured_size = (data_heap->tenured_size * 2) + requested_bytes;
90 return alloc_data_heap(data_heap->gen_count,
91 data_heap->young_size,
92 data_heap->aging_size,
93 new_tenured_size);
96 void dealloc_data_heap(F_DATA_HEAP *data_heap)
98 dealloc_segment(data_heap->segment);
99 free(data_heap->generations);
100 free(data_heap->semispaces);
101 free(data_heap->allot_markers);
102 free(data_heap->cards);
103 free(data_heap->decks);
104 free(data_heap);
107 void clear_cards(CELL from, CELL to)
109 /* NOTE: reverse order due to heap layout. */
110 F_CARD *first_card = ADDR_TO_CARD(data_heap->generations[to].start);
111 F_CARD *last_card = ADDR_TO_CARD(data_heap->generations[from].end);
112 memset(first_card,0,last_card - first_card);
115 void clear_decks(CELL from, CELL to)
117 /* NOTE: reverse order due to heap layout. */
118 F_DECK *first_deck = ADDR_TO_DECK(data_heap->generations[to].start);
119 F_DECK *last_deck = ADDR_TO_DECK(data_heap->generations[from].end);
120 memset(first_deck,0,last_deck - first_deck);
123 void clear_allot_markers(CELL from, CELL to)
125 /* NOTE: reverse order due to heap layout. */
126 F_CARD *first_card = ADDR_TO_ALLOT_MARKER(data_heap->generations[to].start);
127 F_CARD *last_card = ADDR_TO_ALLOT_MARKER(data_heap->generations[from].end);
128 memset(first_card,INVALID_ALLOT_MARKER,last_card - first_card);
131 void set_data_heap(F_DATA_HEAP *data_heap_)
133 data_heap = data_heap_;
134 nursery = data_heap->generations[NURSERY];
135 init_card_decks();
136 clear_cards(NURSERY,TENURED);
137 clear_decks(NURSERY,TENURED);
138 clear_allot_markers(NURSERY,TENURED);
141 void gc_reset(void)
143 int i;
144 for(i = 0; i < MAX_GEN_COUNT; i++)
145 memset(&gc_stats[i],0,sizeof(F_GC_STATS));
147 cards_scanned = 0;
148 decks_scanned = 0;
149 code_heap_scans = 0;
152 void init_data_heap(CELL gens,
153 CELL young_size,
154 CELL aging_size,
155 CELL tenured_size,
156 bool secure_gc_)
158 set_data_heap(alloc_data_heap(gens,young_size,aging_size,tenured_size));
160 gc_locals_region = alloc_segment(getpagesize());
161 gc_locals = gc_locals_region->start - CELLS;
163 extra_roots_region = alloc_segment(getpagesize());
164 extra_roots = extra_roots_region->start - CELLS;
166 secure_gc = secure_gc_;
168 gc_reset();
171 /* Size of the object pointed to by a tagged pointer */
172 CELL object_size(CELL tagged)
174 if(immediate_p(tagged))
175 return 0;
176 else
177 return untagged_object_size(UNTAG(tagged));
180 /* Size of the object pointed to by an untagged pointer */
181 CELL untagged_object_size(CELL pointer)
183 return align8(unaligned_object_size(pointer));
186 /* Size of the data area of an object pointed to by an untagged pointer */
187 CELL unaligned_object_size(CELL pointer)
189 F_TUPLE *tuple;
190 F_TUPLE_LAYOUT *layout;
192 switch(untag_header(get(pointer)))
194 case ARRAY_TYPE:
195 case BIGNUM_TYPE:
196 return array_size(array_capacity((F_ARRAY*)pointer));
197 case BYTE_ARRAY_TYPE:
198 return byte_array_size(
199 byte_array_capacity((F_BYTE_ARRAY*)pointer));
200 case STRING_TYPE:
201 return string_size(string_capacity((F_STRING*)pointer));
202 case TUPLE_TYPE:
203 tuple = untag_object(pointer);
204 layout = untag_object(tuple->layout);
205 return tuple_size(layout);
206 case QUOTATION_TYPE:
207 return sizeof(F_QUOTATION);
208 case WORD_TYPE:
209 return sizeof(F_WORD);
210 case RATIO_TYPE:
211 return sizeof(F_RATIO);
212 case FLOAT_TYPE:
213 return sizeof(F_FLOAT);
214 case COMPLEX_TYPE:
215 return sizeof(F_COMPLEX);
216 case DLL_TYPE:
217 return sizeof(F_DLL);
218 case ALIEN_TYPE:
219 return sizeof(F_ALIEN);
220 case WRAPPER_TYPE:
221 return sizeof(F_WRAPPER);
222 case CALLSTACK_TYPE:
223 return callstack_size(
224 untag_fixnum_fast(((F_CALLSTACK *)pointer)->length));
225 default:
226 critical_error("Invalid header",pointer);
227 return -1; /* can't happen */
231 void primitive_size(void)
233 box_unsigned_cell(object_size(dpop()));
236 /* Push memory usage statistics in data heap */
237 void primitive_data_room(void)
239 F_ARRAY *a = allot_array(ARRAY_TYPE,data_heap->gen_count * 2,F);
240 int gen;
242 dpush(tag_fixnum((data_heap->cards_end - data_heap->cards) >> 10));
243 dpush(tag_fixnum((data_heap->decks_end - data_heap->decks) >> 10));
245 for(gen = 0; gen < data_heap->gen_count; gen++)
247 F_ZONE *z = (gen == NURSERY ? &nursery : &data_heap->generations[gen]);
248 set_array_nth(a,gen * 2,tag_fixnum((z->end - z->here) >> 10));
249 set_array_nth(a,gen * 2 + 1,tag_fixnum((z->size) >> 10));
252 dpush(tag_object(a));
255 /* Disables GC and activates next-object ( -- obj ) primitive */
256 void begin_scan(void)
258 heap_scan_ptr = data_heap->generations[TENURED].start;
259 gc_off = true;
262 void primitive_begin_scan(void)
264 gc();
265 begin_scan();
268 CELL next_object(void)
270 if(!gc_off)
271 general_error(ERROR_HEAP_SCAN,F,F,NULL);
273 CELL value = get(heap_scan_ptr);
274 CELL obj = heap_scan_ptr;
275 CELL type;
277 if(heap_scan_ptr >= data_heap->generations[TENURED].here)
278 return F;
280 type = untag_header(value);
281 heap_scan_ptr += untagged_object_size(heap_scan_ptr);
283 return RETAG(obj,type <= HEADER_TYPE ? type : OBJECT_TYPE);
286 /* Push object at heap scan cursor and advance; pushes f when done */
287 void primitive_next_object(void)
289 dpush(next_object());
292 /* Re-enables GC */
293 void primitive_end_scan(void)
295 gc_off = false;
298 /* Scan all the objects in the card */
299 void collect_card(F_CARD *ptr, CELL gen, CELL here)
301 CELL card_scan = (CELL)CARD_TO_ADDR(ptr) + CARD_OFFSET(ptr);
302 CELL card_end = (CELL)CARD_TO_ADDR(ptr + 1);
304 if(here < card_end)
305 card_end = here;
307 collect_next_loop(card_scan,&card_end);
309 cards_scanned++;
312 void collect_card_deck(F_DECK *deck, CELL gen, F_CARD mask, F_CARD unmask)
314 F_CARD *first_card = DECK_TO_CARD(deck);
315 F_CARD *last_card = DECK_TO_CARD(deck + 1);
317 CELL here = data_heap->generations[gen].here;
319 u32 *quad_ptr;
320 u32 quad_mask = mask | (mask << 8) | (mask << 16) | (mask << 24);
322 for(quad_ptr = (u32 *)first_card; quad_ptr < (u32 *)last_card; quad_ptr++)
324 if(*quad_ptr & quad_mask)
326 F_CARD *ptr = (F_CARD *)quad_ptr;
328 int card;
329 for(card = 0; card < 4; card++)
331 if(ptr[card] & mask)
333 collect_card(&ptr[card],gen,here);
334 ptr[card] &= ~unmask;
340 decks_scanned++;
343 /* Copy all newspace objects referenced from marked cards to the destination */
344 void collect_gen_cards(CELL gen)
346 F_DECK *first_deck = ADDR_TO_DECK(data_heap->generations[gen].start);
347 F_DECK *last_deck = ADDR_TO_DECK(data_heap->generations[gen].end);
349 F_CARD mask, unmask;
351 /* if we are collecting the nursery, we care about old->nursery pointers
352 but not old->aging pointers */
353 if(collecting_gen == NURSERY)
355 mask = CARD_POINTS_TO_NURSERY;
357 /* after the collection, no old->nursery pointers remain
358 anywhere, but old->aging pointers might remain in tenured
359 space */
360 if(gen == TENURED)
361 unmask = CARD_POINTS_TO_NURSERY;
362 /* after the collection, all cards in aging space can be
363 cleared */
364 else if(HAVE_AGING_P && gen == AGING)
365 unmask = CARD_MARK_MASK;
366 else
368 critical_error("bug in collect_gen_cards",gen);
369 return;
372 /* if we are collecting aging space into tenured space, we care about
373 all old->nursery and old->aging pointers. no old->aging pointers can
374 remain */
375 else if(HAVE_AGING_P && collecting_gen == AGING)
377 if(collecting_aging_again)
379 mask = CARD_POINTS_TO_AGING;
380 unmask = CARD_MARK_MASK;
382 /* after we collect aging space into the aging semispace, no
383 old->nursery pointers remain but tenured space might still have
384 pointers to aging space. */
385 else
387 mask = CARD_POINTS_TO_AGING;
388 unmask = CARD_POINTS_TO_NURSERY;
391 else
393 critical_error("bug in collect_gen_cards",gen);
394 return;
397 F_DECK *ptr;
399 for(ptr = first_deck; ptr < last_deck; ptr++)
401 if(*ptr & mask)
403 collect_card_deck(ptr,gen,mask,unmask);
404 *ptr &= ~unmask;
409 /* Scan cards in all generations older than the one being collected, copying
410 old->new references */
411 void collect_cards(void)
413 int i;
414 for(i = collecting_gen + 1; i < data_heap->gen_count; i++)
415 collect_gen_cards(i);
418 /* Copy all tagged pointers in a range of memory */
419 void collect_stack(F_SEGMENT *region, CELL top)
421 CELL ptr = region->start;
423 for(; ptr <= top; ptr += CELLS)
424 copy_handle((CELL*)ptr);
427 void collect_stack_frame(F_STACK_FRAME *frame)
429 recursive_mark(compiled_to_block(frame_code(frame)));
432 /* The base parameter allows us to adjust for a heap-allocated
433 callstack snapshot */
434 void collect_callstack(F_CONTEXT *stacks)
436 if(collecting_gen == TENURED)
438 CELL top = (CELL)stacks->callstack_top;
439 CELL bottom = (CELL)stacks->callstack_bottom;
441 iterate_callstack(top,bottom,collect_stack_frame);
445 void collect_gc_locals(void)
447 CELL ptr = gc_locals_region->start;
449 for(; ptr <= gc_locals; ptr += CELLS)
450 copy_handle(*(CELL **)ptr);
453 /* Copy roots over at the start of GC, namely various constants, stacks,
454 the user environment and extra roots registered with REGISTER_ROOT */
455 void collect_roots(void)
457 copy_handle(&T);
458 copy_handle(&bignum_zero);
459 copy_handle(&bignum_pos_one);
460 copy_handle(&bignum_neg_one);
462 collect_gc_locals();
463 collect_stack(extra_roots_region,extra_roots);
465 save_stacks();
466 F_CONTEXT *stacks = stack_chain;
468 while(stacks)
470 collect_stack(stacks->datastack_region,stacks->datastack);
471 collect_stack(stacks->retainstack_region,stacks->retainstack);
473 copy_handle(&stacks->catchstack_save);
474 copy_handle(&stacks->current_callback_save);
476 collect_callstack(stacks);
478 stacks = stacks->next;
481 int i;
482 for(i = 0; i < USER_ENV; i++)
483 copy_handle(&userenv[i]);
486 /* Given a pointer to oldspace, copy it to newspace */
487 INLINE void *copy_untagged_object(void *pointer, CELL size)
489 if(newspace->here + size >= newspace->end)
490 longjmp(gc_jmp,1);
491 allot_barrier(newspace->here);
492 void *newpointer = allot_zone(newspace,size);
494 F_GC_STATS *s = &gc_stats[collecting_gen];
495 s->object_count++;
496 s->bytes_copied += size;
498 memcpy(newpointer,pointer,size);
499 return newpointer;
502 INLINE void forward_object(CELL pointer, CELL newpointer)
504 if(pointer != newpointer)
505 put(UNTAG(pointer),RETAG(newpointer,GC_COLLECTED));
508 INLINE CELL copy_object_impl(CELL pointer)
510 CELL newpointer = (CELL)copy_untagged_object(
511 (void*)UNTAG(pointer),
512 object_size(pointer));
513 forward_object(pointer,newpointer);
514 return newpointer;
517 /* Follow a chain of forwarding pointers */
518 CELL resolve_forwarding(CELL untagged, CELL tag)
520 CELL header = get(untagged);
521 /* another forwarding pointer */
522 if(TAG(header) == GC_COLLECTED)
523 return resolve_forwarding(UNTAG(header),tag);
524 /* we've found the destination */
525 else
527 CELL pointer = RETAG(untagged,tag);
528 if(should_copy(untagged))
529 pointer = RETAG(copy_object_impl(pointer),tag);
530 return pointer;
534 /* Given a pointer to a tagged pointer to oldspace, copy it to newspace.
535 If the object has already been copied, return the forwarding
536 pointer address without copying anything; otherwise, install
537 a new forwarding pointer. */
538 INLINE CELL copy_object(CELL pointer)
540 CELL tag = TAG(pointer);
541 CELL header = get(UNTAG(pointer));
543 if(TAG(header) == GC_COLLECTED)
544 return resolve_forwarding(UNTAG(header),tag);
545 else
546 return RETAG(copy_object_impl(pointer),tag);
549 void copy_handle(CELL *handle)
551 CELL pointer = *handle;
553 if(!immediate_p(pointer) && should_copy(pointer))
554 *handle = copy_object(pointer);
557 /* The number of cells from the start of the object which should be scanned by
558 the GC. Some types have a binary payload at the end (string, word, DLL) which
559 we ignore. */
560 CELL binary_payload_start(CELL pointer)
562 F_TUPLE *tuple;
563 F_TUPLE_LAYOUT *layout;
565 switch(untag_header(get(pointer)))
567 /* these objects do not refer to other objects at all */
568 case FLOAT_TYPE:
569 case BYTE_ARRAY_TYPE:
570 case BIGNUM_TYPE:
571 case CALLSTACK_TYPE:
572 return 0;
573 /* these objects have some binary data at the end */
574 case WORD_TYPE:
575 return sizeof(F_WORD) - CELLS * 3;
576 case ALIEN_TYPE:
577 return CELLS * 3;
578 case DLL_TYPE:
579 return CELLS * 2;
580 case QUOTATION_TYPE:
581 return sizeof(F_QUOTATION) - CELLS * 2;
582 case STRING_TYPE:
583 return sizeof(F_STRING);
584 /* everything else consists entirely of pointers */
585 case ARRAY_TYPE:
586 return array_size(array_capacity((F_ARRAY*)pointer));
587 case TUPLE_TYPE:
588 tuple = untag_object(pointer);
589 layout = untag_object(tuple->layout);
590 return tuple_size(layout);
591 case RATIO_TYPE:
592 return sizeof(F_RATIO);
593 case COMPLEX_TYPE:
594 return sizeof(F_COMPLEX);
595 case WRAPPER_TYPE:
596 return sizeof(F_WRAPPER);
597 default:
598 critical_error("Invalid header",pointer);
599 return -1; /* can't happen */
603 void do_code_slots(CELL scan)
605 F_WORD *word;
606 F_QUOTATION *quot;
607 F_CALLSTACK *stack;
609 switch(object_type(scan))
611 case WORD_TYPE:
612 word = (F_WORD *)scan;
613 recursive_mark(compiled_to_block(word->code));
614 if(word->profiling)
615 recursive_mark(compiled_to_block(word->profiling));
616 break;
617 case QUOTATION_TYPE:
618 quot = (F_QUOTATION *)scan;
619 if(quot->compiledp != F)
620 recursive_mark(compiled_to_block(quot->code));
621 break;
622 case CALLSTACK_TYPE:
623 stack = (F_CALLSTACK *)scan;
624 iterate_callstack_object(stack,collect_stack_frame);
625 break;
629 CELL collect_next_nursery(CELL scan)
631 CELL *obj = (CELL *)scan;
632 CELL *end = (CELL *)(scan + binary_payload_start(scan));
634 if(obj != end)
636 obj++;
638 CELL nursery_start = nursery.start;
639 CELL nursery_end = nursery.end;
641 for(; obj < end; obj++)
643 CELL pointer = *obj;
645 if(!immediate_p(pointer)
646 && (pointer >= nursery_start && pointer < nursery_end))
647 *obj = copy_object(pointer);
651 return scan + untagged_object_size(scan);
654 CELL collect_next_aging(CELL scan)
656 CELL *obj = (CELL *)scan;
657 CELL *end = (CELL *)(scan + binary_payload_start(scan));
659 if(obj != end)
661 obj++;
663 CELL tenured_start = data_heap->generations[TENURED].start;
664 CELL tenured_end = data_heap->generations[TENURED].end;
666 CELL newspace_start = newspace->start;
667 CELL newspace_end = newspace->end;
669 for(; obj < end; obj++)
671 CELL pointer = *obj;
673 if(!immediate_p(pointer)
674 && !(pointer >= newspace_start && pointer < newspace_end)
675 && !(pointer >= tenured_start && pointer < tenured_end))
676 *obj = copy_object(pointer);
680 return scan + untagged_object_size(scan);
683 /* This function is performance-critical */
684 CELL collect_next_tenured(CELL scan)
686 CELL *obj = (CELL *)scan;
687 CELL *end = (CELL *)(scan + binary_payload_start(scan));
689 if(obj != end)
691 obj++;
693 CELL newspace_start = newspace->start;
694 CELL newspace_end = newspace->end;
696 for(; obj < end; obj++)
698 CELL pointer = *obj;
700 if(!immediate_p(pointer) && !(pointer >= newspace_start && pointer < newspace_end))
701 *obj = copy_object(pointer);
705 do_code_slots(scan);
707 return scan + untagged_object_size(scan);
710 void collect_next_loop(CELL scan, CELL *end)
712 if(HAVE_NURSERY_P && collecting_gen == NURSERY)
714 while(scan < *end)
715 scan = collect_next_nursery(scan);
717 else if(HAVE_AGING_P && collecting_gen == AGING)
719 while(scan < *end)
720 scan = collect_next_aging(scan);
722 else if(collecting_gen == TENURED)
724 while(scan < *end)
725 scan = collect_next_tenured(scan);
729 INLINE void reset_generation(CELL i)
731 F_ZONE *z = (i == NURSERY ? &nursery : &data_heap->generations[i]);
733 z->here = z->start;
734 if(secure_gc)
735 memset((void*)z->start,69,z->size);
738 /* After garbage collection, any generations which are now empty need to have
739 their allocation pointers and cards reset. */
740 void reset_generations(CELL from, CELL to)
742 CELL i;
743 for(i = from; i <= to; i++)
744 reset_generation(i);
746 clear_cards(from,to);
747 clear_decks(from,to);
748 clear_allot_markers(from,to);
751 /* Prepare to start copying reachable objects into an unused zone */
752 void begin_gc(CELL requested_bytes)
754 if(growing_data_heap)
756 if(collecting_gen != TENURED)
757 critical_error("Invalid parameters to begin_gc",0);
759 old_data_heap = data_heap;
760 set_data_heap(grow_data_heap(old_data_heap,requested_bytes));
761 newspace = &data_heap->generations[TENURED];
763 else if(collecting_accumulation_gen_p())
765 /* when collecting one of these generations, rotate it
766 with the semispace */
767 F_ZONE z = data_heap->generations[collecting_gen];
768 data_heap->generations[collecting_gen] = data_heap->semispaces[collecting_gen];
769 data_heap->semispaces[collecting_gen] = z;
770 reset_generation(collecting_gen);
771 newspace = &data_heap->generations[collecting_gen];
772 clear_cards(collecting_gen,collecting_gen);
773 clear_decks(collecting_gen,collecting_gen);
774 clear_allot_markers(collecting_gen,collecting_gen);
776 else
778 /* when collecting a younger generation, we copy
779 reachable objects to the next oldest generation,
780 so we set the newspace so the next generation. */
781 newspace = &data_heap->generations[collecting_gen + 1];
785 void end_gc(CELL gc_elapsed)
787 F_GC_STATS *s = &gc_stats[collecting_gen];
789 s->collections++;
790 s->gc_time += gc_elapsed;
791 if(s->max_gc_time < gc_elapsed)
792 s->max_gc_time = gc_elapsed;
794 if(growing_data_heap)
796 dealloc_data_heap(old_data_heap);
797 old_data_heap = NULL;
798 growing_data_heap = false;
801 if(collecting_accumulation_gen_p())
803 /* all younger generations except are now empty.
804 if collecting_gen == NURSERY here, we only have 1 generation;
805 old-school Cheney collector */
806 if(collecting_gen != NURSERY)
807 reset_generations(NURSERY,collecting_gen - 1);
809 else if(HAVE_NURSERY_P && collecting_gen == NURSERY)
811 nursery.here = nursery.start;
813 else
815 /* all generations up to and including the one
816 collected are now empty */
817 reset_generations(NURSERY,collecting_gen);
820 if(collecting_gen == TENURED)
822 /* now that all reachable code blocks have been marked,
823 deallocate the rest */
824 free_unmarked(&code_heap);
827 collecting_aging_again = false;
830 /* Collect gen and all younger generations.
831 If growing_data_heap_ is true, we must grow the data heap to such a size that
832 an allocation of requested_bytes won't fail */
833 void garbage_collection(CELL gen,
834 bool growing_data_heap_,
835 CELL requested_bytes)
837 if(gc_off)
839 critical_error("GC disabled",gen);
840 return;
843 s64 start = current_micros();
845 performing_gc = true;
846 growing_data_heap = growing_data_heap_;
847 collecting_gen = gen;
849 /* we come back here if a generation is full */
850 if(setjmp(gc_jmp))
852 /* We have no older generations we can try collecting, so we
853 resort to growing the data heap */
854 if(collecting_gen == TENURED)
856 growing_data_heap = true;
858 /* see the comment in unmark_marked() */
859 unmark_marked(&code_heap);
861 /* we try collecting AGING space twice before going on to
862 collect TENURED */
863 else if(HAVE_AGING_P
864 && collecting_gen == AGING
865 && !collecting_aging_again)
867 collecting_aging_again = true;
869 /* Collect the next oldest generation */
870 else
872 collecting_gen++;
876 begin_gc(requested_bytes);
878 /* initialize chase pointer */
879 CELL scan = newspace->here;
881 /* collect objects referenced from stacks and environment */
882 collect_roots();
883 /* collect objects referenced from older generations */
884 collect_cards();
886 /* don't scan code heap unless it has pointers to this
887 generation or younger */
888 if(collecting_gen >= last_code_heap_scan)
890 if(collecting_gen != TENURED)
893 /* if we are doing code GC, then we will copy over
894 literals from any code block which gets marked as live.
895 if we are not doing code GC, just consider all literals
896 as roots. */
897 code_heap_scans++;
899 collect_literals();
902 if(collecting_accumulation_gen_p())
903 last_code_heap_scan = collecting_gen;
904 else
905 last_code_heap_scan = collecting_gen + 1;
908 collect_next_loop(scan,&newspace->here);
910 CELL gc_elapsed = (current_micros() - start);
912 end_gc(gc_elapsed);
914 performing_gc = false;
917 void gc(void)
919 garbage_collection(TENURED,false,0);
922 void minor_gc(void)
924 garbage_collection(NURSERY,false,0);
927 void primitive_gc(void)
929 gc();
932 void primitive_gc_stats(void)
934 GROWABLE_ARRAY(stats);
936 CELL i;
937 u64 total_gc_time = 0;
939 for(i = 0; i < MAX_GEN_COUNT; i++)
941 F_GC_STATS *s = &gc_stats[i];
942 GROWABLE_ARRAY_ADD(stats,allot_cell(s->collections));
943 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->gc_time)));
944 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->max_gc_time)));
945 GROWABLE_ARRAY_ADD(stats,allot_cell(s->collections == 0 ? 0 : s->gc_time / s->collections));
946 GROWABLE_ARRAY_ADD(stats,allot_cell(s->object_count));
947 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->bytes_copied)));
949 total_gc_time += s->gc_time;
952 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(total_gc_time)));
953 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(cards_scanned)));
954 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(decks_scanned)));
955 GROWABLE_ARRAY_ADD(stats,allot_cell(code_heap_scans));
957 GROWABLE_ARRAY_TRIM(stats);
958 dpush(stats);
961 void primitive_gc_reset(void)
963 gc_reset();
966 void primitive_become(void)
968 F_ARRAY *new_objects = untag_array(dpop());
969 F_ARRAY *old_objects = untag_array(dpop());
971 CELL capacity = array_capacity(new_objects);
972 if(capacity != array_capacity(old_objects))
973 critical_error("bad parameters to become",0);
975 CELL i;
977 for(i = 0; i < capacity; i++)
979 CELL old_obj = array_nth(old_objects,i);
980 CELL new_obj = array_nth(new_objects,i);
982 forward_object(old_obj,new_obj);
985 gc();
987 compile_all_words();
990 CELL find_all_words(void)
992 GROWABLE_ARRAY(words);
994 begin_scan();
996 CELL obj;
997 while((obj = next_object()) != F)
999 if(type_of(obj) == WORD_TYPE)
1000 GROWABLE_ARRAY_ADD(words,obj);
1003 /* End heap scan */
1004 gc_off = false;
1006 GROWABLE_ARRAY_TRIM(words);
1008 return words;