Update to ASM 4.1

With ASM 4.1 implicit initial frames are no longer processed as events.
This required a rework and simplification of the frame processing logic.
diff --git a/org.jacoco.agent.rt/META-INF/MANIFEST.MF b/org.jacoco.agent.rt/META-INF/MANIFEST.MF
index 16a32b8..76516c0 100644
--- a/org.jacoco.agent.rt/META-INF/MANIFEST.MF
+++ b/org.jacoco.agent.rt/META-INF/MANIFEST.MF
@@ -9,4 +9,4 @@
  org.jacoco.core.data;bundle-version="[0.6.1,0.6.2)",
  org.jacoco.core.instr;bundle-version="[0.6.1,0.6.2)",
  org.jacoco.core.runtime;bundle-version="[0.6.1,0.6.2)",
- org.objectweb.asm;version="[4.0.0,4.1.0)"
+ org.objectweb.asm;version="[4.1.0,4.2.0)"
diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml
index 3544e7f..e60a05b 100644
--- a/org.jacoco.build/pom.xml
+++ b/org.jacoco.build/pom.xml
@@ -132,7 +132,7 @@
     <tycho.version>0.13.0</tycho.version>
 
     <!-- Dependencies versions -->
-    <asm.version>4.0</asm.version>
+    <asm.version>4.1</asm.version>
     <ant.version>1.7.0</ant.version>
     <junit.version>4.8.2</junit.version>
 
diff --git a/org.jacoco.core.test/META-INF/MANIFEST.MF b/org.jacoco.core.test/META-INF/MANIFEST.MF
index 222304c..e846d60 100644
--- a/org.jacoco.core.test/META-INF/MANIFEST.MF
+++ b/org.jacoco.core.test/META-INF/MANIFEST.MF
@@ -8,4 +8,4 @@
 Bundle-RequiredExecutionEnvironment: J2SE-1.5

 Import-Package: org.junit;version="[4.8.0,5.0.0)",

  org.junit.rules;version="[4.8.0,5.0.0)",

- org.objectweb.asm.util;version="[4.0.0,4.1.0)"

+ org.objectweb.asm.util;version="[4.1.0,4.2.0)"

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
index 8a7d694..2b286cb 100644
--- 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
@@ -75,7 +75,8 @@
 				// Ignore labels inserted by the tracker
 			}
 		};
-		FrameTracker tracker = new FrameTracker(noLabels, "Test");
+		FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
+				"()V", noLabels);
 		before.accept(tracker);
 		mv.instructions.accept(tracker);
 		tracker.insertFrame();
@@ -90,47 +91,101 @@
 
 	@Test(expected = IllegalArgumentException.class)
 	public void testVisitFrameIllegalFrameType() {
-		FrameTracker tracker = new FrameTracker(null, "Test");
+		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(null, "Test");
+		FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
+				"()V", null);
 		tracker.visitInsn(GOTO);
 	}
 
 	@Test(expected = IllegalArgumentException.class)
 	public void testVisitIntInsnIllegalOpcode() {
-		FrameTracker tracker = new FrameTracker(null, "Test");
+		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(null, "Test");
+		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(null, "Test");
+		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(null, "Test");
+		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(null, "Test");
+		FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
+				"()V", null);
 		tracker.visitJumpInsn(NOP, new Label());
 	}
 
 	@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);
@@ -147,13 +202,6 @@
 	}
 
 	@Test
-	public void AALOAD() {
-		before.locals().stack("[Ljava/lang/String;", INTEGER);
-		mv.visitInsn(AALOAD);
-		after.locals().stack("java/lang/String");
-	}
-
-	@Test
 	public void AALOAD_multidim_obj() {
 		before.locals().stack("[[Ljava/lang/String;", INTEGER);
 		mv.visitInsn(AALOAD);
@@ -1130,7 +1178,8 @@
 
 	@Test(expected = IllegalArgumentException.class)
 	public void LDC_invalidType() {
-		FrameTracker tracker = new FrameTracker(null, "Test");
+		FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
+				"()V", null);
 		tracker.visitLdcInsn(Byte.valueOf((byte) 123));
 	}
 
