Mercurial > hg > graal-jvmci-8
comparison jvmci/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java @ 22672:1bbd4a7c274b
Rename jdk.internal.jvmci to jdk.vm.ci
author | Tom Rodriguez <tom.rodriguez@oracle.com> |
---|---|
date | Thu, 08 Oct 2015 17:28:41 -0700 |
parents | jvmci/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/OptionValue.java@ec96f33a101d |
children |
comparison
equal
deleted
inserted
replaced
22671:97f30e4d0e95 | 22672:1bbd4a7c274b |
---|---|
1 /* | |
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package jdk.vm.ci.options; | |
24 | |
25 import java.io.PrintStream; | |
26 import java.util.ArrayList; | |
27 import java.util.Collection; | |
28 import java.util.Collections; | |
29 import java.util.Comparator; | |
30 import java.util.HashMap; | |
31 import java.util.Map; | |
32 import java.util.Map.Entry; | |
33 import java.util.Objects; | |
34 | |
35 /** | |
36 * An option value. | |
37 */ | |
38 public class OptionValue<T> { | |
39 /** | |
40 * Temporarily changes the value for an option. The {@linkplain OptionValue#getValue() value} of | |
41 * {@code option} is set to {@code value} until {@link OverrideScope#close()} is called on the | |
42 * object returned by this method. | |
43 * <p> | |
44 * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be | |
45 * used: | |
46 * | |
47 * <pre> | |
48 * try (OverrideScope s = OptionValue.override(myOption, myValue) { | |
49 * // code that depends on myOption == myValue | |
50 * } | |
51 * </pre> | |
52 */ | |
53 public static OverrideScope override(OptionValue<?> option, Object value) { | |
54 OverrideScope current = getOverrideScope(); | |
55 if (current == null) { | |
56 if (!value.equals(option.getValue())) { | |
57 return new SingleOverrideScope(option, value); | |
58 } | |
59 Map<OptionValue<?>, Object> overrides = Collections.emptyMap(); | |
60 return new MultipleOverridesScope(current, overrides); | |
61 } | |
62 return new MultipleOverridesScope(current, option, value); | |
63 } | |
64 | |
65 /** | |
66 * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() | |
67 * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} | |
68 * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by | |
69 * this method. | |
70 * <p> | |
71 * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be | |
72 * used: | |
73 * | |
74 * <pre> | |
75 * Map<OptionValue, Object> overrides = new HashMap<>(); | |
76 * overrides.put(myOption1, myValue1); | |
77 * overrides.put(myOption2, myValue2); | |
78 * try (OverrideScope s = OptionValue.override(overrides) { | |
79 * // code that depends on myOption == myValue | |
80 * } | |
81 * </pre> | |
82 */ | |
83 public static OverrideScope override(Map<OptionValue<?>, Object> overrides) { | |
84 OverrideScope current = getOverrideScope(); | |
85 if (current == null && overrides.size() == 1) { | |
86 Entry<OptionValue<?>, Object> single = overrides.entrySet().iterator().next(); | |
87 OptionValue<?> option = single.getKey(); | |
88 Object overrideValue = single.getValue(); | |
89 if (!overrideValue.equals(option.getValue())) { | |
90 return new SingleOverrideScope(option, overrideValue); | |
91 } | |
92 } | |
93 return new MultipleOverridesScope(current, overrides); | |
94 } | |
95 | |
96 /** | |
97 * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() | |
98 * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} | |
99 * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by | |
100 * this method. | |
101 * <p> | |
102 * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be | |
103 * used: | |
104 * | |
105 * <pre> | |
106 * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2) { | |
107 * // code that depends on myOption == myValue | |
108 * } | |
109 * </pre> | |
110 * | |
111 * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]} | |
112 */ | |
113 public static OverrideScope override(Object... overrides) { | |
114 OverrideScope current = getOverrideScope(); | |
115 if (current == null && overrides.length == 2) { | |
116 OptionValue<?> option = (OptionValue<?>) overrides[0]; | |
117 Object overrideValue = overrides[1]; | |
118 if (!overrideValue.equals(option.getValue())) { | |
119 return new SingleOverrideScope(option, overrideValue); | |
120 } | |
121 } | |
122 Map<OptionValue<?>, Object> map = Collections.emptyMap(); | |
123 for (int i = 0; i < overrides.length; i += 2) { | |
124 OptionValue<?> option = (OptionValue<?>) overrides[i]; | |
125 Object overrideValue = overrides[i + 1]; | |
126 if (!overrideValue.equals(option.getValue())) { | |
127 if (map.isEmpty()) { | |
128 map = new HashMap<>(); | |
129 } | |
130 map.put(option, overrideValue); | |
131 } | |
132 } | |
133 return new MultipleOverridesScope(current, map); | |
134 } | |
135 | |
136 private static final ThreadLocal<OverrideScope> overrideScopeTL = new ThreadLocal<>(); | |
137 | |
138 protected static OverrideScope getOverrideScope() { | |
139 return overrideScopeTL.get(); | |
140 } | |
141 | |
142 protected static void setOverrideScope(OverrideScope overrideScope) { | |
143 overrideScopeTL.set(overrideScope); | |
144 } | |
145 | |
146 private T defaultValue; | |
147 | |
148 /** | |
149 * The raw option value. | |
150 */ | |
151 protected T value; | |
152 | |
153 private OptionDescriptor descriptor; | |
154 | |
155 private long reads; | |
156 private OptionValue<?> next; | |
157 private static OptionValue<?> head; | |
158 | |
159 private static final boolean ShowReadsHistogram = Boolean.getBoolean("jvmci.showOptionValueReadsHistogram"); | |
160 | |
161 private static void addToHistogram(OptionValue<?> option) { | |
162 if (ShowReadsHistogram) { | |
163 synchronized (OptionValue.class) { | |
164 option.next = head; | |
165 head = option; | |
166 } | |
167 } | |
168 } | |
169 | |
170 @SuppressWarnings("unchecked") | |
171 public OptionValue(T value) { | |
172 this.defaultValue = value; | |
173 this.value = (T) DEFAULT; | |
174 addToHistogram(this); | |
175 } | |
176 | |
177 private static final Object DEFAULT = "DEFAULT"; | |
178 private static final Object UNINITIALIZED = "UNINITIALIZED"; | |
179 | |
180 /** | |
181 * Creates an uninitialized option value for a subclass that initializes itself | |
182 * {@link #defaultValue() lazily}. | |
183 */ | |
184 @SuppressWarnings("unchecked") | |
185 protected OptionValue() { | |
186 this.defaultValue = (T) UNINITIALIZED; | |
187 this.value = (T) DEFAULT; | |
188 addToHistogram(this); | |
189 } | |
190 | |
191 /** | |
192 * Lazy initialization of default value. | |
193 */ | |
194 protected T defaultValue() { | |
195 throw new InternalError("Option without a default value value must override defaultValue()"); | |
196 } | |
197 | |
198 /** | |
199 * Sets the descriptor for this option. | |
200 */ | |
201 public void setDescriptor(OptionDescriptor descriptor) { | |
202 assert this.descriptor == null : "Overwriting existing descriptor"; | |
203 this.descriptor = descriptor; | |
204 } | |
205 | |
206 /** | |
207 * Returns the descriptor for this option, if it has been set by | |
208 * {@link #setDescriptor(OptionDescriptor)}. | |
209 */ | |
210 public OptionDescriptor getDescriptor() { | |
211 return descriptor; | |
212 } | |
213 | |
214 /** | |
215 * Gets the name of this option. The name for an option value with a null | |
216 * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of | |
217 * {@link Object#toString()}. | |
218 */ | |
219 public String getName() { | |
220 return descriptor == null ? super.toString() : (descriptor.getDeclaringClass().getName() + "." + descriptor.getName()); | |
221 } | |
222 | |
223 @Override | |
224 public String toString() { | |
225 return getName() + "=" + getValue(); | |
226 } | |
227 | |
228 /** | |
229 * The initial value specified in source code. The returned value is not affected by calls to | |
230 * {@link #setValue(Object)} or registering {@link OverrideScope}s. Therefore, it is also not | |
231 * affected by options set on the command line. | |
232 */ | |
233 public T getDefaultValue() { | |
234 if (defaultValue == UNINITIALIZED) { | |
235 defaultValue = defaultValue(); | |
236 } | |
237 return defaultValue; | |
238 } | |
239 | |
240 /** | |
241 * Returns true if the option has the same value that was set in the source code. | |
242 */ | |
243 public boolean hasDefaultValue() { | |
244 if (!(this instanceof StableOptionValue)) { | |
245 getValue(); // ensure initialized | |
246 } | |
247 return value == DEFAULT || Objects.equals(value, getDefaultValue()); | |
248 } | |
249 | |
250 /** | |
251 * Gets the value of this option. | |
252 */ | |
253 public T getValue() { | |
254 if (ShowReadsHistogram) { | |
255 reads++; | |
256 } | |
257 if (!(this instanceof StableOptionValue)) { | |
258 OverrideScope overrideScope = getOverrideScope(); | |
259 if (overrideScope != null) { | |
260 T override = overrideScope.getOverride(this); | |
261 if (override != null) { | |
262 return override; | |
263 } | |
264 } | |
265 } | |
266 if (value != DEFAULT) { | |
267 return value; | |
268 } else { | |
269 return getDefaultValue(); | |
270 } | |
271 } | |
272 | |
273 /** | |
274 * Gets the values of this option including overridden values. | |
275 * | |
276 * @param c the collection to which the values are added. If null, one is allocated. | |
277 * @return the collection to which the values were added in order from most overridden to | |
278 * current value | |
279 */ | |
280 @SuppressWarnings("unchecked") | |
281 public Collection<T> getValues(Collection<T> c) { | |
282 Collection<T> values = c == null ? new ArrayList<>() : c; | |
283 if (!(this instanceof StableOptionValue)) { | |
284 OverrideScope overrideScope = getOverrideScope(); | |
285 if (overrideScope != null) { | |
286 overrideScope.getOverrides(this, (Collection<Object>) values); | |
287 } | |
288 } | |
289 if (value != DEFAULT) { | |
290 values.add(value); | |
291 } else { | |
292 values.add(getDefaultValue()); | |
293 } | |
294 return values; | |
295 } | |
296 | |
297 /** | |
298 * Sets the value of this option. | |
299 */ | |
300 @SuppressWarnings("unchecked") | |
301 public void setValue(Object v) { | |
302 this.value = (T) v; | |
303 } | |
304 | |
305 /** | |
306 * An object whose {@link #close()} method reverts the option value overriding initiated by | |
307 * {@link OptionValue#override(OptionValue, Object)} or {@link OptionValue#override(Map)}. | |
308 */ | |
309 public abstract static class OverrideScope implements AutoCloseable { | |
310 | |
311 private Map<DerivedOptionValue<?>, Object> derivedCache = null; | |
312 | |
313 public <T> T getDerived(DerivedOptionValue<T> key) { | |
314 if (derivedCache == null) { | |
315 derivedCache = new HashMap<>(); | |
316 } | |
317 @SuppressWarnings("unchecked") | |
318 T ret = (T) derivedCache.get(key); | |
319 if (ret == null) { | |
320 ret = key.createValue(); | |
321 derivedCache.put(key, ret); | |
322 } | |
323 return ret; | |
324 } | |
325 | |
326 abstract void addToInherited(Map<OptionValue<?>, Object> inherited); | |
327 | |
328 abstract <T> T getOverride(OptionValue<T> option); | |
329 | |
330 abstract void getOverrides(OptionValue<?> option, Collection<Object> c); | |
331 | |
332 public abstract void close(); | |
333 } | |
334 | |
335 static class SingleOverrideScope extends OverrideScope { | |
336 | |
337 private final OptionValue<?> option; | |
338 private final Object value; | |
339 | |
340 public SingleOverrideScope(OptionValue<?> option, Object value) { | |
341 if (option instanceof StableOptionValue) { | |
342 throw new IllegalArgumentException("Cannot override stable option " + option); | |
343 } | |
344 this.option = option; | |
345 this.value = value; | |
346 setOverrideScope(this); | |
347 } | |
348 | |
349 @Override | |
350 void addToInherited(Map<OptionValue<?>, Object> inherited) { | |
351 inherited.put(option, value); | |
352 } | |
353 | |
354 @SuppressWarnings("unchecked") | |
355 @Override | |
356 <T> T getOverride(OptionValue<T> key) { | |
357 if (key == this.option) { | |
358 return (T) value; | |
359 } | |
360 return null; | |
361 } | |
362 | |
363 @Override | |
364 void getOverrides(OptionValue<?> key, Collection<Object> c) { | |
365 if (key == this.option) { | |
366 c.add(value); | |
367 } | |
368 } | |
369 | |
370 @Override | |
371 public void close() { | |
372 setOverrideScope(null); | |
373 } | |
374 } | |
375 | |
376 static class MultipleOverridesScope extends OverrideScope { | |
377 final OverrideScope parent; | |
378 final Map<OptionValue<?>, Object> overrides; | |
379 | |
380 public MultipleOverridesScope(OverrideScope parent, OptionValue<?> option, Object value) { | |
381 this.parent = parent; | |
382 this.overrides = new HashMap<>(); | |
383 if (parent != null) { | |
384 parent.addToInherited(overrides); | |
385 } | |
386 if (option instanceof StableOptionValue) { | |
387 throw new IllegalArgumentException("Cannot override stable option " + option); | |
388 } | |
389 if (!value.equals(option.getValue())) { | |
390 this.overrides.put(option, value); | |
391 } | |
392 if (!overrides.isEmpty()) { | |
393 setOverrideScope(this); | |
394 } | |
395 } | |
396 | |
397 MultipleOverridesScope(OverrideScope parent, Map<OptionValue<?>, Object> overrides) { | |
398 this.parent = parent; | |
399 if (overrides.isEmpty() && parent == null) { | |
400 this.overrides = Collections.emptyMap(); | |
401 return; | |
402 } | |
403 this.overrides = new HashMap<>(); | |
404 if (parent != null) { | |
405 parent.addToInherited(this.overrides); | |
406 } | |
407 for (Map.Entry<OptionValue<?>, Object> e : overrides.entrySet()) { | |
408 OptionValue<?> option = e.getKey(); | |
409 if (option instanceof StableOptionValue) { | |
410 throw new IllegalArgumentException("Cannot override stable option " + option); | |
411 } | |
412 if (!e.getValue().equals(option.getValue())) { | |
413 this.overrides.put(option, e.getValue()); | |
414 } | |
415 } | |
416 if (!this.overrides.isEmpty()) { | |
417 setOverrideScope(this); | |
418 } | |
419 } | |
420 | |
421 @Override | |
422 void addToInherited(Map<OptionValue<?>, Object> inherited) { | |
423 if (parent != null) { | |
424 parent.addToInherited(inherited); | |
425 } | |
426 inherited.putAll(overrides); | |
427 } | |
428 | |
429 @SuppressWarnings("unchecked") | |
430 @Override | |
431 <T> T getOverride(OptionValue<T> option) { | |
432 return (T) overrides.get(option); | |
433 } | |
434 | |
435 @Override | |
436 void getOverrides(OptionValue<?> option, Collection<Object> c) { | |
437 Object v = overrides.get(option); | |
438 if (v != null) { | |
439 c.add(v); | |
440 } | |
441 if (parent != null) { | |
442 parent.getOverrides(option, c); | |
443 } | |
444 } | |
445 | |
446 @Override | |
447 public void close() { | |
448 if (!overrides.isEmpty()) { | |
449 setOverrideScope(parent); | |
450 } | |
451 } | |
452 } | |
453 | |
454 static { | |
455 if (ShowReadsHistogram) { | |
456 Runtime.getRuntime().addShutdownHook(new Thread() { | |
457 @Override | |
458 public void run() { | |
459 ArrayList<OptionValue<?>> options = new ArrayList<>(); | |
460 for (OptionValue<?> option = head; option != null; option = option.next) { | |
461 options.add(option); | |
462 } | |
463 Collections.sort(options, new Comparator<OptionValue<?>>() { | |
464 | |
465 public int compare(OptionValue<?> o1, OptionValue<?> o2) { | |
466 if (o1.reads < o2.reads) { | |
467 return -1; | |
468 } else if (o1.reads > o2.reads) { | |
469 return 1; | |
470 } else { | |
471 return o1.getName().compareTo(o2.getName()); | |
472 } | |
473 } | |
474 }); | |
475 PrintStream out = System.out; | |
476 out.println("=== OptionValue reads histogram ==="); | |
477 for (OptionValue<?> option : options) { | |
478 out.println(option.reads + "\t" + option); | |
479 } | |
480 } | |
481 }); | |
482 } | |
483 } | |
484 } |