2 // Split call sites into call site and return site nodes and add
5 // Run with graph ... | return-paths
8 // Find the immediate parent subgraph of this object
9 graph_t find_owner(obj_t o, graph_t g)
12 for (g1 = fstsubg(g); g1; g1 = nxtsubg(g1))
13 if(isIn(g1,o)) return g1;
19 node_t calls[]; // Crude hash table for tracking who calls what
29 // Each call edge which hasn't already been seen
30 E [op == "call" && tail.split != 1] {
33 // Clear the label of this call
35 g = find_owner(tail, $G);
37 // Consider each outgoing call. Split the node accordingly
39 for (e = fstout(tail); e; e = nxtout(e)) {
43 n2 = node(g, sprintf("%s%s%d", tail.name, "x", offset++));
52 g2 = find_owner(e.head, $G);
54 while(calls[sprintf("%s%d", g2.name, ++i)]) {
56 calls[sprintf("%s%d", g2.name, i)] = n2;
58 // Connect original to split
59 e2 = edge(n, n2, "call");
63 // Replace this outedge
65 e2 = edge(n, e.head, "transformed-call");
71 // Record where we were
76 // Consider the outgoing control flow: move down to the bottom of
77 // the call sequence nodes
78 for (e = fstout(tail); e; e = nxtout(e)) {
80 // Replace this outedge
81 e2 = edge(n,e.head,"transformed");
88 // Each return node: add edges back to the caller
90 for (g = fstsubg($G); g; g = nxtsubg(g)) {
93 while(calls[sprintf("%s%d", g.name, ++i)]) {
94 e = edge($, calls[sprintf("%s%d", g.name, i)], "return");