From 0fe826ade8b21b99e63ff0b174f830b5bd787e7e Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 5 Mar 2015 23:35:12 +0300 Subject: [PATCH] Add more complicated irreducible graph test --- .../main/java/org/teavm/common/DJGraph.java | 6 +- .../java/org/teavm/common/GraphUtils.java | 15 ++-- .../common/IrreducibleGraphConverter.java | 29 ++++---- .../test/java/org/teavm/common/GraphTest.java | 68 +++++++++++++++++++ 4 files changed, 98 insertions(+), 20 deletions(-) diff --git a/teavm-core/src/main/java/org/teavm/common/DJGraph.java b/teavm-core/src/main/java/org/teavm/common/DJGraph.java index d59ad5320..a55ef97ef 100644 --- a/teavm-core/src/main/java/org/teavm/common/DJGraph.java +++ b/teavm-core/src/main/java/org/teavm/common/DJGraph.java @@ -69,9 +69,11 @@ public class DJGraph { } // Add dom edges - for (int i = 1; i < graph.size(); ++i) { + for (int i = 0; i < graph.size(); ++i) { int j = domTree.immediateDominatorOf(i); - graph.addEdge(j, i); + if (j >= 0) { + graph.addEdge(j, i); + } } } diff --git a/teavm-core/src/main/java/org/teavm/common/GraphUtils.java b/teavm-core/src/main/java/org/teavm/common/GraphUtils.java index 886d77d56..692f4190d 100644 --- a/teavm-core/src/main/java/org/teavm/common/GraphUtils.java +++ b/teavm-core/src/main/java/org/teavm/common/GraphUtils.java @@ -91,14 +91,13 @@ public final class GraphUtils { for (int startNode : start) { stack.push(startNode); - IntegerArray currentComponent = new IntegerArray(1); + IntegerStack currentComponent = new IntegerStack(1); while (!stack.isEmpty()) { int node = stack.pop(); if (visitIndex[node] > 0) { if (headerIndex[node] > 0) { continue; } - currentComponent.add(node); int hdr = visitIndex[node]; for (int successor : graph.outgoingEdges(node)) { if (!filter.match(successor)) { @@ -111,15 +110,21 @@ public final class GraphUtils { } } if (hdr == visitIndex[node]) { - components.add(currentComponent.getAll()); - for (int componentMember : currentComponent.getAll()) { + IntegerArray componentMembers = new IntegerArray(graph.size()); + while (true) { + int componentMember = currentComponent.pop(); + componentMembers.add(componentMember); headerIndex[componentMember] = graph.size() + 1; + if (visitIndex[componentMember] == hdr) { + break; + } } - currentComponent.clear(); + components.add(componentMembers.getAll()); } headerIndex[node] = hdr; } else { visitIndex[node] = ++lastIndex; + currentComponent.push(node); stack.push(node); for (int successor : graph.outgoingEdges(node)) { if (!filter.match(successor) || visitIndex[successor] > 0) { diff --git a/teavm-core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java b/teavm-core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java index 594db8992..924d886f1 100644 --- a/teavm-core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java +++ b/teavm-core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java @@ -63,17 +63,6 @@ class IrreducibleGraphConverter { for (int[] scc : sccs) { if (scc.length > 1) { handleStronglyConnectedComponent(djGraph, scc, nodeMap); - int cls = djGraph.collapse(scc); - IntegerArray nodes = new IntegerArray(djGraph.getGraph().size()); - for (int representative : djGraph.classRepresentatives(cls)) { - for (int node : nodeMap[representative]) { - nodes.add(node); - } - } - for (int representative : djGraph.classRepresentatives(cls)) { - nodeMap[representative] = new int[0]; - } - nodeMap[cls] = nodes.getAll(); } } } @@ -89,7 +78,7 @@ class IrreducibleGraphConverter { for (int i = 0; i < scc.length; ++i) { if (scc[i] == sharedDom) { - djGraph.collapse(scc); + collapse(djGraph, scc, nodeMap); return; } } @@ -146,7 +135,7 @@ class IrreducibleGraphConverter { // Collapse int[] sccAndTop = Arrays.copyOf(scc, scc.length + 1); sccAndTop[scc.length] = sharedDom; - djGraph.collapse(sccAndTop); + collapse(djGraph, sccAndTop, nodeMap); } private void splitStronglyConnectedComponent(DJGraph djGraph, IntSet domain, int sharedDom, @@ -241,6 +230,20 @@ class IrreducibleGraphConverter { handleLoops(new DJGraph(builder.build(), mappedWeight), newNodeMap); } + private void collapse(DJGraph djGraph, int[] scc, int[][] nodeMap) { + int cls = djGraph.collapse(scc); + IntegerArray nodes = new IntegerArray(djGraph.getGraph().size()); + for (int representative : djGraph.classRepresentatives(cls)) { + for (int node : nodeMap[representative]) { + nodes.add(node); + } + } + for (int representative : djGraph.classRepresentatives(cls)) { + nodeMap[representative] = new int[0]; + } + nodeMap[cls] = nodes.getAll(); + } + private static int[] flatten(int[][] array) { int count = 0; for (int i = 0; i < array.length; ++i) { diff --git a/teavm-core/src/test/java/org/teavm/common/GraphTest.java b/teavm-core/src/test/java/org/teavm/common/GraphTest.java index 12a2e876f..f0d8fb444 100644 --- a/teavm-core/src/test/java/org/teavm/common/GraphTest.java +++ b/teavm-core/src/test/java/org/teavm/common/GraphTest.java @@ -107,6 +107,41 @@ public class GraphTest { assertThat(sccs[2], is(new int[] { 2 })); } + @Test + public void stronglyConnectedComponentCalculated4() { + GraphBuilder builder = new GraphBuilder(); + builder.addEdge(0, 1); + builder.addEdge(0, 2); + builder.addEdge(1, 2); + builder.addEdge(1, 3); + builder.addEdge(1, 4); + builder.addEdge(2, 1); + builder.addEdge(2, 3); + builder.addEdge(3, 4); + builder.addEdge(4, 5); + builder.addEdge(4, 6); + builder.addEdge(5, 6); + builder.addEdge(6, 5); + builder.addEdge(6, 7); + builder.addEdge(7, 4); + builder.addEdge(7, 3); + builder.addEdge(7, 8); + builder.addEdge(8, 7); + Graph graph = builder.build(); + + int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, new int[] { 1, 2, 3, 4 }, + new GraphNodeFilter() { + @Override public boolean match(int node) { + return node != 0; + } + }); + sortSccs(sccs); + + assertThat(sccs.length, is(2)); + assertThat(sccs[0], is(new int[] { 1, 2 })); + assertThat(sccs[1], is(new int[] { 3, 4, 5, 6, 7, 8 })); + } + @Test public void irreducibleGraphSplit() { GraphBuilder builder = new GraphBuilder(); @@ -152,6 +187,39 @@ public class GraphTest { assertTrue("Should be equialent", isEquialent(backend, graph)); } + @Test + public void irreducibleGraphSplit3() { + GraphBuilder builder = new GraphBuilder(); + builder.addEdge(0, 1); + builder.addEdge(0, 2); + builder.addEdge(1, 2); + builder.addEdge(1, 3); + builder.addEdge(1, 4); + builder.addEdge(2, 1); + builder.addEdge(2, 3); + builder.addEdge(3, 4); + builder.addEdge(4, 5); + builder.addEdge(4, 6); + builder.addEdge(5, 6); + builder.addEdge(6, 5); + builder.addEdge(6, 7); + builder.addEdge(7, 4); + builder.addEdge(7, 3); + builder.addEdge(7, 8); + builder.addEdge(8, 7); + Graph graph = builder.build(); + + DefaultGraphSplittingBackend backend = new DefaultGraphSplittingBackend(graph); + int[] weights = new int[graph.size()]; + Arrays.fill(weights, 1); + GraphUtils.splitIrreducibleGraph(graph, weights, backend); + Graph result = backend.getGraph(); + + assertTrue("Should be irreducible", GraphUtils.isIrreducible(graph)); + assertFalse("Should be reducible", GraphUtils.isIrreducible(result)); + assertTrue("Should be equialent", isEquialent(backend, graph)); + } + private boolean isEquialent(DefaultGraphSplittingBackend backend, Graph proto) { Graph graph = backend.getGraph(); for (int node = 0; node < graph.size(); ++node) {