aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java4
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java202
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/flow/FrameSnapshotTest.java99
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/flow/MethodProbesAdapterTest.java112
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/instr/FrameTrackerTest.java1477
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java32
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java7
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java34
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java83
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java (renamed from org.jacoco.core/src/org/jacoco/core/internal/instr/IFrameInserter.java)25
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java47
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java18
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java11
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/FrameTracker.java737
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java33
17 files changed, 556 insertions, 2369 deletions
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
index 76ad6d03..3cf3b415 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
@@ -556,7 +556,9 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
LabelFlowAnalyzer.markLabels(method);
final MethodAnalyzer analyzer = new MethodAnalyzer("doit", "()V", null,
probes);
- method.accept(new MethodProbesAdapter(analyzer, this));
+ final MethodProbesAdapter probesAdapter = new MethodProbesAdapter(
+ analyzer, this);
+ method.accept(probesAdapter);
result = analyzer.getCoverage();
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java
index 2d5bad55..fde6ecb9 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java
@@ -12,6 +12,8 @@
package org.jacoco.core.internal.flow;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.objectweb.asm.ClassVisitor;
@@ -24,7 +26,44 @@ import org.objectweb.asm.Opcodes;
*/
public class ClassProbesAdapterTest {
- private static class MockVisitor extends ClassProbesVisitor {
+ private static class MockMethodVisitor extends MethodProbesVisitor {
+
+ boolean frame = false;
+
+ @Override
+ public void visitProbe(int probeId) {
+ }
+
+ @Override
+ public void visitJumpInsnWithProbe(int opcode, Label label,
+ int probeId, IFrame frame) {
+ frame.accept(this);
+ }
+
+ @Override
+ public void visitInsnWithProbe(int opcode, int probeId) {
+ }
+
+ @Override
+ public void visitTableSwitchInsnWithProbes(int min, int max,
+ Label dflt, Label[] labels, IFrame frame) {
+ frame.accept(this);
+ }
+
+ @Override
+ public void visitLookupSwitchInsnWithProbes(Label dflt, int[] keys,
+ Label[] labels, IFrame frame) {
+ frame.accept(this);
+ }
+
+ @Override
+ public void visitFrame(int type, int nLocal, Object[] local,
+ int nStack, Object[] stack) {
+ frame = true;
+ }
+ }
+
+ private static class MockClassVisitor extends ClassProbesVisitor {
int count;
@@ -42,118 +81,147 @@ public class ClassProbesAdapterTest {
@Test
public void testProbeCounter() {
- final MockVisitor mv = new MockVisitor();
- final ClassProbesAdapter adapter = new ClassProbesAdapter(mv);
+ final MockClassVisitor cv = new MockClassVisitor();
+ final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false);
assertEquals(0, adapter.nextId());
assertEquals(1, adapter.nextId());
assertEquals(2, adapter.nextId());
adapter.visitEnd();
- assertEquals(3, mv.count);
+ assertEquals(3, cv.count);
}
@Test
public void testVisitClassMethods() {
- final MockVisitor mv = new MockVisitor() {
+ final MockClassVisitor cv = new MockClassVisitor() {
@Override
public MethodProbesVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
- class MockMethodVisitor extends MethodProbesVisitor {
- @Override
- public void visitProbe(int probeId) {
- }
-
- @Override
- public void visitJumpInsnWithProbe(int opcode, Label label,
- int probeId) {
- }
-
- @Override
- public void visitInsnWithProbe(int opcode, int probeId) {
- }
-
- @Override
- public void visitTableSwitchInsnWithProbes(int min,
- int max, Label dflt, Label[] labels) {
- }
-
- @Override
- public void visitLookupSwitchInsnWithProbes(Label dflt,
- int[] keys, Label[] labels) {
- }
- }
return new MockMethodVisitor();
}
};
- final ClassProbesAdapter adapter = new ClassProbesAdapter(mv);
+ final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false);
adapter.visit(Opcodes.V1_5, 0, "Foo", null, "java/lang/Object", null);
writeMethod(adapter);
writeMethod(adapter);
writeMethod(adapter);
- assertEquals(0, mv.count);
+ assertEquals(0, cv.count);
adapter.visitEnd();
- assertEquals(3, mv.count);
+ assertEquals(3, cv.count);
}
@Test
public void testVisitInterfaceMethod() {
- final MockVisitor mv = new MockVisitor() {
+ final MockClassVisitor cv = new MockClassVisitor() {
@Override
public MethodProbesVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
- class MockMethodVisitor extends MethodProbesVisitor {
- @Override
- public void visitProbe(int probeId) {
- }
-
- @Override
- public void visitJumpInsnWithProbe(int opcode, Label label,
- int probeId) {
- }
-
- @Override
- public void visitInsnWithProbe(int opcode, int probeId) {
- }
-
- @Override
- public void visitTableSwitchInsnWithProbes(int min,
- int max, Label dflt, Label[] labels) {
- }
-
- @Override
- public void visitLookupSwitchInsnWithProbes(Label dflt,
- int[] keys, Label[] labels) {
- }
- }
return new MockMethodVisitor();
}
};
- final ClassProbesAdapter adapter = new ClassProbesAdapter(mv);
+ final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false);
adapter.visit(Opcodes.V1_5, Opcodes.ACC_INTERFACE, "Foo", null,
"java/lang/Object", null);
writeMethod(adapter);
- assertEquals(1, mv.count);
+ assertEquals(1, cv.count);
adapter.visitEnd();
- assertEquals(1, mv.count);
+ assertEquals(1, cv.count);
}
@Test
public void testVisitMethodNullMethodVisitor() {
- final MockVisitor mv = new MockVisitor();
- final ClassProbesAdapter adapter = new ClassProbesAdapter(mv);
- writeMethod(adapter);
- writeMethod(adapter);
- writeMethod(adapter);
+ final MockClassVisitor cv = new MockClassVisitor();
+ final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false);
+ writeMethod(adapter); // 1 probe
+ writeMethodWithBranch(adapter); // 3 probes
+ writeMethodWithTableSwitch(adapter); // 3 probes
+ writeMethodWithLookupSwitch(adapter); // 3 probes
+ adapter.visitEnd();
+ assertEquals(10, cv.count);
+ }
+
+ @Test
+ public void testVisitWithFrames() {
+ final MockMethodVisitor mv = new MockMethodVisitor();
+ final MockClassVisitor cv = new MockClassVisitor() {
+ @Override
+ public MethodProbesVisitor visitMethod(int access, String name,
+ String desc, String signature, String[] exceptions) {
+ return mv;
+ }
+ };
+ final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, true);
+ writeMethodWithBranch(adapter);
adapter.visitEnd();
- assertEquals(3, mv.count);
+ assertTrue(mv.frame);
+ }
+
+ @Test
+ public void testVisitWithoutFrames() {
+ final MockMethodVisitor mv = new MockMethodVisitor();
+ final MockClassVisitor cv = new MockClassVisitor() {
+ @Override
+ public MethodProbesVisitor visitMethod(int access, String name,
+ String desc, String signature, String[] exceptions) {
+ return mv;
+ }
+ };
+ final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false);
+ writeMethodWithBranch(adapter);
+ adapter.visitEnd();
+ assertFalse(mv.frame);
}
private void writeMethod(final ClassVisitor cv) {
- MethodVisitor mv = cv.visitMethod(0, "foo", "V()", null, null);
+ MethodVisitor mv = cv.visitMethod(0, "foo", "()V", null, null);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 1);
mv.visitEnd();
}
+
+ private void writeMethodWithBranch(final ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(0, "foo", "()V", null, null);
+ mv.visitCode();
+ mv.visitInsn(Opcodes.ICONST_0);
+ Label l = new Label();
+ mv.visitJumpInsn(Opcodes.IFEQ, l);
+ mv.visitInsn(Opcodes.NOP);
+ mv.visitLabel(l);
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+
+ private void writeMethodWithTableSwitch(final ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(0, "foo", "()V", null, null);
+ mv.visitCode();
+ mv.visitInsn(Opcodes.ICONST_0);
+ Label l1 = new Label();
+ Label l2 = new Label();
+ mv.visitTableSwitchInsn(0, 0, l1, new Label[] { l2 });
+ mv.visitLabel(l1);
+ mv.visitInsn(Opcodes.NOP);
+ mv.visitLabel(l2);
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+
+ private void writeMethodWithLookupSwitch(final ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(0, "foo", "()V", null, null);
+ mv.visitCode();
+ mv.visitInsn(Opcodes.ICONST_0);
+ Label l1 = new Label();
+ Label l2 = new Label();
+ mv.visitLookupSwitchInsn(l1, new int[] { 0 }, new Label[] { l2 });
+ mv.visitLabel(l1);
+ mv.visitInsn(Opcodes.NOP);
+ mv.visitLabel(l2);
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/FrameSnapshotTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/FrameSnapshotTest.java
new file mode 100644
index 00000000..210c0d95
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/FrameSnapshotTest.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc R. Hoffmann - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.flow;
+
+import static org.junit.Assert.assertEquals;
+
+import org.jacoco.core.instr.MethodRecorder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.AnalyzerAdapter;
+
+/**
+ * Unit tests for {@link FrameSnapshot}.
+ */
+public class FrameSnapshotTest {
+
+ private AnalyzerAdapter analyzer;
+ private IFrame frame;
+
+ private MethodRecorder expected;
+
+ private MethodVisitor expectedVisitor;
+
+ @Before
+ public void setup() {
+ analyzer = new AnalyzerAdapter("Foo", 0, "doit", "()V", null);
+ expected = new MethodRecorder();
+ expectedVisitor = expected.getVisitor();
+ }
+
+ @After
+ public void teardown() {
+ MethodRecorder actual = new MethodRecorder();
+ frame.accept(actual.getVisitor());
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testNullAnalyzer() {
+ frame = FrameSnapshot.create(null, 0);
+ }
+
+ @Test
+ public void testNoFrame() {
+ analyzer.visitJumpInsn(Opcodes.GOTO, new Label());
+ frame = FrameSnapshot.create(analyzer, 0);
+ }
+
+ @Test
+ public void testFrame() {
+ analyzer.visitInsn(Opcodes.ICONST_0);
+ frame = FrameSnapshot.create(analyzer, 0);
+
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, arr("Foo"), 1,
+ arr(Opcodes.INTEGER));
+ }
+
+ @Test
+ public void testReduce() {
+ analyzer.visitInsn(Opcodes.ICONST_0);
+ analyzer.visitInsn(Opcodes.LCONST_0);
+ analyzer.visitInsn(Opcodes.ICONST_0);
+ analyzer.visitInsn(Opcodes.DCONST_0);
+ frame = FrameSnapshot.create(analyzer, 0);
+
+ final Object[] stack = arr(Opcodes.INTEGER, Opcodes.LONG,
+ Opcodes.INTEGER, Opcodes.DOUBLE);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, arr("Foo"), 4, stack);
+ }
+
+ @Test
+ public void testPop() {
+ analyzer.visitInsn(Opcodes.ICONST_0);
+ analyzer.visitInsn(Opcodes.LCONST_0);
+ analyzer.visitInsn(Opcodes.ICONST_0);
+ analyzer.visitInsn(Opcodes.ICONST_0);
+ frame = FrameSnapshot.create(analyzer, 2);
+
+ final Object[] stack = arr(Opcodes.INTEGER, Opcodes.LONG);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, arr("Foo"), 2, stack);
+ }
+
+ private Object[] arr(Object... elements) {
+ return elements;
+ }
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/MethodProbesAdapterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/MethodProbesAdapterTest.java
index acd6485c..880ebf20 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/MethodProbesAdapterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/MethodProbesAdapterTest.java
@@ -23,6 +23,7 @@ import org.junit.Test;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.AnalyzerAdapter;
import org.objectweb.asm.util.Printer;
/**
@@ -40,6 +41,8 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
private MethodVisitor adapter;
+ private IFrame frame;
+
private static class TraceAdapter extends MethodProbesVisitor {
private final Printer printer;
@@ -61,22 +64,26 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
}
@Override
- public void visitJumpInsnWithProbe(int opcode, Label label, int probeId) {
+ public void visitJumpInsnWithProbe(int opcode, Label label,
+ int probeId, IFrame frame) {
rec("visitJumpInsnWithProbe", Integer.valueOf(opcode), label,
Integer.valueOf(probeId));
+ frame.accept(this);
}
@Override
public void visitTableSwitchInsnWithProbes(int min, int max,
- Label dflt, Label[] labels) {
+ Label dflt, Label[] labels, IFrame frame) {
rec("visitTableSwitchInsnWithProbes", Integer.valueOf(min),
Integer.valueOf(max), dflt, labels);
+ frame.accept(this);
}
@Override
public void visitLookupSwitchInsnWithProbes(Label dflt, int[] keys,
- Label[] labels) {
+ Label[] labels, IFrame frame) {
rec("visitLookupSwitchInsnWithProbes", dflt, keys, labels);
+ frame.accept(this);
}
private void rec(String name, Object... args) {
@@ -95,7 +102,17 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
expectedVisitor = new TraceAdapter(expected);
actual = new MethodRecorder();
MethodProbesVisitor actualVisitor = new TraceAdapter(actual);
- adapter = new MethodProbesAdapter(actualVisitor, this);
+ MethodProbesAdapter probesAdapter = new MethodProbesAdapter(
+ actualVisitor, this);
+ final AnalyzerAdapter analyzer = new AnalyzerAdapter("Foo", 0, "doit",
+ "()V", probesAdapter);
+ probesAdapter.setAnalyzer(analyzer);
+ adapter = analyzer;
+ frame = new IFrame() {
+
+ public void accept(MethodVisitor mv) {
+ }
+ };
}
@After
@@ -116,6 +133,16 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
@Test
public void testVisitProbe2() {
+ LabelInfo.setTarget(label);
+ LabelInfo.setTarget(label);
+
+ adapter.visitLabel(label);
+
+ expectedVisitor.visitLabel(label);
+ }
+
+ @Test
+ public void testVisitProbe3() {
adapter.visitLabel(label);
expectedVisitor.visitLabel(label);
@@ -130,8 +157,12 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
@Test
public void testVisitInsn2() {
+ adapter.visitInsn(Opcodes.ICONST_0);
+ adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitInsn(Opcodes.IADD);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
expectedVisitor.visitInsn(Opcodes.IADD);
}
@@ -140,28 +171,70 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
LabelInfo.setTarget(label);
LabelInfo.setTarget(label);
- adapter.visitJumpInsn(Opcodes.IFLT, label);
+ adapter.visitJumpInsn(Opcodes.GOTO, label);
- expectedVisitor.visitJumpInsnWithProbe(Opcodes.IFLT, label, 1000);
+ expectedVisitor
+ .visitJumpInsnWithProbe(Opcodes.GOTO, label, 1000, frame);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
+ 0, null);
}
@Test
public void testVisitJumpInsn2() {
+ LabelInfo.setTarget(label);
+ LabelInfo.setTarget(label);
+
+ adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitJumpInsn(Opcodes.IFLT, label);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
+ expectedVisitor
+ .visitJumpInsnWithProbe(Opcodes.IFLT, label, 1000, frame);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
+ 0, null);
+ }
+
+ @Test
+ public void testVisitJumpInsn3() {
+ adapter.visitInsn(Opcodes.ICONST_0);
+ adapter.visitJumpInsn(Opcodes.IFLT, label);
+
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
expectedVisitor.visitJumpInsn(Opcodes.IFLT, label);
}
@Test
+ public void testVisitJumpInsn4() {
+ LabelInfo.setTarget(label);
+ LabelInfo.setTarget(label);
+
+ adapter.visitInsn(Opcodes.ICONST_0);
+ adapter.visitInsn(Opcodes.ICONST_0);
+ adapter.visitJumpInsn(Opcodes.IF_ICMPEQ, label);
+
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
+ expectedVisitor.visitJumpInsnWithProbe(Opcodes.IF_ICMPEQ, label, 1000,
+ frame);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
+ 0, null);
+ }
+
+ @Test
public void testVisitLookupSwitchInsn1() {
LabelInfo.setTarget(label);
LabelInfo.setTarget(label);
final int[] keys = new int[] { 0, 1 };
final Label[] labels = new Label[] { label, label };
+ adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitLookupSwitchInsn(label, keys, labels);
- expectedVisitor.visitLookupSwitchInsnWithProbes(label, keys, labels);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
+ expectedVisitor.visitLookupSwitchInsnWithProbes(label, keys, labels,
+ frame);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
+ 0, null);
assertEquals(1000, LabelInfo.getProbeId(label));
}
@@ -173,9 +246,14 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
final int[] keys = new int[] { 0, 1 };
final Label[] labels = new Label[] { label2, label };
+ adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitLookupSwitchInsn(label, keys, labels);
- expectedVisitor.visitLookupSwitchInsnWithProbes(label, keys, labels);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
+ expectedVisitor.visitLookupSwitchInsnWithProbes(label, keys, labels,
+ frame);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
+ 0, null);
assertEquals(LabelInfo.NO_PROBE, LabelInfo.getProbeId(label));
assertEquals(1000, LabelInfo.getProbeId(label2));
}
@@ -184,8 +262,10 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
public void testVisitLookupSwitchInsn3() {
final int[] keys = new int[] { 0, 1 };
final Label[] labels = new Label[] { label, label };
+ adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitLookupSwitchInsn(label, keys, labels);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
expectedVisitor.visitLookupSwitchInsn(label, keys, labels);
}
@@ -195,9 +275,14 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
LabelInfo.setTarget(label);
final Label[] labels = new Label[] { label, label };
+ adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitTableSwitchInsn(0, 1, label, labels);
- expectedVisitor.visitTableSwitchInsnWithProbes(0, 1, label, labels);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
+ expectedVisitor.visitTableSwitchInsnWithProbes(0, 1, label, labels,
+ frame);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
+ 0, null);
assertEquals(1000, LabelInfo.getProbeId(label));
}
@@ -208,9 +293,14 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
LabelInfo.setTarget(label2);
final Label[] labels = new Label[] { label2, label };
+ adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitTableSwitchInsn(0, 1, label, labels);
- expectedVisitor.visitTableSwitchInsnWithProbes(0, 1, label, labels);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
+ expectedVisitor.visitTableSwitchInsnWithProbes(0, 1, label, labels,
+ frame);
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
+ 0, null);
assertEquals(LabelInfo.NO_PROBE, LabelInfo.getProbeId(label));
assertEquals(1000, LabelInfo.getProbeId(label2));
}
@@ -218,8 +308,10 @@ public class MethodProbesAdapterTest implements IProbeIdGenerator {
@Test
public void testVisitTableSwitchInsn3() {
final Label[] labels = new Label[] { label, label };
+ adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitTableSwitchInsn(0, 1, label, labels);
+ expectedVisitor.visitInsn(Opcodes.ICONST_0);
expectedVisitor.visitTableSwitchInsn(0, 1, label, labels);
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/FrameTrackerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/FrameTrackerTest.java
deleted file mode 100644
index c3a89cd6..00000000
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/FrameTrackerTest.java
+++ /dev/null
@@ -1,1477 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2013 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.instr;
-
-import static org.junit.Assert.assertEquals;
-import static org.objectweb.asm.Opcodes.*;
-
-import org.jacoco.core.JaCoCo;
-import org.jacoco.core.instr.MethodRecorder;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.objectweb.asm.Handle;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.MethodNode;
-
-/**
- * Unit tests for {@link ClassInstrumenter}.
- */
-public class FrameTrackerTest {
-
- private static class FrameBuilder {
-
- private Object[] stack = new Object[0];
- private Object[] locals = new Object[0];
-
- FrameBuilder stack(Object... stack) {
- this.stack = stack;
- return this;
- }
-
- FrameBuilder locals(Object... locals) {
- this.locals = locals;
- return this;
- }
-
- void accept(MethodVisitor mv) {
- mv.visitFrame(F_NEW, locals.length, locals, stack.length, stack);
- }
-
- }
-
- private FrameBuilder before, after;
-
- private MethodNode mv;
-
- private Label label;
-
- @Before
- public void setup() {
- before = new FrameBuilder();
- after = new FrameBuilder();
- mv = new MethodNode(0, "test", "()V", null, null);
- label = new Label();
- }
-
- @After
- public void verify() {
- MethodRecorder actual = new MethodRecorder();
- MethodVisitor noLabels = new MethodVisitor(JaCoCo.ASM_API_VERSION,
- actual.getVisitor()) {
- @Override
- public void visitLabel(Label label) {
- // Ignore labels inserted by the tracker
- }
- };
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", noLabels);
- before.accept(tracker);
- mv.instructions.accept(tracker);
- tracker.insertFrame();
-
- MethodRecorder expected = new MethodRecorder();
- before.accept(expected.getVisitor());
- mv.instructions.accept(expected.getVisitor());
- after.accept(expected.getVisitor());
-
- assertEquals(expected, actual);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testVisitFrameIllegalFrameType() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitFrame(F_APPEND, 0, null, 0, null);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testVisitInsnIllegalOpcode() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitInsn(GOTO);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testVisitIntInsnIllegalOpcode() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitIntInsn(NOP, 0);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testVisitVarInsnIllegalOpcode() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitVarInsn(NOP, 0);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testVisitTypeInsnIllegalOpcode() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitTypeInsn(NOP, "A");
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testVisitFieldInsnIllegalOpcode() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitFieldInsn(NOP, "A", "x", "I");
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testVisitJumpInsnIllegalOpcode() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitJumpInsn(NOP, new Label());
- }
-
- @Test(expected = IllegalStateException.class)
- public void testInvalidFrame_StackUnderflow() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitInsn(POP);
- }
-
- @Test(expected = IllegalStateException.class)
- public void testInvalidFrame_UndefinedLocal() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitVarInsn(ALOAD, 1);
- }
-
- @Test
- public void testArgumentsConstructor() {
- FrameBuilder expectedFrame = new FrameBuilder();
- expectedFrame.locals(UNINITIALIZED_THIS);
- testArguments(0, "<init>", "()V", expectedFrame);
- }
-
- @Test
- public void testArgumentsStatic() {
- FrameBuilder expectedFrame = new FrameBuilder();
- testArguments(Opcodes.ACC_STATIC, "test", "()V", expectedFrame);
- }
-
- @Test
- public void testArgumentsStaticIJZ() {
- FrameBuilder expectedFrame = new FrameBuilder();
- expectedFrame.locals(INTEGER, LONG, INTEGER);
- testArguments(Opcodes.ACC_STATIC, "test", "(IJZ)V", expectedFrame);
- }
-
- @Test
- public void testArgumentsStaticLArr() {
- FrameBuilder expectedFrame = new FrameBuilder();
- expectedFrame.locals("Foo", "[[S");
- testArguments(Opcodes.ACC_STATIC, "test", "(LFoo;[[S)V", expectedFrame);
- }
-
- @Test
- public void testArgumentsFD() {
- FrameBuilder expectedFrame = new FrameBuilder();
- expectedFrame.locals("Test", FLOAT, DOUBLE);
- testArguments(0, "test", "(FD)V", expectedFrame);
- }
-
- private void testArguments(int access, String name, String desc,
- FrameBuilder expectedFrame) {
- MethodRecorder actual = new MethodRecorder();
- FrameTracker tracker = new FrameTracker("Test", access, name, desc,
- actual.getVisitor());
- tracker.insertFrame();
-
- MethodRecorder expected = new MethodRecorder();
- expectedFrame.accept(expected.getVisitor());
-
- assertEquals(expected, actual);
- }
-
- @Test
- public void testFrameGaps() {
- before.locals().stack(INTEGER);
- mv.visitVarInsn(ISTORE, 3);
- after.locals(TOP, TOP, TOP, INTEGER).stack();
- }
-
- @Test
- public void testLargeFrame() {
- before.locals("A", "B", "C", "D", "E").stack("AA", "BB", "CC", "DD",
- "EE");
- mv.visitInsn(NOP);
- after.locals("A", "B", "C", "D", "E").stack("AA", "BB", "CC", "DD",
- "EE");
- }
-
- @Test
- public void AALOAD_multidim_obj() {
- before.locals().stack("[[Ljava/lang/String;", INTEGER);
- mv.visitInsn(AALOAD);
- after.locals().stack("[Ljava/lang/String;");
- }
-
- @Test
- public void AALOAD_multidim_prim() {
- before.locals().stack("[[I", INTEGER);
- mv.visitInsn(AALOAD);
- after.locals().stack("[I");
- }
-
- @Test
- public void AASTORE() {
- before.locals().stack("[Ljava/lang/String;", INTEGER,
- "[Ljava/lang/String;");
- mv.visitInsn(AASTORE);
- after.locals().stack();
- }
-
- @Test
- public void ACONST_NULL() {
- before.locals().stack();
- mv.visitInsn(ACONST_NULL);
- after.locals().stack(NULL);
- }
-
- @Test
- public void ALOAD() {
- before.locals(LONG, "X", INTEGER).stack();
- mv.visitVarInsn(ALOAD, 2);
- after.locals(LONG, "X", INTEGER).stack("X");
- }
-
- @Test
- public void ANEWARRAY() {
- before.locals().stack(INTEGER);
- mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
- after.locals().stack("[Ljava/lang/String;");
- }
-
- @Test
- public void ANEWARRAY_multidim_obj() {
- before.locals().stack(INTEGER);
- mv.visitTypeInsn(ANEWARRAY, "[Ljava/lang/String;");
- after.locals().stack("[[Ljava/lang/String;");
- }
-
- @Test
- public void ANEWARRAY_multidim_prim() {
- before.locals().stack(INTEGER);
- mv.visitTypeInsn(ANEWARRAY, "[I");
- after.locals().stack("[[I");
- }
-
- @Test
- public void ARETURN() {
- before.locals().stack("java/lang/Object");
- mv.visitInsn(ARETURN);
- after.locals().stack();
- }
-
- @Test
- public void ARRAYLENGTH() {
- before.locals().stack("[Z");
- mv.visitInsn(ARRAYLENGTH);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ASTORE() {
- before.locals(LONG, "X", INTEGER).stack("Y");
- mv.visitVarInsn(ASTORE, 3);
- after.locals(LONG, "X", "Y").stack();
- }
-
- @Test
- public void ATHROW() {
- before.locals().stack("java/lang/Exception");
- mv.visitInsn(ATHROW);
- after.locals().stack();
- }
-
- @Test
- public void BALOAD() {
- before.locals().stack("[B", INTEGER);
- mv.visitInsn(BALOAD);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void BASTORE() {
- before.locals().stack("[B", INTEGER, INTEGER);
- mv.visitInsn(BASTORE);
- after.locals().stack();
- }
-
- @Test
- public void BIPUSH() {
- before.locals().stack();
- mv.visitIntInsn(BIPUSH, 123);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void CALOAD() {
- before.locals().stack("[C", INTEGER);
- mv.visitInsn(CALOAD);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void CASTORE() {
- before.locals().stack("[C", INTEGER, INTEGER);
- mv.visitInsn(CASTORE);
- after.locals().stack();
- }
-
- @Test
- public void CHECKCAST() {
- before.locals().stack("java/lang/Object");
- mv.visitTypeInsn(CHECKCAST, "java/lang/String");
- after.locals().stack("java/lang/String");
- }
-
- @Test
- public void D2F() {
- before.locals().stack(DOUBLE);
- mv.visitInsn(D2F);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void D2I() {
- before.locals().stack(DOUBLE);
- mv.visitInsn(D2I);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void D2L() {
- before.locals().stack(DOUBLE);
- mv.visitInsn(D2L);
- after.locals().stack(LONG);
- }
-
- @Test
- public void DADD() {
- before.locals().stack(DOUBLE, DOUBLE);
- mv.visitInsn(DADD);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DALOAD() {
- before.locals().stack("[D", INTEGER);
- mv.visitInsn(DALOAD);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DASTORE() {
- before.locals().stack("[D", INTEGER, DOUBLE);
- mv.visitInsn(DASTORE);
- after.locals().stack();
- }
-
- @Test
- public void DCMPG() {
- before.locals().stack(DOUBLE, DOUBLE);
- mv.visitInsn(DCMPG);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void DCMPL() {
- before.locals().stack(DOUBLE, DOUBLE);
- mv.visitInsn(DCMPL);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void DCONST_0() {
- before.locals().stack();
- mv.visitInsn(DCONST_0);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DCONST_1() {
- before.locals().stack();
- mv.visitInsn(DCONST_1);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DDIV() {
- before.locals().stack(DOUBLE, DOUBLE);
- mv.visitInsn(DDIV);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DLOAD() {
- before.locals(DOUBLE).stack();
- mv.visitVarInsn(DLOAD, 0);
- after.locals(DOUBLE).stack(DOUBLE);
- }
-
- @Test
- public void DMUL() {
- before.locals().stack(DOUBLE, DOUBLE);
- mv.visitInsn(DMUL);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DNEG() {
- before.locals().stack(DOUBLE);
- mv.visitInsn(DNEG);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DREM() {
- before.locals().stack(DOUBLE, DOUBLE);
- mv.visitInsn(DREM);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DRETURN() {
- before.locals().stack(DOUBLE);
- mv.visitInsn(DRETURN);
- after.locals().stack();
- }
-
- @Test
- public void DSTORE() {
- before.locals().stack(DOUBLE);
- mv.visitVarInsn(DSTORE, 0);
- after.locals(DOUBLE).stack();
- }
-
- @Test
- public void DSUB() {
- before.locals().stack(DOUBLE, DOUBLE);
- mv.visitInsn(DSUB);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void DUP() {
- before.locals().stack("A");
- mv.visitInsn(DUP);
- after.locals().stack("A", "A");
- }
-
- @Test
- public void DUP2_one_two_word_item() {
- before.locals().stack(LONG);
- mv.visitInsn(DUP2);
- after.locals().stack(LONG, LONG);
- }
-
- @Test
- public void DUP2_two_one_word_items() {
- before.locals().stack("A", "B");
- mv.visitInsn(DUP2);
- after.locals().stack("A", "B", "A", "B");
- }
-
- @Test
- public void DUP_X1() {
- before.locals().stack("A", "B");
- mv.visitInsn(DUP_X1);
- after.locals().stack("B", "A", "B");
- }
-
- @Test
- public void DUP2_X1_one_two_word_item() {
- before.locals().stack("A", LONG);
- mv.visitInsn(DUP2_X1);
- after.locals().stack(LONG, "A", LONG);
- }
-
- @Test
- public void DUP2_X1_two_one_word_items() {
- before.locals().stack("A", "B", "C");
- mv.visitInsn(DUP2_X1);
- after.locals().stack("B", "C", "A", "B", "C");
- }
-
- @Test
- public void DUP_X2() {
- before.locals().stack("A", "B", "C");
- mv.visitInsn(DUP_X2);
- after.locals().stack("C", "A", "B", "C");
- }
-
- @Test
- public void DUP2_X2_one_two_word_item() {
- before.locals().stack("A", "B", LONG);
- mv.visitInsn(DUP2_X2);
- after.locals().stack(LONG, "A", "B", LONG);
- }
-
- @Test
- public void DUP2_X2_two_one_word_items() {
- before.locals().stack("A", "B", "C", "D");
- mv.visitInsn(DUP2_X2);
- after.locals().stack("C", "D", "A", "B", "C", "D");
- }
-
- @Test
- public void F2D() {
- before.locals().stack(FLOAT);
- mv.visitInsn(F2D);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void F2I() {
- before.locals().stack(FLOAT);
- mv.visitInsn(F2I);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void F2L() {
- before.locals().stack(FLOAT);
- mv.visitInsn(F2L);
- after.locals().stack(LONG);
- }
-
- @Test
- public void FADD() {
- before.locals().stack(FLOAT, FLOAT);
- mv.visitInsn(FADD);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FALOAD() {
- before.locals().stack("[F", INTEGER);
- mv.visitInsn(FALOAD);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FASTORE() {
- before.locals().stack("[F", INTEGER, FLOAT);
- mv.visitInsn(FASTORE);
- after.locals().stack();
- }
-
- @Test
- public void FCMPG() {
- before.locals().stack(FLOAT, FLOAT);
- mv.visitInsn(FCMPG);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void FCMPL() {
- before.locals().stack(FLOAT, FLOAT);
- mv.visitInsn(FCMPL);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void FCONST_0() {
- before.locals().stack();
- mv.visitInsn(FCONST_0);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FCONST_1() {
- before.locals().stack();
- mv.visitInsn(FCONST_1);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FCONST_2() {
- before.locals().stack();
- mv.visitInsn(FCONST_2);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FDIV() {
- before.locals().stack(FLOAT, FLOAT);
- mv.visitInsn(FDIV);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FLOAD() {
- before.locals(FLOAT).stack();
- mv.visitVarInsn(FLOAD, 0);
- after.locals(FLOAT).stack(FLOAT);
- }
-
- @Test
- public void FMUL() {
- before.locals().stack(FLOAT, FLOAT);
- mv.visitInsn(FMUL);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FNEG() {
- before.locals().stack(FLOAT);
- mv.visitInsn(FNEG);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FREM() {
- before.locals().stack(FLOAT, FLOAT);
- mv.visitInsn(FREM);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void FRETURN() {
- before.locals().stack(FLOAT);
- mv.visitInsn(FRETURN);
- after.locals().stack();
- }
-
- @Test
- public void FSTORE() {
- before.locals().stack(FLOAT);
- mv.visitVarInsn(FSTORE, 0);
- after.locals(FLOAT).stack();
- }
-
- @Test
- public void FSUB() {
- before.locals().stack(FLOAT, FLOAT);
- mv.visitInsn(FSUB);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void GETFIELD() {
- before.locals().stack("Test");
- mv.visitFieldInsn(GETFIELD, "Test", "f", "I");
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void GETSTATIC() {
- before.locals().stack();
- mv.visitFieldInsn(GETSTATIC, "Test", "f", "Z");
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void GETSTATIC_float() {
- before.locals().stack();
- mv.visitFieldInsn(GETSTATIC, "Test", "f", "F");
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void GETSTATIC_double() {
- before.locals().stack();
- mv.visitFieldInsn(GETSTATIC, "Test", "f", "D");
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void GOTO() {
- before.locals().stack();
- mv.visitJumpInsn(GOTO, label);
- after.locals().stack();
- }
-
- @Test
- public void I2B() {
- before.locals().stack(INTEGER);
- mv.visitInsn(I2B);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void I2C() {
- before.locals().stack(INTEGER);
- mv.visitInsn(I2C);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void I2D() {
- before.locals().stack(INTEGER);
- mv.visitInsn(I2D);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void I2F() {
- before.locals().stack(INTEGER);
- mv.visitInsn(I2F);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void I2L() {
- before.locals().stack(INTEGER);
- mv.visitInsn(I2L);
- after.locals().stack(LONG);
- }
-
- @Test
- public void I2S() {
- before.locals().stack(INTEGER);
- mv.visitInsn(I2S);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IADD() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(IADD);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IALOAD() {
- before.locals().stack("[I", INTEGER);
- mv.visitInsn(IALOAD);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IAND() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(IAND);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IASTORE() {
- before.locals().stack("[I", INTEGER, INTEGER);
- mv.visitInsn(IASTORE);
- after.locals().stack();
- }
-
- @Test
- public void ICONST_M1() {
- before.locals().stack();
- mv.visitInsn(ICONST_M1);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ICONST_0() {
- before.locals().stack();
- mv.visitInsn(ICONST_0);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ICONST_1() {
- before.locals().stack();
- mv.visitInsn(ICONST_1);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ICONST_2() {
- before.locals().stack();
- mv.visitInsn(ICONST_2);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ICONST_3() {
- before.locals().stack();
- mv.visitInsn(ICONST_3);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ICONST_4() {
- before.locals().stack();
- mv.visitInsn(ICONST_4);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ICONST_5() {
- before.locals().stack();
- mv.visitInsn(ICONST_5);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IDIV() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(IDIV);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IF_ACMPEQ() {
- before.locals().stack("A", "A");
- mv.visitJumpInsn(IF_ACMPEQ, label);
- after.locals().stack();
- }
-
- @Test
- public void IF_ACMPNE() {
- before.locals().stack("A", "A");
- mv.visitJumpInsn(IF_ACMPNE, label);
- after.locals().stack();
- }
-
- @Test
- public void IF_ICMPEQ() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitJumpInsn(IF_ICMPEQ, label);
- after.locals().stack();
- }
-
- @Test
- public void IF_ICMPGE() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitJumpInsn(IF_ICMPGE, label);
- after.locals().stack();
- }
-
- @Test
- public void IF_ICMPGT() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitJumpInsn(IF_ICMPGT, label);
- after.locals().stack();
- }
-
- @Test
- public void IF_ICMPLE() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitJumpInsn(IF_ICMPLE, label);
- after.locals().stack();
- }
-
- @Test
- public void IF_ICMPLT() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitJumpInsn(IF_ICMPLT, label);
- after.locals().stack();
- }
-
- @Test
- public void IF_ICMPNE() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitJumpInsn(IF_ICMPNE, label);
- after.locals().stack();
- }
-
- @Test
- public void IFEQ() {
- before.locals().stack(INTEGER);
- mv.visitJumpInsn(IFEQ, label);
- after.locals().stack();
- }
-
- @Test
- public void IFGE() {
- before.locals().stack(INTEGER);
- mv.visitJumpInsn(IFGE, label);
- after.locals().stack();
- }
-
- @Test
- public void IFGT() {
- before.locals().stack(INTEGER);
- mv.visitJumpInsn(IFGT, label);
- after.locals().stack();
- }
-
- @Test
- public void IFLE() {
- before.locals().stack(INTEGER);
- mv.visitJumpInsn(IFLE, label);
- after.locals().stack();
- }
-
- @Test
- public void IFLT() {
- before.locals().stack(INTEGER);
- mv.visitJumpInsn(IFLT, label);
- after.locals().stack();
- }
-
- @Test
- public void IFNE() {
- before.locals().stack(INTEGER);
- mv.visitJumpInsn(IFNE, label);
- after.locals().stack();
- }
-
- @Test
- public void IFNONNULL() {
- before.locals().stack("A");
- mv.visitJumpInsn(IFNONNULL, label);
- after.locals().stack();
- }
-
- @Test
- public void IFNULL() {
- before.locals().stack("A");
- mv.visitJumpInsn(IFNULL, label);
- after.locals().stack();
- }
-
- @Test
- public void IINC() {
- before.locals(INTEGER).stack();
- mv.visitIincInsn(0, 1);
- after.locals(INTEGER).stack();
- }
-
- @Test
- public void ILOAD() {
- before.locals(INTEGER).stack();
- mv.visitVarInsn(ILOAD, 0);
- after.locals(INTEGER).stack(INTEGER);
- }
-
- @Test
- public void IMUL() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(IMUL);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void INEG() {
- before.locals().stack(INTEGER);
- mv.visitInsn(INEG);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void INSTANCEOF() {
- before.locals().stack("java/lang/String");
- mv.visitTypeInsn(INSTANCEOF, "java/lang/String");
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void INVOKEDYNAMIC() {
- before.locals().stack("java/lang/String");
- mv.visitInvokeDynamicInsn("foo", "(Ljava/lang/String;)I", new Handle(0,
- null, null, null));
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void INVOKEINTERFACE() {
- before.locals().stack("Test");
- mv.visitMethodInsn(INVOKEVIRTUAL, "Test", "getSize", "()I");
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void INVOKESPECIAL() {
- before.locals().stack("Test", LONG, LONG);
- mv.visitMethodInsn(INVOKEVIRTUAL, "Test", "add", "(JJ)J");
- after.locals().stack(LONG);
- }
-
- @Test
- public void INVOKESPECIAL_initsuper() {
- before.locals(UNINITIALIZED_THIS).stack(UNINITIALIZED_THIS);
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "<init>", "()V");
- after.locals("Test").stack();
- }
-
- @Test
- public void INVOKESTATIC() {
- before.locals().stack(LONG, LONG);
- mv.visitMethodInsn(INVOKESTATIC, "Test", "add", "(JJ)J");
- after.locals().stack(LONG);
- }
-
- @Test
- public void INVOKEVIRTUAL() {
- before.locals().stack("Test", INTEGER, DOUBLE);
- mv.visitMethodInsn(INVOKEVIRTUAL, "Test", "run", "(ID)V");
- after.locals().stack();
- }
-
- @Test
- public void IOR() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(IOR);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IREM() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(IREM);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IRETURN() {
- before.locals().stack(INTEGER);
- mv.visitInsn(IRETURN);
- after.locals().stack();
- }
-
- @Test
- public void ISHL() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(ISHL);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ISHR() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(ISHR);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void ISSTORE() {
- before.locals().stack(INTEGER);
- mv.visitVarInsn(ISTORE, 0);
- after.locals(INTEGER).stack();
- }
-
- @Test
- public void ISUB() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(ISUB);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IUSHR() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(IUSHR);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void IXOR() {
- before.locals().stack(INTEGER, INTEGER);
- mv.visitInsn(IXOR);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void L2D() {
- before.locals().stack(LONG);
- mv.visitInsn(L2D);
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void L2F() {
- before.locals().stack(LONG);
- mv.visitInsn(L2F);
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void L2I() {
- before.locals().stack(LONG);
- mv.visitInsn(L2I);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void LADD() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LADD);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LALOAD() {
- before.locals().stack("L[", INTEGER);
- mv.visitInsn(LALOAD);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LAND() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LAND);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LASTORE() {
- before.locals().stack("L[", INTEGER, LONG);
- mv.visitInsn(LASTORE);
- after.locals().stack();
- }
-
- @Test
- public void LCMP() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LCMP);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void LCONST_0() {
- before.locals().stack();
- mv.visitInsn(LCONST_0);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LCONST_1() {
- before.locals().stack();
- mv.visitInsn(LCONST_1);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LDC_int() {
- before.locals().stack();
- mv.visitLdcInsn(Integer.valueOf(123));
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void LDC_float() {
- before.locals().stack();
- mv.visitLdcInsn(Float.valueOf(123));
- after.locals().stack(FLOAT);
- }
-
- @Test
- public void LDC_long() {
- before.locals().stack();
- mv.visitLdcInsn(Long.valueOf(123));
- after.locals().stack(LONG);
- }
-
- @Test
- public void LDC_double() {
- before.locals().stack();
- mv.visitLdcInsn(Double.valueOf(123));
- after.locals().stack(DOUBLE);
- }
-
- @Test
- public void LDC_String() {
- before.locals().stack();
- mv.visitLdcInsn("Hello VM!");
- after.locals().stack("java/lang/String");
- }
-
- @Test
- public void LDC_Class() {
- before.locals().stack();
- mv.visitLdcInsn(Type.getType("[java/lang/Runnable;"));
- after.locals().stack("java/lang/Class");
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void LDC_invalidType() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", null);
- tracker.visitLdcInsn(Byte.valueOf((byte) 123));
- }
-
- @Test
- public void LDIV() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LDIV);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LLOAD() {
- before.locals(LONG).stack();
- mv.visitVarInsn(LLOAD, 0);
- after.locals(LONG).stack(LONG);
- }
-
- @Test
- public void LMUL() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LMUL);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LNEG() {
- before.locals().stack(LONG);
- mv.visitInsn(LNEG);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LOOKUPSWITCH() {
- before.locals().stack(INTEGER);
- mv.visitLookupSwitchInsn(new Label(), new int[0], new Label[0]);
- after.locals().stack();
- }
-
- @Test
- public void LOR() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LOR);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LREM() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LREM);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LRETURN() {
- before.locals().stack(LONG);
- mv.visitInsn(LRETURN);
- after.locals().stack();
- }
-
- @Test
- public void LSHL() {
- before.locals().stack(LONG, INTEGER);
- mv.visitInsn(LSHL);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LSHR() {
- before.locals().stack(LONG, INTEGER);
- mv.visitInsn(LSHR);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LSTORE() {
- before.locals().stack(LONG);
- mv.visitVarInsn(LSTORE, 0);
- after.locals(LONG).stack();
- }
-
- @Test
- public void LSUB() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LSUB);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LUSHR() {
- before.locals().stack(LONG, INTEGER);
- mv.visitInsn(LUSHR);
- after.locals().stack(LONG);
- }
-
- @Test
- public void LXOR() {
- before.locals().stack(LONG, LONG);
- mv.visitInsn(LXOR);
- after.locals().stack(LONG);
- }
-
- @Test
- public void MONITORENTER() {
- before.locals().stack("java/lang/Object");
- mv.visitInsn(MONITORENTER);
- after.locals().stack();
- }
-
- @Test
- public void MONITOREXIT() {
- before.locals().stack("java/lang/Object");
- mv.visitInsn(MONITOREXIT);
- after.locals().stack();
- }
-
- @Test
- public void MULTIANEWARRAY() {
- before.locals().stack(INTEGER, INTEGER, INTEGER);
- mv.visitMultiANewArrayInsn("[[[Ljava/lang/String;", 3);
- after.locals().stack("[[[Ljava/lang/String;");
- }
-
- @Test
- public void NEW() {
- before.locals(LONG).stack(LONG);
- mv.visitTypeInsn(NEW, "Test");
- mv.visitInsn(DUP);
- mv.visitMethodInsn(INVOKESPECIAL, "Test", "<init>", "()V");
- after.locals(LONG).stack(LONG, "Test");
- }
-
- @Test
- public void NEWARRAY_boolean() {
- before.locals().stack(INTEGER);
- mv.visitIntInsn(NEWARRAY, T_BOOLEAN);
- after.locals().stack("[Z");
- }
-
- @Test
- public void NEWARRAY_char() {
- before.locals().stack(INTEGER);
- mv.visitIntInsn(NEWARRAY, T_CHAR);
- after.locals().stack("[C");
- }
-
- @Test
- public void NEWARRAY_float() {
- before.locals().stack(INTEGER);
- mv.visitIntInsn(NEWARRAY, T_FLOAT);
- after.locals().stack("[F");
- }
-
- @Test
- public void NEWARRAY_double() {
- before.locals().stack(INTEGER);
- mv.visitIntInsn(NEWARRAY, T_DOUBLE);
- after.locals().stack("[D");
- }
-
- @Test
- public void NEWARRAY_byte() {
- before.locals().stack(INTEGER);
- mv.visitIntInsn(NEWARRAY, T_BYTE);
- after.locals().stack("[B");
- }
-
- @Test
- public void NEWARRAY_short() {
- before.locals().stack(INTEGER);
- mv.visitIntInsn(NEWARRAY, T_SHORT);
- after.locals().stack("[S");
- }
-
- @Test
- public void NEWARRAY_int() {
- before.locals().stack(INTEGER);
- mv.visitIntInsn(NEWARRAY, T_INT);
- after.locals().stack("[I");
- }
-
- @Test
- public void NEWARRAY_long() {
- before.locals().stack(INTEGER);
- mv.visitIntInsn(NEWARRAY, T_LONG);
- after.locals().stack("[J");
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void NEWARRAY_invalidOperand() {
- FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
- "()V", new MethodNode());
- tracker.visitFrame(F_NEW, 0, new Object[0], 1, new Object[] { INTEGER });
- tracker.visitIntInsn(NEWARRAY, -1);
- }
-
- @Test
- public void NOP() {
- before.locals().stack();
- mv.visitInsn(NOP);
- after.locals().stack();
- }
-
- @Test
- public void POP() {
- before.locals().stack(INTEGER);
- mv.visitInsn(POP);
- after.locals().stack();
- }
-
- @Test
- public void POP2_one_two_word_item() {
- before.locals().stack(DOUBLE);
- mv.visitInsn(POP2);
- after.locals().stack();
- }
-
- @Test
- public void POP2_two_one_word_items() {
- before.locals().stack("A", INTEGER);
- mv.visitInsn(POP2);
- after.locals().stack();
- }
-
- @Test
- public void PUTFIELD() {
- before.locals().stack("Test", INTEGER);
- mv.visitFieldInsn(PUTFIELD, "Test", "field", "I");
- after.locals().stack();
- }
-
- @Test
- public void PUTSTATIC() {
- before.locals().stack(INTEGER);
- mv.visitFieldInsn(PUTSTATIC, "Test", "field", "I");
- after.locals().stack();
- }
-
- @Test
- public void RETURN() {
- before.locals().stack();
- mv.visitInsn(RETURN);
- after.locals().stack();
- }
-
- @Test
- public void SALOAD() {
- before.locals().stack("[S", INTEGER);
- mv.visitInsn(SALOAD);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void SASTORE() {
- before.locals().stack("[S", INTEGER, INTEGER);
- mv.visitInsn(SASTORE);
- after.locals().stack();
- }
-
- @Test
- public void SIPUSH() {
- before.locals().stack();
- mv.visitIntInsn(SIPUSH, 123);
- after.locals().stack(INTEGER);
- }
-
- @Test
- public void SWAP() {
- before.locals().stack("A", "B");
- mv.visitInsn(SWAP);
- after.locals().stack("B", "A");
- }
-
- @Test
- public void TABLESWITCH() {
- before.locals().stack(INTEGER);
- mv.visitTableSwitchInsn(0, 1, new Label(), new Label[0]);
- after.locals().stack();
- }
-
-}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java
index 317fbd61..67ffdbfc 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java
@@ -14,6 +14,7 @@ package org.jacoco.core.internal.instr;
import static org.junit.Assert.assertEquals;
import org.jacoco.core.instr.MethodRecorder;
+import org.jacoco.core.internal.flow.IFrame;
import org.jacoco.core.internal.flow.LabelInfo;
import org.junit.Before;
import org.junit.Test;
@@ -32,6 +33,8 @@ public class MethodInstrumenterTest {
private MethodVisitor expectedVisitor;
+ private IFrame frame;
+
@Before
public void setup() {
actual = new MethodRecorder();
@@ -43,14 +46,13 @@ public class MethodInstrumenterTest {
actual.getVisitor().visitLdcInsn("Probe " + id);
}
};
- final IFrameInserter frameInserter = new IFrameInserter() {
-
- public void insertFrame() {
- actual.getVisitor().visitLdcInsn("Frame");
+ instrumenter = new MethodInstrumenter(actual.getVisitor(),
+ probeInserter);
+ frame = new IFrame() {
+ public void accept(MethodVisitor mv) {
+ mv.visitFrame(Opcodes.F_FULL, 0, null, 0, null);
}
};
- instrumenter = new MethodInstrumenter(actual.getVisitor(),
- probeInserter, frameInserter);
}
void sampleReturn() {
@@ -79,7 +81,7 @@ public class MethodInstrumenterTest {
@Test
public void testVisitJumpInsnWithProbe_GOTO() {
final Label label = new Label();
- instrumenter.visitJumpInsnWithProbe(Opcodes.GOTO, label, 3);
+ instrumenter.visitJumpInsnWithProbe(Opcodes.GOTO, label, 3, frame);
expectedVisitor.visitLdcInsn("Probe 3");
expectedVisitor.visitJumpInsn(Opcodes.GOTO, label);
@@ -174,14 +176,14 @@ public class MethodInstrumenterTest {
private void testVisitJumpInsnWithProbe(int opcodeOrig, int opcodeInstr) {
final Label label = new Label();
- instrumenter.visitJumpInsnWithProbe(opcodeOrig, label, 3);
+ instrumenter.visitJumpInsnWithProbe(opcodeOrig, label, 3, frame);
final Label l2 = new Label();
expectedVisitor.visitJumpInsn(opcodeInstr, l2);
expectedVisitor.visitLdcInsn("Probe 3");
expectedVisitor.visitJumpInsn(Opcodes.GOTO, label);
expectedVisitor.visitLabel(l2);
- expectedVisitor.visitLdcInsn("Frame");
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 0, null, 0, null);
assertEquals(expected, actual);
}
@@ -194,16 +196,16 @@ public class MethodInstrumenterTest {
LabelInfo.setProbeId(L0, 0);
LabelInfo.setProbeId(L1, 1);
instrumenter.visitTableSwitchInsnWithProbes(3, 5, L0, new Label[] { L1,
- L1, L2 });
+ L1, L2 }, frame);
expectedVisitor.visitTableSwitchInsn(3, 4, L0,
new Label[] { L1, L1, L2 });
expectedVisitor.visitLabel(L0);
- expectedVisitor.visitLdcInsn("Frame");
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 0, null, 0, null);
expectedVisitor.visitLdcInsn("Probe 0");
expectedVisitor.visitJumpInsn(Opcodes.GOTO, new Label());
expectedVisitor.visitLabel(L1);
- expectedVisitor.visitLdcInsn("Frame");
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 0, null, 0, null);
expectedVisitor.visitLdcInsn("Probe 1");
expectedVisitor.visitJumpInsn(Opcodes.GOTO, new Label());
@@ -218,16 +220,16 @@ public class MethodInstrumenterTest {
LabelInfo.setProbeId(L0, 0);
LabelInfo.setProbeId(L1, 1);
instrumenter.visitLookupSwitchInsnWithProbes(L0,
- new int[] { 10, 20, 30 }, new Label[] { L1, L1, L2 });
+ new int[] { 10, 20, 30 }, new Label[] { L1, L1, L2 }, frame);
expectedVisitor.visitLookupSwitchInsn(L0, new int[] { 10, 20, 30 },
new Label[] { L1, L1, L2 });
expectedVisitor.visitLabel(L0);
- expectedVisitor.visitLdcInsn("Frame");
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 0, null, 0, null);
expectedVisitor.visitLdcInsn("Probe 0");
expectedVisitor.visitJumpInsn(Opcodes.GOTO, new Label());
expectedVisitor.visitLabel(L1);
- expectedVisitor.visitLdcInsn("Frame");
+ expectedVisitor.visitFrame(Opcodes.F_FULL, 0, null, 0, null);
expectedVisitor.visitLdcInsn("Probe 1");
expectedVisitor.visitJumpInsn(Opcodes.GOTO, new Label());
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
index 0a55213d..fd5265e0 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
@@ -81,7 +81,7 @@ public class Analyzer {
coverageVisitor.visitCoverage(getCoverage());
}
};
- return new ClassProbesAdapter(analyzer);
+ return new ClassProbesAdapter(analyzer, false);
}
/**
diff --git a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
index c4d52669..9a5279cf 100644
--- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
@@ -60,7 +60,7 @@ public class Instrumenter {
private ClassVisitor createInstrumentingVisitor(final long classid,
final ClassVisitor cv) {
return new ClassProbesAdapter(new ClassInstrumenter(classid,
- accessGenerator, cv));
+ accessGenerator, cv), true);
}
/**
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 97ccaa3d..03e0c6d5 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
@@ -17,6 +17,7 @@ import java.util.List;
import org.jacoco.core.analysis.ICounter;
import org.jacoco.core.analysis.IMethodCoverage;
import org.jacoco.core.analysis.ISourceNode;
+import org.jacoco.core.internal.flow.IFrame;
import org.jacoco.core.internal.flow.Instruction;
import org.jacoco.core.internal.flow.LabelInfo;
import org.jacoco.core.internal.flow.MethodProbesVisitor;
@@ -212,7 +213,7 @@ public class MethodAnalyzer extends MethodProbesVisitor {
@Override
public void visitJumpInsnWithProbe(final int opcode, final Label label,
- final int probeId) {
+ final int probeId, final IFrame frame) {
visitInsn();
addProbe(probeId);
}
@@ -225,13 +226,13 @@ public class MethodAnalyzer extends MethodProbesVisitor {
@Override
public void visitTableSwitchInsnWithProbes(final int min, final int max,
- final Label dflt, final Label[] labels) {
+ final Label dflt, final Label[] labels, final IFrame frame) {
visitSwitchInsnWithProbes(dflt, labels);
}
@Override
public void visitLookupSwitchInsnWithProbes(final Label dflt,
- final int[] keys, final Label[] labels) {
+ final int[] keys, final Label[] labels, final IFrame frame) {
visitSwitchInsnWithProbes(dflt, labels);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
index 2fe3e3d7..5089b24c 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
@@ -16,6 +16,7 @@ import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.AnalyzerAdapter;
/**
* A {@link org.objectweb.asm.ClassVisitor} that calculates probes for every
@@ -36,7 +37,7 @@ public class ClassProbesAdapter extends ClassVisitor implements
@Override
public void visitJumpInsnWithProbe(final int opcode,
- final Label label, final int probeId) {
+ final Label label, final int probeId, final IFrame frame) {
// nothing to do
}
@@ -47,13 +48,14 @@ public class ClassProbesAdapter extends ClassVisitor implements
@Override
public void visitTableSwitchInsnWithProbes(final int min,
- final int max, final Label dflt, final Label[] labels) {
+ final int max, final Label dflt, final Label[] labels,
+ final IFrame frame) {
// nothing to do
}
@Override
public void visitLookupSwitchInsnWithProbes(final Label dflt,
- final int[] keys, final Label[] labels) {
+ final int[] keys, final Label[] labels, final IFrame frame) {
// nothing to do
}
}
@@ -70,8 +72,12 @@ public class ClassProbesAdapter extends ClassVisitor implements
private final ClassProbesVisitor cv;
+ private final boolean trackFrames;
+
private int counter = 0;
+ private String name;
+
private boolean interfaceType;
/**
@@ -79,17 +85,22 @@ public class ClassProbesAdapter extends ClassVisitor implements
*
* @param cv
* instance to delegate to
+ * @param trackFrames
+ * if <code>true</code> stackmap frames are tracked and provided
*/
- public ClassProbesAdapter(final ClassProbesVisitor cv) {
+ public ClassProbesAdapter(final ClassProbesVisitor cv,
+ final boolean trackFrames) {
super(JaCoCo.ASM_API_VERSION, cv);
this.cv = cv;
+ this.trackFrames = trackFrames;
}
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
- interfaceType = (access & Opcodes.ACC_INTERFACE) != 0;
+ this.name = name;
+ this.interfaceType = (access & Opcodes.ACC_INTERFACE) != 0;
super.visit(version, access, name, signature, superName, interfaces);
}
@@ -122,8 +133,17 @@ public class ClassProbesAdapter extends ClassVisitor implements
instructions.accept(adapter);
cv.visitTotalProbeCount(probeCounter.count);
}
- this.accept(new MethodProbesAdapter(methodProbes,
- ClassProbesAdapter.this));
+ final MethodProbesAdapter probesAdapter = new MethodProbesAdapter(
+ methodProbes, ClassProbesAdapter.this);
+ if (trackFrames) {
+ final AnalyzerAdapter analyzer = new AnalyzerAdapter(
+ ClassProbesAdapter.this.name, access, name, desc,
+ probesAdapter);
+ probesAdapter.setAnalyzer(analyzer);
+ this.accept(analyzer);
+ } else {
+ this.accept(probesAdapter);
+ }
}
};
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java
new file mode 100644
index 00000000..c3acf5d8
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc R. Hoffmann - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.jacoco.core.internal.flow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.AnalyzerAdapter;
+
+/**
+ * IFrame implementation which creates snapshots from an {@link AnalyzerAdapter}
+ */
+class FrameSnapshot implements IFrame {
+
+ private static final FrameSnapshot NOP = new FrameSnapshot(null, null);
+
+ private final Object[] locals;
+ private final Object[] stack;
+
+ private FrameSnapshot(final Object[] locals, final Object[] stack) {
+ this.locals = locals;
+ this.stack = stack;
+ }
+
+ /**
+ * Create a IFrame instance based on the given analyzer.
+ *
+ * @param analyzer
+ * analyzer instance or <code>null</code>
+ * @param popCount
+ * number of items to remove from the operand stack
+ * @return IFrame instance. In case the analyzer is <code>null</code> or
+ * does not contain stackmap information a "NOP" IFrame is returned.
+ */
+ static IFrame create(final AnalyzerAdapter analyzer, final int popCount) {
+ if (analyzer == null || analyzer.locals == null) {
+ return NOP;
+ }
+ @SuppressWarnings("unchecked")
+ final List<Object> locals = analyzer.locals, stack = analyzer.stack;
+ return new FrameSnapshot(reduce(locals, 0), reduce(stack, popCount));
+ }
+
+ /**
+ * Reduce double word types into a single slot as required
+ * {@link MethodVisitor#visitFrame(int, int, Object[], int, Object[])}
+ * method.
+ */
+ private static Object[] reduce(final List<Object> source, final int popCount) {
+ final List<Object> copy = new ArrayList<Object>(source);
+ final int size = source.size() - popCount;
+ copy.subList(size, source.size()).clear();
+ for (int i = size; --i >= 0;) {
+ final Object type = source.get(i);
+ if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
+ copy.remove(i + 1);
+ }
+ }
+ return copy.toArray();
+ }
+
+ // === IFrame implementation ===
+
+ public void accept(final MethodVisitor mv) {
+ if (locals != null) {
+ mv.visitFrame(Opcodes.F_NEW, locals.length, locals, stack.length,
+ stack);
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/IFrameInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java
index 5bd0b4a8..31042678 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/IFrameInserter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java
@@ -9,26 +9,21 @@
* Marc R. Hoffmann - initial API and implementation
*
*******************************************************************************/
-package org.jacoco.core.internal.instr;
+package org.jacoco.core.internal.flow;
+
+import org.objectweb.asm.MethodVisitor;
/**
- * Internal interface for insertion of additional stackmap frame in the
- * instruction sequence of a method.
+ * Representation of the current stackmap frame content.
*/
-interface IFrameInserter {
-
- /**
- * Empty implementation.
- */
- static final IFrameInserter NOP = new IFrameInserter() {
- public void insertFrame() {
- }
- };
+public interface IFrame {
/**
- * Inserts an additional frame reflecting the current locals and stack
- * types.
+ * Emits a frame event with the current content to the given visitor.
+ *
+ * @param mv
+ * method visitor to emit frame event to
*/
- void insertFrame();
+ void accept(final MethodVisitor mv);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java
index 5d681445..dde89c07 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java
@@ -15,6 +15,7 @@ import org.jacoco.core.JaCoCo;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.AnalyzerAdapter;
/**
* Adapter that creates additional visitor events for probes to be inserted into
@@ -26,6 +27,8 @@ public final class MethodProbesAdapter extends MethodVisitor {
private final IProbeIdGenerator idGenerator;
+ private AnalyzerAdapter analyzer;
+
/**
* Create a new adapter instance.
*
@@ -41,6 +44,17 @@ public final class MethodProbesAdapter extends MethodVisitor {
this.idGenerator = idGenerator;
}
+ /**
+ * If an analyzer is set {@link IFrame} handles are calculated and emitted
+ * to the probes methods.
+ *
+ * @param analyzer
+ * optional analyzer to set
+ */
+ public void setAnalyzer(final AnalyzerAdapter analyzer) {
+ this.analyzer = analyzer;
+ }
+
@Override
public void visitLabel(final Label label) {
if (LabelInfo.isMultiTarget(label) && LabelInfo.isSuccessor(label)) {
@@ -71,17 +85,36 @@ public final class MethodProbesAdapter extends MethodVisitor {
public void visitJumpInsn(final int opcode, final Label label) {
if (LabelInfo.isMultiTarget(label)) {
probesVisitor.visitJumpInsnWithProbe(opcode, label,
- idGenerator.nextId());
+ idGenerator.nextId(), frame(jumpPopCount(opcode)));
} else {
probesVisitor.visitJumpInsn(opcode, label);
}
}
+ private int jumpPopCount(final int opcode) {
+ switch (opcode) {
+ case Opcodes.GOTO:
+ return 0;
+ case Opcodes.IFEQ:
+ case Opcodes.IFNE:
+ case Opcodes.IFLT:
+ case Opcodes.IFGE:
+ case Opcodes.IFGT:
+ case Opcodes.IFLE:
+ case Opcodes.IFNULL:
+ case Opcodes.IFNONNULL:
+ return 1;
+ default: // IF_CMPxx and IF_ACMPxx
+ return 2;
+ }
+ }
+
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
if (markLabels(dflt, labels)) {
- probesVisitor.visitLookupSwitchInsnWithProbes(dflt, keys, labels);
+ probesVisitor.visitLookupSwitchInsnWithProbes(dflt, keys, labels,
+ frame(1));
} else {
probesVisitor.visitLookupSwitchInsn(dflt, keys, labels);
}
@@ -91,8 +124,8 @@ public final class MethodProbesAdapter extends MethodVisitor {
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
if (markLabels(dflt, labels)) {
- probesVisitor
- .visitTableSwitchInsnWithProbes(min, max, dflt, labels);
+ probesVisitor.visitTableSwitchInsnWithProbes(min, max, dflt,
+ labels, frame(1));
} else {
probesVisitor.visitTableSwitchInsn(min, max, dflt, labels);
}
@@ -107,7 +140,7 @@ public final class MethodProbesAdapter extends MethodVisitor {
}
LabelInfo.setDone(dflt);
for (final Label l : labels) {
- if (!LabelInfo.isDone(l) && LabelInfo.isMultiTarget(l)) {
+ if (LabelInfo.isMultiTarget(l) && !LabelInfo.isDone(l)) {
LabelInfo.setProbeId(l, idGenerator.nextId());
probe = true;
}
@@ -116,4 +149,8 @@ public final class MethodProbesAdapter extends MethodVisitor {
return probe;
}
+ private IFrame frame(final int popCount) {
+ return FrameSnapshot.create(analyzer, popCount);
+ }
+
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java
index fd4b281a..609279ba 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java
@@ -63,10 +63,14 @@ public abstract class MethodProbesVisitor extends MethodVisitor {
* instruction may jump.
* @param probeId
* id of the probe
+ * @param frame
+ * stackmap frame status after the execution of the jump
+ * instruction. The instance is only valid with the call of this
+ * method.
* @see MethodVisitor#visitJumpInsn(int, Label)
*/
public abstract void visitJumpInsnWithProbe(int opcode, Label label,
- int probeId);
+ int probeId, IFrame frame);
/**
* Visits a zero operand instruction with a probe. This event is used only
@@ -100,10 +104,14 @@ public abstract class MethodProbesVisitor extends MethodVisitor {
* beginnings of the handler blocks. <code>labels[i]</code> is
* the beginning of the handler block for the
* <code>min + i</code> key.
+ * @param frame
+ * stackmap frame status after the execution of the switch
+ * instruction. The instance is only valid with the call of this
+ * method.
* @see MethodVisitor#visitTableSwitchInsn(int, int, Label, Label[])
*/
public abstract void visitTableSwitchInsnWithProbes(int min, int max,
- Label dflt, Label[] labels);
+ Label dflt, Label[] labels, IFrame frame);
/**
* Visits a LOOKUPSWITCH instruction with optional probes for each target
@@ -120,9 +128,13 @@ public abstract class MethodProbesVisitor extends MethodVisitor {
* beginnings of the handler blocks. <code>labels[i]</code> is
* the beginning of the handler block for the
* <code>keys[i]</code> key.
+ * @param frame
+ * stackmap frame status after the execution of the switch
+ * instruction. The instance is only valid with the call of this
+ * method.
* @see MethodVisitor#visitLookupSwitchInsn(Label, int[], Label[])
*/
public abstract void visitLookupSwitchInsnWithProbes(Label dflt,
- int[] keys, Label[] labels);
+ int[] keys, Label[] labels, IFrame frame);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
index d9fb76ea..8ea1926f 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
@@ -95,15 +95,8 @@ public class ClassInstrumenter extends ClassProbesVisitor {
final MethodVisitor frameEliminator = new DuplicateFrameEliminator(mv);
final ProbeInserter probeVariableInserter = new ProbeInserter(access,
desc, frameEliminator, probeArrayStrategy);
- if (withFrames) {
- final FrameTracker frameTracker = new FrameTracker(className,
- access, name, desc, probeVariableInserter);
- return new MethodInstrumenter(frameTracker, probeVariableInserter,
- frameTracker);
- } else {
- return new MethodInstrumenter(probeVariableInserter,
- probeVariableInserter, IFrameInserter.NOP);
- }
+ return new MethodInstrumenter(probeVariableInserter,
+ probeVariableInserter);
}
@Override
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/FrameTracker.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/FrameTracker.java
deleted file mode 100644
index ced09d26..00000000
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/FrameTracker.java
+++ /dev/null
@@ -1,737 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2013 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.instr;
-
-import org.jacoco.core.JaCoCo;
-import org.objectweb.asm.Handle;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-
-/**
- * This method adapter tracks the state of the local variable and stack types.
- * With insertFrame() additional frames can then be added. The adapter is only
- * intended to be used with class file versions >= {@link Opcodes#V1_6}.
- */
-class FrameTracker extends MethodVisitor implements IFrameInserter {
-
- private final String owner;
-
- private Object[] local;
- private int localSize;
- private Object[] stack;
- private int stackSize;
-
- public FrameTracker(final String owner, final int access,
- final String name, final String desc, final MethodVisitor mv) {
- super(JaCoCo.ASM_API_VERSION, mv);
- this.owner = owner;
- local = new Object[8];
- localSize = 0;
- stack = new Object[8];
- stackSize = 0;
-
- if ((access & Opcodes.ACC_STATIC) == 0) {
- if ("<init>".equals(name)) {
- set(localSize, Opcodes.UNINITIALIZED_THIS);
- } else {
- set(localSize, owner);
- }
- }
- for (final Type t : Type.getArgumentTypes(desc)) {
- set(localSize, t);
- }
-
- }
-
- public void insertFrame() {
- // Reduced types do not need more space than expanded types:
- final Object[] local = new Object[this.localSize];
- final Object[] stack = new Object[this.stackSize];
- final int localSize = reduce(this.local, this.localSize, local);
- final int stackSize = reduce(this.stack, this.stackSize, stack);
- mv.visitFrame(Opcodes.F_NEW, localSize, local, stackSize, stack);
- }
-
- @Override
- public void visitFrame(final int type, final int nLocal,
- final Object[] local, final int nStack, final Object[] stack) {
-
- if (type != Opcodes.F_NEW) {
- throw new IllegalArgumentException(
- "ClassReader.accept() should be called with EXPAND_FRAMES flag");
- }
-
- // expanded types need at most twice the size
- this.local = ensureSize(this.local, nLocal * 2);
- this.stack = ensureSize(this.stack, nStack * 2);
- this.localSize = expand(local, nLocal, this.local);
- this.stackSize = expand(stack, nStack, this.stack);
-
- mv.visitFrame(type, nLocal, local, nStack, stack);
- }
-
- @Override
- public void visitInsn(final int opcode) {
- final Object t1, t2, t3, t4;
- switch (opcode) {
- case Opcodes.NOP:
- case Opcodes.RETURN:
- break;
- case Opcodes.ARETURN:
- case Opcodes.ATHROW:
- case Opcodes.FRETURN:
- case Opcodes.IRETURN:
- case Opcodes.MONITORENTER:
- case Opcodes.MONITOREXIT:
- case Opcodes.POP:
- pop(1);
- break;
- case Opcodes.DRETURN:
- case Opcodes.LRETURN:
- case Opcodes.POP2:
- pop(2);
- break;
- case Opcodes.AASTORE:
- case Opcodes.BASTORE:
- case Opcodes.CASTORE:
- case Opcodes.FASTORE:
- case Opcodes.IASTORE:
- case Opcodes.SASTORE:
- pop(3);
- break;
- case Opcodes.LASTORE:
- case Opcodes.DASTORE:
- pop(4);
- break;
- case Opcodes.ICONST_M1:
- case Opcodes.ICONST_0:
- case Opcodes.ICONST_1:
- case Opcodes.ICONST_2:
- case Opcodes.ICONST_3:
- case Opcodes.ICONST_4:
- case Opcodes.ICONST_5:
- push(Opcodes.INTEGER);
- break;
- case Opcodes.ARRAYLENGTH:
- case Opcodes.F2I:
- case Opcodes.I2B:
- case Opcodes.I2C:
- case Opcodes.I2S:
- case Opcodes.INEG:
- pop(1);
- push(Opcodes.INTEGER);
- break;
- case Opcodes.BALOAD:
- case Opcodes.CALOAD:
- case Opcodes.D2I:
- case Opcodes.FCMPG:
- case Opcodes.FCMPL:
- case Opcodes.IADD:
- case Opcodes.IALOAD:
- case Opcodes.IAND:
- case Opcodes.IDIV:
- case Opcodes.IMUL:
- case Opcodes.IOR:
- case Opcodes.IREM:
- case Opcodes.ISHL:
- case Opcodes.ISHR:
- case Opcodes.ISUB:
- case Opcodes.IUSHR:
- case Opcodes.IXOR:
- case Opcodes.L2I:
- case Opcodes.SALOAD:
- pop(2);
- push(Opcodes.INTEGER);
- break;
- case Opcodes.DCMPG:
- case Opcodes.DCMPL:
- case Opcodes.LCMP:
- pop(4);
- push(Opcodes.INTEGER);
- break;
- case Opcodes.FCONST_0:
- case Opcodes.FCONST_1:
- case Opcodes.FCONST_2:
- push(Opcodes.FLOAT);
- break;
- case Opcodes.FNEG:
- case Opcodes.I2F:
- pop(1);
- push(Opcodes.FLOAT);
- break;
- case Opcodes.D2F:
- case Opcodes.FADD:
- case Opcodes.FALOAD:
- case Opcodes.FDIV:
- case Opcodes.FMUL:
- case Opcodes.FREM:
- case Opcodes.FSUB:
- case Opcodes.L2F:
- pop(2);
- push(Opcodes.FLOAT);
- break;
- case Opcodes.LCONST_0:
- case Opcodes.LCONST_1:
- push(Opcodes.LONG);
- push(Opcodes.TOP);
- break;
- case Opcodes.F2L:
- case Opcodes.I2L:
- pop(1);
- push(Opcodes.LONG);
- push(Opcodes.TOP);
- break;
- case Opcodes.D2L:
- case Opcodes.LALOAD:
- case Opcodes.LNEG:
- pop(2);
- push(Opcodes.LONG);
- push(Opcodes.TOP);
- break;
- case Opcodes.LSHL:
- case Opcodes.LSHR:
- case Opcodes.LUSHR:
- pop(3);
- push(Opcodes.LONG);
- push(Opcodes.TOP);
- break;
- case Opcodes.LADD:
- case Opcodes.LAND:
- case Opcodes.LDIV:
- case Opcodes.LMUL:
- case Opcodes.LOR:
- case Opcodes.LREM:
- case Opcodes.LSUB:
- case Opcodes.LXOR:
- pop(4);
- push(Opcodes.LONG);
- push(Opcodes.TOP);
- break;
- case Opcodes.DCONST_0:
- case Opcodes.DCONST_1:
- push(Opcodes.DOUBLE);
- push(Opcodes.TOP);
- break;
- case Opcodes.F2D:
- case Opcodes.I2D:
- pop(1);
- push(Opcodes.DOUBLE);
- push(Opcodes.TOP);
- break;
- case Opcodes.DALOAD:
- case Opcodes.DNEG:
- case Opcodes.L2D:
- pop(2);
- push(Opcodes.DOUBLE);
- push(Opcodes.TOP);
- break;
- case Opcodes.DADD:
- case Opcodes.DDIV:
- case Opcodes.DMUL:
- case Opcodes.DREM:
- case Opcodes.DSUB:
- pop(4);
- push(Opcodes.DOUBLE);
- push(Opcodes.TOP);
- break;
- case Opcodes.ACONST_NULL:
- push(Opcodes.NULL);
- break;
- case Opcodes.AALOAD:
- pop(1);
- t1 = pop();
- push(Type.getType(((String) t1).substring(1)));
- break;
- case Opcodes.DUP:
- t1 = pop();
- push(t1);
- push(t1);
- break;
- case Opcodes.DUP_X1:
- t1 = pop();
- t2 = pop();
- push(t1);
- push(t2);
- push(t1);
- break;
- case Opcodes.DUP_X2:
- t1 = pop();
- t2 = pop();
- t3 = pop();
- push(t1);
- push(t3);
- push(t2);
- push(t1);
- break;
- case Opcodes.DUP2:
- t1 = pop();
- t2 = pop();
- push(t2);
- push(t1);
- push(t2);
- push(t1);
- break;
- case Opcodes.DUP2_X1:
- t1 = pop();
- t2 = pop();
- t3 = pop();
- push(t2);
- push(t1);
- push(t3);
- push(t2);
- push(t1);
- break;
- case Opcodes.DUP2_X2:
- t1 = pop();
- t2 = pop();
- t3 = pop();
- t4 = pop();
- push(t2);
- push(t1);
- push(t4);
- push(t3);
- push(t2);
- push(t1);
- break;
- case Opcodes.SWAP:
- t1 = pop();
- t2 = pop();
- push(t1);
- push(t2);
- break;
- default:
- throw new IllegalArgumentException();
- }
- mv.visitInsn(opcode);
- }
-
- @Override
- public void visitIntInsn(final int opcode, final int operand) {
- switch (opcode) {
- case Opcodes.BIPUSH:
- case Opcodes.SIPUSH:
- push(Opcodes.INTEGER);
- break;
- case Opcodes.NEWARRAY:
- pop(1);
- switch (operand) {
- case Opcodes.T_BOOLEAN:
- push("[Z");
- break;
- case Opcodes.T_CHAR:
- push("[C");
- break;
- case Opcodes.T_FLOAT:
- push("[F");
- break;
- case Opcodes.T_DOUBLE:
- push("[D");
- break;
- case Opcodes.T_BYTE:
- push("[B");
- break;
- case Opcodes.T_SHORT:
- push("[S");
- break;
- case Opcodes.T_INT:
- push("[I");
- break;
- case Opcodes.T_LONG:
- push("[J");
- break;
- default:
- throw new IllegalArgumentException();
- }
- break;
- default:
- throw new IllegalArgumentException();
- }
- mv.visitIntInsn(opcode, operand);
- }
-
- @Override
- public void visitVarInsn(final int opcode, final int var) {
- final Object t;
- switch (opcode) {
- case Opcodes.ALOAD:
- push(get(var));
- break;
- case Opcodes.ILOAD:
- push(Opcodes.INTEGER);
- break;
- case Opcodes.FLOAD:
- push(Opcodes.FLOAT);
- break;
- case Opcodes.LLOAD:
- push(Opcodes.LONG);
- push(Opcodes.TOP);
- break;
- case Opcodes.DLOAD:
- push(Opcodes.DOUBLE);
- push(Opcodes.TOP);
- break;
- case Opcodes.ASTORE:
- case Opcodes.ISTORE:
- case Opcodes.FSTORE:
- t = pop();
- set(var, t);
- break;
- case Opcodes.LSTORE:
- case Opcodes.DSTORE:
- pop(1);
- t = pop();
- set(var, t);
- set(var + 1, Opcodes.TOP);
- break;
- default:
- throw new IllegalArgumentException();
- }
- mv.visitVarInsn(opcode, var);
- }
-
- @Override
- public void visitTypeInsn(final int opcode, final String type) {
- switch (opcode) {
- case Opcodes.NEW:
- final Label label = new Label();
- mv.visitLabel(label);
- push(label);
- break;
- case Opcodes.ANEWARRAY:
- pop(1);
- push('[' + Type.getObjectType(type).getDescriptor());
- break;
- case Opcodes.CHECKCAST:
- pop(1);
- push(type);
- break;
- case Opcodes.INSTANCEOF:
- pop(1);
- push(Opcodes.INTEGER);
- break;
- default:
- throw new IllegalArgumentException();
- }
- mv.visitTypeInsn(opcode, type);
- }
-
- @Override
- public void visitFieldInsn(final int opcode, final String owner,
- final String name, final String desc) {
- final Type t = Type.getType(desc);
- switch (opcode) {
- case Opcodes.PUTSTATIC:
- pop(t);
- break;
- case Opcodes.PUTFIELD:
- pop(t);
- pop(1);
- break;
- case Opcodes.GETSTATIC:
- push(t);
- break;
- case Opcodes.GETFIELD:
- pop(1);
- push(t);
- break;
- default:
- throw new IllegalArgumentException();
- }
- mv.visitFieldInsn(opcode, owner, name, desc);
- }
-
- @Override
- public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
- for (final Type t : Type.getArgumentTypes(desc)) {
- pop(t);
- }
- if (opcode != Opcodes.INVOKESTATIC) {
- final Object target = pop();
- if (target == Opcodes.UNINITIALIZED_THIS) {
- replace(Opcodes.UNINITIALIZED_THIS, this.owner);
- } else if (target instanceof Label) {
- replace(target, owner);
- }
- }
- push(Type.getReturnType(desc));
-
- mv.visitMethodInsn(opcode, owner, name, desc);
- }
-
- @Override
- public void visitInvokeDynamicInsn(final String name, final String desc,
- final Handle bsm, final Object... bsmArgs) {
- for (final Type t : Type.getArgumentTypes(desc)) {
- pop(t);
- }
- push(Type.getReturnType(desc));
-
- mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
- }
-
- @Override
- public void visitLdcInsn(final Object cst) {
- if (cst instanceof Integer) {
- push(Opcodes.INTEGER);
- } else if (cst instanceof Float) {
- push(Opcodes.FLOAT);
- } else if (cst instanceof Long) {
- push(Opcodes.LONG);
- push(Opcodes.TOP);
- } else if (cst instanceof Double) {
- push(Opcodes.DOUBLE);
- push(Opcodes.TOP);
- } else if (cst instanceof String) {
- push("java/lang/String");
- } else if (cst instanceof Type) {
- push("java/lang/Class");
- } else {
- throw new IllegalArgumentException();
- }
- mv.visitLdcInsn(cst);
- }
-
- @Override
- public void visitJumpInsn(final int opcode, final Label label) {
- switch (opcode) {
- case Opcodes.GOTO:
- break;
- case Opcodes.IFEQ:
- case Opcodes.IFNE:
- case Opcodes.IFLT:
- case Opcodes.IFGE:
- case Opcodes.IFGT:
- case Opcodes.IFLE:
- case Opcodes.IFNULL:
- case Opcodes.IFNONNULL:
- pop(1);
- break;
- case Opcodes.IF_ICMPEQ:
- case Opcodes.IF_ICMPNE:
- case Opcodes.IF_ICMPLT:
- case Opcodes.IF_ICMPGE:
- case Opcodes.IF_ICMPGT:
- case Opcodes.IF_ICMPLE:
- case Opcodes.IF_ACMPEQ:
- case Opcodes.IF_ACMPNE:
- pop(2);
- break;
- default:
- throw new IllegalArgumentException();
- }
- mv.visitJumpInsn(opcode, label);
- }
-
- @Override
- public void visitIincInsn(final int var, final int increment) {
- set(var, Opcodes.INTEGER);
- mv.visitIincInsn(var, increment);
- }
-
- @Override
- public void visitTableSwitchInsn(final int min, final int max,
- final Label dflt, final Label... labels) {
- pop(1);
- mv.visitTableSwitchInsn(min, max, dflt, labels);
- }
-
- @Override
- public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
- final Label[] labels) {
- pop(1);
- mv.visitLookupSwitchInsn(dflt, keys, labels);
- }
-
- @Override
- public void visitMultiANewArrayInsn(final String desc, final int dims) {
- pop(dims);
- push(desc);
- mv.visitMultiANewArrayInsn(desc, dims);
- }
-
- private void push(final Object type) {
- stack = ensureSize(stack, stackSize + 1);
- stack[stackSize] = type;
- stackSize++;
- }
-
- private void push(final Type type) {
- switch (type.getSort()) {
- case Type.VOID:
- break;
- case Type.BOOLEAN:
- case Type.BYTE:
- case Type.CHAR:
- case Type.INT:
- case Type.SHORT:
- push(Opcodes.INTEGER);
- break;
- case Type.FLOAT:
- push(Opcodes.FLOAT);
- break;
- case Type.LONG:
- push(Opcodes.LONG);
- push(Opcodes.TOP);
- break;
- case Type.DOUBLE:
- push(Opcodes.DOUBLE);
- push(Opcodes.TOP);
- break;
- case Type.ARRAY:
- case Type.OBJECT:
- push(type.getInternalName());
- break;
- default:
- throw new AssertionError(type);
- }
- }
-
- private Object pop() {
- stackSize--;
- assertValidFrames(stackSize);
- return stack[stackSize];
- }
-
- private void pop(final int count) {
- stackSize -= count;
- assertValidFrames(stackSize);
- }
-
- private void assertValidFrames(final int stackSize) {
- if (stackSize < 0) {
- throw new IllegalStateException(
- "Missing or invalid stackmap frames.");
- }
- }
-
- private void pop(final Type type) {
- pop(type.getSize());
- }
-
- private void set(final int pos, final Object type) {
- local = ensureSize(local, pos + 1);
- // fill gaps:
- for (int i = localSize; i < pos; i++) {
- local[i] = Opcodes.TOP;
- }
- localSize = Math.max(localSize, pos + 1);
- local[pos] = type;
- }
-
- private void set(final int pos, final Type type) {
- switch (type.getSort()) {
- case Type.BOOLEAN:
- case Type.BYTE:
- case Type.CHAR:
- case Type.INT:
- case Type.SHORT:
- set(pos, Opcodes.INTEGER);
- break;
- case Type.FLOAT:
- set(pos, Opcodes.FLOAT);
- break;
- case Type.LONG:
- set(pos, Opcodes.LONG);
- set(pos + 1, Opcodes.TOP);
- break;
- case Type.DOUBLE:
- set(pos, Opcodes.DOUBLE);
- set(pos + 1, Opcodes.TOP);
- break;
- case Type.ARRAY:
- case Type.OBJECT:
- set(pos, type.getInternalName());
- break;
- default:
- throw new AssertionError(type);
- }
- }
-
- private Object get(final int pos) {
- if (localSize <= pos) {
- throw new IllegalStateException(
- "Missing or invalid stackmap frames.");
- }
- return local[pos];
- }
-
- private Object[] ensureSize(final Object[] array, final int size) {
- if (array.length >= size) {
- return array;
- }
- int newLength = array.length;
- while (newLength < size) {
- newLength *= 2;
- }
- final Object[] newArray = new Object[newLength];
- System.arraycopy(array, 0, newArray, 0, array.length);
- return newArray;
- }
-
- /**
- * Expand double word types into two slots.
- */
- private int expand(final Object[] source, final int size,
- final Object[] target) {
- int targetIdx = 0;
- for (int sourceIdx = 0; sourceIdx < size; sourceIdx++) {
- final Object type = source[sourceIdx];
- target[targetIdx++] = type;
- if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
- target[targetIdx++] = Opcodes.TOP;
- }
- }
- return targetIdx;
- }
-
- /**
- * Reduce double word types into a single slot.
- */
- private int reduce(final Object[] source, final int size,
- final Object[] target) {
- int targetIdx = 0;
- for (int sourceIdx = 0; sourceIdx < size; sourceIdx++) {
- final Object type = source[sourceIdx];
- target[targetIdx++] = type;
- if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
- sourceIdx++;
- }
- }
- return targetIdx;
- }
-
- /**
- * Replaces a type in the locals and on the stack. This is used for
- * uninitialized objects.
- *
- * @param oldtype
- * type to replace
- * @param newtype
- * replacement type
- */
- private void replace(final Object oldtype, final Object newtype) {
- for (int i = 0; i < localSize; i++) {
- if (oldtype.equals(local[i])) {
- local[i] = newtype;
- }
- }
- for (int i = 0; i < stackSize; i++) {
- if (oldtype.equals(stack[i])) {
- stack[i] = newtype;
- }
- }
- }
-
-}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java
index 808362d1..15b88140 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java
@@ -11,8 +11,9 @@
*******************************************************************************/
package org.jacoco.core.internal.instr;
-import org.jacoco.core.internal.flow.MethodProbesVisitor;
+import org.jacoco.core.internal.flow.IFrame;
import org.jacoco.core.internal.flow.LabelInfo;
+import org.jacoco.core.internal.flow.MethodProbesVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -24,7 +25,6 @@ import org.objectweb.asm.Opcodes;
class MethodInstrumenter extends MethodProbesVisitor {
private final IProbeInserter probeInserter;
- private final IFrameInserter frameInserter;
/**
* Create a new instrumenter instance for the given method.
@@ -33,15 +33,11 @@ class MethodInstrumenter extends MethodProbesVisitor {
* next method visitor in the chain
* @param probeInserter
* call-back to insert probes where required
- * @param frameInserter
- * call-back to insert additional frames where required
*/
public MethodInstrumenter(final MethodVisitor mv,
- final IProbeInserter probeInserter,
- final IFrameInserter frameInserter) {
+ final IProbeInserter probeInserter) {
super(mv);
this.probeInserter = probeInserter;
- this.frameInserter = frameInserter;
}
// === IMethodProbesVisitor ===
@@ -59,7 +55,7 @@ class MethodInstrumenter extends MethodProbesVisitor {
@Override
public void visitJumpInsnWithProbe(final int opcode, final Label label,
- final int probeId) {
+ final int probeId, final IFrame frame) {
if (opcode == Opcodes.GOTO) {
probeInserter.insertProbe(probeId);
mv.visitJumpInsn(Opcodes.GOTO, label);
@@ -69,7 +65,7 @@ class MethodInstrumenter extends MethodProbesVisitor {
probeInserter.insertProbe(probeId);
mv.visitJumpInsn(Opcodes.GOTO, label);
mv.visitLabel(intermediate);
- frameInserter.insertFrame();
+ frame.accept(mv);
}
}
@@ -113,7 +109,7 @@ class MethodInstrumenter extends MethodProbesVisitor {
@Override
public void visitTableSwitchInsnWithProbes(final int min, final int max,
- final Label dflt, final Label[] labels) {
+ final Label dflt, final Label[] labels, final IFrame frame) {
// 1. Calculate intermediate labels:
LabelInfo.resetDone(dflt);
LabelInfo.resetDone(labels);
@@ -122,12 +118,12 @@ class MethodInstrumenter extends MethodProbesVisitor {
mv.visitTableSwitchInsn(min, max, newDflt, newLabels);
// 2. Insert probes:
- insertIntermediateProbes(dflt, labels);
+ insertIntermediateProbes(dflt, labels, frame);
}
@Override
public void visitLookupSwitchInsnWithProbes(final Label dflt,
- final int[] keys, final Label[] labels) {
+ final int[] keys, final Label[] labels, final IFrame frame) {
// 1. Calculate intermediate labels:
LabelInfo.resetDone(dflt);
LabelInfo.resetDone(labels);
@@ -136,7 +132,7 @@ class MethodInstrumenter extends MethodProbesVisitor {
mv.visitLookupSwitchInsn(newDflt, keys, newLabels);
// 2. Insert probes:
- insertIntermediateProbes(dflt, labels);
+ insertIntermediateProbes(dflt, labels, frame);
}
private Label[] createIntermediates(final Label[] labels) {
@@ -163,23 +159,24 @@ class MethodInstrumenter extends MethodProbesVisitor {
return intermediate;
}
- private void insertIntermediateProbe(final Label label) {
+ private void insertIntermediateProbe(final Label label, final IFrame frame) {
final int probeId = LabelInfo.getProbeId(label);
if (probeId != LabelInfo.NO_PROBE && !LabelInfo.isDone(label)) {
mv.visitLabel(LabelInfo.getIntermediateLabel(label));
- frameInserter.insertFrame();
+ frame.accept(mv);
probeInserter.insertProbe(probeId);
mv.visitJumpInsn(Opcodes.GOTO, label);
LabelInfo.setDone(label);
}
}
- private void insertIntermediateProbes(final Label dflt, final Label[] labels) {
+ private void insertIntermediateProbes(final Label dflt,
+ final Label[] labels, final IFrame frame) {
LabelInfo.resetDone(dflt);
LabelInfo.resetDone(labels);
- insertIntermediateProbe(dflt);
+ insertIntermediateProbe(dflt, frame);
for (final Label l : labels) {
- insertIntermediateProbe(l);
+ insertIntermediateProbe(l, frame);
}
}