Skip to content

Commit c8778d3

Browse files
authored
Add test cases to sgen-bridge-pathologies
1 parent 07d7a7c commit c8778d3

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,8 @@ create_scc (ScanData *data)
807807
// and xrefs were populated from color_merge_array, which is already
808808
// deduplicated and every entry is marked as visited.
809809
add_other_colors (color_data, &other->xrefs, TRUE);
810+
} else {
811+
g_assert (dyn_array_ptr_size (&other->xrefs) == 0);
810812
}
811813
dyn_array_ptr_uninit (&other->xrefs);
812814

src/mono/mono/tests/sgen-bridge-pathologies.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public class NonBridge
1818
public object Link;
1919
}
2020

21+
public class NonBridge2 : NonBridge
22+
{
23+
public object Link2;
24+
}
25+
2126
class Driver {
2227
const int OBJ_COUNT = 200 * 1000;
2328
const int LINK_COUNT = 2;
@@ -207,6 +212,61 @@ static void Spider () {
207212
c.Links.Add (last_level);
208213
}
209214

215+
/*
216+
* Simulates a graph with two nested cycles that is produces by
217+
* the async state machine when `async Task M()` method gets its
218+
* continuation rooted by an Action held by RunnableImplementor
219+
* (ie. the task continuation is hooked through the SynchronizationContext
220+
* implentation and rooted only by Android bridge objects).
221+
*/
222+
static void NestedCycles ()
223+
{
224+
Bridge runnableImplementor = new Bridge ();
225+
Bridge byteArrayOutputStream = new Bridge ();
226+
NonBridge2 action = new NonBridge2 ();
227+
NonBridge displayClass = new NonBridge ();
228+
NonBridge2 asyncStateMachineBox = new NonBridge2 ();
229+
NonBridge2 asyncStreamWriter = new NonBridge2 ();
230+
231+
runnableImplementor.Links.Add(action);
232+
action.Link = displayClass;
233+
action.Link2 = asyncStateMachineBox;
234+
displayClass.Link = action;
235+
asyncStateMachineBox.Link = asyncStreamWriter;
236+
asyncStateMachineBox.Link2 = action;
237+
asyncStreamWriter.Link = byteArrayOutputStream;
238+
asyncStreamWriter.Link2 = asyncStateMachineBox;
239+
}
240+
241+
/*
242+
* Simulates a graph where a heavy node has its fanout components
243+
* represented by cycles with back-references to the heavy node and
244+
* references to the same bridge objects.
245+
* This enters a pathological path in the SCC contraction where the
246+
* links to the bridge objects need to be correctly deduplicated. The
247+
* deduplication causes the heavy node to no longer be heavy.
248+
*/
249+
static void FauxHeavyNodeWithCycles ()
250+
{
251+
Bridge fanout = new Bridge ();
252+
253+
// Need enough edges for the node to be considered heavy by bridgeless_color_is_heavy
254+
NonBridge[] fauxHeavyNode = new NonBridge [100];
255+
for (int i = 0; i < fauxHeavyNode.Length; i++) {
256+
NonBridge2 cycle = new NonBridge2 ();
257+
cycle.Link = fanout;
258+
cycle.Link2 = fauxHeavyNode;
259+
fauxHeavyNode[i] = cycle;
260+
}
261+
262+
// Need at least HEAVY_REFS_MIN + 1 fan-in nodes
263+
Bridge[] faninNodes = new Bridge [3];
264+
for (int i = 0; i < faninNodes.Length; i++) {
265+
faninNodes[i] = new Bridge ();
266+
faninNodes[i].Links.Add (fauxHeavyNode);
267+
}
268+
}
269+
210270
static void RunTest (ThreadStart setup)
211271
{
212272
var t = new Thread (setup);
@@ -231,6 +291,8 @@ static int Main ()
231291
RunTest (SetupDeadList);
232292
RunTest (SetupSelfLinks);
233293
RunTest (Spider);
294+
RunTest (NestedCycles);
295+
RunTest (FauxHeavyNodeWithCycles);
234296

235297
for (int i = 0; i < 0; ++i) {
236298
GC.Collect ();

0 commit comments

Comments
 (0)