OptionKey.java revision 13083:b9a173f12fe6
1162922Sariff/*
2162922Sariff * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3162922Sariff * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4182999Smav *
5162922Sariff * This code is free software; you can redistribute it and/or modify it
6162922Sariff * under the terms of the GNU General Public License version 2 only, as
7162922Sariff * published by the Free Software Foundation.
8162922Sariff *
9162922Sariff * This code is distributed in the hope that it will be useful, but WITHOUT
10162922Sariff * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11162922Sariff * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12162922Sariff * version 2 for more details (a copy is included in the LICENSE file that
13162922Sariff * accompanied this code).
14162922Sariff *
15162922Sariff * You should have received a copy of the GNU General Public License version
16162922Sariff * 2 along with this work; if not, write to the Free Software Foundation,
17162922Sariff * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18162922Sariff *
19162922Sariff * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20162922Sariff * or visit www.oracle.com if you need additional information or have any
21162922Sariff * questions.
22162922Sariff */
23162922Sariffpackage org.graalvm.compiler.options;
24162922Sariff
25162922Sariffimport java.util.Formatter;
26162922Sariff
27162922Sariffimport org.graalvm.util.EconomicMap;
28162922Sariff
29162922Sariff/**
30162922Sariff * A key for an option. The value for an option is obtained from an {@link OptionValues} object.
31162922Sariff */
32162922Sariffpublic class OptionKey<T> {
33162922Sariff
34162922Sariff    private final T defaultValue;
35162922Sariff
36162922Sariff    private OptionDescriptor descriptor;
37162922Sariff
38162922Sariff    public OptionKey(T defaultValue) {
39162922Sariff        this.defaultValue = defaultValue;
40162922Sariff    }
41162922Sariff
42162922Sariff    /**
43162922Sariff     * Sets the descriptor for this option.
44162922Sariff     */
45162922Sariff    public final void setDescriptor(OptionDescriptor descriptor) {
46162922Sariff        assert this.descriptor == null : "Overwriting existing descriptor";
47162922Sariff        this.descriptor = descriptor;
48164614Sariff    }
49162922Sariff
50162922Sariff    /**
51162922Sariff     * Returns the descriptor for this option, if it has been set by
52162922Sariff     * {@link #setDescriptor(OptionDescriptor)}.
53162922Sariff     */
54162922Sariff    public final OptionDescriptor getDescriptor() {
55162922Sariff        return descriptor;
56162922Sariff    }
57162922Sariff
58162922Sariff    /**
59162922Sariff     * Checks that a descriptor exists for this key after triggering loading of descriptors.
60162922Sariff     */
61162922Sariff    protected boolean checkDescriptorExists() {
62162922Sariff        OptionKey.Lazy.init();
63162922Sariff        if (descriptor == null) {
64162922Sariff            Formatter buf = new Formatter();
65182999Smav            buf.format("Could not find a descriptor for an option key. The most likely cause is " +
66162922Sariff                            "a dependency on the %s annotation without a dependency on the " +
67162922Sariff                            "org.graalvm.compiler.options.processor.OptionProcessor annotation processor.", Option.class.getName());
68162922Sariff            StackTraceElement[] stackTrace = new Exception().getStackTrace();
69162922Sariff            if (stackTrace.length > 2 &&
70162922Sariff                            stackTrace[1].getClassName().equals(OptionKey.class.getName()) &&
71162922Sariff                            stackTrace[1].getMethodName().equals("getValue")) {
72162922Sariff                String caller = stackTrace[2].getClassName();
73162922Sariff                buf.format(" In suite.py, add GRAAL_OPTIONS_PROCESSOR to the \"annotationProcessors\" attribute of the project " +
74162922Sariff                                "containing %s.", caller);
75162922Sariff            }
76171141Sariff            throw new AssertionError(buf.toString());
77171141Sariff        }
78171141Sariff        return true;
79162922Sariff    }
80162922Sariff
81162922Sariff    /**
82162922Sariff     * Mechanism for lazily loading all available options which has the side effect of assigning
83162922Sariff     * names to the options.
84162922Sariff     */
85162922Sariff    static class Lazy {
86189879Smav        static {
87162922Sariff            for (OptionDescriptors opts : OptionsParser.getOptionsLoader()) {
88162922Sariff                for (OptionDescriptor desc : opts) {
89162922Sariff                    desc.getName();
90169277Sariff                }
91169277Sariff            }
92169277Sariff        }
93169277Sariff
94162922Sariff        static void init() {
95162922Sariff            /* Running the static class initializer does all the initialization. */
96183097Smav        }
97183097Smav    }
98183097Smav
99183097Smav    /**
100183097Smav     * Gets the name of this option. The name for an option value with a null
101183097Smav     * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of
102162965Sariff     * {@link Object#toString()}.
103162922Sariff     */
104162922Sariff    public final String getName() {
105162922Sariff        if (descriptor == null) {
106162922Sariff            // Trigger initialization of OptionsLoader to ensure all option values have
107162965Sariff            // a descriptor which is required for them to have meaningful names.
108162965Sariff            Lazy.init();
109163057Sariff        }
110163057Sariff        return descriptor == null ? super.toString() : descriptor.getName();
111162922Sariff    }
112162965Sariff
113163257Sariff    @Override
114163257Sariff    public String toString() {
115163257Sariff        return getName();
116163257Sariff    }
117163257Sariff
118163257Sariff    /**
119162965Sariff     * The initial value specified in source code.
120162965Sariff     */
121162965Sariff    public final T getDefaultValue() {
122169277Sariff        return defaultValue;
123169277Sariff    }
124169277Sariff
125171141Sariff    /**
126171141Sariff     * Returns true if the option has been set in any way. Note that this doesn't mean that the
127171141Sariff     * current value is different than the default.
128171141Sariff     */
129171141Sariff    public boolean hasBeenSet(OptionValues values) {
130171141Sariff        return values.containsKey(this);
131171141Sariff    }
132171141Sariff
133162922Sariff    /**
134162922Sariff     * Gets the value of this option in {@code values}.
135162922Sariff     */
136162922Sariff    public T getValue(OptionValues values) {
137162922Sariff        assert checkDescriptorExists();
138162922Sariff        return values.get(this);
139162922Sariff    }
140162922Sariff
141171330Sariff    /**
142162922Sariff     * Sets the value of this option in a given map. The
143163136Sariff     * {@link #onValueUpdate(EconomicMap, Object, Object)} method is called once the value is set.
144171330Sariff     *
145184207Smav     * @param values map of option values
146187020Smav     * @param v the value to set for this key in {@code map}
147184207Smav     */
148162922Sariff    @SuppressWarnings("unchecked")
149162922Sariff    public void update(EconomicMap<OptionKey<?>, Object> values, Object v) {
150162922Sariff        T oldValue = (T) values.put(this, v);
151162922Sariff        onValueUpdate(values, oldValue, (T) v);
152162922Sariff    }
153162922Sariff
154173817Sariff    /**
155173817Sariff     * Sets the value of this option in a given map if it doesn't already have a value. The
156173817Sariff     * {@link #onValueUpdate(EconomicMap, Object, Object)} method is called once the value is set.
157173817Sariff     *
158173817Sariff     * @param values map of option values
159173817Sariff     * @param v the value to set for this key in {@code map}
160186511Smav     */
161186511Smav    @SuppressWarnings("unchecked")
162186511Smav    public void putIfAbsent(EconomicMap<OptionKey<?>, Object> values, Object v) {
163186511Smav        if (!values.containsKey(this)) {
164186511Smav            T oldValue = (T) values.put(this, v);
165186511Smav            onValueUpdate(values, oldValue, (T) v);
166186511Smav        }
167186511Smav    }
168186511Smav
169186511Smav    /**
170162922Sariff     * Notifies this object when a value associated with this key is set or updated in
171162922Sariff     * {@code values}.
172162922Sariff     *
173162922Sariff     * @param values
174162922Sariff     * @param oldValue
175163136Sariff     * @param newValue
176187020Smav     */
177187020Smav    protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, T oldValue, T newValue) {
178187020Smav    }
179187020Smav}
180187020Smav