[merp] Remove dead code (#20043)
[mono-project.git] / mono / metadata / sgen-bridge.c
blob2b4c662c5ca3c59251dd45e0f479f887522d94e4
1 /**
2 * \file
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.
13 #include "config.h"
15 #ifdef HAVE_SGEN_GC
17 #include <stdlib.h>
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
27 typedef enum {
28 BRIDGE_PROCESSOR_INVALID,
29 BRIDGE_PROCESSOR_OLD,
30 BRIDGE_PROCESSOR_NEW,
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
52 /**
53 * mono_gc_wait_for_bridge_processing:
55 void
56 mono_gc_wait_for_bridge_processing (void)
58 if (!mono_bridge_processing_in_progress)
59 return;
61 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_BRIDGE waiting for bridge processing to finish");
63 sgen_gc_lock ();
64 sgen_gc_unlock ();
67 /**
68 * mono_gc_register_bridge_callbacks:
70 void
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
81 sgen_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;
93 } else {
94 return BRIDGE_PROCESSOR_INVALID;
98 static gboolean
99 bridge_processor_started (void)
101 return bridge_processor.reset_data != NULL;
104 // Initialize a single bridge processor
105 static void
106 init_bridge_processor (SgenBridgeProcessor *processor, BridgeProcessorSelection selection)
108 memset (processor, 0, sizeof (SgenBridgeProcessor));
110 switch (selection) {
111 case BRIDGE_PROCESSOR_OLD:
112 sgen_old_bridge_init (processor);
113 break;
114 case BRIDGE_PROCESSOR_NEW:
115 sgen_new_bridge_init (processor);
116 break;
117 case BRIDGE_PROCESSOR_TARJAN:
118 sgen_tarjan_bridge_init (processor);
119 break;
120 default:
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.
143 void
144 sgen_init_bridge (void)
146 if (sgen_gc_initialized ()) {
147 // This lock is not initialized until the GC is
148 sgen_gc_lock ();
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;
164 sgen_gc_unlock ();
168 void
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");
177 else
178 bridge_processor_selection = selection;
181 gboolean
182 sgen_is_bridge_object (GCObject *obj)
184 if ((obj->vtable->gc_bits & SGEN_GC_BIT_BRIDGE_OBJECT) != SGEN_GC_BIT_BRIDGE_OBJECT)
185 return FALSE;
186 return mono_bridge_callbacks.is_bridge_object (obj);
189 gboolean
190 sgen_need_bridge_processing (void)
192 return mono_bridge_callbacks.cross_references != NULL;
195 static gboolean
196 compare_bridge_processors (void)
198 return compare_to_bridge_processor.reset_data != NULL;
201 /* Dispatch wrappers */
202 void
203 sgen_bridge_reset_data (void)
205 bridge_processor.reset_data ();
206 if (compare_bridge_processors ())
207 compare_to_bridge_processor.reset_data ();
210 void
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 ();
224 static gboolean
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);
229 if (!value)
230 return FALSE;
231 return !*value;
234 static void
235 null_weak_links_to_dead_objects (SgenBridgeProcessor *processor, int generation)
237 int i, j;
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);
265 static void
266 free_callback_data (SgenBridgeProcessor *processor)
268 int i;
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;
289 static int
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)
296 return -1;
297 if (a->src_scc_index > b->src_scc_index)
298 return 1;
300 if (a->dst_scc_index < b->dst_scc_index)
301 return -1;
302 if (a->dst_scc_index > b->dst_scc_index)
303 return 1;
305 return 0;
309 static void
310 dump_processor_state (SgenBridgeProcessor *p)
312 int i;
314 printf ("------\n");
315 printf ("SCCS %d\n", p->num_sccs);
316 for (i = 0; i < p->num_sccs; ++i) {
317 int j;
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];
322 printf (" %p(%s)", obj, SGEN_LOAD_VTABLE (obj)->klass->name);
324 printf ("\n");
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");
335 static gboolean
336 sgen_compare_bridge_processor_results (SgenBridgeProcessor *a, SgenBridgeProcessor *b)
338 int i;
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) {
357 int j;
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
374 * indexes.
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;
380 int a_scc_index;
381 int j;
382 gboolean new_entry;
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
408 * the same.
410 * At the same time, check that no xref is self-referential and that there are no
411 * duplicate ones.
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];
421 int *scc_index_ptr;
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 mono_qsort (a_xrefs, a->num_xrefs, sizeof (MonoGCBridgeXRef), compare_xrefs);
435 mono_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);
447 return TRUE;
450 void
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);
459 goto after_callback;
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);
474 after_callback:
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);
490 void
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);
498 void
499 sgen_bridge_describe_pointer (GCObject *obj)
501 if (bridge_processor.describe_pointer)
502 bridge_processor.describe_pointer (obj);
505 static void
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 (m_class_get_parent (klass) && !strcmp (bridge_class, m_class_get_name (m_class_get_parent (klass)))))
521 return GC_BRIDGE_TRANSPARENT_BRIDGE_CLASS;
522 return GC_BRIDGE_TRANSPARENT_CLASS;
525 static gboolean
526 bridge_test_is_bridge_object (MonoObject *object)
528 return TRUE;
531 static void
532 bridge_test_cross_reference (int num_sccs, MonoGCBridgeSCC **sccs, int num_xrefs, MonoGCBridgeXRef *xrefs)
534 int i;
535 for (i = 0; i < num_sccs; ++i) {
536 int j;
537 // g_print ("--- SCC %d\n", i);
538 for (j = 0; j < sccs [i]->num_objs; ++j) {
539 // g_print (" %s\n", sgen_safe_name (sccs [i]->objs [j]));
540 if (i & 1) /*retain half of the bridged objects */
541 sccs [i]->is_alive = TRUE;
544 for (i = 0; i < num_xrefs; ++i) {
545 g_assert (xrefs [i].src_scc_index >= 0 && xrefs [i].src_scc_index < num_sccs);
546 g_assert (xrefs [i].dst_scc_index >= 0 && xrefs [i].dst_scc_index < num_sccs);
547 // g_print ("%d -> %d\n", xrefs [i].src_scc_index, xrefs [i].dst_scc_index);
551 static MonoClassField *mono_bridge_test_field;
553 enum {
554 BRIDGE_DEAD,
555 BRIDGE_ROOT,
556 BRIDGE_SAME_SCC,
557 BRIDGE_XREF,
560 static gboolean
561 test_scc (MonoGCBridgeSCC *scc, int i)
563 int status = BRIDGE_DEAD;
564 mono_field_get_value_internal (scc->objs [i], mono_bridge_test_field, &status);
565 return status > 0;
568 static void
569 mark_scc (MonoGCBridgeSCC *scc, int value)
571 int i;
572 for (i = 0; i < scc->num_objs; ++i) {
573 if (!test_scc (scc, i)) {
574 int status = value;
575 mono_field_set_value_internal (scc->objs [i], mono_bridge_test_field, &status);
580 static void
581 bridge_test_cross_reference2 (int num_sccs, MonoGCBridgeSCC **sccs, int num_xrefs, MonoGCBridgeXRef *xrefs)
583 int i;
584 gboolean modified;
586 if (!mono_bridge_test_field) {
587 mono_bridge_test_field = mono_class_get_field_from_name_full (mono_object_class (sccs[0]->objs [0]), "__test", NULL);
588 g_assert (mono_bridge_test_field);
591 /*We mark all objects in a scc with live objects as reachable by scc*/
592 for (i = 0; i < num_sccs; ++i) {
593 int j;
594 gboolean live = FALSE;
595 for (j = 0; j < sccs [i]->num_objs; ++j) {
596 if (test_scc (sccs [i], j)) {
597 live = TRUE;
598 break;
601 if (!live)
602 continue;
603 for (j = 0; j < sccs [i]->num_objs; ++j) {
604 if (!test_scc (sccs [i], j)) {
605 int status = BRIDGE_SAME_SCC;
606 mono_field_set_value_internal (sccs [i]->objs [j], mono_bridge_test_field, &status);
611 /*Now we mark the transitive closure of reachable objects from the xrefs*/
612 modified = TRUE;
613 while (modified) {
614 modified = FALSE;
615 /* Mark all objects that are brought to life due to xrefs*/
616 for (i = 0; i < num_xrefs; ++i) {
617 MonoGCBridgeXRef ref = xrefs [i];
618 if (test_scc (sccs [ref.src_scc_index], 0) && !test_scc (sccs [ref.dst_scc_index], 0)) {
619 modified = TRUE;
620 mark_scc (sccs [ref.dst_scc_index], BRIDGE_XREF);
625 /* keep everything in memory, all we want to do is test persistence */
626 for (i = 0; i < num_sccs; ++i)
627 sccs [i]->is_alive = TRUE;
630 /* This bridge keeps all peers with __test > 0 */
631 static void
632 bridge_test_positive_status (int num_sccs, MonoGCBridgeSCC **sccs, int num_xrefs, MonoGCBridgeXRef *xrefs)
634 int i;
636 if (!mono_bridge_test_field) {
637 mono_bridge_test_field = mono_class_get_field_from_name_full (mono_object_class (sccs[0]->objs [0]), "__test", NULL);
638 g_assert (mono_bridge_test_field);
641 /*We mark all objects in a scc with live objects as reachable by scc*/
642 for (i = 0; i < num_sccs; ++i) {
643 int j;
644 for (j = 0; j < sccs [i]->num_objs; ++j) {
645 if (test_scc (sccs [i], j)) {
646 sccs [i]->is_alive = TRUE;
647 break;
654 static void
655 register_test_bridge_callbacks (const char *bridge_class_name)
657 MonoGCBridgeCallbacks callbacks;
658 callbacks.bridge_version = SGEN_BRIDGE_VERSION;
659 callbacks.bridge_class_kind = bridge_test_bridge_class_kind;
660 callbacks.is_bridge_object = bridge_test_is_bridge_object;
662 switch (bridge_class_name [0]) {
663 case '2':
664 bridge_class = bridge_class_name + 1;
665 callbacks.cross_references = bridge_test_cross_reference2;
666 break;
667 case '3':
668 bridge_class = bridge_class_name + 1;
669 callbacks.cross_references = bridge_test_positive_status;
670 break;
671 default:
672 bridge_class = bridge_class_name;
673 callbacks.cross_references = bridge_test_cross_reference;
675 mono_gc_register_bridge_callbacks (&callbacks);
678 gboolean
679 sgen_bridge_handle_gc_param (const char *opt)
681 g_assert (!bridge_processor_started ());
683 if (!strcmp (opt, "bridge-require-precise-merge")) {
684 bridge_processor_config.scc_precise_merge = TRUE;
685 } else {
686 return FALSE;
689 return TRUE;
692 gboolean
693 sgen_bridge_handle_gc_debug (const char *opt)
695 g_assert (!bridge_processor_started ());
697 if (g_str_has_prefix (opt, "bridge=")) {
698 opt = strchr (opt, '=') + 1;
699 register_test_bridge_callbacks (g_strdup (opt));
700 } else if (!strcmp (opt, "enable-bridge-accounting")) {
701 bridge_processor_config.accounting = TRUE;
702 } else if (g_str_has_prefix (opt, "bridge-dump=")) {
703 const char* prefix = strchr (opt, '=') + 1;
704 set_dump_prefix(prefix);
705 } else if (g_str_has_prefix (opt, "bridge-compare-to=")) {
706 const char *name = strchr (opt, '=') + 1;
707 BridgeProcessorSelection selection = bridge_processor_name (name);
709 if (selection != BRIDGE_PROCESSOR_INVALID) {
710 // Compare processor doesn't get config
711 init_bridge_processor (&compare_to_bridge_processor, selection);
712 bridge_processor_config.disable_non_bridge_scc = TRUE;
713 } else {
714 g_warning ("Invalid bridge implementation to compare against - ignoring.");
716 } else {
717 return FALSE;
719 return TRUE;
722 void
723 sgen_bridge_print_gc_debug_usage (void)
725 fprintf (stderr, " bridge=<class-name>\n");
726 fprintf (stderr, " enable-bridge-accounting\n");
727 fprintf (stderr, " bridge-dump=<filename-prefix>\n");
728 fprintf (stderr, " bridge-compare-to=<implementation>\n");
731 #else
733 //UG
734 volatile gboolean mono_bridge_processing_in_progress = FALSE;
736 void
737 mono_gc_wait_for_bridge_processing (void)
741 MonoGCBridgeObjectKind
742 sgen_bridge_class_kind (MonoClass *klass)
744 return GC_BRIDGE_TRANSPARENT_CLASS;
747 void
748 sgen_bridge_describe_pointer (GCObject *obj)
752 gboolean
753 sgen_bridge_handle_gc_debug (const char *opt)
755 return FALSE;
758 gboolean
759 sgen_bridge_handle_gc_param (const char *opt)
761 return FALSE;
764 void
765 sgen_bridge_print_gc_debug_usage (void)
769 void
770 sgen_bridge_processing_finish (int generation)
774 void
775 sgen_bridge_processing_stw_step (void)
779 void
780 sgen_bridge_register_finalized_object (GCObject *obj)
784 void
785 sgen_bridge_reset_data (void)
789 void
790 sgen_init_bridge (void)
794 gboolean
795 sgen_is_bridge_object (GCObject *obj)
797 return FALSE;
800 gboolean
801 sgen_need_bridge_processing (void)
803 return FALSE;
806 void
807 sgen_set_bridge_implementation (const char *name)
809 g_error ("Sgen bridge disabled");
812 #endif
814 #endif