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