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