1 /* 2 * Copyright (c) 2013, 2018, 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 24 25 package org.graalvm.compiler.options; 26 27 import java.util.Formatter; 28 29 import jdk.internal.vm.compiler.collections.EconomicMap; 30 31 /** 32 * A key for an option. The value for an option is obtained from an {@link OptionValues} object. 33 */ 34 public class OptionKey<T> { 35 36 private final T defaultValue; 37 38 private OptionDescriptor descriptor; 39 40 public OptionKey(T defaultValue) { 41 this.defaultValue = defaultValue; 42 } 43 44 /** 45 * Sets the descriptor for this option. 46 */ 47 public final void setDescriptor(OptionDescriptor descriptor) { 48 assert this.descriptor == null : "Overwriting existing descriptor"; 49 this.descriptor = descriptor; 50 } 51 52 /** 53 * Returns the descriptor for this option, if it has been set by 54 * {@link #setDescriptor(OptionDescriptor)}. 55 */ 56 public final OptionDescriptor getDescriptor() { 57 return descriptor; 58 } 59 60 /** 61 * Checks that a descriptor exists for this key after triggering loading of descriptors. 62 */ 63 protected boolean checkDescriptorExists() { 64 OptionKey.Lazy.init(); 65 if (descriptor == null) { 66 Formatter buf = new Formatter(); 67 buf.format("Could not find a descriptor for an option key. The most likely cause is " + 68 "a dependency on the %s annotation without a dependency on the " + 69 "org.graalvm.compiler.options.processor.OptionProcessor annotation processor.", Option.class.getName()); 70 StackTraceElement[] stackTrace = new Exception().getStackTrace(); 71 if (stackTrace.length > 2 && 72 stackTrace[1].getClassName().equals(OptionKey.class.getName()) && 73 stackTrace[1].getMethodName().equals("getValue")) { 74 String caller = stackTrace[2].getClassName(); 75 buf.format(" In suite.py, add GRAAL_OPTIONS_PROCESSOR to the \"annotationProcessors\" attribute of the project " + 76 "containing %s.", caller); 77 } 78 throw new AssertionError(buf.toString()); 79 } 80 return true; 81 } 82 83 /** 84 * Mechanism for lazily loading all available options which has the side effect of assigning 85 * names to the options. 86 */ 87 static class Lazy { 88 static { 89 for (OptionDescriptors opts : OptionsParser.getOptionsLoader()) { 90 for (OptionDescriptor desc : opts) { 91 desc.getName(); 92 } 93 } 94 } 95 96 static void init() { 97 /* Running the static class initializer does all the initialization. */ 98 } 99 } 100 101 /** 102 * Gets the name of this option. The name for an option value with a null 103 * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of 104 * {@link Object#toString()}. 105 */ 106 public final String getName() { 107 if (descriptor == null) { 108 // Trigger initialization of OptionsLoader to ensure all option values have 109 // a descriptor which is required for them to have meaningful names. 110 Lazy.init(); 111 } 112 return descriptor == null ? super.toString() : descriptor.getName(); 113 } 114 115 @Override 116 public String toString() { 117 return getName(); 118 } 119 120 /** 121 * The initial value specified in source code. 122 */ 123 public final T getDefaultValue() { 124 return defaultValue; 125 } 126 127 /** 128 * Returns true if the option has been set in any way. Note that this doesn't mean that the 129 * current value is different than the default. 130 */ 131 public boolean hasBeenSet(OptionValues values) { 132 return values.containsKey(this); 133 } 134 135 /** 136 * Gets the value of this option in {@code values}. 137 */ 138 public T getValue(OptionValues values) { 139 assert checkDescriptorExists(); 140 return values.get(this); 141 } 142 143 /** 144 * Sets the value of this option in a given map. The 145 * {@link #onValueUpdate(EconomicMap, Object, Object)} method is called once the value is set. 146 * 147 * @param values map of option values 148 * @param v the value to set for this key in {@code map} 149 */ 150 @SuppressWarnings("unchecked") 151 public void update(EconomicMap<OptionKey<?>, Object> values, Object v) { 152 T oldValue = (T) values.put(this, v); 153 onValueUpdate(values, oldValue, (T) v); 154 } 155 156 /** 157 * Sets the value of this option in a given map if it doesn't already have a value. The 158 * {@link #onValueUpdate(EconomicMap, Object, Object)} method is called once the value is set. 159 * 160 * @param values map of option values 161 * @param v the value to set for this key in {@code map} 162 */ 163 @SuppressWarnings("unchecked") 164 public void putIfAbsent(EconomicMap<OptionKey<?>, Object> values, Object v) { 165 if (!values.containsKey(this)) { 166 T oldValue = (T) values.put(this, v); 167 onValueUpdate(values, oldValue, (T) v); 168 } 169 } 170 171 /** 172 * Notifies this object when a value associated with this key is set or updated in 173 * {@code values}. 174 * 175 * @param values 176 * @param oldValue 177 * @param newValue 178 */ 179 protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, T oldValue, T newValue) { 180 } 181 }