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 */
013package org.jikesrvm.options;
014
015import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_PRINTED_HELP_MESSAGE;
016
017import org.jikesrvm.VM;
018import org.jikesrvm.runtime.CommandLineArgs;
019import org.jikesrvm.runtime.Memory;
020import org.vmmagic.pragma.Uninterruptible;
021import org.vmmagic.unboxed.Extent;
022import org.vmmagic.unboxed.Word;
023import org.vmutil.options.AddressOption;
024import org.vmutil.options.BooleanOption;
025import org.vmutil.options.EnumOption;
026import org.vmutil.options.FloatOption;
027import org.vmutil.options.IntOption;
028import org.vmutil.options.MicrosecondsOption;
029import org.vmutil.options.Option;
030import org.vmutil.options.PagesOption;
031import org.vmutil.options.StringOption;
032
033/**
034 * Class to handle command-line arguments and options for GC.
035 */
036public final class OptionSet extends org.vmutil.options.OptionSet {
037
038  private final String prefix;
039
040  public static final OptionSet gc = new OptionSet("-X:gc");
041
042  private OptionSet(String prefix) {
043    this.prefix = prefix;
044  }
045
046  /**
047   * Take a string (most likely a command-line argument) and try to proccess it
048   * as an option command.  Return true if the string was understood, false
049   * otherwise.
050   *
051   * @param arg a String to try to process as an option command
052   * @return {@code true} if successful, {@code false} otherwise
053   */
054  public boolean process(String arg) {
055
056    // First handle the "option commands"
057    if (arg.equals("help")) {
058       printHelp();
059       return true;
060    }
061    if (arg.equals("printOptions")) {
062       printOptions();
063       return true;
064    }
065    if (arg.length() == 0) {
066      printHelp();
067      return true;
068    }
069
070    // Required format of arg is 'name=value'
071    // Split into 'name' and 'value' strings
072    int split = arg.indexOf('=');
073    if (split == -1) {
074      VM.sysWriteln("  Illegal option specification!\n  \"" + arg +
075                  "\" must be specified as a name-value pair in the form of option=value");
076      return false;
077    }
078
079    String name = arg.substring(0,split);
080    String value = arg.substring(split + 1);
081
082    Option o = getOption(name);
083
084    if (o == null) return false;
085
086    switch (o.getType()) {
087      case Option.BOOLEAN_OPTION:
088        if (value.equals("true")) {
089          ((BooleanOption)o).setValue(true);
090          return true;
091        } else if (value.equals("false")) {
092          ((BooleanOption)o).setValue(false);
093          return true;
094        }
095        return false;
096      case Option.INT_OPTION:
097        int ival = CommandLineArgs.primitiveParseInt(value);
098        ((IntOption)o).setValue(ival);
099        return true;
100      case Option.ADDRESS_OPTION:
101        ival = CommandLineArgs.primitiveParseInt(value);
102        ((AddressOption)o).setValue(ival);
103        return true;
104      case Option.FLOAT_OPTION:
105        float fval = CommandLineArgs.primitiveParseFloat(value);
106        ((FloatOption)o).setValue(fval);
107        return true;
108      case Option.STRING_OPTION:
109        ((StringOption)o).setValue(value);
110        return true;
111      case Option.ENUM_OPTION:
112        ((EnumOption)o).setValue(value);
113        return true;
114      case Option.PAGES_OPTION:
115        long pval = CommandLineArgs.parseMemorySize(o.getName(), name, "b", 1, arg, value);
116        if (pval < 0) return false;
117        ((PagesOption)o).setBytes(Extent.fromIntSignExtend((int)pval));
118        return true;
119      case Option.MICROSECONDS_OPTION:
120        int mval = CommandLineArgs.primitiveParseInt(value);
121        ((MicrosecondsOption)o).setMicroseconds(mval);
122        return true;
123    }
124
125    // None of the above tests matched, so this wasn't an option
126    return false;
127  }
128
129  /**
130   * Print a short description of every option
131   */
132  public void printHelp() {
133
134    VM.sysWriteln("Commands");
135    VM.sysWrite(prefix);VM.sysWriteln("[:help]\t\t\tPrint brief description of arguments");
136    VM.sysWrite(prefix);VM.sysWriteln(":printOptions\t\tPrint the current values of options");
137    VM.sysWriteln();
138
139    //Begin generated help messages
140    VM.sysWrite("Boolean Options (");
141    VM.sysWrite(prefix);VM.sysWrite(":<option>=true or ");
142    VM.sysWrite(prefix);VM.sysWriteln(":<option>=false)");
143    VM.sysWriteln("Option                                 Description");
144
145    Option o = getFirst();
146    while (o != null) {
147      if (o.getType() == Option.BOOLEAN_OPTION) {
148        String key = o.getKey();
149        VM.sysWrite(key);
150        for (int c = key.length(); c < 39;c++) {
151          VM.sysWrite(" ");
152        }
153        VM.sysWriteln(o.getDescription());
154      }
155      o = o.getNext();
156    }
157
158    VM.sysWrite("\nValue Options (");VM.sysWrite(prefix);VM.sysWriteln(":<option>=<value>)");
159    VM.sysWriteln("Option                         Type    Description");
160
161    o = getFirst();
162    while (o != null) {
163      if (o.getType() != Option.BOOLEAN_OPTION &&
164          o.getType() != Option.ENUM_OPTION) {
165        String key = o.getKey();
166        VM.sysWrite(key);
167        for (int c = key.length(); c < 31;c++) {
168          VM.sysWrite(" ");
169        }
170        switch (o.getType()) {
171          case Option.INT_OPTION:          VM.sysWrite("int     "); break;
172          case Option.ADDRESS_OPTION:      VM.sysWrite("address "); break;
173          case Option.FLOAT_OPTION:        VM.sysWrite("float   "); break;
174          case Option.MICROSECONDS_OPTION: VM.sysWrite("usec    "); break;
175          case Option.PAGES_OPTION:        VM.sysWrite("bytes   "); break;
176          case Option.STRING_OPTION:       VM.sysWrite("string  "); break;
177        }
178        VM.sysWriteln(o.getDescription());
179      }
180      o = o.getNext();
181    }
182
183    VM.sysWriteln("\nSelection Options (set option to one of an enumeration of possible values)");
184
185    o = getFirst();
186    while (o != null) {
187      if (o.getType() == Option.ENUM_OPTION) {
188        String key = o.getKey();
189        VM.sysWrite(key);
190        for (int c = key.length(); c < 31;c++) {
191          VM.sysWrite(" ");
192        }
193        VM.sysWriteln(o.getDescription());
194        VM.sysWrite("    { ");
195        boolean first = true;
196        for (String val : ((EnumOption)o).getValues()) {
197          VM.sysWrite(first ? "" : ", ");
198          VM.sysWrite(val);
199          first = false;
200        }
201        VM.sysWriteln(" }");
202      }
203      o = o.getNext();
204    }
205
206    VM.sysExit(EXIT_STATUS_PRINTED_HELP_MESSAGE);
207  }
208
209  /**
210   * Print out the option values
211   */
212  public void printOptions() {
213    VM.sysWriteln("Current value of GC options");
214
215    Option o = getFirst();
216    while (o != null) {
217      if (o.getType() == Option.BOOLEAN_OPTION) {
218        String key = o.getKey();
219        VM.sysWrite("\t");
220        VM.sysWrite(key);
221        for (int c = key.length(); c < 31;c++) {
222          VM.sysWrite(" ");
223        }
224        VM.sysWrite(" = ");
225        logValue(o, false);
226        VM.sysWriteln();
227      }
228      o = o.getNext();
229    }
230
231    o = getFirst();
232    while (o != null) {
233      if (o.getType() != Option.BOOLEAN_OPTION &&
234          o.getType() != Option.ENUM_OPTION) {
235        String key = o.getKey();
236        VM.sysWrite("\t");
237        VM.sysWrite(key);
238        for (int c = key.length(); c < 31;c++) {
239          VM.sysWrite(" ");
240        }
241        VM.sysWrite(" = ");
242        logValue(o, false);
243        VM.sysWriteln();
244      }
245      o = o.getNext();
246    }
247
248    o = getFirst();
249    while (o != null) {
250      if (o.getType() == Option.ENUM_OPTION) {
251        String key = o.getKey();
252        VM.sysWrite("\t");
253        VM.sysWrite(key);
254        for (int c = key.length(); c < 31;c++) {
255          VM.sysWrite(" ");
256        }
257        VM.sysWrite(" = ");
258        logValue(o, false);
259        VM.sysWriteln();
260      }
261      o = o.getNext();
262    }
263  }
264
265  @Override
266  protected void logValue(Option o, boolean forXml) {
267    switch (o.getType()) {
268    case Option.BOOLEAN_OPTION:
269      VM.sysWrite(((BooleanOption) o).getValue() ? "true" : "false");
270      break;
271    case Option.INT_OPTION:
272      VM.sysWrite(((IntOption) o).getValue());
273      break;
274    case Option.ADDRESS_OPTION:
275      VM.sysWrite(((AddressOption) o).getValue());
276      break;
277    case Option.FLOAT_OPTION:
278      VM.sysWrite(((FloatOption) o).getValue());
279      break;
280    case Option.MICROSECONDS_OPTION:
281      VM.sysWrite(((MicrosecondsOption) o).getMicroseconds());
282      VM.sysWrite(" usec");
283      break;
284    case Option.PAGES_OPTION:
285      VM.sysWrite(((PagesOption) o).getBytes());
286      VM.sysWrite(" bytes");
287      break;
288    case Option.STRING_OPTION:
289      VM.sysWrite(((StringOption) o).getValue());
290      break;
291    case Option.ENUM_OPTION:
292      VM.sysWrite(((EnumOption) o).getValueString());
293      break;
294    }
295  }
296
297  @Override
298  protected void logString(String s) {
299    VM.sysWrite(s);
300  }
301
302  @Override
303  protected void logNewLine() {
304    VM.sysWriteln();
305  }
306
307  @Override
308  protected String computeKey(String name) {
309    int space = name.indexOf(' ');
310    if (space < 0) return name.toLowerCase();
311
312    String word = name.substring(0, space);
313    StringBuilder key = new StringBuilder(word.toLowerCase());
314
315    do {
316      int old = space + 1;
317      space = name.indexOf(' ', old);
318      if (space < 0) {
319        key.append(name.substring(old));
320        return key.toString();
321      }
322      key.append(name.substring(old, space));
323    } while (true);
324  }
325
326  @Override
327  protected void warn(Option o, String message) {
328    VM.sysWriteln("WARNING: Option '" + o.getKey() + "' : " + message);
329  }
330
331  @Override
332  protected void fail(Option o, String message) {
333    VM.sysFail("ERROR: Option '" + o.getKey() + "' : " + message);
334  }
335
336  @Override
337  @Uninterruptible
338  protected int bytesToPages(Extent bytes) {
339    return bytes.plus(Memory.getPagesize() - 1).toWord().rshl(Memory.getPagesizeLog()).toInt();
340  }
341
342  @Override
343  @Uninterruptible
344  protected Extent pagesToBytes(int pages) {
345    return Word.fromIntZeroExtend(pages).lsh(Memory.getPagesizeLog()).toExtent();
346  }
347}