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}