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.
47 #include "sgen-bridge.h"
48 #include "sgen-hash-table.h"
49 #include "sgen-qsort.h"
50 #include "utils/mono-logger-internal.h"
51 #include "utils/mono-time.h"
52 #include "utils/mono-compiler.h"
77 * FIXME: Optimizations:
79 * Don't allocate a scrs array for just one source. Most objects have
80 * just one source, so use the srcs pointer itself.
82 typedef struct _HashEntry
{
83 MonoObject
*obj
; /* This is a duplicate - it's already stored in the hash table */
98 } HashEntryWithAccounting
;
100 typedef struct _SCC
{
103 int num_bridge_entries
;
104 DynIntArray xrefs
; /* these are incoming, not outgoing */
107 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
);
109 static int current_time
;
111 static gboolean bridge_accounting_enabled
= FALSE
;
113 static SgenBridgeProcessor
*bridge_processor
;
121 dyn_array_init (DynArray
*da
)
129 dyn_array_uninit (DynArray
*da
, int elem_size
)
131 if (da
->capacity
<= 0)
134 sgen_free_internal_dynamic (da
->data
, elem_size
* da
->capacity
, INTERNAL_MEM_BRIDGE_DATA
);
139 dyn_array_ensure_capacity (DynArray
*da
, int capacity
, int elem_size
)
141 int old_capacity
= da
->capacity
;
144 if (capacity
<= old_capacity
)
147 if (da
->capacity
== 0)
149 while (capacity
> da
->capacity
)
152 new_data
= sgen_alloc_internal_dynamic (elem_size
* da
->capacity
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
153 memcpy (new_data
, da
->data
, elem_size
* da
->size
);
154 sgen_free_internal_dynamic (da
->data
, elem_size
* old_capacity
, INTERNAL_MEM_BRIDGE_DATA
);
159 dyn_array_add (DynArray
*da
, int elem_size
)
163 dyn_array_ensure_capacity (da
, da
->size
+ 1, elem_size
);
165 p
= da
->data
+ da
->size
* elem_size
;
172 dyn_array_int_init (DynIntArray
*da
)
174 dyn_array_init (&da
->array
);
178 dyn_array_int_uninit (DynIntArray
*da
)
180 dyn_array_uninit (&da
->array
, sizeof (int));
184 dyn_array_int_size (DynIntArray
*da
)
186 return da
->array
.size
;
190 dyn_array_int_set_size (DynIntArray
*da
, int size
)
192 da
->array
.size
= size
;
196 dyn_array_int_add (DynIntArray
*da
, int x
)
198 int *p
= dyn_array_add (&da
->array
, sizeof (int));
203 dyn_array_int_get (DynIntArray
*da
, int x
)
205 return ((int*)da
->array
.data
)[x
];
209 dyn_array_int_set (DynIntArray
*da
, int idx
, int val
)
211 ((int*)da
->array
.data
)[idx
] = val
;
215 dyn_array_int_ensure_capacity (DynIntArray
*da
, int capacity
)
217 dyn_array_ensure_capacity (&da
->array
, capacity
, sizeof (int));
221 dyn_array_int_set_all (DynIntArray
*dst
, DynIntArray
*src
)
223 dyn_array_int_ensure_capacity (dst
, src
->array
.size
);
224 memcpy (dst
->array
.data
, src
->array
.data
, src
->array
.size
* sizeof (int));
225 dst
->array
.size
= src
->array
.size
;
231 dyn_array_ptr_init (DynPtrArray
*da
)
233 dyn_array_init (&da
->array
);
237 dyn_array_ptr_uninit (DynPtrArray
*da
)
239 dyn_array_uninit (&da
->array
, sizeof (void*));
243 dyn_array_ptr_size (DynPtrArray
*da
)
245 return da
->array
.size
;
249 dyn_array_ptr_set_size (DynPtrArray
*da
, int size
)
251 da
->array
.size
= size
;
255 dyn_array_ptr_get (DynPtrArray
*da
, int x
)
257 return ((void**)da
->array
.data
)[x
];
261 dyn_array_ptr_add (DynPtrArray
*da
, void *ptr
)
263 void **p
= dyn_array_add (&da
->array
, sizeof (void*));
267 #define dyn_array_ptr_push dyn_array_ptr_add
270 dyn_array_ptr_pop (DynPtrArray
*da
)
273 int size
= da
->array
.size
;
275 p
= dyn_array_ptr_get (da
, size
- 1);
283 dyn_array_scc_init (DynSCCArray
*da
)
285 dyn_array_init (&da
->array
);
289 dyn_array_scc_uninit (DynSCCArray
*da
)
291 dyn_array_uninit (&da
->array
, sizeof (SCC
));
295 dyn_array_scc_size (DynSCCArray
*da
)
297 return da
->array
.size
;
301 dyn_array_scc_add (DynSCCArray
*da
)
303 return dyn_array_add (&da
->array
, sizeof (SCC
));
307 dyn_array_scc_get_ptr (DynSCCArray
*da
, int x
)
309 return &((SCC
*)da
->array
.data
)[x
];
314 static DynIntArray merge_array
;
317 dyn_array_int_contains (DynIntArray
*da
, int x
)
320 for (i
= 0; i
< dyn_array_int_size (da
); ++i
)
321 if (dyn_array_int_get (da
, i
) == x
)
328 dyn_array_int_merge (DynIntArray
*dst
, DynIntArray
*src
)
332 dyn_array_int_ensure_capacity (&merge_array
, dyn_array_int_size (dst
) + dyn_array_int_size (src
));
333 dyn_array_int_set_size (&merge_array
, 0);
335 for (i
= j
= 0; i
< dyn_array_int_size (dst
) || j
< dyn_array_int_size (src
); ) {
336 if (i
< dyn_array_int_size (dst
) && j
< dyn_array_int_size (src
)) {
337 int a
= dyn_array_int_get (dst
, i
);
338 int b
= dyn_array_int_get (src
, j
);
340 dyn_array_int_add (&merge_array
, a
);
343 dyn_array_int_add (&merge_array
, a
);
347 dyn_array_int_add (&merge_array
, b
);
350 } else if (i
< dyn_array_int_size (dst
)) {
351 dyn_array_int_add (&merge_array
, dyn_array_int_get (dst
, i
));
354 dyn_array_int_add (&merge_array
, dyn_array_int_get (src
, j
));
359 if (dyn_array_int_size (&merge_array
) > dyn_array_int_size (dst
)) {
360 dyn_array_int_set_all (dst
, &merge_array
);
365 dyn_array_int_merge_one (DynIntArray
*array
, int value
)
369 int size
= dyn_array_int_size (array
);
371 for (i
= 0; i
< size
; ++i
) {
372 if (dyn_array_int_get (array
, i
) == value
)
374 else if (dyn_array_int_get (array
, i
) > value
)
378 dyn_array_int_ensure_capacity (array
, size
+ 1);
381 tmp
= dyn_array_int_get (array
, i
);
382 for (; i
< size
; ++i
) {
383 dyn_array_int_set (array
, i
, value
);
385 tmp
= dyn_array_int_get (array
, i
+ 1);
387 dyn_array_int_set (array
, size
, value
);
389 dyn_array_int_set (array
, size
, value
);
392 dyn_array_int_set_size (array
, size
+ 1);
397 enable_accounting (void)
399 SgenHashTable table
= SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE
, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY
, sizeof (HashEntryWithAccounting
), mono_aligned_addr_hash
, NULL
);
400 bridge_accounting_enabled
= TRUE
;
404 static MonoGCBridgeObjectKind
405 class_kind (MonoClass
*class)
407 return bridge_callbacks
.bridge_class_kind (class);
411 get_hash_entry (MonoObject
*obj
, gboolean
*existing
)
413 HashEntry
*entry
= sgen_hash_table_lookup (&hash_table
, obj
);
424 memset (&new_entry
, 0, sizeof (HashEntry
));
427 dyn_array_ptr_init (&new_entry
.srcs
);
428 new_entry
.finishing_time
= -1;
429 new_entry
.scc_index
= -1;
431 sgen_hash_table_replace (&hash_table
, obj
, &new_entry
, NULL
);
433 return sgen_hash_table_lookup (&hash_table
, obj
);
437 add_source (HashEntry
*entry
, HashEntry
*src
)
439 dyn_array_ptr_add (&entry
->srcs
, src
);
450 SGEN_HASH_TABLE_FOREACH (&hash_table
, obj
, entry
) {
451 int entry_size
= dyn_array_ptr_size (&entry
->srcs
);
452 total_srcs
+= entry_size
;
453 if (entry_size
> max_srcs
)
454 max_srcs
= entry_size
;
455 dyn_array_ptr_uninit (&entry
->srcs
);
456 } SGEN_HASH_TABLE_FOREACH_END
;
458 sgen_hash_table_clean (&hash_table
);
460 dyn_array_int_uninit (&merge_array
);
461 //g_print ("total srcs %d - max %d\n", total_srcs, max_srcs);
465 register_bridge_object (MonoObject
*obj
)
467 HashEntry
*entry
= get_hash_entry (obj
, NULL
);
468 entry
->is_bridge
= TRUE
;
473 register_finishing_time (HashEntry
*entry
, int t
)
475 g_assert (entry
->finishing_time
< 0);
476 entry
->finishing_time
= t
;
480 object_is_live (MonoObject
**objp
)
482 MonoObject
*obj
= *objp
;
483 MonoObject
*fwd
= SGEN_OBJECT_IS_FORWARDED (obj
);
486 return sgen_hash_table_lookup (&hash_table
, fwd
) == NULL
;
488 if (!sgen_object_is_live (obj
))
490 return sgen_hash_table_lookup (&hash_table
, obj
) == NULL
;
493 static DynPtrArray registered_bridges
;
494 static DynPtrArray dfs_stack
;
496 static int dfs1_passes
, dfs2_passes
;
500 #define HANDLE_PTR(ptr,obj) do { \
501 MonoObject *dst = (MonoObject*)*(ptr); \
502 if (dst && !object_is_live (&dst)) { \
503 dyn_array_ptr_push (&dfs_stack, obj_entry); \
504 dyn_array_ptr_push (&dfs_stack, get_hash_entry (dst, NULL)); \
509 dfs1 (HashEntry
*obj_entry
)
512 g_assert (dyn_array_ptr_size (&dfs_stack
) == 0);
514 dyn_array_ptr_push (&dfs_stack
, NULL
);
515 dyn_array_ptr_push (&dfs_stack
, obj_entry
);
522 obj_entry
= dyn_array_ptr_pop (&dfs_stack
);
525 src
= dyn_array_ptr_pop (&dfs_stack
);
527 obj
= obj_entry
->obj
;
529 desc
= sgen_obj_get_descriptor (start
);
532 //g_print ("link %s -> %s\n", sgen_safe_name (src->obj), sgen_safe_name (obj));
533 add_source (obj_entry
, src
);
535 //g_print ("starting with %s\n", sgen_safe_name (obj));
538 if (obj_entry
->is_visited
)
541 obj_entry
->is_visited
= TRUE
;
543 dyn_array_ptr_push (&dfs_stack
, obj_entry
);
544 /* NULL marks that the next entry is to be finished */
545 dyn_array_ptr_push (&dfs_stack
, NULL
);
547 #include "sgen-scan-object.h"
549 obj_entry
= dyn_array_ptr_pop (&dfs_stack
);
551 //g_print ("finish %s\n", sgen_safe_name (obj_entry->obj));
552 register_finishing_time (obj_entry
, current_time
++);
554 } while (dyn_array_ptr_size (&dfs_stack
) > 0);
558 scc_add_xref (SCC
*src
, SCC
*dst
)
560 g_assert (src
!= dst
);
561 g_assert (src
->index
!= dst
->index
);
563 if (dyn_array_int_contains (&dst
->xrefs
, src
->index
))
565 if (src
->num_bridge_entries
) {
566 dyn_array_int_merge_one (&dst
->xrefs
, src
->index
);
569 dyn_array_int_merge (&dst
->xrefs
, &src
->xrefs
);
570 for (i
= 0; i
< dyn_array_int_size (&dst
->xrefs
); ++i
)
571 g_assert (dyn_array_int_get (&dst
->xrefs
, i
) != dst
->index
);
576 scc_add_entry (SCC
*scc
, HashEntry
*entry
)
578 g_assert (entry
->scc_index
< 0);
579 entry
->scc_index
= scc
->index
;
580 if (entry
->is_bridge
)
581 ++scc
->num_bridge_entries
;
584 static DynSCCArray sccs
;
585 static SCC
*current_scc
;
588 dfs2 (HashEntry
*entry
)
592 g_assert (dyn_array_ptr_size (&dfs_stack
) == 0);
594 dyn_array_ptr_push (&dfs_stack
, entry
);
597 entry
= dyn_array_ptr_pop (&dfs_stack
);
600 if (entry
->scc_index
>= 0) {
601 if (entry
->scc_index
!= current_scc
->index
)
602 scc_add_xref (dyn_array_scc_get_ptr (&sccs
, entry
->scc_index
), current_scc
);
606 scc_add_entry (current_scc
, entry
);
608 for (i
= 0; i
< dyn_array_ptr_size (&entry
->srcs
); ++i
)
609 dyn_array_ptr_push (&dfs_stack
, dyn_array_ptr_get (&entry
->srcs
, i
));
610 } while (dyn_array_ptr_size (&dfs_stack
) > 0);
614 compare_hash_entries (const HashEntry
*e1
, const HashEntry
*e2
)
616 return e2
->finishing_time
- e1
->finishing_time
;
619 DEF_QSORT_INLINE(hash_entries
, HashEntry
*, compare_hash_entries
)
621 static unsigned long step_1
, step_2
, step_3
, step_4
, step_5
, step_6
;
622 static int fist_pass_links
, second_pass_links
, sccs_links
;
623 static int max_sccs_links
= 0;
626 register_finalized_object (MonoObject
*obj
)
628 g_assert (sgen_need_bridge_processing ());
629 dyn_array_ptr_push (®istered_bridges
, obj
);
635 dyn_array_ptr_set_size (®istered_bridges
, 0);
639 processing_stw_step (void)
643 SGEN_TV_DECLARE (atv
);
644 SGEN_TV_DECLARE (btv
);
646 if (!dyn_array_ptr_size (®istered_bridges
))
649 SGEN_TV_GETTIME (btv
);
653 dyn_array_ptr_init (&dfs_stack
);
654 dyn_array_int_init (&merge_array
);
658 First we insert all bridges into the hash table and then we do dfs1.
660 It must be done in 2 steps since the bridge arrays doesn't come in reverse topological order,
661 which means that we can have entry N pointing to entry N + 1.
663 If we dfs1 entry N before N + 1 is registered we'll not consider N + 1 for this bridge
664 pass and not create the required xref between the two.
666 bridge_count
= dyn_array_ptr_size (®istered_bridges
);
667 for (i
= 0; i
< bridge_count
; ++i
)
668 register_bridge_object (dyn_array_ptr_get (®istered_bridges
, i
));
670 for (i
= 0; i
< bridge_count
; ++i
)
671 dfs1 (get_hash_entry (dyn_array_ptr_get (®istered_bridges
, i
), NULL
));
673 SGEN_TV_GETTIME (atv
);
674 step_2
= SGEN_TV_ELAPSED (btv
, atv
);
677 static int num_registered_bridges
, hash_table_size
;
680 processing_build_callback_data (int generation
)
683 int num_sccs
, num_xrefs
;
684 int max_entries
, max_xrefs
;
688 HashEntry
**all_entries
;
689 MonoGCBridgeSCC
**api_sccs
;
690 MonoGCBridgeXRef
*api_xrefs
;
691 SGEN_TV_DECLARE (atv
);
692 SGEN_TV_DECLARE (btv
);
694 g_assert (bridge_processor
->num_sccs
== 0 && bridge_processor
->num_xrefs
== 0);
695 g_assert (!bridge_processor
->api_sccs
&& !bridge_processor
->api_xrefs
);
697 if (!dyn_array_ptr_size (®istered_bridges
))
700 g_assert (bridge_processing_in_progress
);
702 SGEN_TV_GETTIME (atv
);
704 /* alloc and fill array of all entries */
706 all_entries
= sgen_alloc_internal_dynamic (sizeof (HashEntry
*) * hash_table
.num_entries
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
709 SGEN_HASH_TABLE_FOREACH (&hash_table
, obj
, entry
) {
710 g_assert (entry
->finishing_time
>= 0);
711 all_entries
[j
++] = entry
;
712 fist_pass_links
+= dyn_array_ptr_size (&entry
->srcs
);
713 } SGEN_HASH_TABLE_FOREACH_END
;
714 g_assert (j
== hash_table
.num_entries
);
715 hash_table_size
= hash_table
.num_entries
;
717 /* sort array according to decreasing finishing time */
718 qsort_hash_entries (all_entries
, hash_table
.num_entries
);
720 SGEN_TV_GETTIME (btv
);
721 step_3
= SGEN_TV_ELAPSED (atv
, btv
);
723 /* second DFS pass */
725 dyn_array_scc_init (&sccs
);
726 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
727 HashEntry
*entry
= all_entries
[i
];
728 if (entry
->scc_index
< 0) {
729 int index
= dyn_array_scc_size (&sccs
);
730 current_scc
= dyn_array_scc_add (&sccs
);
731 current_scc
->index
= index
;
732 current_scc
->num_bridge_entries
= 0;
733 current_scc
->api_index
= -1;
734 dyn_array_int_init (¤t_scc
->xrefs
);
741 * Compute the weight of each object. The weight of an object is its size plus the size of all
742 * objects it points do. When the an object is pointed by multiple objects we distribute it's weight
743 * equally among them. This distribution gives a rough estimate of the real impact of making the object
746 * The reasoning for this model is that complex graphs with single roots will have a bridge with very high
747 * value in comparison to others.
749 * The all_entries array has all objects topologically sorted. To correctly propagate the weights it must be
750 * done in reverse topological order - so we calculate the weight of the pointed-to objects before processing
751 * pointer-from objects.
753 * We log those objects in the opposite order for no particular reason. The other constrain is that it should use the same
754 * direction as the other logging loop that records live/dead information.
756 if (bridge_accounting_enabled
) {
757 for (i
= hash_table
.num_entries
- 1; i
>= 0; --i
) {
759 HashEntryWithAccounting
*entry
= (HashEntryWithAccounting
*)all_entries
[i
];
761 entry
->weight
+= (double)sgen_safe_object_get_size (entry
->entry
.obj
);
762 w
= entry
->weight
/ dyn_array_ptr_size (&entry
->entry
.srcs
);
763 for (j
= 0; j
< dyn_array_ptr_size (&entry
->entry
.srcs
); ++j
) {
764 HashEntryWithAccounting
*other
= (HashEntryWithAccounting
*)dyn_array_ptr_get (&entry
->entry
.srcs
, j
);
768 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
769 HashEntryWithAccounting
*entry
= (HashEntryWithAccounting
*)all_entries
[i
];
770 if (entry
->entry
.is_bridge
) {
771 MonoClass
*klass
= ((MonoVTable
*)SGEN_LOAD_VTABLE (entry
->entry
.obj
))->klass
;
772 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
);
777 sccs_size
= dyn_array_scc_size (&sccs
);
779 for (i
= 0; i
< hash_table
.num_entries
; ++i
) {
780 HashEntry
*entry
= all_entries
[i
];
781 second_pass_links
+= dyn_array_ptr_size (&entry
->srcs
);
784 SGEN_TV_GETTIME (atv
);
785 step_4
= SGEN_TV_ELAPSED (btv
, atv
);
787 //g_print ("%d sccs\n", sccs.size);
789 dyn_array_ptr_uninit (&dfs_stack
);
791 /* init data for callback */
794 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
795 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
796 g_assert (scc
->index
== i
);
797 if (scc
->num_bridge_entries
)
799 sccs_links
+= dyn_array_int_size (&scc
->xrefs
);
800 max_sccs_links
= MAX (max_sccs_links
, dyn_array_int_size (&scc
->xrefs
));
803 api_sccs
= sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC
*) * num_sccs
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
806 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
807 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
808 if (!scc
->num_bridge_entries
)
811 api_sccs
[j
] = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC
) + sizeof (MonoObject
*) * scc
->num_bridge_entries
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
812 api_sccs
[j
]->is_alive
= FALSE
;
813 api_sccs
[j
]->num_objs
= scc
->num_bridge_entries
;
814 scc
->num_bridge_entries
= 0;
815 scc
->api_index
= j
++;
817 num_xrefs
+= dyn_array_int_size (&scc
->xrefs
);
820 SGEN_HASH_TABLE_FOREACH (&hash_table
, obj
, entry
) {
821 if (entry
->is_bridge
) {
822 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, entry
->scc_index
);
823 api_sccs
[scc
->api_index
]->objs
[scc
->num_bridge_entries
++] = entry
->obj
;
825 } SGEN_HASH_TABLE_FOREACH_END
;
827 api_xrefs
= sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef
) * num_xrefs
, INTERNAL_MEM_BRIDGE_DATA
, TRUE
);
829 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
831 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
832 if (!scc
->num_bridge_entries
)
834 for (k
= 0; k
< dyn_array_int_size (&scc
->xrefs
); ++k
) {
835 SCC
*src_scc
= dyn_array_scc_get_ptr (&sccs
, dyn_array_int_get (&scc
->xrefs
, k
));
836 if (!src_scc
->num_bridge_entries
)
838 api_xrefs
[j
].src_scc_index
= src_scc
->api_index
;
839 api_xrefs
[j
].dst_scc_index
= scc
->api_index
;
844 SGEN_TV_GETTIME (btv
);
845 step_5
= SGEN_TV_ELAPSED (atv
, btv
);
850 max_entries
= max_xrefs
= 0;
851 for (i
= 0; i
< dyn_array_scc_size (&sccs
); ++i
) {
852 SCC
*scc
= dyn_array_scc_get_ptr (&sccs
, i
);
853 if (scc
->num_bridge_entries
)
855 if (scc
->num_bridge_entries
> max_entries
)
856 max_entries
= scc
->num_bridge_entries
;
857 if (dyn_array_int_size (&scc
->xrefs
) > max_xrefs
)
858 max_xrefs
= dyn_array_int_size (&scc
->xrefs
);
859 dyn_array_int_uninit (&scc
->xrefs
);
862 dyn_array_scc_uninit (&sccs
);
864 sgen_free_internal_dynamic (all_entries
, sizeof (HashEntry
*) * hash_table
.num_entries
, INTERNAL_MEM_BRIDGE_DATA
);
867 /* Empty the registered bridges array */
868 num_registered_bridges
= dyn_array_ptr_size (®istered_bridges
);
869 dyn_array_ptr_set_size (®istered_bridges
, 0);
871 SGEN_TV_GETTIME (atv
);
872 step_6
= SGEN_TV_ELAPSED (btv
, atv
);
874 //g_print ("%d sccs containing bridges - %d max bridge objects - %d max xrefs\n", j, max_entries, max_xrefs);
876 bridge_processor
->num_sccs
= num_sccs
;
877 bridge_processor
->api_sccs
= api_sccs
;
878 bridge_processor
->num_xrefs
= num_xrefs
;
879 bridge_processor
->api_xrefs
= api_xrefs
;
883 processing_after_callback (int generation
)
886 int num_sccs
= bridge_processor
->num_sccs
;
887 MonoGCBridgeSCC
**api_sccs
= bridge_processor
->api_sccs
;
889 if (bridge_accounting_enabled
) {
890 for (i
= 0; i
< num_sccs
; ++i
) {
891 for (j
= 0; j
< api_sccs
[i
]->num_objs
; ++j
)
892 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
,
893 "OBJECT %s (%p) SCC [%d] %s",
894 sgen_safe_name (api_sccs
[i
]->objs
[j
]), api_sccs
[i
]->objs
[j
],
896 api_sccs
[i
]->is_alive
? "ALIVE" : "DEAD");
900 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",
901 num_registered_bridges
, hash_table_size
, dyn_array_scc_size (&sccs
),
908 fist_pass_links
, second_pass_links
, sccs_links
, max_sccs_links
,
909 dfs1_passes
, dfs2_passes
);
911 step_1
= 0; /* We must cleanup since this value is used as an accumulator. */
912 fist_pass_links
= second_pass_links
= sccs_links
= max_sccs_links
= 0;
913 dfs1_passes
= dfs2_passes
= 0;
917 describe_pointer (MonoObject
*obj
)
922 for (i
= 0; i
< dyn_array_ptr_size (®istered_bridges
); ++i
) {
923 if (obj
== dyn_array_ptr_get (®istered_bridges
, i
)) {
924 printf ("Pointer is a registered bridge object.\n");
929 entry
= sgen_hash_table_lookup (&hash_table
, obj
);
933 printf ("Bridge hash table entry %p:\n", entry
);
934 printf (" is bridge: %d\n", (int)entry
->is_bridge
);
935 printf (" is visited: %d\n", (int)entry
->is_visited
);
939 sgen_old_bridge_init (SgenBridgeProcessor
*collector
)
941 collector
->reset_data
= reset_data
;
942 collector
->processing_stw_step
= processing_stw_step
;
943 collector
->processing_build_callback_data
= processing_build_callback_data
;
944 collector
->processing_after_callback
= processing_after_callback
;
945 collector
->class_kind
= class_kind
;
946 collector
->register_finalized_object
= register_finalized_object
;
947 collector
->describe_pointer
= describe_pointer
;
948 collector
->enable_accounting
= enable_accounting
;
950 bridge_processor
= collector
;