Java tutorial
/******************************************************************************* * Copyright (c) 2009, 2013 Mountainminds GmbH & Co. KG and Contributors * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marc R. Hoffmann - initial API and implementation * *******************************************************************************/ package org.jacoco.core.internal.instr; import org.jacoco.core.internal.flow.MethodProbesVisitor; import org.jacoco.core.internal.flow.LabelInfo; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * This method adapter inserts probes as requested by the * {@link MethodProbesVisitor} events. */ class MethodInstrumenter extends MethodProbesVisitor { private final IProbeInserter probeInserter; private final IFrameInserter frameInserter; /** * Create a new instrumenter instance for the given method. * * @param mv * next method visitor in the chain * @param probeInserter * call-back to insert probes where required * @param frameInserter * call-back to insert additional frames where required */ public MethodInstrumenter(final MethodVisitor mv, final IProbeInserter probeInserter, final IFrameInserter frameInserter) { super(mv); this.probeInserter = probeInserter; this.frameInserter = frameInserter; } // === IMethodProbesVisitor === @Override public void visitProbe(final int probeId) { probeInserter.insertProbe(probeId); } @Override public void visitInsnWithProbe(final int opcode, final int probeId) { probeInserter.insertProbe(probeId); mv.visitInsn(opcode); } @Override public void visitJumpInsnWithProbe(final int opcode, final Label label, final int probeId) { if (opcode == Opcodes.GOTO) { probeInserter.insertProbe(probeId); mv.visitJumpInsn(Opcodes.GOTO, label); } else { final Label intermediate = new Label(); mv.visitJumpInsn(getInverted(opcode), intermediate); probeInserter.insertProbe(probeId); mv.visitJumpInsn(Opcodes.GOTO, label); mv.visitLabel(intermediate); frameInserter.insertFrame(); } } private int getInverted(final int opcode) { switch (opcode) { case Opcodes.IFEQ: return Opcodes.IFNE; case Opcodes.IFNE: return Opcodes.IFEQ; case Opcodes.IFLT: return Opcodes.IFGE; case Opcodes.IFGE: return Opcodes.IFLT; case Opcodes.IFGT: return Opcodes.IFLE; case Opcodes.IFLE: return Opcodes.IFGT; case Opcodes.IF_ICMPEQ: return Opcodes.IF_ICMPNE; case Opcodes.IF_ICMPNE: return Opcodes.IF_ICMPEQ; case Opcodes.IF_ICMPLT: return Opcodes.IF_ICMPGE; case Opcodes.IF_ICMPGE: return Opcodes.IF_ICMPLT; case Opcodes.IF_ICMPGT: return Opcodes.IF_ICMPLE; case Opcodes.IF_ICMPLE: return Opcodes.IF_ICMPGT; case Opcodes.IF_ACMPEQ: return Opcodes.IF_ACMPNE; case Opcodes.IF_ACMPNE: return Opcodes.IF_ACMPEQ; case Opcodes.IFNULL: return Opcodes.IFNONNULL; case Opcodes.IFNONNULL: return Opcodes.IFNULL; } throw new IllegalArgumentException(); } @Override public void visitTableSwitchInsnWithProbes(final int min, final int max, final Label dflt, final Label[] labels) { // 1. Calculate intermediate labels: LabelInfo.resetDone(dflt); LabelInfo.resetDone(labels); final Label newDflt = createIntermediate(dflt); final Label[] newLabels = createIntermediates(labels); mv.visitTableSwitchInsn(min, max, newDflt, newLabels); // 2. Insert probes: insertIntermediateProbes(dflt, labels); } @Override public void visitLookupSwitchInsnWithProbes(final Label dflt, final int[] keys, final Label[] labels) { // 1. Calculate intermediate labels: LabelInfo.resetDone(dflt); LabelInfo.resetDone(labels); final Label newDflt = createIntermediate(dflt); final Label[] newLabels = createIntermediates(labels); mv.visitLookupSwitchInsn(newDflt, keys, newLabels); // 2. Insert probes: insertIntermediateProbes(dflt, labels); } private Label[] createIntermediates(final Label[] labels) { final Label[] intermediates = new Label[labels.length]; for (int i = 0; i < labels.length; i++) { intermediates[i] = createIntermediate(labels[i]); } return intermediates; } private Label createIntermediate(final Label label) { final Label intermediate; if (LabelInfo.getProbeId(label) == LabelInfo.NO_PROBE) { intermediate = label; } else { if (LabelInfo.isDone(label)) { intermediate = LabelInfo.getIntermediateLabel(label); } else { intermediate = new Label(); LabelInfo.setIntermediateLabel(label, intermediate); LabelInfo.setDone(label); } } return intermediate; } private void insertIntermediateProbe(final Label label) { final int probeId = LabelInfo.getProbeId(label); if (probeId != LabelInfo.NO_PROBE && !LabelInfo.isDone(label)) { mv.visitLabel(LabelInfo.getIntermediateLabel(label)); frameInserter.insertFrame(); probeInserter.insertProbe(probeId); mv.visitJumpInsn(Opcodes.GOTO, label); LabelInfo.setDone(label); } } private void insertIntermediateProbes(final Label dflt, final Label[] labels) { LabelInfo.resetDone(dflt); LabelInfo.resetDone(labels); insertIntermediateProbe(dflt); for (final Label l : labels) { insertIntermediateProbe(l); } } }