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}