• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors
3  * This program and the accompanying materials are made available under
4  * the terms of the Eclipse Public License 2.0 which is available at
5  * http://www.eclipse.org/legal/epl-2.0
6  *
7  * SPDX-License-Identifier: EPL-2.0
8  *
9  * Contributors:
10  *    Marc R. Hoffmann - initial API and implementation
11  *
12  *******************************************************************************/
13 package org.jacoco.core.internal.flow;
14 
15 import org.jacoco.core.internal.analysis.Instruction;
16 import org.objectweb.asm.Label;
17 
18 /**
19  * Data container that is attached to {@link Label#info} objects to store flow
20  * and instrumentation specific information. The information is only valid
21  * locally in specific contexts.
22  */
23 public final class LabelInfo {
24 
25 	/**
26 	 * Reserved ID for "no probe".
27 	 */
28 	public static final int NO_PROBE = -1;
29 
30 	private boolean target = false;
31 
32 	private boolean multiTarget = false;
33 
34 	private boolean successor = false;
35 
36 	private boolean methodInvocationLine = false;
37 
38 	private boolean done = false;
39 
40 	private int probeid = NO_PROBE;
41 
42 	private Label intermediate = null;
43 
44 	private Instruction instruction = null;
45 
46 	// instances are only created within this class
LabelInfo()47 	private LabelInfo() {
48 	}
49 
50 	/**
51 	 * Defines that the given label is a jump target.
52 	 *
53 	 * @param label
54 	 *            label to define
55 	 */
setTarget(final Label label)56 	public static void setTarget(final Label label) {
57 		final LabelInfo info = create(label);
58 		if (info.target || info.successor) {
59 			info.multiTarget = true;
60 		} else {
61 			info.target = true;
62 		}
63 	}
64 
65 	/**
66 	 * Defines that the given label is the possible successor of the previous
67 	 * instruction in the method.
68 	 *
69 	 * @param label
70 	 *            label to define
71 	 */
setSuccessor(final Label label)72 	public static void setSuccessor(final Label label) {
73 		final LabelInfo info = create(label);
74 		info.successor = true;
75 		if (info.target) {
76 			info.multiTarget = true;
77 		}
78 	}
79 
80 	/**
81 	 * Checks whether multiple control paths lead to a label. Control flow path
82 	 * to a certain label are: jump targets, exception handlers and normal
83 	 * control flow from its predecessor instruction (unless this is an
84 	 * unconditional jump or method exit).
85 	 *
86 	 * @param label
87 	 *            label to check
88 	 * @return <code>true</code> if the given multiple control paths lead to the
89 	 *         given label
90 	 */
isMultiTarget(final Label label)91 	public static boolean isMultiTarget(final Label label) {
92 		final LabelInfo info = get(label);
93 		return info == null ? false : info.multiTarget;
94 	}
95 
96 	/**
97 	 * Checks whether this label is the possible successor of the previous
98 	 * instruction in the method. This is the case if the predecessor isn't a
99 	 * unconditional jump or method exit instruction.
100 	 *
101 	 * @param label
102 	 *            label to check
103 	 * @return <code>true</code> if the label is a possible instruction
104 	 *         successor
105 	 */
isSuccessor(final Label label)106 	public static boolean isSuccessor(final Label label) {
107 		final LabelInfo info = get(label);
108 		return info == null ? false : info.successor;
109 	}
110 
111 	/**
112 	 * Mark a given label as the beginning of a line with method invocations.
113 	 *
114 	 * @param label
115 	 *            label to mark
116 	 */
setMethodInvocationLine(final Label label)117 	public static void setMethodInvocationLine(final Label label) {
118 		create(label).methodInvocationLine = true;
119 	}
120 
121 	/**
122 	 * Checks whether the a given label has been marked as a line with method
123 	 * invocations.
124 	 *
125 	 * @param label
126 	 *            label to check
127 	 * @return <code>true</code> if the label represents a line with method
128 	 *         invocations
129 	 */
isMethodInvocationLine(final Label label)130 	public static boolean isMethodInvocationLine(final Label label) {
131 		final LabelInfo info = get(label);
132 		return info == null ? false : info.methodInvocationLine;
133 	}
134 
135 	/**
136 	 * Determines whether the given label needs a probe to be inserted before.
137 	 *
138 	 * @param label
139 	 *            label to test
140 	 * @return <code>true</code> if a probe should be inserted before
141 	 */
needsProbe(final Label label)142 	public static boolean needsProbe(final Label label) {
143 		final LabelInfo info = get(label);
144 		return info != null && info.successor
145 				&& (info.multiTarget || info.methodInvocationLine);
146 	}
147 
148 	/**
149 	 * Mark a given label as done.
150 	 *
151 	 * @param label
152 	 *            label to mark
153 	 */
setDone(final Label label)154 	public static void setDone(final Label label) {
155 		create(label).done = true;
156 	}
157 
158 	/**
159 	 * Resets the "done" status of a given label.
160 	 *
161 	 * @param label
162 	 *            label to reset
163 	 */
resetDone(final Label label)164 	public static void resetDone(final Label label) {
165 		final LabelInfo info = get(label);
166 		if (info != null) {
167 			info.done = false;
168 		}
169 	}
170 
171 	/**
172 	 * Resets the "done" status of all given labels.
173 	 *
174 	 * @param labels
175 	 *            labels to reset
176 	 */
resetDone(final Label[] labels)177 	public static void resetDone(final Label[] labels) {
178 		for (final Label label : labels) {
179 			resetDone(label);
180 		}
181 	}
182 
183 	/**
184 	 * Checks whether this label is marked as done.
185 	 *
186 	 * @param label
187 	 *            label to check
188 	 * @return <code>true</code> if this label is marked as done
189 	 */
isDone(final Label label)190 	public static boolean isDone(final Label label) {
191 		final LabelInfo info = get(label);
192 		return info == null ? false : info.done;
193 	}
194 
195 	/**
196 	 * Sets the given probe id to the given label.
197 	 *
198 	 * @param label
199 	 *            label to assign a probe to
200 	 * @param id
201 	 *            id of the probe
202 	 */
setProbeId(final Label label, final int id)203 	public static void setProbeId(final Label label, final int id) {
204 		create(label).probeid = id;
205 	}
206 
207 	/**
208 	 * Returns the assigned probe id.
209 	 *
210 	 * @param label
211 	 *            label to check
212 	 * @return probe id or {@link #NO_PROBE} if no probe is assigned to the
213 	 *         label
214 	 */
getProbeId(final Label label)215 	public static int getProbeId(final Label label) {
216 		final LabelInfo info = get(label);
217 		return info == null ? NO_PROBE : info.probeid;
218 	}
219 
220 	/**
221 	 * Defines an intermediate label for the given label. Such intermediate
222 	 * labels are required during instrumentation to add probes to jump targets.
223 	 *
224 	 * @param label
225 	 *            label to define for
226 	 * @param intermediate
227 	 *            intermediate label
228 	 */
setIntermediateLabel(final Label label, final Label intermediate)229 	public static void setIntermediateLabel(final Label label,
230 			final Label intermediate) {
231 		create(label).intermediate = intermediate;
232 	}
233 
234 	/**
235 	 * Returns the intermediate label for the given label if one has been
236 	 * defined.
237 	 *
238 	 * @param label
239 	 *            label to look for
240 	 * @return intermediate label or <code>null</code>
241 	 */
getIntermediateLabel(final Label label)242 	public static Label getIntermediateLabel(final Label label) {
243 		final LabelInfo info = get(label);
244 		return info == null ? null : info.intermediate;
245 	}
246 
247 	/**
248 	 * Sets the instruction corresponding to this label.
249 	 *
250 	 * @param label
251 	 *            label to set the instruction for
252 	 * @param instruction
253 	 *            corresponding instruction
254 	 */
setInstruction(final Label label, final Instruction instruction)255 	public static void setInstruction(final Label label,
256 			final Instruction instruction) {
257 		create(label).instruction = instruction;
258 	}
259 
260 	/**
261 	 * Returns the corresponding instruction for the given label if one has been
262 	 * defined.
263 	 *
264 	 * @param label
265 	 *            label to look for
266 	 * @return corresponding instruction or <code>null</code>
267 	 */
getInstruction(final Label label)268 	public static Instruction getInstruction(final Label label) {
269 		final LabelInfo info = get(label);
270 		return info == null ? null : info.instruction;
271 	}
272 
get(final Label label)273 	private static LabelInfo get(final Label label) {
274 		final Object info = label.info;
275 		return info instanceof LabelInfo ? (LabelInfo) info : null;
276 	}
277 
create(final Label label)278 	private static LabelInfo create(final Label label) {
279 		LabelInfo info = get(label);
280 		if (info == null) {
281 			info = new LabelInfo();
282 			label.info = info;
283 		}
284 		return info;
285 	}
286 
287 }
288