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