1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "parsed_options.h" 18 19 #include <sstream> 20 21 #include "base/logging.h" 22 #include "base/stringpiece.h" 23 #include "debugger.h" 24 #include "gc/heap.h" 25 #include "monitor.h" 26 #include "runtime.h" 27 #include "ti/agent.h" 28 #include "trace.h" 29 #include "utils.h" 30 31 #include "cmdline_parser.h" 32 #include "runtime_options.h" 33 34 namespace art { 35 36 using MemoryKiB = Memory<1024>; 37 38 ParsedOptions::ParsedOptions() 39 : hook_is_sensitive_thread_(nullptr), 40 hook_vfprintf_(vfprintf), 41 hook_exit_(exit), 42 hook_abort_(nullptr) { // We don't call abort(3) by default; see 43 // Runtime::Abort 44 } 45 46 bool ParsedOptions::Parse(const RuntimeOptions& options, 47 bool ignore_unrecognized, 48 RuntimeArgumentMap* runtime_options) { 49 CHECK(runtime_options != nullptr); 50 51 ParsedOptions parser; 52 return parser.DoParse(options, ignore_unrecognized, runtime_options); 53 } 54 55 using RuntimeParser = CmdlineParser<RuntimeArgumentMap, RuntimeArgumentMap::Key>; 56 57 // Yes, the stack frame is huge. But we get called super early on (and just once) 58 // to pass the command line arguments, so we'll probably be ok. 59 // Ideas to avoid suppressing this diagnostic are welcome! 60 #pragma GCC diagnostic push 61 #pragma GCC diagnostic ignored "-Wframe-larger-than=" 62 63 std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognized) { 64 using M = RuntimeArgumentMap; 65 66 std::unique_ptr<RuntimeParser::Builder> parser_builder = 67 std::unique_ptr<RuntimeParser::Builder>(new RuntimeParser::Builder()); 68 69 parser_builder-> 70 Define("-Xzygote") 71 .IntoKey(M::Zygote) 72 .Define("-help") 73 .IntoKey(M::Help) 74 .Define("-showversion") 75 .IntoKey(M::ShowVersion) 76 .Define("-Xbootclasspath:_") 77 .WithType<std::string>() 78 .IntoKey(M::BootClassPath) 79 .Define("-Xbootclasspath-locations:_") 80 .WithType<ParseStringList<':'>>() // std::vector<std::string>, split by : 81 .IntoKey(M::BootClassPathLocations) 82 .Define({"-classpath _", "-cp _"}) 83 .WithType<std::string>() 84 .IntoKey(M::ClassPath) 85 .Define("-Ximage:_") 86 .WithType<std::string>() 87 .IntoKey(M::Image) 88 .Define("-Xcheck:jni") 89 .IntoKey(M::CheckJni) 90 .Define("-Xjniopts:forcecopy") 91 .IntoKey(M::JniOptsForceCopy) 92 .Define({"-Xrunjdwp:_", "-agentlib:jdwp=_"}) 93 .WithType<JDWP::JdwpOptions>() 94 .IntoKey(M::JdwpOptions) 95 // TODO Re-enable -agentlib: once I have a good way to transform the values. 96 // .Define("-agentlib:_") 97 // .WithType<std::vector<ti::Agent>>().AppendValues() 98 // .IntoKey(M::AgentLib) 99 .Define("-agentpath:_") 100 .WithType<std::list<ti::Agent>>().AppendValues() 101 .IntoKey(M::AgentPath) 102 .Define("-Xms_") 103 .WithType<MemoryKiB>() 104 .IntoKey(M::MemoryInitialSize) 105 .Define("-Xmx_") 106 .WithType<MemoryKiB>() 107 .IntoKey(M::MemoryMaximumSize) 108 .Define("-XX:HeapGrowthLimit=_") 109 .WithType<MemoryKiB>() 110 .IntoKey(M::HeapGrowthLimit) 111 .Define("-XX:HeapMinFree=_") 112 .WithType<MemoryKiB>() 113 .IntoKey(M::HeapMinFree) 114 .Define("-XX:HeapMaxFree=_") 115 .WithType<MemoryKiB>() 116 .IntoKey(M::HeapMaxFree) 117 .Define("-XX:NonMovingSpaceCapacity=_") 118 .WithType<MemoryKiB>() 119 .IntoKey(M::NonMovingSpaceCapacity) 120 .Define("-XX:HeapTargetUtilization=_") 121 .WithType<double>().WithRange(0.1, 0.9) 122 .IntoKey(M::HeapTargetUtilization) 123 .Define("-XX:ForegroundHeapGrowthMultiplier=_") 124 .WithType<double>().WithRange(0.1, 5.0) 125 .IntoKey(M::ForegroundHeapGrowthMultiplier) 126 .Define("-XX:ParallelGCThreads=_") 127 .WithType<unsigned int>() 128 .IntoKey(M::ParallelGCThreads) 129 .Define("-XX:ConcGCThreads=_") 130 .WithType<unsigned int>() 131 .IntoKey(M::ConcGCThreads) 132 .Define("-Xss_") 133 .WithType<Memory<1>>() 134 .IntoKey(M::StackSize) 135 .Define("-XX:MaxSpinsBeforeThinLockInflation=_") 136 .WithType<unsigned int>() 137 .IntoKey(M::MaxSpinsBeforeThinLockInflation) 138 .Define("-XX:LongPauseLogThreshold=_") // in ms 139 .WithType<MillisecondsToNanoseconds>() // store as ns 140 .IntoKey(M::LongPauseLogThreshold) 141 .Define("-XX:LongGCLogThreshold=_") // in ms 142 .WithType<MillisecondsToNanoseconds>() // store as ns 143 .IntoKey(M::LongGCLogThreshold) 144 .Define("-XX:DumpGCPerformanceOnShutdown") 145 .IntoKey(M::DumpGCPerformanceOnShutdown) 146 .Define("-XX:DumpJITInfoOnShutdown") 147 .IntoKey(M::DumpJITInfoOnShutdown) 148 .Define("-XX:IgnoreMaxFootprint") 149 .IntoKey(M::IgnoreMaxFootprint) 150 .Define("-XX:LowMemoryMode") 151 .IntoKey(M::LowMemoryMode) 152 .Define("-XX:UseTLAB") 153 .WithValue(true) 154 .IntoKey(M::UseTLAB) 155 .Define({"-XX:EnableHSpaceCompactForOOM", "-XX:DisableHSpaceCompactForOOM"}) 156 .WithValues({true, false}) 157 .IntoKey(M::EnableHSpaceCompactForOOM) 158 .Define("-XX:DumpNativeStackOnSigQuit:_") 159 .WithType<bool>() 160 .WithValueMap({{"false", false}, {"true", true}}) 161 .IntoKey(M::DumpNativeStackOnSigQuit) 162 .Define("-XX:MadviseRandomAccess:_") 163 .WithType<bool>() 164 .WithValueMap({{"false", false}, {"true", true}}) 165 .IntoKey(M::MadviseRandomAccess) 166 .Define("-Xusejit:_") 167 .WithType<bool>() 168 .WithValueMap({{"false", false}, {"true", true}}) 169 .IntoKey(M::UseJitCompilation) 170 .Define("-Xjitinitialsize:_") 171 .WithType<MemoryKiB>() 172 .IntoKey(M::JITCodeCacheInitialCapacity) 173 .Define("-Xjitmaxsize:_") 174 .WithType<MemoryKiB>() 175 .IntoKey(M::JITCodeCacheMaxCapacity) 176 .Define("-Xjitthreshold:_") 177 .WithType<unsigned int>() 178 .IntoKey(M::JITCompileThreshold) 179 .Define("-Xjitwarmupthreshold:_") 180 .WithType<unsigned int>() 181 .IntoKey(M::JITWarmupThreshold) 182 .Define("-Xjitosrthreshold:_") 183 .WithType<unsigned int>() 184 .IntoKey(M::JITOsrThreshold) 185 .Define("-Xjitprithreadweight:_") 186 .WithType<unsigned int>() 187 .IntoKey(M::JITPriorityThreadWeight) 188 .Define("-Xjittransitionweight:_") 189 .WithType<unsigned int>() 190 .IntoKey(M::JITInvokeTransitionWeight) 191 .Define("-Xjitsaveprofilinginfo") 192 .WithType<ProfileSaverOptions>() 193 .AppendValues() 194 .IntoKey(M::ProfileSaverOpts) 195 .Define("-Xps-_") // profile saver options -Xps-<key>:<value> 196 .WithType<ProfileSaverOptions>() 197 .AppendValues() 198 .IntoKey(M::ProfileSaverOpts) // NOTE: Appends into same key as -Xjitsaveprofilinginfo 199 .Define("-XX:HspaceCompactForOOMMinIntervalMs=_") // in ms 200 .WithType<MillisecondsToNanoseconds>() // store as ns 201 .IntoKey(M::HSpaceCompactForOOMMinIntervalsMs) 202 .Define("-D_") 203 .WithType<std::vector<std::string>>().AppendValues() 204 .IntoKey(M::PropertiesList) 205 .Define("-Xjnitrace:_") 206 .WithType<std::string>() 207 .IntoKey(M::JniTrace) 208 .Define("-Xpatchoat:_") 209 .WithType<std::string>() 210 .IntoKey(M::PatchOat) 211 .Define({"-Xrelocate", "-Xnorelocate"}) 212 .WithValues({true, false}) 213 .IntoKey(M::Relocate) 214 .Define({"-Xdex2oat", "-Xnodex2oat"}) 215 .WithValues({true, false}) 216 .IntoKey(M::Dex2Oat) 217 .Define({"-Ximage-dex2oat", "-Xnoimage-dex2oat"}) 218 .WithValues({true, false}) 219 .IntoKey(M::ImageDex2Oat) 220 .Define("-Xint") 221 .WithValue(true) 222 .IntoKey(M::Interpret) 223 .Define("-Xgc:_") 224 .WithType<XGcOption>() 225 .IntoKey(M::GcOption) 226 .Define("-XX:LargeObjectSpace=_") 227 .WithType<gc::space::LargeObjectSpaceType>() 228 .WithValueMap({{"disabled", gc::space::LargeObjectSpaceType::kDisabled}, 229 {"freelist", gc::space::LargeObjectSpaceType::kFreeList}, 230 {"map", gc::space::LargeObjectSpaceType::kMap}}) 231 .IntoKey(M::LargeObjectSpace) 232 .Define("-XX:LargeObjectThreshold=_") 233 .WithType<Memory<1>>() 234 .IntoKey(M::LargeObjectThreshold) 235 .Define("-XX:BackgroundGC=_") 236 .WithType<BackgroundGcOption>() 237 .IntoKey(M::BackgroundGc) 238 .Define("-XX:+DisableExplicitGC") 239 .IntoKey(M::DisableExplicitGC) 240 .Define("-verbose:_") 241 .WithType<LogVerbosity>() 242 .IntoKey(M::Verbose) 243 .Define("-Xlockprofthreshold:_") 244 .WithType<unsigned int>() 245 .IntoKey(M::LockProfThreshold) 246 .Define("-Xstackdumplockprofthreshold:_") 247 .WithType<unsigned int>() 248 .IntoKey(M::StackDumpLockProfThreshold) 249 .Define("-Xusetombstonedtraces") 250 .WithValue(true) 251 .IntoKey(M::UseTombstonedTraces) 252 .Define("-Xstacktracefile:_") 253 .WithType<std::string>() 254 .IntoKey(M::StackTraceFile) 255 .Define("-Xmethod-trace") 256 .IntoKey(M::MethodTrace) 257 .Define("-Xmethod-trace-file:_") 258 .WithType<std::string>() 259 .IntoKey(M::MethodTraceFile) 260 .Define("-Xmethod-trace-file-size:_") 261 .WithType<unsigned int>() 262 .IntoKey(M::MethodTraceFileSize) 263 .Define("-Xmethod-trace-stream") 264 .IntoKey(M::MethodTraceStreaming) 265 .Define("-Xprofile:_") 266 .WithType<TraceClockSource>() 267 .WithValueMap({{"threadcpuclock", TraceClockSource::kThreadCpu}, 268 {"wallclock", TraceClockSource::kWall}, 269 {"dualclock", TraceClockSource::kDual}}) 270 .IntoKey(M::ProfileClock) 271 .Define("-Xcompiler:_") 272 .WithType<std::string>() 273 .IntoKey(M::Compiler) 274 .Define("-Xcompiler-option _") 275 .WithType<std::vector<std::string>>() 276 .AppendValues() 277 .IntoKey(M::CompilerOptions) 278 .Define("-Ximage-compiler-option _") 279 .WithType<std::vector<std::string>>() 280 .AppendValues() 281 .IntoKey(M::ImageCompilerOptions) 282 .Define("-Xverify:_") 283 .WithType<verifier::VerifyMode>() 284 .WithValueMap({{"none", verifier::VerifyMode::kNone}, 285 {"remote", verifier::VerifyMode::kEnable}, 286 {"all", verifier::VerifyMode::kEnable}, 287 {"softfail", verifier::VerifyMode::kSoftFail}}) 288 .IntoKey(M::Verify) 289 .Define("-XX:NativeBridge=_") 290 .WithType<std::string>() 291 .IntoKey(M::NativeBridge) 292 .Define("-Xzygote-max-boot-retry=_") 293 .WithType<unsigned int>() 294 .IntoKey(M::ZygoteMaxFailedBoots) 295 .Define("-Xno-dex-file-fallback") 296 .IntoKey(M::NoDexFileFallback) 297 .Define("-Xno-sig-chain") 298 .IntoKey(M::NoSigChain) 299 .Define("--cpu-abilist=_") 300 .WithType<std::string>() 301 .IntoKey(M::CpuAbiList) 302 .Define("-Xfingerprint:_") 303 .WithType<std::string>() 304 .IntoKey(M::Fingerprint) 305 .Define("-Xexperimental:_") 306 .WithType<ExperimentalFlags>() 307 .AppendValues() 308 .IntoKey(M::Experimental) 309 .Define("-Xforce-nb-testing") 310 .IntoKey(M::ForceNativeBridge) 311 .Define("-Xplugin:_") 312 .WithType<std::vector<Plugin>>().AppendValues() 313 .IntoKey(M::Plugins) 314 .Define("-XX:ThreadSuspendTimeout=_") // in ms 315 .WithType<MillisecondsToNanoseconds>() // store as ns 316 .IntoKey(M::ThreadSuspendTimeout) 317 .Define("-XX:SlowDebug=_") 318 .WithType<bool>() 319 .WithValueMap({{"false", false}, {"true", true}}) 320 .IntoKey(M::SlowDebug) 321 .Ignore({ 322 "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa", 323 "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_", 324 "-Xdexopt:_", "-Xnoquithandler", "-Xjnigreflimit:_", "-Xgenregmap", "-Xnogenregmap", 325 "-Xverifyopt:_", "-Xcheckdexsum", "-Xincludeselectedop", "-Xjitop:_", 326 "-Xincludeselectedmethod", "-Xjitthreshold:_", 327 "-Xjitblocking", "-Xjitmethod:_", "-Xjitclass:_", "-Xjitoffset:_", 328 "-Xjitconfig:_", "-Xjitcheckcg", "-Xjitverbose", "-Xjitprofile", 329 "-Xjitdisableopt", "-Xjitsuspendpoll", "-XX:mainThreadStackSize=_"}) 330 .IgnoreUnrecognized(ignore_unrecognized); 331 332 // TODO: Move Usage information into this DSL. 333 334 return std::unique_ptr<RuntimeParser>(new RuntimeParser(parser_builder->Build())); 335 } 336 337 #pragma GCC diagnostic pop 338 339 // Remove all the special options that have something in the void* part of the option. 340 // If runtime_options is not null, put the options in there. 341 // As a side-effect, populate the hooks from options. 342 bool ParsedOptions::ProcessSpecialOptions(const RuntimeOptions& options, 343 RuntimeArgumentMap* runtime_options, 344 std::vector<std::string>* out_options) { 345 using M = RuntimeArgumentMap; 346 347 // TODO: Move the below loop into JNI 348 // Handle special options that set up hooks 349 for (size_t i = 0; i < options.size(); ++i) { 350 const std::string option(options[i].first); 351 // TODO: support -Djava.class.path 352 if (option == "bootclasspath") { 353 auto boot_class_path = static_cast<std::vector<std::unique_ptr<const DexFile>>*>( 354 const_cast<void*>(options[i].second)); 355 356 if (runtime_options != nullptr) { 357 runtime_options->Set(M::BootClassPathDexList, boot_class_path); 358 } 359 } else if (option == "compilercallbacks") { 360 CompilerCallbacks* compiler_callbacks = 361 reinterpret_cast<CompilerCallbacks*>(const_cast<void*>(options[i].second)); 362 if (runtime_options != nullptr) { 363 runtime_options->Set(M::CompilerCallbacksPtr, compiler_callbacks); 364 } 365 } else if (option == "imageinstructionset") { 366 const char* isa_str = reinterpret_cast<const char*>(options[i].second); 367 auto&& image_isa = GetInstructionSetFromString(isa_str); 368 if (image_isa == kNone) { 369 Usage("%s is not a valid instruction set.", isa_str); 370 return false; 371 } 372 if (runtime_options != nullptr) { 373 runtime_options->Set(M::ImageInstructionSet, image_isa); 374 } 375 } else if (option == "sensitiveThread") { 376 const void* hook = options[i].second; 377 bool (*hook_is_sensitive_thread)() = reinterpret_cast<bool (*)()>(const_cast<void*>(hook)); 378 379 if (runtime_options != nullptr) { 380 runtime_options->Set(M::HookIsSensitiveThread, hook_is_sensitive_thread); 381 } 382 } else if (option == "vfprintf") { 383 const void* hook = options[i].second; 384 if (hook == nullptr) { 385 Usage("vfprintf argument was nullptr"); 386 return false; 387 } 388 int (*hook_vfprintf)(FILE *, const char*, va_list) = 389 reinterpret_cast<int (*)(FILE *, const char*, va_list)>(const_cast<void*>(hook)); 390 391 if (runtime_options != nullptr) { 392 runtime_options->Set(M::HookVfprintf, hook_vfprintf); 393 } 394 hook_vfprintf_ = hook_vfprintf; 395 } else if (option == "exit") { 396 const void* hook = options[i].second; 397 if (hook == nullptr) { 398 Usage("exit argument was nullptr"); 399 return false; 400 } 401 void(*hook_exit)(jint) = reinterpret_cast<void(*)(jint)>(const_cast<void*>(hook)); 402 if (runtime_options != nullptr) { 403 runtime_options->Set(M::HookExit, hook_exit); 404 } 405 hook_exit_ = hook_exit; 406 } else if (option == "abort") { 407 const void* hook = options[i].second; 408 if (hook == nullptr) { 409 Usage("abort was nullptr\n"); 410 return false; 411 } 412 void(*hook_abort)() = reinterpret_cast<void(*)()>(const_cast<void*>(hook)); 413 if (runtime_options != nullptr) { 414 runtime_options->Set(M::HookAbort, hook_abort); 415 } 416 hook_abort_ = hook_abort; 417 } else { 418 // It is a regular option, that doesn't have a known 'second' value. 419 // Push it on to the regular options which will be parsed by our parser. 420 if (out_options != nullptr) { 421 out_options->push_back(option); 422 } 423 } 424 } 425 426 return true; 427 } 428 429 // Intended for local changes only. 430 static void MaybeOverrideVerbosity() { 431 // gLogVerbosity.class_linker = true; // TODO: don't check this in! 432 // gLogVerbosity.collector = true; // TODO: don't check this in! 433 // gLogVerbosity.compiler = true; // TODO: don't check this in! 434 // gLogVerbosity.deopt = true; // TODO: don't check this in! 435 // gLogVerbosity.gc = true; // TODO: don't check this in! 436 // gLogVerbosity.heap = true; // TODO: don't check this in! 437 // gLogVerbosity.jdwp = true; // TODO: don't check this in! 438 // gLogVerbosity.jit = true; // TODO: don't check this in! 439 // gLogVerbosity.jni = true; // TODO: don't check this in! 440 // gLogVerbosity.monitor = true; // TODO: don't check this in! 441 // gLogVerbosity.oat = true; // TODO: don't check this in! 442 // gLogVerbosity.profiler = true; // TODO: don't check this in! 443 // gLogVerbosity.signals = true; // TODO: don't check this in! 444 // gLogVerbosity.simulator = true; // TODO: don't check this in! 445 // gLogVerbosity.startup = true; // TODO: don't check this in! 446 // gLogVerbosity.third_party_jni = true; // TODO: don't check this in! 447 // gLogVerbosity.threads = true; // TODO: don't check this in! 448 // gLogVerbosity.verifier = true; // TODO: don't check this in! 449 } 450 451 bool ParsedOptions::DoParse(const RuntimeOptions& options, 452 bool ignore_unrecognized, 453 RuntimeArgumentMap* runtime_options) { 454 for (size_t i = 0; i < options.size(); ++i) { 455 if (true && options[0].first == "-Xzygote") { 456 LOG(INFO) << "option[" << i << "]=" << options[i].first; 457 } 458 } 459 460 auto parser = MakeParser(ignore_unrecognized); 461 462 // Convert to a simple string list (without the magic pointer options) 463 std::vector<std::string> argv_list; 464 if (!ProcessSpecialOptions(options, nullptr, &argv_list)) { 465 return false; 466 } 467 468 CmdlineResult parse_result = parser->Parse(argv_list); 469 470 // Handle parse errors by displaying the usage and potentially exiting. 471 if (parse_result.IsError()) { 472 if (parse_result.GetStatus() == CmdlineResult::kUsage) { 473 UsageMessage(stdout, "%s\n", parse_result.GetMessage().c_str()); 474 Exit(0); 475 } else if (parse_result.GetStatus() == CmdlineResult::kUnknown && !ignore_unrecognized) { 476 Usage("%s\n", parse_result.GetMessage().c_str()); 477 return false; 478 } else { 479 Usage("%s\n", parse_result.GetMessage().c_str()); 480 Exit(0); 481 } 482 483 UNREACHABLE(); 484 } 485 486 using M = RuntimeArgumentMap; 487 RuntimeArgumentMap args = parser->ReleaseArgumentsMap(); 488 489 // -help, -showversion, etc. 490 if (args.Exists(M::Help)) { 491 Usage(nullptr); 492 return false; 493 } else if (args.Exists(M::ShowVersion)) { 494 UsageMessage(stdout, 495 "ART version %s %s\n", 496 Runtime::GetVersion(), 497 GetInstructionSetString(kRuntimeISA)); 498 Exit(0); 499 } else if (args.Exists(M::BootClassPath)) { 500 LOG(INFO) << "setting boot class path to " << *args.Get(M::BootClassPath); 501 } 502 503 if (args.GetOrDefault(M::UseJitCompilation) && args.GetOrDefault(M::Interpret)) { 504 Usage("-Xusejit:true and -Xint cannot be specified together"); 505 Exit(0); 506 } 507 508 // Set a default boot class path if we didn't get an explicit one via command line. 509 if (getenv("BOOTCLASSPATH") != nullptr) { 510 args.SetIfMissing(M::BootClassPath, std::string(getenv("BOOTCLASSPATH"))); 511 } 512 513 // Set a default class path if we didn't get an explicit one via command line. 514 if (getenv("CLASSPATH") != nullptr) { 515 args.SetIfMissing(M::ClassPath, std::string(getenv("CLASSPATH"))); 516 } 517 518 // Default to number of processors minus one since the main GC thread also does work. 519 args.SetIfMissing(M::ParallelGCThreads, gc::Heap::kDefaultEnableParallelGC ? 520 static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_CONF) - 1u) : 0u); 521 522 // -verbose: 523 { 524 LogVerbosity *log_verbosity = args.Get(M::Verbose); 525 if (log_verbosity != nullptr) { 526 gLogVerbosity = *log_verbosity; 527 } 528 } 529 530 MaybeOverrideVerbosity(); 531 532 SetRuntimeDebugFlagsEnabled(args.Get(M::SlowDebug)); 533 534 // -Xprofile: 535 Trace::SetDefaultClockSource(args.GetOrDefault(M::ProfileClock)); 536 537 if (!ProcessSpecialOptions(options, &args, nullptr)) { 538 return false; 539 } 540 541 { 542 // If not set, background collector type defaults to homogeneous compaction. 543 // If foreground is GSS, use GSS as background collector. 544 // If not low memory mode, semispace otherwise. 545 546 gc::CollectorType background_collector_type_; 547 gc::CollectorType collector_type_ = (XGcOption{}).collector_type_; // NOLINT [whitespace/braces] [5] 548 bool low_memory_mode_ = args.Exists(M::LowMemoryMode); 549 550 background_collector_type_ = args.GetOrDefault(M::BackgroundGc); 551 { 552 XGcOption* xgc = args.Get(M::GcOption); 553 if (xgc != nullptr && xgc->collector_type_ != gc::kCollectorTypeNone) { 554 collector_type_ = xgc->collector_type_; 555 } 556 } 557 558 if (background_collector_type_ == gc::kCollectorTypeNone) { 559 if (collector_type_ != gc::kCollectorTypeGSS) { 560 background_collector_type_ = low_memory_mode_ ? 561 gc::kCollectorTypeSS : gc::kCollectorTypeHomogeneousSpaceCompact; 562 } else { 563 background_collector_type_ = collector_type_; 564 } 565 } 566 567 args.Set(M::BackgroundGc, BackgroundGcOption { background_collector_type_ }); 568 } 569 570 // If a reference to the dalvik core.jar snuck in, replace it with 571 // the art specific version. This can happen with on device 572 // boot.art/boot.oat generation by GenerateImage which relies on the 573 // value of BOOTCLASSPATH. 574 #if defined(ART_TARGET) 575 std::string core_jar("/core.jar"); 576 std::string core_libart_jar("/core-libart.jar"); 577 #else 578 // The host uses hostdex files. 579 std::string core_jar("/core-hostdex.jar"); 580 std::string core_libart_jar("/core-libart-hostdex.jar"); 581 #endif 582 auto boot_class_path_string = args.GetOrDefault(M::BootClassPath); 583 584 size_t core_jar_pos = boot_class_path_string.find(core_jar); 585 if (core_jar_pos != std::string::npos) { 586 boot_class_path_string.replace(core_jar_pos, core_jar.size(), core_libart_jar); 587 args.Set(M::BootClassPath, boot_class_path_string); 588 } 589 590 { 591 auto&& boot_class_path = args.GetOrDefault(M::BootClassPath); 592 auto&& boot_class_path_locations = args.GetOrDefault(M::BootClassPathLocations); 593 if (args.Exists(M::BootClassPathLocations)) { 594 size_t boot_class_path_count = ParseStringList<':'>::Split(boot_class_path).Size(); 595 596 if (boot_class_path_count != boot_class_path_locations.Size()) { 597 Usage("The number of boot class path files does not match" 598 " the number of boot class path locations given\n" 599 " boot class path files (%zu): %s\n" 600 " boot class path locations (%zu): %s\n", 601 boot_class_path.size(), boot_class_path_string.c_str(), 602 boot_class_path_locations.Size(), boot_class_path_locations.Join().c_str()); 603 return false; 604 } 605 } 606 } 607 608 if (!args.Exists(M::CompilerCallbacksPtr) && !args.Exists(M::Image)) { 609 std::string image = GetAndroidRoot(); 610 image += "/framework/boot.art"; 611 args.Set(M::Image, image); 612 } 613 614 // 0 means no growth limit, and growth limit should be always <= heap size 615 if (args.GetOrDefault(M::HeapGrowthLimit) <= 0u || 616 args.GetOrDefault(M::HeapGrowthLimit) > args.GetOrDefault(M::MemoryMaximumSize)) { 617 args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize)); 618 } 619 620 *runtime_options = std::move(args); 621 return true; 622 } 623 624 void ParsedOptions::Exit(int status) { 625 hook_exit_(status); 626 } 627 628 void ParsedOptions::Abort() { 629 hook_abort_(); 630 } 631 632 void ParsedOptions::UsageMessageV(FILE* stream, const char* fmt, va_list ap) { 633 hook_vfprintf_(stream, fmt, ap); 634 } 635 636 void ParsedOptions::UsageMessage(FILE* stream, const char* fmt, ...) { 637 va_list ap; 638 va_start(ap, fmt); 639 UsageMessageV(stream, fmt, ap); 640 va_end(ap); 641 } 642 643 void ParsedOptions::Usage(const char* fmt, ...) { 644 bool error = (fmt != nullptr); 645 FILE* stream = error ? stderr : stdout; 646 647 if (fmt != nullptr) { 648 va_list ap; 649 va_start(ap, fmt); 650 UsageMessageV(stream, fmt, ap); 651 va_end(ap); 652 } 653 654 const char* program = "dalvikvm"; 655 UsageMessage(stream, "%s: [options] class [argument ...]\n", program); 656 UsageMessage(stream, "\n"); 657 UsageMessage(stream, "The following standard options are supported:\n"); 658 UsageMessage(stream, " -classpath classpath (-cp classpath)\n"); 659 UsageMessage(stream, " -Dproperty=value\n"); 660 UsageMessage(stream, " -verbose:tag ('gc', 'jit', 'jni', or 'class')\n"); 661 UsageMessage(stream, " -showversion\n"); 662 UsageMessage(stream, " -help\n"); 663 UsageMessage(stream, " -agentlib:jdwp=options\n"); 664 // TODO add back in once -agentlib actually does something. 665 // UsageMessage(stream, " -agentlib:library=options (Experimental feature, " 666 // "requires -Xexperimental:agent, some features might not be supported)\n"); 667 UsageMessage(stream, " -agentpath:library_path=options (Experimental feature, " 668 "requires -Xexperimental:agent, some features might not be supported)\n"); 669 UsageMessage(stream, "\n"); 670 671 UsageMessage(stream, "The following extended options are supported:\n"); 672 UsageMessage(stream, " -Xrunjdwp:<options>\n"); 673 UsageMessage(stream, " -Xbootclasspath:bootclasspath\n"); 674 UsageMessage(stream, " -Xcheck:tag (e.g. 'jni')\n"); 675 UsageMessage(stream, " -XmsN (min heap, must be multiple of 1K, >= 1MB)\n"); 676 UsageMessage(stream, " -XmxN (max heap, must be multiple of 1K, >= 2MB)\n"); 677 UsageMessage(stream, " -XssN (stack size)\n"); 678 UsageMessage(stream, " -Xint\n"); 679 UsageMessage(stream, "\n"); 680 681 UsageMessage(stream, "The following Dalvik options are supported:\n"); 682 UsageMessage(stream, " -Xzygote\n"); 683 UsageMessage(stream, " -Xjnitrace:substring (eg NativeClass or nativeMethod)\n"); 684 UsageMessage(stream, " -Xstacktracefile:<filename>\n"); 685 UsageMessage(stream, " -Xgc:[no]preverify\n"); 686 UsageMessage(stream, " -Xgc:[no]postverify\n"); 687 UsageMessage(stream, " -XX:HeapGrowthLimit=N\n"); 688 UsageMessage(stream, " -XX:HeapMinFree=N\n"); 689 UsageMessage(stream, " -XX:HeapMaxFree=N\n"); 690 UsageMessage(stream, " -XX:NonMovingSpaceCapacity=N\n"); 691 UsageMessage(stream, " -XX:HeapTargetUtilization=doublevalue\n"); 692 UsageMessage(stream, " -XX:ForegroundHeapGrowthMultiplier=doublevalue\n"); 693 UsageMessage(stream, " -XX:LowMemoryMode\n"); 694 UsageMessage(stream, " -Xprofile:{threadcpuclock,wallclock,dualclock}\n"); 695 UsageMessage(stream, " -Xjitthreshold:integervalue\n"); 696 UsageMessage(stream, "\n"); 697 698 UsageMessage(stream, "The following unique to ART options are supported:\n"); 699 UsageMessage(stream, " -Xgc:[no]preverify_rosalloc\n"); 700 UsageMessage(stream, " -Xgc:[no]postsweepingverify_rosalloc\n"); 701 UsageMessage(stream, " -Xgc:[no]postverify_rosalloc\n"); 702 UsageMessage(stream, " -Xgc:[no]presweepingverify\n"); 703 UsageMessage(stream, " -Ximage:filename\n"); 704 UsageMessage(stream, " -Xbootclasspath-locations:bootclasspath\n" 705 " (override the dex locations of the -Xbootclasspath files)\n"); 706 UsageMessage(stream, " -XX:+DisableExplicitGC\n"); 707 UsageMessage(stream, " -XX:ParallelGCThreads=integervalue\n"); 708 UsageMessage(stream, " -XX:ConcGCThreads=integervalue\n"); 709 UsageMessage(stream, " -XX:MaxSpinsBeforeThinLockInflation=integervalue\n"); 710 UsageMessage(stream, " -XX:LongPauseLogThreshold=integervalue\n"); 711 UsageMessage(stream, " -XX:LongGCLogThreshold=integervalue\n"); 712 UsageMessage(stream, " -XX:ThreadSuspendTimeout=integervalue\n"); 713 UsageMessage(stream, " -XX:DumpGCPerformanceOnShutdown\n"); 714 UsageMessage(stream, " -XX:DumpJITInfoOnShutdown\n"); 715 UsageMessage(stream, " -XX:IgnoreMaxFootprint\n"); 716 UsageMessage(stream, " -XX:UseTLAB\n"); 717 UsageMessage(stream, " -XX:BackgroundGC=none\n"); 718 UsageMessage(stream, " -XX:LargeObjectSpace={disabled,map,freelist}\n"); 719 UsageMessage(stream, " -XX:LargeObjectThreshold=N\n"); 720 UsageMessage(stream, " -XX:DumpNativeStackOnSigQuit=booleanvalue\n"); 721 UsageMessage(stream, " -XX:MadviseRandomAccess:booleanvalue\n"); 722 UsageMessage(stream, " -XX:SlowDebug={false,true}\n"); 723 UsageMessage(stream, " -Xmethod-trace\n"); 724 UsageMessage(stream, " -Xmethod-trace-file:filename"); 725 UsageMessage(stream, " -Xmethod-trace-file-size:integervalue\n"); 726 UsageMessage(stream, " -Xps-min-save-period-ms:integervalue\n"); 727 UsageMessage(stream, " -Xps-save-resolved-classes-delay-ms:integervalue\n"); 728 UsageMessage(stream, " -Xps-hot-startup-method-samples:integervalue\n"); 729 UsageMessage(stream, " -Xps-min-methods-to-save:integervalue\n"); 730 UsageMessage(stream, " -Xps-min-classes-to-save:integervalue\n"); 731 UsageMessage(stream, " -Xps-min-notification-before-wake:integervalue\n"); 732 UsageMessage(stream, " -Xps-max-notification-before-wake:integervalue\n"); 733 UsageMessage(stream, " -Xps-profile-path:file-path\n"); 734 UsageMessage(stream, " -Xcompiler:filename\n"); 735 UsageMessage(stream, " -Xcompiler-option dex2oat-option\n"); 736 UsageMessage(stream, " -Ximage-compiler-option dex2oat-option\n"); 737 UsageMessage(stream, " -Xpatchoat:filename\n"); 738 UsageMessage(stream, " -Xusejit:booleanvalue\n"); 739 UsageMessage(stream, " -Xjitinitialsize:N\n"); 740 UsageMessage(stream, " -Xjitmaxsize:N\n"); 741 UsageMessage(stream, " -Xjitwarmupthreshold:integervalue\n"); 742 UsageMessage(stream, " -Xjitosrthreshold:integervalue\n"); 743 UsageMessage(stream, " -Xjitprithreadweight:integervalue\n"); 744 UsageMessage(stream, " -X[no]relocate\n"); 745 UsageMessage(stream, " -X[no]dex2oat (Whether to invoke dex2oat on the application)\n"); 746 UsageMessage(stream, " -X[no]image-dex2oat (Whether to create and use a boot image)\n"); 747 UsageMessage(stream, " -Xno-dex-file-fallback " 748 "(Don't fall back to dex files without oat files)\n"); 749 UsageMessage(stream, " -Xplugin:<library.so> " 750 "(Load a runtime plugin, requires -Xexperimental:runtime-plugins)\n"); 751 UsageMessage(stream, " -Xexperimental:runtime-plugins" 752 "(Enable new and experimental agent support)\n"); 753 UsageMessage(stream, " -Xexperimental:agents" 754 "(Enable new and experimental agent support)\n"); 755 UsageMessage(stream, "\n"); 756 757 UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n"); 758 UsageMessage(stream, " -ea[:<package name>... |:<class name>]\n"); 759 UsageMessage(stream, " -da[:<package name>... |:<class name>]\n"); 760 UsageMessage(stream, " (-enableassertions, -disableassertions)\n"); 761 UsageMessage(stream, " -esa\n"); 762 UsageMessage(stream, " -dsa\n"); 763 UsageMessage(stream, " (-enablesystemassertions, -disablesystemassertions)\n"); 764 UsageMessage(stream, " -Xverify:{none,remote,all,softfail}\n"); 765 UsageMessage(stream, " -Xrs\n"); 766 UsageMessage(stream, " -Xint:portable, -Xint:fast, -Xint:jit\n"); 767 UsageMessage(stream, " -Xdexopt:{none,verified,all,full}\n"); 768 UsageMessage(stream, " -Xnoquithandler\n"); 769 UsageMessage(stream, " -Xjniopts:{warnonly,forcecopy}\n"); 770 UsageMessage(stream, " -Xjnigreflimit:integervalue\n"); 771 UsageMessage(stream, " -Xgc:[no]precise\n"); 772 UsageMessage(stream, " -Xgc:[no]verifycardtable\n"); 773 UsageMessage(stream, " -X[no]genregmap\n"); 774 UsageMessage(stream, " -Xverifyopt:[no]checkmon\n"); 775 UsageMessage(stream, " -Xcheckdexsum\n"); 776 UsageMessage(stream, " -Xincludeselectedop\n"); 777 UsageMessage(stream, " -Xjitop:hexopvalue[-endvalue][,hexopvalue[-endvalue]]*\n"); 778 UsageMessage(stream, " -Xincludeselectedmethod\n"); 779 UsageMessage(stream, " -Xjitblocking\n"); 780 UsageMessage(stream, " -Xjitmethod:signature[,signature]* (eg Ljava/lang/String\\;replace)\n"); 781 UsageMessage(stream, " -Xjitclass:classname[,classname]*\n"); 782 UsageMessage(stream, " -Xjitcodecachesize:N\n"); 783 UsageMessage(stream, " -Xjitoffset:offset[,offset]\n"); 784 UsageMessage(stream, " -Xjitconfig:filename\n"); 785 UsageMessage(stream, " -Xjitcheckcg\n"); 786 UsageMessage(stream, " -Xjitverbose\n"); 787 UsageMessage(stream, " -Xjitprofile\n"); 788 UsageMessage(stream, " -Xjitdisableopt\n"); 789 UsageMessage(stream, " -Xjitsuspendpoll\n"); 790 UsageMessage(stream, " -XX:mainThreadStackSize=N\n"); 791 UsageMessage(stream, "\n"); 792 793 Exit((error) ? 1 : 0); 794 } 795 796 } // namespace art 797