@@ -1320,7 +1369,8 @@
 
 	@Test(expected = IllegalArgumentException.class)
 	public void NEWARRAY_invalidOperand() {
-		FrameTracker tracker = new FrameTracker(null, "Test");
+		FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test",
+				"()V", null);
 		tracker.visitIntInsn(NEWARRAY, -1);
 	}
 
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeInserterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeInserterTest.java
index d15287e..f7b548b 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeInserterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeInserterTest.java
@@ -18,8 +18,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.Handle;
-import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
@@ -63,7 +61,6 @@
 				actualVisitor, arrayStrategy);
 		pi.insertProbe(0);
 
-		expectedVisitor.visitLdcInsn("init");
 		expectedVisitor.visitVarInsn(Opcodes.ALOAD, 0);
 		expectedVisitor.visitInsn(Opcodes.ICONST_0);
 		expectedVisitor.visitInsn(Opcodes.ICONST_1);
@@ -76,7 +73,6 @@
 				arrayStrategy);
 		pi.insertProbe(0);
 
-		expectedVisitor.visitLdcInsn("init");
 		expectedVisitor.visitVarInsn(Opcodes.ALOAD, 1);
 		expectedVisitor.visitInsn(Opcodes.ICONST_0);
 		expectedVisitor.visitInsn(Opcodes.ICONST_1);
@@ -89,7 +85,6 @@
 				actualVisitor, arrayStrategy);
 		pi.insertProbe(0);
 
-		expectedVisitor.visitLdcInsn("init");
 		expectedVisitor.visitVarInsn(Opcodes.ALOAD, 4);
 		expectedVisitor.visitInsn(Opcodes.ICONST_0);
 		expectedVisitor.visitInsn(Opcodes.ICONST_1);
@@ -102,7 +97,6 @@
 				arrayStrategy);
 		pi.insertProbe(0);
 
-		expectedVisitor.visitLdcInsn("init");
 		expectedVisitor.visitVarInsn(Opcodes.ALOAD, 5);
 		expectedVisitor.visitInsn(Opcodes.ICONST_0);
 		expectedVisitor.visitInsn(Opcodes.ICONST_1);
@@ -110,47 +104,12 @@
 	}
 
 	@Test
-	public void testVisitProlog() {
-		ProbeInserter pi = new ProbeInserter(0, "(I)V", actualVisitor,
-				arrayStrategy);
-		Label label = new Label();
-		pi.visitLabel(label);
-		pi.visitLineNumber(123, label);
-		pi.visitFrame(Opcodes.F_NEW, 1, new Object[] { "I" }, 0, new Object[0]);
-		pi.visitInsn(Opcodes.NOP);
-
-		expectedVisitor.visitFrame(Opcodes.F_NEW, 1, new Object[] { "I" }, 0,
-				new Object[0]);
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitLabel(label);
-		expectedVisitor.visitLineNumber(123, label);
-		expectedVisitor.visitInsn(Opcodes.NOP);
-	}
-
-	@Test
-	public void testVisitLabel() {
+	public void testVisitCode() {
 		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
 				arrayStrategy);
-		Label label = new Label();
-		pi.visitInsn(Opcodes.NOP);
-		pi.visitLabel(label);
+		pi.visitCode();
 
 		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitInsn(Opcodes.NOP);
-		expectedVisitor.visitLabel(label);
-	}
-
-	@Test
-	public void testVisitLineNumber() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		Label label = new Label();
-		pi.visitInsn(Opcodes.NOP);
-		pi.visitLineNumber(123, label);
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitInsn(Opcodes.NOP);
-		expectedVisitor.visitLineNumber(123, label);
 	}
 
 	@Test
@@ -164,7 +123,6 @@
 		pi.visitVarInsn(Opcodes.ISTORE, 3);
 		pi.visitVarInsn(Opcodes.FSTORE, 4);
 
-		expectedVisitor.visitLdcInsn("init");
 		// Argument variables stay at the same position:
 		expectedVisitor.visitVarInsn(Opcodes.ALOAD, 0);
 		expectedVisitor.visitVarInsn(Opcodes.ILOAD, 1);
@@ -185,7 +143,6 @@
 		pi.visitIincInsn(3, 103);
 		pi.visitIincInsn(4, 104);
 
-		expectedVisitor.visitLdcInsn("init");
 		// Argument variables stay at the same position:
 		expectedVisitor.visitIincInsn(0, 100);
 		expectedVisitor.visitIincInsn(1, 101);
@@ -207,7 +164,6 @@
 		pi.visitLocalVariable(null, null, null, null, null, 3);
 		pi.visitLocalVariable(null, null, null, null, null, 4);
 
