SystemPropertiesRuntime.java

    1/*******************************************************************************
    2 * Copyright (c) 2009 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.Collection;
   16import java.util.Map;
   17import java.util.Set;
   18
   19import org.jacoco.core.instr.GeneratorConstants;
   20import org.objectweb.asm.Opcodes;
   21import org.objectweb.asm.commons.GeneratorAdapter;
   22
   23/**
   24 * This {@link IRuntime} implementation makes the execution data available
   25 * through a special entry of the type {@link Map} in the
   26 * {@link System#getProperties()} hash table. The advantage is, that the
   27 * instrumented classes do not get dependencies to other classes than the JRE
   28 * library itself.
   29 * 
   30 * This runtime may cause problems in environments with security restrictions,
   31 * in applications that replace the system properties or in applications that
   32 * fail if non-String values are placed in the system properties.
   33 * 
   34 * 
   35 * @author Marc R. Hoffmann
   36 * @version $Revision: $
   37 */
   38public class SystemPropertiesRuntime extends AbstractRuntime {
   39
   40    private static final String KEYPREFIX = "jacoco-";
   41
   42    private final String key;
   43
   44    private final Map<Long, boolean[][]> dataAccess = new Map<Long, boolean[][]>() {
   45
   46        public boolean[][] get(final Object key) {
   47            final Long id = (Long) key;
   48            synchronized (store) {
   49                final boolean[][] blockdata = store.getData(id);
   50                if (blockdata == null) {
   51                    throw new IllegalStateException(String.format(
   52                            "Unknown class id %x.", id));
   53                }
   54                return blockdata;
   55            }
   56        }
   57
   58        public void clear() {
   59            throw new UnsupportedOperationException();
   60        }
   61
   62        public boolean containsKey(final Object key) {
   63            throw new UnsupportedOperationException();
   64        }
   65
   66        public boolean containsValue(final Object value) {
   67            throw new UnsupportedOperationException();
   68        }
   69
   70        public Set<Entry<Long, boolean[][]>> entrySet() {
   71            throw new UnsupportedOperationException();
   72        }
   73
   74        public boolean isEmpty() {
   75            throw new UnsupportedOperationException();
   76        }
   77
   78        public Set<Long> keySet() {
   79            throw new UnsupportedOperationException();
   80        }
   81
   82        public boolean[][] put(final Long key, final boolean[][] value) {
   83            throw new UnsupportedOperationException();
   84        }
   85
   86        public void putAll(final Map<? extends Long, ? extends boolean[][]> t) {
   87            throw new UnsupportedOperationException();
   88        }
   89
   90        public boolean[][] remove(final Object key) {
   91            throw new UnsupportedOperationException();
   92        }
   93
   94        public Collection<boolean[][]> values() {
   95            throw new UnsupportedOperationException();
   96        }
   97
   98        public int size() {
   99            throw new UnsupportedOperationException();
  100        }
  101    };
  102
  103    /**
  104     * Creates a new runtime.
  105     */
  106    public SystemPropertiesRuntime() {
  107        this.key = KEYPREFIX + hashCode();
  108    }
  109
  110    public int generateDataAccessor(final long classid,
  111            final GeneratorAdapter gen) {
  112
  113        gen.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System",
  114                "getProperties", "()Ljava/util/Properties;");
  115
  116        // Stack[0]: Ljava/util/Properties;
  117
  118        gen.push(key);
  119
  120        // Stack[1]: Ljava/lang/String;
  121        // Stack[0]: Ljava/util/Properties;
  122
  123        gen.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Properties",
  124                "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
  125
  126        // Stack[0]: Ljava/lang/Object;
  127
  128        gen.visitTypeInsn(Opcodes.CHECKCAST, "java/util/Map");
  129
  130        // Stack[0]: Ljava/util/Map;
  131
  132        gen.push(classid);
  133
  134        // Stack[2]: J
  135        // Stack[1]: .
  136        // Stack[0]: Ljava/util/Map;
  137
  138        gen.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf",
  139                "(J)Ljava/lang/Long;");
  140
  141        // Stack[1]: Ljava/lang/Long;
  142        // Stack[0]: Ljava/util/Map;
  143
  144        gen.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Map", "get",
  145                "(Ljava/lang/Object;)Ljava/lang/Object;");
  146
  147        // Stack[0]: Ljava/lang/Object;
  148
  149        gen.checkCast(GeneratorConstants.DATAFIELD_TYPE);
  150
  151        // Stack[0]: [[Z
  152
  153        return 3; // Maximum local stack size is 3
  154    }
  155
  156    public void startup() {
  157        System.getProperties().put(key, dataAccess);
  158    }
  159
  160    public void shutdown() {
  161        System.getProperties().remove(key);
  162    }
  163
  164}