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