SystemPropertiesRuntime.java

    1/*******************************************************************************
    2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and others
    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 * $Id: $
   12 *******************************************************************************/
   13package org.jacoco.core.runtime;
   14
   15import java.util.Map;
   16
   17import org.jacoco.core.instr.GeneratorConstants;
   18import org.objectweb.asm.MethodVisitor;
   19import org.objectweb.asm.Opcodes;
   20
   21/**
   22 * This {@link IRuntime} implementation makes the execution data available
   23 * through a special entry of the type {@link Map} in the
   24 * {@link System#getProperties()} hash table. The advantage is, that the
   25 * instrumented classes do not get dependencies to other classes than the JRE
   26 * library itself.
   27 * 
   28 * This runtime may cause problems in environments with security restrictions,
   29 * in applications that replace the system properties or in applications that
   30 * fail if non-String values are placed in the system properties.
   31 * 
   32 * @author Marc R. Hoffmann
   33 * @version $Revision: $
   34 */
   35public class SystemPropertiesRuntime extends AbstractRuntime {
   36
   37    private static final String KEYPREFIX = "jacoco-";
   38
   39    private final String key;
   40
   41    private final Map<Long, boolean[]> dataAccess = new MapAdapter(store);
   42
   43    /**
   44     * Creates a new runtime.
   45     */
   46    public SystemPropertiesRuntime() {
   47        this.key = KEYPREFIX + hashCode();
   48    }
   49
   50    public int generateDataAccessor(final long classid, final MethodVisitor mv) {
   51
   52        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System",
   53                "getProperties", "()Ljava/util/Properties;");
   54
   55        // Stack[0]: Ljava/util/Properties;
   56
   57        mv.visitLdcInsn(key);
   58
   59        // Stack[1]: Ljava/lang/String;
   60        // Stack[0]: Ljava/util/Properties;
   61
   62        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Properties",
   63                "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
   64
   65        // Stack[0]: Ljava/lang/Object;
   66
   67        mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/Map");
   68
   69        // Stack[0]: Ljava/util/Map;
   70
   71        mv.visitLdcInsn(Long.valueOf(classid));
   72
   73        // Stack[2]: J
   74        // Stack[1]: .
   75        // Stack[0]: Ljava/util/Map;
   76
   77        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf",
   78                "(J)Ljava/lang/Long;");
   79
   80        // Stack[1]: Ljava/lang/Long;
   81        // Stack[0]: Ljava/util/Map;
   82
   83        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Map", "get",
   84                "(Ljava/lang/Object;)Ljava/lang/Object;");
   85
   86        // Stack[0]: Ljava/lang/Object;
   87
   88        mv.visitTypeInsn(Opcodes.CHECKCAST, GeneratorConstants.PROBEDATA_TYPE
   89                .getInternalName());
   90
   91        // Stack[0]: [Z
   92
   93        return 3; // Maximum local stack size is 3
   94    }
   95
   96    public void startup() {
   97        System.getProperties().put(key, dataAccess);
   98    }
   99
  100    public void shutdown() {
  101        System.getProperties().remove(key);
  102    }
  103
  104}