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 int methodId;
   31
   32    private final Type enclosingType;
   33
   34    private int blockArray;
   35
   36    /**
   37     * Create a new instrumenter instance for the given method.
   38     * 
   39     * @param mv
   40     *            next method visitor in the chain
   41     * @param access
   42     *            access flags for the method
   43     * @param name
   44     *            name of the method
   45     * @param desc
   46     *            description of the method
   47     * @param methodId
   48     *            unique id of the method within its enclosing type
   49     * @param enclosingType
   50     *            type enclosing this method
   51     */
   52    public MethodInstrumenter(final MethodVisitor mv, final int access,
   53            final String name, final String desc, final int methodId,
   54            final Type enclosingType) {
   55        super(mv, access, name, desc);
   56        this.methodId = methodId;
   57        this.enclosingType = enclosingType;
   58    }
   59
   60    @Override
   61    public void visitCode() {
   62        super.visitCode();
   63        // At the very beginning of the method we load the boolean[] array into
   64        // a local variable that stores the block coverage of this method.
   65
   66        push(methodId);
   67
   68        // Stack[0]: I
   69
   70        invokeStatic(enclosingType, GeneratorConstants.INIT_METHOD);
   71
   72        // Stack[0]: [Z
   73
   74        blockArray = newLocal(GeneratorConstants.BLOCK_ARR);
   75        storeLocal(blockArray);
   76    }
   77
   78    @Override
   79    public void visitMaxs(final int maxStack, final int maxLocals) {
   80        // Max stack size of the probe code is 3
   81        super.visitMaxs(maxStack + 3, maxLocals + 1);
   82    }
   83
   84    // === IBlockMethodVisitor ===
   85
   86    public void visitBlockEndBeforeJump(final int id) {
   87        // At the end of every block we set the corresponding position in the
   88        // boolean[] array to true.
   89
   90        loadLocal(blockArray);
   91
   92        // Stack[0]: [Z
   93
   94        push(id);
   95
   96        // Stack[1]: I
   97        // Stack[0]: [Z
   98
   99        push(1);
  100
  101        // Stack[2]: I
  102        // Stack[1]: I
  103        // Stack[0]: [Z
  104
  105        visitInsn(Opcodes.BASTORE);
  106    }
  107
  108    public void visitBlockEnd(final int id) {
  109        // nothing to do here
  110    }
  111
  112}