-		expectedVisitor.visitLdcInsn("init");
 		// Argument variables stay at the same position:
 		expectedVisitor.visitLocalVariable(null, null, null, null, null, 0);
 		expectedVisitor.visitLocalVariable(null, null, null, null, null, 1);
@@ -219,119 +175,13 @@
 	}
 
 	@Test
-	public void testVisitIntInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		pi.visitIntInsn(Opcodes.BIPUSH, 15);
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitIntInsn(Opcodes.BIPUSH, 15);
-	}
-
-	@Test
-	public void testVisitTypeInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		pi.visitTypeInsn(Opcodes.NEW, "Foo");
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitTypeInsn(Opcodes.NEW, "Foo");
-	}
-
-	@Test
-	public void testVisitFieldInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		pi.visitFieldInsn(Opcodes.GETFIELD, "Foo", "i", "I");
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitFieldInsn(Opcodes.GETFIELD, "Foo", "i", "I");
-	}
-
-	@Test
-	public void testVisitMethodInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		pi.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Foo", "doit", "()V");
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Foo", "doit",
-				"()V");
-	}
-
-	@Test
-	public void testInvokeDynamicInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		Handle handle = new Handle(0, null, null, null);
-		pi.visitInvokeDynamicInsn("foo", "()V", handle);
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitInvokeDynamicInsn("foo", "()V", handle);
-	}
-
-	@Test
-	public void testVisitJumpInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		Label label = new Label();
-		pi.visitJumpInsn(Opcodes.GOTO, label);
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitJumpInsn(Opcodes.GOTO, label);
-	}
-
-	@Test
-	public void testVisitLdcInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		pi.visitLdcInsn("JaCoCo");
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitLdcInsn("JaCoCo");
-	}
-
-	@Test
-	public void testVisitTableSwitchInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		Label dflt = new Label();
-		pi.visitTableSwitchInsn(0, 1, dflt, new Label[0]);
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitTableSwitchInsn(0, 1, dflt, new Label[0]);
-	}
-
-	@Test
-	public void testVisitLookupSwitchInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		Label dflt = new Label();
-		pi.visitLookupSwitchInsn(dflt, new int[0], new Label[0]);
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitLookupSwitchInsn(dflt, new int[0], new Label[0]);
-	}
-
-	@Test
-	public void testVisitMultiANewArrayInsn() {
-		ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor,
-				arrayStrategy);
-		pi.visitMultiANewArrayInsn("[[[I", 3);
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitMultiANewArrayInsn("[[[I", 3);
-	}
-
-	@Test
 	public void testVisitMaxs1() {
 		ProbeInserter pi = new ProbeInserter(0, "(II)V", actualVisitor,
 				arrayStrategy);
-		pi.visitInsn(Opcodes.NOP);
+		pi.visitCode();
 		pi.visitMaxs(0, 8);
 
 		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitInsn(Opcodes.NOP);
 		expectedVisitor.visitMaxs(5, 9);
 	}
 
@@ -339,11 +189,10 @@
 	public void testVisitMaxs2() {
 		ProbeInserter pi = new ProbeInserter(0, "(II)V", actualVisitor,
 				arrayStrategy);
-		pi.visitInsn(Opcodes.NOP);
+		pi.visitCode();
 		pi.visitMaxs(10, 8);
 
 		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitInsn(Opcodes.NOP);
 		expectedVisitor.visitMaxs(13, 9);
 	}
 
@@ -352,20 +201,9 @@
 		ProbeInserter pi = new ProbeInserter(0, "(J)V", actualVisitor,
 				arrayStrategy);
 
-		pi.visitFrame(Opcodes.F_NEW, 2, new Object[] { "Foo", Opcodes.LONG },
-				0, new Object[0]);
-		pi.visitInsn(Opcodes.NOP);
 		pi.visitFrame(Opcodes.F_NEW, 3, new Object[] { "Foo", Opcodes.LONG,
 				"java/lang/String" }, 0, new Object[0]);
 
-		// The first (implicit) frame must not be modified:
-		expectedVisitor.visitFrame(Opcodes.F_NEW, 2, new Object[] { "Foo",
-				Opcodes.LONG }, 0, new Object[0]);
-
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitInsn(Opcodes.NOP);
-
-		// Starting from the second frame on the probe variable is inserted:
 		expectedVisitor.visitFrame(Opcodes.F_NEW, 4, new Object[] { "Foo",
 				Opcodes.LONG, "[Z", "java/lang/String" }, 0, new Object[0]);
 	}
