Skip to content

Commit 8f94d2e

Browse files
authored
[SGen/Tarjan] Handle edge case with node heaviness changing due to deduplication (#113044)
* [SGen/Tarjan] Handle edge case with node heaviness changing due to deduplication Do early deduplication Fix Windows build Add test cases to sgen-bridge-pathologies * Move test code * Remove old code * Add extra check (no change to functionality)
1 parent ff749c3 commit 8f94d2e

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

src/mono/mono/metadata/sgen-tarjan-bridge.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -525,10 +525,15 @@ find_in_cache (int *insert_index)
525525

526526
// Populate other_colors for a give color (other_colors represent the xrefs for this color)
527527
static void
528-
add_other_colors (ColorData *color, DynPtrArray *other_colors)
528+
add_other_colors (ColorData *color, DynPtrArray *other_colors, gboolean check_visited)
529529
{
530530
for (int i = 0; i < dyn_array_ptr_size (other_colors); ++i) {
531531
ColorData *points_to = (ColorData *)dyn_array_ptr_get (other_colors, i);
532+
if (check_visited) {
533+
if (points_to->visited)
534+
continue;
535+
points_to->visited = TRUE;
536+
}
532537
dyn_array_ptr_add (&color->other_colors, points_to);
533538
// Inform targets
534539
points_to->incoming_colors = MIN (points_to->incoming_colors + 1, INCOMING_COLORS_MAX);
@@ -552,7 +557,7 @@ new_color (gboolean has_bridges)
552557
cd = alloc_color_data ();
553558
cd->api_index = -1;
554559

555-
add_other_colors (cd, &color_merge_array);
560+
add_other_colors (cd, &color_merge_array, FALSE);
556561

557562
/* if cacheSlot >= 0, it means we prepared a given slot to receive the new color */
558563
if (cacheSlot >= 0)
@@ -791,12 +796,18 @@ create_scc (ScanData *data)
791796
dyn_array_ptr_add (&color_data->bridges, other->obj);
792797
}
793798

794-
// Maybe we should make sure we are not adding duplicates here. It is not really a problem
795-
// since we will get rid of duplicates before submitting the SCCs to the client in gather_xrefs
796-
if (color_data) {
797-
add_other_colors (color_data, &other->xrefs);
798-
} else {
799-
g_assert (dyn_array_ptr_size (&other->xrefs) == 0);
799+
if (dyn_array_ptr_size (&other->xrefs) > 0) {
800+
g_assert (color_data != NULL);
801+
g_assert (can_reduce_color == FALSE);
802+
// We need to eliminate duplicates early otherwise the heaviness property
803+
// can change in gather_xrefs and it breaks down the loop that reports the
804+
// xrefs to the client.
805+
//
806+
// We reuse the visited flag to mark the objects that are already part of
807+
// the color_data array. The array was created above with the new_color call
808+
// and xrefs were populated from color_merge_array, which is already
809+
// deduplicated and every entry is marked as visited.
810+
add_other_colors (color_data, &other->xrefs, TRUE);
800811
}
801812
dyn_array_ptr_uninit (&other->xrefs);
802813

@@ -807,6 +818,15 @@ create_scc (ScanData *data)
807818
}
808819
g_assert (found);
809820

821+
// Clear the visited flag on nodes that were added with add_other_colors in the loop above
822+
if (!can_reduce_color) {
823+
for (i = dyn_array_ptr_size (&color_merge_array); i < dyn_array_ptr_size (&color_data->other_colors); i++) {
824+
ColorData *cd = (ColorData *)dyn_array_ptr_get (&color_data->other_colors, i);
825+
g_assert (cd->visited);
826+
cd->visited = FALSE;
827+
}
828+
}
829+
810830
#if DUMP_GRAPH
811831
if (color_data) {
812832
printf ("\tpoints-to-colors: ");
@@ -1116,6 +1136,7 @@ processing_build_callback_data (int generation)
11161136
gather_xrefs (cd);
11171137
reset_xrefs (cd);
11181138
dyn_array_ptr_set_all (&cd->other_colors, &color_merge_array);
1139+
g_assert (color_visible_to_client (cd));
11191140
xref_count += dyn_array_ptr_size (&cd->other_colors);
11201141
}
11211142
}

src/tests/GC/Features/Bridge/Bridge.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,35 @@ static void NestedCycles()
279279
asyncStreamWriter.Link2 = asyncStateMachineBox;
280280
}
281281

282+
// Simulates a graph where a heavy node has its fanout components
283+
// represented by cycles with back-references to the heavy node and
284+
// references to the same bridge objects.
285+
// This enters a pathological path in the SCC contraction where the
286+
// links to the bridge objects need to be correctly deduplicated. The
287+
// deduplication causes the heavy node to no longer be heavy.
288+
static void FauxHeavyNodeWithCycles()
289+
{
290+
Bridge fanout = new Bridge();
291+
292+
// Need enough edges for the node to be considered heavy by bridgeless_color_is_heavy
293+
NonBridge[] fauxHeavyNode = new NonBridge[100];
294+
for (int i = 0; i < fauxHeavyNode.Length; i++)
295+
{
296+
NonBridge2 cycle = new NonBridge2();
297+
cycle.Link = fanout;
298+
cycle.Link2 = fauxHeavyNode;
299+
fauxHeavyNode[i] = cycle;
300+
}
301+
302+
// Need at least HEAVY_REFS_MIN + 1 fan-in nodes
303+
Bridge[] faninNodes = new Bridge[3];
304+
for (int i = 0; i < faninNodes.Length; i++)
305+
{
306+
faninNodes[i] = new Bridge();
307+
faninNodes[i].Links.Add(fauxHeavyNode);
308+
}
309+
}
310+
282311
static void RunGraphTest(Action test)
283312
{
284313
Console.WriteLine("Start test {0}", test.Method.Name);
@@ -386,6 +415,7 @@ public static int Main(string[] args)
386415
RunGraphTest(SetupDeadList);
387416
RunGraphTest(SetupSelfLinks);
388417
RunGraphTest(NestedCycles);
418+
RunGraphTest(FauxHeavyNodeWithCycles);
389419
// RunGraphTest(Spider); // Crashes
390420
return 100;
391421
}

0 commit comments

Comments
 (0)