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