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