2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/gc/dod.c - Dead object destruction of the various headers
11 This file implements I<dead object destruction>. This is documented in
12 PDD 9 with supplementary notes in F<docs/dev/dod.pod> and
13 F<docs/memory_internals.pod>.
15 It's possible to turn on/off the checking of the system stack and
16 processor registers. The actual checking is set up in F<src/cpu_dep.c>
17 and is performed in the function C<trace_memory_block> here.
19 There's also a verbose mode for garbage collection.
30 #include "parrot/parrot.h"
31 #include "parrot/dod.h"
33 /* HEADERIZER HFILE: include/parrot/dod.h */
35 /* HEADERIZER BEGIN: static */
36 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
38 static void clear_live_bits(ARGIN(const Small_Object_Pool
*pool
))
39 __attribute__nonnull__(1);
42 static size_t find_common_mask(PARROT_INTERP
, size_t val1
, size_t val2
)
43 __attribute__nonnull__(1);
45 static void mark_special(PARROT_INTERP
, ARGIN(PMC
*obj
))
46 __attribute__nonnull__(1)
47 __attribute__nonnull__(2);
49 static int sweep_cb(PARROT_INTERP
,
50 ARGMOD(Small_Object_Pool
*pool
),
53 __attribute__nonnull__(1)
54 __attribute__nonnull__(2)
55 __attribute__nonnull__(4)
59 static int trace_active_PMCs(PARROT_INTERP
, int trace_stack
)
60 __attribute__nonnull__(1);
62 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
63 /* HEADERIZER END: static */
66 /* Set this to 1 to see if unanchored objects are found in system areas.
67 * Please note: these objects might be bogus
71 #if ! DISABLE_GC_DEBUG
72 /* Set when walking the system stack */
73 int CONSERVATIVE_POINTER_CHASING
= 0;
78 =item C<static void mark_special>
80 Marks the children of a special PMC. Handles the marking necessary
81 for shared PMCs, and ensures timely marking of high-priority PMCs.
82 Ensures PMC_EXT structures are properly organized for garbage
90 mark_special(PARROT_INTERP
, ARGIN(PMC
*obj
))
96 * If the object is shared, we have to use the arena and dod
97 * pointers of the originating interpreter.
99 * We are possibly changing another interpreter's data here, so
100 * the mark phase of DOD must run only on one interpreter of a pool
101 * at a time. However, freeing unused objects can occur in parallel.
102 * And: to be sure that a shared object is dead, we have to finish
103 * the mark phase of all interpreters in a pool that might reference
106 if (PObj_is_PMC_shared_TEST(obj
)) {
107 interp
= PMC_sync(obj
)->owner
;
108 PARROT_ASSERT(interp
);
110 if (!interp
->arena_base
->dod_mark_ptr
)
111 interp
->arena_base
->dod_mark_ptr
= obj
;
114 arena_base
= interp
->arena_base
;
116 if (PObj_needs_early_DOD_TEST(obj
))
117 ++arena_base
->num_early_PMCs_seen
;
119 if (PObj_high_priority_DOD_TEST(obj
) && arena_base
->dod_trace_ptr
) {
120 /* set obj's parent to high priority */
121 PObj_high_priority_DOD_SET(arena_base
->dod_trace_ptr
);
128 PMC
* const tptr
= arena_base
->dod_trace_ptr
;
130 ++arena_base
->num_extended_PMCs
;
132 * XXX this basically invalidates the high-priority marking
133 * of PMCs by putting all PMCs onto the front of the list.
134 * The reason for this is the by far better cache locality
135 * when aggregates and their contents are marked "together".
137 * To enable high priority marking again we should probably
138 * use a second pointer chain, which is, when not empty,
141 if (hi_prio
&& tptr
) {
142 if (PMC_next_for_GC(tptr
) == tptr
) {
143 PMC_next_for_GC(obj
) = obj
;
146 /* put it at the head of the list */
147 PMC_next_for_GC(obj
) = PMC_next_for_GC(tptr
);
150 PMC_next_for_GC(tptr
) = (PMC
*)obj
;
153 /* put it on the end of the list */
154 PMC_next_for_GC(arena_base
->dod_mark_ptr
) = obj
;
156 /* Explicitly make the tail of the linked list be
157 * self-referential */
158 arena_base
->dod_mark_ptr
= PMC_next_for_GC(obj
) = obj
;
161 else if (PObj_custom_mark_TEST(obj
)) {
162 PObj_get_FLAGS(obj
) |= PObj_custom_GC_FLAG
;
163 VTABLE_mark(interp
, obj
);
169 =item C<void pobject_lives>
171 Marks the PObj as "alive" for the Garbage Collector. Takes a pointer to a
172 PObj, and performs necessary marking to ensure the PMC and it's direct
173 children nodes are marked alive. Implementation is generally dependant on
174 the particular garbage collector in use.
182 pobject_lives(PARROT_INTERP
, ARGMOD(PObj
*obj
))
187 if (!PObj_live_TEST(obj
) && \
188 PObj_to_GMSH(obj
)->gen
->gen_no
>= interp
->gc_generation
) \
189 parrot_gc_gms_pobject_lives(interp
, obj
); \
191 #else /* not PARROT_GC_GMS */
193 /* if object is live or on free list return */
194 if (PObj_is_live_or_free_TESTALL(obj
))
197 # if ! DISABLE_GC_DEBUG
199 if (CONSERVATIVE_POINTER_CHASING
)
200 fprintf(stderr
, "GC Warning! Unanchored %s %p found in system areas \n",
201 PObj_is_PMC_TEST(obj
) ? "PMC" : "Buffer", obj
);
208 /* if object is a PMC and its real_self pointer points to another
209 * PMC, we must mark that. */
210 if (PObj_is_PMC_TEST(obj
)) {
211 PMC
* const p
= (PMC
*)obj
;
213 if (p
->real_self
!= p
)
214 pobject_lives(interp
, (PObj
*)p
->real_self
);
216 /* if object is a PMC and contains buffers or PMCs, then attach the PMC
217 * to the chained mark list. */
218 if (PObj_is_special_PMC_TEST(obj
))
219 mark_special(interp
, p
);
222 else if (p
->pmc_ext
&& PMC_metadata(p
))
223 fprintf(stderr
, "GC: error obj %p (%s) has properties\n",
224 (void *)p
, (char*)p
->vtable
->whoami
->strstart
);
228 /* buffer GC_DEBUG stuff */
229 if (GC_DEBUG(interp
) && PObj_report_TEST(obj
))
230 fprintf(stderr
, "GC: buffer %p pointing to %p marked live\n",
231 obj
, PObj_bufstart((Buffer
*)obj
));
233 #endif /* PARROT_GC_GMS */
238 =item C<int Parrot_dod_trace_root>
240 Traces the root set. Returns 0 if it's a lazy DOD run and all objects
241 that need timely destruction were found.
243 C<trace_stack> can have these values:
245 0 ... trace normal roots, no system areas
246 1 ... trace whole root set
247 2 ... trace system areas only
254 Parrot_dod_trace_root(PARROT_INTERP
, int trace_stack
)
256 Arenas
* const arena_base
= interp
->arena_base
;
257 parrot_context_t
*ctx
;
259 /* note: adding locals here did cause increased DOD runs */
262 if (trace_stack
== 2) {
263 trace_system_areas(interp
);
268 Parrot_dod_profile_start(interp
);
270 /* We have to start somewhere; the interpreter globals is a good place */
271 if (!arena_base
->dod_mark_start
) {
272 arena_base
->dod_mark_start
273 = arena_base
->dod_mark_ptr
277 /* mark it as used */
278 pobject_lives(interp
, (PObj
*)interp
->iglobals
);
280 /* mark the current context. */
281 ctx
= CONTEXT(interp
);
282 mark_context(interp
, ctx
);
284 /* mark the dynamic environment. */
285 mark_stack(interp
, interp
->dynamic_env
);
290 * XXX these PMCs are constant and shouldn't get collected
291 * but t/library/dumper* fails w/o this marking.
293 * It seems that the Class PMC gets DODed - these should
294 * get created as constant PMCs.
296 mark_vtables(interp
);
298 /* mark the root_namespace */
299 pobject_lives(interp
, (PObj
*)interp
->root_namespace
);
301 /* mark the concurrency scheduler */
302 if (interp
->scheduler
)
303 pobject_lives(interp
, (PObj
*)interp
->scheduler
);
306 mark_const_subs(interp
);
308 /* mark caches and freelists */
309 mark_object_cache(interp
);
311 /* Now mark the class hash */
312 pobject_lives(interp
, (PObj
*)interp
->class_hash
);
314 /* Mark the registry */
315 PARROT_ASSERT(interp
->DOD_registry
);
316 pobject_lives(interp
, (PObj
*)interp
->DOD_registry
);
318 /* Mark the transaction log */
319 /* XXX do this more generically? */
320 if (interp
->thread_data
&& interp
->thread_data
->stm_log
)
321 Parrot_STM_mark_transaction(interp
);
323 /* Walk the iodata */
324 Parrot_IOData_mark(interp
, interp
->piodata
);
326 /* quick check if we can already bail out */
327 if (arena_base
->lazy_dod
&& arena_base
->num_early_PMCs_seen
>=
328 arena_base
->num_early_DOD_PMCs
)
331 /* Find important stuff on the system stack */
333 trace_system_areas(interp
);
336 Parrot_dod_profile_end(interp
, PARROT_PROF_DOD_p1
);
344 =item C<static int trace_active_PMCs>
346 Performs a full trace run and marks all the PMCs as active if they
347 are. Returns whether the run completed, that is, whether it's safe
355 trace_active_PMCs(PARROT_INTERP
, int trace_stack
)
357 if (!Parrot_dod_trace_root(interp
, trace_stack
))
360 /* Okay, we've marked the whole root set, and should have a good-sized
361 * list of things to look at. Run through it */
362 return Parrot_dod_trace_children(interp
, (size_t) -1);
367 =item C<int Parrot_dod_trace_children>
369 Returns whether the tracing process has completed.
376 Parrot_dod_trace_children(PARROT_INTERP
, size_t how_many
)
378 Arenas
* const arena_base
= interp
->arena_base
;
379 const int lazy_dod
= arena_base
->lazy_dod
;
380 PMC
*current
= arena_base
->dod_mark_start
;
382 const UINTVAL mask
= PObj_data_is_PMC_array_FLAG
| PObj_custom_mark_FLAG
;
385 * First phase of mark is finished. Now if we are the owner
386 * of a shared pool, we must run the mark phase of other
387 * interpreters in our pool, so that live shared PMCs in that
388 * interpreter are appended to our mark_ptrs chain.
390 * If there is a count of shared PMCs and we have already seen
391 * all these, we could skip that.
394 Parrot_dod_profile_start(interp
);
396 pt_DOD_mark_root_finished(interp
);
399 const UINTVAL bits
= PObj_get_FLAGS(current
) & mask
;
402 if (lazy_dod
&& arena_base
->num_early_PMCs_seen
>=
403 arena_base
->num_early_DOD_PMCs
) {
407 arena_base
->dod_trace_ptr
= current
;
409 /* short-term hack to color objects black */
410 PObj_get_FLAGS(current
) |= PObj_custom_GC_FLAG
;
412 /* clearing the flag is much more expensive then testing */
413 if (!PObj_needs_early_DOD_TEST(current
))
414 PObj_high_priority_DOD_CLEAR(current
);
416 /* mark properties */
417 if (PMC_metadata(current
))
418 pobject_lives(interp
, (PObj
*)PMC_metadata(current
));
420 /* Start by checking if there's anything at all. This assumes that the
421 * largest percentage of PMCs won't have anything in their data
422 * pointer that we need to trace. */
424 if (bits
== PObj_data_is_PMC_array_FLAG
)
425 Parrot_dod_trace_pmc_data(interp
, current
);
427 /* All that's left is the custom */
428 PARROT_ASSERT(!PObj_on_free_list_TEST(current
));
429 VTABLE_mark(interp
, current
);
433 next
= PMC_next_for_GC(current
);
435 if (!PMC_IS_NULL(next
) && next
== current
)
439 } while (--how_many
> 0);
441 arena_base
->dod_mark_start
= current
;
442 arena_base
->dod_trace_ptr
= NULL
;
445 Parrot_dod_profile_end(interp
, PARROT_PROF_DOD_p2
);
452 =item C<void Parrot_dod_trace_pmc_data>
454 If the PMC is an array of PMCs, trace all elements in the array as children.
455 Touches each object in the array to mark it as being alive. To determine
456 whether a PMC is an array to be marked in this way, it is tested for the
457 C<PObj_data_is_PMC_array_FLAG> flag.
464 Parrot_dod_trace_pmc_data(PARROT_INTERP
, ARGIN(PMC
*p
))
466 /* malloced array of PMCs */
467 PMC
** const data
= PMC_data_typed(p
, PMC
**);
472 for (i
= PMC_int_val(p
) - 1; i
>= 0; --i
)
474 pobject_lives(interp
, (PObj
*)data
[i
]);
482 =item C<void clear_cow>
484 Clears the COW ref count.
491 clear_cow(PARROT_INTERP
, ARGMOD(Small_Object_Pool
*pool
), int cleanup
)
493 const UINTVAL object_size
= pool
->object_size
;
494 Small_Object_Arena
*cur_arena
;
496 /* clear refcount for COWable objects. */
497 for (cur_arena
= pool
->last_Arena
;
498 NULL
!= cur_arena
; cur_arena
= cur_arena
->prev
) {
500 Buffer
*b
= cur_arena
->start_objects
;
502 for (i
= 0; i
< cur_arena
->used
; i
++) {
503 if (!PObj_on_free_list_TEST(b
)) {
505 /* clear COWed external FLAG */
506 PObj_external_CLEAR(b
);
508 /* if cleanup (Parrot_destroy) constants are dead too */
509 PObj_constant_CLEAR(b
);
513 if (PObj_COW_TEST(b
) && PObj_bufstart(b
) &&
514 !PObj_external_TEST(b
)) {
515 INTVAL
* const refcount
= PObj_bufrefcountptr(b
);
520 b
= (Buffer
*)((char *)b
+ object_size
);
527 =item C<void used_cow>
529 Finds other users of COW's C<bufstart>.
536 used_cow(PARROT_INTERP
, ARGMOD(Small_Object_Pool
*pool
), int cleanup
)
538 const UINTVAL object_size
= pool
->object_size
;
539 Small_Object_Arena
*cur_arena
;
541 for (cur_arena
= pool
->last_Arena
;
542 NULL
!= cur_arena
; cur_arena
= cur_arena
->prev
) {
543 const Buffer
*b
= cur_arena
->start_objects
;
546 for (i
= 0; i
< cur_arena
->used
; i
++) {
547 if (!PObj_on_free_list_TEST(b
) &&
550 !PObj_external_TEST(b
)) {
552 INTVAL
* const refcount
= PObj_bufrefcountptr(b
);
554 /* mark users of this bufstart by incrementing refcount */
555 if (PObj_live_TEST(b
))
556 *refcount
= 1 << 29; /* ~infinite usage */
558 (*refcount
)++; /* dead usage */
561 b
= (Buffer
*)((char *)b
+ object_size
);
565 #endif /* GC_IS_MALLOC */
569 =item C<void Parrot_dod_sweep>
571 Puts any buffers/PMCs that are now unused onto the pool's free list. If
572 C<GC_IS_MALLOC>, bufstart gets freed too, if possible. Avoids buffers that
573 are immune from collection (i.e. constant).
580 Parrot_dod_sweep(PARROT_INTERP
, ARGMOD(Small_Object_Pool
*pool
))
582 UINTVAL total_used
= 0;
583 const UINTVAL object_size
= pool
->object_size
;
585 Small_Object_Arena
*cur_arena
;
586 dod_object_fn_type dod_object
= pool
->dod_object
;
589 if (Interp_trace_TEST(interp
, 1)) {
590 Interp
* const tracer
= interp
->debugger
;
591 PMC
*pio
= PIO_STDERR(interp
);
593 PIO_flush(interp
, pio
);
596 pio
= PIO_STDERR(tracer
);
597 PIO_flush(tracer
, pio
);
602 /* Run through all the buffer header pools and mark */
603 for (cur_arena
= pool
->last_Arena
; cur_arena
; cur_arena
= cur_arena
->prev
) {
604 Buffer
*b
= (Buffer
*)cur_arena
->start_objects
;
607 /* loop only while there are objects in the arena */
608 for (i
= cur_arena
->total_objects
; i
; i
--) {
610 if (PObj_on_free_list_TEST(b
))
611 ; /* if it's on free list, do nothing */
612 else if (PObj_live_TEST(b
)) {
615 PObj_get_FLAGS(b
) &= ~PObj_custom_GC_FLAG
;
618 /* it must be dead */
621 if (Interp_trace_TEST(interp
, 1)) {
622 fprintf(stderr
, "Freeing pobject %p\n", b
);
623 if (PObj_is_PMC_TEST(b
)) {
624 fprintf(stderr
, "\t = PMC type %s\n",
625 (char*) ((PMC
*)b
)->vtable
->whoami
->strstart
);
630 if (PObj_is_shared_TEST(b
)) {
631 /* only mess with shared objects if we
632 * (and thus everyone) is suspended for
634 * XXX wrong thing to do with "other" GCs
636 if (!(interp
->thread_data
&&
637 (interp
->thread_data
->state
&
638 THREAD_STATE_SUSPENDED_GC
))) {
644 dod_object(interp
, pool
, b
);
646 pool
->add_free_object(interp
, pool
, b
);
649 b
= (Buffer
*)((char *)b
+ object_size
);
653 pool
->num_free_objects
= pool
->total_objects
- total_used
;
658 =item C<void Parrot_dod_free_pmc>
660 Frees a PMC that is no longer being used. Calls a custom C<destroy>
661 VTABLE method if one is available. If the PMC uses a PMC_EXT
662 structure, that is freed as well.
669 Parrot_dod_free_pmc(PARROT_INTERP
, SHIM(Small_Object_Pool
*pool
),
672 PMC
* const pmc
= (PMC
*)p
;
673 Arenas
* const arena_base
= interp
->arena_base
;
675 /* TODO collect objects with finalizers */
676 if (PObj_needs_early_DOD_TEST(p
))
677 --arena_base
->num_early_DOD_PMCs
;
679 if (PObj_active_destroy_TEST(p
))
680 VTABLE_destroy(interp
, pmc
);
682 if (PObj_is_PMC_EXT_TEST(p
))
683 Parrot_free_pmc_ext(interp
, pmc
);
687 pmc
->pmc_ext
= (PMC_EXT
*)0xdeadbeef;
688 pmc
->vtable
= (VTABLE
*)0xdeadbeef;
689 PMC_pmc_val(pmc
) = (PMC
*)0xdeadbeef;
697 =item C<void Parrot_free_pmc_ext>
699 Frees the C<PMC_EXT> structure attached to a PMC, if it exists.
706 Parrot_free_pmc_ext(PARROT_INTERP
, ARGMOD(PMC
*p
))
708 /* if the PMC has a PMC_EXT structure, return it to the pool/arena */
709 Arenas
* const arena_base
= interp
->arena_base
;
710 Small_Object_Pool
* const ext_pool
= arena_base
->pmc_ext_pool
;
712 if (PObj_is_PMC_shared_TEST(p
) && PMC_sync(p
)) {
713 MUTEX_DESTROY(PMC_sync(p
)->pmc_lock
);
714 mem_internal_free(PMC_sync(p
));
719 ext_pool
->add_free_object(interp
, ext_pool
, p
->pmc_ext
);
721 ext_pool
->num_free_objects
++;
728 =item C<void Parrot_dod_free_sysmem>
730 If the PMC uses memory allocated directly from the system, this function
738 Parrot_dod_free_sysmem(SHIM_INTERP
, SHIM(Small_Object_Pool
*pool
),
741 /* has sysmem allocated, e.g. string_pin */
742 if (PObj_sysmem_TEST(b
) && PObj_bufstart(b
))
743 mem_sys_free(PObj_bufstart(b
));
745 PObj_bufstart(b
) = NULL
;
751 =item C<void Parrot_dod_free_buffer_malloc>
753 Frees the given buffer, returning the storage space to the operating system
754 and removing it from Parrot's memory management system. If the buffer is COW,
755 The buffer is not freed if the reference count is greater then 1.
762 Parrot_dod_free_buffer_malloc(SHIM_INTERP
, SHIM(Small_Object_Pool
*pool
),
766 /* free allocated space at (int *)bufstart - 1, but not if it used COW or is
770 if (!PObj_bufstart(b
) || PObj_is_external_or_free_TESTALL(b
))
773 if (PObj_COW_TEST(b
)) {
774 INTVAL
* const refcount
= PObj_bufrefcountptr(b
);
776 if (--(*refcount
) == 0) {
777 mem_sys_free(refcount
); /* the actual bufstart */
781 mem_sys_free(PObj_bufrefcountptr(b
));
786 =item C<void Parrot_dod_free_buffer>
788 Frees a buffer, returning it to the memory pool for Parrot to possibly
796 Parrot_dod_free_buffer(SHIM_INTERP
, ARGMOD(Small_Object_Pool
*pool
), ARGMOD(PObj
*b
))
798 Memory_Pool
* const mem_pool
= (Memory_Pool
*)pool
->mem_pool
;
800 /* XXX Jarkko reported that on irix pool->mem_pool was NULL, which really
801 * shouldn't happen */
803 if (!PObj_COW_TEST(b
))
804 mem_pool
->guaranteed_reclaimable
+= PObj_buflen(b
);
806 mem_pool
->possibly_reclaimable
+= PObj_buflen(b
);
812 #ifndef PLATFORM_STACK_WALK
816 =item C<static size_t find_common_mask>
818 Finds a mask covering the longest common bit-prefix of C<val1>
825 PARROT_CONST_FUNCTION
827 find_common_mask(PARROT_INTERP
, size_t val1
, size_t val2
)
830 const int bound
= sizeof (size_t) * 8;
832 /* Shifting a value by its size (in bits) or larger is undefined behaviour.
833 So need an explicit check to return 0 if there is no prefix, rather than
834 attempting to rely on (say) 0xFFFFFFFF << 32 being 0. */
835 for (i
= 0; i
< bound
; i
++) {
837 return ~(size_t)0 << i
;
844 PARROT_ASSERT(i
== bound
);
848 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INTERP_ERROR
,
849 "Unexpected condition in find_common_mask()!\n");
854 =item C<void trace_mem_block>
856 Traces the memory block between C<lo_var_ptr> and C<hi_var_ptr>.
857 Attempt to find pointers to PObjs or buffers, and mark them as "alive"
858 if found. See src/cpu_dep.c for more information about tracing memory
866 trace_mem_block(PARROT_INTERP
, size_t lo_var_ptr
, size_t hi_var_ptr
)
869 ptrdiff_t cur_var_ptr
;
871 const size_t buffer_min
= get_min_buffer_address(interp
);
872 const size_t buffer_max
= get_max_buffer_address(interp
);
873 const size_t pmc_min
= get_min_pmc_address(interp
);
874 const size_t pmc_max
= get_max_pmc_address(interp
);
877 find_common_mask(interp
,
878 buffer_min
< pmc_min
? buffer_min
: pmc_min
,
879 buffer_max
> pmc_max
? buffer_max
: pmc_max
);
881 if (!lo_var_ptr
|| !hi_var_ptr
)
884 if (lo_var_ptr
< hi_var_ptr
) {
885 const size_t tmp_ptr
= hi_var_ptr
;
886 hi_var_ptr
= lo_var_ptr
;
887 lo_var_ptr
= tmp_ptr
;
890 /* Get the expected prefix */
891 prefix
= mask
& buffer_min
;
893 for (cur_var_ptr
= hi_var_ptr
;
894 (ptrdiff_t)cur_var_ptr
< (ptrdiff_t)lo_var_ptr
;
895 cur_var_ptr
= (size_t)((ptrdiff_t)cur_var_ptr
+ sizeof (void *))) {
896 const size_t ptr
= *(size_t *)cur_var_ptr
;
898 /* Do a quick approximate range check by bit-masking */
899 if ((ptr
& mask
) == prefix
|| !prefix
) {
900 /* Note that what we find via the stack or registers are not
901 * guaranteed to be live pmcs/buffers, and could very well have
902 * had their bufstart/vtable destroyed due to the linked list of
904 if (pmc_min
<= ptr
&& ptr
< pmc_max
&&
905 is_pmc_ptr(interp
, (void *)ptr
)) {
906 /* ...so ensure that pobject_lives checks PObj_on_free_list_FLAG
907 * before adding it to the next_for_GC list, to have
908 * vtable->mark() called. */
909 pobject_lives(interp
, (PObj
*)ptr
);
911 else if (buffer_min
<= ptr
&& ptr
< buffer_max
&&
912 is_buffer_ptr(interp
, (void *)ptr
)) {
913 /* ...and since pobject_lives doesn't care about bufstart, it
914 * doesn't really matter if it sets a flag */
915 pobject_lives(interp
, (PObj
*)ptr
);
926 =item C<static void clear_live_bits>
928 Runs through all PMC arenas and clear live bits. This is used to reset
929 the GC system after a full system sweep.
936 clear_live_bits(ARGIN(const Small_Object_Pool
*pool
))
938 Small_Object_Arena
*arena
;
939 const UINTVAL object_size
= pool
->object_size
;
941 for (arena
= pool
->last_Arena
; arena
; arena
= arena
->prev
) {
942 Buffer
*b
= (Buffer
*)arena
->start_objects
;
945 for (i
= 0; i
< arena
->used
; i
++) {
947 b
= (Buffer
*)((char *)b
+ object_size
);
955 =item C<void Parrot_dod_clear_live_bits>
957 Resets the PMC pool, so all objects are marked as "White". This
958 is done after a GC run to reset the system and prepare for the
966 Parrot_dod_clear_live_bits(PARROT_INTERP
)
968 Small_Object_Pool
* const pool
= interp
->arena_base
->pmc_pool
;
969 clear_live_bits(pool
);
974 =item C<void Parrot_dod_profile_start>
976 Records the start time of a DOD run when profiling is enabled.
983 Parrot_dod_profile_start(PARROT_INTERP
)
985 if (Interp_flags_TEST(interp
, PARROT_PROFILE_FLAG
))
986 interp
->profile
->dod_time
= Parrot_floatval_time();
991 =item C<void Parrot_dod_profile_end>
993 Records the end time of the DOD part C<what> run when profiling is
994 enabled. Also record start time of next part.
1001 Parrot_dod_profile_end(PARROT_INTERP
, int what
)
1003 if (Interp_flags_TEST(interp
, PARROT_PROFILE_FLAG
)) {
1004 RunProfile
* const profile
= interp
->profile
;
1005 const FLOATVAL now
= Parrot_floatval_time();
1007 profile
->data
[what
].numcalls
++;
1008 profile
->data
[what
].time
+= now
- profile
->dod_time
;
1011 * we've recorded the time of a DOD/GC piece from
1012 * dod_time until now, so add this to the start of the
1013 * currently executing opcode, which hasn't run this
1016 profile
->starttime
+= now
- profile
->dod_time
;
1018 /* prepare start for next step */
1019 profile
->dod_time
= now
;
1025 =item C<void Parrot_dod_ms_run_init>
1027 Prepares the collector for a mark & sweep DOD run. This is the
1028 initializer function for the MS garbage collector.
1035 Parrot_dod_ms_run_init(PARROT_INTERP
)
1037 Arenas
* const arena_base
= interp
->arena_base
;
1039 arena_base
->dod_trace_ptr
= NULL
;
1040 arena_base
->dod_mark_start
= NULL
;
1041 arena_base
->num_early_PMCs_seen
= 0;
1042 arena_base
->num_extended_PMCs
= 0;
1047 =item C<static int sweep_cb>
1049 Sweeps the given pool for the MS collector. This function also ends
1050 the profiling timer, if profiling is enabled. Returns the total number
1058 sweep_cb(PARROT_INTERP
, ARGMOD(Small_Object_Pool
*pool
), int flag
,
1061 int * const total_free
= (int *) arg
;
1064 if (flag
& POOL_BUFFER
)
1065 used_cow(interp
, pool
, 0);
1068 Parrot_dod_sweep(interp
, pool
);
1071 if (flag
& POOL_BUFFER
)
1072 clear_cow(interp
, pool
, 0);
1075 if (interp
->profile
&& (flag
& POOL_PMC
))
1076 Parrot_dod_profile_end(interp
, PARROT_PROF_DOD_cp
);
1078 *total_free
+= pool
->num_free_objects
;
1085 =item C<void Parrot_dod_ms_run>
1087 Runs the stop-the-world mark & sweep (MS) collector.
1094 Parrot_dod_ms_run(PARROT_INTERP
, int flags
)
1096 Arenas
* const arena_base
= interp
->arena_base
;
1098 /* XXX these should go into the interpreter */
1101 if (arena_base
->DOD_block_level
)
1104 if (interp
->debugger
) {
1106 * if the other interpreter did a DOD run, it can set
1107 * live bits of shared objects, but these aren't reset, because
1108 * they are in a different arena. When now such a PMC points to
1109 * other non-shared object, these wouldn't be marked and hence
1112 Parrot_dod_clear_live_bits(interp
);
1116 * the sync sweep is always at the end, so that
1117 * the live bits are cleared
1119 if (flags
& GC_finish_FLAG
) {
1120 clear_live_bits(interp
->arena_base
->pmc_pool
);
1121 clear_live_bits(interp
->arena_base
->constant_pmc_pool
);
1123 Parrot_dod_sweep(interp
, interp
->arena_base
->pmc_pool
);
1124 Parrot_dod_sweep(interp
, interp
->arena_base
->constant_pmc_pool
);
1129 ++arena_base
->DOD_block_level
;
1130 arena_base
->lazy_dod
= flags
& GC_lazy_FLAG
;
1132 /* tell the threading system that we're doing DOD mark */
1133 pt_DOD_start_mark(interp
);
1134 Parrot_dod_ms_run_init(interp
);
1136 /* compact STRING pools to collect free headers and allocated buffers */
1137 Parrot_go_collect(interp
);
1139 /* Now go trace the PMCs */
1140 if (trace_active_PMCs(interp
, flags
& GC_trace_stack_FLAG
)) {
1143 arena_base
->dod_trace_ptr
= NULL
;
1144 arena_base
->dod_mark_ptr
= NULL
;
1146 /* mark is now finished */
1147 pt_DOD_stop_mark(interp
);
1149 /* Now put unused PMCs and Buffers on the free list */
1150 ignored
= Parrot_forall_header_pools(interp
, POOL_BUFFER
| POOL_PMC
,
1151 (void*)&total_free
, sweep_cb
);
1154 if (interp
->profile
)
1155 Parrot_dod_profile_end(interp
, PARROT_PROF_DOD_cb
);
1158 pt_DOD_stop_mark(interp
); /* XXX */
1160 /* successful lazy DOD count */
1161 ++arena_base
->lazy_dod_runs
;
1163 Parrot_dod_clear_live_bits(interp
);
1164 if (interp
->profile
)
1165 Parrot_dod_profile_end(interp
, PARROT_PROF_DOD_p2
);
1169 arena_base
->dod_runs
++;
1170 --arena_base
->DOD_block_level
;
1178 =item C<void Parrot_do_dod_run>
1180 Calls the configured garbage collector to find and reclaim unused
1188 Parrot_do_dod_run(PARROT_INTERP
, UINTVAL flags
)
1190 interp
->arena_base
->do_gc_mark(interp
, flags
);
1191 parrot_gc_context(interp
);
1200 F<include/parrot/dod.h>, F<src/cpu_dep.c>, F<docs/dev/dod.dev> and
1201 F<docs/pdds/pdd09_gc.pod>.
1205 Initial version by Mike Lambert on 2002.05.27.
1213 * c-file-style: "parrot"
1215 * vim: expandtab shiftwidth=4: