From 7a57b6b5d0a31bf1d81f2c716dd5fab2a9256130 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 9 Jun 2017 12:01:53 +0700 Subject: [PATCH] BytecodeAnalysis: ControlFlowBuilder deduplication LiteControlFlowBuilder and ControlFlowBuilder are merged into single class (their body was actually identical); dependency from FramelessAnalyzer changed from inheritance to composition --- .../asm/ControlFlowGraph.java | 68 +++---------------- .../asm/FramelessAnalyzer.java | 35 +++++----- .../asm/LiteFramelessAnalyzer.java | 2 + 3 files changed, 32 insertions(+), 73 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java index 86b32d53789c..9fb419b63266 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java @@ -23,6 +23,9 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException; import java.util.HashSet; import java.util.Set; +import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_ABSTRACT; +import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_NATIVE; + /** * @author lambdamix */ @@ -68,19 +71,21 @@ public final class ControlFlowGraph { } public static ControlFlowGraph build(String className, MethodNode methodNode, boolean jsr) throws AnalyzerException { - return jsr ? new ControlFlowBuilder(className, methodNode).buildCFG() : new LiteControlFlowBuilder(className, methodNode).buildCFG(); + return new ControlFlowBuilder(className, methodNode, jsr).buildCFG(); } } -final class ControlFlowBuilder extends FramelessAnalyzer { +final class ControlFlowBuilder implements FramelessAnalyzer.EdgeCreator { final String className; final MethodNode methodNode; final TIntArrayList[] transitions; final Set errorTransitions; + final FramelessAnalyzer myAnalyzer; private final boolean[] errors; private int edgeCount; - ControlFlowBuilder(String className, MethodNode methodNode) { + ControlFlowBuilder(String className, MethodNode methodNode, boolean jsr) { + myAnalyzer = jsr ? new FramelessAnalyzer(this) : new LiteFramelessAnalyzer(this); this.className = className; this.methodNode = methodNode; transitions = new TIntArrayList[methodNode.instructions.size()]; @@ -93,7 +98,7 @@ final class ControlFlowBuilder extends FramelessAnalyzer { final ControlFlowGraph buildCFG() throws AnalyzerException { if ((methodNode.access & (ACC_ABSTRACT | ACC_NATIVE)) == 0) { - analyze(methodNode); + myAnalyzer.analyze(methodNode); } int[][] resultTransitions = new int[transitions.length][]; for (int i = 0; i < resultTransitions.length; i++) { @@ -103,7 +108,7 @@ final class ControlFlowBuilder extends FramelessAnalyzer { } @Override - protected final void newControlFlowEdge(int insn, int successor) { + public final void newControlFlowEdge(int insn, int successor) { if (!transitions[insn].contains(successor)) { transitions[insn].add(successor); edgeCount++; @@ -111,7 +116,7 @@ final class ControlFlowBuilder extends FramelessAnalyzer { } @Override - protected final boolean newControlFlowExceptionEdge(int insn, int successor) { + public final boolean newControlFlowExceptionEdge(int insn, int successor) { if (!transitions[insn].contains(successor)) { transitions[insn].add(successor); edgeCount++; @@ -121,54 +126,3 @@ final class ControlFlowBuilder extends FramelessAnalyzer { return true; } } - -final class LiteControlFlowBuilder extends LiteFramelessAnalyzer { - final String className; - final MethodNode methodNode; - final TIntArrayList[] transitions; - final Set errorTransitions; - private final boolean[] errors; - private int edgeCount; - - LiteControlFlowBuilder(String className, MethodNode methodNode) { - this.className = className; - this.methodNode = methodNode; - transitions = new TIntArrayList[methodNode.instructions.size()]; - errors = new boolean[methodNode.instructions.size()]; - for (int i = 0; i < transitions.length; i++) { - transitions[i] = new TIntArrayList(); - } - errorTransitions = new HashSet<>(); - } - - final ControlFlowGraph buildCFG() throws AnalyzerException { - if ((methodNode.access & (ACC_ABSTRACT | ACC_NATIVE)) == 0) { - analyze(methodNode); - } - int[][] resultTransitions = new int[transitions.length][]; - for (int i = 0; i < resultTransitions.length; i++) { - resultTransitions[i] = transitions[i].toNativeArray(); - } - return new ControlFlowGraph(className, methodNode, resultTransitions, edgeCount, errors, errorTransitions); - } - - @Override - protected final void newControlFlowEdge(int insn, int successor) { - if (!transitions[insn].contains(successor)) { - transitions[insn].add(successor); - edgeCount++; - } - } - - @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; - } -} - diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java index 18039b1a1894..3f9f821a5d72 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java @@ -34,6 +34,9 @@ public class FramelessAnalyzer extends SubroutineFinder { protected boolean[] queued; protected int[] queue; protected int top; + protected final EdgeCreator myEdgeCreator; + + public FramelessAnalyzer(EdgeCreator creator) {myEdgeCreator = creator;} public void analyze(final MethodNode m) throws AnalyzerException { n = m.instructions.size(); @@ -101,7 +104,7 @@ public class FramelessAnalyzer extends SubroutineFinder { if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) { merge(insn + 1, subroutine); - newControlFlowEdge(insn, insn + 1); + myEdgeCreator.newControlFlowEdge(insn, insn + 1); } else { subroutine = subroutine == null ? null : subroutine.copy(); @@ -109,7 +112,7 @@ public class FramelessAnalyzer extends SubroutineFinder { JumpInsnNode j = (JumpInsnNode) insnNode; if (insnOpcode != GOTO && insnOpcode != JSR) { merge(insn + 1, subroutine); - newControlFlowEdge(insn, insn + 1); + myEdgeCreator.newControlFlowEdge(insn, insn + 1); } int jump = insns.indexOf(j.label); if (insnOpcode == JSR) { @@ -117,28 +120,28 @@ public class FramelessAnalyzer extends SubroutineFinder { } else { merge(jump, subroutine); } - newControlFlowEdge(insn, jump); + myEdgeCreator.newControlFlowEdge(insn, jump); } else if (insnNode instanceof LookupSwitchInsnNode) { LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode; int jump = insns.indexOf(lsi.dflt); merge(jump, subroutine); - newControlFlowEdge(insn, jump); + myEdgeCreator.newControlFlowEdge(insn, jump); for (int j = 0; j < lsi.labels.size(); ++j) { LabelNode label = lsi.labels.get(j); jump = insns.indexOf(label); merge(jump, subroutine); - newControlFlowEdge(insn, jump); + myEdgeCreator.newControlFlowEdge(insn, jump); } } else if (insnNode instanceof TableSwitchInsnNode) { TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode; int jump = insns.indexOf(tsi.dflt); merge(jump, subroutine); - newControlFlowEdge(insn, jump); + myEdgeCreator.newControlFlowEdge(insn, jump); for (int j = 0; j < tsi.labels.size(); ++j) { LabelNode label = tsi.labels.get(j); jump = insns.indexOf(label); merge(jump, subroutine); - newControlFlowEdge(insn, jump); + myEdgeCreator.newControlFlowEdge(insn, jump); } } else if (insnOpcode == RET) { if (subroutine == null) { @@ -149,7 +152,7 @@ public class FramelessAnalyzer extends SubroutineFinder { int call = insns.indexOf(caller); if (wasQueued[call]) { merge(call + 1, subroutines[call], subroutine.access); - newControlFlowEdge(insn, call + 1); + myEdgeCreator.newControlFlowEdge(insn, call + 1); } } } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) { @@ -168,7 +171,7 @@ public class FramelessAnalyzer extends SubroutineFinder { } } merge(insn + 1, subroutine); - newControlFlowEdge(insn, insn + 1); + myEdgeCreator.newControlFlowEdge(insn, insn + 1); } } @@ -189,14 +192,8 @@ public class FramelessAnalyzer extends SubroutineFinder { } } - protected void newControlFlowEdge(final int insn, final int successor) {} - - protected boolean newControlFlowExceptionEdge(final int insn, final int successor) { - return true; - } - protected boolean newControlFlowExceptionEdge(final int insn, final TryCatchBlockNode tcb) { - return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler)); + return myEdgeCreator.newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler)); } // ------------------------------------------------------------------------- @@ -243,4 +240,10 @@ public class FramelessAnalyzer extends SubroutineFinder { queue[top++] = insn; } } + + interface EdgeCreator { + void newControlFlowEdge(final int insn, final int successor); + + boolean newControlFlowExceptionEdge(final int insn, final int successor); + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java index 3cfb1ae51feb..e704a10ee29f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java @@ -28,6 +28,8 @@ import java.util.List; */ public class LiteFramelessAnalyzer extends FramelessAnalyzer { + public LiteFramelessAnalyzer(EdgeCreator creator) {super(creator);} + @Override protected void findSubroutine(int insn, Subroutine sub, List calls) throws AnalyzerException { }