@@ -375,10 +213,6 @@
 		ProbeInserter pi = new ProbeInserter(0, "(J)V", actualVisitor,
 				arrayStrategy);
 
-		pi.visitFrame(Opcodes.F_NEW, 2, new Object[] { "Foo", Opcodes.LONG },
-				0, new Object[0]);
-		pi.visitInsn(Opcodes.RETURN);
-
 		// Such sequences are generated by ASM to replace dead code, see
 		// http://asm.ow2.org/doc/developer-guide.html#deadcode
 		pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 1,
@@ -387,12 +221,6 @@
 		pi.visitInsn(Opcodes.NOP);
 		pi.visitInsn(Opcodes.ATHROW);
 
-		// The first (implicit) frame must not be modified:
-		expectedVisitor.visitFrame(Opcodes.F_NEW, 2, new Object[] { "Foo",
-				Opcodes.LONG }, 0, new Object[0]);
-		expectedVisitor.visitLdcInsn("init");
-		expectedVisitor.visitInsn(Opcodes.RETURN);
-
 		// The locals in this frame are filled with TOP up to the probe variable
 		expectedVisitor.visitFrame(Opcodes.F_NEW, 3, new Object[] {
 				Opcodes.TOP, Opcodes.TOP, "[Z", }, 1,
diff --git a/org.jacoco.core/META-INF/MANIFEST.MF b/org.jacoco.core/META-INF/MANIFEST.MF
index 194be14..b7538ce 100644
--- a/org.jacoco.core/META-INF/MANIFEST.MF
+++ b/org.jacoco.core/META-INF/MANIFEST.MF
@@ -11,6 +11,6 @@
  org.jacoco.core.instr;version="0.6.1",

  org.jacoco.core.internal.analysis;version="0.6.1"; x-internal=true,

  org.jacoco.core.runtime;version="0.6.1"

-Import-Package: org.objectweb.asm;version="[4.0.0,4.1.0)",

- org.objectweb.asm.tree;version="[4.0.0,4.1.0)",

- org.objectweb.asm.commons;version="[4.0.0,4.1.0)"

+Import-Package: org.objectweb.asm;version="[4.1.0,4.2.0)",

+ org.objectweb.asm.tree;version="[4.1.0,4.2.0)",

+ org.objectweb.asm.commons;version="[4.1.0,4.2.0)"

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 2aa2606..44d3c21 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
@@ -97,10 +97,15 @@
 		final MethodVisitor frameEliminator = new DuplicateFrameEliminator(mv);
 		final ProbeInserter probeVariableInserter = new ProbeInserter(access,
 				desc, frameEliminator, probeArrayStrategy);
-		final LazyFrameTracker frameTracker = new LazyFrameTracker(
-				probeVariableInserter, className);
-		return new MethodInstrumenter(frameTracker, probeVariableInserter,
-				frameTracker);
+		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);
+		}
 	}
 
 	@Override
@@ -162,9 +167,6 @@
 					InstrSupport.INITMETHOD_ACC, InstrSupport.INITMETHOD_NAME,
 					InstrSupport.INITMETHOD_DESC, null, null);
 			mv.visitCode();
-			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,
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
index de0e357..ed396bf 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/FrameTracker.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/FrameTracker.java
@@ -31,13 +31,26 @@
 	private Object[] stack;
 	private int stackSize;
 
