diff --git a/core/src/main/java/org/teavm/common/DefaultGraphSplittingBackend.java b/core/src/main/java/org/teavm/common/DefaultGraphSplittingBackend.java index 3a2453123..44f774568 100644 --- a/core/src/main/java/org/teavm/common/DefaultGraphSplittingBackend.java +++ b/core/src/main/java/org/teavm/common/DefaultGraphSplittingBackend.java @@ -18,10 +18,6 @@ package org.teavm.common; import com.carrotsearch.hppc.IntIntMap; import com.carrotsearch.hppc.IntIntOpenHashMap; -/** - * - * @author Alexey Andreev - */ public class DefaultGraphSplittingBackend implements GraphSplittingBackend { private MutableDirectedGraph graph; private int index; @@ -49,10 +45,6 @@ public class DefaultGraphSplittingBackend implements GraphSplittingBackend { return prototypeNodes.get(index); } - public int copyIndex(int index) { - return copyIndexes.get(index); - } - @Override public int[] split(int[] domain, int[] nodes) { int[] copies = new int[nodes.length]; diff --git a/core/src/main/java/org/teavm/common/GraphSplittingBackend.java b/core/src/main/java/org/teavm/common/GraphSplittingBackend.java index 791764e76..42fe9d91d 100644 --- a/core/src/main/java/org/teavm/common/GraphSplittingBackend.java +++ b/core/src/main/java/org/teavm/common/GraphSplittingBackend.java @@ -15,10 +15,6 @@ */ package org.teavm.common; -/** - * - * @author Alexey Andreev - */ public interface GraphSplittingBackend { int[] split(int[] domain, int[] nodes); } diff --git a/core/src/main/java/org/teavm/common/GraphUtils.java b/core/src/main/java/org/teavm/common/GraphUtils.java index eb2bc06cb..365d1fd11 100644 --- a/core/src/main/java/org/teavm/common/GraphUtils.java +++ b/core/src/main/java/org/teavm/common/GraphUtils.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.IntPredicate; +import java.util.stream.Collectors; /** * @@ -371,4 +372,16 @@ public final class GraphUtils { } return set; } + + public static String printToDot(Graph graph) { + StringBuilder sb = new StringBuilder("digraph G {\n"); + for (int i = 0; i < graph.size(); ++i) { + String successors = Arrays.stream(graph.outgoingEdges(i)) + .mapToObj(String::valueOf) + .collect(Collectors.joining(", ")); + sb.append(" ").append(i).append(" -> {").append(successors).append("}\n"); + } + sb.append("}"); + return sb.toString(); + } } diff --git a/core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java b/core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java index ec8a79003..17cd3fe83 100644 --- a/core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java +++ b/core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java @@ -32,9 +32,19 @@ class IrreducibleGraphConverter { private Graph cfg; private int totalNodeCount; private GraphSplittingBackend backend; + private IntSet[] nodeCopies; + private IntegerArray nodeOriginals; public void convertToReducible(Graph cfg, int[] weight, GraphSplittingBackend backend) { this.backend = backend; + + nodeCopies = new IntOpenHashSet[cfg.size()]; + nodeOriginals = new IntegerArray(cfg.size()); + for (int i = 0; i < cfg.size(); ++i) { + nodeCopies[i] = new IntOpenHashSet(); + nodeOriginals.add(i); + } + int[][] identityNodeMap = new int[cfg.size()][]; for (int i = 0; i < identityNodeMap.length; ++i) { identityNodeMap[i] = new int[] { i }; @@ -163,7 +173,11 @@ class IrreducibleGraphConverter { } // Delegate splitting to domain - int[][] newNodes = unflatten(backend.split(flatten(mappedDomain), flatten(mappedNonDomain)), mappedNonDomain); + int[] nodesToCopy = withCopies(flatten(mappedNonDomain)); + int[] copies = backend.split(withCopies(flatten(mappedDomain)), nodesToCopy); + registerCopies(nodesToCopy, copies); + + int[][] newNodes = unflatten(withoutCopies(copies), mappedNonDomain); for (int[] nodes : newNodes) { totalNodeCount += nodes.length; } @@ -231,6 +245,50 @@ class IrreducibleGraphConverter { handleLoops(new DJGraph(builder.build(), mappedWeight), newNodeMap); } + private int[] withCopies(int[] nodes) { + IntegerArray nodesWithCopies = new IntegerArray(nodes.length); + for (int node : nodes) { + nodesWithCopies.add(node); + IntSet copies = nodeCopies[node]; + if (copies != null) { + nodesWithCopies.addAll(copies.toArray()); + } + } + return nodesWithCopies.getAll(); + } + + private int[] withoutCopies(int[] nodesWithCopies) { + IntSet visited = new IntOpenHashSet(); + int[] nodes = new int[nodesWithCopies.length]; + int sz = 0; + for (int node : nodesWithCopies) { + node = nodeOriginals.get(node); + if (visited.add(node)) { + nodes[sz++] = node; + } + } + return Arrays.copyOf(nodes, sz); + } + + private void registerCopies(int[] originalNodes, int[] copies) { + for (int i = 0; i < originalNodes.length; ++i) { + int original = nodeOriginals.get(originalNodes[i]); + int copy = copies[i]; + IntSet knownCopies = nodeCopies[original]; + if (knownCopies == null) { + knownCopies = new IntOpenHashSet(); + nodeCopies[original] = knownCopies; + } + + if (knownCopies.add(copy)) { + while (nodeOriginals.size() <= copy) { + nodeOriginals.add(-1); + } + nodeOriginals.set(copy, original); + } + } + } + private void collapse(DJGraph djGraph, int[] scc, int[][] nodeMap) { int cls = djGraph.collapse(scc); IntegerArray nodes = new IntegerArray(djGraph.getGraph().size()); diff --git a/core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java b/core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java index 7369f7c38..3584ee3b5 100644 --- a/core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java +++ b/core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java @@ -21,10 +21,6 @@ import org.teavm.common.GraphSplittingBackend; import org.teavm.model.BasicBlock; import org.teavm.model.Program; -/** - * - * @author Alexey Andreev - */ public class ProgramNodeSplittingBackend implements GraphSplittingBackend { private Program program; diff --git a/core/src/test/java/org/teavm/common/GraphTest.java b/core/src/test/java/org/teavm/common/GraphTest.java index 10632d610..ffddbf5bd 100644 --- a/core/src/test/java/org/teavm/common/GraphTest.java +++ b/core/src/test/java/org/teavm/common/GraphTest.java @@ -26,10 +26,6 @@ import java.util.Comparator; import java.util.function.IntPredicate; import org.junit.Test; -/** - * - * @author Alexey Andreev - */ public class GraphTest { @Test public void stronglyConnectedComponentsCalculated() { @@ -205,7 +201,6 @@ public class GraphTest { 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); @@ -214,7 +209,7 @@ public class GraphTest { assertTrue("Should be irreducible", GraphUtils.isIrreducible(graph)); assertFalse("Should be reducible", GraphUtils.isIrreducible(result)); - assertTrue("Should be equialent", isEquialent(backend, graph)); + assertTrue("Should be equivalent", isEquialent(backend, graph)); } private boolean isEquialent(DefaultGraphSplittingBackend backend, Graph proto) {