2 * sgen-bridge.c: Simple generational GC.
4 * Copyright 2011 Novell, Inc (http://www.novell.com)
6 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
9 * Permission is hereby granted to use or copy this program
10 * for any purpose, provided the above notices are retained on all copies.
11 * Permission to modify the code and to distribute modified code is granted,
12 * provided the above notices are retained, and a notice that the code was
13 * modified is included with the above copyright notice.
16 * Copyright 2001-2003 Ximian, Inc
17 * Copyright 2003-2010 Novell, Inc.
19 * Permission is hereby granted, free of charge, to any person obtaining
20 * a copy of this software and associated documentation files (the
21 * "Software"), to deal in the Software without restriction, including
22 * without limitation the rights to use, copy, modify, merge, publish,
23 * distribute, sublicense, and/or sell copies of the Software, and to
24 * permit persons to whom the Software is furnished to do so, subject to
25 * the following conditions:
27 * The above copyright notice and this permission notice shall be
28 * included in all copies or substantial portions of the Software.
30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44 #include "sgen-bridge.h"
45 #include "utils/mono-logger-internal.h"
46 #include "utils/mono-time.h"
56 #define DYN_ARRAY_REF(da,i) ((void*)((da)->data + (i) * (da)->elem_size))
57 #define DYN_ARRAY_PTR_REF(da,i) (((void**)(da)->data) [(i)])
58 #define DYN_ARRAY_INT_REF(da,i) (((int*)(da)->data) [(i)])
59 #define DYN_ARRAY_PTR_STATIC_INITIALIZER { 0, sizeof (void*), 0, NULL }
60 #define DYN_ARRAY_INT_STATIC_INITIALIZER { 0, sizeof (int), 0, NULL }
63 dyn_array_init (DynArray
*da
, int elem_size
)
66 da
->elem_size
= elem_size
;
72 dyn_array_ptr_init (DynArray
*da
)
74 dyn_array_init (da
, sizeof (void*));
78 dyn_array_int_init (DynArray
*da
)
80 dyn_array_init (da
, sizeof (int));
84 dyn_array_uninit (DynArray
*da
)
86 if (da
->capacity
<= 0)
89 mono_sgen_free_internal_dynamic (da
->data
, da
->elem_size
* da
->capacity
, INTERNAL_MEM_BRIDGE_DATA
);
94 dyn_array_ensure_capacity (DynArray
*da
, int capacity
)
96 int old_capacity
= da
->capacity
;
99 if (capacity
<= old_capacity
)
102 if (da
->capacity
== 0)
104 while (capacity
> da
->capacity
)
107 new_data
= mono_sgen_alloc_internal_dynamic (da
->elem_size
* da
->capacity
, INTERNAL_MEM_BRIDGE_DATA
);
108 memcpy (new_data
, da
->data
, da
->elem_size
* da
->size
);
109 mono_sgen_free_internal_dynamic (da
->data
, da
->elem_size
* old_capacity
, INTERNAL_MEM_BRIDGE_DATA
);
114 dyn_array_add (DynArray
*da
)
118 dyn_array_ensure_capacity (da
, da
->size
+ 1);
120 p
= DYN_ARRAY_REF (da
, da
->size
);
126 dyn_array_ptr_add (DynArray
*da
, void *ptr
)
128 void **p
= dyn_array_add (da
);
132 #define dyn_array_ptr_push dyn_array_ptr_add
135 dyn_array_ptr_pop (DynArray
*da
)
138 g_assert (da
->size
> 0);
139 p
= DYN_ARRAY_PTR_REF (da
, da
->size
- 1);
145 dyn_array_int_add (DynArray
*da
, int x
)
147 int *p
= dyn_array_add (da
);
153 dyn_array_ptr_contains (DynArray *da, void *ptr)
156 for (i = 0; i < da->size; ++i)
157 if (DYN_ARRAY_PTR_REF (da, i) == ptr)
164 dyn_array_int_contains (DynArray
*da
, int x
)
167 for (i
= 0; i
< da
->size
; ++i
)
168 if (DYN_ARRAY_INT_REF (da
, i
) == x
)
173 static DynArray merge_array
;
176 dyn_array_int_merge (DynArray
*dst
, DynArray
*src
)
180 dyn_array_ensure_capacity (&merge_array
, dst
->size
+ src
->size
);
181 merge_array
.size
= 0;
183 for (i
= j
= 0; i
< dst
->size
|| j
< src
->size
; ) {
184 if (i
< dst
->size
&& j
< src
->size
) {
185 int a
= DYN_ARRAY_INT_REF (dst
, i
);
186 int b
= DYN_ARRAY_INT_REF (src
, j
);
188 dyn_array_int_add (&merge_array
, a
);
191 dyn_array_int_add (&merge_array
, a
);
195 dyn_array_int_add (&merge_array
, b
);
198 } else if (i
< dst
->size
) {
199 dyn_array_int_add (&merge_array
, DYN_ARRAY_INT_REF (dst
, i
));
202 dyn_array_int_add (&merge_array
, DYN_ARRAY_INT_REF (src
, j
));
207 if (merge_array
.size
> dst
->size
) {
208 dyn_array_ensure_capacity (dst
, merge_array
.size
);
209 memcpy (DYN_ARRAY_REF (dst
, 0), DYN_ARRAY_REF (&merge_array
, 0), merge_array
.size
* merge_array
.elem_size
);
210 dst
->size
= merge_array
.size
;
215 dyn_array_int_merge_one (DynArray
*array
, int value
)
219 int end
= array
->size
;
221 for (i
= 0; i
< end
; ++i
) {
222 if (DYN_ARRAY_INT_REF (array
, i
) == value
)
224 else if (DYN_ARRAY_INT_REF (array
, i
) > value
)
228 dyn_array_ensure_capacity (array
, array
->size
+ 1);
231 tmp
= DYN_ARRAY_INT_REF (array
, i
);
232 for (; i
<= end
; ++i
) {
233 DYN_ARRAY_INT_REF (array
, i
) = value
;
235 tmp
= DYN_ARRAY_INT_REF (array
, i
+ 1);
237 DYN_ARRAY_INT_REF (array
, end
+ 1) = tmp
;
239 DYN_ARRAY_INT_REF (array
, end
) = value
;
245 * FIXME: Optimizations:
247 * Don't allocate a scrs array for just one source. Most objects have
248 * just one source, so use the srcs pointer itself.
250 typedef struct _HashEntry
{
261 struct _HashEntry
*next
;
264 typedef struct _SCC
{
267 int num_bridge_entries
;
268 DynArray xrefs
; /* these are incoming, not outgoing */
271 static int num_hash_entries
= 0;
272 static int hash_size
= 0;
273 static HashEntry
**hash_table
= NULL
;
275 static MonoGCBridgeCallbacks bridge_callbacks
;
277 static int current_time
;
280 mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks
*callbacks
)
282 bridge_callbacks
= *callbacks
;
286 mono_sgen_need_bridge_processing (void)
288 return bridge_callbacks
.cross_references
!= NULL
;
292 alloc_hash_table (int size
)
295 table
= mono_sgen_alloc_internal_dynamic (sizeof (HashEntry
*) * size
, INTERNAL_MEM_BRIDGE_DATA
);
296 memset (table
, 0, sizeof (HashEntry
*) * size
);
303 HashEntry
**new_table
;
304 int new_size
= hash_size
<< 1;
307 new_table
= alloc_hash_table (new_size
);
308 for (i
= 0; i
< hash_size
; ++i
) {
309 HashEntry
*entry
= hash_table
[i
];
310 while (entry
!= NULL
) {
311 HashEntry
*next
= entry
->next
;
312 int hash
= ((mword
)entry
->obj
>> 4) & (new_size
- 1);
313 entry
->next
= new_table
[hash
];
314 new_table
[hash
] = entry
;
319 mono_sgen_free_internal_dynamic (hash_table
, sizeof (HashEntry
*) * hash_size
, INTERNAL_MEM_BRIDGE_DATA
);
321 hash_table
= new_table
;
322 hash_size
= new_size
;
326 lookup_hash_entry (MonoObject
*obj
)
328 int hash
= (mword
)obj
>> 4;
332 g_assert (hash_size
== 0 && num_hash_entries
== 0);
334 hash_table
= alloc_hash_table (hash_size
);
337 hash
&= hash_size
- 1;
338 for (entry
= hash_table
[hash
]; entry
!= NULL
; entry
= entry
->next
) {
339 if (entry
->obj
== obj
)
347 get_hash_entry (MonoObject
*obj
, gboolean
*existing
)
349 HashEntry
*entry
= lookup_hash_entry (obj
);
360 entry
= mono_sgen_alloc_internal_dynamic (sizeof (HashEntry
), INTERNAL_MEM_BRIDGE_DATA
);
361 memset (entry
, 0, sizeof (HashEntry
));
364 dyn_array_ptr_init (&entry
->srcs
);
365 entry
->finishing_time
= -1;
366 entry
->scc_index
= -1;
368 hash
= ((mword
)obj
>> 4) & (hash_size
- 1);
369 entry
->next
= hash_table
[hash
];
370 hash_table
[hash
] = entry
;
374 if (num_hash_entries
> hash_size
>> 1)
381 add_source (HashEntry
*entry
, HashEntry
*src
)
383 dyn_array_ptr_add (&entry
->srcs
, src
);
393 if (hash_table
== NULL
)
396 for (i
= 0; i
< hash_size
; ++i
) {
397 HashEntry
*entry
= hash_table
[i
];
398 while (entry
!= NULL
) {
399 HashEntry
*next
= entry
->next
;
400 total_srcs
+= entry
->srcs
.size
;
401 if (entry
->srcs
.size
> max_srcs
)
402 max_srcs
= entry
->srcs
.size
;
403 dyn_array_uninit (&entry
->srcs
);
404 mono_sgen_free_internal_dynamic (entry
, sizeof (HashEntry
), INTERNAL_MEM_BRIDGE_DATA
);
409 mono_sgen_free_internal_dynamic (hash_table
, sizeof (HashEntry
*) * hash_size
, INTERNAL_MEM_BRIDGE_DATA
);
412 num_hash_entries
= 0;
415 dyn_array_uninit (&merge_array
);
416 //g_print ("total srcs %d - max %d\n", total_srcs, max_srcs);
420 register_bridge_object (MonoObject
*obj
)
423 HashEntry
*entry
= get_hash_entry (obj
, &existing
);
424 entry
->is_bridge
= TRUE
;
429 register_finishing_time (HashEntry
*entry
, int t
)
431 g_assert (entry
->finishing_time
< 0);
432 entry
->finishing_time
= t
;
436 object_is_live (MonoObject
**objp
)
438 MonoObject
*obj
= *objp
;
439 MonoObject
*fwd
= SGEN_OBJECT_IS_FORWARDED (obj
);
442 return lookup_hash_entry (fwd
) == NULL
;
444 if (!mono_sgen_object_is_live (obj
))
446 return lookup_hash_entry (obj
) == NULL
;
449 static DynArray registered_bridges
= DYN_ARRAY_PTR_STATIC_INITIALIZER
;
450 static DynArray dfs_stack
;
452 static int dsf1_passes
, dsf2_passes
;
456 #define HANDLE_PTR(ptr,obj) do { \
457 MonoObject *dst = (MonoObject*)*(ptr); \
458 if (dst && !object_is_live (&dst)) { \
459 dyn_array_ptr_push (&dfs_stack, obj_entry); \
460 dyn_array_ptr_push (&dfs_stack, get_hash_entry (dst, NULL)); \
465 dfs1 (HashEntry
*obj_entry
, HashEntry
*src
)
467 g_assert (dfs_stack
.size
== 0);
469 dyn_array_ptr_push (&dfs_stack
, src
);
470 dyn_array_ptr_push (&dfs_stack
, obj_entry
);
477 obj_entry
= dyn_array_ptr_pop (&dfs_stack
);
479 src
= dyn_array_ptr_pop (&dfs_stack
);
481 obj
= obj_entry
->obj
;
485 //g_print ("link %s -> %s\n", mono_sgen_safe_name (src->obj), mono_sgen_safe_name (obj));
486 add_source (obj_entry
, src
);
488 //g_print ("starting with %s\n", mono_sgen_safe_name (obj));
491 if (obj_entry
->is_visited
)
494 obj_entry
->is_visited
= TRUE
;
496 dyn_array_ptr_push (&dfs_stack
, obj_entry
);
497 /* NULL marks that the next entry is to be finished */
498 dyn_array_ptr_push (&dfs_stack
, NULL
);
500 #include "sgen-scan-object.h"
502 obj_entry
= dyn_array_ptr_pop (&dfs_stack
);
504 //g_print ("finish %s\n", mono_sgen_safe_name (obj_entry->obj));
505 register_finishing_time (obj_entry
, current_time
++);
507 } while (dfs_stack
.size
> 0);
511 scc_add_xref (SCC
*src
, SCC
*dst
)
513 g_assert (src
!= dst
);
514 g_assert (src
->index
!= dst
->index
);
516 if (dyn_array_int_contains (&dst
->xrefs
, src
->index
))
518 if (src
->num_bridge_entries
) {
519 dyn_array_int_merge_one (&dst
->xrefs
, src
->index
);
522 dyn_array_int_merge (&dst
->xrefs
, &src
->xrefs
);
523 for (i
= 0; i
< dst
->xrefs
.size
; ++i
)
524 g_assert (DYN_ARRAY_INT_REF (&dst
->xrefs
, i
) != dst
->index
);
529 scc_add_entry (SCC
*scc
, HashEntry
*entry
)
531 g_assert (entry
->scc_index
< 0);
532 entry
->scc_index
= scc
->index
;
533 if (entry
->is_bridge
)
534 ++scc
->num_bridge_entries
;
537 static DynArray sccs
;
538 static SCC
*current_scc
;
541 dfs2 (HashEntry
*entry
)
545 g_assert (dfs_stack
.size
== 0);
547 dyn_array_ptr_push (&dfs_stack
, entry
);
550 entry
= dyn_array_ptr_pop (&dfs_stack
);
553 if (entry
->scc_index
>= 0) {
554 if (entry
->scc_index
!= current_scc
->index
)
555 scc_add_xref (DYN_ARRAY_REF (&sccs
, entry
->scc_index
), current_scc
);
559 scc_add_entry (current_scc
, entry
);
561 for (i
= 0; i
< entry
->srcs
.size
; ++i
)
562 dyn_array_ptr_push (&dfs_stack
, DYN_ARRAY_PTR_REF (&entry
->srcs
, i
));
563 } while (dfs_stack
.size
> 0);
567 compare_hash_entries (const void *ep1
, const void *ep2
)
569 HashEntry
*e1
= *(HashEntry
**)ep1
;
570 HashEntry
*e2
= *(HashEntry
**)ep2
;
571 return e2
->finishing_time
- e1
->finishing_time
;
575 mono_sgen_is_bridge_object (MonoObject
*obj
)
577 return bridge_callbacks
.is_bridge_object (obj
);
580 static unsigned long step_1
, step_2
, step_3
, step_4
, step_5
, step_6
, step_7
, step_8
;
581 static int fist_pass_links
, second_pass_links
, sccs_links
;
582 static int max_sccs_links
= 0;
585 mono_sgen_bridge_processing_register_objects (int num_objs
, MonoObject
**objs
)
589 SGEN_TV_DECLARE (atv
);
590 SGEN_TV_DECLARE (btv
);
592 fist_pass_links
= second_pass_links
= sccs_links
= 0;
593 dsf1_passes
= dsf2_passes
= 0;
594 SGEN_TV_GETTIME (atv
);
596 g_assert (mono_sgen_need_bridge_processing ());
598 //g_print ("%d finalized objects\n", num_objs);
600 /* The collector step checks for bridge objects already, so we don't need to do it again. */
601 for (i
= 0; i
< num_objs
; ++i
) {
602 MonoObject
*obj
= objs
[i
];
603 if (register_bridge_object (obj
))
604 dyn_array_ptr_push (®istered_bridges
, obj
);
607 SGEN_TV_GETTIME (btv
);
608 step_1
+= SGEN_TV_ELAPSED (atv
, btv
);
612 mono_sgen_bridge_processing_stw_step (void)
615 SGEN_TV_DECLARE (atv
);
616 SGEN_TV_DECLARE (btv
);
618 if (!registered_bridges
.size
)
621 SGEN_TV_GETTIME (btv
);
625 dyn_array_ptr_init (&dfs_stack
);
626 dyn_array_int_init (&merge_array
);
629 for (i
= 0; i
< registered_bridges
.size
; ++i
)
630 dfs1 (get_hash_entry (DYN_ARRAY_PTR_REF (®istered_bridges
, i
), NULL
), NULL
);
632 SGEN_TV_GETTIME (atv
);
633 step_2
= SGEN_TV_ELAPSED (btv
, atv
);
637 mono_sgen_bridge_processing_finish (void)
640 int num_sccs
, num_xrefs
;
641 int max_entries
, max_xrefs
;
642 int hash_table_size
, sccs_size
;
645 int num_registered_bridges
;
646 HashEntry
**all_entries
;
647 MonoGCBridgeSCC
**api_sccs
;
648 MonoGCBridgeXRef
*api_xrefs
;
649 SGEN_TV_DECLARE (atv
);
650 SGEN_TV_DECLARE (btv
);
652 if (!registered_bridges
.size
)
655 SGEN_TV_GETTIME (atv
);
657 /* alloc and fill array of all entries */
659 all_entries
= mono_sgen_alloc_internal_dynamic (sizeof (HashEntry
*) * num_hash_entries
, INTERNAL_MEM_BRIDGE_DATA
);
663 for (i
= 0; i
< hash_size
; ++i
) {
666 for (entry
= hash_table
[i
]; entry
!= NULL
; entry
= entry
->next
) {
667 g_assert (entry
->finishing_time
>= 0);
668 all_entries
[j
++] = entry
;
670 fist_pass_links
+= entry
->srcs
.size
;
672 if (length
> max_entries
)
673 max_entries
= length
;
675 g_assert (j
== num_hash_entries
);
676 hash_table_size
= num_hash_entries
;
678 //g_print ("max hash bucket length %d\n", max_entries);
680 /* sort array according to decreasing finishing time */
682 qsort (all_entries
, num_hash_entries
, sizeof (HashEntry
*), compare_hash_entries
);
684 SGEN_TV_GETTIME (btv
);
685 step_3
= SGEN_TV_ELAPSED (atv
, btv
);
687 /* second DFS pass */
689 dyn_array_init (&sccs
, sizeof (SCC
));
690 for (i
= 0; i
< num_hash_entries
; ++i
) {
691 HashEntry
*entry
= all_entries
[i
];
692 if (entry
->scc_index
< 0) {
693 int index
= sccs
.size
;
694 current_scc
= dyn_array_add (&sccs
);
695 current_scc
->index
= index
;
696 current_scc
->num_bridge_entries
= 0;
697 current_scc
->api_index
= -1;
698 dyn_array_int_init (¤t_scc
->xrefs
);
704 sccs_size
= sccs
.size
;
706 for (i
= 0; i
< num_hash_entries
; ++i
) {
707 HashEntry
*entry
= all_entries
[i
];
708 second_pass_links
+= entry
->srcs
.size
;
711 SGEN_TV_GETTIME (atv
);
712 step_4
= SGEN_TV_ELAPSED (btv
, atv
);
714 //g_print ("%d sccs\n", sccs.size);
716 dyn_array_uninit (&dfs_stack
);
718 /* init data for callback */
721 for (i
= 0; i
< sccs
.size
; ++i
) {
722 SCC
*scc
= DYN_ARRAY_REF (&sccs
, i
);
723 g_assert (scc
->index
== i
);
724 if (scc
->num_bridge_entries
)
726 sccs_links
+= scc
->xrefs
.size
;
727 max_sccs_links
= MAX (max_sccs_links
, scc
->xrefs
.size
);
730 api_sccs
= mono_sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC
*) * num_sccs
, INTERNAL_MEM_BRIDGE_DATA
);
733 for (i
= 0; i
< sccs
.size
; ++i
) {
734 SCC
*scc
= DYN_ARRAY_REF (&sccs
, i
);
735 if (!scc
->num_bridge_entries
)
738 api_sccs
[j
] = mono_sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC
) + sizeof (MonoObject
*) * scc
->num_bridge_entries
, INTERNAL_MEM_BRIDGE_DATA
);
739 api_sccs
[j
]->num_objs
= scc
->num_bridge_entries
;
740 scc
->num_bridge_entries
= 0;
741 scc
->api_index
= j
++;
743 num_xrefs
+= scc
->xrefs
.size
;
746 for (i
= 0; i
< hash_size
; ++i
) {
748 for (entry
= hash_table
[i
]; entry
!= NULL
; entry
= entry
->next
) {
750 if (!entry
->is_bridge
)
752 scc
= DYN_ARRAY_REF (&sccs
, entry
->scc_index
);
753 api_sccs
[scc
->api_index
]->objs
[scc
->num_bridge_entries
++] = entry
->obj
;
757 api_xrefs
= mono_sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef
) * num_xrefs
, INTERNAL_MEM_BRIDGE_DATA
);
759 for (i
= 0; i
< sccs
.size
; ++i
) {
761 SCC
*scc
= DYN_ARRAY_REF (&sccs
, i
);
762 if (!scc
->num_bridge_entries
)
764 for (k
= 0; k
< scc
->xrefs
.size
; ++k
) {
765 SCC
*src_scc
= DYN_ARRAY_REF (&sccs
, DYN_ARRAY_INT_REF (&scc
->xrefs
, k
));
766 if (!src_scc
->num_bridge_entries
)
768 api_xrefs
[j
].src_scc_index
= src_scc
->api_index
;
769 api_xrefs
[j
].dst_scc_index
= scc
->api_index
;
774 SGEN_TV_GETTIME (btv
);
775 step_5
= SGEN_TV_ELAPSED (atv
, btv
);
780 max_entries
= max_xrefs
= 0;
781 for (i
= 0; i
< sccs
.size
; ++i
) {
782 SCC
*scc
= DYN_ARRAY_REF (&sccs
, i
);
783 if (scc
->num_bridge_entries
)
785 if (scc
->num_bridge_entries
> max_entries
)
786 max_entries
= scc
->num_bridge_entries
;
787 if (scc
->xrefs
.size
> max_xrefs
)
788 max_xrefs
= scc
->xrefs
.size
;
789 dyn_array_uninit (&scc
->xrefs
);
792 dyn_array_uninit (&sccs
);
794 mono_sgen_free_internal_dynamic (all_entries
, sizeof (HashEntry
*) * num_hash_entries
, INTERNAL_MEM_BRIDGE_DATA
);
797 /* Empty the registered bridges array */
798 num_registered_bridges
= registered_bridges
.size
;
799 registered_bridges
.size
= 0;
801 SGEN_TV_GETTIME (atv
);
802 step_6
= SGEN_TV_ELAPSED (btv
, atv
);
804 //g_print ("%d sccs containing bridges - %d max bridge objects - %d max xrefs\n", j, max_entries, max_xrefs);
808 bridge_callbacks
.cross_references (num_sccs
, api_sccs
, num_xrefs
, api_xrefs
);
810 SGEN_TV_GETTIME (btv
);
811 step_7
= SGEN_TV_ELAPSED (atv
, btv
);
813 /*Release for finalization those objects we no longer care. */
814 for (i
= 0; i
< num_sccs
; ++i
) {
815 if (!api_sccs
[i
]->objs
[0])
817 for (j
= 0; j
< api_sccs
[i
]->num_objs
; ++j
)
818 mono_sgen_mark_bridge_object (api_sccs
[i
]->objs
[j
]);
821 /* free callback data */
823 for (i
= 0; i
< num_sccs
; ++i
) {
824 mono_sgen_free_internal_dynamic (api_sccs
[i
],
825 sizeof (MonoGCBridgeSCC
) + sizeof (MonoObject
*) * api_sccs
[i
]->num_objs
,
826 INTERNAL_MEM_BRIDGE_DATA
);
828 mono_sgen_free_internal_dynamic (api_sccs
, sizeof (MonoGCBridgeSCC
*) * num_sccs
, INTERNAL_MEM_BRIDGE_DATA
);
830 mono_sgen_free_internal_dynamic (api_xrefs
, sizeof (MonoGCBridgeXRef
) * num_xrefs
, INTERNAL_MEM_BRIDGE_DATA
);
832 SGEN_TV_GETTIME (atv
);
833 step_8
= SGEN_TV_ELAPSED (btv
, atv
);
835 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
, "GC_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 user-cb %.2fms clenanup %.2fms links %d/%d/%d/%d dfs passes %d/%d",
836 num_registered_bridges
, hash_table_size
, sccs
.size
,
845 fist_pass_links
, second_pass_links
, sccs_links
, max_sccs_links
,
846 dsf1_passes
, dsf2_passes
);
848 step_1
= 0; /* We must cleanup since this value is used as an accumulator. */
852 bridge_test_is_bridge_object (MonoObject
*obj
)
858 bridge_test_cross_reference (int num_sccs
, MonoGCBridgeSCC
**sccs
, int num_xrefs
, MonoGCBridgeXRef
*xrefs
)
861 for (i
= 0; i
< num_sccs
; ++i
) {
863 g_print ("--- SCC %d\n", i
);
864 for (j
= 0; j
< sccs
[i
]->num_objs
; ++j
)
865 g_print (" %s\n", mono_sgen_safe_name (sccs
[i
]->objs
[j
]));
867 for (i
= 0; i
< num_xrefs
; ++i
) {
868 g_assert (xrefs
[i
].src_scc_index
>= 0 && xrefs
[i
].src_scc_index
< num_sccs
);
869 g_assert (xrefs
[i
].dst_scc_index
>= 0 && xrefs
[i
].dst_scc_index
< num_sccs
);
870 g_print ("%d -> %d\n", xrefs
[i
].src_scc_index
, xrefs
[i
].dst_scc_index
);
876 mono_sgen_register_test_bridge_callbacks (void)
878 MonoGCBridgeCallbacks callbacks
;
879 callbacks
.is_bridge_object
= bridge_test_is_bridge_object
;
880 callbacks
.cross_references
= bridge_test_cross_reference
;
881 mono_gc_register_bridge_callbacks (&callbacks
);