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 static java.lang.String.format;
     15 
     16 import org.objectweb.asm.MethodVisitor;
     17 import org.objectweb.asm.Opcodes;
     18 
     19 /**
     20  * Constants and utilities for byte code instrumentation.
     21  */
     22 public final class InstrSupport {
     23 
     24 	private InstrSupport() {
     25 	}
     26 
     27 	/** ASM API version */
     28 	public static final int ASM_API_VERSION = Opcodes.ASM6;
     29 
     30 	// === Data Field ===
     31 
     32 	/**
     33 	 * Name of the field that stores coverage information of a class.
     34 	 */
     35 	public static final String DATAFIELD_NAME = "$jacocoData";
     36 
     37 	/**
     38 	 * Access modifiers of the field that stores coverage information of a
     39 	 * class.
     40 	 *
     41 	 * According to Java Virtual Machine Specification <a href=
     42 	 * "https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.putstatic">
     43 	 * 6.5.putstatic</a> this field must not be final:
     44 	 *
     45 	 * <blockquote>
     46 	 * <p>
     47 	 * if the field is final, it must be declared in the current class, and the
     48 	 * instruction must occur in the {@code <clinit>} method of the current
     49 	 * class.
     50 	 * </p>
     51 	 * </blockquote>
     52 	 */
     53 	public static final int DATAFIELD_ACC = Opcodes.ACC_SYNTHETIC
     54 			| Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT;
     55 
     56 	/**
     57 	 * Access modifiers of the field that stores coverage information of a Java
     58 	 * 8 interface.
     59 	 *
     60 	 * According to Java Virtual Machine Specification <a href=
     61 	 * "https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5-200-A.3">
     62 	 * 4.5</a>:
     63 	 *
     64 	 * <blockquote>
     65 	 * <p>
     66 	 * Fields of interfaces must have their ACC_PUBLIC, ACC_STATIC, and
     67 	 * ACC_FINAL flags set; they may have their ACC_SYNTHETIC flag set and must
     68 	 * not have any of the other flags.
     69 	 * </p>
     70 	 * </blockquote>
     71 	 */
     72 	public static final int DATAFIELD_INTF_ACC = Opcodes.ACC_SYNTHETIC
     73 			| Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
     74 
     75 	/**
     76 	 * Data type of the field that stores coverage information for a class (
     77 	 * <code>boolean[]</code>).
     78 	 */
     79 	public static final String DATAFIELD_DESC = "[Z";
     80 
     81 	// === Init Method ===
     82 
     83 	/**
     84 	 * Name of the initialization method.
     85 	 */
     86 	public static final String INITMETHOD_NAME = "$jacocoInit";
     87 
     88 	/**
     89 	 * Descriptor of the initialization method.
     90 	 */
     91 	public static final String INITMETHOD_DESC = "()[Z";
     92 
     93 	/**
     94 	 * Access modifiers of the initialization method.
     95 	 */
     96 	public static final int INITMETHOD_ACC = Opcodes.ACC_SYNTHETIC
     97 			| Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;
     98 
     99 	/**
    100 	 * Name of the interface initialization method.
    101 	 *
    102 	 * According to Java Virtual Machine Specification <a href=
    103 	 * "https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9-200">
    104 	 * 2.9</a>:
    105 	 *
    106 	 * <blockquote>
    107 	 * <p>
    108 	 * A class or interface has at most one class or interface initialization
    109 	 * method and is initialized by invoking that method. The initialization
    110 	 * method of a class or interface has the special name {@code <clinit>},
    111 	 * takes no arguments, and is void.
    112 	 * </p>
    113 	 * <p>
    114 	 * Other methods named {@code <clinit>} in a class file are of no
    115 	 * consequence. They are not class or interface initialization methods. They
    116 	 * cannot be invoked by any Java Virtual Machine instruction and are never
    117 	 * invoked by the Java Virtual Machine itself.
    118 	 * </p>
    119 	 * <p>
    120 	 * In a class file whose version number is 51.0 or above, the method must
    121 	 * additionally have its ACC_STATIC flag set in order to be the class or
    122 	 * interface initialization method.
    123 	 * </p>
    124 	 * <p>
    125 	 * This requirement was introduced in Java SE 7. In a class file whose
    126 	 * version number is 50.0 or below, a method named {@code <clinit>} that is
    127 	 * void and takes no arguments is considered the class or interface
    128 	 * initialization method regardless of the setting of its ACC_STATIC flag.
    129 	 * </p>
    130 	 * </blockquote>
    131 	 *
    132 	 * And <a href=
    133 	 * "https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6-200-A.6">
    134 	 * 4.6</a>:
    135 	 *
    136 	 * <blockquote>
    137 	 * <p>
    138 	 * Class and interface initialization methods are called implicitly by the
    139 	 * Java Virtual Machine. The value of their access_flags item is ignored
    140 	 * except for the setting of the ACC_STRICT flag.
    141 	 * </p>
    142 	 * </blockquote>
    143 	 */
    144 	static final String CLINIT_NAME = "<clinit>";
    145 
    146 	/**
    147 	 * Descriptor of the interface initialization method.
    148 	 *
    149 	 * @see #CLINIT_NAME
    150 	 */
    151 	static final String CLINIT_DESC = "()V";
    152 
    153 	/**
    154 	 * Access flags of the interface initialization method generated by JaCoCo.
    155 	 *
    156 	 * @see #CLINIT_NAME
    157 	 */
    158 	static final int CLINIT_ACC = Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC;
    159 
    160 	/**
    161 	 * Ensures that the given member does not correspond to a internal member
    162 	 * created by the instrumentation process. This would mean that the class is
    163 	 * already instrumented.
    164 	 *
    165 	 * @param member
    166 	 *            name of the member to check
    167 	 * @param owner
    168 	 *            name of the class owning the member
    169 	 * @throws IllegalStateException
    170 	 *             thrown if the member has the same name than the
    171 	 *             instrumentation member
    172 	 */
    173 	public static void assertNotInstrumented(final String member,
    174 			final String owner) throws IllegalStateException {
    175 		if (member.equals(DATAFIELD_NAME) || member.equals(INITMETHOD_NAME)) {
    176 			throw new IllegalStateException(format(
    177 					"Class %s is already instrumented.", owner));
    178 		}
    179 	}
    180 
    181 	/**
    182 	 * Generates the instruction to push the given int value on the stack.
    183 	 * Implementation taken from
    184 	 * {@link org.objectweb.asm.commons.GeneratorAdapter#push(int)}.
    185 	 *
    186 	 * @param mv
    187 	 *            visitor to emit the instruction
    188 	 * @param value
    189 	 *            the value to be pushed on the stack.
    190 	 */
    191 	public static void push(final MethodVisitor mv, final int value) {
    192 		if (value >= -1 && value <= 5) {
    193 			mv.visitInsn(Opcodes.ICONST_0 + value);
    194 		} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
    195 			mv.visitIntInsn(Opcodes.BIPUSH, value);
    196 		} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
    197 			mv.visitIntInsn(Opcodes.SIPUSH, value);
    198 		} else {
    199 			mv.visitLdcInsn(Integer.valueOf(value));
    200 		}
    201 	}
    202 
    203 }
    204