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}