mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
Improve DJ-graph implementation. Add Tarjan's SCC finding algorithm. Add
HPCC dependency.
This commit is contained in:
parent
11437af5ae
commit
14ce9e23a4
@ -40,6 +40,11 @@
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-debug-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.carrotsearch</groupId>
|
||||
<artifactId>hppc</artifactId>
|
||||
<version>0.6.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<name>TeaVM core</name>
|
||||
|
@ -15,6 +15,10 @@
|
||||
*/
|
||||
package org.teavm.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
@ -22,39 +26,57 @@ package org.teavm.common;
|
||||
public class DJGraph {
|
||||
private DominatorTree domTree;
|
||||
private Graph graph;
|
||||
private Graph backEdges;
|
||||
private LCATree spanningTree;
|
||||
private int[] spanningTreeNode;
|
||||
private int[] spanningTreeIndex;
|
||||
private int[][] levelContent;
|
||||
|
||||
public DJGraph(Graph src) {
|
||||
domTree = GraphUtils.buildDominatorTree(src);
|
||||
buildGraph(src);
|
||||
buildLevels();
|
||||
dfs();
|
||||
}
|
||||
|
||||
private void buildGraph(Graph graph) {
|
||||
GraphBuilder builder = new GraphBuilder(graph.size());
|
||||
|
||||
// Add join edges
|
||||
for (int i = 0; i < graph.size(); ++i) {
|
||||
for (int j : graph.outgoingEdges(i)) {
|
||||
builder.addEdge(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
// Add dom edges
|
||||
for (int i = 1; i < graph.size(); ++i) {
|
||||
int j = domTree.immediateDominatorOf(i);
|
||||
boolean needsDomEdge = true;
|
||||
for (int k : graph.incomingEdges(i)) {
|
||||
if (k == j) {
|
||||
needsDomEdge = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needsDomEdge) {
|
||||
builder.addEdge(j, i);
|
||||
}
|
||||
builder.addEdge(j, i);
|
||||
}
|
||||
|
||||
graph = builder.build();
|
||||
}
|
||||
|
||||
private void buildLevels() {
|
||||
List<IntegerArray> builder = new ArrayList<>();
|
||||
for (int i = 0; i < graph.size(); ++i) {
|
||||
int level = domTree.levelOf(i);
|
||||
while (level >= builder.size()) {
|
||||
builder.add(new IntegerArray(1));
|
||||
}
|
||||
builder.get(level).add(i);
|
||||
}
|
||||
levelContent = new int[builder.size()][];
|
||||
for (int i = 0; i < builder.size(); ++i) {
|
||||
levelContent[i] = builder.get(i).getAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void dfs() {
|
||||
GraphBuilder builder = new GraphBuilder();
|
||||
spanningTreeNode = new int[graph.size()];
|
||||
spanningTreeIndex = new int[graph.size()];
|
||||
Arrays.fill(spanningTreeIndex, -1);
|
||||
Arrays.fill(spanningTreeNode, -1);
|
||||
boolean[] visited = new boolean[graph.size()];
|
||||
IntegerStack stack = new IntegerStack(graph.size() * 2);
|
||||
stack.push(0);
|
||||
@ -63,16 +85,17 @@ public class DJGraph {
|
||||
int node = stack.pop();
|
||||
int source = stack.pop();
|
||||
if (visited[node]) {
|
||||
builder.addEdge(node, source);
|
||||
continue;
|
||||
}
|
||||
int index = spanningTree.addNode(spanningTreeIndex[source]);
|
||||
spanningTreeNode[index] = node;
|
||||
spanningTreeIndex[node] = index;
|
||||
visited[node] = true;
|
||||
for (int succ : graph.outgoingEdges(node)) {
|
||||
stack.push(node);
|
||||
stack.push(succ);
|
||||
}
|
||||
}
|
||||
backEdges = builder.build();
|
||||
}
|
||||
|
||||
public DominatorTree getDomTree() {
|
||||
@ -83,7 +106,50 @@ public class DJGraph {
|
||||
return graph;
|
||||
}
|
||||
|
||||
public int[] getSpanningTreeBackEdges(int node) {
|
||||
return backEdges.outgoingEdges(node);
|
||||
public boolean isAncestorInSpanningTree(int anc, int node) {
|
||||
anc = spanningTreeIndex[anc];
|
||||
node = spanningTreeIndex[node];
|
||||
if (anc < 0 || node < 0) {
|
||||
return false;
|
||||
}
|
||||
return spanningTree.lcaOf(anc, node) == anc;
|
||||
}
|
||||
|
||||
public boolean isDomEdge(int i, int j) {
|
||||
return domTree.immediateDominatorOf(j) == i;
|
||||
}
|
||||
|
||||
public boolean isJoinEdge(int i, int j) {
|
||||
return !isDomEdge(i, j);
|
||||
}
|
||||
|
||||
public boolean isBackJoin(int i, int j) {
|
||||
return isJoinEdge(i, j) && !domTree.dominates(j, i);
|
||||
}
|
||||
|
||||
public boolean isCrossJoin(int i, int j) {
|
||||
return isJoinEdge(i, j) && domTree.dominates(j, i);
|
||||
}
|
||||
|
||||
public boolean isSpanningBack(int i, int j) {
|
||||
return spanningTree.lcaOf(i, j) == j;
|
||||
}
|
||||
|
||||
public boolean isSpanningCross(int i, int j) {
|
||||
int c = spanningTree.lcaOf(i, j);
|
||||
return c != i && c != j;
|
||||
}
|
||||
|
||||
public int levelOf(int node) {
|
||||
return domTree.levelOf(node);
|
||||
}
|
||||
|
||||
public int[] level(int level) {
|
||||
int[] result = levelContent[level];
|
||||
return Arrays.copyOf(result, result.length);
|
||||
}
|
||||
|
||||
public int levelCount() {
|
||||
return levelContent.length;
|
||||
}
|
||||
}
|
||||
|
@ -21,42 +21,42 @@ package org.teavm.common;
|
||||
*/
|
||||
class DefaultDominatorTree implements DominatorTree {
|
||||
private LCATree lcaTree;
|
||||
private int[] indexes;
|
||||
private int[] nodes;
|
||||
private int[] unodes;
|
||||
|
||||
public DefaultDominatorTree(int[] dominators, int[] vertices) {
|
||||
lcaTree = new LCATree(dominators.length + 1);
|
||||
indexes = new int[dominators.length + 1];
|
||||
nodes = new int[dominators.length + 1];
|
||||
unodes = new int[dominators.length + 1];
|
||||
nodes[0] = -1;
|
||||
indexes[0] = -1;
|
||||
for (int i = 0; i < dominators.length; ++i) {
|
||||
int v = vertices[i];
|
||||
if (v < 0) {
|
||||
continue;
|
||||
}
|
||||
int dom = nodes[dominators[v] + 1];
|
||||
int dom = indexes[dominators[v] + 1];
|
||||
int node = lcaTree.addNode(dom);
|
||||
nodes[v + 1] = node;
|
||||
unodes[node] = v;
|
||||
indexes[v + 1] = node;
|
||||
nodes[node] = v;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean directlyDominates(int a, int b) {
|
||||
a = nodes[a + 1];
|
||||
b = nodes[b + 1];
|
||||
a = indexes[a + 1];
|
||||
b = indexes[b + 1];
|
||||
return lcaTree.lcaOf(a, b) == a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int commonDominatorOf(int a, int b) {
|
||||
return unodes[lcaTree.lcaOf(nodes[a + 1], nodes[b + 1])];
|
||||
return nodes[lcaTree.lcaOf(indexes[a + 1], indexes[b + 1])];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dominates(int a, int b) {
|
||||
a = nodes[a + 1];
|
||||
b = nodes[b + 1];
|
||||
a = indexes[a + 1];
|
||||
b = indexes[b + 1];
|
||||
return lcaTree.lcaOf(a, b) == a;
|
||||
}
|
||||
|
||||
@ -65,7 +65,13 @@ class DefaultDominatorTree implements DominatorTree {
|
||||
if (a == 0) {
|
||||
return -1;
|
||||
}
|
||||
int result = lcaTree.parentOf(nodes[a + 1]);
|
||||
return result >= 0 ? unodes[result] : -1;
|
||||
int result = lcaTree.parentOf(indexes[a + 1]);
|
||||
return result >= 0 ? nodes[result] : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int levelOf(int a) {
|
||||
int index = indexes[a];
|
||||
return lcaTree.depthOf(index);
|
||||
}
|
||||
}
|
||||
|
@ -27,4 +27,6 @@ public interface DominatorTree {
|
||||
boolean dominates(int a, int b);
|
||||
|
||||
int immediateDominatorOf(int a);
|
||||
|
||||
int levelOf(int a);
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.teavm.common;
|
||||
|
||||
import com.carrotsearch.hppc.IntOpenHashSet;
|
||||
import com.carrotsearch.hppc.IntSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -26,14 +28,14 @@ import java.util.List;
|
||||
*/
|
||||
public class GraphBuilder {
|
||||
private GraphImpl builtGraph;
|
||||
private List<IntegerArray> addedEdges = new ArrayList<>();
|
||||
private List<IntSet> addedEdges = new ArrayList<>();
|
||||
private int sz;
|
||||
|
||||
public GraphBuilder() {
|
||||
}
|
||||
|
||||
public GraphBuilder(int sz) {
|
||||
addedEdges.addAll(Collections.<IntegerArray>nCopies(sz, null));
|
||||
addedEdges.addAll(Collections.<IntSet>nCopies(sz, null));
|
||||
this.sz = sz;
|
||||
}
|
||||
|
||||
@ -49,14 +51,14 @@ public class GraphBuilder {
|
||||
sz = Math.max(sz, Math.max(from, to) + 1);
|
||||
builtGraph = null;
|
||||
if (addedEdges.size() == from) {
|
||||
addedEdges.add(IntegerArray.of(to));
|
||||
addedEdges.add(IntOpenHashSet.from(to));
|
||||
} else if (addedEdges.size() <= from) {
|
||||
addedEdges.addAll(Collections.<IntegerArray>nCopies(from - addedEdges.size(), null));
|
||||
addedEdges.add(IntegerArray.of(to));
|
||||
addedEdges.addAll(Collections.<IntSet>nCopies(from - addedEdges.size(), null));
|
||||
addedEdges.add(IntOpenHashSet.from(to));
|
||||
} else {
|
||||
IntegerArray set = addedEdges.get(from);
|
||||
IntSet set = addedEdges.get(from);
|
||||
if (set == null) {
|
||||
addedEdges.set(from, IntegerArray.of(to));
|
||||
addedEdges.set(from, IntOpenHashSet.from(to));
|
||||
} else {
|
||||
set.add(to);
|
||||
}
|
||||
@ -65,14 +67,15 @@ public class GraphBuilder {
|
||||
|
||||
public Graph build() {
|
||||
if (builtGraph == null) {
|
||||
IntegerArray[] incomingEdges = new IntegerArray[sz];
|
||||
IntSet[] incomingEdges = new IntSet[sz];
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
incomingEdges[i] = new IntegerArray(1);
|
||||
incomingEdges[i] = new IntOpenHashSet();
|
||||
}
|
||||
int[][] outgoingEdgeList = new int[sz][];
|
||||
for (int i = 0; i < addedEdges.size(); ++i) {
|
||||
IntegerArray edgeList = addedEdges.get(i);
|
||||
outgoingEdgeList[i] = edgeList != null ? edgeList.getAll() : new int[0];
|
||||
IntSet edgeList = addedEdges.get(i);
|
||||
outgoingEdgeList[i] = edgeList != null ? edgeList.toArray() : new int[0];
|
||||
Arrays.sort(outgoingEdgeList[i]);
|
||||
for (int j : outgoingEdgeList[i]) {
|
||||
incomingEdges[j].add(i);
|
||||
}
|
||||
@ -82,7 +85,8 @@ public class GraphBuilder {
|
||||
}
|
||||
int[][] incomingEdgeList = new int[sz][];
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
incomingEdgeList[i] = incomingEdges[i].getAll();
|
||||
incomingEdgeList[i] = incomingEdges[i].toArray();
|
||||
Arrays.sort(incomingEdgeList);
|
||||
}
|
||||
builtGraph = new GraphImpl(incomingEdgeList, outgoingEdgeList);
|
||||
}
|
||||
|
@ -61,6 +61,10 @@ public class LCATree {
|
||||
return path.length > 0 ? path[0] : -1;
|
||||
}
|
||||
|
||||
public int depthOf(int node) {
|
||||
return depths[node];
|
||||
}
|
||||
|
||||
public int lcaOf(int a, int b) {
|
||||
if (a == b) {
|
||||
return a;
|
||||
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.common;
|
||||
|
||||
import com.carrotsearch.hppc.IntOpenHashSet;
|
||||
import com.carrotsearch.hppc.IntSet;
|
||||
import com.carrotsearch.hppc.cursors.IntCursor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class MutableDirectedGraph implements Graph {
|
||||
private List<IntSet> successors = new ArrayList<>();
|
||||
private List<IntSet> predecessors = new ArrayList<>();
|
||||
|
||||
public MutableDirectedGraph() {
|
||||
}
|
||||
|
||||
public MutableDirectedGraph(Graph graph) {
|
||||
int[] data = new int[graph.size()];
|
||||
for (int i = 0; i < graph.size(); ++i) {
|
||||
int sz = graph.copyOutgoingEdges(i, data);
|
||||
for (int j = 0; j < sz; ++j) {
|
||||
addEdge(i, data[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return successors.size();
|
||||
}
|
||||
|
||||
public void addEdge(int from, int to) {
|
||||
int max = Math.max(from, to);
|
||||
while (max >= successors.size()) {
|
||||
successors.add(new IntOpenHashSet(1));
|
||||
predecessors.add(new IntOpenHashSet(1));
|
||||
}
|
||||
successors.get(from).add(to);
|
||||
predecessors.get(to).add(from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] incomingEdges(int node) {
|
||||
return predecessors.get(node).toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int copyIncomingEdges(int node, int[] target) {
|
||||
int index = 0;
|
||||
for (IntCursor cursor : predecessors.get(node)) {
|
||||
target[index++] = cursor.value;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] outgoingEdges(int node) {
|
||||
return successors.get(node).toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int copyOutgoingEdges(int node, int[] target) {
|
||||
int index = 0;
|
||||
for (IntCursor cursor : successors.get(node)) {
|
||||
target[index++] = cursor.value;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int incomingEdgesCount(int node) {
|
||||
return predecessors.get(node).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int outgoingEdgesCount(int node) {
|
||||
return successors.get(node).size();
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.model.util;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface GraphSplittingBackend {
|
||||
int[] split(int[] nodes);
|
||||
}
|
@ -15,33 +15,137 @@
|
||||
*/
|
||||
package org.teavm.model.util;
|
||||
|
||||
import com.carrotsearch.hppc.IntOpenHashSet;
|
||||
import com.carrotsearch.hppc.IntSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.teavm.common.DisjointSet;
|
||||
import org.teavm.common.Graph;
|
||||
import org.teavm.common.MutableGraphNode;
|
||||
import org.teavm.common.*;
|
||||
|
||||
/**
|
||||
* <p>Converts irreducible graph to reducible one using node splitting algorithm described at
|
||||
* the paper “Handling irreducible loops: optimized node splitting vs. DJ-graphs” by
|
||||
* Sebastian Unger and Frank Mueller.</p>
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class IrreducibleGraphConverter {
|
||||
List<MutableGraphNode> nodes = new ArrayList<>();
|
||||
DisjointSet nodeClasses = new DisjointSet();
|
||||
private MutableDirectedGraph graph;
|
||||
private DisjointSet nodeClasses = new DisjointSet();
|
||||
private List<IntegerArray> classContents = new ArrayList<>();
|
||||
private DJGraph djGraph;
|
||||
private GraphSplittingBackend backend;
|
||||
|
||||
public void convertToReducible(Graph graph) {
|
||||
buildMutableCFG(graph);
|
||||
public void convertToReducible(Graph cfg, GraphSplittingBackend backend) {
|
||||
this.backend = backend;
|
||||
buildMutableCFG(cfg);
|
||||
rebuildDJGraph();
|
||||
splitLoops(0, allNodesOf(cfg));
|
||||
this.backend = null;
|
||||
}
|
||||
|
||||
private void buildMutableCFG(Graph graph) {
|
||||
nodes.clear();
|
||||
for (int i = 0; i < graph.size(); ++i) {
|
||||
nodes.add(new MutableGraphNode(i));
|
||||
private boolean splitLoops(int top, IntSet nodesToHandle) {
|
||||
boolean hasCrossEdge = false;
|
||||
for (int child : djGraph.getGraph().outgoingEdges(top)) {
|
||||
if (!djGraph.isDomEdge(top, child)) {
|
||||
continue;
|
||||
}
|
||||
hasCrossEdge |= nodesToHandle.contains(child) && splitLoops(child, nodesToHandle);
|
||||
}
|
||||
for (int i = 0; i < graph.size(); ++i) {
|
||||
for (int j : graph.outgoingEdges(i)) {
|
||||
nodes.get(i).connect(nodes.get(j));
|
||||
if (hasCrossEdge) {
|
||||
handleIrreducibleLoopChildren(top, nodesToHandle);
|
||||
}
|
||||
for (int pred : graph.incomingEdges(top)) {
|
||||
if (djGraph.isSpanningBack(pred, top) && djGraph.isCrossJoin(top, pred)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleIrreducibleLoopChildren(int top, IntSet nodesToHandle) {
|
||||
List<int[]> sccs = findStronglyConnectedComponents(top, nodesToHandle, djGraph.levelOf(top));
|
||||
for (int[] scc : sccs) {
|
||||
if (scc.length > 1) {
|
||||
handleStronglyConnectedComponent(top, scc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStronglyConnectedComponent(int top, int[] nodes) {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Tarjan's algorithm
|
||||
*/
|
||||
private List<int[]> findStronglyConnectedComponents(int start, IntSet nodesToHandle, int topLevel) {
|
||||
List<int[]> components = new ArrayList<>();
|
||||
boolean[] done = new boolean[djGraph.getGraph().size()];
|
||||
int[] visitIndex = new int[djGraph.getGraph().size()];
|
||||
Arrays.fill(visitIndex, -1);
|
||||
int[] headerIndex = new int[djGraph.getGraph().size()];
|
||||
int lastIndex = 0;
|
||||
IntegerStack stack = new IntegerStack(nodesToHandle.size());
|
||||
stack.push(-1);
|
||||
stack.push(start);
|
||||
|
||||
IntegerArray currentComponent = new IntegerArray(1);
|
||||
while (!stack.isEmpty()) {
|
||||
int node = stack.pop();
|
||||
if (visitIndex[node] == 0) {
|
||||
if (done[node]) {
|
||||
currentComponent.add(node);
|
||||
int hdr = node;
|
||||
for (int successor : djGraph.getGraph().outgoingEdges(node)) {
|
||||
if (!nodesToHandle.contains(successor) || djGraph.levelOf(node) < topLevel) {
|
||||
continue;
|
||||
}
|
||||
if (!done[successor]) {
|
||||
hdr = Math.min(hdr, visitIndex[successor]);
|
||||
} else {
|
||||
hdr = Math.min(hdr, headerIndex[successor]);
|
||||
}
|
||||
}
|
||||
if (hdr == node) {
|
||||
components.add(currentComponent.getAll());
|
||||
currentComponent.clear();
|
||||
}
|
||||
headerIndex[node] = hdr;
|
||||
} else {
|
||||
done[node] = true;
|
||||
}
|
||||
} else {
|
||||
visitIndex[node] = ++lastIndex;
|
||||
stack.push(node);
|
||||
for (int successor : djGraph.getGraph().outgoingEdges(node)) {
|
||||
if (!nodesToHandle.contains(successor) || djGraph.levelOf(node) >= topLevel) {
|
||||
continue;
|
||||
}
|
||||
stack.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
private void buildMutableCFG(Graph cfg) {
|
||||
graph = new MutableDirectedGraph(cfg);
|
||||
for (int i = 0; i < cfg.size(); ++i) {
|
||||
nodeClasses.create();
|
||||
classContents.add(IntegerArray.of(i));
|
||||
}
|
||||
}
|
||||
|
||||
private IntSet allNodesOf(Graph cfg) {
|
||||
int[] allNodes = new int[cfg.size()];
|
||||
for (int i = 0; i < cfg.size(); ++i) {
|
||||
allNodes[i] = i;
|
||||
}
|
||||
return IntOpenHashSet.from(allNodes);
|
||||
}
|
||||
|
||||
private void rebuildDJGraph() {
|
||||
djGraph = new DJGraph(graph);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user