MethodInstrumenter.java

    1/*******************************************************************************
    2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
    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 */
   26class MethodInstrumenter extends GeneratorAdapter implements
   27        IBlockMethodVisitor {
   28
   29    private final IProbeArrayStrategy probeArrayStrategy;
   30
   31    private int accessorStackSize;
   32
   33    private int probeArray;
   34
   35    /**
   36     * Create a new instrumenter instance for the given method.
   37     * 
   38     * @param mv
   39     *            next method visitor in the chain
   40     * @param access
   41     *            access flags for the method
   42     * @param name
   43     *            name of the method
   44     * @param desc
   45     *            description of the method
   46     * @param probeArrayStrategy
   47     *            strategy to get access to the probe array
   48     */
   49    public MethodInstrumenter(final MethodVisitor mv, final int access,
   50            final String name, final String desc,
   51            final IProbeArrayStrategy probeArrayStrategy) {
   52        super(mv, access, name, desc);
   53        this.probeArrayStrategy = probeArrayStrategy;
   54    }
   55
   56    @Override
   57    public void visitCode() {
   58        super.visitCode();
   59        // At the very beginning of the method we load the boolean[] array into
   60        // a local variable that stores the probes for this class.
   61        accessorStackSize = probeArrayStrategy.pushInstance(mv);
   62
   63        // Stack[0]: [Z
   64
   65        probeArray = newLocal(GeneratorConstants.PROBEDATA_TYPE);
   66        mv.visitVarInsn(Opcodes.ASTORE, probeArray);
   67    }
   68
   69    @Override
   70    public void visitMaxs(final int maxStack, final int maxLocals) {
   71        // Max stack size of the probe code is 3 which can add to the
   72        // original stack size depending on the probe locations. The accessor
   73        // stack size is an absolute maximum, as the accessor code is inserted
   74        // at the very beginning of each method when the stack size is empty.
   75        final int increasedStack = Math.max(maxStack + 3, accessorStackSize);
   76        super.visitMaxs(increasedStack, maxLocals + 1);
   77    }
   78
   79    // === IBlockMethodVisitor ===
   80
   81    public void visitBlockEndBeforeJump(final int id) {
   82        // At the end of every block we set the corresponding position in the
   83        // boolean[] array to true.
   84
   85        mv.visitVarInsn(Opcodes.ALOAD, probeArray);
   86
   87        // Stack[0]: [Z
   88
   89        push(id);
   90
   91        // Stack[1]: I
   92        // Stack[0]: [Z
   93
   94        mv.visitInsn(Opcodes.ICONST_1);
   95
   96        // Stack[2]: I
   97        // Stack[1]: I
   98        // Stack[0]: [Z
   99
  100        visitInsn(Opcodes.BASTORE);
  101    }
  102
  103    public void visitBlockEnd(final int id) {
  104        // nothing to do here
  105    }
  106
  107}