From e951b681ca1a96fdb2aa32bdb5b73f9655b095ad Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sun, 8 Mar 2015 11:57:03 +0300 Subject: [PATCH] Fix ordering of basic blocks before decompilation --- .../java/org/teavm/common/GraphIndexer.java | 149 ++++++++++-------- 1 file changed, 83 insertions(+), 66 deletions(-) diff --git a/teavm-core/src/main/java/org/teavm/common/GraphIndexer.java b/teavm-core/src/main/java/org/teavm/common/GraphIndexer.java index 9a968ffee..7fba32a06 100644 --- a/teavm-core/src/main/java/org/teavm/common/GraphIndexer.java +++ b/teavm-core/src/main/java/org/teavm/common/GraphIndexer.java @@ -15,8 +15,10 @@ */ package org.teavm.common; +import com.carrotsearch.hppc.IntOpenHashSet; +import com.carrotsearch.hppc.IntSet; +import com.carrotsearch.hppc.cursors.IntCursor; import java.util.Arrays; -import java.util.Comparator; /** * @@ -28,74 +30,21 @@ public class GraphIndexer { static final byte VISITED = 2; private int[] indexToNode; private int[] nodeToIndex; + private byte[] state; private Graph graph; + private DominatorTree domTree; + private int lastIndex; public GraphIndexer(Graph graph) { - sort(graph); - } - - private static class LoopEntrance { - int head; - int follower; - } - - private int sort(Graph graph) { - LoopGraph loopGraph = new LoopGraph(graph); int sz = graph.size(); - int[] indexToNode = new int[sz + 1]; - int[] nodeToIndex = new int[sz + 1]; - int[] visitIndex = new int[sz + 1]; + indexToNode = new int[sz + 1]; + nodeToIndex = new int[sz + 1]; Arrays.fill(nodeToIndex, -1); Arrays.fill(indexToNode, -1); - Arrays.fill(visitIndex, -1); - byte[] state = new byte[sz]; - int lastIndex = 0; - int lastVisitIndex = 0; - IntegerStack stack = new IntegerStack(sz * 2); - stack.push(loopGraph.loopAt(0) != null ? loopGraph.loopAt(0).getHead() : 0); - while (!stack.isEmpty()) { - int node = stack.pop(); - switch (state[node]) { - case VISITING: { - state[node] = VISITED; - nodeToIndex[node] = lastIndex++; - break; - } - case NONE: { - visitIndex[node] = lastVisitIndex++; - state[node] = VISITING; - stack.push(node); - int[] successors = graph.outgoingEdges(node); - LoopEntrance[] edges = new LoopEntrance[successors.length]; - for (int i = 0; i < edges.length; ++i) { - int successor = successors[i]; - Loop successorLoop = loopGraph.loopAt(successor); - LoopEntrance edge = new LoopEntrance(); - edge.head = successorLoop != null ? - visitIndex[successorLoop.getHead()] : -1; - edge.follower = successor; - edges[i] = edge; - } - Arrays.sort(edges, new Comparator() { - @Override - public int compare(LoopEntrance o1, LoopEntrance o2) { - return Integer.compare(o2.head, o1.head); - } - }); - for (LoopEntrance edge : edges) { - int next = edge.follower; - switch (state[next]) { - case NONE: - stack.push(next); - break; - default: - break; - } - } - break; - } - } - } + state = new byte[sz]; + this.graph = graph; + domTree = GraphUtils.buildDominatorTree(graph); + sort(graph); --lastIndex; for (int node = 0; node < sz; ++node) { int index = nodeToIndex[node]; @@ -115,9 +64,77 @@ public class GraphIndexer { } } this.graph = sorted.build(); - this.indexToNode = indexToNode; - this.nodeToIndex = nodeToIndex; - return lastIndex + 1; + } + + private void sort(Graph graph) { + int sz = graph.size(); + IntegerStack stack = new IntegerStack(sz * 2); + stack.push(0); + while (!stack.isEmpty()) { + int node = stack.pop(); + switch (state[node]) { + case VISITING: { + state[node] = VISITED; + nodeToIndex[node] = lastIndex++; + break; + } + case NONE: { + state[node] = VISITING; + stack.push(node); + IntegerArray terminalNodes = new IntegerArray(1); + for (int pred : graph.incomingEdges(node)) { + if (domTree.dominates(node, pred)) { + terminalNodes.add(pred); + } + } + int[] successors = graph.outgoingEdges(node); + if (terminalNodes.size() > 0) { + IntSet loopNodes = IntOpenHashSet.from(findNaturalLoop(node, terminalNodes.getAll())); + IntegerArray orderedSuccessors = new IntegerArray(successors.length); + for (int succ : successors) { + if (loopNodes.contains(succ)) { + orderedSuccessors.add(succ); + } + } + IntSet outerSuccessors = new IntOpenHashSet(successors.length); + for (IntCursor loopNode : loopNodes) { + for (int succ : graph.outgoingEdges(loopNode.value)) { + if (!loopNodes.contains(succ)) { + outerSuccessors.add(succ); + } + } + } + orderedSuccessors.addAll(outerSuccessors.toArray()); + successors = orderedSuccessors.getAll(); + } + for (int succ : successors) { + if (state[succ] == NONE) { + stack.push(succ); + } + } + break; + } + } + } + } + + private int[] findNaturalLoop(int head, int[] terminals) { + IntSet loop = new IntOpenHashSet(); + loop.add(head); + IntegerStack stack = new IntegerStack(1); + for (int pred : terminals) { + stack.push(pred); + } + while (!stack.isEmpty()) { + int node = stack.pop(); + if (!loop.add(node)) { + continue; + } + for (int pred : graph.incomingEdges(node)) { + stack.push(pred); + } + } + return loop.toArray(); } public int nodeAt(int index) {