Don't insert stackmap frames for class files before version 1.6.
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java
new file mode 100644
index 0000000..2a0bb5c
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 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.test.validation;
+
+import static junit.framework.Assert.assertEquals;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_SUPER;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static org.objectweb.asm.Opcodes.RETURN;
+import static org.objectweb.asm.Opcodes.V1_1;
+import static org.objectweb.asm.Opcodes.V1_2;
+import static org.objectweb.asm.Opcodes.V1_3;
+import static org.objectweb.asm.Opcodes.V1_4;
+import static org.objectweb.asm.Opcodes.V1_5;
+import static org.objectweb.asm.Opcodes.V1_6;
+import static org.objectweb.asm.Opcodes.V1_7;
+
+import org.jacoco.core.instr.Instrumenter;
+import org.jacoco.core.runtime.IRuntime;
+import org.jacoco.core.runtime.SystemPropertiesRuntime;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Test class inserted stackmap frames for different class file versions.
+ */
+public class ClassFileVersionsTest {
+
+ @Test
+ public void test_1_1() {
+ testVersion(V1_1, false);
+ }
+
+ @Test
+ public void test_1_2() {
+ testVersion(V1_2, false);
+ }
+
+ @Test
+ public void test_1_3() {
+ testVersion(V1_3, false);
+ }
+
+ @Test
+ public void test_1_4() {
+ testVersion(V1_4, false);
+ }
+
+ @Test
+ public void test_1_5() {
+ testVersion(V1_5, false);
+ }
+
+ @Test
+ public void test_1_6() {
+ testVersion(V1_6, true);
+ }
+
+ @Test
+ public void test_1_7() {
+ testVersion(V1_7, true);
+ }
+
+ private void testVersion(int version, boolean frames) {
+ final byte[] original = createClass(version);
+
+ IRuntime runtime = new SystemPropertiesRuntime();
+ Instrumenter instrumenter = new Instrumenter(runtime);
+ byte[] instrumented = instrumenter.instrument(original);
+
+ assertFrames(instrumented, frames);
+ }
+
+ private void assertFrames(byte[] source, boolean expected) {
+ final boolean[] hasFrames = new boolean[] { false };
+ new ClassReader(source).accept(new EmptyVisitor() {
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name,
+ String desc, String signature, String[] exceptions) {
+ return new EmptyVisitor() {
+
+ @Override
+ public void visitFrame(int type, int nLocal,
+ Object[] local, int nStack, Object[] stack) {
+ hasFrames[0] = true;
+ }
+
+ };
+ }
+
+ }, 0);
+ assertEquals(Boolean.valueOf(expected), Boolean.valueOf(hasFrames[0]));
+ }
+
+ private byte[] createClass(int version) {
+
+ ClassWriter cw = new ClassWriter(0);
+ MethodVisitor mv;
+
+ cw.visit(version, ACC_PUBLIC + ACC_SUPER, "org/jacoco/test/Sample",
+ null, "java/lang/Object", null);
+
+ mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java
index 22a5226..a86f122 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java
@@ -37,6 +37,7 @@
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.TraceClassVisitor;
/**
@@ -83,7 +84,17 @@
private byte[] calculateFrames(byte[] source) {
ClassReader rc = new ClassReader(source);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
- rc.accept(cw, 0);
+
+ // Adjust Version to 1.6 to enable frames:
+ rc.accept(new ClassAdapter(cw) {
+
+ @Override
+ public void visit(int version, int access, String name,
+ String signature, String superName, String[] interfaces) {
+ super.visit(Opcodes.V1_6, access, name, signature, superName,
+ interfaces);
+ }
+ }, 0);
return cw.toByteArray();
}
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 cbb991c..7d1295c 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
@@ -40,6 +40,8 @@
private String className;
+ private boolean withFrames;
+
private int probeCount;
/**
@@ -66,6 +68,7 @@
final String signature, final String superName,
final String[] interfaces) {
this.className = name;
+ withFrames = (version & 0xff) >= Opcodes.V1_6;
if ((access & Opcodes.ACC_INTERFACE) == 0) {
this.probeArrayStrategy = new ClassTypeStrategy();
} else {
@@ -154,7 +157,9 @@
InstrSupport.INITMETHOD_ACC, InstrSupport.INITMETHOD_NAME,
InstrSupport.INITMETHOD_DESC, null, null);
mv.visitCode();
- mv.visitFrame(Opcodes.F_NEW, 0, NO_LOCALS, 0, STACK_ARRZ);
+ if (withFrames) {
+ mv.visitFrame(Opcodes.F_NEW, 0, NO_LOCALS, 0, STACK_ARRZ);
+ }
// Load the value of the static data field:
mv.visitFieldInsn(Opcodes.GETSTATIC, className,
@@ -176,7 +181,9 @@
// Stack[0]: [Z
// Return the class' probe array:
- mv.visitFrame(Opcodes.F_NEW, 0, NO_LOCALS, 1, STACK_ARRZ);
+ if (withFrames) {
+ mv.visitFrame(Opcodes.F_NEW, 0, NO_LOCALS, 1, STACK_ARRZ);
+ }
mv.visitLabel(alreadyInitialized);
mv.visitInsn(Opcodes.ARETURN);
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index a218dc0..b9a6d16 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -25,6 +25,11 @@
<li>jacoco-maven-plugin can be used together with maven-site-plugin (Trac #181).</li>
</ul>
+<h3>Fixed Bugs</h3>
+<ul>
+ <li>Don't insert stackmap frames for class files before version 1.6.</li>
+</ul>
+
<h2>Release 0.5.5 (2011/12/15)</h2>
<h3>Fixed Bugs</h3>
@@ -145,7 +150,7 @@
<h3>Fixed Bugs</h3>
<ul>
- <li>Calculate correct stack map frames for Java 1.6 branches (Trac #139).</li>
+ <li>Calculate correct stackmap frames for Java 1.6 branches (Trac #139).</li>
<li>Link source files also for classes in default package (Trac #151).</li>
</ul>