// 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) {