use of com.intellij.codeInspection.bytecodeAnalysis.asm.ControlFlowGraph.Edge in project intellij-community by JetBrains.
the class RichControlFlow method reducible.
// 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;
}
use of com.intellij.codeInspection.bytecodeAnalysis.asm.ControlFlowGraph.Edge in project intellij-community by JetBrains.
the class InOutInterpreter method processState.
void processState(State state) throws AnalyzerException {
Conf preConf = state.conf;
int insnIndex = preConf.insnIndex;
boolean loopEnter = dfsTree.loopEnters[insnIndex];
Conf conf = loopEnter ? generalize(preConf) : preConf;
List<Conf> history = state.history;
boolean taken = state.taken;
Frame<BasicValue> frame = conf.frame;
AbstractInsnNode insnNode = methodNode.instructions.get(insnIndex);
List<Conf> nextHistory = loopEnter ? append(history, conf) : history;
Frame<BasicValue> nextFrame = execute(frame, insnNode);
addComputed(insnIndex, state);
if (interpreter.deReferenced) {
return;
}
int opcode = insnNode.getOpcode();
switch(opcode) {
case ARETURN:
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case RETURN:
BasicValue stackTop = popValue(frame);
Result subResult;
if (FalseValue == stackTop) {
subResult = new Final(Value.False);
} else if (TrueValue == stackTop) {
subResult = new Final(Value.True);
} else if (NullValue == stackTop) {
subResult = new Final(Value.Null);
} else if (stackTop instanceof NotNullValue) {
subResult = new Final(Value.NotNull);
} else if (stackTop instanceof ParamValue) {
subResult = new Final(inValue);
} else if (stackTop instanceof CallResultValue) {
Set<Key> keys = ((CallResultValue) stackTop).inters;
subResult = new Pending(Collections.singleton(new Product(Value.Top, keys)));
} else {
earlyResult = new Final(Value.Top);
return;
}
internalResult = resultUtil.join(internalResult, subResult);
if (internalResult instanceof Final && ((Final) internalResult).value == Value.Top) {
earlyResult = internalResult;
}
return;
case ATHROW:
return;
default:
}
if (opcode == IFNONNULL && popValue(frame) instanceof ParamValue) {
int nextInsnIndex = inValue == Value.Null ? insnIndex + 1 : methodNode.instructions.indexOf(((JumpInsnNode) insnNode).label);
State nextState = new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false);
pendingPush(nextState);
return;
}
if (opcode == IFNULL && popValue(frame) instanceof ParamValue) {
int nextInsnIndex = inValue == Value.NotNull ? insnIndex + 1 : methodNode.instructions.indexOf(((JumpInsnNode) insnNode).label);
State nextState = new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false);
pendingPush(nextState);
return;
}
if (opcode == IFEQ && popValue(frame) == InstanceOfCheckValue && inValue == Value.Null) {
int nextInsnIndex = methodNode.instructions.indexOf(((JumpInsnNode) insnNode).label);
State nextState = new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false);
pendingPush(nextState);
return;
}
if (opcode == IFNE && popValue(frame) == InstanceOfCheckValue && inValue == Value.Null) {
int nextInsnIndex = insnIndex + 1;
State nextState = new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false);
pendingPush(nextState);
return;
}
// general case
for (int nextInsnIndex : controlFlow.transitions[insnIndex]) {
Frame<BasicValue> nextFrame1 = nextFrame;
if (controlFlow.errors[nextInsnIndex] && controlFlow.errorTransitions.contains(new Edge(insnIndex, nextInsnIndex))) {
nextFrame1 = new Frame<>(frame);
nextFrame1.clearStack();
nextFrame1.push(ASMUtils.THROWABLE_VALUE);
}
pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame1), nextHistory, taken, false));
}
}
use of com.intellij.codeInspection.bytecodeAnalysis.asm.ControlFlowGraph.Edge in project intellij-community by JetBrains.
the class NullableInterpreter method processState.
private void processState(State state) throws AnalyzerException {
Conf conf = state.conf;
int insnIndex = conf.insnIndex;
List<Conf> history = state.history;
boolean taken = state.taken;
Frame<BasicValue> frame = conf.frame;
AbstractInsnNode insnNode = methodNode.instructions.get(insnIndex);
List<Conf> nextHistory = dfsTree.loopEnters[insnIndex] ? append(history, conf) : history;
addComputed(insnIndex, state);
execute(frame, insnNode, taken);
if (subResult == NPE || top) {
earlyResult = NPE;
return;
}
if (subResult instanceof ConditionalNPE) {
myResult = combineNullable(myResult, subResult);
}
int opcode = insnNode.getOpcode();
switch(opcode) {
case ARETURN:
if (popValue(frame) instanceof ParamValue) {
earlyResult = NPE;
}
return;
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case RETURN:
return;
default:
}
if (opcode == ATHROW) {
if (taken) {
earlyResult = NPE;
}
return;
}
if (opcode == IFNONNULL && popValue(frame) instanceof ParamValue) {
int nextInsnIndex = insnIndex + 1;
pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false));
return;
}
if (opcode == IFNULL && popValue(frame) instanceof ParamValue) {
int nextInsnIndex = methodNode.instructions.indexOf(((JumpInsnNode) insnNode).label);
pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false));
return;
}
if (opcode == IFEQ && popValue(frame) == InstanceOfCheckValue) {
int nextInsnIndex = methodNode.instructions.indexOf(((JumpInsnNode) insnNode).label);
pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false));
return;
}
if (opcode == IFNE && popValue(frame) == InstanceOfCheckValue) {
int nextInsnIndex = insnIndex + 1;
pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false));
return;
}
// general case
for (int nextInsnIndex : controlFlow.transitions[insnIndex]) {
Frame<BasicValue> nextFrame1 = nextFrame;
if (controlFlow.errors[nextInsnIndex] && controlFlow.errorTransitions.contains(new Edge(insnIndex, nextInsnIndex))) {
nextFrame1 = new Frame<>(frame);
nextFrame1.clearStack();
nextFrame1.push(ASMUtils.THROWABLE_VALUE);
}
pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame1), nextHistory, taken, false));
}
}
use of com.intellij.codeInspection.bytecodeAnalysis.asm.ControlFlowGraph.Edge in project intellij-community by JetBrains.
the class LiteControlFlowBuilder method newControlFlowExceptionEdge.
@Override
protected final boolean newControlFlowExceptionEdge(int insn, int successor) {
if (!transitions[insn].contains(successor)) {
transitions[insn].add(successor);
edgeCount++;
errorTransitions.add(new Edge(insn, successor));
errors[successor] = true;
}
return true;
}
use of com.intellij.codeInspection.bytecodeAnalysis.asm.ControlFlowGraph.Edge in project intellij-community by JetBrains.
the class DFSTree method build.
// Graphs: Theory and Algorithms. by K. Thulasiraman , M. N. S. Swamy (1992)
// 11.7.2 DFS of a directed graph
public static DFSTree build(int[][] transitions, int edgeCount) {
HashSet<Edge> nonBack = new HashSet<>();
HashSet<Edge> back = new HashSet<>();
boolean[] marked = new boolean[transitions.length];
boolean[] scanned = new boolean[transitions.length];
int[] preOrder = new int[transitions.length];
int[] postOrder = new int[transitions.length];
int entered = 0;
int completed = 0;
boolean[] loopEnters = new boolean[transitions.length];
// enter 0
entered++;
preOrder[0] = entered;
marked[0] = true;
boolean[] stackFlag = new boolean[edgeCount * 2 + 1];
int[] stackFrom = new int[edgeCount * 2 + 1];
int[] stackTo = new int[edgeCount * 2 + 1];
int top = 0;
// stack.push(new MarkScanned(0));
stackFlag[top] = true;
stackTo[top] = 0;
top++;
for (int to : transitions[0]) {
//stack.push(new ExamineEdge(0, to));
stackFlag[top] = false;
stackFrom[top] = 0;
stackTo[top] = to;
top++;
}
while (top > 0) {
top--;
// markScanned
if (stackFlag[top]) {
completed++;
postOrder[stackTo[top]] = completed;
scanned[stackTo[top]] = true;
} else {
//ExamineEdge examineEdgeAction = (ExamineEdge) action;
int from = stackFrom[top];
int to = stackTo[top];
if (!marked[to]) {
nonBack.add(new Edge(from, to));
// enter to
entered++;
preOrder[to] = entered;
marked[to] = true;
//stack.push(new MarkScanned(to));
stackFlag[top] = true;
stackTo[top] = to;
top++;
for (int to1 : transitions[to]) {
//stack.push(new ExamineEdge(to, to1));
stackFlag[top] = false;
stackFrom[top] = to;
stackTo[top] = to1;
top++;
}
} else if (preOrder[to] > preOrder[from]) {
nonBack.add(new Edge(from, to));
} else if (preOrder[to] < preOrder[from] && !scanned[to]) {
back.add(new Edge(from, to));
loopEnters[to] = true;
} else {
nonBack.add(new Edge(from, to));
}
}
}
return new DFSTree(preOrder, postOrder, nonBack, back, loopEnters);
}
Aggregations