diff --git a/teavm-core/src/main/java/org/teavm/model/util/MutableGraphEdge.java b/teavm-core/src/main/java/org/teavm/common/MutableGraphEdge.java similarity index 94% rename from teavm-core/src/main/java/org/teavm/model/util/MutableGraphEdge.java rename to teavm-core/src/main/java/org/teavm/common/MutableGraphEdge.java index 3a38ddac2..9f5ffc6c6 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/MutableGraphEdge.java +++ b/teavm-core/src/main/java/org/teavm/common/MutableGraphEdge.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.model.util; +package org.teavm.common; /** * * @author Alexey Andreev */ -class MutableGraphEdge { +public class MutableGraphEdge { MutableGraphEdge back; MutableGraphNode first; MutableGraphNode second; @@ -44,6 +44,7 @@ class MutableGraphEdge { first.edges.remove(this.second); if (!second.edges.containsKey(first)) { this.second = second; + back.first = second; second.edges.put(first, back); first.edges.put(second, this); } else { diff --git a/teavm-core/src/main/java/org/teavm/model/util/MutableGraphNode.java b/teavm-core/src/main/java/org/teavm/common/MutableGraphNode.java similarity index 66% rename from teavm-core/src/main/java/org/teavm/model/util/MutableGraphNode.java rename to teavm-core/src/main/java/org/teavm/common/MutableGraphNode.java index 87958f352..981af1848 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/MutableGraphNode.java +++ b/teavm-core/src/main/java/org/teavm/common/MutableGraphNode.java @@ -13,17 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.model.util; +package org.teavm.common; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * * @author Alexey Andreev */ -class MutableGraphNode { +public class MutableGraphNode { int tag; Map edges = new HashMap<>(); @@ -48,6 +46,12 @@ class MutableGraphNode { return edge; } + public void connectAll(Collection nodes) { + for (MutableGraphNode node : nodes) { + connect(node); + } + } + public Collection getEdges() { return edges.values(); } @@ -55,4 +59,22 @@ class MutableGraphNode { public int getTag() { return tag; } + + public void setTag(int tag) { + this.tag = tag; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(tag).append(":"); + Iterator edges = this.edges.values().iterator(); + if (edges.hasNext()) { + sb.append(edges.next().getSecond().getTag()); + } + while (edges.hasNext()) { + sb.append(',').append(edges.next().getSecond().getTag()); + } + return sb.toString(); + } } diff --git a/teavm-core/src/main/java/org/teavm/model/util/GraphColorer.java b/teavm-core/src/main/java/org/teavm/model/util/GraphColorer.java index 2277129e9..66404b645 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/GraphColorer.java +++ b/teavm-core/src/main/java/org/teavm/model/util/GraphColorer.java @@ -16,14 +16,16 @@ package org.teavm.model.util; import java.util.BitSet; -import org.teavm.common.Graph; +import java.util.List; +import org.teavm.common.MutableGraphEdge; +import org.teavm.common.MutableGraphNode; /** * * @author Alexey Andreev */ class GraphColorer { - public void colorize(Graph graph, int[] colors) { + public void colorize(List graph, int[] colors) { BitSet usedColors = new BitSet(); for (int v : getOrdering(graph)) { if (colors[v] >= 0) { @@ -31,7 +33,8 @@ class GraphColorer { } usedColors.clear(); usedColors.set(0); - for (int succ : graph.outgoingEdges(v)) { + for (MutableGraphEdge edge : graph.get(v).getEdges()) { + int succ = edge.getSecond().getTag(); if (colors[succ] >= 0) { usedColors.set(colors[succ]); } @@ -40,7 +43,7 @@ class GraphColorer { } } - private int[] getOrdering(Graph graph) { + private int[] getOrdering(List graph) { boolean[] visited = new boolean[graph.size()]; int[] ordering = new int[graph.size()]; int index = 0; @@ -62,7 +65,8 @@ class GraphColorer { } visited[v] = true; ordering[index++] = v; - for (int succ : graph.outgoingEdges(v)) { + for (MutableGraphEdge edge : graph.get(v).getEdges()) { + int succ = edge.getSecond().getTag(); if (visited[succ]) { continue; } diff --git a/teavm-core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java b/teavm-core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java index 5d473f907..9b38bada5 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java @@ -15,10 +15,8 @@ */ package org.teavm.model.util; -import com.carrotsearch.hppc.IntOpenHashSet; import java.util.*; -import org.teavm.common.Graph; -import org.teavm.common.GraphBuilder; +import org.teavm.common.MutableGraphNode; import org.teavm.model.*; /** @@ -26,15 +24,16 @@ import org.teavm.model.*; * @author Alexey Andreev */ class InterferenceGraphBuilder { - public Graph build(Program program, int paramCount, LivenessAnalyzer liveness) { - List edges = new ArrayList<>(); + public List build(Program program, int paramCount, LivenessAnalyzer liveness) { + List nodes = new ArrayList<>(); for (int i = 0; i < program.variableCount(); ++i) { - edges.add(new IntOpenHashSet()); + nodes.add(new MutableGraphNode(i)); } UsageExtractor useExtractor = new UsageExtractor(); DefinitionExtractor defExtractor = new DefinitionExtractor(); InstructionTransitionExtractor succExtractor = new InstructionTransitionExtractor(); List> outgoings = getOutgoings(program); + Set live = new HashSet<>(128); for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); block.getLastInstruction().acceptVisitor(succExtractor); @@ -42,75 +41,49 @@ class InterferenceGraphBuilder { for (BasicBlock succ : succExtractor.getTargets()) { liveOut.or(liveness.liveIn(succ.getIndex())); } - IntOpenHashSet live = new IntOpenHashSet(8); + live.clear(); for (int j = 0; j < liveOut.length(); ++j) { if (liveOut.get(j)) { - live.add(j); + live.add(nodes.get(j)); } } for (Incoming outgoing : outgoings.get(i)) { - live.add(outgoing.getValue().getIndex()); + live.add(nodes.get(outgoing.getValue().getIndex())); } for (int j = block.getInstructions().size() - 1; j >= 0; --j) { Instruction insn = block.getInstructions().get(j); insn.acceptVisitor(useExtractor); insn.acceptVisitor(defExtractor); for (Variable var : defExtractor.getDefinedVariables()) { - edges.get(var.getIndex()).addAll(live); + nodes.get(var.getIndex()).connectAll(live); } for (Variable var : defExtractor.getDefinedVariables()) { - live.remove(var.getIndex()); + live.remove(nodes.get(var.getIndex())); } for (Variable var : useExtractor.getUsedVariables()) { - live.add(var.getIndex()); + live.add(nodes.get(var.getIndex())); } } if (block.getIndex() == 0) { for (int j = 0; j <= paramCount; ++j) { - edges.get(j).addAll(live); + nodes.get(j).connectAll(live); } } BitSet liveIn = liveness.liveIn(i); - live = new IntOpenHashSet(); + live.clear(); for (int j = 0; j < liveOut.length(); ++j) { if (liveIn.get(j)) { - live.add(j); + live.add(nodes.get(j)); } } for (Phi phi : block.getPhis()) { - live.add(phi.getReceiver().getIndex()); + live.add(nodes.get(phi.getReceiver().getIndex())); } for (Phi phi : block.getPhis()) { - edges.get(phi.getReceiver().getIndex()).addAll(live); + nodes.get(phi.getReceiver().getIndex()).connectAll(live); } } - GraphBuilder builder = new GraphBuilder(edges.size()); - List backEdges = new ArrayList<>(edges.size()); - for (int i = 0; i < edges.size(); ++i) { - backEdges.add(new IntOpenHashSet(8)); - } - for (int i = 0; i < edges.size(); ++i) { - IntOpenHashSet edgeSet = edges.get(i); - for (int j = 0; j < edgeSet.allocated.length; ++j) { - if (edgeSet.allocated[j]) { - backEdges.get(edgeSet.keys[j]).add(i); - } - } - for (int j = 0; j < edgeSet.allocated.length; ++j) { - if (edgeSet.allocated[j]) { - backEdges.get(i).add(edgeSet.keys[j]); - } - } - } - for (int i = 0; i < edges.size(); ++i) { - IntOpenHashSet edgeSet = backEdges.get(i); - for (int j = 0; j < edgeSet.allocated.length; ++j) { - if (edgeSet.allocated[j]) { - builder.addEdge(edgeSet.keys[j], i); - } - } - } - return builder.build(); + return nodes; } private List> getOutgoings(Program program) { diff --git a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java index fc57a134b..946fdf740 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java +++ b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java @@ -16,9 +16,7 @@ package org.teavm.model.util; import java.util.*; -import org.teavm.common.DisjointSet; -import org.teavm.common.Graph; -import org.teavm.common.GraphBuilder; +import org.teavm.common.*; import org.teavm.model.*; import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.EmptyInstruction; @@ -34,10 +32,11 @@ public class RegisterAllocator { InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder(); LivenessAnalyzer liveness = new LivenessAnalyzer(); liveness.analyze(program); - Graph interferenceGraph = interferenceBuilder.build(program, method.parameterCount(), liveness); + List interferenceGraph = interferenceBuilder.build( + program, method.parameterCount(), liveness); DisjointSet congruenceClasses = buildPhiCongruenceClasses(program); - List classInterferenceGraph = makeMutableGraph(interferenceGraph, congruenceClasses); - removeRedundantCopies(program, classInterferenceGraph, congruenceClasses); + joinClassNodes(interferenceGraph, congruenceClasses); + removeRedundantCopies(program, interferenceGraph, congruenceClasses); int[] classArray = congruenceClasses.pack(program.variableCount()); renameVariables(program, classArray); int[] colors = new int[program.variableCount()]; @@ -45,30 +44,33 @@ public class RegisterAllocator { for (int i = 0; i <= method.parameterCount(); ++i) { colors[i] = i; } + renameInterferenceGraph(interferenceGraph, congruenceClasses, classArray); GraphColorer colorer = new GraphColorer(); - colorer.colorize(renameInterferenceGraph(interferenceGraph, classArray), colors); + colorer.colorize(interferenceGraph, colors); for (int i = 0; i < colors.length; ++i) { program.variableAt(i).setRegister(colors[i]); } } - private static List makeMutableGraph(Graph graph, DisjointSet classes) { - List mutableGraph = new ArrayList<>(); - for (int i = 0; i < graph.size(); ++i) { + private static void joinClassNodes(List graph, DisjointSet classes) { + int sz = graph.size(); + for (int i = 0; i < sz; ++i) { int cls = classes.find(i); - while (cls >= mutableGraph.size()) { - mutableGraph.add(new MutableGraphNode(mutableGraph.size())); + while (cls >= graph.size()) { + graph.add(new MutableGraphNode(graph.size())); } - MutableGraphNode node = mutableGraph.get(cls); - for (int j : graph.outgoingEdges(i)) { - int otherCls = classes.find(j); - while (otherCls >= mutableGraph.size()) { - mutableGraph.add(new MutableGraphNode(mutableGraph.size())); + if (cls != i) { + for (MutableGraphEdge edge : graph.get(i).getEdges().toArray(new MutableGraphEdge[0])) { + if (edge.getFirst() == graph.get(i)) { + edge.setFirst(graph.get(cls)); + } + if (edge.getSecond() == graph.get(i)) { + edge.setSecond(graph.get(cls)); + } } - node.connect(mutableGraph.get(otherCls)); + graph.set(i, graph.get(cls)); } } - return mutableGraph; } private void insertPhiArgumentsCopies(Program program) { @@ -167,16 +169,24 @@ public class RegisterAllocator { } for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges() .toArray(new MutableGraphEdge[0])) { - if (edge.getFirst() != null) { + if (edge.getFirst() == interferenceGraph.get(origClass)) { edge.setFirst(interferenceGraph.get(newClass)); } + if (edge.getSecond() == interferenceGraph.get(origClass)) { + edge.setSecond(interferenceGraph.get(newClass)); + } } for (MutableGraphEdge edge : interferenceGraph.get(copyClass).getEdges() .toArray(new MutableGraphEdge[0])) { - if (edge.getFirst() != null) { + if (edge.getFirst() == interferenceGraph.get(copyClass)) { edge.setFirst(interferenceGraph.get(newClass)); } + if (edge.getSecond() == interferenceGraph.get(copyClass)) { + edge.setSecond(interferenceGraph.get(newClass)); + } } + interferenceGraph.set(copyClass, interferenceGraph.get(newClass)); + interferenceGraph.set(origClass, interferenceGraph.get(newClass)); } } } @@ -206,14 +216,21 @@ public class RegisterAllocator { } } - private Graph renameInterferenceGraph(Graph graph, final int[] varMap) { - GraphBuilder renamedGraph = new GraphBuilder(); + private void renameInterferenceGraph(List graph, DisjointSet classes, final int[] varMap) { + List newGraph = new ArrayList<>(); for (int i = 0; i < graph.size(); ++i) { - for (int j : graph.outgoingEdges(i)) { - renamedGraph.addEdge(varMap[i], varMap[j]); + int mapped = varMap[i]; + while (newGraph.size() <= mapped) { + newGraph.add(null); + } + if (newGraph.get(mapped) == null) { + int cls = classes.find(i); + newGraph.set(mapped, graph.get(cls)); + graph.get(cls).setTag(mapped); } } - return renamedGraph.build(); + graph.clear(); + graph.addAll(newGraph); } private DisjointSet buildPhiCongruenceClasses(Program program) {