3 CELL
init_zone(F_ZONE
*z
, CELL size
, CELL start
)
6 z
->start
= z
->here
= start
;
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
,
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
;
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
;
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
);
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
,
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
);
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
];
136 clear_cards(NURSERY
,TENURED
);
137 clear_decks(NURSERY
,TENURED
);
138 clear_allot_markers(NURSERY
,TENURED
);
144 for(i
= 0; i
< MAX_GEN_COUNT
; i
++)
145 memset(&gc_stats
[i
],0,sizeof(F_GC_STATS
));
152 void init_data_heap(CELL gens
,
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_
;
171 /* Size of the object pointed to by a tagged pointer */
172 CELL
object_size(CELL tagged
)
174 if(immediate_p(tagged
))
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
)
190 F_TUPLE_LAYOUT
*layout
;
192 switch(untag_header(get(pointer
)))
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
));
201 return string_size(string_capacity((F_STRING
*)pointer
));
203 tuple
= untag_object(pointer
);
204 layout
= untag_object(tuple
->layout
);
205 return tuple_size(layout
);
207 return sizeof(F_QUOTATION
);
209 return sizeof(F_WORD
);
211 return sizeof(F_RATIO
);
213 return sizeof(F_FLOAT
);
215 return sizeof(F_COMPLEX
);
217 return sizeof(F_DLL
);
219 return sizeof(F_ALIEN
);
221 return sizeof(F_WRAPPER
);
223 return callstack_size(
224 untag_fixnum_fast(((F_CALLSTACK
*)pointer
)->length
));
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
);
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
;
262 void primitive_begin_scan(void)
268 CELL
next_object(void)
271 general_error(ERROR_HEAP_SCAN
,F
,F
,NULL
);
273 CELL value
= get(heap_scan_ptr
);
274 CELL obj
= heap_scan_ptr
;
277 if(heap_scan_ptr
>= data_heap
->generations
[TENURED
].here
)
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());
293 void primitive_end_scan(void)
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);
307 copy_reachable_objects(card_scan
,&card_end
);
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
;
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
;
329 for(card
= 0; card
< 4; card
++)
333 copy_card(&ptr
[card
],gen
,here
);
334 ptr
[card
] &= ~unmask
;
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
);
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
361 unmask
= CARD_POINTS_TO_NURSERY
;
362 /* after the collection, all cards in aging space can be
364 else if(HAVE_AGING_P
&& gen
== AGING
)
365 unmask
= CARD_MARK_MASK
;
368 critical_error("bug in copy_gen_cards",gen
);
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
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. */
387 mask
= CARD_POINTS_TO_AGING
;
388 unmask
= CARD_POINTS_TO_NURSERY
;
393 critical_error("bug in copy_gen_cards",gen
);
399 for(ptr
= first_deck
; ptr
< last_deck
; ptr
++)
403 copy_card_deck(ptr
,gen
,mask
,unmask
);
409 /* Scan cards in all generations older than the one being collected, copying
410 old->new references */
411 void copy_cards(void)
414 for(i
= collecting_gen
+ 1; i
< data_heap
->gen_count
; 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)
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
);
464 F_CONTEXT
*stacks
= stack_chain
;
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
;
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
)
489 allot_barrier(newspace
->here
);
490 void *newpointer
= allot_zone(newspace
,size
);
492 F_GC_STATS
*s
= &gc_stats
[collecting_gen
];
494 s
->bytes_copied
+= size
;
496 memcpy(newpointer
,pointer
,size
);
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
);
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 */
525 CELL pointer
= RETAG(untagged
,tag
);
526 if(should_copy(untagged
))
527 pointer
= RETAG(copy_object_impl(pointer
),tag
);
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
);
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
558 CELL
binary_payload_start(CELL pointer
)
561 F_TUPLE_LAYOUT
*layout
;
563 switch(untag_header(get(pointer
)))
565 /* these objects do not refer to other objects at all */
567 case BYTE_ARRAY_TYPE
:
571 /* these objects have some binary data at the end */
573 return sizeof(F_WORD
) - CELLS
* 3;
579 return sizeof(F_QUOTATION
) - CELLS
* 2;
581 return sizeof(F_STRING
);
582 /* everything else consists entirely of pointers */
584 return array_size(array_capacity((F_ARRAY
*)pointer
));
586 tuple
= untag_object(pointer
);
587 layout
= untag_object(tuple
->layout
);
588 return tuple_size(layout
);
590 return sizeof(F_RATIO
);
592 return sizeof(F_COMPLEX
);
594 return sizeof(F_WRAPPER
);
596 critical_error("Invalid header",pointer
);
597 return -1; /* can't happen */
601 void do_code_slots(CELL scan
)
607 switch(object_type(scan
))
610 word
= (F_WORD
*)scan
;
611 mark_code_block(word
->code
);
613 mark_code_block(word
->profiling
);
616 quot
= (F_QUOTATION
*)scan
;
617 if(quot
->compiledp
!= F
)
618 mark_code_block(quot
->code
);
621 stack
= (F_CALLSTACK
*)scan
;
622 iterate_callstack_object(stack
,copy_stack_frame_step
);
627 CELL
copy_next_from_nursery(CELL scan
)
629 CELL
*obj
= (CELL
*)scan
;
630 CELL
*end
= (CELL
*)(scan
+ binary_payload_start(scan
));
636 CELL nursery_start
= nursery
.start
;
637 CELL nursery_end
= nursery
.end
;
639 for(; obj
< end
; 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
));
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
++)
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
));
690 CELL newspace_start
= newspace
->start
;
691 CELL newspace_end
= newspace
->end
;
693 for(; obj
< end
; obj
++)
697 if(!immediate_p(pointer
) && !(pointer
>= newspace_start
&& pointer
< newspace_end
))
698 *obj
= copy_object(pointer
);
704 return scan
+ untagged_object_size(scan
);
707 void copy_reachable_objects(CELL scan
, CELL
*end
)
709 if(HAVE_NURSERY_P
&& collecting_gen
== NURSERY
)
712 scan
= copy_next_from_nursery(scan
);
714 else if(HAVE_AGING_P
&& collecting_gen
== AGING
)
717 scan
= copy_next_from_aging(scan
);
719 else if(collecting_gen
== TENURED
)
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
]);
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
)
740 for(i
= from
; i
<= to
; 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
);
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
];
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
;
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
)
836 critical_error("GC disabled",gen
);
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 */
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
861 && collecting_gen
== AGING
862 && !collecting_aging_again
)
864 collecting_aging_again
= true;
866 /* Collect the next oldest generation */
873 begin_gc(requested_bytes
);
875 /* initialize chase pointer */
876 CELL scan
= newspace
->here
;
878 /* collect objects referenced from stacks and environment */
880 /* collect objects referenced from older generations */
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
)
891 if(collecting_gen
== TENURED
)
892 update_code_heap_roots();
894 copy_code_heap_roots();
896 if(collecting_accumulation_gen_p())
897 last_code_heap_scan
= collecting_gen
;
899 last_code_heap_scan
= collecting_gen
+ 1;
902 CELL gc_elapsed
= (current_micros() - start
);
906 performing_gc
= false;
911 garbage_collection(TENURED
,false,0);
916 garbage_collection(NURSERY
,false,0);
919 void primitive_gc(void)
924 void primitive_gc_stats(void)
926 GROWABLE_ARRAY(stats
);
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
);
953 void primitive_gc_reset(void)
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);
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
);
982 CELL
find_all_words(void)
984 GROWABLE_ARRAY(words
);
989 while((obj
= next_object()) != F
)
991 if(type_of(obj
) == WORD_TYPE
)
992 GROWABLE_ARRAY_ADD(words
,obj
);
998 GROWABLE_ARRAY_TRIM(words
);