BytecodeAnalysis: ControlFlowBuilder deduplication

LiteControlFlowBuilder and ControlFlowBuilder are merged into single class (their body was actually identical); dependency from FramelessAnalyzer changed from inheritance to composition
This commit is contained in:
Tagir Valeev
2017-06-14 09:43:38 +07:00
parent fcf2373ae2
commit 7a57b6b5d0
3 changed files with 32 additions and 73 deletions
@@ -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<ControlFlowGraph.Edge> 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<ControlFlowGraph.Edge> 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;
}
}
@@ -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);
}
}
@@ -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<AbstractInsnNode> calls) throws AnalyzerException {
}