Big code GC refactoring
[factor/jcg.git] / vm / data_gc.c
blob90d1c7625f0f43cb1c947fc6749af1da976d03d6
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 copy_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 copy_reachable_objects(card_scan,&card_end);
309 cards_scanned++;
312 void copy_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 copy_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 copy_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 copy_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 copy_gen_cards",gen);
394 return;
397 F_DECK *ptr;
399 for(ptr = first_deck; ptr < last_deck; ptr++)
401 if(*ptr & mask)
403 copy_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 copy_cards(void)
413 int i;
414 for(i = collecting_gen + 1; i < data_heap->gen_count; i++)
415 copy_gen_cards(i);
418 /* Copy all tagged pointers in a range of memory */
419 void copy_stack_elements(F_SEGMENT *region, CELL top)
421 CELL ptr = region->start;
423 for(; ptr <= top; ptr += CELLS)
424 copy_handle((CELL*)ptr);
427 void copy_stack_frame_step(F_STACK_FRAME *frame)
429 mark_code_block(frame_code(frame));
432 void copy_callstack_roots(F_CONTEXT *stacks)
434 if(collecting_gen == TENURED)
436 CELL top = (CELL)stacks->callstack_top;
437 CELL bottom = (CELL)stacks->callstack_bottom;
439 iterate_callstack(top,bottom,copy_stack_frame_step);
443 void copy_registered_locals(void)
445 CELL ptr = gc_locals_region->start;
447 for(; ptr <= gc_locals; ptr += CELLS)
448 copy_handle(*(CELL **)ptr);
451 /* Copy roots over at the start of GC, namely various constants, stacks,
452 the user environment and extra roots registered with REGISTER_ROOT */
453 void copy_roots(void)
455 copy_handle(&T);
456 copy_handle(&bignum_zero);
457 copy_handle(&bignum_pos_one);
458 copy_handle(&bignum_neg_one);
460 copy_registered_locals();
461 copy_stack_elements(extra_roots_region,extra_roots);
463 save_stacks();
464 F_CONTEXT *stacks = stack_chain;
466 while(stacks)
468 copy_stack_elements(stacks->datastack_region,stacks->datastack);
469 copy_stack_elements(stacks->retainstack_region,stacks->retainstack);
471 copy_handle(&stacks->catchstack_save);
472 copy_handle(&stacks->current_callback_save);
474 copy_callstack_roots(stacks);
476 stacks = stacks->next;
479 int i;
480 for(i = 0; i < USER_ENV; i++)
481 copy_handle(&userenv[i]);
484 /* Given a pointer to oldspace, copy it to newspace */
485 INLINE void *copy_untagged_object(void *pointer, CELL size)
487 if(newspace->here + size >= newspace->end)
488 longjmp(gc_jmp,1);
489 allot_barrier(newspace->here);
490 void *newpointer = allot_zone(newspace,size);
492 F_GC_STATS *s = &gc_stats[collecting_gen];
493 s->object_count++;
494 s->bytes_copied += size;
496 memcpy(newpointer,pointer,size);
497 return newpointer;
500 INLINE void forward_object(CELL pointer, CELL newpointer)
502 if(pointer != newpointer)
503 put(UNTAG(pointer),RETAG(newpointer,GC_COLLECTED));
506 INLINE CELL copy_object_impl(CELL pointer)
508 CELL newpointer = (CELL)copy_untagged_object(
509 (void*)UNTAG(pointer),
510 object_size(pointer));
511 forward_object(pointer,newpointer);
512 return newpointer;
515 /* Follow a chain of forwarding pointers */
516 CELL resolve_forwarding(CELL untagged, CELL tag)
518 CELL header = get(untagged);
519 /* another forwarding pointer */
520 if(TAG(header) == GC_COLLECTED)
521 return resolve_forwarding(UNTAG(header),tag);
522 /* we've found the destination */
523 else
525 CELL pointer = RETAG(untagged,tag);
526 if(should_copy(untagged))
527 pointer = RETAG(copy_object_impl(pointer),tag);
528 return pointer;
532 /* Given a pointer to a tagged pointer to oldspace, copy it to newspace.
533 If the object has already been copied, return the forwarding
534 pointer address without copying anything; otherwise, install
535 a new forwarding pointer. */
536 INLINE CELL copy_object(CELL pointer)
538 CELL tag = TAG(pointer);
539 CELL header = get(UNTAG(pointer));
541 if(TAG(header) == GC_COLLECTED)
542 return resolve_forwarding(UNTAG(header),tag);
543 else
544 return RETAG(copy_object_impl(pointer),tag);
547 void copy_handle(CELL *handle)
549 CELL pointer = *handle;
551 if(!immediate_p(pointer) && should_copy(pointer))
552 *handle = copy_object(pointer);
555 /* The number of cells from the start of the object which should be scanned by
556 the GC. Some types have a binary payload at the end (string, word, DLL) which
557 we ignore. */
558 CELL binary_payload_start(CELL pointer)
560 F_TUPLE *tuple;
561 F_TUPLE_LAYOUT *layout;
563 switch(untag_header(get(pointer)))
565 /* these objects do not refer to other objects at all */
566 case FLOAT_TYPE:
567 case BYTE_ARRAY_TYPE:
568 case BIGNUM_TYPE:
569 case CALLSTACK_TYPE:
570 return 0;
571 /* these objects have some binary data at the end */
572 case WORD_TYPE:
573 return sizeof(F_WORD) - CELLS * 3;
574 case ALIEN_TYPE:
575 return CELLS * 3;
576 case DLL_TYPE:
577 return CELLS * 2;
578 case QUOTATION_TYPE:
579 return sizeof(F_QUOTATION) - CELLS * 2;
580 case STRING_TYPE:
581 return sizeof(F_STRING);
582 /* everything else consists entirely of pointers */
583 case ARRAY_TYPE:
584 return array_size(array_capacity((F_ARRAY*)pointer));
585 case TUPLE_TYPE:
586 tuple = untag_object(pointer);
587 layout = untag_object(tuple->layout);
588 return tuple_size(layout);
589 case RATIO_TYPE:
590 return sizeof(F_RATIO);
591 case COMPLEX_TYPE:
592 return sizeof(F_COMPLEX);
593 case WRAPPER_TYPE:
594 return sizeof(F_WRAPPER);
595 default:
596 critical_error("Invalid header",pointer);
597 return -1; /* can't happen */
601 void do_code_slots(CELL scan)
603 F_WORD *word;
604 F_QUOTATION *quot;
605 F_CALLSTACK *stack;
607 switch(object_type(scan))
609 case WORD_TYPE:
610 word = (F_WORD *)scan;
611 mark_code_block(word->code);
612 if(word->profiling)
613 mark_code_block(word->profiling);
614 break;
615 case QUOTATION_TYPE:
616 quot = (F_QUOTATION *)scan;
617 if(quot->compiledp != F)
618 mark_code_block(quot->code);
619 break;
620 case CALLSTACK_TYPE:
621 stack = (F_CALLSTACK *)scan;
622 iterate_callstack_object(stack,copy_stack_frame_step);
623 break;
627 CELL copy_next_from_nursery(CELL scan)
629 CELL *obj = (CELL *)scan;
630 CELL *end = (CELL *)(scan + binary_payload_start(scan));
632 if(obj != end)
634 obj++;
636 CELL nursery_start = nursery.start;
637 CELL nursery_end = nursery.end;
639 for(; obj < end; obj++)
641 CELL pointer = *obj;
643 if(!immediate_p(pointer)
644 && (pointer >= nursery_start && pointer < nursery_end))
645 *obj = copy_object(pointer);
649 return scan + untagged_object_size(scan);
652 CELL copy_next_from_aging(CELL scan)
654 CELL *obj = (CELL *)scan;
655 CELL *end = (CELL *)(scan + binary_payload_start(scan));
657 if(obj != end)
659 obj++;
661 CELL tenured_start = data_heap->generations[TENURED].start;
662 CELL tenured_end = data_heap->generations[TENURED].end;
664 CELL newspace_start = newspace->start;
665 CELL newspace_end = newspace->end;
667 for(; obj < end; obj++)
669 CELL pointer = *obj;
671 if(!immediate_p(pointer)
672 && !(pointer >= newspace_start && pointer < newspace_end)
673 && !(pointer >= tenured_start && pointer < tenured_end))
674 *obj = copy_object(pointer);
678 return scan + untagged_object_size(scan);
681 CELL copy_next_from_tenured(CELL scan)
683 CELL *obj = (CELL *)scan;
684 CELL *end = (CELL *)(scan + binary_payload_start(scan));
686 if(obj != end)
688 obj++;
690 CELL newspace_start = newspace->start;
691 CELL newspace_end = newspace->end;
693 for(; obj < end; obj++)
695 CELL pointer = *obj;
697 if(!immediate_p(pointer) && !(pointer >= newspace_start && pointer < newspace_end))
698 *obj = copy_object(pointer);
702 do_code_slots(scan);
704 return scan + untagged_object_size(scan);
707 void copy_reachable_objects(CELL scan, CELL *end)
709 if(HAVE_NURSERY_P && collecting_gen == NURSERY)
711 while(scan < *end)
712 scan = copy_next_from_nursery(scan);
714 else if(HAVE_AGING_P && collecting_gen == AGING)
716 while(scan < *end)
717 scan = copy_next_from_aging(scan);
719 else if(collecting_gen == TENURED)
721 while(scan < *end)
722 scan = copy_next_from_tenured(scan);
726 INLINE void reset_generation(CELL i)
728 F_ZONE *z = (i == NURSERY ? &nursery : &data_heap->generations[i]);
730 z->here = z->start;
731 if(secure_gc)
732 memset((void*)z->start,69,z->size);
735 /* After garbage collection, any generations which are now empty need to have
736 their allocation pointers and cards reset. */
737 void reset_generations(CELL from, CELL to)
739 CELL i;
740 for(i = from; i <= to; i++)
741 reset_generation(i);
743 clear_cards(from,to);
744 clear_decks(from,to);
745 clear_allot_markers(from,to);
748 /* Prepare to start copying reachable objects into an unused zone */
749 void begin_gc(CELL requested_bytes)
751 if(growing_data_heap)
753 if(collecting_gen != TENURED)
754 critical_error("Invalid parameters to begin_gc",0);
756 old_data_heap = data_heap;
757 set_data_heap(grow_data_heap(old_data_heap,requested_bytes));
758 newspace = &data_heap->generations[TENURED];
760 else if(collecting_accumulation_gen_p())
762 /* when collecting one of these generations, rotate it
763 with the semispace */
764 F_ZONE z = data_heap->generations[collecting_gen];
765 data_heap->generations[collecting_gen] = data_heap->semispaces[collecting_gen];
766 data_heap->semispaces[collecting_gen] = z;
767 reset_generation(collecting_gen);
768 newspace = &data_heap->generations[collecting_gen];
769 clear_cards(collecting_gen,collecting_gen);
770 clear_decks(collecting_gen,collecting_gen);
771 clear_allot_markers(collecting_gen,collecting_gen);
773 else
775 /* when collecting a younger generation, we copy
776 reachable objects to the next oldest generation,
777 so we set the newspace so the next generation. */
778 newspace = &data_heap->generations[collecting_gen + 1];
782 void end_gc(CELL gc_elapsed)
784 F_GC_STATS *s = &gc_stats[collecting_gen];
786 s->collections++;
787 s->gc_time += gc_elapsed;
788 if(s->max_gc_time < gc_elapsed)
789 s->max_gc_time = gc_elapsed;
791 if(growing_data_heap)
793 dealloc_data_heap(old_data_heap);
794 old_data_heap = NULL;
795 growing_data_heap = false;
798 if(collecting_accumulation_gen_p())
800 /* all younger generations except are now empty.
801 if collecting_gen == NURSERY here, we only have 1 generation;
802 old-school Cheney collector */
803 if(collecting_gen != NURSERY)
804 reset_generations(NURSERY,collecting_gen - 1);
806 else if(HAVE_NURSERY_P && collecting_gen == NURSERY)
808 nursery.here = nursery.start;
810 else
812 /* all generations up to and including the one
813 collected are now empty */
814 reset_generations(NURSERY,collecting_gen);
817 if(collecting_gen == TENURED)
819 /* now that all reachable code blocks have been marked,
820 deallocate the rest */
821 free_unmarked(&code_heap);
824 collecting_aging_again = false;
827 /* Collect gen and all younger generations.
828 If growing_data_heap_ is true, we must grow the data heap to such a size that
829 an allocation of requested_bytes won't fail */
830 void garbage_collection(CELL gen,
831 bool growing_data_heap_,
832 CELL requested_bytes)
834 if(gc_off)
836 critical_error("GC disabled",gen);
837 return;
840 s64 start = current_micros();
842 performing_gc = true;
843 growing_data_heap = growing_data_heap_;
844 collecting_gen = gen;
846 /* we come back here if a generation is full */
847 if(setjmp(gc_jmp))
849 /* We have no older generations we can try collecting, so we
850 resort to growing the data heap */
851 if(collecting_gen == TENURED)
853 growing_data_heap = true;
855 /* see the comment in unmark_marked() */
856 unmark_marked(&code_heap);
858 /* we try collecting AGING space twice before going on to
859 collect TENURED */
860 else if(HAVE_AGING_P
861 && collecting_gen == AGING
862 && !collecting_aging_again)
864 collecting_aging_again = true;
866 /* Collect the next oldest generation */
867 else
869 collecting_gen++;
873 begin_gc(requested_bytes);
875 /* initialize chase pointer */
876 CELL scan = newspace->here;
878 /* collect objects referenced from stacks and environment */
879 copy_roots();
880 /* collect objects referenced from older generations */
881 copy_cards();
882 /* do some tracing */
883 copy_reachable_objects(scan,&newspace->here);
885 /* don't scan code heap unless it has pointers to this
886 generation or younger */
887 if(collecting_gen >= last_code_heap_scan)
889 code_heap_scans++;
891 if(collecting_gen == TENURED)
892 update_code_heap_roots();
893 else
894 copy_code_heap_roots();
896 if(collecting_accumulation_gen_p())
897 last_code_heap_scan = collecting_gen;
898 else
899 last_code_heap_scan = collecting_gen + 1;
902 CELL gc_elapsed = (current_micros() - start);
904 end_gc(gc_elapsed);
906 performing_gc = false;
909 void gc(void)
911 garbage_collection(TENURED,false,0);
914 void minor_gc(void)
916 garbage_collection(NURSERY,false,0);
919 void primitive_gc(void)
921 gc();
924 void primitive_gc_stats(void)
926 GROWABLE_ARRAY(stats);
928 CELL i;
929 u64 total_gc_time = 0;
931 for(i = 0; i < MAX_GEN_COUNT; i++)
933 F_GC_STATS *s = &gc_stats[i];
934 GROWABLE_ARRAY_ADD(stats,allot_cell(s->collections));
935 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->gc_time)));
936 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->max_gc_time)));
937 GROWABLE_ARRAY_ADD(stats,allot_cell(s->collections == 0 ? 0 : s->gc_time / s->collections));
938 GROWABLE_ARRAY_ADD(stats,allot_cell(s->object_count));
939 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->bytes_copied)));
941 total_gc_time += s->gc_time;
944 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(total_gc_time)));
945 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(cards_scanned)));
946 GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(decks_scanned)));
947 GROWABLE_ARRAY_ADD(stats,allot_cell(code_heap_scans));
949 GROWABLE_ARRAY_TRIM(stats);
950 dpush(stats);
953 void primitive_gc_reset(void)
955 gc_reset();
958 void primitive_become(void)
960 F_ARRAY *new_objects = untag_array(dpop());
961 F_ARRAY *old_objects = untag_array(dpop());
963 CELL capacity = array_capacity(new_objects);
964 if(capacity != array_capacity(old_objects))
965 critical_error("bad parameters to become",0);
967 CELL i;
969 for(i = 0; i < capacity; i++)
971 CELL old_obj = array_nth(old_objects,i);
972 CELL new_obj = array_nth(new_objects,i);
974 forward_object(old_obj,new_obj);
977 gc();
979 compile_all_words();
982 CELL find_all_words(void)
984 GROWABLE_ARRAY(words);
986 begin_scan();
988 CELL obj;
989 while((obj = next_object()) != F)
991 if(type_of(obj) == WORD_TYPE)
992 GROWABLE_ARRAY_ADD(words,obj);
995 /* End heap scan */
996 gc_off = false;
998 GROWABLE_ARRAY_TRIM(words);
1000 return words;