001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.vmutil.options;
014
015 import org.vmmagic.pragma.Uninterruptible;
016 import org.vmmagic.unboxed.*;
017
018 /**
019 * The abstract base class for all option sets.
020 * <p>
021 * Concrete instantiations of this class include logic.
022 * <p>
023 * All options within the system should have a unique name. No
024 * two options shall have a name that is the same when a case
025 * insensitive comparison between the names with spaces removed
026 * is performed. Only basic alphanumeric characters and spaces
027 * are allowed.
028 * <p>
029 * The VM is required to provide a one way mapping function that
030 * takes the name and creates a VM style name, such as mapping
031 * "No Finalizer" to noFinalizer. The VM may not remove any letters
032 * when performing this mapping but may remove spaces and change
033 * the case of any character.
034 */
035 public abstract class OptionSet {
036 private Option head;
037 private Option tail;
038 private boolean loggingChanges;
039
040 /**
041 * Initialize the option set so that options can be created.
042 */
043 protected OptionSet() {
044 head = null;
045 tail = null;
046 loggingChanges = false;
047 }
048
049 /**
050 * Register the option to this set, computing its key in the process.
051 *
052 * @param o The option to register.
053 */
054 final String register(Option o, String name) {
055 if (tail == null) {
056 tail = head = o;
057 } else {
058 tail.setNext(o);
059 tail = o;
060 }
061 return computeKey(name);
062 }
063
064 /**
065 * Using the VM determined key, look up the corresponding option,
066 * or return <code>null</code> if an option can not be found.
067 *
068 * @param key The (unique) option key.
069 * @return The option, or <code>null</code>.
070 */
071 public final Option getOption(String key) {
072 Option o = getFirst();
073 while (o != null) {
074 if (o.getKey().equals(key)) {
075 return o;
076 }
077 o = o.getNext();
078 }
079 return null;
080 }
081
082 /**
083 * Return the first option. This can be used with the getNext method to
084 * iterate through the options.
085 *
086 * @return The first option, or <code>null</code> if no options exist.
087 */
088 public final Option getFirst() {
089 return head;
090 }
091
092 /**
093 * Log an option change
094 * @param o The option that changed
095 */
096 public void logChange(Option o) {
097 if (loggingChanges) {
098 logString("Option Update: ");
099 log(o);
100 }
101 }
102
103 /**
104 * Log the option value in plain text.
105 *
106 * @param o The option to log.
107 */
108 public void log(Option o) {
109 logString("Option '");
110 logString(o.getKey());
111 logString("' = ");
112 logValue(o, false);
113 logNewLine();
114 }
115
116 /**
117 * Log the option value in XML.
118 *
119 * @param o The option to log.
120 */
121 public void logXml(Option o) {
122 logString("<option name=\"");
123 logString(o.getKey());
124 logString("\" value=\"");
125 logValue(o, true);
126 logString("\"/>");
127 logNewLine();
128 }
129
130 /**
131 * Log the option values in XML.
132 */
133 public void logXml() {
134 logString("<options>");
135 logNewLine();
136
137 for(Option o = getFirst(); o != null; o = o.getNext()) {
138 logXml(o);
139 }
140
141 logString("</options>");
142 logNewLine();
143 }
144
145 /**
146 * Format and log an option value.
147 *
148 * @param o The option.
149 * @param forXml Is this part of XML output?
150 */
151 protected abstract void logValue(Option o, boolean forXml);
152
153 /**
154 * Log a string.
155 */
156 protected abstract void logString(String s);
157
158 /**
159 * Print a new line.
160 */
161 protected abstract void logNewLine();
162
163 /**
164 * Determine the VM specific key for a given option name. Option names are
165 * space delimited with capitalised words (e.g. "GC Verbosity Level").
166 *
167 * @param name The option name.
168 * @return The VM specific key.
169 */
170 protected abstract String computeKey(String name);
171
172 /**
173 * A non-fatal error occurred during the setting of an option. This method
174 * calls into the VM and shall not cause the system to stop.
175 *
176 * @param o The responsible option.
177 * @param message The message associated with the warning.
178 */
179 protected abstract void warn(Option o, String message);
180
181 /**
182 * A fatal error occurred during the setting of an option. This method
183 * calls into the VM and is required to cause the system to stop.
184 *
185 * @param o The responsible option.
186 * @param message The error message associated with the failure.
187 */
188 protected abstract void fail(Option o, String message);
189
190 /**
191 * Convert bytes into pages, rounding up if necessary.
192 *
193 * @param bytes The number of bytes.
194 * @return The corresponding number of pages.
195 */
196 @Uninterruptible
197 protected abstract int bytesToPages(Extent bytes);
198
199 /**
200 * Convert from pages into bytes.
201 * @param pages the number of pages.
202 * @return The corresponding number of bytes.
203 */
204 @Uninterruptible
205 protected abstract Extent pagesToBytes(int pages);
206 }
207