/* * Based on http://code.google.com/p/javacoveragent/ by * "alex.mq0" and "dmitry.kandalov" * * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. */ package org.pitest.coverage.analysis; import java.util.List; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.pitest.mutationtest.engine.gregor.analysis.InstructionCounter; import sun.pitest.CodeCoverageStore; /** * Instruments a method adding probes at each line. The strategy requires the * compiler to be configured to add line number debug information. * * Probes are implemented by adding an array to each method. Lines hits are * registered by a write to this local array. Each method exit point is then * augmented with a call that passes this array to the coverage store class that * handles communication of this data back to the parent process on the * completion of each test. * * All methods are wrapped in a try finally block to ensure that coverage data * is sent in the event of a runtime exception. * * Creating a new array on each method entry is not cheap - other coverage * systems add a static field used across all methods. We must clear down all * coverage history for each test however. Resetting static fields in all loaded * classes would be messy to implement - it may or may not be faster than the * current approach. */ public class ArrayProbeCoverageMethodVisitor extends AbstractCoverageStrategy { private int probeHitArrayLocal; public ArrayProbeCoverageMethodVisitor(List<Block> blocks, InstructionCounter counter, final int classId, final MethodVisitor writer, final int access, final String name, final String desc, final int probeOffset) { super(blocks, counter, classId, writer, access, name, desc, probeOffset); } @Override void prepare() { this.probeHitArrayLocal = newLocal(Type.getType("[Z")); pushConstant(this.blocks.size()); this.mv.visitIntInsn(NEWARRAY, T_BOOLEAN); this.mv.visitVarInsn(ASTORE, this.probeHitArrayLocal); } @Override void generateProbeReportCode() { pushConstant(this.classId); pushConstant(this.probeOffset); this.mv.visitVarInsn(ALOAD, this.probeHitArrayLocal); this.methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, CodeCoverageStore.CLASS_NAME, CodeCoverageStore.PROBE_METHOD_NAME, "(II[Z)V", false); } @Override void insertProbe() { this.mv.visitVarInsn(ALOAD, this.probeHitArrayLocal); pushConstant(this.probeCount); pushConstant(1); this.mv.visitInsn(BASTORE); } }