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 java.util.HashMap; 15 import java.util.Map; 16 17 import org.jacoco.core.internal.instr.InstrSupport; 18 import org.objectweb.asm.Label; 19 import org.objectweb.asm.MethodVisitor; 20 import org.objectweb.asm.Opcodes; 21 import org.objectweb.asm.commons.AnalyzerAdapter; 22 23 /** 24 * Adapter that creates additional visitor events for probes to be inserted into 25 * a method. 26 */ 27 public final class MethodProbesAdapter extends MethodVisitor { 28 29 private final MethodProbesVisitor probesVisitor; 30 31 private final IProbeIdGenerator idGenerator; 32 33 private AnalyzerAdapter analyzer; 34 35 private final Map<Label, Label> tryCatchProbeLabels; 36 37 /** 38 * Create a new adapter instance. 39 * 40 * @param probesVisitor 41 * visitor to delegate to 42 * @param idGenerator 43 * generator for unique probe ids 44 */ MethodProbesAdapter(final MethodProbesVisitor probesVisitor, final IProbeIdGenerator idGenerator)45 public MethodProbesAdapter(final MethodProbesVisitor probesVisitor, 46 final IProbeIdGenerator idGenerator) { 47 super(InstrSupport.ASM_API_VERSION, probesVisitor); 48 this.probesVisitor = probesVisitor; 49 this.idGenerator = idGenerator; 50 this.tryCatchProbeLabels = new HashMap<Label, Label>(); 51 } 52 53 /** 54 * If an analyzer is set {@link IFrame} handles are calculated and emitted 55 * to the probes methods. 56 * 57 * @param analyzer 58 * optional analyzer to set 59 */ setAnalyzer(final AnalyzerAdapter analyzer)60 public void setAnalyzer(final AnalyzerAdapter analyzer) { 61 this.analyzer = analyzer; 62 } 63 64 @Override visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type)65 public void visitTryCatchBlock(final Label start, final Label end, 66 final Label handler, final String type) { 67 probesVisitor.visitTryCatchBlock(getTryCatchLabel(start), getTryCatchLabel(end), 68 handler, type); 69 } 70 getTryCatchLabel(Label label)71 private Label getTryCatchLabel(Label label) { 72 if (tryCatchProbeLabels.containsKey(label)) { 73 label = tryCatchProbeLabels.get(label); 74 } else if (LabelInfo.needsProbe(label)) { 75 // If a probe will be inserted before the label, we'll need to use a 76 // different label to define the range of the try-catch block. 77 final Label probeLabel = new Label(); 78 LabelInfo.setSuccessor(probeLabel); 79 tryCatchProbeLabels.put(label, probeLabel); 80 label = probeLabel; 81 } 82 return label; 83 } 84 85 @Override visitLabel(final Label label)86 public void visitLabel(final Label label) { 87 if (LabelInfo.needsProbe(label)) { 88 if (tryCatchProbeLabels.containsKey(label)) { 89 probesVisitor.visitLabel(tryCatchProbeLabels.get(label)); 90 } 91 probesVisitor.visitProbe(idGenerator.nextId()); 92 } 93 probesVisitor.visitLabel(label); 94 } 95 96 @Override visitInsn(final int opcode)97 public void visitInsn(final int opcode) { 98 switch (opcode) { 99 case Opcodes.IRETURN: 100 case Opcodes.LRETURN: 101 case Opcodes.FRETURN: 102 case Opcodes.DRETURN: 103 case Opcodes.ARETURN: 104 case Opcodes.RETURN: 105 case Opcodes.ATHROW: 106 probesVisitor.visitInsnWithProbe(opcode, idGenerator.nextId()); 107 break; 108 default: 109 probesVisitor.visitInsn(opcode); 110 break; 111 } 112 } 113 114 @Override visitJumpInsn(final int opcode, final Label label)115 public void visitJumpInsn(final int opcode, final Label label) { 116 if (LabelInfo.isMultiTarget(label)) { 117 probesVisitor.visitJumpInsnWithProbe(opcode, label, 118 idGenerator.nextId(), frame(jumpPopCount(opcode))); 119 } else { 120 probesVisitor.visitJumpInsn(opcode, label); 121 } 122 } 123 jumpPopCount(final int opcode)124 private int jumpPopCount(final int opcode) { 125 switch (opcode) { 126 case Opcodes.GOTO: 127 return 0; 128 case Opcodes.IFEQ: 129 case Opcodes.IFNE: 130 case Opcodes.IFLT: 131 case Opcodes.IFGE: 132 case Opcodes.IFGT: 133 case Opcodes.IFLE: 134 case Opcodes.IFNULL: 135 case Opcodes.IFNONNULL: 136 return 1; 137 default: // IF_CMPxx and IF_ACMPxx 138 return 2; 139 } 140 } 141 142 @Override visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)143 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, 144 final Label[] labels) { 145 if (markLabels(dflt, labels)) { 146 probesVisitor.visitLookupSwitchInsnWithProbes(dflt, keys, labels, 147 frame(1)); 148 } else { 149 probesVisitor.visitLookupSwitchInsn(dflt, keys, labels); 150 } 151 } 152 153 @Override visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels)154 public void visitTableSwitchInsn(final int min, final int max, 155 final Label dflt, final Label... labels) { 156 if (markLabels(dflt, labels)) { 157 probesVisitor.visitTableSwitchInsnWithProbes(min, max, dflt, 158 labels, frame(1)); 159 } else { 160 probesVisitor.visitTableSwitchInsn(min, max, dflt, labels); 161 } 162 } 163 markLabels(final Label dflt, final Label[] labels)164 private boolean markLabels(final Label dflt, final Label[] labels) { 165 boolean probe = false; 166 LabelInfo.resetDone(labels); 167 if (LabelInfo.isMultiTarget(dflt)) { 168 LabelInfo.setProbeId(dflt, idGenerator.nextId()); 169 probe = true; 170 } 171 LabelInfo.setDone(dflt); 172 for (final Label l : labels) { 173 if (LabelInfo.isMultiTarget(l) && !LabelInfo.isDone(l)) { 174 LabelInfo.setProbeId(l, idGenerator.nextId()); 175 probe = true; 176 } 177 LabelInfo.setDone(l); 178 } 179 return probe; 180 } 181 frame(final int popCount)182 private IFrame frame(final int popCount) { 183 return FrameSnapshot.create(analyzer, popCount); 184 } 185 186 } 187