2 * sgen-bridge.c: Simple generational GC.
4 * Copyright 2011 Novell, Inc (http://www.novell.com)
5 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
7 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
10 * Permission is hereby granted to use or copy this program
11 * for any purpose, provided the above notices are retained on all copies.
12 * Permission to modify the code and to distribute modified code is granted,
13 * provided the above notices are retained, and a notice that the code was
14 * modified is included with the above copyright notice.
17 * Copyright 2001-2003 Ximian, Inc
18 * Copyright 2003-2010 Novell, Inc.
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46 #include "sgen/sgen-gc.h"
47 #include "sgen-bridge-internal.h"
48 #include "sgen/sgen-hash-table.h"
49 #include "sgen/sgen-qsort.h"
50 #include "sgen/sgen-client.h"
51 #include "utils/mono-logger-internal.h"
75 * FIXME: Optimizations:
77 * Don't allocate a scrs array for just one source. Most objects have
78 * just one source, so use the srcs pointer itself.
80 typedef struct _HashEntry
{
81 GCObject
*obj
; /* This is a duplicate - it's already stored in the hash table */
96 } HashEntryWithAccounting
;
101 int num_bridge_entries
;
102 DynIntArray xrefs
; /* these are incoming, not outgoing */
105 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
);
107 static int current_time
;
109 static gboolean bridge_accounting_enabled
= FALSE
;
111 static SgenBridgeProcessor
*bridge_processor
;
119 dyn_array_init (DynArray
*da
)
127 dyn_array_uninit (DynArray
*da
, int elem_size
)
129 if (da
->capacity
<= 0)
132 sgen_free_internal_dynamic (da
->data
, elem_size
* da
->capacity
, INTERNAL_MEM_BRIDGE_DATA
);
137 dyn_array_ensure_capacity (DynArray
*da
, int capacity
, int elem_size
)
139 int old_capacity
= da
->capacity
;
142 if (capacity
<= old_capacity
)
145 if (da
->capacity
== 0)
147 while (capacity
> da
->capacity
)
150 new_data
= sgen_alloc_internal_dynamic (elem_size
* da
->capacity
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
151 memcpy (new_data
, da
->data
, elem_size
* da
->size
);
152 sgen_free_internal_dynamic (da
->data
, elem_size
* old_capacity
, INTERNAL_MEM_BRIDGE_DATA
);
157 dyn_array_add (DynArray
*da
, int elem_size
)
161 dyn_array_ensure_capacity (da
, da
->size
+ 1, elem_size
);
163 p
= da
->data
+ da
->size
* elem_size
;
170 dyn_array_int_init (DynIntArray
*da
)
172 dyn_array_init (&da
->array
);
176 dyn_array_int_uninit (DynIntArray
*da
)
178 dyn_array_uninit (&da
->array
, sizeof (int));
182 dyn_array_int_size (DynIntArray
*da
)
184 return da
->array
.size
;
188 dyn_array_int_set_size (DynIntArray
*da
, int size
)
190 da
->array
.size
= size
;
194 dyn_array_int_add (DynIntArray
*da
, int x
)
196 int *p
= dyn_array_add (&da
->array
, sizeof (int));
201 dyn_array_int_get (DynIntArray
*da
, int x
)
203 return ((int*)da
->array
.data
)[x
];
207 dyn_array_int_set (DynIntArray
*da
, int idx
, int val
)
209 ((int*)da
->array
.data
)[idx
] = val
;
213 dyn_array_int_ensure_capacity (DynIntArray
*da
, int capacity
)
215 dyn_array_ensure_capacity (&da
->array
, capacity
, sizeof (int));
219 dyn_array_int_set_all (DynIntArray
*dst
, DynIntArray
*src
)
221 dyn_array_int_ensure_capacity (dst
, src
->array
.size
);
222 memcpy (dst
->array
.data
, src
->array
.data
, src
->array
.size
* sizeof (int));
223 dst
->array
.size
= src
->array
.size
;
229 dyn_array_ptr_init (DynPtrArray
*da
)
231 dyn_array_init (&da
->array
);
235 dyn_array_ptr_uninit (DynPtrArray
*da
)
237 dyn_array_uninit (&da
->array
, sizeof (void*));
241 dyn_array_ptr_size (DynPtrArray
*da
)
243 return da
->array
.size
;
247 dyn_array_ptr_set_size (DynPtrArray
*da
, int size
)
249 da
->array
.size
= size
;
253 dyn_array_ptr_get (DynPtrArray
*da
, int x
)
255 return ((void**)da
->array
.data
)[x
];
259 dyn_array_ptr_add (DynPtrArray
*da
, void *ptr
)
261 void **p
= dyn_array_add (&da
->array
, sizeof (void*));
265 #define dyn_array_ptr_push dyn_array_ptr_add
268 dyn_array_ptr_pop (DynPtrArray
*da
)
271 int size
= da
->array
.size
;
273 p
= dyn_array_ptr_get (da
, size
- 1);
281 dyn_array_scc_init (DynSCCArray
*da
)
283 dyn_array_init (&da
->array
);
287 dyn_array_scc_uninit (DynSCCArray
*da
)
289 dyn_array_uninit (&da
->array
, sizeof (SCC
));
293 dyn_array_scc_size (DynSCCArray
*da
)
295 return da
->array
.size
;
299 dyn_array_scc_add (DynSCCArray
*da
)
301 return dyn_array_add (&da
->array
, sizeof (SCC
));
305 dyn_array_scc_get_ptr (DynSCCArray
*da
, int x
)
307 return &((SCC
*)da
->array
.data
)[x
];
312 static DynIntArray merge_array
;
315 dyn_array_int_contains (DynIntArray
*da
, int x
)
318 for (i
= 0; i
< dyn_array_int_size (da
); ++i
)
319 if (dyn_array_int_get (da
, i
) == x
)
326 dyn_array_int_merge (DynIntArray
*dst
, DynIntArray
*src
)
330 dyn_array_int_ensure_capacity (&merge_array
, dyn_array_int_size (dst
) + dyn_array_int_size (src
));
331 dyn_array_int_set_size (&merge_array
, 0);
333 for (i
= j
= 0; i
< dyn_array_int_size (dst
) || j
< dyn_array_int_size (src
); ) {
334 if (i
< dyn_array_int_size (dst
) && j
< dyn_array_int_size (src
)) {
335 int a
= dyn_array_int_get (dst
, i
);
336 int b
= dyn_array_int_get (src
, j
);
338 dyn_array_int_add (&merge_array
, a
);
341 dyn_array_int_add (&merge_array
, a
);
345 dyn_array_int_add (&merge_array
, b
);
348 } else if (i
< dyn_array_int_size (dst
)) {
349 dyn_array_int_add (&merge_array
, dyn_array_int_get (dst
, i
));
352 dyn_array_int_add (&merge_array
, dyn_array_int_get (src
, j
));
357 if (dyn_array_int_size (&merge_array
) > dyn_array_int_size (dst
)) {
358 dyn_array_int_set_all (dst
, &merge_array
);
363 dyn_array_int_merge_one (DynIntArray
*array
, int value
)
367 int size
= dyn_array_int_size (array
);
369 for (i
= 0; i
< size
; ++i
) {
370 if (dyn_array_int_get (array
, i
) == value
)
372 else if (dyn_array_int_get (array
, i
) > value
)
376 dyn_array_int_ensure_capacity (array
, size
+ 1);
379 tmp
= dyn_array_int_get (array
, i
);
380 for (; i
< size
; ++i
) {
381 dyn_array_int_set (array
, i
, value
);
383 tmp
= dyn_array_int_get (array
, i
+ 1);
385 dyn_array_int_set (array
, size
, value
);
387 dyn_array_int_set (array
, size
, value
);
390 dyn_array_int_set_size (array
, size
+ 1);
395 enable_accounting (void)
397 SgenHashTable table
= SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE
, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY
, sizeof (HashEntryWithAccounting
), mono_aligned_addr_hash
, NULL
);
398 bridge_accounting_enabled
= TRUE
;
402 static MonoGCBridgeObjectKind
403 class_kind (MonoClass
*class)
405 return bridge_callbacks
.bridge_class_kind (class);
409 get_hash_entry (GCObject
*obj
, gboolean
*existing
)
411 HashEntry
*entry
= sgen_hash_table_lookup (&hash_table
, obj
);
422 memset (&new_entry
, 0, sizeof (HashEntry
));
425 dyn_array_ptr_init (&new_entry
.srcs
);
426 new_entry
.finishing_time
= -1;
427 new_entry
.scc_index
= -1;
429 sgen_hash_table_replace (&hash_table
, obj
, &new_entry
, NULL
);
431 return sgen_hash_table_lookup (&hash_table
, obj
);
435 add_source (HashEntry
*entry
, HashEntry
*src
)
437 dyn_array_ptr_add (&entry
->srcs
, src
);
443 GCObject
*obj G_GNUC_UNUSED
;
448 SGEN_HASH_TABLE_FOREACH (&hash_table
, obj
, entry
) {
449 int entry_size
= dyn_array_ptr_size (&entry
->srcs
);
450 total_srcs
+= entry_size
;
451 if (entry_size
> max_srcs
)
452 max_srcs
= entry_size
;
453 dyn_array_ptr_uninit (&entry
->srcs
);
454 } SGEN_HASH_TABLE_FOREACH_END
;
456 sgen_hash_table_clean (&hash_table
);
458 dyn_array_int_uninit (&merge_array
);
459 //g_print ("total srcs %d - max %d\n", total_srcs, max_srcs);
463 register_bridge_object (GCObject
*obj
)
465 HashEntry
*entry
= get_hash_entry (obj
, NULL
);
466 entry
->is_bridge
= TRUE
;
471 register_finishing_time (HashEntry
*entry
, int t
)
473 g_assert (entry
->finishing_time
< 0);
474 entry
->finishing_time
= t
;
478 object_is_live (GCObject
**objp
)
480 GCObject
*obj
= *objp
;
481 GCObject
*fwd
= SGEN_OBJECT_IS_FORWARDED (obj
);
484 return sgen_hash_table_lookup (&hash_table
, fwd
) == NULL
;
486 if (!sgen_object_is_live (obj
))
488 return sgen_hash_table_lookup (&hash_table
, obj
) == NULL
;
491 static DynPtrArray registered_bridges
;
492 static DynPtrArray dfs_stack
;
494 static int dfs1_passes
, dfs2_passes
;
498 #define HANDLE_PTR(ptr,obj) do { \
499 GCObject *dst = (GCObject*)*(ptr); \
500 if (dst && !object_is_live (&dst)) { \
501 dyn_array_ptr_push (&dfs_stack, obj_entry); \
502 dyn_array_ptr_push (&dfs_stack, get_hash_entry (dst, NULL)); \
507 dfs1 (HashEntry
*obj_entry
)
510 g_assert (dyn_array_ptr_size (&dfs_stack
) == 0);
512 dyn_array_ptr_push (&dfs_stack
, NULL
);
513 dyn_array_ptr_push (&dfs_stack
, obj_entry
);
519 obj_entry
= dyn_array_ptr_pop (&dfs_stack
);
523 src
= dyn_array_ptr_pop (&dfs_stack
);
525 obj
= obj_entry
->obj
;
526 desc
= sgen_obj_get_descriptor_safe (obj
);
529 //g_print ("link %s -> %s\n", sgen_safe_name (src->obj), sgen_safe_name (obj));
530 add_source (obj_entry
, src
);
532 //g_print ("starting with %s\n", sgen_safe_name (obj));
535 if (obj_entry
->is_visited
)
538 obj_entry
->is_visited
= TRUE
;
540 dyn_array_ptr_push (&dfs_stack
, obj_entry
);
541 /* NULL marks that the next entry is to be finished */
542 dyn_array_ptr_push (&dfs_stack
, NULL
);
545 #include "sgen/sgen-scan-object.h"
547 obj_entry
= dyn_array_ptr_pop (&dfs_stack
);
549 //g_print ("finish %s\n", sgen_safe_name (obj_entry->obj));
550 register_finishing_time (obj_entry
, current_time
++);
552 } while (dyn_array_ptr_size (&dfs_stack
) > 0);
556 scc_add_xref (SCC
*src
, SCC
*dst
)
558 g_assert (src
!= dst
);
559 g_assert (src
->index
!= dst
->index
);
561 if (dyn_array_int_contains (&dst
->xrefs
, src
->index
))
563 if (src
->num_bridge_entries
) {
564 dyn_array_int_merge_one (&dst
->xrefs
, src
->index
);
567 dyn_array_int_merge (&dst
->xrefs
, &src
->xrefs
);
568 for (i
= 0; i
< dyn_array_int_size (&dst
->xrefs
); ++i
)
569 g_assert (dyn_array_int_get (&dst
->xrefs
, i
) != dst
->index
);
574 scc_add_entry (SCC
*scc
, HashEntry
*entry
)
576 g_assert (entry
->scc_index
< 0);
577 entry
->scc_index
= scc
->index
;
578 if (entry
->is_bridge
)
579 ++scc
->num_bridge_entries
;
582 static DynSCCArray sccs
;
583 static SCC
*current_scc
;
586 dfs2 (HashEntry
*entry
)
590 g_assert (dyn_array_ptr_size (&dfs_stack
) == 0);
592 dyn_array_ptr_push (&dfs_stack
, entry
);
595 entry
= dyn_array_ptr_pop (&dfs_stack
);
598 if (entry
->scc_index
>= 0) {
599 if (entry
->scc_index
!= current_scc
->index
)
600 scc_add_xref (dyn_array_scc_get_ptr (&sccs
, entry
->scc_index
), current_scc
);
604 scc_add_entry (current_scc
, entry
);
606 for (i
= 0; i
< dyn_array_ptr_size (&entry
->srcs
); ++i
)
607 dyn_array_ptr_push (&dfs_stack
, dyn_array_ptr_get (&entry
->srcs
, i
));
608 } while (dyn_array_ptr_size (&dfs_stack
) > 0);
612 compare_hash_entries (const HashEntry
*e1
, const HashEntry
*e2
)
614 return e2
->finishing_time
- e1
->finishing_time
;
617 DEF_QSORT_INLINE(hash_entries
, HashEntry
*, compare_hash_entries
)
619 static unsigned long step_1
, step_2
, step_3
, step_4
, step_5
, step_6
;
620 static int fist_pass_links
, second_pass_links
, sccs_links
;
621 static int max_sccs_links
= 0;
624 register_finalized_object (GCObject
*obj
)
626 g_assert (sgen_need_bridge_processing ());
627 dyn_array_ptr_push (®istered_bridges
, obj
);
633 dyn_array_ptr_set_size (®istered_bridges
, 0);
637 processing_stw_step (void)
641 SGEN_TV_DECLARE (atv
);
642 SGEN_TV_DECLARE (btv
);
644 if (!dyn_array_ptr_size (®istered_bridges
))
647 SGEN_TV_GETTIME (btv
);
651 dyn_array_ptr_init (&dfs_stack
);
652 dyn_array_int_init (&merge_array
);
656 First we insert all bridges into the hash table and then we do dfs1.
658 It must be done in 2 steps since the bridge arrays doesn't come in reverse topological order,
659 which means that we can have entry N pointing to entry N + 1.
661 If we dfs1 entry N before N + 1 is registered we'll not consider N + 1 for this bridge
662 pass and not create the required xref between the two.
664 bridge_count
= dyn_array_ptr_size (®istered_bridges
);
665 for (i
= 0; i
< bridge_count
; ++i
)
666 register_bridge_object (dyn_array_ptr_get (®istered_bridges
, i
));
668 for (i
= 0; i
< bridge_count
; ++i
)
669 dfs1 (get_hash_entry (dyn_array_ptr_get (®istered_bridges
, i
), NULL
));
671 SGEN_TV_GETTIME (atv
);
672 step_2
= SGEN_TV_ELAPSED (btv
, atv
);
675 static int num_registered_bridges
, hash_table_size
;
678 processing_build_callback_data (int generation
)
681 int num_sccs
, num_xrefs
;
682 int max_entries
, max_xrefs
;
683 GCObject
*obj G_GNUC_UNUSED
;
685 HashEntry
**all_entries
;
686 MonoGCBridgeSCC
**api_sccs
;
687 MonoGCBridgeXRef
*api_xrefs
;
688 SGEN_TV_DECLARE (atv
);
689 SGEN_TV_DECLARE (btv
);
691 g_assert (bridge_processor
->num_sccs
== 0 && bridge_processor
->num_xrefs
== 0);
692 g_assert (!bridge_processor
->api_sccs
&& !bridge_processor
->api_xrefs
);
694 if (!dyn_array_ptr_size (®istered_bridges
))
697 g_assert (bridge_processing_in_progress
);
699 SGEN_TV_GETTIME (atv
);
701 /* alloc and fill array of all entries */
703 all_entries
= sgen_alloc_internal_dynamic (sizeof (HashEntry
*) * hash_table
.num_entries
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
706 SGEN_HASH_TABLE_FOREACH (&hash_table
, obj
, entry
) {
707 g_assert (entry
->finishing_time
>= 0);
708 all_entries
[j
++] = entry
;
709 fist_pass_links
+= dyn_array_ptr_size (&entry
->srcs
);
710 } SGEN_HASH_TABLE_FOREACH_END
;
711 g_assert (j
== hash_table
.num_entries
);
712 hash_table_size
= hash_table
.num_entries
;
714 /* sort array according to decreasing finishing time */
715 qsort_hash_entries (all_entries
, hash_table
.num_entries
);
717 SGEN_TV_GETTIME (btv
);
718 step_3
= SGEN_TV_ELAPSED (atv
, btv
);
720 /* second DFS pass */
722 dyn_array_scc_init (&sccs
);
723 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
724 HashEntry
*entry
= all_entries
[i
];
725 if (entry
->scc_index
< 0) {
726 int index
= dyn_array_scc_size (&sccs
);
727 current_scc
= dyn_array_scc_add (&sccs
);
728 current_scc
->index
= index
;
729 current_scc
->num_bridge_entries
= 0;
730 current_scc
->api_index
= -1;
731 dyn_array_int_init (¤t_scc
->xrefs
);
738 * Compute the weight of each object. The weight of an object is its size plus the size of all
739 * objects it points do. When the an object is pointed by multiple objects we distribute it's weight
740 * equally among them. This distribution gives a rough estimate of the real impact of making the object
743 * The reasoning for this model is that complex graphs with single roots will have a bridge with very high
744 * value in comparison to others.
746 * The all_entries array has all objects topologically sorted. To correctly propagate the weights it must be
747 * done in reverse topological order - so we calculate the weight of the pointed-to objects before processing
748 * pointer-from objects.
750 * We log those objects in the opposite order for no particular reason. The other constrain is that it should use the same
751 * direction as the other logging loop that records live/dead information.
753 if (bridge_accounting_enabled
) {
754 for (i
= hash_table
.num_entries
- 1; i
>= 0; --i
) {
756 HashEntryWithAccounting
*entry
= (HashEntryWithAccounting
*)all_entries
[i
];
758 entry
->weight
+= (double)sgen_safe_object_get_size (entry
->entry
.obj
);
759 w
= entry
->weight
/ dyn_array_ptr_size (&entry
->entry
.srcs
);
760 for (j
= 0; j
< dyn_array_ptr_size (&entry
->entry
.srcs
); ++j
) {
761 HashEntryWithAccounting
*other
= (HashEntryWithAccounting
*)dyn_array_ptr_get (&entry
->entry
.srcs
, j
);
765 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
766 HashEntryWithAccounting
*entry
= (HashEntryWithAccounting
*)all_entries
[i
];
767 if (entry
->entry
.is_bridge
) {
768 MonoClass
*klass
= SGEN_LOAD_VTABLE (entry
->entry
.obj
)->klass
;
769 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
, "OBJECT %s::%s (%p) weight %f", klass
->name_space
, klass
->name
, entry
->entry
.obj
, entry
->weight
);
774 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
775 HashEntry
*entry
= all_entries
[i
];
776 second_pass_links
+= dyn_array_ptr_size (&entry
->srcs
);
779 SGEN_TV_GETTIME (atv
);
780 step_4
= SGEN_TV_ELAPSED (btv
, atv
);
782 //g_print ("%d sccs\n", sccs.size);
784 dyn_array_ptr_uninit (&dfs_stack
);
786 /* init data for callback */
789 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
790 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
791 g_assert (scc
->index
== i
);
792 if (scc
->num_bridge_entries
)
794 sccs_links
+= dyn_array_int_size (&scc
->xrefs
);
795 max_sccs_links
= MAX (max_sccs_links
, dyn_array_int_size (&scc
->xrefs
));
798 api_sccs
= sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC
*) * num_sccs
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
801 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
802 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
803 if (!scc
->num_bridge_entries
)
806 api_sccs
[j
] = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC
) + sizeof (MonoObject
*) * scc
->num_bridge_entries
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
807 api_sccs
[j
]->is_alive
= FALSE
;
808 api_sccs
[j
]->num_objs
= scc
->num_bridge_entries
;
809 scc
->num_bridge_entries
= 0;
810 scc
->api_index
= j
++;
812 num_xrefs
+= dyn_array_int_size (&scc
->xrefs
);
815 SGEN_HASH_TABLE_FOREACH (&hash_table
, obj
, entry
) {
816 if (entry
->is_bridge
) {
817 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, entry
->scc_index
);
818 api_sccs
[scc
->api_index
]->objs
[scc
->num_bridge_entries
++] = (MonoObject
*)entry
->obj
;
820 } SGEN_HASH_TABLE_FOREACH_END
;
822 api_xrefs
= sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef
) * num_xrefs
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
824 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
826 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
827 if (!scc
->num_bridge_entries
)
829 for (k
= 0; k
< dyn_array_int_size (&scc
->xrefs
); ++k
) {
830 SCC
*src_scc
= dyn_array_scc_get_ptr (&sccs
, dyn_array_int_get (&scc
->xrefs
, k
));
831 if (!src_scc
->num_bridge_entries
)
833 api_xrefs
[j
].src_scc_index
= src_scc
->api_index
;
834 api_xrefs
[j
].dst_scc_index
= scc
->api_index
;
839 SGEN_TV_GETTIME (btv
);
840 step_5
= SGEN_TV_ELAPSED (atv
, btv
);
845 max_entries
= max_xrefs
= 0;
846 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
847 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
848 if (scc
->num_bridge_entries
)
850 if (scc
->num_bridge_entries
> max_entries
)
851 max_entries
= scc
->num_bridge_entries
;
852 if (dyn_array_int_size (&scc
->xrefs
) > max_xrefs
)
853 max_xrefs
= dyn_array_int_size (&scc
->xrefs
);
854 dyn_array_int_uninit (&scc
->xrefs
);
857 dyn_array_scc_uninit (&sccs
);
859 sgen_free_internal_dynamic (all_entries
, sizeof (HashEntry
*) * hash_table
.num_entries
, INTERNAL_MEM_BRIDGE_DATA
);
862 /* Empty the registered bridges array */
863 num_registered_bridges
= dyn_array_ptr_size (®istered_bridges
);
864 dyn_array_ptr_set_size (®istered_bridges
, 0);
866 SGEN_TV_GETTIME (atv
);
867 step_6
= SGEN_TV_ELAPSED (btv
, atv
);
869 //g_print ("%d sccs containing bridges - %d max bridge objects - %d max xrefs\n", j, max_entries, max_xrefs);
871 bridge_processor
->num_sccs
= num_sccs
;
872 bridge_processor
->api_sccs
= api_sccs
;
873 bridge_processor
->num_xrefs
= num_xrefs
;
874 bridge_processor
->api_xrefs
= api_xrefs
;
878 processing_after_callback (int generation
)
881 int num_sccs
= bridge_processor
->num_sccs
;
882 MonoGCBridgeSCC
**api_sccs
= bridge_processor
->api_sccs
;
884 if (bridge_accounting_enabled
) {
885 for (i
= 0; i
< num_sccs
; ++i
) {
886 for (j
= 0; j
< api_sccs
[i
]->num_objs
; ++j
) {
887 GCVTable vtable
= SGEN_LOAD_VTABLE (api_sccs
[i
]->objs
[j
]);
888 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
,
889 "OBJECT %s.%s (%p) SCC [%d] %s",
890 sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
), api_sccs
[i
]->objs
[j
],
892 api_sccs
[i
]->is_alive
? "ALIVE" : "DEAD");
897 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",
898 num_registered_bridges
, hash_table_size
, dyn_array_scc_size (&sccs
),
905 fist_pass_links
, second_pass_links
, sccs_links
, max_sccs_links
,
906 dfs1_passes
, dfs2_passes
);
908 step_1
= 0; /* We must cleanup since this value is used as an accumulator. */
909 fist_pass_links
= second_pass_links
= sccs_links
= max_sccs_links
= 0;
910 dfs1_passes
= dfs2_passes
= 0;
914 describe_pointer (GCObject
*obj
)
919 for (i
= 0; i
< dyn_array_ptr_size (®istered_bridges
); ++i
) {
920 if (obj
== dyn_array_ptr_get (®istered_bridges
, i
)) {
921 printf ("Pointer is a registered bridge object.\n");
926 entry
= sgen_hash_table_lookup (&hash_table
, obj
);
930 printf ("Bridge hash table entry %p:\n", entry
);
931 printf (" is bridge: %d\n", (int)entry
->is_bridge
);
932 printf (" is visited: %d\n", (int)entry
->is_visited
);
936 sgen_old_bridge_init (SgenBridgeProcessor
*collector
)
938 collector
->reset_data
= reset_data
;
939 collector
->processing_stw_step
= processing_stw_step
;
940 collector
->processing_build_callback_data
= processing_build_callback_data
;
941 collector
->processing_after_callback
= processing_after_callback
;
942 collector
->class_kind
= class_kind
;
943 collector
->register_finalized_object
= register_finalized_object
;
944 collector
->describe_pointer
= describe_pointer
;
945 collector
->enable_accounting
= enable_accounting
;
947 bridge_processor
= collector
;