LabelFlowAnalyzer.java revision e4a474ce30af55463d114b5c18c9b59eadbef00b
1/******************************************************************************* 2 * Copyright (c) 2009, 2014 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 *******************************************************************************/ 12package org.jacoco.core.internal.flow; 13 14import org.jacoco.core.JaCoCo; 15import org.objectweb.asm.Handle; 16import org.objectweb.asm.Label; 17import org.objectweb.asm.MethodVisitor; 18import org.objectweb.asm.Opcodes; 19import org.objectweb.asm.tree.MethodNode; 20 21/** 22 * Method visitor to collect flow related information about the {@link Label}s 23 * within a class. It calculates the properties "multitarget" and "successor" 24 * that can afterwards be obtained via {@link LabelInfo}. 25 */ 26public final class LabelFlowAnalyzer extends MethodVisitor { 27 28 /** 29 * Marks all labels of the method with control flow information. 30 * 31 * @param method 32 * Method to mark labels 33 */ 34 public static void markLabels(final MethodNode method) { 35 method.instructions.accept(new LabelFlowAnalyzer()); 36 } 37 38 /** 39 * <code>true</code> if the current instruction is a potential successor of 40 * the previous instruction. Accessible for testing. 41 */ 42 boolean successor = false; 43 44 /** 45 * <code>true</code> for the very first instruction only. Accessible for 46 * testing. 47 */ 48 boolean first = true; 49 50 /** 51 * Create new instance. 52 */ 53 public LabelFlowAnalyzer() { 54 super(JaCoCo.ASM_API_VERSION); 55 } 56 57 @Override 58 public void visitJumpInsn(final int opcode, final Label label) { 59 LabelInfo.setTarget(label); 60 if (opcode == Opcodes.JSR) { 61 throw new AssertionError("Subroutines not supported."); 62 } 63 successor = opcode != Opcodes.GOTO; 64 first = false; 65 } 66 67 @Override 68 public void visitLabel(final Label label) { 69 if (first) { 70 LabelInfo.setTarget(label); 71 } 72 if (successor) { 73 LabelInfo.setSuccessor(label); 74 } 75 } 76 77 @Override 78 public void visitTableSwitchInsn(final int min, final int max, 79 final Label dflt, final Label... labels) { 80 visitSwitchInsn(dflt, labels); 81 } 82 83 @Override 84 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, 85 final Label[] labels) { 86 visitSwitchInsn(dflt, labels); 87 } 88 89 private void visitSwitchInsn(final Label dflt, final Label[] labels) { 90 LabelInfo.resetDone(dflt); 91 LabelInfo.resetDone(labels); 92 setTargetIfNotDone(dflt); 93 for (final Label l : labels) { 94 setTargetIfNotDone(l); 95 } 96 successor = false; 97 first = false; 98 } 99 100 private static void setTargetIfNotDone(final Label label) { 101 if (!LabelInfo.isDone(label)) { 102 LabelInfo.setTarget(label); 103 LabelInfo.setDone(label); 104 } 105 } 106 107 @Override 108 public void visitInsn(final int opcode) { 109 switch (opcode) { 110 case Opcodes.RET: 111 throw new AssertionError("Subroutines not supported."); 112 case Opcodes.IRETURN: 113 case Opcodes.LRETURN: 114 case Opcodes.FRETURN: 115 case Opcodes.DRETURN: 116 case Opcodes.ARETURN: 117 case Opcodes.RETURN: 118 case Opcodes.ATHROW: 119 successor = false; 120 break; 121 default: 122 successor = true; 123 break; 124 } 125 first = false; 126 } 127 128 @Override 129 public void visitIntInsn(final int opcode, final int operand) { 130 successor = true; 131 first = false; 132 } 133 134 @Override 135 public void visitVarInsn(final int opcode, final int var) { 136 successor = true; 137 first = false; 138 } 139 140 @Override 141 public void visitTypeInsn(final int opcode, final String type) { 142 successor = true; 143 first = false; 144 } 145 146 @Override 147 public void visitFieldInsn(final int opcode, final String owner, 148 final String name, final String desc) { 149 successor = true; 150 first = false; 151 } 152 153 @Override 154 public void visitMethodInsn(final int opcode, final String owner, 155 final String name, final String desc, final boolean itf) { 156 successor = true; 157 first = false; 158 } 159 160 @Override 161 public void visitInvokeDynamicInsn(final String name, final String desc, 162 final Handle bsm, final Object... bsmArgs) { 163 successor = true; 164 first = false; 165 } 166 167 @Override 168 public void visitLdcInsn(final Object cst) { 169 successor = true; 170 first = false; 171 } 172 173 @Override 174 public void visitIincInsn(final int var, final int increment) { 175 successor = true; 176 first = false; 177 } 178 179 @Override 180 public void visitMultiANewArrayInsn(final String desc, final int dims) { 181 successor = true; 182 first = false; 183 } 184 185} 186