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.jikesrvm;
014
015 import java.io.File;
016 import java.util.Arrays;
017 import org.jikesrvm.adaptive.controller.Controller;
018 import org.jikesrvm.classloader.RVMClassLoader;
019 import org.jikesrvm.compilers.baseline.BaselineCompiler;
020 import org.jikesrvm.compilers.baseline.BaselineOptions;
021 import org.jikesrvm.compilers.common.RuntimeCompiler;
022 import org.jikesrvm.mm.mminterface.MemoryManager;
023
024 import static org.jikesrvm.runtime.SysCall.sysCall;
025 import org.jikesrvm.scheduler.RVMThread;
026
027 /**
028 * Command line option processing.
029 *
030 * Arbitrary prefix support
031 */
032 public class CommandLineArgs {
033 private static final boolean DEBUG = false;
034
035 /**
036 * Argument types
037 */
038 private enum PrefixType {
039 /**
040 * Invalid argument type
041 */
042 INVALID_ARG, // default
043 /**
044 * Application argument
045 */
046 APPLICATION_ARG,
047
048 // -----------------------------------------------//
049 // The following arguments are standard java. //
050 // -----------------------------------------------//
051 CLASSPATH_ARG,
052 ENVIRONMENT_ARG,
053 VERBOSE_JNI_ARG,
054 VERBOSE_CLS_ARG,
055 JAR_ARG,
056 JAVAAGENT_ARG,
057 ENABLE_ASSERTION_ARG,
058 ENABLE_SYSTEM_ASSERTION_ARG,
059 DISABLE_ASSERTION_ARG,
060 DISABLE_SYSTEM_ASSERTION_ARG,
061
062 // -----------------------------------------------//
063 // The following arguments are RVM-specific. //
064 // -----------------------------------------------//
065 HELP_ARG,
066 ARG,
067 IRC_HELP_ARG,
068 IRC_ARG,
069 RECOMP_HELP_ARG,
070 RECOMP_ARG,
071 AOS_HELP_ARG,
072 AOS_ARG,
073 BASE_HELP_ARG,
074 BASE_ARG,
075 OPT_ARG,
076 OPT_HELP_ARG,
077 /* Silently ignored */
078 VERIFY_ARG,
079 GC_HELP_ARG,
080 GC_ARG,
081 BOOTCLASSPATH_P_ARG,
082 BOOTCLASSPATH_A_ARG,
083 BOOTSTRAP_CLASSES_ARG,
084 PROCESSORS_ARG
085 }
086
087 /** Represent a single command line prefix */
088 private static final class Prefix implements Comparable<Prefix> {
089 /** The command line string e.g. "-X:irc:" */
090 public final String value;
091 /** A number that describes the type of the argument */
092 public final PrefixType type;
093 /** Number of arguments of this type seen */
094 public int count = 0;
095
096 /** Construct a prefix with the given argument string and type */
097 public Prefix(String v, PrefixType t) {
098 value = v;
099 type = t;
100 if (t == null) {
101 throw new Error("Type of prefix should never be null");
102 }
103 }
104
105 /** Sorting method for Comparable. Sort by string value */
106 public int compareTo(Prefix o) {
107 return -value.compareTo(o.value);
108 }
109 /** Equals method to be consistent with Comparable */
110 public boolean equals(Object o) {
111 if (o instanceof Prefix) {
112 return value.equals(((Prefix)o).value);
113 }
114 return false;
115 }
116 /** Hashcode to be consistent with Comparable */
117 public int hashCode() {
118 return value.hashCode();
119 }
120 /** Command line string representation of the prefix */
121 public String toString() {
122 return value;
123 }
124 }
125
126 /**
127 * A catch-all prefix to find application name.
128 */
129 private static final Prefix app_prefix = new Prefix("", PrefixType.APPLICATION_ARG);
130
131 /**
132 * A list of possible prefixes for command line arguments.
133 * Each argument will be classified by the prefix it matches.
134 * One prefix can contain another.
135 *
136 * Prefixes are normally matched with the start of the argument.
137 * If the last character of the prefix is a '$', the prefix (without the
138 * trailing '$') will be matched with the whole argument.
139 * If the last character of the prefix is a ' ' (space), the prefix
140 * (without the trailing ' ') will be matched with the whole argument,
141 * and the next argument will be appended to the end of the one matching
142 * the prefix, with a space in between.
143 *
144 * The type will be used to classify the prefix. Multiple entries CAN
145 * have the same type.
146 */
147 private static final Prefix[] prefixes = {new Prefix("-classpath ", PrefixType.CLASSPATH_ARG),
148 // Note: space is significant
149 new Prefix("-cp ", PrefixType.CLASSPATH_ARG),
150 // Note: space is significant
151 new Prefix("-jar ", PrefixType.JAR_ARG),
152 // Note: space is significant
153 new Prefix("-javaagent:", PrefixType.JAVAAGENT_ARG),
154 new Prefix("-D", PrefixType.ENVIRONMENT_ARG),
155 new Prefix("-verbose:class$", PrefixType.VERBOSE_CLS_ARG),
156 new Prefix("-verbose:jni$", PrefixType.VERBOSE_JNI_ARG),
157 new Prefix("-verbose$", PrefixType.VERBOSE_CLS_ARG),
158
159 new Prefix("-enableassertions:", PrefixType.ENABLE_ASSERTION_ARG),
160 new Prefix("-ea:", PrefixType.ENABLE_ASSERTION_ARG),
161 new Prefix("-enableassertions:", PrefixType.ENABLE_ASSERTION_ARG),
162 new Prefix("-ea", PrefixType.ENABLE_ASSERTION_ARG),
163
164 new Prefix("-enableassertions", PrefixType.ENABLE_ASSERTION_ARG),
165
166 new Prefix("-esa:", PrefixType.ENABLE_SYSTEM_ASSERTION_ARG),
167 new Prefix("-enablesystemassertions:", PrefixType.ENABLE_SYSTEM_ASSERTION_ARG),
168 new Prefix("-esa", PrefixType.ENABLE_SYSTEM_ASSERTION_ARG),
169 new Prefix("-enablesystemassertions", PrefixType.ENABLE_SYSTEM_ASSERTION_ARG),
170
171 new Prefix("-disableassertions:", PrefixType.DISABLE_ASSERTION_ARG),
172 new Prefix("-da:", PrefixType.DISABLE_ASSERTION_ARG),
173 new Prefix("-disableassertions", PrefixType.DISABLE_ASSERTION_ARG),
174 new Prefix("-da", PrefixType.DISABLE_ASSERTION_ARG),
175
176 new Prefix("-disablesystemassertions:", PrefixType.DISABLE_SYSTEM_ASSERTION_ARG),
177 new Prefix("-dsa:", PrefixType.DISABLE_SYSTEM_ASSERTION_ARG),
178 new Prefix("-disablesystemassertions", PrefixType.DISABLE_SYSTEM_ASSERTION_ARG),
179 new Prefix("-dsa", PrefixType.DISABLE_SYSTEM_ASSERTION_ARG),
180
181 new Prefix("-Xbootclasspath/p:", PrefixType.BOOTCLASSPATH_P_ARG),
182 new Prefix("-Xbootclasspath/a:", PrefixType.BOOTCLASSPATH_A_ARG),
183 new Prefix("-X:vmClasses=", PrefixType.BOOTSTRAP_CLASSES_ARG),
184 new Prefix("-X:processors=", PrefixType.PROCESSORS_ARG),
185 new Prefix("-X:irc:help$", PrefixType.IRC_HELP_ARG),
186 new Prefix("-X:irc$", PrefixType.IRC_HELP_ARG),
187 new Prefix("-X:irc:", PrefixType.IRC_ARG),
188 new Prefix("-X:recomp:help$", PrefixType.RECOMP_HELP_ARG),
189 new Prefix("-X:recomp$", PrefixType.RECOMP_HELP_ARG),
190 new Prefix("-X:recomp", PrefixType.RECOMP_ARG),
191 new Prefix("-X:aos:help$", PrefixType.AOS_HELP_ARG),
192 new Prefix("-X:aos$", PrefixType.AOS_HELP_ARG),
193 new Prefix("-X:aos:", PrefixType.AOS_ARG),
194 new Prefix("-X:gc:help$", PrefixType.GC_HELP_ARG),
195 new Prefix("-X:gc$", PrefixType.GC_HELP_ARG),
196 new Prefix("-X:gc:", PrefixType.GC_ARG),
197 new Prefix("-X:base:help$", PrefixType.BASE_HELP_ARG),
198 new Prefix("-X:base$", PrefixType.BASE_HELP_ARG),
199 new Prefix("-X:base:", PrefixType.BASE_ARG),
200 new Prefix("-X:opt:help$", PrefixType.OPT_HELP_ARG),
201 new Prefix("-X:opt$", PrefixType.OPT_HELP_ARG),
202 new Prefix("-X:opt:", PrefixType.OPT_ARG),
203 new Prefix("-X:vm:help$", PrefixType.HELP_ARG),
204 new Prefix("-X:vm$", PrefixType.HELP_ARG),
205 new Prefix("-X:vm:", PrefixType.ARG),
206
207 /* Silently ignored */
208 new Prefix("-Xverify", PrefixType.VERIFY_ARG),
209
210 app_prefix};
211
212 static {
213 Arrays.sort(prefixes);
214 if (DEBUG) {
215 for (int i = 0; i < prefixes.length; i++) {
216 Prefix t = prefixes[i];
217 VM.sysWrite("Prefix[" + i + "]: \"" + t.value + "\"; " + t.type + "\n");
218 }
219 }
220 }
221
222 /**
223 * The command line arguments.
224 */
225 private static String[] args;
226 /**
227 * The types of each command line argument.
228 */
229 private static PrefixType[] arg_types;
230 /**
231 * The position of application class name.
232 */
233 private static int app_name_pos = -1;
234
235 /**
236 * Fetch arguments from program command line.
237 */
238 static void fetchCommandLineArguments() {
239 if (args != null) {
240 // if already been here...
241 return;
242 }
243 ArgReader argRdr = new ArgReader();
244
245 int numArgs = argRdr.numArgs();
246 args = new String[numArgs];
247 arg_types = new PrefixType[numArgs];
248
249 for (int i = 0; i < numArgs; ++i) {
250 String arg = argRdr.getArg(i);
251
252 if (app_prefix.count > 0) {
253 /* We're already into the application arguments. Here's another
254 * one. */
255 args[i] = arg;
256 arg_types[i] = PrefixType.APPLICATION_ARG;
257 app_prefix.count++;
258 continue;
259 }
260
261 // Note: This loop will never run to the end.
262 for (Prefix p : prefixes) {
263 String v = p.value;
264 if (!matches(arg, v)) {
265 continue;
266 }
267 // Chop off the prefix (which we've already matched) and store the
268 // value portion of the string (the unique part) in args[i]. Store
269 // information about the prefix itself in arg_types[i].
270 args[i] = arg.substring(length(v));
271 if (DEBUG) {
272 VM.sysWrite("length(v) = ");
273 VM.sysWrite(length(v));
274
275 VM.sysWrite("; v = \"");
276 VM.sysWrite(v);
277 VM.sysWriteln("\"");
278 VM.sysWrite("args[");
279 VM.sysWrite(i);
280 VM.sysWrite("] = \"");
281 VM.sysWrite(args[i]);
282 VM.sysWrite("\"; arg = \"");
283 VM.sysWrite(arg);
284 VM.sysWriteln("\"");
285 }
286
287 arg_types[i] = p.type;
288 p = findPrefix(p.type); // Find the canonical prefix for this type...
289 p.count++; // And increment the usage count for that
290 // canonical prefix.
291 if (v.endsWith(" ")) {
292 if (++i >= numArgs) {
293 VM.sysWriteln("vm: ", v, "needs an argument");
294 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
295 }
296 args[i - 1] += argRdr.getArg(i);
297 args[i] = null;
298 }
299 if (p == app_prefix) {
300 app_name_pos = i;
301 }
302 break;
303 }
304 } // for (i = 0; i < numArgs...)
305 /*
306 * If no application is specified, set app_name_pos to numArgs (that is,
307 * to one past the last item in the array of arguments) to ensure all
308 * command-line arguments are processed.
309 */
310 if (app_name_pos == -1) {
311 app_name_pos = numArgs;
312 }
313 }
314
315 /**
316 * Does the argument match the prefix?
317 * @param arg argument
318 * @param p prefix
319 * @return true if argument "matches" the prefix, false otherwise
320 */
321 private static boolean matches(String arg, String p) {
322 if (p.endsWith(" ")) {
323 return arg.equals(p.substring(0, p.length() - 1)) || arg.startsWith(p);
324 }
325 if (p.endsWith("$")) {
326 return arg.equals(p.substring(0, p.length() - 1));
327 }
328 return arg.startsWith(p);
329 }
330
331 /**
332 * The real length of the prefix.
333 * @param p prefix
334 * @return real length of prefix
335 */
336 private static int length(String p) {
337 if (p.endsWith("$") || p.endsWith(" ")) return p.length() - 1;
338 return p.length();
339 }
340
341 /**
342 * Find a Prefix object of a given type.
343 */
344 private static Prefix findPrefix(PrefixType type) {
345 for (Prefix prefix : prefixes) if (prefix.type == type) return prefix;
346 return null;
347 }
348
349 /**
350 * Extract all command line arguments of a particular type.
351 * Strips out the prefixes (if any).
352 * !!TODO: cache results instead of constructing a new array each time.
353 * @param prefix type of arguments to extract
354 * @return array of arguments or null if type is invalid
355 */
356 public static String[] getArgs(PrefixType prefix) {
357 String[] retarg = null;
358 Prefix p = findPrefix(prefix);
359 if (p != null) {
360 retarg = new String[p.count];
361 for (int i = 0, j = 0; i < args.length; i++) {
362 if (arg_types[i] == prefix) {
363 retarg[j++] = args[i];
364 }
365 }
366 }
367 return retarg;
368 }
369
370 /**
371 * Extract command line arguments for the Java agent
372 * @return Java agent arguments
373 */
374 public static String[] getJavaAgentArgs() {
375 return CommandLineArgs.getArgs(CommandLineArgs.PrefixType.JAVAAGENT_ARG);
376 }
377
378 /**
379 * Get all environment arguments as pairs of string of key followed by value
380 */
381 public static String[] getEnvironmentArgs() {
382 if (!VM.runningVM) throw new IllegalAccessError("Environment variables can't be read in a non-running VM");
383 return getArgs(PrefixType.ENVIRONMENT_ARG);
384 }
385
386 /**
387 * Extract the first -D... command line argument that matches a given
388 * variable, and return it.
389 * @return the environment arg, or null if there is none.
390 */
391 public static String getEnvironmentArg(String variable) {
392 if (!VM.runningVM) throw new IllegalAccessError("Environment variables can't be read in a non-running VM");
393 String[] allEnvArgs = getArgs(PrefixType.ENVIRONMENT_ARG);
394 String prefix = variable + "=";
395 if (allEnvArgs != null) {
396 for (String allEnvArg : allEnvArgs) {
397 if (allEnvArg.startsWith(prefix)) {
398 return allEnvArg.substring(variable.length() + 1);
399 }
400 }
401 }
402
403 // There are some that we treat specially.
404 if (variable.equals("java.home")) {
405 return getRvmRoot();
406 } else if (variable.equals("gnu.classpath.home.url")) {
407 return "file:" + getRvmRoot();
408 } else if (variable.equals("gnu.classpath.vm.shortname")) {
409 return "JikesRVM";
410 } else if (variable.equals("user.home")) {
411 return getUserHome();
412 } else if (variable.equals("user.dir")) {
413 return getCWD();
414 } else if (variable.equals("os.name")) {
415 return getOsName();
416 } else if (variable.equals("os.version")) {
417 return getOsVersion();
418 } else if (variable.equals("os.arch")) {
419 return getOsArch();
420 }
421 // Ok, didn't find it.
422 return null;
423 }
424
425 private static String getRvmRoot() {
426 return null;
427 }
428
429 private static String getUserHome() {
430 return null;
431 }
432
433 private static String getCWD() {
434 return null;
435 }
436
437 private static String getOsName() {
438 return null;
439 }
440
441 private static String getOsVersion() {
442 return null;
443 }
444
445 private static String getOsArch() {
446 return null;
447 }
448
449 /**
450 * Extract the classes that should go through bootstrap classloader.
451 * @return null if no such command line argument is given.
452 */
453 public static String getBootstrapClasses() {
454 String[] vmClassesAll = getArgs(PrefixType.BOOTSTRAP_CLASSES_ARG);
455 String[] prependClasses = getArgs(PrefixType.BOOTCLASSPATH_P_ARG);
456 String[] appendClasses = getArgs(PrefixType.BOOTCLASSPATH_A_ARG);
457
458 // choose the latest definition of -X:vmClasses
459 String vmClasses = null;
460 // could be specified multiple times, use last specification
461 if (vmClassesAll.length > 0) {
462 vmClasses = vmClassesAll[vmClassesAll.length - 1];
463 }
464
465 // concatenate all bootclasspath entries
466 String result = vmClasses;
467
468 for(int c = 0; c < prependClasses.length; c++) {
469 result = prependClasses[c] + ":" + result;
470 }
471
472 for(int c = 0; c < appendClasses.length; c++) {
473 result = result + ":" + appendClasses[c];
474 }
475
476 return result;
477 }
478
479 /**
480 * Stage1 processing of virtual machine directives appearing in argument list.
481 * We try to process as many classes of command line arguments as possible here.
482 * Only those command line arguments that require a more or less
483 * fully booted VM to handle are delayed until lateProcessCommandLineArguments.
484 */
485 static void earlyProcessCommandLineArguments() {
486 for (int i = 0; i < app_name_pos; i++) {
487 String arg = args[i];
488 PrefixType type = arg_types[i];
489 if (type == PrefixType.INVALID_ARG) continue;
490 Prefix p = findPrefix(type);
491 if (DEBUG) VM.sysWriteln(" CommandLineArgs.earlyProcessCLA(" + p + arg + " - " + type + ")");
492 switch (type) {
493
494 case CLASSPATH_ARG:
495 // arguments of the form "-classpath a:b:c" or "-cp a:b:c"
496 // We are experimentally processing this early so that we can have the
497 // Application class loader complete for when
498 // ClassLoader$StaticData's initializer is run.
499 RVMClassLoader.stashApplicationRepositories(arg);
500 i++; // skip second argument to classpath
501 break;
502
503 case JAR_ARG:
504 // maybe also load classes on the classpath list in the manifest
505 RVMClassLoader.stashApplicationRepositories(arg);
506 i++; // skip second argument to jar
507 break;
508
509 case ENABLE_ASSERTION_ARG:
510 // arguments of the form "-ea[:<packagename>...|:<classname>]"
511 RVMClassLoader.stashEnableAssertionArg(arg);
512 break;
513
514 case ENABLE_SYSTEM_ASSERTION_ARG:
515 // arguments of the form "-esa[:<packagename>...|:<classname>]"
516 // TODO: currently just treat as -ea
517 RVMClassLoader.stashEnableAssertionArg(arg);
518 break;
519
520 case DISABLE_ASSERTION_ARG:
521 // arguments of the form "-da[:<packagename>...|:<classname>]"
522 RVMClassLoader.stashDisableAssertionArg(arg);
523 break;
524
525 case DISABLE_SYSTEM_ASSERTION_ARG:
526 // arguments of the form "-dsa[:<packagename>...|:<classname>]"
527 // TODO: currently just treat as -da
528 RVMClassLoader.stashDisableAssertionArg(arg);
529 break;
530
531 case VERBOSE_CLS_ARG:
532 VM.verboseClassLoading = true;
533 break;
534
535 case VERBOSE_JNI_ARG:
536 VM.verboseJNI = true;
537 break;
538
539 case PROCESSORS_ARG: // "-X:processors=<n>" or "-X:processors=all"
540 int nProcs;
541 if (arg.equals("all")) {
542 /* Assume sysCall.sysNumProcessors() always returns a sane
543 value. */
544 nProcs = sysCall.sysNumProcessors();
545 } else {
546 nProcs = primitiveParseInt(arg);
547 }
548 if (nProcs < 1) {
549 VM.sysWrite("vm: ", p.value, " needs an argument that is at least 1");
550 VM.sysWriteln(", but found ", arg);
551 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
552 }
553 RVMThread.numProcessors = nProcs;
554 break;
555
556 // -------------------------------------------------------------------
557 // GC options
558 // -------------------------------------------------------------------
559 case GC_HELP_ARG: // -X:gc passed 'help' as an option
560 MemoryManager.processCommandLineArg("help");
561 break;
562 case GC_ARG: // "-X:gc:arg" pass 'arg' as an option
563 MemoryManager.processCommandLineArg(arg);
564 break;
565
566 // ----------------------------------------------------
567 // Access initial runtime compiler (may be baseline or optimizing).
568 // ----------------------------------------------------
569 case IRC_HELP_ARG:
570 RuntimeCompiler.processCommandLineArg("-X:irc:", "help");
571 break;
572 case IRC_ARG: // "-X:irc:arg"; pass 'arg' as an option
573 RuntimeCompiler.processCommandLineArg("-X:irc:", arg);
574 break;
575
576 // --------------------------------------------------------------------
577 // Access adaptive system's recompilation compilers
578 // Currently this means the opt compiler, but in general we could be
579 // talking to several different compilers used by AOS for recompilation.
580 // --------------------------------------------------------------------
581 case RECOMP_HELP_ARG:
582 if (VM.BuildForAdaptiveSystem) {
583 Controller.addOptCompilerOption("opt:help");
584 } else {
585 VM.sysWriteln("vm: nonadaptive configuration; -X:recomp is not a legal prefix in this configuration");
586 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
587 }
588 break;
589 case RECOMP_ARG:
590 // "-X:recomp[?]:arg" process as 'opt[?]:arg' to opt
591 // Note arg actually includes the optional opt level and :
592 if (VM.BuildForAdaptiveSystem) {
593 Controller.addOptCompilerOption("opt" + arg);
594 } else {
595 VM.sysWriteln("vm: nonadaptive configuration; -X:recomp is not a legal prefix in this configuration");
596 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
597 }
598 break;
599
600 // -------------------------------------------------------------------
601 // Access adaptive optimization system
602 // -------------------------------------------------------------------
603 case AOS_HELP_ARG: // -X:aos passed 'help' as an option
604 if (VM.BuildForAdaptiveSystem) {
605 Controller.processCommandLineArg("help");
606 } else {
607 VM.sysWrite("vm: nonadaptive configuration; -X:aos is not a legal prefix in this configuration\n");
608 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
609 }
610 break;
611 case AOS_ARG: // "-X:aos:arg" pass 'arg' as an option
612 if (VM.BuildForAdaptiveSystem) {
613 Controller.processCommandLineArg(arg);
614 } else {
615 VM.sysWrite("vm: nonadaptive configuration; -X:aos is not a legal prefix in this configuration\n");
616 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
617 }
618 break;
619
620 // ----------------------------------------------------
621 // Access baseline compiler
622 // ----------------------------------------------------
623 case BASE_HELP_ARG:
624 BaselineOptions.printHelp("-X:base:");
625 break;
626 case BASE_ARG: // "-X:base:arg"; pass 'arg' as an option
627 BaselineCompiler.processCommandLineArg(p.value, arg);
628 break;
629
630 // ----------------------------------------------------
631 // Access all 'logical' optimizing compilers
632 // (both irc and recomp compilers)
633 // ----------------------------------------------------
634 case OPT_HELP_ARG:
635 if (VM.BuildForAdaptiveSystem) {
636 RuntimeCompiler.processOptCommandLineArg("-X:opt:", "help");
637 } else {
638 VM.sysWriteln("vm: You are not using a system that includes the optimizing compiler.");
639 VM.sysWriteln(" Illegal command line argument prefix '-X:opt'");
640 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
641 }
642 break;
643 case OPT_ARG: // "-X:opt:arg"; pass 'arg' as an option
644 if (VM.BuildForAdaptiveSystem) {
645 RuntimeCompiler.processOptCommandLineArg("-X:opt:", arg);
646 Controller.addOptCompilerOption("opt:" + arg);
647 } else {
648 VM.sysWriteln("vm: You are not using a system that includes the optimizing compiler.");
649 VM.sysWriteln(" Illegal command line argument prefix '-X:opt'");
650 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
651 }
652 break;
653
654 // -------------------------------------------------------------------
655 // Other arguments to the core VM
656 // -------------------------------------------------------------------
657 case HELP_ARG: // -X:vm passed 'help' as an option
658 Options.printHelp();
659 break;
660 case ARG: // "-X:vm:arg" pass 'arg' as an option
661 if (!Options.process(arg)) {
662 VM.sysWriteln("Unrecognized command line argument ", p.value, arg);
663 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
664 }
665 break;
666 }
667 }
668 }
669
670 /**
671 * Stage2 processing of virtual machine directives appearing in argument list.
672 * This function is responsible for processing the few
673 * command line arguments that need to be handled late in booting.
674 * It also returns the application's command line arguments.
675 *
676 * @return application arguments (first is application class name)
677 * If no application arguments are specified on the command line,
678 * process commands anyway.
679 */
680 static String[] lateProcessCommandLineArguments() {
681 for (int i = 0; i < app_name_pos; i++) {
682 String arg = args[i];
683 PrefixType type = arg_types[i];
684 if (type == PrefixType.INVALID_ARG) continue;
685 Prefix p = findPrefix(type);
686 if (DEBUG) VM.sysWriteln(" CommandLineArgs.processCLA(" + p + arg + " - " + type + ")");
687 switch (type) {
688 case ENVIRONMENT_ARG: // arguments of the form "-Dx=y"
689 {
690 int mid = arg.indexOf('=');
691 if (mid == -1 || mid + 1 == arg.length()) {
692 VM.sysWriteln("vm: bad property setting: \"", arg, "\"");
693 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
694 }
695 String name = arg.substring(0, mid);
696 String value = arg.substring(mid + 1);
697 System.getProperties().put(name, value);
698 }
699 break;
700
701 case CLASSPATH_ARG: // This is run in duplicate.
702 // arguments of the form "-classpath a:b:c" or "-cp a:b:c"
703 RVMClassLoader.setApplicationRepositories(arg);
704 i++; // skip second argument to classpath
705 break;
706
707 case JAR_ARG: // XXX This WILL BECOME the second half of
708 // handling JAR_ARG. TODO
709 // arguments of the form -jar <jarfile>
710 java.util.jar.Manifest mf = null;
711 try {
712 java.util.jar.JarFile jf = new java.util.jar.JarFile(arg);
713 mf = jf.getManifest();
714 } catch (Exception e) {
715 VM.sysWriteln("vm: IO Exception opening JAR file ", arg, ": ", e.getMessage());
716 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
717 }
718 if (mf == null) {
719 VM.sysWriteln("The jar file is missing the manifest entry for the main class: ", arg);
720 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
721 }
722 String s = mf.getMainAttributes().getValue("Main-Class");
723 if (s == null) {
724 VM.sysWriteln("The jar file is missing the manifest entry for the main class: ", arg);
725 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
726 }
727 // maybe also load classes on the classpath list in the manifest
728 RVMClassLoader.setApplicationRepositories(arg);
729
730 args[i] = s;
731 arg_types[i] = PrefixType.APPLICATION_ARG;
732 app_prefix.count++;
733 i++; // skip second argument to classpath
734 break;
735 case JAVAAGENT_ARG:
736 /* Extract jar file from the -javaagent:<jar>[=options] form */
737 int equalsPos = arg.indexOf("=");
738 String jarPath;
739 if (equalsPos != -1) {
740 jarPath = arg.substring(0, equalsPos);
741 } else {
742 jarPath = arg;
743 }
744 String newClassPath = RVMClassLoader.getApplicationRepositories() + File.pathSeparator + jarPath;
745 RVMClassLoader.setApplicationRepositories(newClassPath);
746 break;
747 }
748 }
749
750 // get application directives
751 String[] arglist = getArgs(PrefixType.APPLICATION_ARG);
752
753 // Debugging: write out application arguments
754 if (DEBUG) {
755 VM.sysWrite("VM.CommandLineArgs(): application arguments " + arglist.length + "\n");
756 for (int i = 0; i < arglist.length; i++) {
757 VM.sysWrite(i + ": \"" + arglist[i] + "\"\n");
758 }
759 }
760
761 return arglist;
762 }
763
764 /**
765 * Read the <code>argno</code>'th command line argument from the C argv
766 * @param argno Number of argument sought
767 * @param buf Buffer to fill
768 * @return number of bytes placed in buffer. -1 means buffer too small
769 * for argument to fit)
770 */
771 private static int sysArg(int argno, byte[] buf) {
772 return sysCall.sysArg(argno, buf, buf.length);
773 }
774
775 /**
776 * Primitive parsing of float/double values.
777 * Done this way to enable us to parse command line arguments
778 * early in VM booting before we are able to do the JNI call
779 * that using Double.valueOf would require.
780 * Does not support the full Java spec.
781 */
782 public static float primitiveParseFloat(String arg) {
783 byte[] b = stringToBytes("floating point", arg);
784 return sysCall.sysPrimitiveParseFloat(b);
785 }
786
787 /**
788 * Primitive parsing of byte/integer numeric values.
789 * Done this way to enable us to parse command line arguments
790 * early in VM booting before we are able call
791 * Byte.parseByte or Integer.parseInt.
792 */
793 public static int primitiveParseInt(String arg) {
794 byte[] b = stringToBytes("integer or byte", arg);
795 return sysCall.sysPrimitiveParseInt(b);
796 }
797
798 /**
799 * Primitive parsing of memory sizes, with proper error handling,
800 * and so on.
801 * Works without needing Byte.parseByte or Integer.parseInt().
802 *
803 * At the moment, we have a maximum limit of an unsigned integer. If
804 *
805 * @return Negative values on error.
806 * Otherwise, positive or zero values as bytes.
807 * */
808 public static long parseMemorySize(String sizeName, String sizeFlag, String defaultFactor, int roundTo,
809 String fullArg, String subArg) {
810 return sysCall.sysParseMemorySize(s2b(sizeName),
811 s2b(sizeFlag),
812 s2b(defaultFactor),
813 roundTo,
814 s2b(fullArg),
815 s2b(subArg));
816 }
817
818 private static final class ArgReader {
819 // int buflen = 10; // for testing; small enough to force
820 // reallocation really soon.
821 int buflen = 512;
822
823 byte[] buf; // gets freed with the class instance.
824
825 ArgReader() {
826 buf = new byte[buflen];
827 }
828
829 /** Read argument # @param i
830 * Assume arguments are encoded in the platform's
831 * "default character set". */
832 @SuppressWarnings({"deprecation"})
833 String getArg(int i) {
834 int cnt;
835 for (; ;) {
836 cnt = sysArg(i, buf);
837 if (cnt >= 0) {
838 break;
839 }
840 buflen += 1024;
841 buf = new byte[buflen];
842 }
843 if (VM.VerifyAssertions) VM._assert(cnt != -1);
844 /*
845 * Implementation note: Do NOT use the line below, which uses the
846 * three-argument constructor for String, the one that respects the native
847 * encoding (the platform's "default character set").
848 *
849 * Instead, we use the four-argument constructor, the one that takes a
850 * HIBYTE parameter.
851 *
852 * 1) It is safe to do this; we *know* that all of the legal command-line
853 * args use only characters within the ASCII character set.
854 *
855 * 2) The "default character set" version below will break. That is
856 * because GNU Classpath's implementation of the
857 * three-argument-constructor will fail if EncodingManager.getDecoder()
858 * returns a null pointer. And EncodingManager.getDecoder() returns a null
859 * pointer if it's called early on in the boot process (which the
860 * default-character-set version below does).
861 */
862 // return new String(buf, 0, cnt);
863 return new String(buf, 0, 0, cnt);
864 }
865
866 int numArgs() {
867 return sysArg(-1, buf);
868 }
869 }
870
871 /** Convenience method for calling stringToBytes */
872 private static byte[] s2b(String arg) {
873 return stringToBytes(null, arg);
874 }
875
876 /** Convert the string s (the "argument") to a null-terminated byte array.
877 * This is used for converting arguments and for converting fixed
878 * strings we pass down to lower commands.
879 *
880 * @return a byte array that represents <code>arg</code> as a
881 * null-terminated C string.
882 * Returns null for a null arg.
883 *
884 * @param arg the argument to convert
885 * @param argName text to print for error reporting. */
886 private static byte[] stringToBytes(String argName, String arg) {
887 if (arg == null) {
888 return null;
889 }
890 int len = arg.length();
891 byte[] b = new byte[len + 1];
892
893 for (int i = 0; i < len; i++) {
894 char c = arg.charAt(i);
895 if (c > 127) {
896 VM.sysWrite("vm: Invalid character found in a");
897 if (argName == null) {
898 VM.sysWrite("n");
899 } else {
900 char v = argName.charAt(0);
901 switch (v) {
902 case'a':
903 case'e':
904 case'i':
905 case'o':
906 case'u':
907 VM.sysWrite("n");
908 }
909 VM.sysWrite(" ", argName);
910 }
911 VM.sysWriteln(" argument: >", arg, "<");
912 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
913 }
914 b[i] = (byte) c;
915 }
916 return b;
917 }
918 }