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