diff options
author | Evgeny Mandrikov <Godin@users.noreply.github.com> | 2017-09-25 13:27:06 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-25 13:27:06 +0200 |
commit | 4109d66fd71e022b2bb7920dc45c98b00a2c2ba2 (patch) | |
tree | cf159fda788bab1e60f4df37cdc90971163e2779 /org.jacoco.core/src/org | |
parent | 04f923c151b11c9b7f3a28f604ba65ec44dfa2ec (diff) | |
download | jacoco-4109d66fd71e022b2bb7920dc45c98b00a2c2ba2.tar.gz |
Yak shaving: determine covered branches for each instruction (#598)
This is required for merge of coverage information from several
instructions that cover different branches, which in his turn is
required for implementation of filter of duplicate blocks that
compilers generate for `finally`.
Diffstat (limited to 'org.jacoco.core/src/org')
-rw-r--r-- | org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java | 55 | ||||
-rw-r--r-- | org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java | 41 |
2 files changed, 69 insertions, 27 deletions
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java index 328d079a..e216bb77 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java @@ -74,7 +74,7 @@ public class MethodAnalyzer extends MethodProbesVisitor private final List<Instruction> instructions = new ArrayList<Instruction>(); /** List of all predecessors of covered probes */ - private final List<Instruction> coveredProbes = new ArrayList<Instruction>(); + private final List<CoveredProbe> coveredProbes = new ArrayList<CoveredProbe>(); /** List of all jumps encountered */ private final List<Jump> jumps = new ArrayList<Jump>(); @@ -177,7 +177,7 @@ public class MethodAnalyzer extends MethodProbesVisitor final Instruction insn = new Instruction(currentNode, currentLine); instructions.add(insn); if (lastInsn != null) { - insn.setPredecessor(lastInsn); + insn.setPredecessor(lastInsn, 0); } final int labelCount = currentLabel.size(); if (labelCount > 0) { @@ -230,7 +230,7 @@ public class MethodAnalyzer extends MethodProbesVisitor @Override public void visitJumpInsn(final int opcode, final Label label) { visitInsn(); - jumps.add(new Jump(lastInsn, label)); + jumps.add(new Jump(lastInsn, label, 1)); } @Override @@ -258,11 +258,13 @@ public class MethodAnalyzer extends MethodProbesVisitor private void visitSwitchInsn(final Label dflt, final Label[] labels) { visitInsn(); LabelInfo.resetDone(labels); - jumps.add(new Jump(lastInsn, dflt)); + int branch = 0; + jumps.add(new Jump(lastInsn, dflt, branch)); LabelInfo.setDone(dflt); for (final Label l : labels) { if (!LabelInfo.isDone(l)) { - jumps.add(new Jump(lastInsn, l)); + branch++; + jumps.add(new Jump(lastInsn, l, branch)); LabelInfo.setDone(l); } } @@ -275,7 +277,7 @@ public class MethodAnalyzer extends MethodProbesVisitor @Override public void visitProbe(final int probeId) { - addProbe(probeId); + addProbe(probeId, 0); lastInsn = null; } @@ -283,13 +285,13 @@ public class MethodAnalyzer extends MethodProbesVisitor public void visitJumpInsnWithProbe(final int opcode, final Label label, final int probeId, final IFrame frame) { visitInsn(); - addProbe(probeId); + addProbe(probeId, 1); } @Override public void visitInsnWithProbe(final int opcode, final int probeId) { visitInsn(); - addProbe(probeId); + addProbe(probeId, 0); } @Override @@ -309,19 +311,21 @@ public class MethodAnalyzer extends MethodProbesVisitor visitInsn(); LabelInfo.resetDone(dflt); LabelInfo.resetDone(labels); - visitSwitchTarget(dflt); + int branch = 0; + visitSwitchTarget(dflt, branch); for (final Label l : labels) { - visitSwitchTarget(l); + branch++; + visitSwitchTarget(l, branch); } } - private void visitSwitchTarget(final Label label) { + private void visitSwitchTarget(final Label label, final int branch) { final int id = LabelInfo.getProbeId(label); if (!LabelInfo.isDone(label)) { if (id == LabelInfo.NO_PROBE) { - jumps.add(new Jump(lastInsn, label)); + jumps.add(new Jump(lastInsn, label, branch)); } else { - addProbe(id); + addProbe(id, branch); } LabelInfo.setDone(label); } @@ -331,11 +335,12 @@ public class MethodAnalyzer extends MethodProbesVisitor public void visitEnd() { // Wire jumps: for (final Jump j : jumps) { - LabelInfo.getInstruction(j.target).setPredecessor(j.source); + LabelInfo.getInstruction(j.target).setPredecessor(j.source, + j.branch); } // Propagate probe values: - for (final Instruction p : coveredProbes) { - p.setCovered(); + for (final CoveredProbe p : coveredProbes) { + p.instruction.setCovered(p.branch); } // Report result: coverage.ensureCapacity(firstLine, lastLine); @@ -356,10 +361,20 @@ public class MethodAnalyzer extends MethodProbesVisitor coverage.incrementMethodCounter(); } - private void addProbe(final int probeId) { + private void addProbe(final int probeId, final int branch) { lastInsn.addBranch(); if (probes != null && probes[probeId]) { - coveredProbes.add(lastInsn); + coveredProbes.add(new CoveredProbe(lastInsn, branch)); + } + } + + private static class CoveredProbe { + final Instruction instruction; + final int branch; + + private CoveredProbe(Instruction instruction, int branch) { + this.instruction = instruction; + this.branch = branch; } } @@ -367,10 +382,12 @@ public class MethodAnalyzer extends MethodProbesVisitor final Instruction source; final Label target; + final int branch; - Jump(final Instruction source, final Label target) { + Jump(final Instruction source, final Label target, final int branch) { this.source = source; this.target = target; + this.branch = branch; } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java index e41ca468..4f550407 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java @@ -13,6 +13,8 @@ package org.jacoco.core.internal.flow; import org.objectweb.asm.tree.AbstractInsnNode; +import java.util.BitSet; + /** * Representation of a byte code instruction for analysis. Internally used for * analysis. @@ -25,10 +27,12 @@ public class Instruction { private int branches; - private int coveredBranches; + private final BitSet coveredBranches; private Instruction predecessor; + private int predecessorBranch; + /** * New instruction at the given line. * @@ -41,7 +45,7 @@ public class Instruction { this.node = node; this.line = line; this.branches = 0; - this.coveredBranches = 0; + this.coveredBranches = new BitSet(); } /** @@ -59,26 +63,42 @@ public class Instruction { } /** - * Sets the given instruction as a predecessor of this instruction. This - * will add an branch to the predecessor. + * Sets the given instruction as a predecessor of this instruction and adds + * branch to the predecessor. Probes are inserted in a way that every + * instruction has at most one direct predecessor. * * @see #addBranch() * @param predecessor * predecessor instruction + * @param branch + * branch number in predecessor that should be marked as covered + * when this instruction marked as covered */ - public void setPredecessor(final Instruction predecessor) { + public void setPredecessor(final Instruction predecessor, + final int branch) { this.predecessor = predecessor; predecessor.addBranch(); + this.predecessorBranch = branch; } /** * Marks one branch of this instruction as covered. Also recursively marks * all predecessor instructions as covered if this is the first covered * branch. + * + * @param branch + * branch number to mark as covered */ - public void setCovered() { + public void setCovered(final int branch) { Instruction i = this; - while (i != null && i.coveredBranches++ == 0) { + int b = branch; + while (i != null) { + if (!i.coveredBranches.isEmpty()) { + i.coveredBranches.set(b); + break; + } + i.coveredBranches.set(b); + b = i.predecessorBranch; i = i.predecessor; } } @@ -107,7 +127,12 @@ public class Instruction { * @return number of covered branches */ public int getCoveredBranches() { - return coveredBranches; + return coveredBranches.cardinality(); + } + + @Override + public String toString() { + return coveredBranches.toString(); } } |