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}