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