Fixed inconsistent stackmap frames when instrumenting class files
produced by certain tools like ProGuard (GitHub #85).
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 e6f3ce1..250aa14 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
@@ -209,25 +209,64 @@
 	}
 
 	@Test
-	public void testVisitFrameDeadCode() {
-		ProbeInserter pi = new ProbeInserter(0, "(J)V", actualVisitor,
-				arrayStrategy);
+	public void testVisitFrameNoLocals() {
+		ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "()V",
+				actualVisitor, arrayStrategy);
 
-		// 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,
-				new Object[] { "java/lang/Throwable" });
-		pi.visitInsn(Opcodes.NOP);
-		pi.visitInsn(Opcodes.NOP);
-		pi.visitInsn(Opcodes.ATHROW);
+		pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[0]);
+
+		expectedVisitor.visitFrame(Opcodes.F_NEW, 1, new Object[] { "[Z" }, 0,
+				new Object[0]);
+	}
+
+	@Test
+	public void testVisitFrameProbeAt0() {
+		ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "()V",
+				actualVisitor, arrayStrategy);
+
+		pi.visitFrame(Opcodes.F_NEW, 2, new Object[] { Opcodes.DOUBLE, "Foo" },
+				0, new Object[0]);
+
+		expectedVisitor.visitFrame(Opcodes.F_NEW, 3, new Object[] { "[Z",
+				Opcodes.DOUBLE, "Foo" }, 0, new Object[0]);
+	}
+
+	@Test
+	public void testFillOneWord() {
+		ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "(I)V",
+				actualVisitor, arrayStrategy);
+
+		pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[] {});
+
+		// The locals in this frame are filled with TOP up to the probe variable
+		expectedVisitor.visitFrame(Opcodes.F_NEW, 2, new Object[] {
+				Opcodes.TOP, "[Z", }, 0, new Object[] {});
+	}
+
+	@Test
+	public void testFillTwoWord() {
+		ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "(J)V",
+				actualVisitor, arrayStrategy);
+
+		pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[] {});
 
 		// 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,
-				new Object[] { "java/lang/Throwable" });
-		expectedVisitor.visitInsn(Opcodes.NOP);
-		expectedVisitor.visitInsn(Opcodes.NOP);
-		expectedVisitor.visitInsn(Opcodes.ATHROW);
+				Opcodes.TOP, Opcodes.TOP, "[Z", }, 0, new Object[] {});
+	}
+
+	@Test
+	public void testFillPartly() {
+		ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "(DIJ)V",
+				actualVisitor, arrayStrategy);
+
+		pi.visitFrame(Opcodes.F_NEW, 1, new Object[] { Opcodes.DOUBLE }, 0,
+				new Object[] {});
+
+		// The locals in this frame are filled with TOP up to the probe variable
+		expectedVisitor.visitFrame(Opcodes.F_NEW, 5, new Object[] {
+				Opcodes.DOUBLE, Opcodes.TOP, Opcodes.TOP, Opcodes.TOP, "[Z", },
+				0, new Object[] {});
 	}
 
 	@Test(expected = IllegalArgumentException.class)
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 b250fc8..2db2d39 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
@@ -29,9 +29,6 @@
 	/** Position of the inserted variable. */
 	private final int variable;
 
-	/** Index the inserted variable. */
-	private final int variableIdx;
-
 	/** Maximum stack usage of the code to access the probe array. */
 	private int accessorStackSize;
 
@@ -52,13 +49,10 @@
 			final IProbeArrayStrategy arrayStrategy) {
 		super(Opcodes.ASM4, mv);
 		this.arrayStrategy = arrayStrategy;
-		int idx = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
-		int pos = idx;
+		int pos = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
 		for (final Type t : Type.getArgumentTypes(desc)) {
-			idx++;
 			pos += t.getSize();
 		}
-		variableIdx = idx;
 		variable = pos;
 	}
 
@@ -109,12 +103,6 @@
 	}
 
 	@Override
-	public final void visitFieldInsn(final int opcode, final String owner,
-			final String name, final String desc) {
-		mv.visitFieldInsn(opcode, owner, name, desc);
-	}
-
-	@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
@@ -141,22 +129,30 @@
 					"ClassReader.accept() should be called with EXPAND_FRAMES flag");
 		}
 
-		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;
+		final Object[] newLocal = new Object[Math.max(nLocal, variable) + 1];
+		int idx = 0; // Arrays index for existing locals
+		int newIdx = 0; // Array index for new locals
+		int pos = 0; // Current variable position
+		while (idx < nLocal || pos <= variable) {
+			if (pos == variable) {
+				newLocal[newIdx++] = InstrSupport.DATAFIELD_DESC;
+				pos++;
+			} else {
+				if (idx < nLocal) {
+					final Object t = local[idx++];
+					newLocal[newIdx++] = t;
+					pos++;
+					if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
+						pos++;
+					}
+				} else {
+					// Fill unused slots with TOP
+					newLocal[newIdx++] = Opcodes.TOP;
+					pos++;
+				}
 			}
-			if (i > variableIdx) {
-				newLocal[i] = local[i - 1];
-				continue;
-			}
-			newLocal[i] = InstrSupport.DATAFIELD_DESC;
 		}
-		mv.visitFrame(type, n, newLocal, nStack, stack);
+		mv.visitFrame(type, newIdx, newLocal, nStack, stack);
 	}
 
 }
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index ef166c4..6ce065a 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -20,6 +20,12 @@
 
 <h2>Trunk Build @qualified.bundle.version@ (@build.date@)</h2>
 
+<h3>Fixed Bugs</h3>
+<ul>
+  <li>Fixed inconsistent stackmap frames when instrumenting class files produced
+      by certain tools like ProGuard (GitHub #85).</li>
+</ul>
+
 <h2>Release 0.6.2 (2013/02/03)</h2>
 
 <h3>New Features</h3>