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