Home | History | Annotate | Download | only in instr
      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.instr;
     13 
     14 import org.jacoco.core.runtime.IExecutionDataAccessorGenerator;
     15 import org.objectweb.asm.ClassVisitor;
     16 import org.objectweb.asm.Label;
     17 import org.objectweb.asm.MethodVisitor;
     18 import org.objectweb.asm.Opcodes;
     19 
     20 /**
     21  * The strategy for regular classes adds a static field to hold the probe array
     22  * and a static initialization method requesting the probe array from the
     23  * runtime.
     24  */
     25 class ClassFieldProbeArrayStrategy implements IProbeArrayStrategy {
     26 
     27 	/**
     28 	 * Frame stack with a single boolean array.
     29 	 */
     30 	private static final Object[] FRAME_STACK_ARRZ = new Object[] { InstrSupport.DATAFIELD_DESC };
     31 
     32 	/**
     33 	 * Empty frame locals.
     34 	 */
     35 	private static final Object[] FRAME_LOCALS_EMPTY = new Object[0];
     36 
     37 	private final String className;
     38 	private final long classId;
     39 	private final boolean withFrames;
     40 	private final IExecutionDataAccessorGenerator accessorGenerator;
     41 
     42 	ClassFieldProbeArrayStrategy(final String className, final long classId,
     43 			final boolean withFrames,
     44 			final IExecutionDataAccessorGenerator accessorGenerator) {
     45 		this.className = className;
     46 		this.classId = classId;
     47 		this.withFrames = withFrames;
     48 		this.accessorGenerator = accessorGenerator;
     49 	}
     50 
     51 	public int storeInstance(final MethodVisitor mv, final boolean clinit,
     52 			final int variable) {
     53 		mv.visitMethodInsn(Opcodes.INVOKESTATIC, className,
     54 				InstrSupport.INITMETHOD_NAME, InstrSupport.INITMETHOD_DESC,
     55 				false);
     56 		mv.visitVarInsn(Opcodes.ASTORE, variable);
     57 		return 1;
     58 	}
     59 
     60 	public void addMembers(final ClassVisitor cv, final int probeCount) {
     61 		createDataField(cv);
     62 		createInitMethod(cv, probeCount);
     63 	}
     64 
     65 	private void createDataField(final ClassVisitor cv) {
     66 		cv.visitField(InstrSupport.DATAFIELD_ACC, InstrSupport.DATAFIELD_NAME,
     67 				InstrSupport.DATAFIELD_DESC, null, null);
     68 	}
     69 
     70 	private void createInitMethod(final ClassVisitor cv, final int probeCount) {
     71 		final MethodVisitor mv = cv.visitMethod(InstrSupport.INITMETHOD_ACC,
     72 				InstrSupport.INITMETHOD_NAME, InstrSupport.INITMETHOD_DESC,
     73 				null, null);
     74 		mv.visitCode();
     75 
     76 		// Load the value of the static data field:
     77 		mv.visitFieldInsn(Opcodes.GETSTATIC, className,
     78 				InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC);
     79 		mv.visitInsn(Opcodes.DUP);
     80 
     81 		// Stack[1]: [Z
     82 		// Stack[0]: [Z
     83 
     84 		// Skip initialization when we already have a data array:
     85 		final Label alreadyInitialized = new Label();
     86 		mv.visitJumpInsn(Opcodes.IFNONNULL, alreadyInitialized);
     87 
     88 		// Stack[0]: [Z
     89 
     90 		mv.visitInsn(Opcodes.POP);
     91 		final int size = genInitializeDataField(mv, probeCount);
     92 
     93 		// Stack[0]: [Z
     94 
     95 		// Return the class' probe array:
     96 		if (withFrames) {
     97 			mv.visitFrame(Opcodes.F_NEW, 0, FRAME_LOCALS_EMPTY, 1,
     98 					FRAME_STACK_ARRZ);
     99 		}
    100 		mv.visitLabel(alreadyInitialized);
    101 		mv.visitInsn(Opcodes.ARETURN);
    102 
    103 		mv.visitMaxs(Math.max(size, 2), 0); // Maximum local stack size is 2
    104 		mv.visitEnd();
    105 	}
    106 
    107 	/**
    108 	 * Generates the byte code to initialize the static coverage data field
    109 	 * within this class.
    110 	 *
    111 	 * The code will push the [Z data array on the operand stack.
    112 	 *
    113 	 * @param mv
    114 	 *            generator to emit code to
    115 	 */
    116 	private int genInitializeDataField(final MethodVisitor mv,
    117 			final int probeCount) {
    118 		final int size = accessorGenerator.generateDataAccessor(classId,
    119 				className, probeCount, mv);
    120 
    121 		// Stack[0]: [Z
    122 
    123 		mv.visitInsn(Opcodes.DUP);
    124 
    125 		// Stack[1]: [Z
    126 		// Stack[0]: [Z
    127 
    128 		mv.visitFieldInsn(Opcodes.PUTSTATIC, className,
    129 				InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC);
    130 
    131 		// Stack[0]: [Z
    132 
    133 		return Math.max(size, 2); // Maximum local stack size is 2
    134 	}
    135 
    136 }
    137