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.commons.GeneratorAdapter;
   18
   19/**
   20 * This method adapter instruments a method to record every block that gets
   21 * fully executed.
   22 * 
   23 * @author Marc R. Hoffmann
   24 * @version $Revision: $
   25 */
   26public class MethodInstrumenter extends GeneratorAdapter implements
   27        IBlockMethodVisitor {
   28
   29    private final String enclosingType;
   30
   31    private int probeArray;
   32
   33    /**
   34     * Create a new instrumenter instance for the given method.
   35     * 
   36     * @param mv
   37     *            next method visitor in the chain
   38     * @param access
   39     *            access flags for the method
   40     * @param name
   41     *            name of the method
   42     * @param desc
   43     *            description of the method
   44     * @param enclosingType
   45     *            type enclosing this method
   46     */
   47    public MethodInstrumenter(final MethodVisitor mv, final int access,
   48            final String name, final String desc, final String enclosingType) {
   49        super(mv, access, name, desc);
   50        this.enclosingType = enclosingType;
   51    }
   52
   53    @Override
   54    public void visitCode() {
   55        super.visitCode();
   56        // At the very beginning of the method we load the boolean[] array into
   57        // a local variable that stores the probes for this class.
   58        mv.visitMethodInsn(Opcodes.INVOKESTATIC, enclosingType,
   59                GeneratorConstants.INITMETHOD_NAME,
   60                GeneratorConstants.INITMETHOD_DESC);
   61
   62        // Stack[0]: [Z
   63
   64        probeArray = newLocal(GeneratorConstants.PROBEDATA_TYPE);
   65        mv.visitVarInsn(Opcodes.ASTORE, probeArray);
   66    }
   67
   68    @Override
   69    public void visitMaxs(final int maxStack, final int maxLocals) {
   70        // Max stack size of the probe code is 3
   71        super.visitMaxs(maxStack + 3, maxLocals + 1);
   72    }
   73
   74    // === IBlockMethodVisitor ===
   75
   76    public void visitBlockEndBeforeJump(final int id) {
   77        // At the end of every block we set the corresponding position in the
   78        // boolean[] array to true.
   79
   80        mv.visitVarInsn(Opcodes.ALOAD, probeArray);
   81
   82        // Stack[0]: [Z
   83
   84        push(id);
   85
   86        // Stack[1]: I
   87        // Stack[0]: [Z
   88
   89        mv.visitInsn(Opcodes.ICONST_1);
   90
   91        // Stack[2]: I
   92        // Stack[1]: I
   93        // Stack[0]: [Z
   94
   95        visitInsn(Opcodes.BASTORE);
   96    }
   97
   98    public void visitBlockEnd(final int id) {
   99        // nothing to do here
  100    }
  101
  102}