MethodInstrumenter.java

    1/*******************************************************************************
    2 * Copyright (c) 2009 Mountainminds GmbH & Co. KG and others
    3 * All rights reserved. This program and the accompanying materials
    4 * are made available under the terms of the Eclipse Public License v1.0
    5 * which accompanies this distribution, and is available at
    6 * http://www.eclipse.org/legal/epl-v10.html
    7 *
    8 * Contributors:
    9 *    Marc R. Hoffmann - initial API and implementation
   10 *    
   11 * $Id: $
   12 *******************************************************************************/
   13package org.jacoco.core.instr;
   14
   15import org.objectweb.asm.MethodVisitor;
   16import org.objectweb.asm.Opcodes;
   17import org.objectweb.asm.Type;
   18import org.objectweb.asm.commons.GeneratorAdapter;
   19
   20/**
   21 * This method adapter instruments a method to record every block that gets
   22 * fully executed.
   23 * 
   24 * @author Marc R. Hoffmann
   25 * @version $Revision: $
   26 */
   27public class MethodInstrumenter extends GeneratorAdapter implements
   28        IBlockMethodVisitor {
   29
   30    private final Type enclosingType;
   31
   32    private int probeArray;
   33
   34    /**
   35     * Create a new instrumenter instance for the given method.
   36     * 
   37     * @param mv
   38     *            next method visitor in the chain
   39     * @param access
   40     *            access flags for the method
   41     * @param name
   42     *            name of the method
   43     * @param desc
   44     *            description of the method
   45     * @param enclosingType
   46     *            type enclosing this method
   47     */
   48    public MethodInstrumenter(final MethodVisitor mv, final int access,
   49            final String name, final String desc, final Type enclosingType) {
   50        super(mv, access, name, desc);
   51        this.enclosingType = enclosingType;
   52    }
   53
   54    @Override
   55    public void visitCode() {
   56        super.visitCode();
   57        // At the very beginning of the method we load the boolean[] array into
   58        // a local variable that stores the probes for this class.
   59        invokeStatic(enclosingType, GeneratorConstants.INIT_METHOD);
   60
   61        // Stack[0]: [Z
   62
   63        probeArray = newLocal(GeneratorConstants.PROBEDATA_TYPE);
   64        storeLocal(probeArray);
   65    }
   66
   67    @Override
   68    public void visitMaxs(final int maxStack, final int maxLocals) {
   69        // Max stack size of the probe code is 3
   70        super.visitMaxs(maxStack + 3, maxLocals + 1);
   71    }
   72
   73    // === IBlockMethodVisitor ===
   74
   75    public void visitBlockEndBeforeJump(final int id) {
   76        // At the end of every block we set the corresponding position in the
   77        // boolean[] array to true.
   78
   79        loadLocal(probeArray);
   80
   81        // Stack[0]: [Z
   82
   83        push(id);
   84
   85        // Stack[1]: I
   86        // Stack[0]: [Z
   87
   88        push(1);
   89
   90        // Stack[2]: I
   91        // Stack[1]: I
   92        // Stack[0]: [Z
   93
   94        visitInsn(Opcodes.BASTORE);
   95    }
   96
   97    public void visitBlockEnd(final int id) {
   98        // nothing to do here
   99    }
  100
  101}