1 /******************************************************************************* 2 * Copyright (c) 2009, 2015 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.instr; 13 14 import org.jacoco.core.internal.flow.IFrame; 15 import org.jacoco.core.internal.flow.LabelInfo; 16 import org.jacoco.core.internal.flow.MethodProbesVisitor; 17 import org.objectweb.asm.Label; 18 import org.objectweb.asm.MethodVisitor; 19 import org.objectweb.asm.Opcodes; 20 21 /** 22 * This method adapter inserts probes as requested by the 23 * {@link MethodProbesVisitor} events. 24 */ 25 class MethodInstrumenter extends MethodProbesVisitor { 26 27 private final IProbeInserter probeInserter; 28 29 /** 30 * Create a new instrumenter instance for the given method. 31 * 32 * @param mv 33 * next method visitor in the chain 34 * @param probeInserter 35 * call-back to insert probes where required 36 */ MethodInstrumenter(final MethodVisitor mv, final IProbeInserter probeInserter)37 public MethodInstrumenter(final MethodVisitor mv, 38 final IProbeInserter probeInserter) { 39 super(mv); 40 this.probeInserter = probeInserter; 41 } 42 43 // === IMethodProbesVisitor === 44 45 @Override visitProbe(final int probeId)46 public void visitProbe(final int probeId) { 47 probeInserter.insertProbe(probeId); 48 } 49 50 @Override visitInsnWithProbe(final int opcode, final int probeId)51 public void visitInsnWithProbe(final int opcode, final int probeId) { 52 probeInserter.insertProbe(probeId); 53 mv.visitInsn(opcode); 54 } 55 56 @Override visitJumpInsnWithProbe(final int opcode, final Label label, final int probeId, final IFrame frame)57 public void visitJumpInsnWithProbe(final int opcode, final Label label, 58 final int probeId, final IFrame frame) { 59 if (opcode == Opcodes.GOTO) { 60 probeInserter.insertProbe(probeId); 61 mv.visitJumpInsn(Opcodes.GOTO, label); 62 } else { 63 final Label intermediate = new Label(); 64 mv.visitJumpInsn(getInverted(opcode), intermediate); 65 probeInserter.insertProbe(probeId); 66 mv.visitJumpInsn(Opcodes.GOTO, label); 67 mv.visitLabel(intermediate); 68 frame.accept(mv); 69 } 70 } 71 getInverted(final int opcode)72 private int getInverted(final int opcode) { 73 switch (opcode) { 74 case Opcodes.IFEQ: 75 return Opcodes.IFNE; 76 case Opcodes.IFNE: 77 return Opcodes.IFEQ; 78 case Opcodes.IFLT: 79 return Opcodes.IFGE; 80 case Opcodes.IFGE: 81 return Opcodes.IFLT; 82 case Opcodes.IFGT: 83 return Opcodes.IFLE; 84 case Opcodes.IFLE: 85 return Opcodes.IFGT; 86 case Opcodes.IF_ICMPEQ: 87 return Opcodes.IF_ICMPNE; 88 case Opcodes.IF_ICMPNE: 89 return Opcodes.IF_ICMPEQ; 90 case Opcodes.IF_ICMPLT: 91 return Opcodes.IF_ICMPGE; 92 case Opcodes.IF_ICMPGE: 93 return Opcodes.IF_ICMPLT; 94 case Opcodes.IF_ICMPGT: 95 return Opcodes.IF_ICMPLE; 96 case Opcodes.IF_ICMPLE: 97 return Opcodes.IF_ICMPGT; 98 case Opcodes.IF_ACMPEQ: 99 return Opcodes.IF_ACMPNE; 100 case Opcodes.IF_ACMPNE: 101 return Opcodes.IF_ACMPEQ; 102 case Opcodes.IFNULL: 103 return Opcodes.IFNONNULL; 104 case Opcodes.IFNONNULL: 105 return Opcodes.IFNULL; 106 } 107 throw new IllegalArgumentException(); 108 } 109 110 @Override visitTableSwitchInsnWithProbes(final int min, final int max, final Label dflt, final Label[] labels, final IFrame frame)111 public void visitTableSwitchInsnWithProbes(final int min, final int max, 112 final Label dflt, final Label[] labels, final IFrame frame) { 113 // 1. Calculate intermediate labels: 114 LabelInfo.resetDone(dflt); 115 LabelInfo.resetDone(labels); 116 final Label newDflt = createIntermediate(dflt); 117 final Label[] newLabels = createIntermediates(labels); 118 mv.visitTableSwitchInsn(min, max, newDflt, newLabels); 119 120 // 2. Insert probes: 121 insertIntermediateProbes(dflt, labels, frame); 122 } 123 124 @Override visitLookupSwitchInsnWithProbes(final Label dflt, final int[] keys, final Label[] labels, final IFrame frame)125 public void visitLookupSwitchInsnWithProbes(final Label dflt, 126 final int[] keys, final Label[] labels, final IFrame frame) { 127 // 1. Calculate intermediate labels: 128 LabelInfo.resetDone(dflt); 129 LabelInfo.resetDone(labels); 130 final Label newDflt = createIntermediate(dflt); 131 final Label[] newLabels = createIntermediates(labels); 132 mv.visitLookupSwitchInsn(newDflt, keys, newLabels); 133 134 // 2. Insert probes: 135 insertIntermediateProbes(dflt, labels, frame); 136 } 137 createIntermediates(final Label[] labels)138 private Label[] createIntermediates(final Label[] labels) { 139 final Label[] intermediates = new Label[labels.length]; 140 for (int i = 0; i < labels.length; i++) { 141 intermediates[i] = createIntermediate(labels[i]); 142 } 143 return intermediates; 144 } 145 createIntermediate(final Label label)146 private Label createIntermediate(final Label label) { 147 final Label intermediate; 148 if (LabelInfo.getProbeId(label) == LabelInfo.NO_PROBE) { 149 intermediate = label; 150 } else { 151 if (LabelInfo.isDone(label)) { 152 intermediate = LabelInfo.getIntermediateLabel(label); 153 } else { 154 intermediate = new Label(); 155 LabelInfo.setIntermediateLabel(label, intermediate); 156 LabelInfo.setDone(label); 157 } 158 } 159 return intermediate; 160 } 161 insertIntermediateProbe(final Label label, final IFrame frame)162 private void insertIntermediateProbe(final Label label, final IFrame frame) { 163 final int probeId = LabelInfo.getProbeId(label); 164 if (probeId != LabelInfo.NO_PROBE && !LabelInfo.isDone(label)) { 165 mv.visitLabel(LabelInfo.getIntermediateLabel(label)); 166 frame.accept(mv); 167 probeInserter.insertProbe(probeId); 168 mv.visitJumpInsn(Opcodes.GOTO, label); 169 LabelInfo.setDone(label); 170 } 171 } 172 insertIntermediateProbes(final Label dflt, final Label[] labels, final IFrame frame)173 private void insertIntermediateProbes(final Label dflt, 174 final Label[] labels, final IFrame frame) { 175 LabelInfo.resetDone(dflt); 176 LabelInfo.resetDone(labels); 177 insertIntermediateProbe(dflt, frame); 178 for (final Label l : labels) { 179 insertIntermediateProbe(l, frame); 180 } 181 } 182 183 } 184