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