aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/instr/MethodInstrumenterTest.java56
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java10
-rw-r--r--org.jacoco.core/src/org/jacoco/core/instr/MethodInstrumenter.java66
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java29
4 files changed, 157 insertions, 4 deletions
diff --git a/org.jacoco.core.test/src/org/jacoco/core/instr/MethodInstrumenterTest.java b/org.jacoco.core.test/src/org/jacoco/core/instr/MethodInstrumenterTest.java
index 2e2dd7a9..5f036652 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/instr/MethodInstrumenterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/instr/MethodInstrumenterTest.java
@@ -13,6 +13,7 @@ package org.jacoco.core.instr;
import static org.junit.Assert.assertEquals;
+import org.jacoco.core.internal.flow.LabelInfo;
import org.junit.Before;
import org.junit.Test;
import org.objectweb.asm.ClassVisitor;
@@ -213,4 +214,59 @@ public class MethodInstrumenterTest {
assertEquals(expected, actual);
}
+ @Test
+ public void testVisitTableSwitchInsnWithProbes() {
+ final Label L0 = new Label();
+ final Label L1 = new Label();
+ final Label L2 = new Label();
+ LabelInfo.setProbeId(L0, 0);
+ LabelInfo.setProbeId(L1, 1);
+ instrumenter.visitTableSwitchInsnWithProbes(3, 5, L0, new Label[] { L1,
+ L1, L2 });
+
+ expected.visitTableSwitchInsn(3, 4, L0, new Label[] { L1, L1, L2 });
+ expected.visitLabel(L0);
+ expected.visitVarInsn(Opcodes.ALOAD, 1);
+ expected.visitInsn(Opcodes.ICONST_0);
+ expected.visitInsn(Opcodes.ICONST_1);
+ expected.visitInsn(Opcodes.BASTORE);
+ expected.visitJumpInsn(Opcodes.GOTO, new Label());
+ expected.visitLabel(L1);
+ expected.visitVarInsn(Opcodes.ALOAD, 1);
+ expected.visitInsn(Opcodes.ICONST_1);
+ expected.visitInsn(Opcodes.ICONST_1);
+ expected.visitInsn(Opcodes.BASTORE);
+ expected.visitJumpInsn(Opcodes.GOTO, new Label());
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testVisitLookupSwitchInsnWithProbes() {
+ final Label L0 = new Label();
+ final Label L1 = new Label();
+ final Label L2 = new Label();
+ LabelInfo.setProbeId(L0, 0);
+ LabelInfo.setProbeId(L1, 1);
+ instrumenter.visitLookupSwitchInsnWithProbes(L0,
+ new int[] { 10, 20, 30 }, new Label[] { L1, L1, L2 });
+
+ expected.visitLookupSwitchInsn(L0, new int[] { 10, 20, 30 },
+ new Label[] { L1, L1, L2 });
+ expected.visitLabel(L0);
+ expected.visitVarInsn(Opcodes.ALOAD, 1);
+ expected.visitInsn(Opcodes.ICONST_0);
+ expected.visitInsn(Opcodes.ICONST_1);
+ expected.visitInsn(Opcodes.BASTORE);
+ expected.visitJumpInsn(Opcodes.GOTO, new Label());
+ expected.visitLabel(L1);
+ expected.visitVarInsn(Opcodes.ALOAD, 1);
+ expected.visitInsn(Opcodes.ICONST_1);
+ expected.visitInsn(Opcodes.ICONST_1);
+ expected.visitInsn(Opcodes.BASTORE);
+ expected.visitJumpInsn(Opcodes.GOTO, new Label());
+
+ assertEquals(expected, actual);
+ }
+
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java
index 6cbeb815..20bc1dab 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java
@@ -13,6 +13,8 @@ package org.jacoco.core.internal.flow;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
@@ -40,6 +42,7 @@ public class LabelInfoTest {
assertFalse(LabelInfo.isSuccessor(label));
assertFalse(LabelInfo.isDone(label));
assertEquals(LabelInfo.NO_PROBE, LabelInfo.getProbeId(label));
+ assertNull(LabelInfo.getIntermediateLabel(label));
}
@Test
@@ -103,4 +106,11 @@ public class LabelInfoTest {
assertEquals(123, LabelInfo.getProbeId(label));
}
+ @Test
+ public void testIntermediateLabel() {
+ final Label i = new Label();
+ LabelInfo.setIntermediateLabel(label, i);
+ assertSame(i, LabelInfo.getIntermediateLabel(label));
+ }
+
}
diff --git a/org.jacoco.core/src/org/jacoco/core/instr/MethodInstrumenter.java b/org.jacoco.core/src/org/jacoco/core/instr/MethodInstrumenter.java
index 6e772bff..b52d5a69 100644
--- a/org.jacoco.core/src/org/jacoco/core/instr/MethodInstrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/instr/MethodInstrumenter.java
@@ -12,6 +12,7 @@
package org.jacoco.core.instr;
import org.jacoco.core.internal.flow.IMethodProbesVisitor;
+import org.jacoco.core.internal.flow.LabelInfo;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -157,14 +158,71 @@ class MethodInstrumenter extends ProbeVariableInserter implements
public void visitTableSwitchInsnWithProbes(final int min, final int max,
final Label dflt, final Label[] labels) {
- // TODO Auto-generated method stub
- mv.visitTableSwitchInsn(min, max, dflt, labels);
+ // 1. Calculate intermediate labels:
+ LabelInfo.resetDone(dflt);
+ LabelInfo.resetDone(labels);
+ final Label newDflt = createIntermediate(dflt);
+ final Label[] newLabels = createIntermediates(labels);
+ mv.visitTableSwitchInsn(min, max, newDflt, newLabels);
+
+ // 2. Insert probes:
+ insertIntermediateProbes(dflt, labels);
}
public void visitLookupSwitchInsnWithProbes(final Label dflt,
final int[] keys, final Label[] labels) {
- // TODO Auto-generated method stub
- mv.visitLookupSwitchInsn(dflt, keys, labels);
+ // 1. Calculate intermediate labels:
+ LabelInfo.resetDone(dflt);
+ LabelInfo.resetDone(labels);
+ final Label newDflt = createIntermediate(dflt);
+ final Label[] newLabels = createIntermediates(labels);
+ mv.visitLookupSwitchInsn(newDflt, keys, newLabels);
+
+ // 2. Insert probes:
+ insertIntermediateProbes(dflt, labels);
+ }
+
+ private Label createIntermediate(final Label label) {
+ final Label intermediate;
+ if (LabelInfo.getProbeId(label) == LabelInfo.NO_PROBE) {
+ intermediate = label;
+ } else {
+ if (LabelInfo.isDone(label)) {
+ intermediate = LabelInfo.getIntermediateLabel(label);
+ } else {
+ intermediate = new Label();
+ LabelInfo.setIntermediateLabel(label, intermediate);
+ LabelInfo.setDone(label);
+ }
+ }
+ return intermediate;
+ }
+
+ private Label[] createIntermediates(final Label[] labels) {
+ final Label[] intermediates = new Label[labels.length];
+ for (int i = 0; i < labels.length; i++) {
+ intermediates[i] = createIntermediate(labels[i]);
+ }
+ return intermediates;
+ }
+
+ private void insertIntermediateProbe(final Label label) {
+ final int probeId = LabelInfo.getProbeId(label);
+ if (probeId != LabelInfo.NO_PROBE && !LabelInfo.isDone(label)) {
+ mv.visitLabel(LabelInfo.getIntermediateLabel(label));
+ insertProbe(probeId);
+ mv.visitJumpInsn(Opcodes.GOTO, label);
+ LabelInfo.setDone(label);
+ }
+ }
+
+ private void insertIntermediateProbes(final Label dflt, final Label[] labels) {
+ LabelInfo.resetDone(dflt);
+ LabelInfo.resetDone(labels);
+ insertIntermediateProbe(dflt);
+ for (final Label l : labels) {
+ insertIntermediateProbe(l);
+ }
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java
index b774c01c..9e54e7fb 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java
@@ -38,6 +38,8 @@ public final class LabelInfo {
private int probeid = NO_PROBE;
+ private Label intermediate = null;
+
// instances are only created within this class
private LabelInfo() {
}
@@ -175,6 +177,33 @@ public final class LabelInfo {
return info == null ? NO_PROBE : info.probeid;
}
+ /**
+ * Defines an intermediate label for the given label. Such intermediate
+ * labels are required during instrumentation to add probes to jump targets.
+ *
+ * @param label
+ * label to define for
+ * @param intermediate
+ * intermediate label
+ */
+ public static void setIntermediateLabel(final Label label,
+ final Label intermediate) {
+ create(label).intermediate = intermediate;
+ }
+
+ /**
+ * Returns the intermediate label for the given label if one has been
+ * defined.
+ *
+ * @param label
+ * label to look for
+ * @return intermediate label or <code>null</code>
+ */
+ public static Label getIntermediateLabel(final Label label) {
+ final LabelInfo info = get(label);
+ return info == null ? null : info.intermediate;
+ }
+
private static LabelInfo get(final Label label) {
final Object info = label.info;
return info instanceof LabelInfo ? (LabelInfo) info : null;