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 * @author Marc R. Hoffmann
35 * @version $Revision: $
36 */
37public class SystemPropertiesRuntime extends AbstractRuntime {
38
39 private static final String KEYPREFIX = "jacoco-";
40
41 private final String key;
42
43 private final Map<Long, boolean[]> dataAccess = new Map<Long, boolean[]>() {
44
45 public boolean[] get(final Object key) {
46 final Long id = (Long) key;
47 synchronized (store) {
48 final boolean[] data = store.getData(id);
49 if (data == null) {
50 throw new IllegalStateException(String.format(
51 "Unknown class id %x.", id));
52 }
53 return data;
54 }
55 }
56
57 public void clear() {
58 throw new UnsupportedOperationException();
59 }
60
61 public boolean containsKey(final Object key) {
62 throw new UnsupportedOperationException();
63 }
64
65 public boolean containsValue(final Object value) {
66 throw new UnsupportedOperationException();
67 }
68
69 public Set<Entry<Long, boolean[]>> entrySet() {
70 throw new UnsupportedOperationException();
71 }
72
73 public boolean isEmpty() {
74 throw new UnsupportedOperationException();
75 }
76
77 public Set<Long> keySet() {
78 throw new UnsupportedOperationException();
79 }
80
81 public boolean[] put(final Long key, final boolean[] value) {
82 throw new UnsupportedOperationException();
83 }
84
85 public void putAll(final Map<? extends Long, ? extends boolean[]> t) {
86 throw new UnsupportedOperationException();
87 }
88
89 public boolean[] remove(final Object key) {
90 throw new UnsupportedOperationException();
91 }
92
93 public Collection<boolean[]> values() {
94 throw new UnsupportedOperationException();
95 }
96
97 public int size() {
98 throw new UnsupportedOperationException();
99 }
100 };
101
102 /**
103 * Creates a new runtime.
104 */
105 public SystemPropertiesRuntime() {
106 this.key = KEYPREFIX + hashCode();
107 }
108
109 public int generateDataAccessor(final long classid,
110 final GeneratorAdapter gen) {
111
112 gen.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System",
113 "getProperties", "()Ljava/util/Properties;");
114
115 // Stack[0]: Ljava/util/Properties;
116
117 gen.push(key);
118
119 // Stack[1]: Ljava/lang/String;
120 // Stack[0]: Ljava/util/Properties;
121
122 gen.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Properties",
123 "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
124
125 // Stack[0]: Ljava/lang/Object;
126
127 gen.visitTypeInsn(Opcodes.CHECKCAST, "java/util/Map");
128
129 // Stack[0]: Ljava/util/Map;
130
131 gen.push(classid);
132
133 // Stack[2]: J
134 // Stack[1]: .
135 // Stack[0]: Ljava/util/Map;
136
137 gen.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf",
138 "(J)Ljava/lang/Long;");
139
140 // Stack[1]: Ljava/lang/Long;
141 // Stack[0]: Ljava/util/Map;
142
143 gen.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Map", "get",
144 "(Ljava/lang/Object;)Ljava/lang/Object;");
145
146 // Stack[0]: Ljava/lang/Object;
147
148 gen.checkCast(GeneratorConstants.PROBEDATA_TYPE);
149
150 // Stack[0]: [Z
151
152 return 3; // Maximum local stack size is 3
153 }
154
155 public void startup() {
156 System.getProperties().put(key, dataAccess);
157 }
158
159 public void shutdown() {
160 System.getProperties().remove(key);
161 }
162
163}