3 * Simple generational GC.
5 * Copyright 2011 Novell, Inc (http://www.novell.com)
6 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
7 * Copyright 2001-2003 Ximian, Inc
8 * Copyright 2003-2010 Novell, Inc.
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #if defined (HAVE_SGEN_GC) && !defined (DISABLE_SGEN_GC_BRIDGE)
18 #include "sgen/sgen-gc.h"
19 #include "sgen-bridge-internals.h"
20 #include "sgen/sgen-hash-table.h"
21 #include "sgen/sgen-qsort.h"
22 #include "sgen/sgen-client.h"
23 #include "utils/mono-logger-internals.h"
46 * Bridge data for a single managed object
48 * FIXME: Optimizations:
50 * Don't allocate a srcs array for just one source. Most objects have
51 * just one source, so use the srcs pointer itself.
53 typedef struct _HashEntry
{
54 GCObject
*obj
; /* This is a duplicate - it's already stored in the hash table */
61 // "Source" managed objects pointing at this destination
64 // Index in sccs array of SCC this object was folded into
71 } HashEntryWithAccounting
;
73 // The graph of managed objects/HashEntries is reduced to a graph of strongly connected components
78 // How many bridged objects does this SCC hold references to?
79 int num_bridge_entries
;
81 // Index in global sccs array of SCCs holding pointers to this SCC
82 DynIntArray xrefs
; /* these are incoming, not outgoing */
85 // Maps managed objects to corresponding HashEntry stricts
86 static SgenHashTable hash_table
= SGEN_HASH_TABLE_INIT (INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE
, INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE_ENTRY
, sizeof (HashEntry
), mono_aligned_addr_hash
, NULL
);
88 static int current_time
;
90 static gboolean bridge_accounting_enabled
= FALSE
;
92 static SgenBridgeProcessor
*bridge_processor
;
100 dyn_array_init (DynArray
*da
)
108 dyn_array_uninit (DynArray
*da
, int elem_size
)
110 if (da
->capacity
<= 0)
113 sgen_free_internal_dynamic (da
->data
, elem_size
* da
->capacity
, INTERNAL_MEM_BRIDGE_DATA
);
118 dyn_array_ensure_capacity (DynArray
*da
, int capacity
, int elem_size
)
120 int old_capacity
= da
->capacity
;
123 if (capacity
<= old_capacity
)
126 if (da
->capacity
== 0)
128 while (capacity
> da
->capacity
)
131 new_data
= (char *)sgen_alloc_internal_dynamic (elem_size
* da
->capacity
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
132 memcpy (new_data
, da
->data
, elem_size
* da
->size
);
133 sgen_free_internal_dynamic (da
->data
, elem_size
* old_capacity
, INTERNAL_MEM_BRIDGE_DATA
);
138 dyn_array_add (DynArray
*da
, int elem_size
)
142 dyn_array_ensure_capacity (da
, da
->size
+ 1, elem_size
);
144 p
= da
->data
+ da
->size
* elem_size
;
151 dyn_array_int_init (DynIntArray
*da
)
153 dyn_array_init (&da
->array
);
157 dyn_array_int_uninit (DynIntArray
*da
)
159 dyn_array_uninit (&da
->array
, sizeof (int));
163 dyn_array_int_size (DynIntArray
*da
)
165 return da
->array
.size
;
169 dyn_array_int_set_size (DynIntArray
*da
, int size
)
171 da
->array
.size
= size
;
175 dyn_array_int_add (DynIntArray
*da
, int x
)
177 int *p
= (int *)dyn_array_add (&da
->array
, sizeof (int));
182 dyn_array_int_get (DynIntArray
*da
, int x
)
184 return ((int*)da
->array
.data
)[x
];
188 dyn_array_int_set (DynIntArray
*da
, int idx
, int val
)
190 ((int*)da
->array
.data
)[idx
] = val
;
194 dyn_array_int_ensure_capacity (DynIntArray
*da
, int capacity
)
196 dyn_array_ensure_capacity (&da
->array
, capacity
, sizeof (int));
200 dyn_array_int_set_all (DynIntArray
*dst
, DynIntArray
*src
)
202 dyn_array_int_ensure_capacity (dst
, src
->array
.size
);
203 memcpy (dst
->array
.data
, src
->array
.data
, src
->array
.size
* sizeof (int));
204 dst
->array
.size
= src
->array
.size
;
210 dyn_array_ptr_init (DynPtrArray
*da
)
212 dyn_array_init (&da
->array
);
216 dyn_array_ptr_uninit (DynPtrArray
*da
)
218 dyn_array_uninit (&da
->array
, sizeof (void*));
222 dyn_array_ptr_size (DynPtrArray
*da
)
224 return da
->array
.size
;
228 dyn_array_ptr_set_size (DynPtrArray
*da
, int size
)
230 da
->array
.size
= size
;
234 dyn_array_ptr_get (DynPtrArray
*da
, int x
)
236 return ((void**)da
->array
.data
)[x
];
240 dyn_array_ptr_add (DynPtrArray
*da
, void *ptr
)
242 void **p
= (void **)dyn_array_add (&da
->array
, sizeof (void*));
246 #define dyn_array_ptr_push dyn_array_ptr_add
249 dyn_array_ptr_pop (DynPtrArray
*da
)
252 int size
= da
->array
.size
;
254 p
= dyn_array_ptr_get (da
, size
- 1);
262 dyn_array_scc_init (DynSCCArray
*da
)
264 dyn_array_init (&da
->array
);
268 dyn_array_scc_uninit (DynSCCArray
*da
)
270 dyn_array_uninit (&da
->array
, sizeof (SCC
));
274 dyn_array_scc_size (DynSCCArray
*da
)
276 return da
->array
.size
;
280 dyn_array_scc_add (DynSCCArray
*da
)
282 return (SCC
*)dyn_array_add (&da
->array
, sizeof (SCC
));
286 dyn_array_scc_get_ptr (DynSCCArray
*da
, int x
)
288 return &((SCC
*)da
->array
.data
)[x
];
293 static DynIntArray merge_array
;
296 dyn_array_int_contains (DynIntArray
*da
, int x
)
299 for (i
= 0; i
< dyn_array_int_size (da
); ++i
)
300 if (dyn_array_int_get (da
, i
) == x
)
307 dyn_array_int_merge (DynIntArray
*dst
, DynIntArray
*src
)
311 dyn_array_int_ensure_capacity (&merge_array
, dyn_array_int_size (dst
) + dyn_array_int_size (src
));
312 dyn_array_int_set_size (&merge_array
, 0);
314 for (i
= j
= 0; i
< dyn_array_int_size (dst
) || j
< dyn_array_int_size (src
); ) {
315 if (i
< dyn_array_int_size (dst
) && j
< dyn_array_int_size (src
)) {
316 int a
= dyn_array_int_get (dst
, i
);
317 int b
= dyn_array_int_get (src
, j
);
319 dyn_array_int_add (&merge_array
, a
);
322 dyn_array_int_add (&merge_array
, a
);
326 dyn_array_int_add (&merge_array
, b
);
329 } else if (i
< dyn_array_int_size (dst
)) {
330 dyn_array_int_add (&merge_array
, dyn_array_int_get (dst
, i
));
333 dyn_array_int_add (&merge_array
, dyn_array_int_get (src
, j
));
338 if (dyn_array_int_size (&merge_array
) > dyn_array_int_size (dst
)) {
339 dyn_array_int_set_all (dst
, &merge_array
);
344 dyn_array_int_merge_one (DynIntArray
*array
, int value
)
348 int size
= dyn_array_int_size (array
);
350 for (i
= 0; i
< size
; ++i
) {
351 if (dyn_array_int_get (array
, i
) == value
)
353 else if (dyn_array_int_get (array
, i
) > value
)
357 dyn_array_int_ensure_capacity (array
, size
+ 1);
360 tmp
= dyn_array_int_get (array
, i
);
361 for (; i
< size
; ++i
) {
362 dyn_array_int_set (array
, i
, value
);
364 tmp
= dyn_array_int_get (array
, i
+ 1);
366 dyn_array_int_set (array
, size
, value
);
368 dyn_array_int_set (array
, size
, value
);
371 dyn_array_int_set_size (array
, size
+ 1);
376 set_config (const SgenBridgeProcessorConfig
*config
)
378 if (config
->accounting
) {
379 SgenHashTable table
= SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE
, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY
, sizeof (HashEntryWithAccounting
), mono_aligned_addr_hash
, NULL
);
380 bridge_accounting_enabled
= TRUE
;
385 static MonoGCBridgeObjectKind
386 class_kind (MonoClass
*klass
)
388 return mono_bridge_callbacks
.bridge_class_kind (klass
);
392 get_hash_entry (GCObject
*obj
, gboolean
*existing
)
394 HashEntry
*entry
= (HashEntry
*)sgen_hash_table_lookup (&hash_table
, obj
);
405 memset (&new_entry
, 0, sizeof (HashEntry
));
408 dyn_array_ptr_init (&new_entry
.srcs
);
409 new_entry
.finishing_time
= -1;
410 new_entry
.scc_index
= -1;
412 sgen_hash_table_replace (&hash_table
, obj
, &new_entry
, NULL
);
414 return (HashEntry
*)sgen_hash_table_lookup (&hash_table
, obj
);
418 add_source (HashEntry
*entry
, HashEntry
*src
)
420 dyn_array_ptr_add (&entry
->srcs
, src
);
426 GCObject
*obj G_GNUC_UNUSED
;
431 SGEN_HASH_TABLE_FOREACH (&hash_table
, GCObject
*, obj
, HashEntry
*, entry
) {
432 int entry_size
= dyn_array_ptr_size (&entry
->srcs
);
433 total_srcs
+= entry_size
;
434 if (entry_size
> max_srcs
)
435 max_srcs
= entry_size
;
436 dyn_array_ptr_uninit (&entry
->srcs
);
437 } SGEN_HASH_TABLE_FOREACH_END
;
439 sgen_hash_table_clean (&hash_table
);
441 dyn_array_int_uninit (&merge_array
);
442 //g_print ("total srcs %d - max %d\n", total_srcs, max_srcs);
446 register_bridge_object (GCObject
*obj
)
448 HashEntry
*entry
= get_hash_entry (obj
, NULL
);
449 entry
->is_bridge
= TRUE
;
454 register_finishing_time (HashEntry
*entry
, int t
)
456 g_assert (entry
->finishing_time
< 0);
457 entry
->finishing_time
= t
;
461 object_is_live (GCObject
**objp
)
463 GCObject
*obj
= *objp
;
464 GCObject
*fwd
= SGEN_OBJECT_IS_FORWARDED (obj
);
467 return sgen_hash_table_lookup (&hash_table
, fwd
) == NULL
;
469 if (!sgen_object_is_live (obj
))
471 return sgen_hash_table_lookup (&hash_table
, obj
) == NULL
;
474 static DynPtrArray registered_bridges
;
475 static DynPtrArray dfs_stack
;
477 static int dfs1_passes
, dfs2_passes
;
481 #define HANDLE_PTR(ptr,obj) do { \
482 GCObject *dst = (GCObject*)*(ptr); \
483 if (dst && !object_is_live (&dst)) { \
484 dyn_array_ptr_push (&dfs_stack, obj_entry); \
485 dyn_array_ptr_push (&dfs_stack, get_hash_entry (dst, NULL)); \
490 dfs1 (HashEntry
*obj_entry
)
493 g_assert (dyn_array_ptr_size (&dfs_stack
) == 0);
495 dyn_array_ptr_push (&dfs_stack
, NULL
);
496 dyn_array_ptr_push (&dfs_stack
, obj_entry
);
502 obj_entry
= (HashEntry
*)dyn_array_ptr_pop (&dfs_stack
);
506 src
= (HashEntry
*)dyn_array_ptr_pop (&dfs_stack
);
508 obj
= obj_entry
->obj
;
509 desc
= sgen_obj_get_descriptor_safe (obj
);
512 //g_print ("link %s -> %s\n", sgen_safe_name (src->obj), sgen_safe_name (obj));
513 add_source (obj_entry
, src
);
515 //g_print ("starting with %s\n", sgen_safe_name (obj));
518 if (obj_entry
->is_visited
)
521 obj_entry
->is_visited
= TRUE
;
523 dyn_array_ptr_push (&dfs_stack
, obj_entry
);
524 /* NULL marks that the next entry is to be finished */
525 dyn_array_ptr_push (&dfs_stack
, NULL
);
528 #include "sgen/sgen-scan-object.h"
530 obj_entry
= (HashEntry
*)dyn_array_ptr_pop (&dfs_stack
);
532 //g_print ("finish %s\n", sgen_safe_name (obj_entry->obj));
533 register_finishing_time (obj_entry
, current_time
++);
535 } while (dyn_array_ptr_size (&dfs_stack
) > 0);
539 scc_add_xref (SCC
*src
, SCC
*dst
)
541 g_assert (src
!= dst
);
542 g_assert (src
->index
!= dst
->index
);
544 if (dyn_array_int_contains (&dst
->xrefs
, src
->index
))
546 if (src
->num_bridge_entries
) {
547 dyn_array_int_merge_one (&dst
->xrefs
, src
->index
);
550 dyn_array_int_merge (&dst
->xrefs
, &src
->xrefs
);
551 for (i
= 0; i
< dyn_array_int_size (&dst
->xrefs
); ++i
)
552 g_assert (dyn_array_int_get (&dst
->xrefs
, i
) != dst
->index
);
557 scc_add_entry (SCC
*scc
, HashEntry
*entry
)
559 g_assert (entry
->scc_index
< 0);
560 entry
->scc_index
= scc
->index
;
561 if (entry
->is_bridge
)
562 ++scc
->num_bridge_entries
;
565 static DynSCCArray sccs
;
566 static SCC
*current_scc
;
569 dfs2 (HashEntry
*entry
)
573 g_assert (dyn_array_ptr_size (&dfs_stack
) == 0);
575 dyn_array_ptr_push (&dfs_stack
, entry
);
578 entry
= (HashEntry
*)dyn_array_ptr_pop (&dfs_stack
);
581 if (entry
->scc_index
>= 0) {
582 if (entry
->scc_index
!= current_scc
->index
)
583 scc_add_xref (dyn_array_scc_get_ptr (&sccs
, entry
->scc_index
), current_scc
);
587 scc_add_entry (current_scc
, entry
);
589 for (i
= 0; i
< dyn_array_ptr_size (&entry
->srcs
); ++i
)
590 dyn_array_ptr_push (&dfs_stack
, dyn_array_ptr_get (&entry
->srcs
, i
));
591 } while (dyn_array_ptr_size (&dfs_stack
) > 0);
595 compare_hash_entries (const HashEntry
*e1
, const HashEntry
*e2
)
597 return e2
->finishing_time
- e1
->finishing_time
;
600 DEF_QSORT_INLINE(hash_entries
, HashEntry
*, compare_hash_entries
)
602 static gint64 step_1
, step_2
, step_3
, step_4
, step_5
, step_6
;
603 static int fist_pass_links
, second_pass_links
, sccs_links
;
604 static int max_sccs_links
= 0;
607 register_finalized_object (GCObject
*obj
)
609 g_assert (sgen_need_bridge_processing ());
610 dyn_array_ptr_push (®istered_bridges
, obj
);
616 dyn_array_ptr_set_size (®istered_bridges
, 0);
620 processing_stw_step (void)
624 SGEN_TV_DECLARE (atv
);
625 SGEN_TV_DECLARE (btv
);
627 if (!dyn_array_ptr_size (®istered_bridges
))
630 SGEN_TV_GETTIME (btv
);
634 dyn_array_ptr_init (&dfs_stack
);
635 dyn_array_int_init (&merge_array
);
639 First we insert all bridges into the hash table and then we do dfs1.
641 It must be done in 2 steps since the bridge arrays doesn't come in reverse topological order,
642 which means that we can have entry N pointing to entry N + 1.
644 If we dfs1 entry N before N + 1 is registered we'll not consider N + 1 for this bridge
645 pass and not create the required xref between the two.
647 bridge_count
= dyn_array_ptr_size (®istered_bridges
);
648 for (i
= 0; i
< bridge_count
; ++i
)
649 register_bridge_object ((GCObject
*)dyn_array_ptr_get (®istered_bridges
, i
));
651 for (i
= 0; i
< bridge_count
; ++i
)
652 dfs1 (get_hash_entry ((GCObject
*)dyn_array_ptr_get (®istered_bridges
, i
), NULL
));
654 SGEN_TV_GETTIME (atv
);
655 step_2
= SGEN_TV_ELAPSED (btv
, atv
);
658 static int num_registered_bridges
, hash_table_size
;
661 processing_build_callback_data (int generation
)
664 int num_sccs
, num_xrefs
;
665 int max_entries
, max_xrefs
;
666 GCObject
*obj G_GNUC_UNUSED
;
668 HashEntry
**all_entries
;
669 MonoGCBridgeSCC
**api_sccs
;
670 MonoGCBridgeXRef
*api_xrefs
;
671 SGEN_TV_DECLARE (atv
);
672 SGEN_TV_DECLARE (btv
);
674 g_assert (bridge_processor
->num_sccs
== 0 && bridge_processor
->num_xrefs
== 0);
675 g_assert (!bridge_processor
->api_sccs
&& !bridge_processor
->api_xrefs
);
677 if (!dyn_array_ptr_size (®istered_bridges
))
680 g_assert (mono_bridge_processing_in_progress
);
682 SGEN_TV_GETTIME (atv
);
684 /* alloc and fill array of all entries */
686 all_entries
= (HashEntry
**)sgen_alloc_internal_dynamic (sizeof (HashEntry
*) * hash_table
.num_entries
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
689 SGEN_HASH_TABLE_FOREACH (&hash_table
, GCObject
*, obj
, HashEntry
*, entry
) {
690 g_assert (entry
->finishing_time
>= 0);
691 all_entries
[j
++] = entry
;
692 fist_pass_links
+= dyn_array_ptr_size (&entry
->srcs
);
693 } SGEN_HASH_TABLE_FOREACH_END
;
694 g_assert (j
== hash_table
.num_entries
);
695 hash_table_size
= hash_table
.num_entries
;
697 /* sort array according to decreasing finishing time */
698 qsort_hash_entries (all_entries
, hash_table
.num_entries
);
700 SGEN_TV_GETTIME (btv
);
701 step_3
= SGEN_TV_ELAPSED (atv
, btv
);
703 /* second DFS pass */
705 dyn_array_scc_init (&sccs
);
706 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
707 HashEntry
*entry
= all_entries
[i
];
708 if (entry
->scc_index
< 0) {
709 int index
= dyn_array_scc_size (&sccs
);
710 current_scc
= dyn_array_scc_add (&sccs
);
711 current_scc
->index
= index
;
712 current_scc
->num_bridge_entries
= 0;
713 current_scc
->api_index
= -1;
714 dyn_array_int_init (¤t_scc
->xrefs
);
721 * Compute the weight of each object. The weight of an object is its size plus the size of all
722 * objects it points do. When the an object is pointed by multiple objects we distribute it's weight
723 * equally among them. This distribution gives a rough estimate of the real impact of making the object
726 * The reasoning for this model is that complex graphs with single roots will have a bridge with very high
727 * value in comparison to others.
729 * The all_entries array has all objects topologically sorted. To correctly propagate the weights it must be
730 * done in reverse topological order - so we calculate the weight of the pointed-to objects before processing
731 * pointer-from objects.
733 * We log those objects in the opposite order for no particular reason. The other constrain is that it should use the same
734 * direction as the other logging loop that records live/dead information.
736 if (bridge_accounting_enabled
) {
737 for (i
= hash_table
.num_entries
- 1; i
>= 0; --i
) {
739 HashEntryWithAccounting
*entry
= (HashEntryWithAccounting
*)all_entries
[i
];
741 entry
->weight
+= (double)sgen_safe_object_get_size (entry
->entry
.obj
);
742 w
= entry
->weight
/ dyn_array_ptr_size (&entry
->entry
.srcs
);
743 for (j
= 0; j
< dyn_array_ptr_size (&entry
->entry
.srcs
); ++j
) {
744 HashEntryWithAccounting
*other
= (HashEntryWithAccounting
*)dyn_array_ptr_get (&entry
->entry
.srcs
, j
);
748 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
749 HashEntryWithAccounting
*entry
= (HashEntryWithAccounting
*)all_entries
[i
];
750 if (entry
->entry
.is_bridge
) {
751 MonoClass
*klass
= SGEN_LOAD_VTABLE (entry
->entry
.obj
)->klass
;
752 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
, "OBJECT %s::%s (%p) weight %f", m_class_get_name_space (klass
), m_class_get_name (klass
), entry
->entry
.obj
, entry
->weight
);
757 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
758 HashEntry
*entry
= all_entries
[i
];
759 second_pass_links
+= dyn_array_ptr_size (&entry
->srcs
);
762 SGEN_TV_GETTIME (atv
);
763 step_4
= SGEN_TV_ELAPSED (btv
, atv
);
765 //g_print ("%d sccs\n", sccs.size);
767 dyn_array_ptr_uninit (&dfs_stack
);
769 /* init data for callback */
772 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
773 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
774 g_assert (scc
->index
== i
);
775 if (scc
->num_bridge_entries
)
777 sccs_links
+= dyn_array_int_size (&scc
->xrefs
);
778 max_sccs_links
= MAX (max_sccs_links
, dyn_array_int_size (&scc
->xrefs
));
781 api_sccs
= (MonoGCBridgeSCC
**)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC
*) * num_sccs
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
784 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
785 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
786 if (!scc
->num_bridge_entries
)
789 api_sccs
[j
] = (MonoGCBridgeSCC
*)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC
) + sizeof (MonoObject
*) * scc
->num_bridge_entries
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
790 api_sccs
[j
]->is_alive
= FALSE
;
791 api_sccs
[j
]->num_objs
= scc
->num_bridge_entries
;
792 scc
->num_bridge_entries
= 0;
793 scc
->api_index
= j
++;
795 num_xrefs
+= dyn_array_int_size (&scc
->xrefs
);
798 SGEN_HASH_TABLE_FOREACH (&hash_table
, GCObject
*, obj
, HashEntry
*, entry
) {
799 if (entry
->is_bridge
) {
800 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, entry
->scc_index
);
801 api_sccs
[scc
->api_index
]->objs
[scc
->num_bridge_entries
++] = (MonoObject
*)entry
->obj
;
803 } SGEN_HASH_TABLE_FOREACH_END
;
805 api_xrefs
= (MonoGCBridgeXRef
*)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef
) * num_xrefs
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
807 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
809 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
810 if (!scc
->num_bridge_entries
)
812 for (k
= 0; k
< dyn_array_int_size (&scc
->xrefs
); ++k
) {
813 SCC
*src_scc
= dyn_array_scc_get_ptr (&sccs
, dyn_array_int_get (&scc
->xrefs
, k
));
814 if (!src_scc
->num_bridge_entries
)
816 api_xrefs
[j
].src_scc_index
= src_scc
->api_index
;
817 api_xrefs
[j
].dst_scc_index
= scc
->api_index
;
822 SGEN_TV_GETTIME (btv
);
823 step_5
= SGEN_TV_ELAPSED (atv
, btv
);
828 max_entries
= max_xrefs
= 0;
829 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
830 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
831 if (scc
->num_bridge_entries
)
833 if (scc
->num_bridge_entries
> max_entries
)
834 max_entries
= scc
->num_bridge_entries
;
835 if (dyn_array_int_size (&scc
->xrefs
) > max_xrefs
)
836 max_xrefs
= dyn_array_int_size (&scc
->xrefs
);
837 dyn_array_int_uninit (&scc
->xrefs
);
840 dyn_array_scc_uninit (&sccs
);
842 sgen_free_internal_dynamic (all_entries
, sizeof (HashEntry
*) * hash_table
.num_entries
, INTERNAL_MEM_BRIDGE_DATA
);
845 /* Empty the registered bridges array */
846 num_registered_bridges
= dyn_array_ptr_size (®istered_bridges
);
847 dyn_array_ptr_set_size (®istered_bridges
, 0);
849 SGEN_TV_GETTIME (atv
);
850 step_6
= SGEN_TV_ELAPSED (btv
, atv
);
852 //g_print ("%d sccs containing bridges - %d max bridge objects - %d max xrefs\n", j, max_entries, max_xrefs);
854 bridge_processor
->num_sccs
= num_sccs
;
855 bridge_processor
->api_sccs
= api_sccs
;
856 bridge_processor
->num_xrefs
= num_xrefs
;
857 bridge_processor
->api_xrefs
= api_xrefs
;
861 processing_after_callback (int generation
)
864 int num_sccs
= bridge_processor
->num_sccs
;
865 MonoGCBridgeSCC
**api_sccs
= bridge_processor
->api_sccs
;
867 if (bridge_accounting_enabled
) {
868 for (i
= 0; i
< num_sccs
; ++i
) {
869 for (j
= 0; j
< api_sccs
[i
]->num_objs
; ++j
) {
870 GCVTable vtable
= SGEN_LOAD_VTABLE (api_sccs
[i
]->objs
[j
]);
871 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
,
872 "OBJECT %s.%s (%p) SCC [%d] %s",
873 sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
), api_sccs
[i
]->objs
[j
],
875 api_sccs
[i
]->is_alive
? "ALIVE" : "DEAD");
880 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
, "GC_OLD_BRIDGE num-objects %d num_hash_entries %d sccs size %d init %.2fms df1 %.2fms sort %.2fms dfs2 %.2fms setup-cb %.2fms free-data %.2fms links %d/%d/%d/%d dfs passes %d/%d",
881 num_registered_bridges
, hash_table_size
, dyn_array_scc_size (&sccs
),
888 fist_pass_links
, second_pass_links
, sccs_links
, max_sccs_links
,
889 dfs1_passes
, dfs2_passes
);
891 step_1
= 0; /* We must cleanup since this value is used as an accumulator. */
892 fist_pass_links
= second_pass_links
= sccs_links
= max_sccs_links
= 0;
893 dfs1_passes
= dfs2_passes
= 0;
897 describe_pointer (GCObject
*obj
)
902 for (i
= 0; i
< dyn_array_ptr_size (®istered_bridges
); ++i
) {
903 if (obj
== dyn_array_ptr_get (®istered_bridges
, i
)) {
904 printf ("Pointer is a registered bridge object.\n");
909 entry
= (HashEntry
*)sgen_hash_table_lookup (&hash_table
, obj
);
913 printf ("Bridge hash table entry %p:\n", entry
);
914 printf (" is bridge: %d\n", (int)entry
->is_bridge
);
915 printf (" is visited: %d\n", (int)entry
->is_visited
);
919 sgen_old_bridge_init (SgenBridgeProcessor
*collector
)
921 collector
->reset_data
= reset_data
;
922 collector
->processing_stw_step
= processing_stw_step
;
923 collector
->processing_build_callback_data
= processing_build_callback_data
;
924 collector
->processing_after_callback
= processing_after_callback
;
925 collector
->class_kind
= class_kind
;
926 collector
->register_finalized_object
= register_finalized_object
;
927 collector
->describe_pointer
= describe_pointer
;
928 collector
->set_config
= set_config
;
930 bridge_processor
= collector
;