/* * Copyright 2000-2014 JetBrains s.r.o. * * 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 com.intellij.codeInspection.bytecodeAnalysis.asm; import com.intellij.codeInspection.bytecodeAnalysis.asm.ControlFlowGraph.Edge; import gnu.trove.TIntArrayList; import gnu.trove.TIntHashSet; import gnu.trove.TIntIterator; /** * @author lambdamix */ public final class RichControlFlow { public final ControlFlowGraph controlFlow; public final DFSTree dfsTree; public RichControlFlow(ControlFlowGraph controlFlow, DFSTree dfsTree) { this.controlFlow = controlFlow; this.dfsTree = dfsTree; } // Tarjan. Testing flow graph reducibility. // Journal of Computer and System Sciences 9.3 (1974): 355-365. public boolean reducible() { if (dfsTree.back.isEmpty()) { return true; } int size = controlFlow.transitions.length; boolean[] loopEnters = dfsTree.loopEnters; TIntHashSet[] cycleIncomings = new TIntHashSet[size]; // really this may be array, since dfs already ensures no duplicates TIntArrayList[] nonCycleIncomings = new TIntArrayList[size]; int[] collapsedTo = new int[size]; int[] queue = new int[size]; int top; for (int i = 0; i < size; i++) { if (loopEnters[i]) { cycleIncomings[i] = new TIntHashSet(); } nonCycleIncomings[i] = new TIntArrayList(); collapsedTo[i] = i; } // from whom back connections for (Edge edge : dfsTree.back) { cycleIncomings[edge.to].add(edge.from); } // from whom ordinary connections for (Edge edge : dfsTree.nonBack) { nonCycleIncomings[edge.to].add(edge.from); } for (int w = size - 1; w >= 0 ; w--) { top = 0; // NB - it is modified later! TIntHashSet p = cycleIncomings[w]; if (p == null) { continue; } TIntIterator iter = p.iterator(); while (iter.hasNext()) { queue[top++] = iter.next(); } while (top > 0) { int x = queue[--top]; TIntArrayList incoming = nonCycleIncomings[x]; for (int i = 0; i < incoming.size(); i++) { int y1 = collapsedTo[incoming.getQuick(i)]; if (!dfsTree.isDescendant(y1, w)) { return false; } if (y1 != w && p.add(y1)) { queue[top++] = y1; } } } iter = p.iterator(); while (iter.hasNext()) { collapsedTo[iter.next()] = w; } } return true; } }