MethodProbesAdapter.java revision 9f4ef8dcffb3acbcd066ec073d87de65eeb06b48
1/*******************************************************************************
2 * Copyright (c) 2009, 2013 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.internal.flow;
13
14import org.jacoco.core.JaCoCo;
15import org.objectweb.asm.Label;
16import org.objectweb.asm.MethodVisitor;
17import org.objectweb.asm.Opcodes;
18
19/**
20 * Adapter that creates additional visitor events for probes to be inserted into
21 * a method.
22 */
23public final class MethodProbesAdapter extends MethodVisitor {
24
25	private final MethodProbesVisitor probesVisitor;
26
27	private final IProbeIdGenerator idGenerator;
28
29	/**
30	 * Create a new adapter instance.
31	 *
32	 * @param probesVisitor
33	 *            visitor to delegate to
34	 * @param idGenerator
35	 *            generator for unique probe ids
36	 */
37	public MethodProbesAdapter(final MethodProbesVisitor probesVisitor,
38			final IProbeIdGenerator idGenerator) {
39		super(JaCoCo.ASM_API_VERSION, probesVisitor);
40		this.probesVisitor = probesVisitor;
41		this.idGenerator = idGenerator;
42	}
43
44	@Override
45	public void visitLabel(final Label label) {
46		if (LabelInfo.isMultiTarget(label) && LabelInfo.isSuccessor(label)) {
47			probesVisitor.visitProbe(idGenerator.nextId());
48		}
49		probesVisitor.visitLabel(label);
50	}
51
52	@Override
53	public void visitInsn(final int opcode) {
54		switch (opcode) {
55		case Opcodes.IRETURN:
56		case Opcodes.LRETURN:
57		case Opcodes.FRETURN:
58		case Opcodes.DRETURN:
59		case Opcodes.ARETURN:
60		case Opcodes.RETURN:
61		case Opcodes.ATHROW:
62			probesVisitor.visitInsnWithProbe(opcode, idGenerator.nextId());
63			break;
64		default:
65			probesVisitor.visitInsn(opcode);
66			break;
67		}
68	}
69
70	@Override
71	public void visitJumpInsn(final int opcode, final Label label) {
72		if (LabelInfo.isMultiTarget(label)) {
73			probesVisitor.visitJumpInsnWithProbe(opcode, label,
74					idGenerator.nextId());
75		} else {
76			probesVisitor.visitJumpInsn(opcode, label);
77		}
78	}
79
80	@Override
81	public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
82			final Label[] labels) {
83		if (markLabels(dflt, labels)) {
84			probesVisitor.visitLookupSwitchInsnWithProbes(dflt, keys, labels);
85		} else {
86			probesVisitor.visitLookupSwitchInsn(dflt, keys, labels);
87		}
88	}
89
90	@Override
91	public void visitTableSwitchInsn(final int min, final int max,
92			final Label dflt, final Label... labels) {
93		if (markLabels(dflt, labels)) {
94			probesVisitor
95					.visitTableSwitchInsnWithProbes(min, max, dflt, labels);
96		} else {
97			probesVisitor.visitTableSwitchInsn(min, max, dflt, labels);
98		}
99	}
100
101	private boolean markLabels(final Label dflt, final Label[] labels) {
102		boolean probe = false;
103		LabelInfo.resetDone(labels);
104		if (LabelInfo.isMultiTarget(dflt)) {
105			LabelInfo.setProbeId(dflt, idGenerator.nextId());
106			probe = true;
107		}
108		LabelInfo.setDone(dflt);
109		for (final Label l : labels) {
110			if (!LabelInfo.isDone(l) && LabelInfo.isMultiTarget(l)) {
111				LabelInfo.setProbeId(l, idGenerator.nextId());
112				probe = true;
113			}
114			LabelInfo.setDone(l);
115		}
116		return probe;
117	}
118
119}
120