aboutsummaryrefslogtreecommitdiffstats
path: root/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java
blob: 85dc1d815c222b87ca84b55f381673752a27d6a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/*******************************************************************************
 * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Marc R. Hoffmann - initial API and implementation
 *    
 *******************************************************************************/
package org.jacoco.core.internal.flow;

import org.jacoco.core.internal.analysis.Instruction;
import org.objectweb.asm.Label;

/**
 * Data container that is attached to {@link Label#info} objects to store flow
 * and instrumentation specific information. The information is only valid
 * locally in specific contexts.
 */
public final class LabelInfo {

	/**
	 * Reserved ID for "no probe".
	 */
	public static final int NO_PROBE = -1;

	private boolean target = false;

	private boolean multiTarget = false;

	private boolean successor = false;

	private boolean methodInvocationLine = false;

	private boolean done = false;

	private int probeid = NO_PROBE;

	private Label intermediate = null;

	private Instruction instruction = null;

	// instances are only created within this class
	private LabelInfo() {
	}

	/**
	 * Defines that the given label is a jump target.
	 * 
	 * @param label
	 *            label to define
	 */
	public static void setTarget(final Label label) {
		final LabelInfo info = create(label);
		if (info.target || info.successor) {
			info.multiTarget = true;
		} else {
			info.target = true;
		}
	}

	/**
	 * Defines that the given label is the possible successor of the previous
	 * instruction in the method.
	 * 
	 * @param label
	 *            label to define
	 */
	public static void setSuccessor(final Label label) {
		final LabelInfo info = create(label);
		info.successor = true;
		if (info.target) {
			info.multiTarget = true;
		}
	}

	/**
	 * Checks whether multiple control paths lead to a label. Control flow path
	 * to a certain label are: jump targets, exception handlers and normal
	 * control flow from its predecessor instruction (unless this is an
	 * unconditional jump or method exit).
	 * 
	 * @param label
	 *            label to check
	 * @return <code>true</code> if the given multiple control paths lead to the
	 *         given label
	 */
	public static boolean isMultiTarget(final Label label) {
		final LabelInfo info = get(label);
		return info == null ? false : info.multiTarget;
	}

	/**
	 * Checks whether this label is the possible successor of the previous
	 * instruction in the method. This is the case if the predecessor isn't a
	 * unconditional jump or method exit instruction.
	 * 
	 * @param label
	 *            label to check
	 * @return <code>true</code> if the label is a possible instruction
	 *         successor
	 */
	public static boolean isSuccessor(final Label label) {
		final LabelInfo info = get(label);
		return info == null ? false : info.successor;
	}

	/**
	 * Mark a given label as the beginning of a line with method invocations.
	 * 
	 * @param label
	 *            label to mark
	 */
	public static void setMethodInvocationLine(final Label label) {
		create(label).methodInvocationLine = true;
	}

	/**
	 * Checks whether the a given label has been marked as a line with method
	 * invocations.
	 * 
	 * @param label
	 *            label to check
	 * @return <code>true</code> if the label represents a line with method
	 *         invocations
	 */
	public static boolean isMethodInvocationLine(final Label label) {
		final LabelInfo info = get(label);
		return info == null ? false : info.methodInvocationLine;
	}

	/**
	 * Determines whether the given label needs a probe to be inserted before.
	 * 
	 * @param label
	 *            label to test
	 * @return <code>true</code> if a probe should be inserted before
	 */
	public static boolean needsProbe(final Label label) {
		final LabelInfo info = get(label);
		return info != null && info.successor
				&& (info.multiTarget || info.methodInvocationLine);
	}

	/**
	 * Mark a given label as done.
	 * 
	 * @param label
	 *            label to mark
	 */
	public static void setDone(final Label label) {
		create(label).done = true;
	}

	/**
	 * Resets the "done" status of a given label.
	 * 
	 * @param label
	 *            label to reset
	 */
	public static void resetDone(final Label label) {
		final LabelInfo info = get(label);
		if (info != null) {
			info.done = false;
		}
	}

	/**
	 * Resets the "done" status of all given labels.
	 * 
	 * @param labels
	 *            labels to reset
	 */
	public static void resetDone(final Label[] labels) {
		for (final Label label : labels) {
			resetDone(label);
		}
	}

	/**
	 * Checks whether this label is marked as done.
	 * 
	 * @param label
	 *            label to check
	 * @return <code>true</code> if this label is marked as done
	 */
	public static boolean isDone(final Label label) {
		final LabelInfo info = get(label);
		return info == null ? false : info.done;
	}

	/**
	 * Sets the given probe id to the given label.
	 * 
	 * @param label
	 *            label to assign a probe to
	 * @param id
	 *            id of the probe
	 */
	public static void setProbeId(final Label label, final int id) {
		create(label).probeid = id;
	}

	/**
	 * Returns the assigned probe id.
	 * 
	 * @param label
	 *            label to check
	 * @return probe id or {@link #NO_PROBE} if no probe is assigned to the
	 *         label
	 */
	public static int getProbeId(final Label label) {
		final LabelInfo info = get(label);
		return info == null ? NO_PROBE : info.probeid;
	}

	/**
	 * Defines an intermediate label for the given label. Such intermediate
	 * labels are required during instrumentation to add probes to jump targets.
	 * 
	 * @param label
	 *            label to define for
	 * @param intermediate
	 *            intermediate label
	 */
	public static void setIntermediateLabel(final Label label,
			final Label intermediate) {
		create(label).intermediate = intermediate;
	}

	/**
	 * Returns the intermediate label for the given label if one has been
	 * defined.
	 * 
	 * @param label
	 *            label to look for
	 * @return intermediate label or <code>null</code>
	 */
	public static Label getIntermediateLabel(final Label label) {
		final LabelInfo info = get(label);
		return info == null ? null : info.intermediate;
	}

	/**
	 * Sets the instruction corresponding to this label.
	 * 
	 * @param label
	 *            label to set the instruction for
	 * @param instruction
	 *            corresponding instruction
	 */
	public static void setInstruction(final Label label,
			final Instruction instruction) {
		create(label).instruction = instruction;
	}

	/**
	 * Returns the corresponding instruction for the given label if one has been
	 * defined.
	 * 
	 * @param label
	 *            label to look for
	 * @return corresponding instruction or <code>null</code>
	 */
	public static Instruction getInstruction(final Label label) {
		final LabelInfo info = get(label);
		return info == null ? null : info.instruction;
	}

	private static LabelInfo get(final Label label) {
		final Object info = label.info;
		return info instanceof LabelInfo ? (LabelInfo) info : null;
	}

	private static LabelInfo create(final Label label) {
		LabelInfo info = get(label);
		if (info == null) {
			info = new LabelInfo();
			label.info = info;
		}
		return info;
	}

}