-	public FrameTracker(final MethodVisitor mv, final String owner) {
+	public FrameTracker(final String owner, final int access,
+			final String name, final String desc, final MethodVisitor mv) {
 		super(Opcodes.ASM4, 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() {
@@ -607,6 +620,35 @@
 		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) {
 		return local[pos];
 	}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/IFrameInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/IFrameInserter.java
index 581aa52..9f98860 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/IFrameInserter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/IFrameInserter.java
@@ -18,6 +18,14 @@
 interface IFrameInserter {
 
 	/**
+	 * Empty implementation.
+	 */
+	static final IFrameInserter NOP = new IFrameInserter() {
+		public void insertFrame() {
+		}
+	};
+
+	/**
 	 * Inserts an additional frame reflecting the current locals and stack
 	 * types.
 	 */
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/LazyFrameTracker.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/LazyFrameTracker.java
deleted file mode 100644
index 6edddbf..0000000
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/LazyFrameTracker.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
- * 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.internal.instr;
-
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * Internal wrapper for the FrameTracker which activates frame tracking lazily
- * when the first frame is reported.
- */
-class LazyFrameTracker extends MethodVisitor implements IFrameInserter {
-
-	private final String owner;
-	private FrameTracker tracker;
-
-	public LazyFrameTracker(final MethodVisitor mv, final String owner) {
-		super(Opcodes.ASM4, mv);
-		this.owner = owner;
-		this.tracker = null;
-	}
-
-	@Override
-	public void visitFrame(final int type, final int nLocal,
-			final Object[] local, final int nStack, final Object[] stack) {
-		if (tracker == null) {
-			mv = tracker = new FrameTracker(mv, owner);
-		}
-		tracker.visitFrame(type, nLocal, local, nStack, stack);
-	}
-
-	public void insertFrame() {
-		if (tracker != null) {
-			tracker.insertFrame();
-		}
-	}
-
-}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
index 5bc80c1..c45883b 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
@@ -11,14 +11,10 @@
  *******************************************************************************/
 package org.jacoco.core.internal.instr;
 
-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.InsnList;
-import org.objectweb.asm.tree.LabelNode;
-import org.objectweb.asm.tree.LineNumberNode;
 
 /**
  * Internal utility to add probes into the control flow of a method. The code
@@ -36,15 +32,9 @@
 	/** Index the inserted variable. */
 	private final int variableIdx;
 
-	/** Indicated whether the probe variable has already been inserted. */
-	private boolean inserted;
-
 	/** Maximum stack usage of the code to access the probe array. */
 	private int accessorStackSize;
 
-	/** Labels and line numbers preceding the first real instruction. */
-	private final InsnList prolog;
-
 	/**
 	 * Creates a new {@link ProbeInserter}.
 	 * 
@@ -70,13 +60,10 @@
 		}
 		variableIdx = idx;
 		variable = pos;
-		inserted = false;
-		prolog = new InsnList();
 	}
 
 	public void insertProbe(final int id) {
 
-		checkLoad();
 		// For a probe we set the corresponding position in the boolean[] array
 		// to true.
 
@@ -98,41 +85,19 @@
 		mv.visitInsn(Opcodes.BASTORE);
 	}
 
-	private void checkLoad() {
-		if (!inserted) {
-			accessorStackSize = arrayStrategy.storeInstance(mv, variable);
-			prolog.accept(mv);
-			inserted = true;
-		}
-	}
-
 	@Override
-	public final void visitLabel(final Label label) {
-		if (!inserted) {
-			prolog.add(new LabelNode(label));
-		} else {
-			mv.visitLabel(label);
-		}
-	}
-
-	@Override
-	public void visitLineNumber(final int line, final Label start) {
-		if (!inserted) {
-			prolog.add(new LineNumberNode(line, new LabelNode(start)));
-		} else {
-			mv.visitLineNumber(line, start);
-		}
+	public void visitCode() {
+		accessorStackSize = arrayStrategy.storeInstance(mv, variable);
+		mv.visitCode();
 	}
 
 	@Override
 	public final void visitVarInsn(final int opcode, final int var) {
-		checkLoad();
 		mv.visitVarInsn(opcode, map(var));
 	}
 
 	@Override
 	public final void visitIincInsn(final int var, final int increment) {
-		checkLoad();
 		mv.visitIincInsn(map(var), increment);
 	}
 
@@ -140,82 +105,16 @@
 	public final void visitLocalVariable(final String name, final String desc,
 			final String signature, final Label start, final Label end,
 			final int index) {
-		checkLoad();
 		mv.visitLocalVariable(name, desc, signature, start, end, map(index));
 	}
 
 	@Override
-	public final void visitInsn(final int opcode) {
-		checkLoad();
-		mv.visitInsn(opcode);
-	}
-
-	@Override
-	public final void visitIntInsn(final int opcode, final int operand) {
-		checkLoad();
-		mv.visitIntInsn(opcode, operand);
-	}
-
-	@Override
-	public final void visitTypeInsn(final int opcode, final String type) {
-		checkLoad();
-		mv.visitTypeInsn(opcode, type);
-	}
-
-	@Override
 	public final void visitFieldInsn(final int opcode, final String owner,
 			final String name, final String desc) {
-		checkLoad();
 		mv.visitFieldInsn(opcode, owner, name, desc);
 	}
 
 	@Override
-	public final void visitMethodInsn(final int opcode, final String owner,
-			final String name, final String desc) {
-		checkLoad();
-		mv.visitMethodInsn(opcode, owner, name, desc);
-	}
-
-	@Override
-	public void visitInvokeDynamicInsn(final String name, final String desc,
-			final Handle bsm, final Object... bsmArgs) {
-		checkLoad();
-		mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-	}
-
-	@Override
-	public final void visitJumpInsn(final int opcode, final Label label) {
-		checkLoad();
-		mv.visitJumpInsn(opcode, label);
-	}
-
-	@Override
-	public final void visitLdcInsn(final Object cst) {
-		checkLoad();
-		mv.visitLdcInsn(cst);
-	}
-
-	@Override
-	public final void visitTableSwitchInsn(final int min, final int max,
-			final Label dflt, final Label... labels) {
-		checkLoad();
-		mv.visitTableSwitchInsn(min, max, dflt, labels);
-	}
-
-	@Override
-	public final void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-			final Label[] labels) {
-		checkLoad();
-		mv.visitLookupSwitchInsn(dflt, keys, labels);
-	}
-
-	@Override
-	public final void visitMultiANewArrayInsn(final String desc, final int dims) {
-		checkLoad();
-		mv.visitMultiANewArrayInsn(desc, dims);
-	}
-
-	@Override
 	public void visitMaxs(final int maxStack, final int maxLocals) {
 		// Max stack size of the probe code is 3 which can add to the
 		// original stack size depending on the probe locations. The accessor
@@ -242,28 +141,22 @@
 					"ClassReader.accept() should be called with EXPAND_FRAMES flag");
 		}
 
-		if (inserted) {
-			final int n = Math.max(nLocal, variableIdx) + 1;
-			final Object[] newLocal = new Object[n];
-			for (int i = 0; i < n; i++) {
-				if (i < variableIdx) {
-					// For dead code it is possible to specify less locals than
-					// we have method parameters.
-					newLocal[i] = i < nLocal ? local[i] : Opcodes.TOP;
-					continue;
-				}
-				if (i > variableIdx) {
-					newLocal[i] = local[i - 1];
-					continue;
-				}
-				newLocal[i] = InstrSupport.DATAFIELD_DESC;
+		final int n = Math.max(nLocal, variableIdx) + 1;
+		final Object[] newLocal = new Object[n];
+		for (int i = 0; i < n; i++) {
+			if (i < variableIdx) {
+				// For dead code it is possible to specify less locals than
+				// we have method parameters.
+				newLocal[i] = i < nLocal ? local[i] : Opcodes.TOP;
+				continue;
 			}
-			mv.visitFrame(type, n, newLocal, nStack, stack);
-		} else {
-			mv.visitFrame(type, nLocal, local, nStack, stack);
+			if (i > variableIdx) {
+				newLocal[i] = local[i - 1];
+				continue;
+			}
+			newLocal[i] = InstrSupport.DATAFIELD_DESC;
 		}
-
-		checkLoad();
+		mv.visitFrame(type, n, newLocal, nStack, stack);
 	}
 
 }
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index cdde19b..8557fa5 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -20,6 +20,11 @@
 
 <h2>Trunk Build @qualified.bundle.version@ (@build.date@)</h2>
 
+<h3>Non-functional Changes</h3>
+<ul>
+  <li>Upgrade to ASM 4.1 (GitHub #37)</li>
+</ul>
+
 <h2>Release 0.6.0 (2012/10/06)</h2>
 
 <h3>New Features</h3>
diff --git a/org.jacoco.report/META-INF/MANIFEST.MF b/org.jacoco.report/META-INF/MANIFEST.MF
index e2caaef..bbf42c2 100644
--- a/org.jacoco.report/META-INF/MANIFEST.MF
+++ b/org.jacoco.report/META-INF/MANIFEST.MF
@@ -12,4 +12,4 @@
 Import-Package: org.jacoco.core;bundle-version="[0.6.1,0.6.2)",

  org.jacoco.core.analysis;bundle-version="[0.6.1,0.6.2)",

  org.jacoco.core.data;bundle-version="[0.6.1,0.6.2)",

- org.objectweb.asm;version="[4.0.0,4.1.0)"

+ org.objectweb.asm;version="[4.1.0,4.2.0)"