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.
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "sgen/sgen-gc.h"
20 #include "sgen-bridge-internals.h"
21 #include "sgen/sgen-hash-table.h"
22 #include "sgen/sgen-qsort.h"
23 #include "utils/mono-logger-internals.h"
25 #ifndef DISABLE_SGEN_GC_BRIDGE
28 BRIDGE_PROCESSOR_INVALID
,
31 BRIDGE_PROCESSOR_TARJAN
,
32 BRIDGE_PROCESSOR_DEFAULT
= BRIDGE_PROCESSOR_TARJAN
33 } BridgeProcessorSelection
;
35 // Bridge processor type pending / in use
36 static BridgeProcessorSelection bridge_processor_selection
= BRIDGE_PROCESSOR_DEFAULT
;
37 // Most recently requested callbacks
38 static MonoGCBridgeCallbacks pending_bridge_callbacks
;
39 // Configuration to be passed to bridge processor after init
40 static SgenBridgeProcessorConfig bridge_processor_config
;
41 // Currently-in-use callbacks
42 MonoGCBridgeCallbacks mono_bridge_callbacks
;
44 // Bridge processor state
45 static SgenBridgeProcessor bridge_processor
;
46 // This is used for a special debug feature
47 static SgenBridgeProcessor compare_to_bridge_processor
;
49 volatile gboolean mono_bridge_processing_in_progress
= FALSE
;
51 // FIXME: The current usage pattern for this function is unsafe. Bridge processing could start immediately after unlock
53 * mono_gc_wait_for_bridge_processing:
56 mono_gc_wait_for_bridge_processing (void)
58 if (!mono_bridge_processing_in_progress
)
61 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
, "GC_BRIDGE waiting for bridge processing to finish");
68 * mono_gc_register_bridge_callbacks:
71 mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks
*callbacks
)
73 if (callbacks
->bridge_version
!= SGEN_BRIDGE_VERSION
)
74 g_error ("Invalid bridge callback version. Expected %d but got %d\n", SGEN_BRIDGE_VERSION
, callbacks
->bridge_version
);
76 // Defer assigning to bridge_callbacks until we have the gc lock.
77 // Note: This line is unsafe if we are on a separate thread from the one the runtime was initialized on.
78 pending_bridge_callbacks
= *callbacks
;
80 // If sgen has started, will assign bridge callbacks and init bridge
84 static BridgeProcessorSelection
85 bridge_processor_name (const char *name
)
87 if (!strcmp ("old", name
)) {
88 return BRIDGE_PROCESSOR_OLD
;
89 } else if (!strcmp ("new", name
)) {
90 return BRIDGE_PROCESSOR_NEW
;
91 } else if (!strcmp ("tarjan", name
)) {
92 return BRIDGE_PROCESSOR_TARJAN
;
94 return BRIDGE_PROCESSOR_INVALID
;
99 bridge_processor_started (void)
101 return bridge_processor
.reset_data
!= NULL
;
104 // Initialize a single bridge processor
106 init_bridge_processor (SgenBridgeProcessor
*processor
, BridgeProcessorSelection selection
)
108 memset (processor
, 0, sizeof (SgenBridgeProcessor
));
111 case BRIDGE_PROCESSOR_OLD
:
112 sgen_old_bridge_init (processor
);
114 case BRIDGE_PROCESSOR_NEW
:
115 sgen_new_bridge_init (processor
);
117 case BRIDGE_PROCESSOR_TARJAN
:
118 sgen_tarjan_bridge_init (processor
);
121 g_assert_not_reached ();
126 * Initializing the sgen bridge consists of setting the bridge callbacks,
127 * and initializing the bridge processor. Init should follow these rules:
129 * - Init happens only after sgen is initialized (because we don't
130 * know which bridge processor to initialize until then, and also
131 * to allow bridge processor init to interact with sgen if it wants)
133 * - Init happens only after mono_gc_register_bridge_callbacks is called
135 * - Init should not happen concurrently with a GC (because a GC will
136 * call sgen_need_bridge_processing at various times)
138 * - Initializing the bridge processor should happen only once
140 * We call sgen_init_bridge when the callbacks are set, and also when sgen
141 * is done initing. Actual initialization then only occurs if it is ready.
144 sgen_init_bridge (void)
146 if (sgen_gc_initialized ()) {
147 // This lock is not initialized until the GC is
150 mono_bridge_callbacks
= pending_bridge_callbacks
;
152 // If a bridge was registered but there is no bridge processor yet
153 if (mono_bridge_callbacks
.cross_references
&& !bridge_processor_started ()) {
154 init_bridge_processor (&bridge_processor
, bridge_processor_selection
);
156 if (bridge_processor
.set_config
)
157 bridge_processor
.set_config (&bridge_processor_config
);
159 // Config is no longer needed so free its memory
160 free (bridge_processor_config
.dump_prefix
);
161 bridge_processor_config
.dump_prefix
= NULL
;
169 sgen_set_bridge_implementation (const char *name
)
171 BridgeProcessorSelection selection
= bridge_processor_name (name
);
173 if (selection
== BRIDGE_PROCESSOR_INVALID
)
174 g_warning ("Invalid value for bridge processor implementation, valid values are: 'new', 'old' and 'tarjan'.");
175 else if (bridge_processor_started ())
176 g_warning ("Cannot set bridge processor implementation once bridge has already started");
178 bridge_processor_selection
= selection
;
182 sgen_is_bridge_object (GCObject
*obj
)
184 if ((obj
->vtable
->gc_bits
& SGEN_GC_BIT_BRIDGE_OBJECT
) != SGEN_GC_BIT_BRIDGE_OBJECT
)
186 return mono_bridge_callbacks
.is_bridge_object (obj
);
190 sgen_need_bridge_processing (void)
192 return mono_bridge_callbacks
.cross_references
!= NULL
;
196 compare_bridge_processors (void)
198 return compare_to_bridge_processor
.reset_data
!= NULL
;
201 /* Dispatch wrappers */
203 sgen_bridge_reset_data (void)
205 bridge_processor
.reset_data ();
206 if (compare_bridge_processors ())
207 compare_to_bridge_processor
.reset_data ();
211 sgen_bridge_processing_stw_step (void)
214 * mono_bridge_processing_in_progress must be set with the world
215 * stopped. If not there would be race conditions.
217 mono_bridge_processing_in_progress
= TRUE
;
219 bridge_processor
.processing_stw_step ();
220 if (compare_bridge_processors ())
221 compare_to_bridge_processor
.processing_stw_step ();
225 is_bridge_object_dead (GCObject
*obj
, void *data
)
227 SgenHashTable
*table
= (SgenHashTable
*)data
;
228 unsigned char *value
= (unsigned char *)sgen_hash_table_lookup (table
, obj
);
235 null_weak_links_to_dead_objects (SgenBridgeProcessor
*processor
, int generation
)
238 int num_sccs
= processor
->num_sccs
;
239 MonoGCBridgeSCC
**api_sccs
= processor
->api_sccs
;
240 SgenHashTable alive_hash
= SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE
, INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE_ENTRY
, 1, mono_aligned_addr_hash
, NULL
);
242 for (i
= 0; i
< num_sccs
; ++i
) {
243 unsigned char alive
= api_sccs
[i
]->is_alive
? 1 : 0;
244 for (j
= 0; j
< api_sccs
[i
]->num_objs
; ++j
) {
245 /* Build hash table for nulling weak links. */
246 sgen_hash_table_replace (&alive_hash
, api_sccs
[i
]->objs
[j
], &alive
, NULL
);
248 /* Release for finalization those objects we no longer care. */
249 if (!api_sccs
[i
]->is_alive
)
250 sgen_mark_bridge_object (api_sccs
[i
]->objs
[j
]);
254 /* Null weak links to dead objects. */
255 sgen_null_links_if (is_bridge_object_dead
, &alive_hash
, GENERATION_NURSERY
, FALSE
);
256 sgen_null_links_if (is_bridge_object_dead
, &alive_hash
, GENERATION_NURSERY
, TRUE
);
257 if (generation
== GENERATION_OLD
) {
258 sgen_null_links_if (is_bridge_object_dead
, &alive_hash
, GENERATION_OLD
, FALSE
);
259 sgen_null_links_if (is_bridge_object_dead
, &alive_hash
, GENERATION_OLD
, TRUE
);
262 sgen_hash_table_clean (&alive_hash
);
266 free_callback_data (SgenBridgeProcessor
*processor
)
269 int num_sccs
= processor
->num_sccs
;
270 int num_xrefs
= processor
->num_xrefs
;
271 MonoGCBridgeSCC
**api_sccs
= processor
->api_sccs
;
272 MonoGCBridgeXRef
*api_xrefs
= processor
->api_xrefs
;
274 for (i
= 0; i
< num_sccs
; ++i
) {
275 sgen_free_internal_dynamic (api_sccs
[i
],
276 sizeof (MonoGCBridgeSCC
) + sizeof (MonoObject
*) * api_sccs
[i
]->num_objs
,
277 INTERNAL_MEM_BRIDGE_DATA
);
279 sgen_free_internal_dynamic (api_sccs
, sizeof (MonoGCBridgeSCC
*) * num_sccs
, INTERNAL_MEM_BRIDGE_DATA
);
281 sgen_free_internal_dynamic (api_xrefs
, sizeof (MonoGCBridgeXRef
) * num_xrefs
, INTERNAL_MEM_BRIDGE_DATA
);
283 processor
->num_sccs
= 0;
284 processor
->api_sccs
= NULL
;
285 processor
->num_xrefs
= 0;
286 processor
->api_xrefs
= NULL
;
290 compare_xrefs (const void *a_ptr
, const void *b_ptr
)
292 const MonoGCBridgeXRef
*a
= (const MonoGCBridgeXRef
*)a_ptr
;
293 const MonoGCBridgeXRef
*b
= (const MonoGCBridgeXRef
*)b_ptr
;
295 if (a
->src_scc_index
< b
->src_scc_index
)
297 if (a
->src_scc_index
> b
->src_scc_index
)
300 if (a
->dst_scc_index
< b
->dst_scc_index
)
302 if (a
->dst_scc_index
> b
->dst_scc_index
)
310 dump_processor_state (SgenBridgeProcessor *p)
315 printf ("SCCS %d\n", p->num_sccs);
316 for (i = 0; i < p->num_sccs; ++i) {
318 MonoGCBridgeSCC *scc = p->api_sccs [i];
319 printf ("\tSCC %d:", i);
320 for (j = 0; j < scc->num_objs; ++j) {
321 MonoObject *obj = scc->objs [j];
327 printf ("XREFS %d\n", p->num_xrefs);
328 for (i = 0; i < p->num_xrefs; ++i)
329 printf ("\t%d -> %d\n", p->api_xrefs [i].src_scc_index, p->api_xrefs [i].dst_scc_index);
331 printf ("-------\n");
336 sgen_compare_bridge_processor_results (SgenBridgeProcessor
*a
, SgenBridgeProcessor
*b
)
339 SgenHashTable obj_to_a_scc
= SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_DEBUG
, INTERNAL_MEM_BRIDGE_DEBUG
, sizeof (int), mono_aligned_addr_hash
, NULL
);
340 SgenHashTable b_scc_to_a_scc
= SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_DEBUG
, INTERNAL_MEM_BRIDGE_DEBUG
, sizeof (int), g_direct_hash
, NULL
);
341 MonoGCBridgeXRef
*a_xrefs
, *b_xrefs
;
342 size_t xrefs_alloc_size
;
344 // dump_processor_state (a);
345 // dump_processor_state (b);
347 if (a
->num_sccs
!= b
->num_sccs
)
348 g_error ("SCCS count expected %d but got %d", a
->num_sccs
, b
->num_sccs
);
349 if (a
->num_xrefs
!= b
->num_xrefs
)
350 g_error ("SCCS count expected %d but got %d", a
->num_xrefs
, b
->num_xrefs
);
353 * First we build a hash of each object in `a` to its respective SCC index within
354 * `a`. Along the way we also assert that no object is more than one SCC.
356 for (i
= 0; i
< a
->num_sccs
; ++i
) {
358 MonoGCBridgeSCC
*scc
= a
->api_sccs
[i
];
360 g_assert (scc
->num_objs
> 0);
362 for (j
= 0; j
< scc
->num_objs
; ++j
) {
363 GCObject
*obj
= scc
->objs
[j
];
364 gboolean new_entry
= sgen_hash_table_replace (&obj_to_a_scc
, obj
, &i
, NULL
);
365 g_assert (new_entry
);
370 * Now we check whether each of the objects in `b` are in `a`, and whether the SCCs
371 * of `b` contain the same sets of objects as those of `a`.
373 * While we're doing this, build a hash table to map from `b` SCC indexes to `a` SCC
376 for (i
= 0; i
< b
->num_sccs
; ++i
) {
377 MonoGCBridgeSCC
*scc
= b
->api_sccs
[i
];
378 MonoGCBridgeSCC
*a_scc
;
379 int *a_scc_index_ptr
;
384 g_assert (scc
->num_objs
> 0);
385 a_scc_index_ptr
= (int *)sgen_hash_table_lookup (&obj_to_a_scc
, scc
->objs
[0]);
386 g_assert (a_scc_index_ptr
);
387 a_scc_index
= *a_scc_index_ptr
;
389 //g_print ("A SCC %d -> B SCC %d\n", a_scc_index, i);
391 a_scc
= a
->api_sccs
[a_scc_index
];
392 g_assert (a_scc
->num_objs
== scc
->num_objs
);
394 for (j
= 1; j
< scc
->num_objs
; ++j
) {
395 a_scc_index_ptr
= (int *)sgen_hash_table_lookup (&obj_to_a_scc
, scc
->objs
[j
]);
396 g_assert (a_scc_index_ptr
);
397 g_assert (*a_scc_index_ptr
== a_scc_index
);
400 new_entry
= sgen_hash_table_replace (&b_scc_to_a_scc
, GINT_TO_POINTER (i
), &a_scc_index
, NULL
);
401 g_assert (new_entry
);
405 * Finally, check that we have the same xrefs. We do this by making copies of both
406 * xref arrays, and replacing the SCC indexes in the copy for `b` with the
407 * corresponding indexes in `a`. Then we sort both arrays and assert that they're
410 * At the same time, check that no xref is self-referential and that there are no
414 xrefs_alloc_size
= a
->num_xrefs
* sizeof (MonoGCBridgeXRef
);
415 a_xrefs
= (MonoGCBridgeXRef
*)sgen_alloc_internal_dynamic (xrefs_alloc_size
, INTERNAL_MEM_BRIDGE_DEBUG
, TRUE
);
416 b_xrefs
= (MonoGCBridgeXRef
*)sgen_alloc_internal_dynamic (xrefs_alloc_size
, INTERNAL_MEM_BRIDGE_DEBUG
, TRUE
);
418 memcpy (a_xrefs
, a
->api_xrefs
, xrefs_alloc_size
);
419 for (i
= 0; i
< b
->num_xrefs
; ++i
) {
420 MonoGCBridgeXRef
*xref
= &b
->api_xrefs
[i
];
423 g_assert (xref
->src_scc_index
!= xref
->dst_scc_index
);
425 scc_index_ptr
= (int *)sgen_hash_table_lookup (&b_scc_to_a_scc
, GINT_TO_POINTER (xref
->src_scc_index
));
426 g_assert (scc_index_ptr
);
427 b_xrefs
[i
].src_scc_index
= *scc_index_ptr
;
429 scc_index_ptr
= (int *)sgen_hash_table_lookup (&b_scc_to_a_scc
, GINT_TO_POINTER (xref
->dst_scc_index
));
430 g_assert (scc_index_ptr
);
431 b_xrefs
[i
].dst_scc_index
= *scc_index_ptr
;
434 qsort (a_xrefs
, a
->num_xrefs
, sizeof (MonoGCBridgeXRef
), compare_xrefs
);
435 qsort (b_xrefs
, a
->num_xrefs
, sizeof (MonoGCBridgeXRef
), compare_xrefs
);
437 for (i
= 0; i
< a
->num_xrefs
; ++i
) {
438 g_assert (a_xrefs
[i
].src_scc_index
== b_xrefs
[i
].src_scc_index
);
439 g_assert (a_xrefs
[i
].dst_scc_index
== b_xrefs
[i
].dst_scc_index
);
442 sgen_hash_table_clean (&obj_to_a_scc
);
443 sgen_hash_table_clean (&b_scc_to_a_scc
);
444 sgen_free_internal_dynamic (a_xrefs
, xrefs_alloc_size
, INTERNAL_MEM_BRIDGE_DEBUG
);
445 sgen_free_internal_dynamic (b_xrefs
, xrefs_alloc_size
, INTERNAL_MEM_BRIDGE_DEBUG
);
451 sgen_bridge_processing_finish (int generation
)
453 bridge_processor
.processing_build_callback_data (generation
);
454 if (compare_bridge_processors ())
455 compare_to_bridge_processor
.processing_build_callback_data (generation
);
457 if (bridge_processor
.num_sccs
== 0) {
458 g_assert (bridge_processor
.num_xrefs
== 0);
462 mono_bridge_callbacks
.cross_references (bridge_processor
.num_sccs
, bridge_processor
.api_sccs
,
463 bridge_processor
.num_xrefs
, bridge_processor
.api_xrefs
);
465 if (compare_bridge_processors ())
466 sgen_compare_bridge_processor_results (&bridge_processor
, &compare_to_bridge_processor
);
468 null_weak_links_to_dead_objects (&bridge_processor
, generation
);
470 free_callback_data (&bridge_processor
);
471 if (compare_bridge_processors ())
472 free_callback_data (&compare_to_bridge_processor
);
475 bridge_processor
.processing_after_callback (generation
);
476 if (compare_bridge_processors ())
477 compare_to_bridge_processor
.processing_after_callback (generation
);
479 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_GC
, "GC_BRIDGE: Complete, was running for %.2fms", mono_time_since_last_stw () / 10000.0f
);
481 mono_bridge_processing_in_progress
= FALSE
;
484 MonoGCBridgeObjectKind
485 sgen_bridge_class_kind (MonoClass
*klass
)
487 return bridge_processor
.class_kind (klass
);
491 sgen_bridge_register_finalized_object (GCObject
*obj
)
493 bridge_processor
.register_finalized_object (obj
);
494 if (compare_bridge_processors ())
495 compare_to_bridge_processor
.register_finalized_object (obj
);
499 sgen_bridge_describe_pointer (GCObject
*obj
)
501 if (bridge_processor
.describe_pointer
)
502 bridge_processor
.describe_pointer (obj
);
506 set_dump_prefix (const char *prefix
)
508 if (bridge_processor_config
.dump_prefix
)
509 free (bridge_processor_config
.dump_prefix
);
510 bridge_processor_config
.dump_prefix
= strdup (prefix
);
513 /* Test support code */
514 static const char *bridge_class
;
516 static MonoGCBridgeObjectKind
517 bridge_test_bridge_class_kind (MonoClass
*klass
)
519 if (!strcmp (bridge_class
, m_class_get_name (klass
)))
520 return GC_BRIDGE_TRANSPARENT_BRIDGE_CLASS
;
521 return GC_BRIDGE_TRANSPARENT_CLASS
;
525 bridge_test_is_bridge_object (MonoObject
*object
)
531 bridge_test_cross_reference (int num_sccs
, MonoGCBridgeSCC
**sccs
, int num_xrefs
, MonoGCBridgeXRef
*xrefs
)
534 for (i
= 0; i
< num_sccs
; ++i
) {
536 // g_print ("--- SCC %d\n", i);
537 for (j
= 0; j
< sccs
[i
]->num_objs
; ++j
) {
538 // g_print (" %s\n", sgen_safe_name (sccs [i]->objs [j]));
539 if (i
& 1) /*retain half of the bridged objects */
540 sccs
[i
]->is_alive
= TRUE
;
543 for (i
= 0; i
< num_xrefs
; ++i
) {
544 g_assert (xrefs
[i
].src_scc_index
>= 0 && xrefs
[i
].src_scc_index
< num_sccs
);
545 g_assert (xrefs
[i
].dst_scc_index
>= 0 && xrefs
[i
].dst_scc_index
< num_sccs
);
546 // g_print ("%d -> %d\n", xrefs [i].src_scc_index, xrefs [i].dst_scc_index);
550 static MonoClassField
*mono_bridge_test_field
;
560 test_scc (MonoGCBridgeSCC
*scc
, int i
)
562 int status
= BRIDGE_DEAD
;
563 mono_field_get_value (scc
->objs
[i
], mono_bridge_test_field
, &status
);
568 mark_scc (MonoGCBridgeSCC
*scc
, int value
)
571 for (i
= 0; i
< scc
->num_objs
; ++i
) {
572 if (!test_scc (scc
, i
)) {
574 mono_field_set_value (scc
->objs
[i
], mono_bridge_test_field
, &status
);
580 bridge_test_cross_reference2 (int num_sccs
, MonoGCBridgeSCC
**sccs
, int num_xrefs
, MonoGCBridgeXRef
*xrefs
)
585 if (!mono_bridge_test_field
) {
586 mono_bridge_test_field
= mono_class_get_field_from_name (mono_object_get_class (sccs
[0]->objs
[0]), "__test");
587 g_assert (mono_bridge_test_field
);
590 /*We mark all objects in a scc with live objects as reachable by scc*/
591 for (i
= 0; i
< num_sccs
; ++i
) {
593 gboolean live
= FALSE
;
594 for (j
= 0; j
< sccs
[i
]->num_objs
; ++j
) {
595 if (test_scc (sccs
[i
], j
)) {
602 for (j
= 0; j
< sccs
[i
]->num_objs
; ++j
) {
603 if (!test_scc (sccs
[i
], j
)) {
604 int status
= BRIDGE_SAME_SCC
;
605 mono_field_set_value (sccs
[i
]->objs
[j
], mono_bridge_test_field
, &status
);
610 /*Now we mark the transitive closure of reachable objects from the xrefs*/
614 /* Mark all objects that are brought to life due to xrefs*/
615 for (i
= 0; i
< num_xrefs
; ++i
) {
616 MonoGCBridgeXRef ref
= xrefs
[i
];
617 if (test_scc (sccs
[ref
.src_scc_index
], 0) && !test_scc (sccs
[ref
.dst_scc_index
], 0)) {
619 mark_scc (sccs
[ref
.dst_scc_index
], BRIDGE_XREF
);
624 /* keep everything in memory, all we want to do is test persistence */
625 for (i
= 0; i
< num_sccs
; ++i
)
626 sccs
[i
]->is_alive
= TRUE
;
629 /* This bridge keeps all peers with __test > 0 */
631 bridge_test_positive_status (int num_sccs
, MonoGCBridgeSCC
**sccs
, int num_xrefs
, MonoGCBridgeXRef
*xrefs
)
635 if (!mono_bridge_test_field
) {
636 mono_bridge_test_field
= mono_class_get_field_from_name (mono_object_get_class (sccs
[0]->objs
[0]), "__test");
637 g_assert (mono_bridge_test_field
);
640 /*We mark all objects in a scc with live objects as reachable by scc*/
641 for (i
= 0; i
< num_sccs
; ++i
) {
643 for (j
= 0; j
< sccs
[i
]->num_objs
; ++j
) {
644 if (test_scc (sccs
[i
], j
)) {
645 sccs
[i
]->is_alive
= TRUE
;
654 register_test_bridge_callbacks (const char *bridge_class_name
)
656 MonoGCBridgeCallbacks callbacks
;
657 callbacks
.bridge_version
= SGEN_BRIDGE_VERSION
;
658 callbacks
.bridge_class_kind
= bridge_test_bridge_class_kind
;
659 callbacks
.is_bridge_object
= bridge_test_is_bridge_object
;
661 switch (bridge_class_name
[0]) {
663 bridge_class
= bridge_class_name
+ 1;
664 callbacks
.cross_references
= bridge_test_cross_reference2
;
667 bridge_class
= bridge_class_name
+ 1;
668 callbacks
.cross_references
= bridge_test_positive_status
;
671 bridge_class
= bridge_class_name
;
672 callbacks
.cross_references
= bridge_test_cross_reference
;
674 mono_gc_register_bridge_callbacks (&callbacks
);
678 sgen_bridge_handle_gc_param (const char *opt
)
680 g_assert (!bridge_processor_started ());
682 if (!strcmp (opt
, "bridge-require-precise-merge")) {
683 bridge_processor_config
.scc_precise_merge
= TRUE
;
692 sgen_bridge_handle_gc_debug (const char *opt
)
694 g_assert (!bridge_processor_started ());
696 if (g_str_has_prefix (opt
, "bridge=")) {
697 opt
= strchr (opt
, '=') + 1;
698 register_test_bridge_callbacks (g_strdup (opt
));
699 } else if (!strcmp (opt
, "enable-bridge-accounting")) {
700 bridge_processor_config
.accounting
= TRUE
;
701 } else if (g_str_has_prefix (opt
, "bridge-dump=")) {
702 char *prefix
= strchr (opt
, '=') + 1;
703 set_dump_prefix(prefix
);
704 } else if (g_str_has_prefix (opt
, "bridge-compare-to=")) {
705 const char *name
= strchr (opt
, '=') + 1;
706 BridgeProcessorSelection selection
= bridge_processor_name (name
);
708 if (selection
!= BRIDGE_PROCESSOR_INVALID
) {
709 // Compare processor doesn't get config
710 init_bridge_processor (&compare_to_bridge_processor
, selection
);
712 g_warning ("Invalid bridge implementation to compare against - ignoring.");
721 sgen_bridge_print_gc_debug_usage (void)
723 fprintf (stderr
, " bridge=<class-name>\n");
724 fprintf (stderr
, " enable-bridge-accounting\n");
725 fprintf (stderr
, " bridge-dump=<filename-prefix>\n");
726 fprintf (stderr
, " bridge-compare-to=<implementation>\n");
732 volatile gboolean mono_bridge_processing_in_progress
= FALSE
;
735 mono_gc_wait_for_bridge_processing (void)
739 MonoGCBridgeObjectKind
740 sgen_bridge_class_kind (MonoClass
*klass
)
742 return GC_BRIDGE_TRANSPARENT_CLASS
;
746 sgen_bridge_describe_pointer (GCObject
*obj
)
751 sgen_bridge_handle_gc_debug (const char *opt
)
757 sgen_bridge_handle_gc_param (const char *opt
)
763 sgen_bridge_print_gc_debug_usage (void)
768 sgen_bridge_processing_finish (int generation
)
773 sgen_bridge_processing_stw_step (void)
778 sgen_bridge_register_finalized_object (GCObject
*obj
)
783 sgen_bridge_reset_data (void)
788 sgen_init_bridge (void)
793 sgen_is_bridge_object (GCObject
*obj
)
799 sgen_need_bridge_processing (void)
805 sgen_set_bridge_implementation (const char *name
)
807 g_error ("Sgen bridge disabled");