// SPDX-License-Identifier: EPL-2.0 and Apache-2.0
// These patches apply to JaCoCo (https://github.com/jacoco/jacoco) and are hereby made available under the terms of the
// Eclipse Public License 2.0 available at:
//   http://www.eclipse.org/legal/epl-2.0
diff --git org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
index 476c9e34..bc192dc6 100644
--- org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
+++ org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
@@ -24,6 +24,7 @@ import org.objectweb.asm.MethodVisitor;
 public class ClassInstrumenter extends ClassProbesVisitor {
 
 	private final IProbeArrayStrategy probeArrayStrategy;
+	private final IProbeInserterFactory probeInserterFactory;
 
 	private String className;
 
@@ -40,6 +41,22 @@ public class ClassInstrumenter extends ClassProbesVisitor {
 			final ClassVisitor cv) {
 		super(cv);
 		this.probeArrayStrategy = probeArrayStrategy;
+		this.probeInserterFactory = new IProbeInserterFactory() {
+			@Override
+			public ProbeInserter makeProbeInserter(int access, String name,
+					String desc, MethodVisitor mv,
+					IProbeArrayStrategy arrayStrategy) {
+				return new ProbeInserter(access, name, desc, mv, arrayStrategy);
+			}
+		};
+	}
+
+	public ClassInstrumenter(final IProbeArrayStrategy probeArrayStrategy,
+			final IProbeInserterFactory probeInserterFactory,
+			final ClassVisitor cv) {
+		super(cv);
+		this.probeArrayStrategy = probeArrayStrategy;
+		this.probeInserterFactory = probeInserterFactory;
 	}
 
 	@Override
@@ -71,8 +88,9 @@ public class ClassInstrumenter extends ClassProbesVisitor {
 			return null;
 		}
 		final MethodVisitor frameEliminator = new DuplicateFrameEliminator(mv);
-		final ProbeInserter probeVariableInserter = new ProbeInserter(access,
-				name, desc, frameEliminator, probeArrayStrategy);
+		final ProbeInserter probeVariableInserter =
+				probeInserterFactory.makeProbeInserter(access, name, desc,
+						frameEliminator, probeArrayStrategy);
 		return new MethodInstrumenter(probeVariableInserter,
 				probeVariableInserter);
 	}
diff --git org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserterFactory.java org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserterFactory.java
new file mode 100644
index 00000000..19c2a7e2
--- /dev/null
+++ org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserterFactory.java
@@ -0,0 +1,8 @@
+package org.jacoco.core.internal.instr;
+
+import org.objectweb.asm.MethodVisitor;
+
+public interface IProbeInserterFactory {
+    ProbeInserter makeProbeInserter(int access, String name, String desc,
+            MethodVisitor mv, IProbeArrayStrategy arrayStrategy);
+}
diff --git org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
index 0f5b99ff..80965dfe 100644
--- org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
+++ org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
@@ -25,7 +25,7 @@ import org.objectweb.asm.TypePath;
  * addition the probe array has to be retrieved at the beginning of the method
  * and stored in a local variable.
  */
-class ProbeInserter extends MethodVisitor implements IProbeInserter {
+public class ProbeInserter extends MethodVisitor implements IProbeInserter {
 
 	private final IProbeArrayStrategy arrayStrategy;
 
@@ -36,7 +36,7 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter {
 	private final boolean clinit;
 
 	/** Position of the inserted variable. */
-	private final int variable;
+	protected final int variable;
 
 	/** Label for the new beginning of the method */
 	private final Label beginLabel;
@@ -56,7 +56,7 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter {
 	 *            callback to create the code that retrieves the reference to
 	 *            the probe array
 	 */
-	ProbeInserter(final int access, final String name, final String desc,
+	public ProbeInserter(final int access, final String name, final String desc,
 			final MethodVisitor mv, final IProbeArrayStrategy arrayStrategy) {
 		super(InstrSupport.ASM_API_VERSION, mv);
 		this.clinit = InstrSupport.CLINIT_NAME.equals(name);
@@ -91,6 +91,10 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter {
 		mv.visitInsn(Opcodes.BASTORE);
 	}
 
+	protected Object getLocalVariableType() {
+		return InstrSupport.DATAFIELD_DESC;
+	}
+
 	@Override
 	public void visitCode() {
 		mv.visitLabel(beginLabel);
@@ -118,6 +122,10 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter {
 	public AnnotationVisitor visitLocalVariableAnnotation(final int typeRef,
 			final TypePath typePath, final Label[] start, final Label[] end,
 			final int[] index, final String descriptor, final boolean visible) {
+		if (getLocalVariableType() == null) {
+			return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
+		}
+
 		final int[] newIndex = new int[index.length];
 		for (int i = 0; i < newIndex.length; i++) {
 			newIndex[i] = map(index[i]);
@@ -137,6 +145,9 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter {
 	}
 
 	private int map(final int var) {
+		if (getLocalVariableType() == null) {
+			return var;
+		}
 		if (var < variable) {
 			return var;
 		} else {
@@ -153,13 +164,18 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter {
 					"ClassReader.accept() should be called with EXPAND_FRAMES flag");
 		}
 
+        if (getLocalVariableType() == null) {
+			mv.visitFrame(type, nLocal, local, nStack, stack);
+			return;
+		}
+
 		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;
+				newLocal[newIdx++] = getLocalVariableType();
 				pos++;
 			} else {
 				if (idx < nLocal) {
